Fsutil: added option -m to mount the filesystem via FUSE.
This commit is contained in:
@@ -1,12 +1,16 @@
|
|||||||
CC = gcc -g
|
CC = gcc -g
|
||||||
CFLAGS = -O -Wall
|
CFLAGS = -O -Wall
|
||||||
DESTDIR = /usr/local
|
DESTDIR = /usr/local
|
||||||
OBJS = fsutil.o superblock.o block.c inode.o create.o check.o file.o
|
OBJS = fsutil.o superblock.o block.c inode.o create.o check.o file.o mount.o
|
||||||
PROG = fsutil
|
PROG = fsutil
|
||||||
|
|
||||||
# For Mac OS X
|
# For Mac OS X
|
||||||
#LIBS = -largp
|
#LIBS = -largp
|
||||||
|
|
||||||
|
# Fuse
|
||||||
|
CFLAGS += $(shell pkg-config fuse --cflags)
|
||||||
|
LIBS += $(shell pkg-config fuse --libs)
|
||||||
|
|
||||||
all: $(PROG)
|
all: $(PROG)
|
||||||
|
|
||||||
install: $(PROG)
|
install: $(PROG)
|
||||||
|
|||||||
@@ -52,8 +52,6 @@
|
|||||||
*/
|
*/
|
||||||
#define MAXMNTLEN 28
|
#define MAXMNTLEN 28
|
||||||
|
|
||||||
#define MAXNAMLEN 63
|
|
||||||
|
|
||||||
#define FSMAGIC1 ('F' | 'S'<<8 | '<'<<16 | '<'<<24)
|
#define FSMAGIC1 ('F' | 'S'<<8 | '<'<<16 | '<'<<24)
|
||||||
#define FSMAGIC2 ('>' | '>'<<8 | 'F'<<16 | 'S'<<24)
|
#define FSMAGIC2 ('>' | '>'<<8 | 'F'<<16 | 'S'<<24)
|
||||||
|
|
||||||
@@ -135,7 +133,7 @@ typedef struct {
|
|||||||
unsigned ino;
|
unsigned ino;
|
||||||
unsigned reclen;
|
unsigned reclen;
|
||||||
unsigned namlen;
|
unsigned namlen;
|
||||||
char name [MAXNAMLEN+1];
|
char name [63+1];
|
||||||
} fs_dirent_t;
|
} fs_dirent_t;
|
||||||
|
|
||||||
typedef void (*fs_directory_scanner_t) (fs_inode_t *dir,
|
typedef void (*fs_directory_scanner_t) (fs_inode_t *dir,
|
||||||
@@ -166,6 +164,8 @@ int fs_create (fs_t *fs, const char *filename, unsigned kbytes,
|
|||||||
int fs_check (fs_t *fs);
|
int fs_check (fs_t *fs);
|
||||||
void fs_print (fs_t *fs, FILE *out);
|
void fs_print (fs_t *fs, FILE *out);
|
||||||
|
|
||||||
|
int fs_mount(fs_t *fs, char *dirname);
|
||||||
|
|
||||||
int fs_inode_get (fs_t *fs, fs_inode_t *inode, unsigned inum);
|
int fs_inode_get (fs_t *fs, fs_inode_t *inode, unsigned inum);
|
||||||
int fs_inode_save (fs_inode_t *inode, int force);
|
int fs_inode_save (fs_inode_t *inode, int force);
|
||||||
void fs_inode_clear (fs_inode_t *inode);
|
void fs_inode_clear (fs_inode_t *inode);
|
||||||
@@ -176,7 +176,7 @@ int fs_inode_read (fs_inode_t *inode, unsigned long offset,
|
|||||||
int fs_inode_write (fs_inode_t *inode, unsigned long offset,
|
int fs_inode_write (fs_inode_t *inode, unsigned long offset,
|
||||||
unsigned char *data, unsigned long bytes);
|
unsigned char *data, unsigned long bytes);
|
||||||
int fs_inode_alloc (fs_t *fs, fs_inode_t *inode);
|
int fs_inode_alloc (fs_t *fs, fs_inode_t *inode);
|
||||||
int fs_inode_by_name (fs_t *fs, fs_inode_t *inode, char *name,
|
int fs_inode_by_name (fs_t *fs, fs_inode_t *inode, const char *name,
|
||||||
int op, int mode);
|
int op, int mode);
|
||||||
int inode_build_list (fs_t *fs);
|
int inode_build_list (fs_t *fs);
|
||||||
|
|
||||||
|
|||||||
@@ -37,12 +37,13 @@ int add;
|
|||||||
int newfs;
|
int newfs;
|
||||||
int check;
|
int check;
|
||||||
int fix;
|
int fix;
|
||||||
|
int mount;
|
||||||
unsigned kbytes;
|
unsigned kbytes;
|
||||||
unsigned swap_kbytes;
|
unsigned swap_kbytes;
|
||||||
|
|
||||||
static const char *program_version =
|
static const char *program_version =
|
||||||
"BSD 2.x file system utility, version 1.0\n"
|
"BSD 2.x file system utility, version 1.1\n"
|
||||||
"Copyright (C) 2011 Serge Vakulenko";
|
"Copyright (C) 2011-2014 Serge Vakulenko";
|
||||||
|
|
||||||
static const char *program_bug_address = "<serge@vak.ru>";
|
static const char *program_bug_address = "<serge@vak.ru>";
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ static struct option program_options[] = {
|
|||||||
{ "extract", no_argument, 0, 'x' },
|
{ "extract", no_argument, 0, 'x' },
|
||||||
{ "check", no_argument, 0, 'c' },
|
{ "check", no_argument, 0, 'c' },
|
||||||
{ "fix", no_argument, 0, 'f' },
|
{ "fix", no_argument, 0, 'f' },
|
||||||
|
{ "mount", no_argument, 0, 'm' },
|
||||||
{ "new", required_argument, 0, 'n' },
|
{ "new", required_argument, 0, 'n' },
|
||||||
{ "swap", required_argument, 0, 's' },
|
{ "swap", required_argument, 0, 's' },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
@@ -70,11 +72,12 @@ static void print_help (char *progname)
|
|||||||
"see the GNU General Public License for more details.\n");
|
"see the GNU General Public License for more details.\n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf ("Usage:\n");
|
printf ("Usage:\n");
|
||||||
printf (" %s [--verbose] filesys.bin\n", progname);
|
printf (" %s [--verbose] filesys.img\n", progname);
|
||||||
printf (" %s --add filesys.bin files...\n", progname);
|
printf (" %s --add filesys.img files...\n", progname);
|
||||||
printf (" %s --extract filesys.bin\n", progname);
|
printf (" %s --extract filesys.img\n", progname);
|
||||||
printf (" %s --check [--fix] filesys.bin\n", progname);
|
printf (" %s --check [--fix] filesys.img\n", progname);
|
||||||
printf (" %s --new=kbytes [--swap=kbytes] filesys.bin\n", progname);
|
printf (" %s --new=kbytes [--swap=kbytes] filesys.img\n", progname);
|
||||||
|
printf (" %s --mount filesys.img dir\n", progname);
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
printf ("Options:\n");
|
printf ("Options:\n");
|
||||||
printf (" -a, --add Add files to filesystem.\n");
|
printf (" -a, --add Add files to filesystem.\n");
|
||||||
@@ -83,7 +86,8 @@ static void print_help (char *progname)
|
|||||||
printf (" -f, --fix Fix bugs in filesystem.\n");
|
printf (" -f, --fix Fix bugs in filesystem.\n");
|
||||||
printf (" -n NUM, --new=NUM Create new filesystem, size in kbytes.\n");
|
printf (" -n NUM, --new=NUM Create new filesystem, size in kbytes.\n");
|
||||||
printf (" -s NUM, --swap=NUM Size of swap area in kbytes.\n");
|
printf (" -s NUM, --swap=NUM Size of swap area in kbytes.\n");
|
||||||
printf (" -v, --verbose Print verbose information.\n");
|
printf (" -m, --mount Mount the filesystem.\n");
|
||||||
|
printf (" -v, --verbose Be verbose.\n");
|
||||||
printf (" -V, --version Print version information and then exit.\n");
|
printf (" -V, --version Print version information and then exit.\n");
|
||||||
printf (" -h, --help Print this message.\n");
|
printf (" -h, --help Print this message.\n");
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
@@ -415,7 +419,7 @@ int main (int argc, char **argv)
|
|||||||
fs_inode_t inode;
|
fs_inode_t inode;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
key = getopt_long (argc, argv, "vaxn:cfs:",
|
key = getopt_long (argc, argv, "vaxmn:cfs:",
|
||||||
program_options, 0);
|
program_options, 0);
|
||||||
if (key == -1)
|
if (key == -1)
|
||||||
break;
|
break;
|
||||||
@@ -439,6 +443,9 @@ int main (int argc, char **argv)
|
|||||||
case 'f':
|
case 'f':
|
||||||
++fix;
|
++fix;
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
++mount;
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
swap_kbytes = strtol (optarg, 0, 0);
|
swap_kbytes = strtol (optarg, 0, 0);
|
||||||
break;
|
break;
|
||||||
@@ -454,8 +461,9 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = optind;
|
i = optind;
|
||||||
if ((! add && i != argc-1) || (add && i >= argc) ||
|
if ((! add && ! mount && i != argc-1) || (add && i >= argc) ||
|
||||||
(extract + newfs + check + add > 1) ||
|
(mount && i != argc-2) ||
|
||||||
|
(extract + newfs + check + add + mount > 1) ||
|
||||||
(newfs && kbytes < BSDFS_BSIZE * 10 / 1024)) {
|
(newfs && kbytes < BSDFS_BSIZE * 10 / 1024)) {
|
||||||
print_help (argv[0]);
|
print_help (argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -509,6 +517,15 @@ int main (int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mount) {
|
||||||
|
/* Mount the filesystem. */
|
||||||
|
if (++i >= argc) {
|
||||||
|
print_help (argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fs_mount(&fs, argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Print the structure of flesystem. */
|
/* Print the structure of flesystem. */
|
||||||
fs_print (&fs, stdout);
|
fs_print (&fs, stdout);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|||||||
@@ -544,12 +544,12 @@ void fs_dirent_unpack (fs_dirent_t *dirent, unsigned char *data)
|
|||||||
#define DELETE 2 /* setup for file deletion */
|
#define DELETE 2 /* setup for file deletion */
|
||||||
#define LINK 3 /* setup for link */
|
#define LINK 3 /* setup for link */
|
||||||
|
|
||||||
int fs_inode_by_name (fs_t *fs, fs_inode_t *inode, char *name,
|
int fs_inode_by_name (fs_t *fs, fs_inode_t *inode, const char *name,
|
||||||
int op, int mode)
|
int op, int mode)
|
||||||
{
|
{
|
||||||
fs_inode_t dir;
|
fs_inode_t dir;
|
||||||
int c, namlen, reclen;
|
int c, namlen, reclen;
|
||||||
char *namptr;
|
const char *namptr;
|
||||||
unsigned long offset, last_offset;
|
unsigned long offset, last_offset;
|
||||||
struct {
|
struct {
|
||||||
unsigned int inum;
|
unsigned int inum;
|
||||||
|
|||||||
748
tools/fsutil/mount.c
Normal file
748
tools/fsutil/mount.c
Normal file
@@ -0,0 +1,748 @@
|
|||||||
|
/*
|
||||||
|
* Mount 2.xBSD filesystem via FUSE interface.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Serge Vakulenko, <serge@vak.ru>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software
|
||||||
|
* and its documentation for any purpose and without fee is hereby
|
||||||
|
* granted, provided that the above copyright notice appear in all
|
||||||
|
* copies and that both that the copyright notice and this
|
||||||
|
* permission notice and warranty disclaimer appear in supporting
|
||||||
|
* documentation, and that the name of the author not be used in
|
||||||
|
* advertising or publicity pertaining to distribution of the
|
||||||
|
* software without specific, written prior permission.
|
||||||
|
*
|
||||||
|
* The author disclaim all warranties with regard to this
|
||||||
|
* software, including all implied warranties of merchantability
|
||||||
|
* and fitness. In no event shall the author be liable for any
|
||||||
|
* special, indirect or consequential damages or any damages
|
||||||
|
* whatsoever resulting from loss of use, data or profits, whether
|
||||||
|
* in an action of contract, negligence or other tortious action,
|
||||||
|
* arising out of or in connection with the use or performance of
|
||||||
|
* this software.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define FUSE_USE_VERSION 26
|
||||||
|
#include <fuse.h>
|
||||||
|
|
||||||
|
#include "bsdfs.h"
|
||||||
|
|
||||||
|
extern int verbose;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a message to log file.
|
||||||
|
*/
|
||||||
|
static void printlog(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
va_start(ap, format);
|
||||||
|
vfprintf(stderr, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 op_getattr(const char *path, struct stat *statbuf)
|
||||||
|
{
|
||||||
|
fs_t *fs = fuse_get_context()->private_data;
|
||||||
|
fs_inode_t dir;
|
||||||
|
|
||||||
|
printlog("--- op_getattr(path=\"%s\", statbuf=%p)\n",
|
||||||
|
path, statbuf);
|
||||||
|
|
||||||
|
if (! fs_inode_by_name (fs, &dir, path, 0, 0)) {
|
||||||
|
printlog("--- cannot find path %s\n", path);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dir.mode & INODE_MODE_FMT) { /* type of file */
|
||||||
|
case INODE_MODE_FREG: /* regular */
|
||||||
|
statbuf->st_mode = S_IFREG;
|
||||||
|
break;
|
||||||
|
case INODE_MODE_FDIR: /* directory */
|
||||||
|
statbuf->st_mode = S_IFDIR;
|
||||||
|
break;
|
||||||
|
case INODE_MODE_FCHR: /* character special */
|
||||||
|
statbuf->st_mode = S_IFCHR;
|
||||||
|
break;
|
||||||
|
case INODE_MODE_FBLK: /* block special */
|
||||||
|
statbuf->st_mode = S_IFBLK;
|
||||||
|
break;
|
||||||
|
case INODE_MODE_FLNK: /* symbolic link */
|
||||||
|
statbuf->st_mode = S_IFLNK;
|
||||||
|
break;
|
||||||
|
case INODE_MODE_FSOCK: /* socket */
|
||||||
|
statbuf->st_mode = S_IFSOCK;
|
||||||
|
break;
|
||||||
|
default: /* cannot happen */
|
||||||
|
printlog("--- unknown file type %#x\n", dir.mode & INODE_MODE_FMT);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
statbuf->st_mode |= dir.mode & 07777; /* protection */
|
||||||
|
statbuf->st_ino = dir.number; /* inode number */
|
||||||
|
statbuf->st_nlink = dir.nlink; /* number of hard links */
|
||||||
|
statbuf->st_uid = dir.uid; /* user ID of owner */
|
||||||
|
statbuf->st_gid = dir.gid; /* group ID of owner */
|
||||||
|
statbuf->st_rdev = dir.addr[1]; /* device ID (if special file) */
|
||||||
|
statbuf->st_size = dir.size; /* total size, in bytes */
|
||||||
|
statbuf->st_blocks = dir.size >> 9; /* number of 512B blocks allocated */
|
||||||
|
statbuf->st_atime = dir.atime; /* time of last access */
|
||||||
|
statbuf->st_mtime = dir.mtime; /* time of last modification */
|
||||||
|
statbuf->st_ctime = dir.ctime; /* time of last status change */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_fgetattr(const char *path, struct stat *statbuf, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_fgetattr(path=\"%s\", statbuf=%p, fi=%p)\n",
|
||||||
|
path, statbuf, fi);
|
||||||
|
|
||||||
|
// On FreeBSD, trying to do anything with the mountpoint ends up
|
||||||
|
// opening it, and then using the FD for an fgetattr. So in the
|
||||||
|
// special case of a path of "/", I need to do a getattr on the
|
||||||
|
// underlying root directory instead of doing the fgetattr().
|
||||||
|
if (strcmp(path, "/") == 0)
|
||||||
|
return op_getattr(path, statbuf);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = fstat(fi->fh, statbuf);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_fgetattr fstat");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
// Note the system readlink() will truncate and lose the terminating
|
||||||
|
// null. So, the size passed to to the system readlink() must be one
|
||||||
|
// less than the size passed to op_readlink()
|
||||||
|
// op_readlink() code by Bernardo F Costa (thanks!)
|
||||||
|
int op_readlink(const char *path, char *link, size_t size)
|
||||||
|
{
|
||||||
|
printlog("op_readlink(path=\"%s\", link=\"%s\", size=%d)\n",
|
||||||
|
path, link, size);
|
||||||
|
|
||||||
|
//retstat = readlink(path, link, size - 1);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_readlink readlink");
|
||||||
|
//else {
|
||||||
|
// link[retstat] = '\0';
|
||||||
|
// retstat = 0;
|
||||||
|
//}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a file node
|
||||||
|
*
|
||||||
|
* There is no create() operation, mknod() will be called for
|
||||||
|
* creation of all non-directory, non-symlink nodes.
|
||||||
|
*/
|
||||||
|
int op_mknod(const char *path, mode_t mode, dev_t dev)
|
||||||
|
{
|
||||||
|
printlog("--- op_mknod(path=\"%s\", mode=0%3o, dev=%lld)\n",
|
||||||
|
path, mode, dev);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//if (S_ISREG(mode)) {
|
||||||
|
// retstat = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
|
||||||
|
// if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_mknod open");
|
||||||
|
// else {
|
||||||
|
// retstat = close(retstat);
|
||||||
|
// if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_mknod close");
|
||||||
|
// }
|
||||||
|
//} else if (S_ISFIFO(mode)) {
|
||||||
|
// retstat = mkfifo(path, mode);
|
||||||
|
// if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_mknod mkfifo");
|
||||||
|
//} else {
|
||||||
|
// retstat = mknod(path, mode, dev);
|
||||||
|
// if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_mknod mknod");
|
||||||
|
//}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a directory
|
||||||
|
*/
|
||||||
|
int op_mkdir(const char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
printlog("--- op_mkdir(path=\"%s\", mode=0%3o)\n",
|
||||||
|
path, mode);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = mkdir(path, mode);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_mkdir mkdir");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a file
|
||||||
|
*/
|
||||||
|
int op_unlink(const char *path)
|
||||||
|
{
|
||||||
|
printlog("op_unlink(path=\"%s\")\n",
|
||||||
|
path);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = unlink(path);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_unlink unlink");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a directory
|
||||||
|
*/
|
||||||
|
int op_rmdir(const char *path)
|
||||||
|
{
|
||||||
|
printlog("op_rmdir(path=\"%s\")\n",
|
||||||
|
path);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = rmdir(path);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_rmdir rmdir");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 op_symlink(const char *path, const char *link)
|
||||||
|
{
|
||||||
|
printlog("--- op_symlink(path=\"%s\", link=\"%s\")\n",
|
||||||
|
path, link);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = symlink(path, link);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_symlink symlink");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rename a file
|
||||||
|
*
|
||||||
|
* Both path and newpath are fs-relative.
|
||||||
|
*/
|
||||||
|
int op_rename(const char *path, const char *newpath)
|
||||||
|
{
|
||||||
|
printlog("--- op_rename(path=\"%s\", newpath=\"%s\")\n",
|
||||||
|
path, newpath);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = rename(path, newpath);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_rename rename");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a hard link to a file
|
||||||
|
*/
|
||||||
|
int op_link(const char *path, const char *newpath)
|
||||||
|
{
|
||||||
|
printlog("--- op_link(path=\"%s\", newpath=\"%s\")\n",
|
||||||
|
path, newpath);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = link(path, newpath);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_link link");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change the permission bits of a file
|
||||||
|
*/
|
||||||
|
int op_chmod(const char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
printlog("--- op_chmod(path=\"%s\", mode=0%03o)\n",
|
||||||
|
path, mode);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = chmod(path, mode);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_chmod chmod");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change the owner and group of a file
|
||||||
|
*/
|
||||||
|
int op_chown(const char *path, uid_t uid, gid_t gid)
|
||||||
|
|
||||||
|
{
|
||||||
|
printlog("--- op_chown(path=\"%s\", uid=%d, gid=%d)\n",
|
||||||
|
path, uid, gid);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = chown(path, uid, gid);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_chown chown");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change the size of a file
|
||||||
|
*/
|
||||||
|
int op_truncate(const char *path, off_t newsize)
|
||||||
|
{
|
||||||
|
printlog("--- op_truncate(path=\"%s\", newsize=%lld)\n",
|
||||||
|
path, newsize);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = truncate(path, newsize);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// print_errno("op_truncate truncate");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change the access and/or modification times of a file
|
||||||
|
*/
|
||||||
|
int op_utime(const char *path, struct utimbuf *ubuf)
|
||||||
|
{
|
||||||
|
printlog("--- op_utime(path=\"%s\", ubuf=%p)\n",
|
||||||
|
path, ubuf);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = utime(path, ubuf);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_utime utime");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_open(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int fd = 0;
|
||||||
|
|
||||||
|
printlog("--- op_open(path\"%s\", fi=%p)\n",
|
||||||
|
path, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//fd = open(path, fi->flags);
|
||||||
|
//if (fd < 0)
|
||||||
|
// retstat = print_errno("op_open open");
|
||||||
|
|
||||||
|
fi->fh = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_read(path=\"%s\", buf=%p, size=%d, offset=%lld, fi=%p)\n",
|
||||||
|
path, buf, size, offset, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = pread(fi->fh, buf, size, offset);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_read read");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
int op_write(const char *path, const char *buf, size_t size, off_t offset,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_write(path=\"%s\", buf=%p, size=%d, offset=%lld, fi=%p)\n",
|
||||||
|
path, buf, size, offset, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = pwrite(fi->fh, buf, size, offset);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_write pwrite");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get file system statistics
|
||||||
|
*
|
||||||
|
* The 'f_frsize', 'f_favail', 'f_fsid' and 'f_flag' fields are ignored
|
||||||
|
*/
|
||||||
|
int op_statfs(const char *path, struct statvfs *statv)
|
||||||
|
{
|
||||||
|
printlog("--- op_statfs(path=\"%s\", statv=%p)\n",
|
||||||
|
path, statv);
|
||||||
|
|
||||||
|
// get stats for underlying filesystem
|
||||||
|
//TODO
|
||||||
|
//retstat = statvfs(path, statv);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_statfs statvfs");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_flush(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_flush(path=\"%s\", fi=%p)\n", path, fi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_release(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_release(path=\"%s\", fi=%p)\n",
|
||||||
|
path, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
// 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 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronize file contents
|
||||||
|
*
|
||||||
|
* If the datasync parameter is non-zero, then only the user data
|
||||||
|
* should be flushed, not the meta data.
|
||||||
|
*/
|
||||||
|
int op_fsync(const char *path, int datasync, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_fsync(path=\"%s\", datasync=%d, fi=%p)\n",
|
||||||
|
path, datasync, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = fsync(fi->fh);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// print_errno("op_fsync fsync");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open directory
|
||||||
|
*
|
||||||
|
* This method should check if the open operation is permitted for
|
||||||
|
* this directory
|
||||||
|
*/
|
||||||
|
int op_opendir(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_opendir(path=\"%s\", fi=%p)\n",
|
||||||
|
path, fi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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'.
|
||||||
|
*/
|
||||||
|
int op_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
fs_t *fs = fuse_get_context()->private_data;
|
||||||
|
fs_inode_t dir;
|
||||||
|
char name [BSDFS_BSIZE - 12];
|
||||||
|
struct {
|
||||||
|
unsigned int inum;
|
||||||
|
unsigned short reclen;
|
||||||
|
unsigned short namlen;
|
||||||
|
} dirent;
|
||||||
|
|
||||||
|
printlog("--- op_readdir(path=\"%s\", buf=%p, filler=%p, offset=%lld, fi=%p)\n",
|
||||||
|
path, buf, filler, offset, fi);
|
||||||
|
|
||||||
|
if (! fs_inode_by_name (fs, &dir, path, 0, 0)) {
|
||||||
|
printlog("--- cannot find path %s\n", path);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the entire directory into the buffer. */
|
||||||
|
for (offset = 0; offset < dir.size; offset += dirent.reclen) {
|
||||||
|
if (! fs_inode_read (&dir, offset, (unsigned char*) &dirent, sizeof(dirent))) {
|
||||||
|
printlog("--- read error at offset %ld\n", offset);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
//printlog("--- readdir offset %lu: inum=%u, reclen=%u, namlen=%u\n", offset, dirent.inum, dirent.reclen, dirent.namlen);
|
||||||
|
|
||||||
|
if (! fs_inode_read (&dir, offset+sizeof(dirent),
|
||||||
|
(unsigned char*)name, (dirent.namlen + 4) / 4 * 4))
|
||||||
|
{
|
||||||
|
printlog("--- name read error at offset %ld\n", offset);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
//printlog("--- readdir offset %lu: name='%s'\n", offset, name);
|
||||||
|
|
||||||
|
if (dirent.inum != 0) {
|
||||||
|
//printlog("calling filler with name %s\n", name);
|
||||||
|
if (filler(buf, name, NULL, 0) != 0) {
|
||||||
|
printlog(" ERROR op_readdir filler: buffer full");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release directory
|
||||||
|
*/
|
||||||
|
int op_releasedir(const char *path, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_releasedir(path=\"%s\", fi=%p)\n",
|
||||||
|
path, fi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up filesystem
|
||||||
|
*
|
||||||
|
* Called on filesystem exit.
|
||||||
|
*/
|
||||||
|
void op_destroy(void *userdata)
|
||||||
|
{
|
||||||
|
printlog("--- op_destroy(userdata=%p)\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.
|
||||||
|
*/
|
||||||
|
int op_access(const char *path, int mask)
|
||||||
|
{
|
||||||
|
printlog("--- op_access(path=\"%s\", mask=0%o)\n",
|
||||||
|
path, mask);
|
||||||
|
|
||||||
|
/* Always permitted. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_create(const char *path, mode_t mode, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
int fd = 0;
|
||||||
|
|
||||||
|
printlog("--- op_create(path=\"%s\", mode=0%03o, fi=%p)\n",
|
||||||
|
path, mode, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//fd = creat(path, mode);
|
||||||
|
//if (fd < 0)
|
||||||
|
// retstat = print_errno("op_create creat");
|
||||||
|
|
||||||
|
fi->fh = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int op_ftruncate(const char *path, off_t offset, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
printlog("--- op_ftruncate(path=\"%s\", offset=%lld, fi=%p)\n",
|
||||||
|
path, offset, fi);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//retstat = ftruncate(fi->fh, offset);
|
||||||
|
//if (retstat < 0)
|
||||||
|
// retstat = print_errno("op_ftruncate ftruncate");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fuse_operations mount_ops = {
|
||||||
|
.access = op_access,
|
||||||
|
.chmod = op_chmod,
|
||||||
|
.chown = op_chown,
|
||||||
|
.create = op_create, //
|
||||||
|
.destroy = op_destroy, //
|
||||||
|
.fgetattr = op_fgetattr, //
|
||||||
|
.flush = op_flush, //
|
||||||
|
.fsync = op_fsync,
|
||||||
|
.ftruncate = op_ftruncate, //
|
||||||
|
.getattr = op_getattr,
|
||||||
|
.link = op_link,
|
||||||
|
.mkdir = op_mkdir,
|
||||||
|
.mknod = op_mknod,
|
||||||
|
.open = op_open,
|
||||||
|
.opendir = op_opendir, //
|
||||||
|
.readdir = op_readdir,
|
||||||
|
.readlink = op_readlink,
|
||||||
|
.read = op_read,
|
||||||
|
.release = op_release,
|
||||||
|
.releasedir = op_releasedir, //
|
||||||
|
.rename = op_rename,
|
||||||
|
.rmdir = op_rmdir,
|
||||||
|
.statfs = op_statfs,
|
||||||
|
.symlink = op_symlink,
|
||||||
|
.truncate = op_truncate,
|
||||||
|
.unlink = op_unlink,
|
||||||
|
.utime = op_utime, //
|
||||||
|
.write = op_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
int fs_mount(fs_t *fs, char *dirname)
|
||||||
|
{
|
||||||
|
char *av[8];
|
||||||
|
int ret, ac;
|
||||||
|
|
||||||
|
printf ("Filesystem mounted as %s\n", dirname);
|
||||||
|
printf ("Press ^C to unmount\n");
|
||||||
|
|
||||||
|
/* Invoke FUSE to mount the filesystem. */
|
||||||
|
ac = 0;
|
||||||
|
av[ac++] = "fsutil";
|
||||||
|
av[ac++] = "-f"; // foreground
|
||||||
|
av[ac++] = "-s"; // single-threaded
|
||||||
|
if (verbose > 1)
|
||||||
|
av[ac++] = "-d"; // debug
|
||||||
|
av[ac++] = dirname;
|
||||||
|
av[ac] = 0;
|
||||||
|
ret = fuse_main(ac, av, &mount_ops, fs);
|
||||||
|
if (ret != 0) {
|
||||||
|
perror ("fuse_main failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf ("\nFilesystem %s unmounted\n", dirname);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user