bbfs.c =Joseph J. Pfeiffer - Пример файловой системы во FUSE
Primary tabs
Forums:
[об авторе]
[основная тема]
содержимое файла (не забудьте исправить #include инструкции) = код в комментарии
- Log in to post comments
- 5132 reads
[об авторе]
[основная тема]
содержимое файла (не забудьте исправить #include инструкции) = код в комментарии
vedro-compota
Sat, 02/04/2012 - 02:02
Permalink
/*
/* Big Brother File System Файловая система Большого Брата The point of this FUSE filesystem is to provide an introduction to FUSE. It was my first FUSE filesystem as I got to know the software; hopefully, the comments in this code will help people who follow later to get a gentler introduction. This might be called a no-op filesystem: it doesn't impose filesystem semantics on top of any other existing structure. It simply reports the requests that come in, and passes them to an underlying filesystem. The information is saved in a logfile named bbfs.log, in the directory from which you run bbfs. gcc -Wall `pkg-config fuse --cflags --libs` -o bbfs bbfs.c Файловая система Большого Брата Целью этой системы является создание своеобразного "вступления" к работе с FUSE - то есть примера, который поможет разобраться с основными моментами использования возможностей FUSE Это моя первая файловая система в рамках знакомства с программным обеспечением , Надеюсь, что она будет способствовать тому, чтобы всем кто будет изучать FUSE после меня - это изучение давалось значительно легче. Данную файловую систему можно назвать "пустой" -она НЕ ПРОИЗВОДИТ САМОСТОЯТЕЛЬНО НИКАКОЙ РАБОТЫ СО СТРУКТУРАМИ ДАННЫХ( - не хранит всю информацию о файловой системе - её иерархии - содержимом папок и файлов , например , в собственном бинарном файле - не использует самостоятельно никакую структуру представления данных для хранения файловой системы ) - данная файловая система ПРОСТО ОТВЕЧАЕТ НА ПОСТУПАЮЩИЕ ИЗВНЕ ЗАПРОСЫ И ПЕРЕНАПРАВЛЯЕТ ИХ к нижележащей файловой системе (например , той, которая по-умолчанию используется вашей операционный системой). Информация о произведённых действиях просто сохраняется в файл bbfs.log - который располагается в той же директории , откуда был запущен скомпилированный код данного файла */ #include "params.h" #include ctype.h> #include dirent.h> #include errno.h> #include fcntl.h> #include fuse.h> #include libgen.h> #include limits.h> #include stdlib.h> #include stdio.h> #include string.h> #include unistd.h> #include sys/types.h> #include sys/xattr.h> #include "log.h" // поключаем заголовок - чать этого проекта // Report errors to logfile and give -errno to calle // Делаем записи об ошибках в logfile и передаём сведения об ошибке в виде -errno static int bb_error(char *str) { int ret = -errno; log_msg(" ERROR %s: %s\n", str, strerror(errno)); return ret; } // Check whether the given user is permitted to perform the given operation on the given // All the paths I see are relative to the root of the mounted // filesystem. In order to get to the underlying filesystem, I need to // have the mountpoint. I'll save it away early on in main(), and then // whenever I need a path for something I'll call this to construct // it. static void bb_fullpath(char fpath[PATH_MAX], const char *path) { strcpy(fpath, BB_DATA->rootdir); strncat(fpath, path, PATH_MAX); // ridiculously long paths will // break here log_msg(" bb_fullpath: rootdir = \"%s\", path = \"%s\", fpath = \"%s\"\n", BB_DATA->rootdir, path, fpath); } /////////////////////////////////////////////////////////// // // Prototypes for all these functions, and the C-style comments, // come indirectly from /usr/include/fuse.h // /** Get file attributes. * * Similar to stat(). The 'st_dev' and 'st_blksize' fields are * ignored. The 'st_ino' field is ignored except if the 'use_ino' * mount option is given. */ int bb_getattr(const char *path, struct stat *statbuf) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_getattr(path=\"%s\", statbuf=0x%08x)\n", path, statbuf); bb_fullpath(fpath, path); retstat = lstat(fpath, statbuf); if (retstat != 0) retstat = bb_error("bb_getattr lstat"); log_stat(statbuf); return retstat; } /** Read the target of a symbolic link Читает цель, записанную в виде символов * * The buffer should be filled with a null terminated string. The * buffer size argument includes the space for the terminating * null character. If the linkname is too long to fit in the * buffer, it should be truncated. The return value should be 0 * for success. Буфер должен быть заполнен строкой-ссылкой которая заканчивается символом \0 - null Причём размер буфера подразумевает место для этого null-символа Если связующее имя ссылки слишком длинное для того, чтобы уместится в буфере , оно должно быть сокращено. Признак успешного выполнения это 0 в качестве возвращаемого значения. */ // Note the system readlink() will truncate and lose the terminating // null. So, the size passed to the system readlink() must be one // less than the size passed to bb_readlink() // bb_readlink() code by Bernardo F Costa (thanks!) /* ВНИМАНИЕ = системная функция readlink() не добавляет null символ к передаваемой строке , который должен завершать строку, содержащую имя, потому путь передаваемый передаваемый в readlink() должен быть на один символ меньше пути для bb_readlink() - так как */ int bb_readlink(const char *path, char *link, size_t size) { int retstat = 0; char fpath[PATH_MAX]; log_msg("bb_readlink(path=\"%s\", link=\"%s\", size=%d)\n", path, link, size); bb_fullpath(fpath, path); retstat = readlink(fpath, link, size - 1); // передаём на сивол меньше if (retstat < 0) retstat = bb_error("bb_readlink readlink"); else { link[retstat] = '\0'; // завершаем строку спец-символом retstat = 0; } return retstat; } /** Create a file node * * There is no create() operation, mknod() will be called for * creation of all non-directory, non-symlink nodes. */ // shouldn't that comment be "if" there is no.... ? int bb_mknod(const char *path, mode_t mode, dev_t dev) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_mknod(path=\"%s\", mode=0%3o, dev=%lld)\n", path, mode, dev); bb_fullpath(fpath, path); // On Linux this could just be 'mknod(path, mode, rdev)' but this // is more portable if (S_ISREG(mode)) { retstat = open(fpath, O_CREAT | O_EXCL | O_WRONLY, mode); if (retstat < 0) retstat = bb_error("bb_mknod open"); else { retstat = close(retstat); if (retstat < 0) retstat = bb_error("bb_mknod close"); } } else if (S_ISFIFO(mode)) { retstat = mkfifo(fpath, mode); if (retstat < 0) retstat = bb_error("bb_mknod mkfifo"); } else { retstat = mknod(fpath, mode, dev); if (retstat < 0) retstat = bb_error("bb_mknod mknod"); } return retstat; } /** Create a directory Описываем создание директории*/ int bb_mkdir(const char *path, mode_t mode) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_mkdir(path=\"%s\", mode=0%3o)\n", path, mode); bb_fullpath(fpath, path); retstat = mkdir(fpath, mode); if (retstat < 0) retstat = bb_error("bb_mkdir mkdir"); return retstat; } /** Remove a file */ int bb_unlink(const char *path) { int retstat = 0; char fpath[PATH_MAX]; log_msg("bb_unlink(path=\"%s\")\n", path); bb_fullpath(fpath, path); retstat = unlink(fpath); if (retstat < 0) retstat = bb_error("bb_unlink unlink"); return retstat; } /** Remove a directory */ int bb_rmdir(const char *path) { int retstat = 0; char fpath[PATH_MAX]; log_msg("bb_rmdir(path=\"%s\")\n", path); bb_fullpath(fpath, path); retstat = rmdir(fpath); if (retstat < 0) retstat = bb_error("bb_rmdir rmdir"); return retstat; } /** Create a symbolic link */ // The parameters here are a little bit confusing, but do correspond // to the symlink() system call. The 'path' is where the link points, // while the 'link' is the link itself. So we need to leave the path // unaltered, but insert the link into the mounted directory. int bb_symlink(const char *path, const char *link) { int retstat = 0; char flink[PATH_MAX]; log_msg("\nbb_symlink(path=\"%s\", link=\"%s\")\n", path, link); bb_fullpath(flink, link); retstat = symlink(path, flink); if (retstat < 0) retstat = bb_error("bb_symlink symlink"); return retstat; } /** Rename a file */ // both path and newpath are fs-relative int bb_rename(const char *path, const char *newpath) { int retstat = 0; char fpath[PATH_MAX]; char fnewpath[PATH_MAX]; log_msg("\nbb_rename(fpath=\"%s\", newpath=\"%s\")\n", path, newpath); bb_fullpath(fpath, path); bb_fullpath(fnewpath, newpath); retstat = rename(fpath, fnewpath); if (retstat < 0) retstat = bb_error("bb_rename rename"); return retstat; } /** Create a hard link to a file */ int bb_link(const char *path, const char *newpath) { int retstat = 0; char fpath[PATH_MAX], fnewpath[PATH_MAX]; log_msg("\nbb_link(path=\"%s\", newpath=\"%s\")\n", path, newpath); bb_fullpath(fpath, path); bb_fullpath(fnewpath, newpath); retstat = link(fpath, fnewpath); if (retstat < 0) retstat = bb_error("bb_link link"); return retstat; } /** Change the permission bits of a file */ int bb_chmod(const char *path, mode_t mode) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_chmod(fpath=\"%s\", mode=0%03o)\n", path, mode); bb_fullpath(fpath, path); retstat = chmod(fpath, mode); if (retstat < 0) retstat = bb_error("bb_chmod chmod"); return retstat; } /** Change the owner and group of a file */ int bb_chown(const char *path, uid_t uid, gid_t gid) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_chown(path=\"%s\", uid=%d, gid=%d)\n", path, uid, gid); bb_fullpath(fpath, path); retstat = chown(fpath, uid, gid); if (retstat < 0) retstat = bb_error("bb_chown chown"); return retstat; } /** Change the size of a file */ int bb_truncate(const char *path, off_t newsize) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_truncate(path=\"%s\", newsize=%lld)\n", path, newsize); bb_fullpath(fpath, path); retstat = truncate(fpath, newsize); if (retstat < 0) bb_error("bb_truncate truncate"); return retstat; } /** Change the access and/or modification times of a file */ /* note -- I'll want to change this as soon as 2.6 is in debian testing */ int bb_utime(const char *path, struct utimbuf *ubuf) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_utime(path=\"%s\", ubuf=0x%08x)\n", path, ubuf); bb_fullpath(fpath, path); retstat = utime(fpath, ubuf); if (retstat < 0) retstat = bb_error("bb_utime utime"); return retstat; } /** File open operation * * No creation, or truncation flags (O_CREAT, O_EXCL, O_TRUNC) * will be passed to open(). Open should check if the operation * is permitted for the given flags. Optionally open may also * return an arbitrary filehandle in the fuse_file_info structure, * which will be passed to all file operations. * * Changed in version 2.2 */ int bb_open(const char *path, struct fuse_file_info *fi) { int retstat = 0; int fd; char fpath[PATH_MAX]; log_msg("\nbb_open(path\"%s\", fi=0x%08x)\n", path, fi); bb_fullpath(fpath, path); fd = open(fpath, fi->flags); if (fd < 0) retstat = bb_error("bb_open open"); fi->fh = fd; log_fi(fi); return retstat; } /** Read data from an open file * * Read should return exactly the number of bytes requested except * on EOF or error, otherwise the rest of the data will be * substituted with zeroes. An exception to this is when the * 'direct_io' mount option is specified, in which case the return * value of the read system call will reflect the return value of * this operation. * * Changed in version 2.2 */ // I don't fully understand the documentation above -- it doesn't // match the documentation for the read() system call which says it // can return with anything up to the amount of data requested. nor // with the fusexmp code which returns the amount of data also // returned by read. int bb_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_read(path=\"%s\", buf=0x%08x, size=%d, offset=%lld, fi=0x%08x)\n", path, buf, size, offset, fi); // no need to get fpath on this one, since I work from fi->fh not the path log_fi(fi); retstat = pread(fi->fh, buf, size, offset); if (retstat < 0) retstat = bb_error("bb_read read"); return retstat; } /** Write data to an open file * * Write should return exactly the number of bytes requested * except on error. An exception to this is when the 'direct_io' * mount option is specified (see read operation). * * Changed in version 2.2 */ // As with read(), the documentation above is inconsistent with the // documentation for the write() system call. int bb_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_write(path=\"%s\", buf=0x%08x, size=%d, offset=%lld, fi=0x%08x)\n", path, buf, size, offset, fi ); // no need to get fpath on this one, since I work from fi->fh not the path log_fi(fi); retstat = pwrite(fi->fh, buf, size, offset); if (retstat < 0) retstat = bb_error("bb_write pwrite"); return retstat; } /** Get file system statistics * * The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored * * Replaced 'struct statfs' parameter with 'struct statvfs' in * version 2.5 */ int bb_statfs(const char *path, struct statvfs *statv) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_statfs(path=\"%s\", statv=0x%08x)\n", path, statv); bb_fullpath(fpath, path); // get stats for underlying filesystem retstat = statvfs(fpath, statv); if (retstat < 0) retstat = bb_error("bb_statfs statvfs"); log_statvfs(statv); return retstat; } /** Possibly flush cached data * * BIG NOTE: This is not equivalent to fsync(). It's not a * request to sync dirty data. * * Flush is called on each close() of a file descriptor. So if a * filesystem wants to return write errors in close() and the file * has cached dirty data, this is a good place to write back data * and return any errors. Since many applications ignore close() * errors this is not always useful. * * NOTE: The flush() method may be called more than once for each * open(). This happens if more than one file descriptor refers * to an opened file due to dup(), dup2() or fork() calls. It is * not possible to determine if a flush is final, so each flush * should be treated equally. Multiple write-flush sequences are * relatively rare, so this shouldn't be a problem. * * Filesystems shouldn't assume that flush will always be called * after some writes, or that if will be called at all. * * Changed in version 2.2 */ int bb_flush(const char *path, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_flush(path=\"%s\", fi=0x%08x)\n", path, fi); // no need to get fpath on this one, since I work from fi->fh not the path log_fi(fi); return retstat; } /** Release an open file * * Release is called when there are no more references to an open * file: all file descriptors are closed and all memory mappings * are unmapped. * * For every open() call there will be exactly one release() call * with the same flags and file descriptor. It is possible to * have a file opened more than once, in which case only the last * release will mean, that no more reads/writes will happen on the * file. The return value of release is ignored. * * Changed in version 2.2 */ int bb_release(const char *path, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_release(path=\"%s\", fi=0x%08x)\n", path, fi); log_fi(fi); // We need to close the file. Had we allocated any resources // (buffers etc) we'd need to free them here as well. retstat = close(fi->fh); return retstat; } /** Synchronize file contents * * If the datasync parameter is non-zero, then only the user data * should be flushed, not the meta data. * * Changed in version 2.2 */ int bb_fsync(const char *path, int datasync, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_fsync(path=\"%s\", datasync=%d, fi=0x%08x)\n", path, datasync, fi); log_fi(fi); if (datasync) retstat = fdatasync(fi->fh); else retstat = fsync(fi->fh); if (retstat < 0) bb_error("bb_fsync fsync"); return retstat; } /** Set extended attributes */ int bb_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_setxattr(path=\"%s\", name=\"%s\", value=\"%s\", size=%d, flags=0x%08x)\n", path, name, value, size, flags); bb_fullpath(fpath, path); retstat = lsetxattr(fpath, name, value, size, flags); if (retstat < 0) retstat = bb_error("bb_setxattr lsetxattr"); return retstat; } /** Get extended attributes */ int bb_getxattr(const char *path, const char *name, char *value, size_t size) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_getxattr(path = \"%s\", name = \"%s\", value = 0x%08x, size = %d)\n", path, name, value, size); bb_fullpath(fpath, path); retstat = lgetxattr(fpath, name, value, size); if (retstat < 0) retstat = bb_error("bb_getxattr lgetxattr"); else log_msg(" value = \"%s\"\n", value); return retstat; } /** List extended attributes */ int bb_listxattr(const char *path, char *list, size_t size) { int retstat = 0; char fpath[PATH_MAX]; char *ptr; log_msg("bb_listxattr(path=\"%s\", list=0x%08x, size=%d)\n", path, list, size ); bb_fullpath(fpath, path); retstat = llistxattr(fpath, list, size); if (retstat < 0) retstat = bb_error("bb_listxattr llistxattr"); log_msg(" returned attributes (length %d):\n", retstat); for (ptr = list; ptr < list + retstat; ptr += strlen(ptr)+1) log_msg(" \"%s\"\n", ptr); return retstat; } /** Remove extended attributes */ int bb_removexattr(const char *path, const char *name) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_removexattr(path=\"%s\", name=\"%s\")\n", path, name); bb_fullpath(fpath, path); retstat = lremovexattr(fpath, name); if (retstat < 0) retstat = bb_error("bb_removexattr lrmovexattr"); return retstat; } /** Open directory * * This method should check if the open operation is permitted for * this directory * * Introduced in version 2.3 */ int bb_opendir(const char *path, struct fuse_file_info *fi) { DIR *dp; int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_opendir(path=\"%s\", fi=0x%08x)\n", path, fi); bb_fullpath(fpath, path); dp = opendir(fpath); if (dp == NULL) retstat = bb_error("bb_opendir opendir"); fi->fh = (intptr_t) dp; log_fi(fi); return retstat; } /** Read directory * * This supersedes the old getdir() interface. New applications * should use this. * * The filesystem may choose between two modes of operation: * * 1) The readdir implementation ignores the offset parameter, and * passes zero to the filler function's offset. The filler * function will not return '1' (unless an error happens), so the * whole directory is read in a single readdir operation. This * works just like the old getdir() method. * * 2) The readdir implementation keeps track of the offsets of the * directory entries. It uses the offset parameter and always * passes non-zero offset to the filler function. When the buffer * is full (or an error happens) the filler function will return * '1'. * * Introduced in version 2.3 */ int bb_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { int retstat = 0; DIR *dp; struct dirent *de; log_msg("\nbb_readdir(path=\"%s\", buf=0x%08x, filler=0x%08x, offset=%lld, fi=0x%08x)\n", path, buf, filler, offset, fi); // once again, no need for fullpath -- but note that I need to cast fi->fh dp = (DIR *) (uintptr_t) fi->fh; // Every directory contains at least two entries: . and .. If my // first call to the system readdir() returns NULL I've got an // error; near as I can tell, that's the only condition under // which I can get an error from readdir() de = readdir(dp); if (de == 0) { retstat = bb_error("bb_readdir readdir"); return retstat; } // This will copy the entire directory into the buffer. The loop exits // when either the system readdir() returns NULL, or filler() // returns something non-zero. The first case just means I've // read the whole directory; the second means the buffer is full. do { log_msg("calling filler with name %s\n", de->d_name); if (filler(buf, de->d_name, NULL, 0) != 0) { log_msg(" ERROR bb_readdir filler: buffer full"); return -ENOMEM; } } while ((de = readdir(dp)) != NULL); log_fi(fi); return retstat; } /** Release directory * * Introduced in version 2.3 */ int bb_releasedir(const char *path, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_releasedir(path=\"%s\", fi=0x%08x)\n", path, fi); log_fi(fi); closedir((DIR *) (uintptr_t) fi->fh); return retstat; } /** Synchronize directory contents * * If the datasync parameter is non-zero, then only the user data * should be flushed, not the meta data * * Introduced in version 2.3 */ // when exactly is this called? when a user calls fsync and it // happens to be a directory? ??? int bb_fsyncdir(const char *path, int datasync, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_fsyncdir(path=\"%s\", datasync=%d, fi=0x%08x)\n", path, datasync, fi); log_fi(fi); return retstat; } /** * Initialize filesystem * * The return value will passed in the private_data field of * fuse_context to all file operations and as a parameter to the * destroy() method. * * Introduced in version 2.3 * Changed in version 2.6 */ // Undocumented but extraordinarily useful fact: the fuse_context is // set up before this function is called, and // fuse_get_context()->private_data returns the user_data passed to // fuse_main(). Really seems like either it should be a third // parameter coming in here, or else the fact should be documented // (and this might as well return void, as it did in older versions of // FUSE). void *bb_init(struct fuse_conn_info *conn) { log_msg("\nbb_init()\n"); return BB_DATA; } /** * Clean up filesystem * * Called on filesystem exit. * * Introduced in version 2.3 */ void bb_destroy(void *userdata) { log_msg("\nbb_destroy(userdata=0x%08x)\n", userdata); } /** * Check file access permissions * * This will be called for the access() system call. If the * 'default_permissions' mount option is given, this method is not * called. * * This method is not called under Linux kernel versions 2.4.x * * Introduced in version 2.5 */ int bb_access(const char *path, int mask) { int retstat = 0; char fpath[PATH_MAX]; log_msg("\nbb_access(path=\"%s\", mask=0%o)\n", path, mask); bb_fullpath(fpath, path); retstat = access(fpath, mask); if (retstat < 0) retstat = bb_error("bb_access access"); return retstat; } /** * Create and open a file * * If the file does not exist, first create it with the specified * mode, and then open it. * * If this method is not implemented or under Linux kernel * versions earlier than 2.6.15, the mknod() and open() methods * will be called instead. * * Introduced in version 2.5 */ int bb_create(const char *path, mode_t mode, struct fuse_file_info *fi) { int retstat = 0; char fpath[PATH_MAX]; int fd; log_msg("\nbb_create(path=\"%s\", mode=0%03o, fi=0x%08x)\n", path, mode, fi); bb_fullpath(fpath, path); fd = creat(fpath, mode); if (fd < 0) retstat = bb_error("bb_create creat"); fi->fh = fd; log_fi(fi); return retstat; } /** * Change the size of an open file * * This method is called instead of the truncate() method if the * truncation was invoked from an ftruncate() system call. * * If this method is not implemented or under Linux kernel * versions earlier than 2.6.15, the truncate() method will be * called instead. * * Introduced in version 2.5 */ int bb_ftruncate(const char *path, off_t offset, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_ftruncate(path=\"%s\", offset=%lld, fi=0x%08x)\n", path, offset, fi); log_fi(fi); retstat = ftruncate(fi->fh, offset); if (retstat < 0) retstat = bb_error("bb_ftruncate ftruncate"); return retstat; } /** * Get attributes from an open file * * This method is called instead of the getattr() method if the * file information is available. * * Currently this is only called after the create() method if that * is implemented (see above). Later it may be called for * invocations of fstat() too. * * Introduced in version 2.5 */ // Since it's currently only called after bb_create(), and bb_create() // opens the file, I ought to be able to just use the fd and ignore // the path... int bb_fgetattr(const char *path, struct stat *statbuf, struct fuse_file_info *fi) { int retstat = 0; log_msg("\nbb_fgetattr(path=\"%s\", statbuf=0x%08x, fi=0x%08x)\n", path, statbuf, fi); log_fi(fi); retstat = fstat(fi->fh, statbuf); if (retstat < 0) retstat = bb_error("bb_fgetattr fstat"); log_stat(statbuf); return retstat; } struct fuse_operations bb_oper = { .getattr = bb_getattr, .readlink = bb_readlink, // no .getdir -- that's deprecated .getdir = NULL, .mknod = bb_mknod, .mkdir = bb_mkdir, .unlink = bb_unlink, .rmdir = bb_rmdir, .symlink = bb_symlink, .rename = bb_rename, .link = bb_link, .chmod = bb_chmod, .chown = bb_chown, .truncate = bb_truncate, .utime = bb_utime, .open = bb_open, .read = bb_read, .write = bb_write, /** Just a placeholder, don't set */ // huh??? .statfs = bb_statfs, .flush = bb_flush, .release = bb_release, .fsync = bb_fsync, .setxattr = bb_setxattr, .getxattr = bb_getxattr, .listxattr = bb_listxattr, .removexattr = bb_removexattr, .opendir = bb_opendir, .readdir = bb_readdir, .releasedir = bb_releasedir, .fsyncdir = bb_fsyncdir, .init = bb_init, .destroy = bb_destroy, .access = bb_access, .create = bb_create, .ftruncate = bb_ftruncate, .fgetattr = bb_fgetattr }; void bb_usage() { fprintf(stderr, "usage: bbfs rootDir mountPoint\n"); abort(); } int main(int argc, char *argv[]) { int i; int fuse_stat; struct bb_state *bb_data; // bbfs doesn't do any access checking on its own (the comment // blocks in fuse.h mention some of the functions that need // accesses checked -- but note there are other functions, like // chown(), that also need checking!). Since running bbfs as root // will therefore open Metrodome-sized holes in the system // security, we'll check if root is trying to mount the filesystem // and refuse if it is. The somewhat smaller hole of an ordinary // user doing it with the allow_other flag is still there because // I don't want to parse the options string. if ((getuid() == 0) || (geteuid() == 0)) { fprintf(stderr, "Running BBFS as root opens unnacceptable security holes\n"); return 1; } bb_data = calloc(sizeof(struct bb_state), 1); if (bb_data == NULL) { perror("main calloc"); abort(); } bb_data->logfile = log_open(); // libfuse is able to do most of the command line parsing; all I // need to do is to extract the rootdir; this will be the first // non-option passed in. I'm using the GNU non-standard extension // and having realpath malloc the space for the path // the string. for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) if (argv[i][1] == 'o') i++; // -o takes a parameter; need to // skip it too. This doesn't // handle "squashed" parameters if ((argc - i) != 2) bb_usage(); bb_data->rootdir = realpath(argv[i], NULL); argv[i] = argv[i+1]; argc--; fprintf(stderr, "about to call fuse_main\n"); fuse_stat = fuse_main(argc, argv, &bb_oper, bb_data); fprintf(stderr, "fuse_main returned %d\n", fuse_stat); return fuse_stat; }_____________
матфак вгу и остальная классика =)