Function in fuse linux in c - c

I am new in linux, and i have an assignment about FUSE.
My FUSE need to be able open a file, edit, and rename it.
Here is my full code
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/statfs.h>
#include <stdlib.h>
static const char *dirpath = "/home/cync48/Downloads";
static int xmp_getattr(const char *path, struct stat *stbuf)
{
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
res = lstat(fpath, stbuf);
if(res == -1)
return -errno;
return 0;
}
static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
char fpath[1000];
if(strcmp(path,"/")==0)
{
path = dirpath;
sprintf(fpath, "%s", path);
}
else
sprintf(fpath, "%s%s", dirpath, path);
DIR *dp;
struct dirent *de;
(void) offset;
(void) fi;
dp = opendir(fpath);
if (dp == NULL)
return -errno;
while ((de = readdir(dp)) != NULL) {
struct stat st;
memset(&st, 0, sizeof(st));
st.st_ino = de->d_ino;
st.st_mode = de->d_type << 12;
if (filler(buf, de->d_name, &st, 0))
break;
}
closedir(dp);
return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
//On Linux this could just be 'mknod(path, mode, rdev)' but thisis more portable
if (S_ISREG(mode)) {
res = open(fpath, O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0)
res = close(res);
} else if (S_ISFIFO(mode))
res = mkfifo(fpath, mode);
else
res = mknod(fpath, mode, rdev);
if (res == -1)
return -errno;
return 0;
}
static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
res = mkdir(fpath, mode);
if (res == -1)
return -errno;
return 0;
}
static int xmp_unlink(const char *path)
{
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
res = unlink(fpath);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rmdir(const char *path)
{
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
res = rmdir(fpath);
if (res == -1)
return -errno;
return 0;
}
static int xmp_rename(const char *from, const char *to)
{
int res;
res = rename(from, to);
if (res == -1)
return -errno;
return 0;
}
static int xmp_open(const char *path, struct fuse_file_info *fi)
{
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
//(void) fi;
res = open(fpath, fi->flags);
if (res == -1)
return -errno;
close(res);
return 0;
}
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
int fd;
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
(void) fi;
fd = open(path, O_RDONLY);
if (fd == -1)
return -errno;
res = pread(fd, buf, size, offset);
if (res == -1)
res = -errno;
close(fd);
return res;
}
static int xmp_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int fd;
int res;
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
(void) fi;
fd = open(fpath, O_WRONLY);
if (fd == -1)
return -errno;
res = pwrite(fd, buf, size, offset);
if (res == -1)
res = -errno;
close(fd);
return res;
}
static int xmp_release(const char *path, struct fuse_file_info *fi)
{
//Just a stub. This method is optional and can safely be left unimplemented
char fpath[1000];
sprintf(fpath, "%s%s", dirpath, path);
(void) fpath;
(void) fi;
return 0;
}
static struct fuse_operations xmp_oper = {
.getattr = xmp_getattr,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.readdir = xmp_readdir,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.open = xmp_open,
.read = xmp_read,
.write = xmp_write,
.release = xmp_release,
};
int main(int argc, char *argv[])
{
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
}
I still cannot open a file, the error is "Too many open files ins system"
I still cannot rename a file, i write the exact syntax to rename a file ( mv name new_name ) but it said about moving a file.
Does my code incorrect?

Related

Linux kernel module : Is it possible to use an open function inside another open function for my module?

Maybe this question makes no sense, but I was wondering if there was a "recommended practice" on how to open a file descriptor for a device inside an open function of the created module.
In fact, I developped a simple Linux kernel module with its basic functions :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
I compile it and no errors occured.
Now I want to open the file descriptor of my device ( BUTTON ) in order to manipulate it later from user space program, so I made some modifications by adding the BUTTON device path and another open function like this :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
#define BTN_FILE_PATH "/dev/input/event0"
int file;
char *str = BTN_FILE_PATH;
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
if((file = open(str, O_RDONLY)) < 0) {
printk("simplekey: File can not open");
return(-1);
}
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
But the problem, when I try to compile the module now errors are printed :
/home/gaston/ledshared/exer_simple_char_drv.c: In function
‘exer_open’: /home/gaston/ledshared/exer_simple_char_drv.c:32:13:
error: implicit declaration of function ‘open’
[-Werror=implicit-function-declaration]
if((file = open(str,O_RDONLY)) < 0) {
How can I fix the problem please ?
open() is a user-space function. The equivalent kernel-space function is filp_open(), but it returns a struct file * instead of a int file descriptor. The returned struct file * could be an error code instead of a valid pointer. Use the IS_ERR(ptr) macro to check for that, and the PTR_ERR(ptr) macro to extract the error code (which will be a negated errno value).
Use of the filp_open function is discouraged, but here are some modifications to your code to use this function:
int exer_open(struct inode *pinode, struct file *pfile) {
struct file *f;
f = filp_open(str, O_RDONLY);
if (IS_ERR(f)) {
printk("simplekey: File can not open");
return(PTR_ERR(f));
}
pfile->private_data = f;
printk(KERN_INFO "Device has been opened\n");
return 0;
}
The close function should look something like this:
int exer_close(struct inode *pinode, struct file *pfile) {
struct file *f = pfile->private_data;
int rc;
rc = filp_close(f, NULL);
if (rc == 0) {
printk(KERN_INFO "Device successfully closed\n");
}
return rc;
}
There is no legitimate way for a module to read from a struct file * directly into a user-space buffer or write from a user-space buffer to a struct file *, so an intermediate buffer in kernel memory is needed, so that kernel_read() or kernel_write() can be used to read or write the file:
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
struct file *f = pfile->private_data;
enum { MAX_BUF_SIZE = 4096 };
size_t buf_size = 0;
char *buf = NULL;
ssize_t total = 0;
ssize_t rc = 0;
/* Allocate temporary buffer. */
if (length) {
buf_size = min_t(size_t, MAX_BUF_SIZE, length);
buf = kmalloc(buf_size, GFP_KERNEL);
if (buf == NULL) {
return -ENOMEM;
}
}
/* Read file to buffer in chunks. */
do {
size_t amount = min_t(size_t, length, buf_size);
rc = kernel_read(f, buf, amount, offset);
if (rc > 0) {
/* Have read some data from file. */
if (copy_to_user(buffer, buf, rc) != 0) {
/* Bad user memory! */
rc = -EFAULT;
} else {
/* Update totals. */
total += rc;
buffer += rc;
*offset += rc;
length -= rc;
if (rc < amount) {
/* Didn't read the full amount, so terminate early. */
rc = 0;
}
}
}
} while (rc > 0 && length > 0);
/* Free temporary buffer. */
kfree(buf);
if (total > 0) {
return total;
}
return rc;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
struct file *f = pfile->private_data;
enum { MAX_BUF_SIZE = 4096 };
size_t buf_size = 0;
char *buf = NULL;
ssize_t total = 0;
ssize_t rc = 0;
/* Allocate temporary buffer. */
if (length) {
buf_size = min_t(size_t, MAX_BUF_SIZE, length);
buf = kmalloc(buf_size, GFP_KERNEL);
if (buf == NULL) {
return -ENOMEM;
}
}
/* Write file from buffer in chunks. */
do {
size_t amount = min_t(size_t, length, buf_size);
if (copy_from_user(buf, buffer, amount) != 0) {
/* Bad user memory! */
rc = -EFAULT;
} else {
rc = kernel_write(f, buf, amount, offset);
if (rc > 0) {
/* Have written some data to file. */
/* Update totals. */
total += rc;
buffer += rc;
*offset += rc;
length -= rc;
if (rc < amount) {
/* Didn't write the full amount, so terminate early. */
rc = 0;
}
}
}
} while (rc > 0 && length > 0);
/* Free temporary buffer. */
kfree(buf);
if (total > 0) {
return total;
}
return rc;
}

C - little code, file descriptor, segmentation fault

I have write this code but i have a problem
first i have a function that create a file descriptor (fd)
int fd;//global
static int init_fd(int fd) {
remove("file descriptor.txt");//if yet present
fd = open("file descriptor.txt", O_WRONLY | O_CREAT, 0666);
if (fd == -1) {
printf("Error in opening the file descriptor!\n");
exit(0);
}
return fd;
}
the second function is a handler function
static int handler(struct connection *conn, enum event ev) {
...
int i;
for (i = 0; i < array_size; i++) {
if (!strncmp(conn->uri, uri_array[i], strlen(uri_array[i]))) {
func_array[i](conn->request_method, conn->uri, NULL, init_fd(fd));
close(fd);
fd = open("file descriptor.txt", O_RDONLY);
ret = read(fd, &buf, BUFSIZ);
if (ret == -1) {
printf("Error in reading!\n");
exit(0);
}
...
}
with fun_array is a pointer to function
httpCallback_t func_array[MAXARRAY];
and the function is
void http_serve1(const char *method, const char *path, const httpOptions_t *options, int fd) {
const char *string = "All is ok1!";
int ret_value;
// send header: 200 OK
ret_value = sendHeaders(fd, TIMEOUT_SEC, NETHTTP_HTTP_HEADER_200, NETHTTP_Content_Type_text_html_utf8, NETHTTP_CRLF, NULL);
// close the file descriptor
close(fd);
}
and the function sendHeaders is
size_t sendHeaders(int fd, int seconds, const char* header1, ...) {
va_list args;
va_start(args, header1);
size_t totalSize = 0;
const char* hdr = header1;
while (hdr != NULL) {
size_t result = sendHeaders(fd, seconds, hdr, NULL); // segmentation fault
if (result < 0) {
return result;
}
totalSize += result;
hdr = va_arg(args, const char*);
va_end(args);
return totalSize;
}
if (size == SIZE) {
setErrorCode(ERROR);
return ERROR;
}
size_t sizewrite = 1024;
tmp[size] = strdup(hdr);
write(fd, tmp, sizewrite);
setErrorCode(SUCCESS);
return SUCCESS;
}
my problem is that my code create a file descriptor, but it doesn't write inside, and during the run i have problem with segmentation fault. anyone have a suggest?

fuse changes chown to?

i m trying to modify fuse example to mount any directory. I want to mount /home/nikhil in tmp.
i ran it as,
$ ./ni /home/nikhil tmp
It mounts tmp folder, but cannot access it.
$ls -ltr tmp
ls: cannot access tmp: Operation not permitted
$ ls -ltr
ls: cannot access delete: Operation not permitted
total 11716
d????????? ? ? ? ? ? delete
My code is
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#define MAX 100
char *rootpath;
static void ni_fullpath(char fpath[MAX], const char *path){
strcpy(fpath, rootpath);
strncat(fpath, path, MAX);
}
static int ni_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
char fpath[MAX];
memset(stbuf, 0, sizeof(struct stat));
ni_fullpath(fpath, path);
res = lstat(fpath, stbuf);
return res;
}
static int ni_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
// i didnt understand this
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
ni_fullpath(fpath, path);
filler(buf, fpath + 1, NULL, 0);
return 0;
}
static int ni_open(const char *path, struct fuse_file_info *fi)
{
int fd;
char fpath[MAX];
ni_fullpath(fpath, path);
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
fd = open(fpath, fi->flags);
return fd;
}
static int ni_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
return pread(fi->fh, buf, size, offset);
}
static struct fuse_operations ni_oper = {
.getattr = ni_getattr,
.readdir = ni_readdir,
.open = ni_open,
.read = ni_read,
};
void ni_usage(){
fprintf(stderr, "usage ni rootDir mountPoint");
abort();
}
int main(int argc, char *argv[])
{
printf("%s %s \n", argv[1], argv[2]);
rootpath = realpath(argv[1], NULL);
argv[1] = argv[2];
argc--;
return fuse_main(argc, argv, &ni_oper, NULL);
}
Can anybody help what i m doing wrong ?
I m using ubuntu 1104 64 bit.
How about using uninitialized var fpath instead of path?
static int ni_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
char fpath[MAX];
memset(stbuf, 0, sizeof(struct stat));
res = lstat(fpath, stbuf);
return res;
}
You probably missed ni_fullpath(fpath, path);
And as far as I understand the 0 should be returned in open callback if success, so it should look like:
....
fd = open(fpath, fi->flags);
if (fd < 0)
return -errno;
fi->fh = fd;
return 0;
}
List operation should uses readdir callback, and in your case it has very limited application. It'd be better to start code on the basis of fusexmp. Check how readdir is implemented there.

FUSE file system crashed at opening file (only in release mode)

I have some problem, and i can't find solution of this :/ I need to open a text file inside my fuse filesystem. In debug everything works fine, but in release system is crashing. I made a simples example, with this. Could anybody tell what's wrong in this code?
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos#szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` hello.c -o hello
*/
# define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
void stripnl(char *str) {
while(strlen(str) && ( (str[strlen(str) - 1] == 13) ||
( str[strlen(str) - 1] == 10 ))) {
str[strlen(str) - 1] = 0;
}
}
static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
} else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
FILE *infile;
char fname[40];
char line[100];
int lcount;
/* We need to get rid of the newline char. */
stripnl(fname);
/* Open the file. If NULL is returned there was an error */
if((infile = fopen("ex.txt", "r")) == NULL) {
printf("Error Opening File.\n");
}
while( fgets(line, sizeof(line), infile) != NULL ) {
/* Get each line from the infile */
lcount++;
/* print the line number and data */
printf("Line %d: %s", lcount, line);
filler(buf, line, NULL, 0);
}
fclose(infile); /* Close the file */
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path, hello_path) != 0)
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0)
return -ENOENT;
len = strlen(hello_str);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, hello_str + offset, size);
} else
size = 0;
return size;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper, NULL);
}
Update
Ok, i've found solution, path must be absolute file path (not sure is this is proper sentence), but here is example code, which is working in release as well as in debug:
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos#szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` hello.c -o hello
*/
# define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
void stripnl(char *str) {
while(strlen(str) && ( (str[strlen(str) - 1] == 13) ||
( str[strlen(str) - 1] == 10 ))) {
str[strlen(str) - 1] = 0;
}
}
static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
} else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
FILE *infile;
char line[100];
if((infile = fopen("/root/Desktop/fexamples/ex.txt", "rb")) == NULL)
{
return -1;
}
while( fgets(line, sizeof(line), infile) != NULL )
{
filler(buf, line, NULL, 0);
}
fclose(infile); /* Close the file */
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path, hello_path) != 0)
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0)
return -ENOENT;
len = strlen(hello_str);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, hello_str + offset, size);
} else
size = 0;
return size;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper, NULL);
}
There are at least two issues in your readdir implementation.
char fname[40];
char line[100];
int lcount;
/* We need to get rid of the newline char. */
stripnl(fname);
You're acting on the contents of fname that you're not initializing anywhere. This could do just about anything. The fact that you're not using fname after that is irrelevant, you could be modifying completely random data with that stripnl call.
/* Open the file. If NULL is returned there was an error */
if((infile = fopen("ex.txt", "r")) == NULL) {
printf("Error Opening File.\n");
}
If fopen fails, you should error out (or just leave) this function. Otherwise the next line will call fgets with NULL as its file argument.
Ok, i've found solution, path must be absolute file path (not sure is this is proper sentence), but here is example code, which is working in release as well as in debug:
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos#szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` hello.c -o hello
*/
# define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
void stripnl(char *str) {
while(strlen(str) && ( (str[strlen(str) - 1] == 13) ||
( str[strlen(str) - 1] == 10 ))) {
str[strlen(str) - 1] = 0;
}
}
static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path, hello_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
} else
res = -ENOENT;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
FILE *infile;
char line[100];
if((infile = fopen("/root/Desktop/fexamples/ex.txt", "rb")) == NULL)
{
return -1;
}
while( fgets(line, sizeof(line), infile) != NULL )
{
filler(buf, line, NULL, 0);
}
fclose(infile); /* Close the file */
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path, hello_path) != 0)
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0)
return -ENOENT;
len = strlen(hello_str);
if (offset < len) {
if (offset + size > len)
size = len - offset;
memcpy(buf, hello_str + offset, size);
} else
size = 0;
return size;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &hello_oper, NULL);
}

Fuse Filesystem Problem

i'm developing a fuse filesystem that stores data in the RAM, but i'm having problems when i write something to a file. The file turns into a blank file.
Here's the code:
#define FUSE_USE_VERSION 26
#include <fuse/fuse.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
char hello_data[200] = {'h', 'e', 'l', 'l', 'o', '\n'};
int hello_size = 6;
int homsifs_getattr(const char* path, struct stat* stbuf)
{
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0)
stbuf->st_mode = S_IFDIR | 0666;
else if (strcmp(path, "/hello") == 0)
{
stbuf->st_mode = S_IFREG | 0666;
stbuf->st_size = hello_size;
}
else
return -ENOENT;
return 0;
}
int homsifs_readdir(const char* path, void* buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info* fi)
{
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, "hello", NULL, 0);
return 0;
}
int homsifs_open(const char* path, struct fuse_file_info* fi)
{
if (strcmp(path, "/hello") != 0)
return -ENOENT;
return 0;
}
int homsifs_read(const char* path, char* buf, size_t size, off_t offset,
struct fuse_file_info* fi)
{
int offset_size = hello_size - offset;
if (size > offset_size)
size = offset_size;
memcpy(buf, hello_data + offset, size);
return size;
}
int homsifs_truncate(const char* path, off_t size)
{
if (size > 200)
return -ENOMEM;
if (hello_size < size)
memset(hello_data + size, 0, size - hello_size);
hello_size = size;
return 0;
}
int homsifs_write(const char* path, const char* buf, size_t size, off_t offset,
struct fuse_file_info* fi)
{
if (strcmp(path, "/hello") != 0)
return -ENOENT;
memcpy(hello_data + offset, buf, size);
return size;
}
struct fuse_operations homsifs_operations =
{
.getattr = homsifs_getattr,
.readdir = homsifs_readdir,
.open = homsifs_open,
.read = homsifs_read,
.truncate = homsifs_truncate,
.write = homsifs_write
};
int main(int argc, char** argv)
{
return fuse_main(argc, argv, &homsifs_operations, NULL);
}
Anyone knows what's wrong?
Thanks.
When a program opens the file for writing, it gets truncated. After that, any data written is inaccessible because you're not correctly updating hello_size in homsifs_write.

Resources