change indenting

This commit is contained in:
Miklos Szeredi 2007-12-12 14:25:40 +00:00
parent 918f0ad95b
commit cdb8b79bad
37 changed files with 10993 additions and 10812 deletions

View File

@ -1,11 +1,11 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
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.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp
gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp
*/
#define FUSE_USE_VERSION 26
@ -33,353 +33,353 @@
static int xmp_getattr(const char *path, struct stat *stbuf)
{
int res;
int res;
res = lstat(path, stbuf);
if (res == -1)
return -errno;
res = lstat(path, stbuf);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_access(const char *path, int mask)
{
int res;
int res;
res = access(path, mask);
if (res == -1)
return -errno;
res = access(path, mask);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;
int res;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
buf[res] = '\0';
return 0;
buf[res] = '\0';
return 0;
}
static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
DIR *dp;
struct dirent *de;
DIR *dp;
struct dirent *de;
(void) offset;
(void) fi;
(void) offset;
(void) fi;
dp = opendir(path);
if (dp == NULL)
return -errno;
dp = opendir(path);
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;
}
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;
closedir(dp);
return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
int res;
/* On Linux this could just be 'mknod(path, mode, rdev)' but this
is more portable */
if (S_ISREG(mode)) {
res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0)
res = close(res);
} else if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
/* On Linux this could just be 'mknod(path, mode, rdev)' but this
is more portable */
if (S_ISREG(mode)) {
res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0)
res = close(res);
} else if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
int res;
res = mkdir(path, mode);
if (res == -1)
return -errno;
res = mkdir(path, mode);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_unlink(const char *path)
{
int res;
int res;
res = unlink(path);
if (res == -1)
return -errno;
res = unlink(path);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_rmdir(const char *path)
{
int res;
int res;
res = rmdir(path);
if (res == -1)
return -errno;
res = rmdir(path);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_symlink(const char *from, const char *to)
{
int res;
int res;
res = symlink(from, to);
if (res == -1)
return -errno;
res = symlink(from, to);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_rename(const char *from, const char *to)
{
int res;
int res;
res = rename(from, to);
if (res == -1)
return -errno;
res = rename(from, to);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_link(const char *from, const char *to)
{
int res;
int res;
res = link(from, to);
if (res == -1)
return -errno;
res = link(from, to);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_chmod(const char *path, mode_t mode)
{
int res;
int res;
res = chmod(path, mode);
if (res == -1)
return -errno;
res = chmod(path, mode);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
int res;
int res;
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_truncate(const char *path, off_t size)
{
int res;
int res;
res = truncate(path, size);
if (res == -1)
return -errno;
res = truncate(path, size);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_utimens(const char *path, const struct timespec ts[2])
{
int res;
struct timeval tv[2];
int res;
struct timeval tv[2];
tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000;
tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000;
res = utimes(path, tv);
if (res == -1)
return -errno;
res = utimes(path, tv);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_open(const char *path, struct fuse_file_info *fi)
{
int res;
int res;
res = open(path, fi->flags);
if (res == -1)
return -errno;
res = open(path, fi->flags);
if (res == -1)
return -errno;
close(res);
return 0;
close(res);
return 0;
}
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
int fd;
int res;
int fd;
int res;
(void) fi;
fd = open(path, O_RDONLY);
if (fd == -1)
return -errno;
(void) fi;
fd = open(path, O_RDONLY);
if (fd == -1)
return -errno;
res = pread(fd, buf, size, offset);
if (res == -1)
res = -errno;
res = pread(fd, buf, size, offset);
if (res == -1)
res = -errno;
close(fd);
return res;
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)
off_t offset, struct fuse_file_info *fi)
{
int fd;
int res;
int fd;
int res;
(void) fi;
fd = open(path, O_WRONLY);
if (fd == -1)
return -errno;
(void) fi;
fd = open(path, O_WRONLY);
if (fd == -1)
return -errno;
res = pwrite(fd, buf, size, offset);
if (res == -1)
res = -errno;
res = pwrite(fd, buf, size, offset);
if (res == -1)
res = -errno;
close(fd);
return res;
close(fd);
return res;
}
static int xmp_statfs(const char *path, struct statvfs *stbuf)
{
int res;
int res;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
return 0;
return 0;
}
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 */
/* Just a stub. This method is optional and can safely be left
unimplemented */
(void) path;
(void) fi;
return 0;
(void) path;
(void) fi;
return 0;
}
static int xmp_fsync(const char *path, int isdatasync,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
/* Just a stub. This method is optional and can safely be left
unimplemented */
/* Just a stub. This method is optional and can safely be left
unimplemented */
(void) path;
(void) isdatasync;
(void) fi;
return 0;
(void) path;
(void) isdatasync;
(void) fi;
return 0;
}
#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags)
size_t size, int flags)
{
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
}
static int xmp_getxattr(const char *path, const char *name, char *value,
size_t size)
size_t size)
{
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_listxattr(const char *path, char *list, size_t size)
{
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_removexattr(const char *path, const char *name)
{
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
}
#endif /* HAVE_SETXATTR */
static struct fuse_operations xmp_oper = {
.getattr = xmp_getattr,
.access = xmp_access,
.readlink = xmp_readlink,
.readdir = xmp_readdir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
.utimens = xmp_utimens,
.open = xmp_open,
.read = xmp_read,
.write = xmp_write,
.statfs = xmp_statfs,
.release = xmp_release,
.fsync = xmp_fsync,
.getattr = xmp_getattr,
.access = xmp_access,
.readlink = xmp_readlink,
.readdir = xmp_readdir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
.utimens = xmp_utimens,
.open = xmp_open,
.read = xmp_read,
.write = xmp_write,
.statfs = xmp_statfs,
.release = xmp_release,
.fsync = xmp_fsync,
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr= xmp_removexattr,
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr = xmp_removexattr,
#endif
};
int main(int argc, char *argv[])
{
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
}

View File

@ -1,11 +1,11 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
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.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` -lulockmgr fusexmp_fh.c -o fusexmp_fh
gcc -Wall `pkg-config fuse --cflags --libs` -lulockmgr fusexmp_fh.c -o fusexmp_fh
*/
#define FUSE_USE_VERSION 26
@ -31,430 +31,430 @@
static int xmp_getattr(const char *path, struct stat *stbuf)
{
int res;
int res;
res = lstat(path, stbuf);
if (res == -1)
return -errno;
res = lstat(path, stbuf);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
int res;
int res;
(void) path;
(void) path;
res = fstat(fi->fh, stbuf);
if (res == -1)
return -errno;
res = fstat(fi->fh, stbuf);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_access(const char *path, int mask)
{
int res;
int res;
res = access(path, mask);
if (res == -1)
return -errno;
res = access(path, mask);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_readlink(const char *path, char *buf, size_t size)
{
int res;
int res;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
res = readlink(path, buf, size - 1);
if (res == -1)
return -errno;
buf[res] = '\0';
return 0;
buf[res] = '\0';
return 0;
}
static int xmp_opendir(const char *path, struct fuse_file_info *fi)
{
DIR *dp = opendir(path);
if (dp == NULL)
return -errno;
DIR *dp = opendir(path);
if (dp == NULL)
return -errno;
fi->fh = (unsigned long) dp;
return 0;
fi->fh = (unsigned long) dp;
return 0;
}
static inline DIR *get_dirp(struct fuse_file_info *fi)
{
return (DIR *) (uintptr_t) fi->fh;
return (DIR *) (uintptr_t) fi->fh;
}
static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
DIR *dp = get_dirp(fi);
struct dirent *de;
DIR *dp = get_dirp(fi);
struct dirent *de;
(void) path;
seekdir(dp, offset);
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, telldir(dp)))
break;
}
(void) path;
seekdir(dp, offset);
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, telldir(dp)))
break;
}
return 0;
return 0;
}
static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
{
DIR *dp = get_dirp(fi);
(void) path;
closedir(dp);
return 0;
DIR *dp = get_dirp(fi);
(void) path;
closedir(dp);
return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
int res;
int res;
if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
if (S_ISFIFO(mode))
res = mkfifo(path, mode);
else
res = mknod(path, mode, rdev);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_mkdir(const char *path, mode_t mode)
{
int res;
int res;
res = mkdir(path, mode);
if (res == -1)
return -errno;
res = mkdir(path, mode);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_unlink(const char *path)
{
int res;
int res;
res = unlink(path);
if (res == -1)
return -errno;
res = unlink(path);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_rmdir(const char *path)
{
int res;
int res;
res = rmdir(path);
if (res == -1)
return -errno;
res = rmdir(path);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_symlink(const char *from, const char *to)
{
int res;
int res;
res = symlink(from, to);
if (res == -1)
return -errno;
res = symlink(from, to);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_rename(const char *from, const char *to)
{
int res;
int res;
res = rename(from, to);
if (res == -1)
return -errno;
res = rename(from, to);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_link(const char *from, const char *to)
{
int res;
int res;
res = link(from, to);
if (res == -1)
return -errno;
res = link(from, to);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_chmod(const char *path, mode_t mode)
{
int res;
int res;
res = chmod(path, mode);
if (res == -1)
return -errno;
res = chmod(path, mode);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
int res;
int res;
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
res = lchown(path, uid, gid);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_truncate(const char *path, off_t size)
{
int res;
int res;
res = truncate(path, size);
if (res == -1)
return -errno;
res = truncate(path, size);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
int res;
int res;
(void) path;
(void) path;
res = ftruncate(fi->fh, size);
if (res == -1)
return -errno;
res = ftruncate(fi->fh, size);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_utimens(const char *path, const struct timespec ts[2])
{
int res;
struct timeval tv[2];
int res;
struct timeval tv[2];
tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000;
tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000;
tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000;
res = utimes(path, tv);
if (res == -1)
return -errno;
res = utimes(path, tv);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
{
int fd;
int fd;
fd = open(path, fi->flags, mode);
if (fd == -1)
return -errno;
fd = open(path, fi->flags, mode);
if (fd == -1)
return -errno;
fi->fh = fd;
return 0;
fi->fh = fd;
return 0;
}
static int xmp_open(const char *path, struct fuse_file_info *fi)
{
int fd;
int fd;
fd = open(path, fi->flags);
if (fd == -1)
return -errno;
fd = open(path, fi->flags);
if (fd == -1)
return -errno;
fi->fh = fd;
return 0;
fi->fh = fd;
return 0;
}
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
int res;
int res;
(void) path;
res = pread(fi->fh, buf, size, offset);
if (res == -1)
res = -errno;
(void) path;
res = pread(fi->fh, buf, size, offset);
if (res == -1)
res = -errno;
return res;
return res;
}
static int xmp_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
int res;
int res;
(void) path;
res = pwrite(fi->fh, buf, size, offset);
if (res == -1)
res = -errno;
(void) path;
res = pwrite(fi->fh, buf, size, offset);
if (res == -1)
res = -errno;
return res;
return res;
}
static int xmp_statfs(const char *path, struct statvfs *stbuf)
{
int res;
int res;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
res = statvfs(path, stbuf);
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_flush(const char *path, struct fuse_file_info *fi)
{
int res;
int res;
(void) path;
/* This is called from every close on an open file, so call the
close on the underlying filesystem. But since flush may be
called multiple times for an open file, this must not really
close the file. This is important if used on a network
filesystem like NFS which flush the data/metadata on close() */
res = close(dup(fi->fh));
if (res == -1)
return -errno;
(void) path;
/* This is called from every close on an open file, so call the
close on the underlying filesystem. But since flush may be
called multiple times for an open file, this must not really
close the file. This is important if used on a network
filesystem like NFS which flush the data/metadata on close() */
res = close(dup(fi->fh));
if (res == -1)
return -errno;
return 0;
return 0;
}
static int xmp_release(const char *path, struct fuse_file_info *fi)
{
(void) path;
close(fi->fh);
(void) path;
close(fi->fh);
return 0;
return 0;
}
static int xmp_fsync(const char *path, int isdatasync,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
int res;
(void) path;
int res;
(void) path;
#ifndef HAVE_FDATASYNC
(void) isdatasync;
(void) isdatasync;
#else
if (isdatasync)
res = fdatasync(fi->fh);
else
if (isdatasync)
res = fdatasync(fi->fh);
else
#endif
res = fsync(fi->fh);
if (res == -1)
return -errno;
res = fsync(fi->fh);
if (res == -1)
return -errno;
return 0;
return 0;
}
#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags)
size_t size, int flags)
{
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
int res = lsetxattr(path, name, value, size, flags);
if (res == -1)
return -errno;
return 0;
}
static int xmp_getxattr(const char *path, const char *name, char *value,
size_t size)
size_t size)
{
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
int res = lgetxattr(path, name, value, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_listxattr(const char *path, char *list, size_t size)
{
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
int res = llistxattr(path, list, size);
if (res == -1)
return -errno;
return res;
}
static int xmp_removexattr(const char *path, const char *name)
{
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
int res = lremovexattr(path, name);
if (res == -1)
return -errno;
return 0;
}
#endif /* HAVE_SETXATTR */
static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
struct flock *lock)
struct flock *lock)
{
(void) path;
(void) path;
return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
sizeof(fi->lock_owner));
return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
sizeof(fi->lock_owner));
}
static struct fuse_operations xmp_oper = {
.getattr = xmp_getattr,
.fgetattr = xmp_fgetattr,
.access = xmp_access,
.readlink = xmp_readlink,
.opendir = xmp_opendir,
.readdir = xmp_readdir,
.releasedir = xmp_releasedir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
.ftruncate = xmp_ftruncate,
.utimens = xmp_utimens,
.create = xmp_create,
.open = xmp_open,
.read = xmp_read,
.write = xmp_write,
.statfs = xmp_statfs,
.flush = xmp_flush,
.release = xmp_release,
.fsync = xmp_fsync,
.getattr = xmp_getattr,
.fgetattr = xmp_fgetattr,
.access = xmp_access,
.readlink = xmp_readlink,
.opendir = xmp_opendir,
.readdir = xmp_readdir,
.releasedir = xmp_releasedir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
.unlink = xmp_unlink,
.rmdir = xmp_rmdir,
.rename = xmp_rename,
.link = xmp_link,
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
.ftruncate = xmp_ftruncate,
.utimens = xmp_utimens,
.create = xmp_create,
.open = xmp_open,
.read = xmp_read,
.write = xmp_write,
.statfs = xmp_statfs,
.flush = xmp_flush,
.release = xmp_release,
.fsync = xmp_fsync,
#ifdef HAVE_SETXATTR
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr= xmp_removexattr,
.setxattr = xmp_setxattr,
.getxattr = xmp_getxattr,
.listxattr = xmp_listxattr,
.removexattr = xmp_removexattr,
#endif
.lock = xmp_lock,
.lock = xmp_lock,
};
int main(int argc, char *argv[])
{
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
umask(0);
return fuse_main(argc, argv, &xmp_oper, NULL);
}

View File

@ -1,11 +1,11 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
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.
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
gcc -Wall `pkg-config fuse --cflags --libs` hello.c -o hello
*/
#define FUSE_USE_VERSION 26
@ -21,76 +21,76 @@ static const char *hello_path = "/hello";
static int hello_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
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;
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;
return res;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
(void) offset;
(void) fi;
if (strcmp(path, "/") != 0)
return -ENOENT;
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, hello_path + 1, NULL, 0);
return 0;
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
if (strcmp(path, hello_path) != 0)
return -ENOENT;
if (strcmp(path, hello_path) != 0)
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
return 0;
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
size_t len;
(void) fi;
if(strcmp(path, hello_path) != 0)
return -ENOENT;
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;
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;
return size;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
.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);
return fuse_main(argc, argv, &hello_oper, NULL);
}

View File

@ -1,11 +1,11 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
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.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` hello_ll.c -o hello_ll
gcc -Wall `pkg-config fuse --cflags --libs` hello_ll.c -o hello_ll
*/
#define FUSE_USE_VERSION 26
@ -24,157 +24,158 @@ static const char *hello_name = "hello";
static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
{
stbuf->st_ino = ino;
switch (ino) {
case 1:
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
break;
stbuf->st_ino = ino;
switch (ino) {
case 1:
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
break;
case 2:
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
break;
case 2:
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = strlen(hello_str);
break;
default:
return -1;
}
return 0;
default:
return -1;
}
return 0;
}
static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
struct stat stbuf;
struct stat stbuf;
(void) fi;
(void) fi;
memset(&stbuf, 0, sizeof(stbuf));
if (hello_stat(ino, &stbuf) == -1)
fuse_reply_err(req, ENOENT);
else
fuse_reply_attr(req, &stbuf, 1.0);
memset(&stbuf, 0, sizeof(stbuf));
if (hello_stat(ino, &stbuf) == -1)
fuse_reply_err(req, ENOENT);
else
fuse_reply_attr(req, &stbuf, 1.0);
}
static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
struct fuse_entry_param e;
struct fuse_entry_param e;
if (parent != 1 || strcmp(name, hello_name) != 0)
fuse_reply_err(req, ENOENT);
else {
memset(&e, 0, sizeof(e));
e.ino = 2;
e.attr_timeout = 1.0;
e.entry_timeout = 1.0;
hello_stat(e.ino, &e.attr);
if (parent != 1 || strcmp(name, hello_name) != 0)
fuse_reply_err(req, ENOENT);
else {
memset(&e, 0, sizeof(e));
e.ino = 2;
e.attr_timeout = 1.0;
e.entry_timeout = 1.0;
hello_stat(e.ino, &e.attr);
fuse_reply_entry(req, &e);
}
fuse_reply_entry(req, &e);
}
}
struct dirbuf {
char *p;
size_t size;
char *p;
size_t size;
};
static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
fuse_ino_t ino)
fuse_ino_t ino)
{
struct stat stbuf;
size_t oldsize = b->size;
b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
b->p = (char *) realloc(b->p, b->size);
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_ino = ino;
fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
b->size);
struct stat stbuf;
size_t oldsize = b->size;
b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
b->p = (char *) realloc(b->p, b->size);
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_ino = ino;
fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
b->size);
}
#define min(x, y) ((x) < (y) ? (x) : (y))
static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
off_t off, size_t maxsize)
off_t off, size_t maxsize)
{
if (off < bufsize)
return fuse_reply_buf(req, buf + off, min(bufsize - off, maxsize));
else
return fuse_reply_buf(req, NULL, 0);
if (off < bufsize)
return fuse_reply_buf(req, buf + off,
min(bufsize - off, maxsize));
else
return fuse_reply_buf(req, NULL, 0);
}
static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
off_t off, struct fuse_file_info *fi)
{
(void) fi;
(void) fi;
if (ino != 1)
fuse_reply_err(req, ENOTDIR);
else {
struct dirbuf b;
if (ino != 1)
fuse_reply_err(req, ENOTDIR);
else {
struct dirbuf b;
memset(&b, 0, sizeof(b));
dirbuf_add(req, &b, ".", 1);
dirbuf_add(req, &b, "..", 1);
dirbuf_add(req, &b, hello_name, 2);
reply_buf_limited(req, b.p, b.size, off, size);
free(b.p);
}
memset(&b, 0, sizeof(b));
dirbuf_add(req, &b, ".", 1);
dirbuf_add(req, &b, "..", 1);
dirbuf_add(req, &b, hello_name, 2);
reply_buf_limited(req, b.p, b.size, off, size);
free(b.p);
}
}
static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
struct fuse_file_info *fi)
{
if (ino != 2)
fuse_reply_err(req, EISDIR);
else if ((fi->flags & 3) != O_RDONLY)
fuse_reply_err(req, EACCES);
else
fuse_reply_open(req, fi);
if (ino != 2)
fuse_reply_err(req, EISDIR);
else if ((fi->flags & 3) != O_RDONLY)
fuse_reply_err(req, EACCES);
else
fuse_reply_open(req, fi);
}
static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
off_t off, struct fuse_file_info *fi)
{
(void) fi;
(void) fi;
assert(ino == 2);
reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
assert(ino == 2);
reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
}
static struct fuse_lowlevel_ops hello_ll_oper = {
.lookup = hello_ll_lookup,
.getattr = hello_ll_getattr,
.readdir = hello_ll_readdir,
.open = hello_ll_open,
.read = hello_ll_read,
.lookup = hello_ll_lookup,
.getattr = hello_ll_getattr,
.readdir = hello_ll_readdir,
.open = hello_ll_open,
.read = hello_ll_read,
};
int main(int argc, char *argv[])
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
char *mountpoint;
int err = -1;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
char *mountpoint;
int err = -1;
if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 &&
(ch = fuse_mount(mountpoint, &args)) != NULL) {
struct fuse_session *se;
if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != -1 &&
(ch = fuse_mount(mountpoint, &args)) != NULL) {
struct fuse_session *se;
se = fuse_lowlevel_new(&args, &hello_ll_oper, sizeof(hello_ll_oper),
NULL);
if (se != NULL) {
if (fuse_set_signal_handlers(se) != -1) {
fuse_session_add_chan(se, ch);
err = fuse_session_loop(se);
fuse_remove_signal_handlers(se);
fuse_session_remove_chan(ch);
}
fuse_session_destroy(se);
}
fuse_unmount(mountpoint, ch);
}
fuse_opt_free_args(&args);
se = fuse_lowlevel_new(&args, &hello_ll_oper,
sizeof(hello_ll_oper), NULL);
if (se != NULL) {
if (fuse_set_signal_handlers(se) != -1) {
fuse_session_add_chan(se, ch);
err = fuse_session_loop(se);
fuse_remove_signal_handlers(se);
fuse_session_remove_chan(ch);
}
fuse_session_destroy(se);
}
fuse_unmount(mountpoint, ch);
}
fuse_opt_free_args(&args);
return err ? 1 : 0;
return err ? 1 : 0;
}

View File

@ -1,11 +1,11 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
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.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall `pkg-config fuse --cflags --libs` null.c -o null
gcc -Wall `pkg-config fuse --cflags --libs` null.c -o null
*/
#define FUSE_USE_VERSION 26
@ -18,75 +18,75 @@
static int null_getattr(const char *path, struct stat *stbuf)
{
if(strcmp(path, "/") != 0)
return -ENOENT;
if(strcmp(path, "/") != 0)
return -ENOENT;
stbuf->st_mode = S_IFREG | 0644;
stbuf->st_nlink = 1;
stbuf->st_uid = getuid();
stbuf->st_gid = getgid();
stbuf->st_size = (1ULL << 32); /* 4G */
stbuf->st_blocks = 0;
stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL);
stbuf->st_mode = S_IFREG | 0644;
stbuf->st_nlink = 1;
stbuf->st_uid = getuid();
stbuf->st_gid = getgid();
stbuf->st_size = (1ULL << 32); /* 4G */
stbuf->st_blocks = 0;
stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL);
return 0;
return 0;
}
static int null_truncate(const char *path, off_t size)
{
(void) size;
(void) size;
if(strcmp(path, "/") != 0)
return -ENOENT;
if(strcmp(path, "/") != 0)
return -ENOENT;
return 0;
return 0;
}
static int null_open(const char *path, struct fuse_file_info *fi)
{
(void) fi;
(void) fi;
if(strcmp(path, "/") != 0)
return -ENOENT;
if(strcmp(path, "/") != 0)
return -ENOENT;
return 0;
return 0;
}
static int null_read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
(void) buf;
(void) offset;
(void) fi;
(void) buf;
(void) offset;
(void) fi;
if(strcmp(path, "/") != 0)
return -ENOENT;
if(strcmp(path, "/") != 0)
return -ENOENT;
return size;
return size;
}
static int null_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
(void) buf;
(void) offset;
(void) fi;
(void) buf;
(void) offset;
(void) fi;
if(strcmp(path, "/") != 0)
return -ENOENT;
if(strcmp(path, "/") != 0)
return -ENOENT;
return size;
return size;
}
static struct fuse_operations null_oper = {
.getattr = null_getattr,
.truncate = null_truncate,
.open = null_open,
.read = null_read,
.write = null_write,
.getattr = null_getattr,
.truncate = null_truncate,
.open = null_open,
.read = null_read,
.write = null_write,
};
int main(int argc, char *argv[])
{
return fuse_main(argc, argv, &null_oper, NULL);
return fuse_main(argc, argv, &null_oper, NULL);
}

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#ifndef _FUSE_H_
@ -37,7 +37,7 @@ extern "C" {
#endif
/* ----------------------------------------------------------- *
* Basic FUSE API *
* Basic FUSE API *
* ----------------------------------------------------------- */
/** Handle for a FUSE filesystem */
@ -55,12 +55,12 @@ struct fuse_cmd;
* @return 1 if buffer is full, zero otherwise
*/
typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
const struct stat *stbuf, off_t off);
const struct stat *stbuf, off_t off);
/* Used by deprecated getdir() method */
typedef struct fuse_dirhandle *fuse_dirh_t;
typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
ino_t ino);
ino_t ino);
/**
* The file system operations:
@ -77,351 +77,352 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
* featured filesystem can still be implemented.
*/
struct fuse_operations {
/** 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 (*getattr) (const char *, struct stat *);
/** 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 (*getattr) (const char *, struct stat *);
/** 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.
*/
int (*readlink) (const char *, char *, size_t);
/** 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.
*/
int (*readlink) (const char *, char *, size_t);
/* Deprecated, use readdir() instead */
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
/* Deprecated, use readdir() instead */
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
/** Create a file node
*
* This is called for creation of all non-directory, non-symlink
* nodes. If the filesystem defines a create() method, then for
* regular files that will be called instead.
*/
int (*mknod) (const char *, mode_t, dev_t);
/** Create a file node
*
* This is called for creation of all non-directory, non-symlink
* nodes. If the filesystem defines a create() method, then for
* regular files that will be called instead.
*/
int (*mknod) (const char *, mode_t, dev_t);
/** Create a directory */
int (*mkdir) (const char *, mode_t);
/** Create a directory */
int (*mkdir) (const char *, mode_t);
/** Remove a file */
int (*unlink) (const char *);
/** Remove a file */
int (*unlink) (const char *);
/** Remove a directory */
int (*rmdir) (const char *);
/** Remove a directory */
int (*rmdir) (const char *);
/** Create a symbolic link */
int (*symlink) (const char *, const char *);
/** Create a symbolic link */
int (*symlink) (const char *, const char *);
/** Rename a file */
int (*rename) (const char *, const char *);
/** Rename a file */
int (*rename) (const char *, const char *);
/** Create a hard link to a file */
int (*link) (const char *, const char *);
/** Create a hard link to a file */
int (*link) (const char *, const char *);
/** Change the permission bits of a file */
int (*chmod) (const char *, mode_t);
/** Change the permission bits of a file */
int (*chmod) (const char *, mode_t);
/** Change the owner and group of a file */
int (*chown) (const char *, uid_t, gid_t);
/** Change the owner and group of a file */
int (*chown) (const char *, uid_t, gid_t);
/** Change the size of a file */
int (*truncate) (const char *, off_t);
/** Change the size of a file */
int (*truncate) (const char *, off_t);
/** Change the access and/or modification times of a file
*
* Deprecated, use utimens() instead.
*/
int (*utime) (const char *, struct utimbuf *);
/** Change the access and/or modification times of a file
*
* Deprecated, use utimens() instead.
*/
int (*utime) (const char *, struct utimbuf *);
/** 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 (*open) (const char *, struct fuse_file_info *);
/** 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 (*open) (const char *, struct fuse_file_info *);
/** 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
*/
int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
/** 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
*/
int (*read) (const char *, char *, size_t, off_t,
struct fuse_file_info *);
/** 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
*/
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info *);
/** 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
*/
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info *);
/** 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 (*statfs) (const char *, struct statvfs *);
/** 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 (*statfs) (const char *, struct statvfs *);
/** 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 (*flush) (const char *, struct fuse_file_info *);
/** 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 (*flush) (const char *, struct fuse_file_info *);
/** 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 (*release) (const char *, struct fuse_file_info *);
/** 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 (*release) (const char *, struct fuse_file_info *);
/** 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 (*fsync) (const char *, int, struct fuse_file_info *);
/** 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 (*fsync) (const char *, int, struct fuse_file_info *);
/** Set extended attributes */
int (*setxattr) (const char *, const char *, const char *, size_t, int);
/** Set extended attributes */
int (*setxattr) (const char *, const char *, const char *, size_t, int);
/** Get extended attributes */
int (*getxattr) (const char *, const char *, char *, size_t);
/** Get extended attributes */
int (*getxattr) (const char *, const char *, char *, size_t);
/** List extended attributes */
int (*listxattr) (const char *, char *, size_t);
/** List extended attributes */
int (*listxattr) (const char *, char *, size_t);
/** Remove extended attributes */
int (*removexattr) (const char *, const char *);
/** Remove extended attributes */
int (*removexattr) (const char *, const char *);
/** Open directory
*
* This method should check if the open operation is permitted for
* this directory
*
* Introduced in version 2.3
*/
int (*opendir) (const char *, struct fuse_file_info *);
/** Open directory
*
* This method should check if the open operation is permitted for
* this directory
*
* Introduced in version 2.3
*/
int (*opendir) (const char *, struct fuse_file_info *);
/** 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 (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info *);
/** 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 (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info *);
/** Release directory
*
* Introduced in version 2.3
*/
int (*releasedir) (const char *, struct fuse_file_info *);
/** Release directory
*
* Introduced in version 2.3
*/
int (*releasedir) (const char *, struct fuse_file_info *);
/** 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
*/
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
/** 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
*/
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
/**
* 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
*/
void *(*init) (struct fuse_conn_info *conn);
/**
* 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
*/
void *(*init) (struct fuse_conn_info *conn);
/**
* Clean up filesystem
*
* Called on filesystem exit.
*
* Introduced in version 2.3
*/
void (*destroy) (void *);
/**
* Clean up filesystem
*
* Called on filesystem exit.
*
* Introduced in version 2.3
*/
void (*destroy) (void *);
/**
* 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 (*access) (const char *, int);
/**
* 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 (*access) (const char *, int);
/**
* 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 (*create) (const char *, mode_t, struct fuse_file_info *);
/**
* 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 (*create) (const char *, mode_t, struct fuse_file_info *);
/**
* 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 (*ftruncate) (const char *, off_t, struct fuse_file_info *);
/**
* 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 (*ftruncate) (const char *, off_t, struct fuse_file_info *);
/**
* 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
*/
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
/**
* 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
*/
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
/**
* Perform POSIX file locking operation
*
* The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
*
* For the meaning of fields in 'struct flock' see the man page
* for fcntl(2). The l_whence field will always be set to
* SEEK_SET.
*
* For checking lock ownership, the 'fuse_file_info->owner'
* argument must be used.
*
* For F_GETLK operation, the library will first check currently
* held locks, and if a conflicting lock is found it will return
* information without calling this method. This ensures, that
* for local locks the l_pid field is correctly filled in. The
* results may not be accurate in case of race conditions and in
* the presence of hard links, but it's unlikly that an
* application would rely on accurate GETLK results in these
* cases. If a conflicting lock is not found, this method will be
* called, and the filesystem may fill out l_pid by a meaningful
* value, or it may leave this field zero.
*
* For F_SETLK and F_SETLKW the l_pid field will be set to the pid
* of the process performing the locking operation.
*
* Note: if this method is not implemented, the kernel will still
* allow file locking to work locally. Hence it is only
* interesting for network filesystems and similar.
*
* Introduced in version 2.6
*/
int (*lock) (const char *, struct fuse_file_info *, int cmd,
struct flock *);
/**
* Perform POSIX file locking operation
*
* The cmd argument will be either F_GETLK, F_SETLK or F_SETLKW.
*
* For the meaning of fields in 'struct flock' see the man page
* for fcntl(2). The l_whence field will always be set to
* SEEK_SET.
*
* For checking lock ownership, the 'fuse_file_info->owner'
* argument must be used.
*
* For F_GETLK operation, the library will first check currently
* held locks, and if a conflicting lock is found it will return
* information without calling this method. This ensures, that
* for local locks the l_pid field is correctly filled in. The
* results may not be accurate in case of race conditions and in
* the presence of hard links, but it's unlikly that an
* application would rely on accurate GETLK results in these
* cases. If a conflicting lock is not found, this method will be
* called, and the filesystem may fill out l_pid by a meaningful
* value, or it may leave this field zero.
*
* For F_SETLK and F_SETLKW the l_pid field will be set to the pid
* of the process performing the locking operation.
*
* Note: if this method is not implemented, the kernel will still
* allow file locking to work locally. Hence it is only
* interesting for network filesystems and similar.
*
* Introduced in version 2.6
*/
int (*lock) (const char *, struct fuse_file_info *, int cmd,
struct flock *);
/**
* Change the access and modification times of a file with
* nanosecond resolution
*
* Introduced in version 2.6
*/
int (*utimens) (const char *, const struct timespec tv[2]);
/**
* Change the access and modification times of a file with
* nanosecond resolution
*
* Introduced in version 2.6
*/
int (*utimens) (const char *, const struct timespec tv[2]);
/**
* Map block index within file to block index within device
*
* Note: This makes sense only for block device backed filesystems
* mounted with the 'blkdev' option
*
* Introduced in version 2.6
*/
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
/**
* Map block index within file to block index within device
*
* Note: This makes sense only for block device backed filesystems
* mounted with the 'blkdev' option
*
* Introduced in version 2.6
*/
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
};
/** Extra context that may be needed by some filesystems
@ -430,20 +431,20 @@ struct fuse_operations {
* operation.
*/
struct fuse_context {
/** Pointer to the fuse object */
struct fuse *fuse;
/** Pointer to the fuse object */
struct fuse *fuse;
/** User ID of the calling process */
uid_t uid;
/** User ID of the calling process */
uid_t uid;
/** Group ID of the calling process */
gid_t gid;
/** Group ID of the calling process */
gid_t gid;
/** Thread ID of the calling process */
pid_t pid;
/** Thread ID of the calling process */
pid_t pid;
/** Private filesystem data */
void *private_data;
/** Private filesystem data */
void *private_data;
};
/**
@ -470,14 +471,14 @@ struct fuse_context {
* @return 0 on success, nonzero on failure
*/
/*
int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
void *user_data);
int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
void *user_data);
*/
#define fuse_main(argc, argv, op, user_data) \
fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
#define fuse_main(argc, argv, op, user_data) \
fuse_main_real(argc, argv, op, sizeof(*(op)), user_data)
/* ----------------------------------------------------------- *
* More detailed API *
* More detailed API *
* ----------------------------------------------------------- */
/**
@ -491,15 +492,15 @@ int fuse_main(int argc, char *argv[], const struct fuse_operations *op,
* @return the created FUSE handle
*/
struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op, size_t op_size,
void *user_data);
const struct fuse_operations *op, size_t op_size,
void *user_data);
/**
* Destroy the FUSE handle.
*
* The communication channel attached to the handle is also destroyed.
*
* NOTE: This function does not unmount the filesystem. If this is
* NOTE: This function does not unmount the filesystem. If this is
* needed, call fuse_unmount() before calling this function.
*
* @param f the FUSE handle
@ -573,7 +574,7 @@ int fuse_is_lib_option(const char *opt);
* Do not call this directly, use fuse_main()
*/
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
size_t op_size, void *user_data);
size_t op_size, void *user_data);
/*
* Stacking API
@ -597,63 +598,63 @@ struct fuse_fs;
int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf);
int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
const char *newpath);
const char *newpath);
int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
const char *path);
const char *path);
int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
int fuse_fs_release(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
int fuse_fs_release(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
int fuse_fs_open(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
off_t off, struct fuse_file_info *fi);
off_t off, struct fuse_file_info *fi);
int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi);
size_t size, off_t off, struct fuse_file_info *fi);
int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_flush(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
fuse_fill_dir_t filler, off_t off,
struct fuse_file_info *fi);
fuse_fill_dir_t filler, off_t off,
struct fuse_file_info *fi);
int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_lock(struct fuse_fs *fs, const char *path,
struct fuse_file_info *fi, int cmd, struct flock *lock);
struct fuse_file_info *fi, int cmd, struct flock *lock);
int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode);
int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid);
int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size);
int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
struct fuse_file_info *fi);
struct fuse_file_info *fi);
int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
const struct timespec tv[2]);
const struct timespec tv[2]);
int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
size_t len);
size_t len);
int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
dev_t rdev);
dev_t rdev);
int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
const char *value, size_t size, int flags);
const char *value, size_t size, int flags);
int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
char *value, size_t size);
char *value, size_t size);
int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
size_t size);
size_t size);
int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
const char *name);
const char *name);
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
uint64_t *idx);
uint64_t *idx);
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
void fuse_fs_destroy(struct fuse_fs *fs);
@ -669,7 +670,7 @@ void fuse_fs_destroy(struct fuse_fs *fs);
* @return a new filesystem object
*/
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
void *user_data);
void *user_data);
/**
* Filesystem module
@ -682,30 +683,31 @@ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
* function.
*/
struct fuse_module {
/**
* Name of filesystem
*/
const char *name;
/**
* Name of filesystem
*/
const char *name;
/**
* Factory for creating filesystem objects
*
* The function may use and remove options from 'args' that belong
* to this module.
*
* For now the 'fs' vector always contains exactly one filesystem.
* This is the filesystem which will be below the newly created
* filesystem in the stack.
*
* @param args the command line arguments
* @param fs NULL terminated filesystem object vector
* @return the new filesystem object
*/
struct fuse_fs *(*factory)(struct fuse_args *args, struct fuse_fs *fs[]);
/**
* Factory for creating filesystem objects
*
* The function may use and remove options from 'args' that belong
* to this module.
*
* For now the 'fs' vector always contains exactly one filesystem.
* This is the filesystem which will be below the newly created
* filesystem in the stack.
*
* @param args the command line arguments
* @param fs NULL terminated filesystem object vector
* @return the new filesystem object
*/
struct fuse_fs *(*factory)(struct fuse_args *args,
struct fuse_fs *fs[]);
struct fuse_module *next;
struct fusemod_so *so;
int ctr;
struct fuse_module *next;
struct fusemod_so *so;
int ctr;
};
/**
@ -722,12 +724,13 @@ void fuse_register_module(struct fuse_module *mod);
* For the parameters, see description of the fields in 'struct
* fuse_module'
*/
#define FUSE_REGISTER_MODULE(name_, factory_) \
static __attribute__((constructor)) void name_ ## _register(void) \
{ \
static struct fuse_module mod = { #name_, factory_, NULL, NULL, 0 }; \
fuse_register_module(&mod); \
}
#define FUSE_REGISTER_MODULE(name_, factory_) \
static __attribute__((constructor)) void name_ ## _register(void) \
{ \
static struct fuse_module mod = \
{ #name_, factory_, NULL, NULL, 0 }; \
fuse_register_module(&mod); \
}
/* ----------------------------------------------------------- *
@ -742,9 +745,9 @@ typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *);
/** This is the part of fuse_main() before the event loop */
struct fuse *fuse_setup(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
char **mountpoint, int *multithreaded,
void *user_data);
const struct fuse_operations *op, size_t op_size,
char **mountpoint, int *multithreaded,
void *user_data);
/** This is the part of fuse_main() after the event loop */
void fuse_teardown(struct fuse *fuse, char *mountpoint);
@ -770,22 +773,22 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void));
struct fuse_session *fuse_get_session(struct fuse *f);
/* ----------------------------------------------------------- *
* Compatibility stuff *
* Compatibility stuff *
* ----------------------------------------------------------- */
#if FUSE_USE_VERSION < 26
# include "fuse_compat.h"
# undef fuse_main
# if FUSE_USE_VERSION == 25
# define fuse_main(argc, argv, op) \
fuse_main_real_compat25(argc, argv, op, sizeof(*(op)))
# define fuse_main(argc, argv, op) \
fuse_main_real_compat25(argc, argv, op, sizeof(*(op)))
# define fuse_new fuse_new_compat25
# define fuse_setup fuse_setup_compat25
# define fuse_teardown fuse_teardown_compat22
# define fuse_operations fuse_operations_compat25
# elif FUSE_USE_VERSION == 22
# define fuse_main(argc, argv, op) \
fuse_main_real_compat22(argc, argv, op, sizeof(*(op)))
# define fuse_main(argc, argv, op) \
fuse_main_real_compat22(argc, argv, op, sizeof(*(op)))
# define fuse_new fuse_new_compat22
# define fuse_setup fuse_setup_compat22
# define fuse_teardown fuse_teardown_compat22

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/** @file */
@ -42,38 +42,38 @@ extern "C" {
* Changed in version 2.5
*/
struct fuse_file_info {
/** Open flags. Available in open() and release() */
int flags;
/** Open flags. Available in open() and release() */
int flags;
/** Old file handle, don't use */
unsigned long fh_old;
/** Old file handle, don't use */
unsigned long fh_old;
/** In case of a write operation indicates if this was caused by a
writepage */
int writepage;
/** In case of a write operation indicates if this was caused by a
writepage */
int writepage;
/** Can be filled in by open, to use direct I/O on this file.
Introduced in version 2.4 */
unsigned int direct_io : 1;
/** Can be filled in by open, to use direct I/O on this file.
Introduced in version 2.4 */
unsigned int direct_io : 1;
/** Can be filled in by open, to indicate, that cached file data
need not be invalidated. Introduced in version 2.4 */
unsigned int keep_cache : 1;
/** Can be filled in by open, to indicate, that cached file data
need not be invalidated. Introduced in version 2.4 */
unsigned int keep_cache : 1;
/** Indicates a flush operation. Set in flush operation, also
maybe set in highlevel lock operation and lowlevel release
operation. Introduced in version 2.6 */
unsigned int flush : 1;
/** Indicates a flush operation. Set in flush operation, also
maybe set in highlevel lock operation and lowlevel release
operation. Introduced in version 2.6 */
unsigned int flush : 1;
/** Padding. Do not use*/
unsigned int padding : 29;
/** Padding. Do not use*/
unsigned int padding : 29;
/** File handle. May be filled in by filesystem in open().
Available in all other file operations */
uint64_t fh;
/** File handle. May be filled in by filesystem in open().
Available in all other file operations */
uint64_t fh;
/** Lock owner id. Available in locking operations and flush */
uint64_t lock_owner;
/** Lock owner id. Available in locking operations and flush */
uint64_t lock_owner;
};
/**
@ -84,35 +84,35 @@ struct fuse_file_info {
* value must usually be smaller than the indicated value.
*/
struct fuse_conn_info {
/**
* Major version of the protocol (read-only)
*/
unsigned proto_major;
/**
* Major version of the protocol (read-only)
*/
unsigned proto_major;
/**
* Minor version of the protocol (read-only)
*/
unsigned proto_minor;
/**
* Minor version of the protocol (read-only)
*/
unsigned proto_minor;
/**
* Is asynchronous read supported (read-write)
*/
unsigned async_read;
/**
* Is asynchronous read supported (read-write)
*/
unsigned async_read;
/**
* Maximum size of the write buffer
*/
unsigned max_write;
/**
* Maximum size of the write buffer
*/
unsigned max_write;
/**
* Maximum readahead
*/
unsigned max_readahead;
/**
* Maximum readahead
*/
unsigned max_readahead;
/**
* For future use.
*/
unsigned reserved[27];
/**
* For future use.
*/
unsigned reserved[27];
};
struct fuse_session;
@ -143,13 +143,13 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
*
* The following options are parsed:
*
* '-f' foreground
* '-f' foreground
* '-d' '-odebug' foreground, but keep the debug option
* '-s' single threaded
* '-s' single threaded
* '-h' '--help' help
* '-ho' help without header
* '-ho' help without header
* '-ofsname=..' file system name, if not present, then set to the program
* name
* name
*
* All parameters may be NULL
*
@ -160,7 +160,7 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
* @return 0 on success, -1 on failure
*/
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
int *multithreaded, int *foreground);
int *multithreaded, int *foreground);
/**
* Go into the background
@ -178,13 +178,13 @@ int fuse_daemonize(int foreground);
int fuse_version(void);
/* ----------------------------------------------------------- *
* Signal handling *
* Signal handling *
* ----------------------------------------------------------- */
/**
* Exit session on HUP, TERM and INT signals and ignore PIPE signal
*
* Stores session in a global variable. May only be called once per
* Stores session in a global variable. May only be called once per
* process until fuse_remove_signal_handlers() is called.
*
* @param se the session to exit
@ -203,36 +203,36 @@ int fuse_set_signal_handlers(struct fuse_session *se);
void fuse_remove_signal_handlers(struct fuse_session *se);
/* ----------------------------------------------------------- *
* Compatibility stuff *
* Compatibility stuff *
* ----------------------------------------------------------- */
#if FUSE_USE_VERSION < 26
# ifdef __FreeBSD__
# if FUSE_USE_VERSION < 25
# error On FreeBSD API version 25 or greater must be used
# endif
# if FUSE_USE_VERSION < 25
# error On FreeBSD API version 25 or greater must be used
# endif
# endif
# include "fuse_common_compat.h"
# undef FUSE_MINOR_VERSION
# undef fuse_main
# define fuse_unmount fuse_unmount_compat22
# if FUSE_USE_VERSION == 25
# define FUSE_MINOR_VERSION 5
# define fuse_mount fuse_mount_compat25
# define FUSE_MINOR_VERSION 5
# define fuse_mount fuse_mount_compat25
# elif FUSE_USE_VERSION == 24 || FUSE_USE_VERSION == 22
# define FUSE_MINOR_VERSION 4
# define fuse_mount fuse_mount_compat22
# define FUSE_MINOR_VERSION 4
# define fuse_mount fuse_mount_compat22
# elif FUSE_USE_VERSION == 21
# define FUSE_MINOR_VERSION 1
# define fuse_mount fuse_mount_compat22
# define FUSE_MINOR_VERSION 1
# define fuse_mount fuse_mount_compat22
# elif FUSE_USE_VERSION == 11
# warning Compatibility with API version 11 is deprecated
# undef FUSE_MAJOR_VERSION
# define FUSE_MAJOR_VERSION 1
# define FUSE_MINOR_VERSION 1
# define fuse_mount fuse_mount_compat1
# warning Compatibility with API version 11 is deprecated
# undef FUSE_MAJOR_VERSION
# define FUSE_MAJOR_VERSION 1
# define FUSE_MINOR_VERSION 1
# define fuse_mount fuse_mount_compat1
# else
# error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported
# error Compatibility with API version other than 21, 22, 24, 25 and 11 not supported
# endif
#endif

View File

@ -1,20 +1,20 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/* these definitions provide source compatibility to prior versions.
Do not include this file directly! */
struct fuse_file_info_compat {
int flags;
unsigned long fh;
int writepage;
unsigned int direct_io : 1;
unsigned int keep_cache : 1;
int flags;
unsigned long fh;
int writepage;
unsigned int direct_io : 1;
unsigned int keep_cache : 1;
};
int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args);
@ -24,4 +24,3 @@ int fuse_mount_compat22(const char *mountpoint, const char *opts);
int fuse_mount_compat1(const char *mountpoint, const char *args[]);
void fuse_unmount_compat22(const char *mountpoint);

View File

@ -1,66 +1,67 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/* these definitions provide source compatibility to prior versions.
Do not include this file directly! */
struct fuse_operations_compat25 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, struct fuse_file_info *);
int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info *);
int (*statfs) (const char *, struct statvfs *);
int (*flush) (const char *, struct fuse_file_info *);
int (*release) (const char *, struct fuse_file_info *);
int (*fsync) (const char *, int, struct fuse_file_info *);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*opendir) (const char *, struct fuse_file_info *);
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info *);
int (*releasedir) (const char *, struct fuse_file_info *);
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
void *(*init) (void);
void (*destroy) (void *);
int (*access) (const char *, int);
int (*create) (const char *, mode_t, struct fuse_file_info *);
int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, struct fuse_file_info *);
int (*read) (const char *, char *, size_t, off_t,
struct fuse_file_info *);
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info *);
int (*statfs) (const char *, struct statvfs *);
int (*flush) (const char *, struct fuse_file_info *);
int (*release) (const char *, struct fuse_file_info *);
int (*fsync) (const char *, int, struct fuse_file_info *);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*opendir) (const char *, struct fuse_file_info *);
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info *);
int (*releasedir) (const char *, struct fuse_file_info *);
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
void *(*init) (void);
void (*destroy) (void *);
int (*access) (const char *, int);
int (*create) (const char *, mode_t, struct fuse_file_info *);
int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *);
};
struct fuse *fuse_new_compat25(int fd, struct fuse_args *args,
const struct fuse_operations_compat25 *op,
size_t op_size);
const struct fuse_operations_compat25 *op,
size_t op_size);
int fuse_main_real_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size);
const struct fuse_operations_compat25 *op,
size_t op_size);
struct fuse *fuse_setup_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd);
const struct fuse_operations_compat25 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd);
void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint);
@ -68,126 +69,133 @@ void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint);
#include <sys/statfs.h>
struct fuse_operations_compat22 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, struct fuse_file_info_compat *);
int (*read) (const char *, char *, size_t, off_t,
struct fuse_file_info_compat *);
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info_compat *);
int (*statfs) (const char *, struct statfs *);
int (*flush) (const char *, struct fuse_file_info_compat *);
int (*release) (const char *, struct fuse_file_info_compat *);
int (*fsync) (const char *, int, struct fuse_file_info_compat *);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*opendir) (const char *, struct fuse_file_info_compat *);
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info_compat *);
int (*releasedir) (const char *, struct fuse_file_info_compat *);
int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *);
void *(*init) (void);
void (*destroy) (void *);
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, struct fuse_file_info_compat *);
int (*read) (const char *, char *, size_t, off_t,
struct fuse_file_info_compat *);
int (*write) (const char *, const char *, size_t, off_t,
struct fuse_file_info_compat *);
int (*statfs) (const char *, struct statfs *);
int (*flush) (const char *, struct fuse_file_info_compat *);
int (*release) (const char *, struct fuse_file_info_compat *);
int (*fsync) (const char *, int, struct fuse_file_info_compat *);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*opendir) (const char *, struct fuse_file_info_compat *);
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info_compat *);
int (*releasedir) (const char *, struct fuse_file_info_compat *);
int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *);
void *(*init) (void);
void (*destroy) (void *);
};
struct fuse *fuse_new_compat22(int fd, const char *opts,
const struct fuse_operations_compat22 *op,
size_t op_size);
const struct fuse_operations_compat22 *op,
size_t op_size);
struct fuse *fuse_setup_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd);
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd);
int fuse_main_real_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size);
const struct fuse_operations_compat22 *op,
size_t op_size);
typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type);
struct fuse_operations_compat2 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
int (*statfs) (const char *, struct statfs *);
int (*flush) (const char *);
int (*release) (const char *, int);
int (*fsync) (const char *, int);
int (*setxattr) (const char *, const char *, const char *, size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
int (*statfs) (const char *, struct statfs *);
int (*flush) (const char *);
int (*release) (const char *, int);
int (*fsync) (const char *, int);
int (*setxattr) (const char *, const char *, const char *,
size_t, int);
int (*getxattr) (const char *, const char *, char *, size_t);
int (*listxattr) (const char *, char *, size_t);
int (*removexattr) (const char *, const char *);
};
int fuse_main_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op);
int fuse_main_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op);
struct fuse *fuse_new_compat2(int fd, const char *opts, const struct fuse_operations_compat2 *op);
struct fuse *fuse_new_compat2(int fd, const char *opts,
const struct fuse_operations_compat2 *op);
struct fuse *fuse_setup_compat2(int argc, char *argv[], const struct fuse_operations_compat2 *op, char **mountpoint, int *multithreaded, int *fd);
struct fuse *fuse_setup_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op,
char **mountpoint, int *multithreaded, int *fd);
struct fuse_statfs_compat1 {
long block_size;
long blocks;
long blocks_free;
long files;
long files_free;
long namelen;
long block_size;
long blocks;
long blocks_free;
long files;
long files_free;
long namelen;
};
struct fuse_operations_compat1 {
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
int (*statfs) (struct fuse_statfs_compat1 *);
int (*release) (const char *, int);
int (*fsync) (const char *, int);
int (*getattr) (const char *, struct stat *);
int (*readlink) (const char *, char *, size_t);
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
int (*mknod) (const char *, mode_t, dev_t);
int (*mkdir) (const char *, mode_t);
int (*unlink) (const char *);
int (*rmdir) (const char *);
int (*symlink) (const char *, const char *);
int (*rename) (const char *, const char *);
int (*link) (const char *, const char *);
int (*chmod) (const char *, mode_t);
int (*chown) (const char *, uid_t, gid_t);
int (*truncate) (const char *, off_t);
int (*utime) (const char *, struct utimbuf *);
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
int (*statfs) (struct fuse_statfs_compat1 *);
int (*release) (const char *, int);
int (*fsync) (const char *, int);
};
#define FUSE_DEBUG_COMPAT1 (1 << 1)
#define FUSE_DEBUG_COMPAT1 (1 << 1)
struct fuse *fuse_new_compat1(int fd, int flags, const struct fuse_operations_compat1 *op);
struct fuse *fuse_new_compat1(int fd, int flags,
const struct fuse_operations_compat1 *op);
void fuse_main_compat1(int argc, char *argv[], const struct fuse_operations_compat1 *op);
void fuse_main_compat1(int argc, char *argv[],
const struct fuse_operations_compat1 *op);
#endif /* __FreeBSD__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,144 +1,155 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
/* these definitions provide source compatibility to prior versions.
Do not include this file directly! */
struct fuse_lowlevel_ops_compat25 {
void (*init) (void *userdata);
void (*destroy) (void *userdata);
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi);
void (*readlink) (fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi);
void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi);
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
void (*statfs) (fuse_req_t req);
void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info *fi);
void (*init) (void *userdata);
void (*destroy) (void *userdata);
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
void (*getattr) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi);
void (*readlink) (fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
void (*open) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi);
void (*flush) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*release) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
void (*opendir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
void (*statfs) (fuse_req_t req);
void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info *fi);
};
struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
const struct fuse_lowlevel_ops_compat25 *op,
size_t op_size, void *userdata);
const struct fuse_lowlevel_ops_compat25 *op,
size_t op_size, void *userdata);
size_t fuse_dirent_size(size_t namelen);
char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
off_t off);
off_t off);
#ifndef __FreeBSD__
#include <sys/statfs.h>
struct fuse_lowlevel_ops_compat {
void (*init) (void *userdata);
void (*destroy) (void *userdata);
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi);
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info_compat *fi);
void (*readlink) (fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info_compat *fi);
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info_compat *fi);
void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi);
void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi);
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info_compat *fi);
void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info_compat *fi);
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info_compat *fi);
void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info_compat *fi);
void (*statfs) (fuse_req_t req);
void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info_compat *fi);
void (*init) (void *userdata);
void (*destroy) (void *userdata);
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup);
void (*getattr) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info_compat *fi);
void (*readlink) (fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode);
void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
const char *name);
void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
fuse_ino_t newparent, const char *newname);
void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
const char *newname);
void (*open) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info_compat *fi);
void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
size_t size, off_t off, struct fuse_file_info_compat *fi);
void (*flush) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*release) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info_compat *fi);
void (*opendir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info_compat *fi);
void (*releasedir) (fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info_compat *fi);
void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info_compat *fi);
void (*statfs) (fuse_req_t req);
void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags);
void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size);
void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
mode_t mode, struct fuse_file_info_compat *fi);
};
int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf);
int fuse_reply_open_compat(fuse_req_t req,
const struct fuse_file_info_compat *fi);
const struct fuse_file_info_compat *fi);
struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
const struct fuse_lowlevel_ops_compat *op,
size_t op_size, void *userdata);
const struct fuse_lowlevel_ops_compat *op,
size_t op_size, void *userdata);
#endif /* __FreeBSD__ */
struct fuse_chan_ops_compat24 {
int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count);
void (*destroy)(struct fuse_chan *ch);
int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
int (*send)(struct fuse_chan *ch, const struct iovec iov[],
size_t count);
void (*destroy)(struct fuse_chan *ch);
};
struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
int fd, size_t bufsize, void *data);
int fd, size_t bufsize, void *data);
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
struct fuse_chan *fuse_kern_chan_new(int fd);

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#ifndef _FUSE_OPT_H_
@ -41,7 +41,7 @@ extern "C" {
*
* - 'offsetof(struct foo, member)' actions i) and iii)
*
* - -1 action ii)
* - -1 action ii)
*
* The 'offsetof()' macro is defined in the <stddef.h> header.
*
@ -52,7 +52,7 @@ extern "C" {
*
* The types of templates are:
*
* 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
* 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
* themselves. Invalid values are "--" and anything beginning
* with "-o"
*
@ -74,30 +74,30 @@ extern "C" {
* with scanf().
*/
struct fuse_opt {
/** Matching template and optional parameter formatting */
const char *templ;
/** Matching template and optional parameter formatting */
const char *templ;
/**
* Offset of variable within 'data' parameter of fuse_opt_parse()
* or -1
*/
unsigned long offset;
/**
* Offset of variable within 'data' parameter of fuse_opt_parse()
* or -1
*/
unsigned long offset;
/**
* Value to set the variable to, or to be passed as 'key' to the
* processing function. Ignored if template has a format
*/
int value;
/**
* Value to set the variable to, or to be passed as 'key' to the
* processing function. Ignored if template has a format
*/
int value;
};
/**
* Key option. In case of a match, the processing function will be
* Key option. In case of a match, the processing function will be
* called with the specified key.
*/
#define FUSE_OPT_KEY(templ, key) { templ, -1U, key }
/**
* Last option. An array of 'struct fuse_opt' must end with a NULL
* Last option. An array of 'struct fuse_opt' must end with a NULL
* template value
*/
#define FUSE_OPT_END { .templ = NULL }
@ -106,14 +106,14 @@ struct fuse_opt {
* Argument list
*/
struct fuse_args {
/** Argument count */
int argc;
/** Argument count */
int argc;
/** Argument vector. NULL terminated */
char **argv;
/** Argument vector. NULL terminated */
char **argv;
/** Is 'argv' allocated? */
int allocated;
/** Is 'argv' allocated? */
int allocated;
};
/**
@ -177,7 +177,7 @@ struct fuse_args {
* @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
*/
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
struct fuse_args *outargs);
struct fuse_args *outargs);
/**
* Option parsing function
@ -200,7 +200,7 @@ typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
* @return -1 on error, 0 on success
*/
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc);
const struct fuse_opt opts[], fuse_opt_proc_t proc);
/**
* Add an option to a comma separated option list

View File

@ -1,9 +1,9 @@
/*
libulockmgr: Userspace Lock Manager Library
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
libulockmgr: Userspace Lock Manager Library
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include <stdint.h>
@ -21,4 +21,4 @@
* @return 0 on success -errno on error
*/
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
size_t owner_len);
size_t owner_len);

4695
lib/fuse.c

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse.h"
@ -14,22 +14,22 @@ struct fuse_lowlevel_ops;
struct fuse_req;
struct fuse_cmd {
char *buf;
size_t buflen;
struct fuse_chan *ch;
char *buf;
size_t buflen;
struct fuse_chan *ch;
};
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data, int compat);
const struct fuse_operations *op,
size_t op_size, void *user_data, int compat);
int fuse_sync_compat_args(struct fuse_args *args);
struct fuse_chan *fuse_kern_chan_new(int fd);
struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata);
const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata);
void fuse_kern_unmount_compat22(const char *mountpoint);
void fuse_kern_unmount(const char *mountpoint, int fd);

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
@ -16,80 +16,80 @@
#include <assert.h>
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
size_t size)
size_t size)
{
struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
restart:
res = read(fuse_chan_fd(ch), buf, size);
err = errno;
restart:
res = read(fuse_chan_fd(ch), buf, size);
err = errno;
if (fuse_session_exited(se))
return 0;
if (res == -1) {
/* ENOENT means the operation was interrupted, it's safe
to restart */
if (err == ENOENT)
goto restart;
if (fuse_session_exited(se))
return 0;
if (res == -1) {
/* ENOENT means the operation was interrupted, it's safe
to restart */
if (err == ENOENT)
goto restart;
if (err == ENODEV) {
fuse_session_exit(se);
return 0;
}
/* Errors occuring during normal operation: EINTR (read
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
umounted) */
if (err != EINTR && err != EAGAIN)
perror("fuse: reading device");
return -err;
}
if ((size_t) res < sizeof(struct fuse_in_header)) {
fprintf(stderr, "short read on fuse device\n");
return -EIO;
}
return res;
if (err == ENODEV) {
fuse_session_exit(se);
return 0;
}
/* Errors occuring during normal operation: EINTR (read
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
umounted) */
if (err != EINTR && err != EAGAIN)
perror("fuse: reading device");
return -err;
}
if ((size_t) res < sizeof(struct fuse_in_header)) {
fprintf(stderr, "short read on fuse device\n");
return -EIO;
}
return res;
}
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
size_t count)
size_t count)
{
if (iov) {
ssize_t res = writev(fuse_chan_fd(ch), iov, count);
int err = errno;
if (iov) {
ssize_t res = writev(fuse_chan_fd(ch), iov, count);
int err = errno;
if (res == -1) {
struct fuse_session *se = fuse_chan_session(ch);
if (res == -1) {
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
assert(se != NULL);
/* ENOENT means the operation was interrupted */
if (!fuse_session_exited(se) && err != ENOENT)
perror("fuse: writing device");
return -err;
}
}
return 0;
/* ENOENT means the operation was interrupted */
if (!fuse_session_exited(se) && err != ENOENT)
perror("fuse: writing device");
return -err;
}
}
return 0;
}
static void fuse_kern_chan_destroy(struct fuse_chan *ch)
{
close(fuse_chan_fd(ch));
close(fuse_chan_fd(ch));
}
#define MIN_BUFSIZE 0x21000
struct fuse_chan *fuse_kern_chan_new(int fd)
{
struct fuse_chan_ops op = {
.receive = fuse_kern_chan_receive,
.send = fuse_kern_chan_send,
.destroy = fuse_kern_chan_destroy,
};
size_t bufsize = getpagesize() + 0x1000;
bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
return fuse_chan_new(&op, fd, bufsize, NULL);
struct fuse_chan_ops op = {
.receive = fuse_kern_chan_receive,
.send = fuse_kern_chan_send,
.destroy = fuse_kern_chan_destroy,
};
size_t bufsize = getpagesize() + 0x1000;
bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
return fuse_chan_new(&op, fd, bufsize, NULL);
}

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
@ -14,26 +14,26 @@
int fuse_session_loop(struct fuse_session *se)
{
int res = 0;
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
size_t bufsize = fuse_chan_bufsize(ch);
char *buf = (char *) malloc(bufsize);
if (!buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
return -1;
}
int res = 0;
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
size_t bufsize = fuse_chan_bufsize(ch);
char *buf = (char *) malloc(bufsize);
if (!buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
return -1;
}
while (!fuse_session_exited(se)) {
struct fuse_chan *tmpch = ch;
res = fuse_chan_recv(&tmpch, buf, bufsize);
if (res == -EINTR)
continue;
if (res <= 0)
break;
fuse_session_process(se, buf, res, tmpch);
}
while (!fuse_session_exited(se)) {
struct fuse_chan *tmpch = ch;
res = fuse_chan_recv(&tmpch, buf, bufsize);
if (res == -EINTR)
continue;
if (res <= 0)
break;
fuse_session_process(se, buf, res, tmpch);
}
free(buf);
fuse_session_reset(se);
return res < 0 ? -1 : 0;
free(buf);
fuse_session_reset(se);
return res < 0 ? -1 : 0;
}

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "fuse_lowlevel.h"
@ -20,202 +20,203 @@
#include <sys/time.h>
struct fuse_worker {
struct fuse_worker *prev;
struct fuse_worker *next;
pthread_t thread_id;
size_t bufsize;
char *buf;
struct fuse_mt *mt;
struct fuse_worker *prev;
struct fuse_worker *next;
pthread_t thread_id;
size_t bufsize;
char *buf;
struct fuse_mt *mt;
};
struct fuse_mt {
pthread_mutex_t lock;
int numworker;
int numavail;
struct fuse_session *se;
struct fuse_chan *prevch;
struct fuse_worker main;
sem_t finish;
int exit;
int error;
pthread_mutex_t lock;
int numworker;
int numavail;
struct fuse_session *se;
struct fuse_chan *prevch;
struct fuse_worker main;
sem_t finish;
int exit;
int error;
};
static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
{
struct fuse_worker *prev = next->prev;
w->next = next;
w->prev = prev;
prev->next = w;
next->prev = w;
struct fuse_worker *prev = next->prev;
w->next = next;
w->prev = prev;
prev->next = w;
next->prev = w;
}
static void list_del_worker(struct fuse_worker *w)
{
struct fuse_worker *prev = w->prev;
struct fuse_worker *next = w->next;
prev->next = next;
next->prev = prev;
struct fuse_worker *prev = w->prev;
struct fuse_worker *next = w->next;
prev->next = next;
next->prev = prev;
}
static int fuse_start_thread(struct fuse_mt *mt);
static void *fuse_do_work(void *data)
{
struct fuse_worker *w = (struct fuse_worker *) data;
struct fuse_mt *mt = w->mt;
struct fuse_worker *w = (struct fuse_worker *) data;
struct fuse_mt *mt = w->mt;
while (!fuse_session_exited(mt->se)) {
int isforget = 0;
struct fuse_chan *ch = mt->prevch;
int res = fuse_chan_recv(&ch, w->buf, w->bufsize);
if (res == -EINTR)
continue;
if (res <= 0) {
if (res < 0) {
fuse_session_exit(mt->se);
mt->error = -1;
}
break;
}
while (!fuse_session_exited(mt->se)) {
int isforget = 0;
struct fuse_chan *ch = mt->prevch;
int res = fuse_chan_recv(&ch, w->buf, w->bufsize);
if (res == -EINTR)
continue;
if (res <= 0) {
if (res < 0) {
fuse_session_exit(mt->se);
mt->error = -1;
}
break;
}
pthread_mutex_lock(&mt->lock);
if (mt->exit) {
pthread_mutex_unlock(&mt->lock);
return NULL;
}
pthread_mutex_lock(&mt->lock);
if (mt->exit) {
pthread_mutex_unlock(&mt->lock);
return NULL;
}
/*
* This disgusting hack is needed so that zillions of threads
* are not created on a burst of FORGET messages
*/
if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET)
isforget = 1;
/*
* This disgusting hack is needed so that zillions of threads
* are not created on a burst of FORGET messages
*/
if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET)
isforget = 1;
if (!isforget)
mt->numavail--;
if (mt->numavail == 0)
fuse_start_thread(mt);
pthread_mutex_unlock(&mt->lock);
if (!isforget)
mt->numavail--;
if (mt->numavail == 0)
fuse_start_thread(mt);
pthread_mutex_unlock(&mt->lock);
fuse_session_process(mt->se, w->buf, res, ch);
fuse_session_process(mt->se, w->buf, res, ch);
pthread_mutex_lock(&mt->lock);
if (!isforget)
mt->numavail++;
if (mt->numavail > 10) {
if (mt->exit) {
pthread_mutex_unlock(&mt->lock);
return NULL;
}
list_del_worker(w);
mt->numavail--;
mt->numworker--;
pthread_mutex_unlock(&mt->lock);
pthread_mutex_lock(&mt->lock);
if (!isforget)
mt->numavail++;
if (mt->numavail > 10) {
if (mt->exit) {
pthread_mutex_unlock(&mt->lock);
return NULL;
}
list_del_worker(w);
mt->numavail--;
mt->numworker--;
pthread_mutex_unlock(&mt->lock);
pthread_detach(w->thread_id);
free(w->buf);
free(w);
return NULL;
}
pthread_mutex_unlock(&mt->lock);
}
pthread_detach(w->thread_id);
free(w->buf);
free(w);
return NULL;
}
pthread_mutex_unlock(&mt->lock);
}
sem_post(&mt->finish);
pause();
sem_post(&mt->finish);
pause();
return NULL;
return NULL;
}
static int fuse_start_thread(struct fuse_mt *mt)
{
sigset_t oldset;
sigset_t newset;
int res;
struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
if (!w) {
fprintf(stderr, "fuse: failed to allocate worker structure\n");
return -1;
}
memset(w, 0, sizeof(struct fuse_worker));
w->bufsize = fuse_chan_bufsize(mt->prevch);
w->buf = malloc(w->bufsize);
w->mt = mt;
if (!w->buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
free(w);
return -1;
}
sigset_t oldset;
sigset_t newset;
int res;
struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
if (!w) {
fprintf(stderr, "fuse: failed to allocate worker structure\n");
return -1;
}
memset(w, 0, sizeof(struct fuse_worker));
w->bufsize = fuse_chan_bufsize(mt->prevch);
w->buf = malloc(w->bufsize);
w->mt = mt;
if (!w->buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
free(w);
return -1;
}
/* Disallow signal reception in worker threads */
sigemptyset(&newset);
sigaddset(&newset, SIGTERM);
sigaddset(&newset, SIGINT);
sigaddset(&newset, SIGHUP);
sigaddset(&newset, SIGQUIT);
pthread_sigmask(SIG_BLOCK, &newset, &oldset);
res = pthread_create(&w->thread_id, NULL, fuse_do_work, w);
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
if (res != 0) {
fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res));
free(w->buf);
free(w);
return -1;
}
list_add_worker(w, &mt->main);
mt->numavail ++;
mt->numworker ++;
/* Disallow signal reception in worker threads */
sigemptyset(&newset);
sigaddset(&newset, SIGTERM);
sigaddset(&newset, SIGINT);
sigaddset(&newset, SIGHUP);
sigaddset(&newset, SIGQUIT);
pthread_sigmask(SIG_BLOCK, &newset, &oldset);
res = pthread_create(&w->thread_id, NULL, fuse_do_work, w);
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
if (res != 0) {
fprintf(stderr, "fuse: error creating thread: %s\n",
strerror(res));
free(w->buf);
free(w);
return -1;
}
list_add_worker(w, &mt->main);
mt->numavail ++;
mt->numworker ++;
return 0;
return 0;
}
static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
{
pthread_join(w->thread_id, NULL);
pthread_mutex_lock(&mt->lock);
list_del_worker(w);
pthread_mutex_unlock(&mt->lock);
free(w->buf);
free(w);
pthread_join(w->thread_id, NULL);
pthread_mutex_lock(&mt->lock);
list_del_worker(w);
pthread_mutex_unlock(&mt->lock);
free(w->buf);
free(w);
}
int fuse_session_loop_mt(struct fuse_session *se)
{
int err;
struct fuse_mt mt;
struct fuse_worker *w;
int err;
struct fuse_mt mt;
struct fuse_worker *w;
memset(&mt, 0, sizeof(struct fuse_mt));
mt.se = se;
mt.prevch = fuse_session_next_chan(se, NULL);
mt.error = 0;
mt.numworker = 0;
mt.numavail = 0;
mt.main.thread_id = pthread_self();
mt.main.prev = mt.main.next = &mt.main;
sem_init(&mt.finish, 0, 0);
fuse_mutex_init(&mt.lock);
memset(&mt, 0, sizeof(struct fuse_mt));
mt.se = se;
mt.prevch = fuse_session_next_chan(se, NULL);
mt.error = 0;
mt.numworker = 0;
mt.numavail = 0;
mt.main.thread_id = pthread_self();
mt.main.prev = mt.main.next = &mt.main;
sem_init(&mt.finish, 0, 0);
fuse_mutex_init(&mt.lock);
pthread_mutex_lock(&mt.lock);
err = fuse_start_thread(&mt);
pthread_mutex_unlock(&mt.lock);
if (!err) {
/* sem_wait() is interruptible */
while (!fuse_session_exited(se))
sem_wait(&mt.finish);
pthread_mutex_lock(&mt.lock);
err = fuse_start_thread(&mt);
pthread_mutex_unlock(&mt.lock);
if (!err) {
/* sem_wait() is interruptible */
while (!fuse_session_exited(se))
sem_wait(&mt.finish);
for (w = mt.main.next; w != &mt.main; w = w->next)
pthread_cancel(w->thread_id);
mt.exit = 1;
pthread_mutex_unlock(&mt.lock);
for (w = mt.main.next; w != &mt.main; w = w->next)
pthread_cancel(w->thread_id);
mt.exit = 1;
pthread_mutex_unlock(&mt.lock);
while (mt.main.next != &mt.main)
fuse_join_worker(&mt, mt.main.next);
while (mt.main.next != &mt.main)
fuse_join_worker(&mt, mt.main.next);
err = mt.error;
}
err = mt.error;
}
pthread_mutex_destroy(&mt.lock);
sem_destroy(&mt.finish);
fuse_session_reset(se);
return err;
pthread_mutex_destroy(&mt.lock);
sem_destroy(&mt.finish);
fuse_session_reset(se);
return err;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "config.h"
@ -22,11 +22,11 @@
/* Is this hack still needed? */
static inline void fuse_mutex_init(pthread_mutex_t *mut)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
pthread_mutex_init(mut, &attr);
pthread_mutexattr_destroy(&attr);
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
pthread_mutex_init(mut, &attr);
pthread_mutexattr_destroy(&attr);
}
#endif

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "fuse_i.h"
@ -17,100 +17,100 @@
#include <assert.h>
struct procdata {
struct fuse *f;
struct fuse_chan *prevch;
struct fuse_session *prevse;
fuse_processor_t proc;
void *data;
struct fuse *f;
struct fuse_chan *prevch;
struct fuse_session *prevse;
fuse_processor_t proc;
void *data;
};
static void mt_session_proc(void *data, const char *buf, size_t len,
struct fuse_chan *ch)
struct fuse_chan *ch)
{
struct procdata *pd = (struct procdata *) data;
struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
struct procdata *pd = (struct procdata *) data;
struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
(void) len;
(void) ch;
pd->proc(pd->f, cmd, pd->data);
(void) len;
(void) ch;
pd->proc(pd->f, cmd, pd->data);
}
static void mt_session_exit(void *data, int val)
{
struct procdata *pd = (struct procdata *) data;
if (val)
fuse_session_exit(pd->prevse);
else
fuse_session_reset(pd->prevse);
struct procdata *pd = (struct procdata *) data;
if (val)
fuse_session_exit(pd->prevse);
else
fuse_session_reset(pd->prevse);
}
static int mt_session_exited(void *data)
{
struct procdata *pd = (struct procdata *) data;
return fuse_session_exited(pd->prevse);
struct procdata *pd = (struct procdata *) data;
return fuse_session_exited(pd->prevse);
}
static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_cmd *cmd;
struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
struct fuse_cmd *cmd;
struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
assert(size >= sizeof(cmd));
assert(size >= sizeof(cmd));
cmd = fuse_read_cmd(pd->f);
if (cmd == NULL)
return 0;
cmd = fuse_read_cmd(pd->f);
if (cmd == NULL)
return 0;
*(struct fuse_cmd **) buf = cmd;
*(struct fuse_cmd **) buf = cmd;
return sizeof(cmd);
return sizeof(cmd);
}
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
{
int res;
struct procdata pd;
struct fuse_session *prevse = fuse_get_session(f);
struct fuse_session *se;
struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
struct fuse_chan *ch;
struct fuse_session_ops sop = {
.exit = mt_session_exit,
.exited = mt_session_exited,
.process = mt_session_proc,
};
struct fuse_chan_ops cop = {
.receive = mt_chan_receive,
};
int res;
struct procdata pd;
struct fuse_session *prevse = fuse_get_session(f);
struct fuse_session *se;
struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
struct fuse_chan *ch;
struct fuse_session_ops sop = {
.exit = mt_session_exit,
.exited = mt_session_exited,
.process = mt_session_proc,
};
struct fuse_chan_ops cop = {
.receive = mt_chan_receive,
};
pd.f = f;
pd.prevch = prevch;
pd.prevse = prevse;
pd.proc = proc;
pd.data = data;
pd.f = f;
pd.prevch = prevch;
pd.prevse = prevse;
pd.proc = proc;
pd.data = data;
se = fuse_session_new(&sop, &pd);
if (se == NULL)
return -1;
se = fuse_session_new(&sop, &pd);
if (se == NULL)
return -1;
ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), sizeof(struct fuse_cmd *),
&pd);
if (ch == NULL) {
fuse_session_destroy(se);
return -1;
}
fuse_session_add_chan(se, ch);
res = fuse_session_loop_mt(se);
fuse_session_destroy(se);
return res;
ch = fuse_chan_new(&cop, fuse_chan_fd(prevch),
sizeof(struct fuse_cmd *), &pd);
if (ch == NULL) {
fuse_session_destroy(se);
return -1;
}
fuse_session_add_chan(se, ch);
res = fuse_session_loop_mt(se);
fuse_session_destroy(se);
return res;
}
int fuse_loop_mt(struct fuse *f)
{
if (f == NULL)
return -1;
if (f == NULL)
return -1;
return fuse_session_loop_mt(fuse_get_session(f));
return fuse_session_loop_mt(fuse_get_session(f));
}
FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@");

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_opt.h"
@ -15,71 +15,71 @@
#include <assert.h>
struct fuse_opt_context {
void *data;
const struct fuse_opt *opt;
fuse_opt_proc_t proc;
int argctr;
int argc;
char **argv;
struct fuse_args outargs;
char *opts;
int nonopt;
void *data;
const struct fuse_opt *opt;
fuse_opt_proc_t proc;
int argctr;
int argc;
char **argv;
struct fuse_args outargs;
char *opts;
int nonopt;
};
void fuse_opt_free_args(struct fuse_args *args)
{
if (args) {
if (args->argv && args->allocated) {
int i;
for (i = 0; i < args->argc; i++)
free(args->argv[i]);
free(args->argv);
}
args->argc = 0;
args->argv = NULL;
args->allocated = 0;
}
if (args) {
if (args->argv && args->allocated) {
int i;
for (i = 0; i < args->argc; i++)
free(args->argv[i]);
free(args->argv);
}
args->argc = 0;
args->argv = NULL;
args->allocated = 0;
}
}
static int alloc_failed(void)
{
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
{
char **newargv;
char *newarg;
char **newargv;
char *newarg;
assert(!args->argv || args->allocated);
assert(!args->argv || args->allocated);
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
newarg = newargv ? strdup(arg) : NULL;
if (!newargv || !newarg)
return alloc_failed();
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
newarg = newargv ? strdup(arg) : NULL;
if (!newargv || !newarg)
return alloc_failed();
args->argv = newargv;
args->allocated = 1;
args->argv[args->argc++] = newarg;
args->argv[args->argc] = NULL;
return 0;
args->argv = newargv;
args->allocated = 1;
args->argv[args->argc++] = newarg;
args->argv[args->argc] = NULL;
return 0;
}
static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
const char *arg)
{
assert(pos <= args->argc);
if (fuse_opt_add_arg(args, arg) == -1)
return -1;
assert(pos <= args->argc);
if (fuse_opt_add_arg(args, arg) == -1)
return -1;
if (pos != args->argc - 1) {
char *newarg = args->argv[args->argc - 1];
memmove(&args->argv[pos + 1], &args->argv[pos],
sizeof(char *) * (args->argc - pos - 1));
args->argv[pos] = newarg;
}
return 0;
if (pos != args->argc - 1) {
char *newarg = args->argv[args->argc - 1];
memmove(&args->argv[pos + 1], &args->argv[pos],
sizeof(char *) * (args->argc - pos - 1));
args->argv[pos] = newarg;
}
return 0;
}
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
@ -96,288 +96,290 @@ int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg)
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
{
if (ctx->argctr + 1 >= ctx->argc) {
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
return -1;
}
ctx->argctr++;
return 0;
if (ctx->argctr + 1 >= ctx->argc) {
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
return -1;
}
ctx->argctr++;
return 0;
}
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
{
return fuse_opt_add_arg(&ctx->outargs, arg);
return fuse_opt_add_arg(&ctx->outargs, arg);
}
int fuse_opt_add_opt(char **opts, const char *opt)
{
char *newopts;
if (!*opts)
newopts = strdup(opt);
else {
unsigned oldlen = strlen(*opts);
newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1);
if (newopts) {
newopts[oldlen] = ',';
strcpy(newopts + oldlen + 1, opt);
}
}
if (!newopts)
return alloc_failed();
char *newopts;
if (!*opts)
newopts = strdup(opt);
else {
unsigned oldlen = strlen(*opts);
newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1);
if (newopts) {
newopts[oldlen] = ',';
strcpy(newopts + oldlen + 1, opt);
}
}
if (!newopts)
return alloc_failed();
*opts = newopts;
return 0;
*opts = newopts;
return 0;
}
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
{
return fuse_opt_add_opt(&ctx->opts, opt);
return fuse_opt_add_opt(&ctx->opts, opt);
}
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
int iso)
int iso)
{
if (key == FUSE_OPT_KEY_DISCARD)
return 0;
if (key == FUSE_OPT_KEY_DISCARD)
return 0;
if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
if (res == -1 || !res)
return res;
}
if (iso)
return add_opt(ctx, arg);
else
return add_arg(ctx, arg);
if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
if (res == -1 || !res)
return res;
}
if (iso)
return add_opt(ctx, arg);
else
return add_arg(ctx, arg);
}
static int match_template(const char *t, const char *arg, unsigned *sepp)
{
int arglen = strlen(arg);
const char *sep = strchr(t, '=');
sep = sep ? sep : strchr(t, ' ');
if (sep && (!sep[1] || sep[1] == '%')) {
int tlen = sep - t;
if (sep[0] == '=')
tlen ++;
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
*sepp = sep - t;
return 1;
}
}
if (strcmp(t, arg) == 0) {
*sepp = 0;
return 1;
}
return 0;
int arglen = strlen(arg);
const char *sep = strchr(t, '=');
sep = sep ? sep : strchr(t, ' ');
if (sep && (!sep[1] || sep[1] == '%')) {
int tlen = sep - t;
if (sep[0] == '=')
tlen ++;
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
*sepp = sep - t;
return 1;
}
}
if (strcmp(t, arg) == 0) {
*sepp = 0;
return 1;
}
return 0;
}
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
const char *arg, unsigned *sepp)
const char *arg, unsigned *sepp)
{
for (; opt && opt->templ; opt++)
if (match_template(opt->templ, arg, sepp))
return opt;
return NULL;
for (; opt && opt->templ; opt++)
if (match_template(opt->templ, arg, sepp))
return opt;
return NULL;
}
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
{
unsigned dummy;
return find_opt(opts, opt, &dummy) ? 1 : 0;
unsigned dummy;
return find_opt(opts, opt, &dummy) ? 1 : 0;
}
static int process_opt_param(void *var, const char *format, const char *param,
const char *arg)
const char *arg)
{
assert(format[0] == '%');
if (format[1] == 's') {
char *copy = strdup(param);
if (!copy)
return alloc_failed();
assert(format[0] == '%');
if (format[1] == 's') {
char *copy = strdup(param);
if (!copy)
return alloc_failed();
*(char **) var = copy;
} else {
if (sscanf(param, format, var) != 1) {
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
return -1;
}
}
return 0;
*(char **) var = copy;
} else {
if (sscanf(param, format, var) != 1) {
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
return -1;
}
}
return 0;
}
static int process_opt(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
if (opt->offset == -1U) {
if (call_proc(ctx, arg, opt->value, iso) == -1)
return -1;
} else {
void *var = ctx->data + opt->offset;
if (sep && opt->templ[sep + 1]) {
const char *param = arg + sep;
if (opt->templ[sep] == '=')
param ++;
if (process_opt_param(var, opt->templ + sep + 1,
param, arg) == -1)
return -1;
} else
*(int *)var = opt->value;
}
return 0;
if (opt->offset == -1U) {
if (call_proc(ctx, arg, opt->value, iso) == -1)
return -1;
} else {
void *var = ctx->data + opt->offset;
if (sep && opt->templ[sep + 1]) {
const char *param = arg + sep;
if (opt->templ[sep] == '=')
param ++;
if (process_opt_param(var, opt->templ + sep + 1,
param, arg) == -1)
return -1;
} else
*(int *)var = opt->value;
}
return 0;
}
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
int res;
char *newarg;
char *param;
int res;
char *newarg;
char *param;
if (next_arg(ctx, arg) == -1)
return -1;
if (next_arg(ctx, arg) == -1)
return -1;
param = ctx->argv[ctx->argctr];
newarg = malloc(sep + strlen(param) + 1);
if (!newarg)
return alloc_failed();
param = ctx->argv[ctx->argctr];
newarg = malloc(sep + strlen(param) + 1);
if (!newarg)
return alloc_failed();
memcpy(newarg, arg, sep);
strcpy(newarg + sep, param);
res = process_opt(ctx, opt, sep, newarg, iso);
free(newarg);
memcpy(newarg, arg, sep);
strcpy(newarg + sep, param);
res = process_opt(ctx, opt, sep, newarg, iso);
free(newarg);
return res;
return res;
}
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
{
unsigned sep;
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
if (opt) {
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
int res;
if (sep && opt->templ[sep] == ' ' && !arg[sep])
res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
else
res = process_opt(ctx, opt, sep, arg, iso);
if (res == -1)
return -1;
}
return 0;
} else
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
unsigned sep;
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
if (opt) {
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
int res;
if (sep && opt->templ[sep] == ' ' && !arg[sep])
res = process_opt_sep_arg(ctx, opt, sep, arg,
iso);
else
res = process_opt(ctx, opt, sep, arg, iso);
if (res == -1)
return -1;
}
return 0;
} else
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
}
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
{
char *sep;
char *sep;
do {
int res;
sep = strchr(opts, ',');
if (sep)
*sep = '\0';
res = process_gopt(ctx, opts, 1);
if (res == -1)
return -1;
opts = sep + 1;
} while (sep);
do {
int res;
sep = strchr(opts, ',');
if (sep)
*sep = '\0';
res = process_gopt(ctx, opts, 1);
if (res == -1)
return -1;
opts = sep + 1;
} while (sep);
return 0;
return 0;
}
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
{
int res;
char *copy;
const char *sep = strchr(opts, ',');
if (!sep)
return process_gopt(ctx, opts, 1);
int res;
char *copy;
const char *sep = strchr(opts, ',');
if (!sep)
return process_gopt(ctx, opts, 1);
copy = strdup(opts);
if (!copy) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
res = process_real_option_group(ctx, copy);
free(copy);
return res;
copy = strdup(opts);
if (!copy) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
res = process_real_option_group(ctx, copy);
free(copy);
return res;
}
static int process_one(struct fuse_opt_context *ctx, const char *arg)
{
if (ctx->nonopt || arg[0] != '-')
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
else if (arg[1] == 'o') {
if (arg[2])
return process_option_group(ctx, arg + 2);
else {
if (next_arg(ctx, arg) == -1)
return -1;
if (ctx->nonopt || arg[0] != '-')
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
else if (arg[1] == 'o') {
if (arg[2])
return process_option_group(ctx, arg + 2);
else {
if (next_arg(ctx, arg) == -1)
return -1;
return process_option_group(ctx, ctx->argv[ctx->argctr]);
}
} else if (arg[1] == '-' && !arg[2]) {
if (add_arg(ctx, arg) == -1)
return -1;
ctx->nonopt = ctx->outargs.argc;
return 0;
} else
return process_gopt(ctx, arg, 0);
return process_option_group(ctx,
ctx->argv[ctx->argctr]);
}
} else if (arg[1] == '-' && !arg[2]) {
if (add_arg(ctx, arg) == -1)
return -1;
ctx->nonopt = ctx->outargs.argc;
return 0;
} else
return process_gopt(ctx, arg, 0);
}
static int opt_parse(struct fuse_opt_context *ctx)
{
if (ctx->argc) {
if (add_arg(ctx, ctx->argv[0]) == -1)
return -1;
}
if (ctx->argc) {
if (add_arg(ctx, ctx->argv[0]) == -1)
return -1;
}
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
return -1;
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
return -1;
if (ctx->opts) {
if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
return -1;
}
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) {
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
}
if (ctx->opts) {
if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
return -1;
}
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) {
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
}
return 0;
return 0;
}
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc)
const struct fuse_opt opts[], fuse_opt_proc_t proc)
{
int res;
struct fuse_opt_context ctx = {
.data = data,
.opt = opts,
.proc = proc,
};
int res;
struct fuse_opt_context ctx = {
.data = data,
.opt = opts,
.proc = proc,
};
if (!args || !args->argv || !args->argc)
return 0;
if (!args || !args->argv || !args->argc)
return 0;
ctx.argc = args->argc;
ctx.argv = args->argv;
ctx.argc = args->argc;
ctx.argv = args->argv;
res = opt_parse(&ctx);
if (res != -1) {
struct fuse_args tmp = *args;
*args = ctx.outargs;
ctx.outargs = tmp;
}
free(ctx.opts);
fuse_opt_free_args(&ctx.outargs);
return res;
res = opt_parse(&ctx);
if (res != -1) {
struct fuse_args tmp = *args;
*args = ctx.outargs;
ctx.outargs = tmp;
}
free(ctx.opts);
fuse_opt_free_args(&ctx.outargs);
return res;
}
/* This symbol version was mistakenly added to the version script */

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
@ -18,190 +18,191 @@
#include <errno.h>
struct fuse_session {
struct fuse_session_ops op;
struct fuse_session_ops op;
void *data;
void *data;
volatile int exited;
volatile int exited;
struct fuse_chan *ch;
struct fuse_chan *ch;
};
struct fuse_chan {
struct fuse_chan_ops op;
struct fuse_chan_ops op;
struct fuse_session *se;
struct fuse_session *se;
int fd;
int fd;
size_t bufsize;
size_t bufsize;
void *data;
void *data;
int compat;
int compat;
};
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
{
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
if (se == NULL) {
fprintf(stderr, "fuse: failed to allocate session\n");
return NULL;
}
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
if (se == NULL) {
fprintf(stderr, "fuse: failed to allocate session\n");
return NULL;
}
memset(se, 0, sizeof(*se));
se->op = *op;
se->data = data;
memset(se, 0, sizeof(*se));
se->op = *op;
se->data = data;
return se;
return se;
}
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
{
assert(se->ch == NULL);
assert(ch->se == NULL);
se->ch = ch;
ch->se = se;
assert(se->ch == NULL);
assert(ch->se == NULL);
se->ch = ch;
ch->se = se;
}
void fuse_session_remove_chan(struct fuse_chan *ch)
{
struct fuse_session *se = ch->se;
if (se) {
assert(se->ch == ch);
se->ch = NULL;
ch->se = NULL;
}
struct fuse_session *se = ch->se;
if (se) {
assert(se->ch == ch);
se->ch = NULL;
ch->se = NULL;
}
}
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
struct fuse_chan *ch)
struct fuse_chan *ch)
{
assert(ch == NULL || ch == se->ch);
if (ch == NULL)
return se->ch;
else
return NULL;
assert(ch == NULL || ch == se->ch);
if (ch == NULL)
return se->ch;
else
return NULL;
}
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
struct fuse_chan *ch)
struct fuse_chan *ch)
{
se->op.process(se->data, buf, len, ch);
se->op.process(se->data, buf, len, ch);
}
void fuse_session_destroy(struct fuse_session *se)
{
if (se->op.destroy)
se->op.destroy(se->data);
if (se->ch != NULL)
fuse_chan_destroy(se->ch);
free(se);
if (se->op.destroy)
se->op.destroy(se->data);
if (se->ch != NULL)
fuse_chan_destroy(se->ch);
free(se);
}
void fuse_session_exit(struct fuse_session *se)
{
if (se->op.exit)
se->op.exit(se->data, 1);
se->exited = 1;
if (se->op.exit)
se->op.exit(se->data, 1);
se->exited = 1;
}
void fuse_session_reset(struct fuse_session *se)
{
if (se->op.exit)
se->op.exit(se->data, 0);
se->exited = 0;
if (se->op.exit)
se->op.exit(se->data, 0);
se->exited = 0;
}
int fuse_session_exited(struct fuse_session *se)
{
if (se->op.exited)
return se->op.exited(se->data);
else
return se->exited;
if (se->op.exited)
return se->op.exited(se->data);
else
return se->exited;
}
static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data, int compat)
size_t bufsize, void *data,
int compat)
{
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
if (ch == NULL) {
fprintf(stderr, "fuse: failed to allocate channel\n");
return NULL;
}
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
if (ch == NULL) {
fprintf(stderr, "fuse: failed to allocate channel\n");
return NULL;
}
memset(ch, 0, sizeof(*ch));
ch->op = *op;
ch->fd = fd;
ch->bufsize = bufsize;
ch->data = data;
ch->compat = compat;
memset(ch, 0, sizeof(*ch));
ch->op = *op;
ch->fd = fd;
ch->bufsize = bufsize;
ch->data = data;
ch->compat = compat;
return ch;
return ch;
}
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data)
size_t bufsize, void *data)
{
return fuse_chan_new_common(op, fd, bufsize, data, 0);
return fuse_chan_new_common(op, fd, bufsize, data, 0);
}
struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
int fd, size_t bufsize, void *data)
int fd, size_t bufsize, void *data)
{
return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize,
data, 24);
return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize,
data, 24);
}
int fuse_chan_fd(struct fuse_chan *ch)
{
return ch->fd;
return ch->fd;
}
size_t fuse_chan_bufsize(struct fuse_chan *ch)
{
return ch->bufsize;
return ch->bufsize;
}
void *fuse_chan_data(struct fuse_chan *ch)
{
return ch->data;
return ch->data;
}
struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
{
return ch->se;
return ch->se;
}
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_chan *ch = *chp;
if (ch->compat)
return ((struct fuse_chan_ops_compat24 *) &ch->op)
->receive(ch, buf, size);
else
return ch->op.receive(chp, buf, size);
struct fuse_chan *ch = *chp;
if (ch->compat)
return ((struct fuse_chan_ops_compat24 *) &ch->op)
->receive(ch, buf, size);
else
return ch->op.receive(chp, buf, size);
}
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
{
int res;
int res;
res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
}
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
{
return ch->op.send(ch, iov, count);
return ch->op.send(ch, iov, count);
}
void fuse_chan_destroy(struct fuse_chan *ch)
{
fuse_session_remove_chan(ch);
if (ch->op.destroy)
ch->op.destroy(ch);
free(ch);
fuse_session_remove_chan(ch);
if (ch->op.destroy)
ch->op.destroy(ch);
free(ch);
}
#ifndef __FreeBSD__

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
@ -16,57 +16,57 @@ static struct fuse_session *fuse_instance;
static void exit_handler(int sig)
{
(void) sig;
if (fuse_instance)
fuse_session_exit(fuse_instance);
(void) sig;
if (fuse_instance)
fuse_session_exit(fuse_instance);
}
static int set_one_signal_handler(int sig, void (*handler)(int))
{
struct sigaction sa;
struct sigaction old_sa;
struct sigaction sa;
struct sigaction old_sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handler;
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handler;
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
if (sigaction(sig, NULL, &old_sa) == -1) {
perror("fuse: cannot get old signal handler");
return -1;
}
if (sigaction(sig, NULL, &old_sa) == -1) {
perror("fuse: cannot get old signal handler");
return -1;
}
if (old_sa.sa_handler == SIG_DFL &&
sigaction(sig, &sa, NULL) == -1) {
perror("fuse: cannot set signal handler");
return -1;
}
return 0;
if (old_sa.sa_handler == SIG_DFL &&
sigaction(sig, &sa, NULL) == -1) {
perror("fuse: cannot set signal handler");
return -1;
}
return 0;
}
int fuse_set_signal_handlers(struct fuse_session *se)
{
if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
set_one_signal_handler(SIGINT, exit_handler) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
return -1;
if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
set_one_signal_handler(SIGINT, exit_handler) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
return -1;
fuse_instance = se;
return 0;
fuse_instance = se;
return 0;
}
void fuse_remove_signal_handlers(struct fuse_session *se)
{
if (fuse_instance != se)
fprintf(stderr,
"fuse: fuse_remove_signal_handlers: unknown session\n");
else
fuse_instance = NULL;
if (fuse_instance != se)
fprintf(stderr,
"fuse: fuse_remove_signal_handlers: unknown session\n");
else
fuse_instance = NULL;
set_one_signal_handler(SIGHUP, SIG_DFL);
set_one_signal_handler(SIGINT, SIG_DFL);
set_one_signal_handler(SIGTERM, SIG_DFL);
set_one_signal_handler(SIGPIPE, SIG_DFL);
set_one_signal_handler(SIGHUP, SIG_DFL);
set_one_signal_handler(SIGINT, SIG_DFL);
set_one_signal_handler(SIGTERM, SIG_DFL);
set_one_signal_handler(SIGPIPE, SIG_DFL);
}

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "config.h"
@ -22,333 +22,336 @@
#include <errno.h>
enum {
KEY_HELP,
KEY_HELP_NOHEADER,
KEY_VERSION,
KEY_HELP,
KEY_HELP_NOHEADER,
KEY_VERSION,
};
struct helper_opts {
int singlethread;
int foreground;
int nodefault_subtype;
char *mountpoint;
int singlethread;
int foreground;
int nodefault_subtype;
char *mountpoint;
};
#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
static const struct fuse_opt fuse_helper_opts[] = {
FUSE_HELPER_OPT("-d", foreground),
FUSE_HELPER_OPT("debug", foreground),
FUSE_HELPER_OPT("-f", foreground),
FUSE_HELPER_OPT("-s", singlethread),
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
FUSE_HELPER_OPT("-d", foreground),
FUSE_HELPER_OPT("debug", foreground),
FUSE_HELPER_OPT("-f", foreground),
FUSE_HELPER_OPT("-s", singlethread),
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_END
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_END
};
static void usage(const char *progname)
{
fprintf(stderr,
"usage: %s mountpoint [options]\n\n", progname);
fprintf(stderr,
"general options:\n"
" -o opt,[opt...] mount options\n"
" -h --help print help\n"
" -V --version print version\n"
"\n");
fprintf(stderr,
"usage: %s mountpoint [options]\n\n", progname);
fprintf(stderr,
"general options:\n"
" -o opt,[opt...] mount options\n"
" -h --help print help\n"
" -V --version print version\n"
"\n");
}
static void helper_help(void)
{
fprintf(stderr,
"FUSE options:\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n"
"\n"
);
fprintf(stderr,
"FUSE options:\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n"
"\n"
);
}
static void helper_version(void)
{
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
}
static int fuse_helper_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
struct fuse_args *outargs)
{
struct helper_opts *hopts = data;
struct helper_opts *hopts = data;
switch (key) {
case KEY_HELP:
usage(outargs->argv[0]);
/* fall through */
switch (key) {
case KEY_HELP:
usage(outargs->argv[0]);
/* fall through */
case KEY_HELP_NOHEADER:
helper_help();
return fuse_opt_add_arg(outargs, "-h");
case KEY_HELP_NOHEADER:
helper_help();
return fuse_opt_add_arg(outargs, "-h");
case KEY_VERSION:
helper_version();
return 1;
case KEY_VERSION:
helper_version();
return 1;
case FUSE_OPT_KEY_NONOPT:
if (!hopts->mountpoint) {
char mountpoint[PATH_MAX];
if (realpath(arg, mountpoint) == NULL) {
fprintf(stderr, "fuse: bad mount point `%s': %s\n", arg, strerror(errno));
return -1;
}
return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
} else {
fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
return -1;
}
case FUSE_OPT_KEY_NONOPT:
if (!hopts->mountpoint) {
char mountpoint[PATH_MAX];
if (realpath(arg, mountpoint) == NULL) {
fprintf(stderr,
"fuse: bad mount point `%s': %s\n",
arg, strerror(errno));
return -1;
}
return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
} else {
fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
return -1;
}
default:
return 1;
}
default:
return 1;
}
}
static int add_default_subtype(const char *progname, struct fuse_args *args)
{
int res;
char *subtype_opt;
const char *basename = strrchr(progname, '/');
if (basename == NULL)
basename = progname;
else if (basename[1] != '\0')
basename++;
int res;
char *subtype_opt;
const char *basename = strrchr(progname, '/');
if (basename == NULL)
basename = progname;
else if (basename[1] != '\0')
basename++;
subtype_opt = (char *) malloc(strlen(basename) + 64);
if (subtype_opt == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
sprintf(subtype_opt, "-osubtype=%s", basename);
res = fuse_opt_add_arg(args, subtype_opt);
free(subtype_opt);
return res;
subtype_opt = (char *) malloc(strlen(basename) + 64);
if (subtype_opt == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
sprintf(subtype_opt, "-osubtype=%s", basename);
res = fuse_opt_add_arg(args, subtype_opt);
free(subtype_opt);
return res;
}
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
int *multithreaded, int *foreground)
int *multithreaded, int *foreground)
{
int res;
struct helper_opts hopts;
int res;
struct helper_opts hopts;
memset(&hopts, 0, sizeof(hopts));
res = fuse_opt_parse(args, &hopts, fuse_helper_opts, fuse_helper_opt_proc);
if (res == -1)
return -1;
memset(&hopts, 0, sizeof(hopts));
res = fuse_opt_parse(args, &hopts, fuse_helper_opts,
fuse_helper_opt_proc);
if (res == -1)
return -1;
if (!hopts.nodefault_subtype) {
res = add_default_subtype(args->argv[0], args);
if (res == -1)
goto err;
}
if (mountpoint)
*mountpoint = hopts.mountpoint;
else
free(hopts.mountpoint);
if (!hopts.nodefault_subtype) {
res = add_default_subtype(args->argv[0], args);
if (res == -1)
goto err;
}
if (mountpoint)
*mountpoint = hopts.mountpoint;
else
free(hopts.mountpoint);
if (multithreaded)
*multithreaded = !hopts.singlethread;
if (foreground)
*foreground = hopts.foreground;
return 0;
if (multithreaded)
*multithreaded = !hopts.singlethread;
if (foreground)
*foreground = hopts.foreground;
return 0;
err:
free(hopts.mountpoint);
return -1;
err:
free(hopts.mountpoint);
return -1;
}
int fuse_daemonize(int foreground)
{
int res;
int res;
if (!foreground) {
res = daemon(0, 0);
if (res == -1) {
perror("fuse: failed to daemonize program\n");
return -1;
}
}
return 0;
if (!foreground) {
res = daemon(0, 0);
if (res == -1) {
perror("fuse: failed to daemonize program\n");
return -1;
}
}
return 0;
}
static struct fuse_chan *fuse_mount_common(const char *mountpoint,
struct fuse_args *args)
struct fuse_args *args)
{
struct fuse_chan *ch;
int fd;
struct fuse_chan *ch;
int fd;
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
* would ensue.
*/
do {
fd = open("/dev/null", O_RDWR);
if (fd > 2)
close(fd);
} while (fd >= 0 && fd <= 2);
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
* would ensue.
*/
do {
fd = open("/dev/null", O_RDWR);
if (fd > 2)
close(fd);
} while (fd >= 0 && fd <= 2);
fd = fuse_mount_compat25(mountpoint, args);
if (fd == -1)
return NULL;
fd = fuse_mount_compat25(mountpoint, args);
if (fd == -1)
return NULL;
ch = fuse_kern_chan_new(fd);
if (!ch)
fuse_kern_unmount(mountpoint, fd);
ch = fuse_kern_chan_new(fd);
if (!ch)
fuse_kern_unmount(mountpoint, fd);
return ch;
return ch;
}
struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
{
return fuse_mount_common(mountpoint, args);
return fuse_mount_common(mountpoint, args);
}
static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
{
int fd = ch ? fuse_chan_fd(ch) : -1;
fuse_kern_unmount(mountpoint, fd);
fuse_chan_destroy(ch);
int fd = ch ? fuse_chan_fd(ch) : -1;
fuse_kern_unmount(mountpoint, fd);
fuse_chan_destroy(ch);
}
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
{
fuse_unmount_common(mountpoint, ch);
fuse_unmount_common(mountpoint, ch);
}
static struct fuse *fuse_setup_common(int argc, char *argv[],
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *multithreaded,
int *fd,
void *user_data,
int compat)
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *multithreaded,
int *fd,
void *user_data,
int compat)
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
struct fuse *fuse;
int foreground;
int res;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
struct fuse *fuse;
int foreground;
int res;
res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
if (res == -1)
return NULL;
res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
if (res == -1)
return NULL;
ch = fuse_mount_common(*mountpoint, &args);
if (!ch) {
fuse_opt_free_args(&args);
goto err_free;
}
ch = fuse_mount_common(*mountpoint, &args);
if (!ch) {
fuse_opt_free_args(&args);
goto err_free;
}
fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
fuse_opt_free_args(&args);
if (fuse == NULL)
goto err_unmount;
fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
fuse_opt_free_args(&args);
if (fuse == NULL)
goto err_unmount;
res = fuse_daemonize(foreground);
if (res == -1)
goto err_unmount;
res = fuse_daemonize(foreground);
if (res == -1)
goto err_unmount;
res = fuse_set_signal_handlers(fuse_get_session(fuse));
if (res == -1)
goto err_unmount;
res = fuse_set_signal_handlers(fuse_get_session(fuse));
if (res == -1)
goto err_unmount;
if (fd)
*fd = fuse_chan_fd(ch);
if (fd)
*fd = fuse_chan_fd(ch);
return fuse;
return fuse;
err_unmount:
fuse_unmount_common(*mountpoint, ch);
if (fuse)
fuse_destroy(fuse);
err_free:
free(*mountpoint);
return NULL;
err_unmount:
fuse_unmount_common(*mountpoint, ch);
if (fuse)
fuse_destroy(fuse);
err_free:
free(*mountpoint);
return NULL;
}
struct fuse *fuse_setup(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
char **mountpoint, int *multithreaded, void *user_data)
const struct fuse_operations *op, size_t op_size,
char **mountpoint, int *multithreaded, void *user_data)
{
return fuse_setup_common(argc, argv, op, op_size, mountpoint,
multithreaded, NULL, user_data, 0);
return fuse_setup_common(argc, argv, op, op_size, mountpoint,
multithreaded, NULL, user_data, 0);
}
static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
{
struct fuse_session *se = fuse_get_session(fuse);
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
fuse_remove_signal_handlers(se);
fuse_unmount_common(mountpoint, ch);
fuse_destroy(fuse);
free(mountpoint);
struct fuse_session *se = fuse_get_session(fuse);
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
fuse_remove_signal_handlers(se);
fuse_unmount_common(mountpoint, ch);
fuse_destroy(fuse);
free(mountpoint);
}
void fuse_teardown(struct fuse *fuse, char *mountpoint)
{
fuse_teardown_common(fuse, mountpoint);
fuse_teardown_common(fuse, mountpoint);
}
static int fuse_main_common(int argc, char *argv[],
const struct fuse_operations *op, size_t op_size,
void *user_data, int compat)
const struct fuse_operations *op, size_t op_size,
void *user_data, int compat)
{
struct fuse *fuse;
char *mountpoint;
int multithreaded;
int res;
struct fuse *fuse;
char *mountpoint;
int multithreaded;
int res;
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
&multithreaded, NULL, user_data, compat);
if (fuse == NULL)
return 1;
fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
&multithreaded, NULL, user_data, compat);
if (fuse == NULL)
return 1;
if (multithreaded)
res = fuse_loop_mt(fuse);
else
res = fuse_loop(fuse);
if (multithreaded)
res = fuse_loop_mt(fuse);
else
res = fuse_loop(fuse);
fuse_teardown_common(fuse, mountpoint);
if (res == -1)
return 1;
fuse_teardown_common(fuse, mountpoint);
if (res == -1)
return 1;
return 0;
return 0;
}
int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
size_t op_size, void *user_data)
size_t op_size, void *user_data)
{
return fuse_main_common(argc, argv, op, op_size, user_data, 0);
return fuse_main_common(argc, argv, op, op_size, user_data, 0);
}
#undef fuse_main
int fuse_main(void);
int fuse_main(void)
{
fprintf(stderr, "fuse_main(): This function does not exist\n");
return -1;
fprintf(stderr, "fuse_main(): This function does not exist\n");
return -1;
}
int fuse_version(void)
{
return FUSE_VERSION;
return FUSE_VERSION;
}
#include "fuse_compat.h"
@ -356,51 +359,53 @@ int fuse_version(void)
#ifndef __FreeBSD__
struct fuse *fuse_setup_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
const struct fuse_operations_compat22 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, NULL, 22);
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, NULL,
22);
}
struct fuse *fuse_setup_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op,
char **mountpoint, int *multithreaded,
int *fd)
const struct fuse_operations_compat2 *op,
char **mountpoint, int *multithreaded,
int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat2),
mountpoint, multithreaded, fd, NULL, 21);
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat2),
mountpoint, multithreaded, fd, NULL, 21);
}
int fuse_main_real_compat22(int argc, char *argv[],
const struct fuse_operations_compat22 *op,
size_t op_size)
const struct fuse_operations_compat22 *op,
size_t op_size)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size,
NULL, 22);
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
op_size, NULL, 22);
}
void fuse_main_compat1(int argc, char *argv[],
const struct fuse_operations_compat1 *op)
const struct fuse_operations_compat1 *op)
{
fuse_main_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat1), NULL, 11);
fuse_main_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat1), NULL, 11);
}
int fuse_main_compat2(int argc, char *argv[],
const struct fuse_operations_compat2 *op)
const struct fuse_operations_compat2 *op)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat2), NULL, 21);
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
sizeof(struct fuse_operations_compat2), NULL,
21);
}
int fuse_mount_compat1(const char *mountpoint, const char *args[])
{
/* just ignore mount args for now */
(void) args;
return fuse_mount_compat22(mountpoint, NULL);
/* just ignore mount args for now */
(void) args;
return fuse_mount_compat22(mountpoint, NULL);
}
FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@");
@ -413,31 +418,32 @@ FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
struct fuse *fuse_setup_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
const struct fuse_operations_compat25 *op,
size_t op_size, char **mountpoint,
int *multithreaded, int *fd)
{
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, NULL, 25);
return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
op_size, mountpoint, multithreaded, fd, NULL,
25);
}
int fuse_main_real_compat25(int argc, char *argv[],
const struct fuse_operations_compat25 *op,
size_t op_size)
const struct fuse_operations_compat25 *op,
size_t op_size)
{
return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size,
NULL, 25);
return fuse_main_common(argc, argv, (struct fuse_operations *) op,
op_size, NULL, 25);
}
void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint)
{
(void) fd;
fuse_teardown_common(fuse, mountpoint);
(void) fd;
fuse_teardown_common(fuse, mountpoint);
}
int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)
{
return fuse_kern_mount(mountpoint, args);
return fuse_kern_mount(mountpoint, args);
}
FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "config.h"
@ -25,8 +25,8 @@
#include <sys/wait.h>
#include <sys/mount.h>
#define FUSERMOUNT_PROG "fusermount"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
#define FUSERMOUNT_PROG "fusermount"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
#ifndef HAVE_FORK
#define fork() vfork()
@ -37,551 +37,555 @@
#endif
enum {
KEY_KERN_FLAG,
KEY_KERN_OPT,
KEY_FUSERMOUNT_OPT,
KEY_SUBTYPE_OPT,
KEY_MTAB_OPT,
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP,
KEY_VERSION,
KEY_KERN_FLAG,
KEY_KERN_OPT,
KEY_FUSERMOUNT_OPT,
KEY_SUBTYPE_OPT,
KEY_MTAB_OPT,
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP,
KEY_VERSION,
};
struct mount_opts {
int allow_other;
int allow_root;
int ishelp;
int flags;
int nonempty;
int blkdev;
char *fsname;
char *subtype;
char *subtype_opt;
char *mtab_opts;
char *fusermount_opts;
char *kernel_opts;
int allow_other;
int allow_root;
int ishelp;
int flags;
int nonempty;
int blkdev;
char *fsname;
char *subtype;
char *subtype_opt;
char *mtab_opts;
char *fusermount_opts;
char *kernel_opts;
};
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
static const struct fuse_opt fuse_mount_opts[] = {
FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("fsname=%s", fsname),
FUSE_MOUNT_OPT("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
FUSE_OPT_KEY("async", KEY_KERN_FLAG),
FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_END
FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("fsname=%s", fsname),
FUSE_MOUNT_OPT("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
FUSE_OPT_KEY("async", KEY_KERN_FLAG),
FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_END
};
static void mount_help(void)
{
fprintf(stderr,
" -o allow_other allow access to other users\n"
" -o allow_root allow access to root\n"
" -o nonempty allow mounts over non-empty file/dir\n"
" -o default_permissions enable permission checking by kernel\n"
" -o fsname=NAME set filesystem name\n"
" -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
" -o max_read=N set maximum size of read requests\n"
"\n"
);
fprintf(stderr,
" -o allow_other allow access to other users\n"
" -o allow_root allow access to root\n"
" -o nonempty allow mounts over non-empty file/dir\n"
" -o default_permissions enable permission checking by kernel\n"
" -o fsname=NAME set filesystem name\n"
" -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
" -o max_read=N set maximum size of read requests\n"
"\n");
}
static void exec_fusermount(const char *argv[])
{
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
execvp(FUSERMOUNT_PROG, (char **) argv);
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
execvp(FUSERMOUNT_PROG, (char **) argv);
}
static void mount_version(void)
{
int pid = fork();
if (!pid) {
const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
exec_fusermount(argv);
_exit(1);
} else if (pid != -1)
waitpid(pid, NULL, 0);
int pid = fork();
if (!pid) {
const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
exec_fusermount(argv);
_exit(1);
} else if (pid != -1)
waitpid(pid, NULL, 0);
}
struct mount_flags {
const char *opt;
unsigned long flag;
int on;
const char *opt;
unsigned long flag;
int on;
};
static struct mount_flags mount_flags[] = {
{"rw", MS_RDONLY, 0},
{"ro", MS_RDONLY, 1},
{"suid", MS_NOSUID, 0},
{"nosuid", MS_NOSUID, 1},
{"dev", MS_NODEV, 0},
{"nodev", MS_NODEV, 1},
{"exec", MS_NOEXEC, 0},
{"noexec", MS_NOEXEC, 1},
{"async", MS_SYNCHRONOUS, 0},
{"sync", MS_SYNCHRONOUS, 1},
{"atime", MS_NOATIME, 0},
{"noatime", MS_NOATIME, 1},
{"dirsync", MS_DIRSYNC, 1},
{NULL, 0, 0}
{"rw", MS_RDONLY, 0},
{"ro", MS_RDONLY, 1},
{"suid", MS_NOSUID, 0},
{"nosuid", MS_NOSUID, 1},
{"dev", MS_NODEV, 0},
{"nodev", MS_NODEV, 1},
{"exec", MS_NOEXEC, 0},
{"noexec", MS_NOEXEC, 1},
{"async", MS_SYNCHRONOUS, 0},
{"sync", MS_SYNCHRONOUS, 1},
{"atime", MS_NOATIME, 0},
{"noatime", MS_NOATIME, 1},
{"dirsync", MS_DIRSYNC, 1},
{NULL, 0, 0}
};
static void set_mount_flag(const char *s, int *flags)
{
int i;
int i;
for (i = 0; mount_flags[i].opt != NULL; i++) {
const char *opt = mount_flags[i].opt;
if (strcmp(opt, s) == 0) {
if (mount_flags[i].on)
*flags |= mount_flags[i].flag;
else
*flags &= ~mount_flags[i].flag;
return;
}
}
fprintf(stderr, "fuse: internal error, can't find mount flag\n");
abort();
for (i = 0; mount_flags[i].opt != NULL; i++) {
const char *opt = mount_flags[i].opt;
if (strcmp(opt, s) == 0) {
if (mount_flags[i].on)
*flags |= mount_flags[i].flag;
else
*flags &= ~mount_flags[i].flag;
return;
}
}
fprintf(stderr, "fuse: internal error, can't find mount flag\n");
abort();
}
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
struct fuse_args *outargs)
{
struct mount_opts *mo = data;
struct mount_opts *mo = data;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_KERN_FLAG:
set_mount_flag(arg, &mo->flags);
return 0;
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_KERN_FLAG:
set_mount_flag(arg, &mo->flags);
return 0;
case KEY_KERN_OPT:
return fuse_opt_add_opt(&mo->kernel_opts, arg);
case KEY_KERN_OPT:
return fuse_opt_add_opt(&mo->kernel_opts, arg);
case KEY_FUSERMOUNT_OPT:
return fuse_opt_add_opt(&mo->fusermount_opts, arg);
case KEY_FUSERMOUNT_OPT:
return fuse_opt_add_opt(&mo->fusermount_opts, arg);
case KEY_SUBTYPE_OPT:
return fuse_opt_add_opt(&mo->subtype_opt, arg);
case KEY_SUBTYPE_OPT:
return fuse_opt_add_opt(&mo->subtype_opt, arg);
case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg);
case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg);
case KEY_HELP:
mount_help();
mo->ishelp = 1;
break;
case KEY_HELP:
mount_help();
mo->ishelp = 1;
break;
case KEY_VERSION:
mount_version();
mo->ishelp = 1;
break;
}
return 1;
case KEY_VERSION:
mount_version();
mo->ishelp = 1;
break;
}
return 1;
}
/* return value:
* >= 0 => fd
* -1 => error
* >= 0 => fd
* -1 => error
*/
static int receive_fd(int fd)
{
struct msghdr msg;
struct iovec iov;
char buf[1];
int rv;
size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
struct cmsghdr *cmsg;
struct msghdr msg;
struct iovec iov;
char buf[1];
int rv;
size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
struct cmsghdr *cmsg;
iov.iov_base = buf;
iov.iov_len = 1;
iov.iov_base = buf;
iov.iov_len = 1;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* old BSD implementations should use msg_accrights instead of
* msg_control; the interface is different. */
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* old BSD implementations should use msg_accrights instead of
* msg_control; the interface is different. */
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
if (rv == -1) {
perror("recvmsg");
return -1;
}
if(!rv) {
/* EOF */
return -1;
}
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
if (rv == -1) {
perror("recvmsg");
return -1;
}
if(!rv) {
/* EOF */
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg->cmsg_type == SCM_RIGHTS) {
fprintf(stderr, "got control message of unknown type %d\n",
cmsg->cmsg_type);
return -1;
}
return *(int*)CMSG_DATA(cmsg);
cmsg = CMSG_FIRSTHDR(&msg);
if (!cmsg->cmsg_type == SCM_RIGHTS) {
fprintf(stderr, "got control message of unknown type %d\n",
cmsg->cmsg_type);
return -1;
}
return *(int*)CMSG_DATA(cmsg);
}
void fuse_kern_unmount(const char *mountpoint, int fd)
{
int res;
int pid;
int res;
int pid;
if (!mountpoint)
return;
if (!mountpoint)
return;
if (fd != -1) {
struct pollfd pfd;
if (fd != -1) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events = 0;
res = poll(&pfd, 1, 0);
/* If file poll returns POLLERR on the device file descriptor,
then the filesystem is already unmounted */
if (res == 1 && (pfd.revents & POLLERR))
return;
pfd.fd = fd;
pfd.events = 0;
res = poll(&pfd, 1, 0);
/* If file poll returns POLLERR on the device file descriptor,
then the filesystem is already unmounted */
if (res == 1 && (pfd.revents & POLLERR))
return;
/* Need to close file descriptor, otherwise synchronous umount
would recurse into filesystem, and deadlock */
close(fd);
}
/* Need to close file descriptor, otherwise synchronous umount
would recurse into filesystem, and deadlock */
close(fd);
}
if (geteuid() == 0) {
fuse_mnt_umount("fuse", mountpoint, 1);
return;
}
if (geteuid() == 0) {
fuse_mnt_umount("fuse", mountpoint, 1);
return;
}
res = umount2(mountpoint, 2);
if (res == 0)
return;
res = umount2(mountpoint, 2);
if (res == 0)
return;
pid = fork();
if(pid == -1)
return;
pid = fork();
if(pid == -1)
return;
if(pid == 0) {
const char *argv[] =
{ FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL };
if(pid == 0) {
const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
"--", mountpoint, NULL };
exec_fusermount(argv);
_exit(1);
}
waitpid(pid, NULL, 0);
exec_fusermount(argv);
_exit(1);
}
waitpid(pid, NULL, 0);
}
void fuse_unmount_compat22(const char *mountpoint)
{
fuse_kern_unmount(mountpoint, -1);
fuse_kern_unmount(mountpoint, -1);
}
static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
int quiet)
int quiet)
{
int fds[2], pid;
int res;
int rv;
int fds[2], pid;
int res;
int rv;
if (!mountpoint) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
if (!mountpoint) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
perror("fuse: socketpair() failed");
return -1;
}
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
perror("fuse: socketpair() failed");
return -1;
}
pid = fork();
if(pid == -1) {
perror("fuse: fork() failed");
close(fds[0]);
close(fds[1]);
return -1;
}
pid = fork();
if(pid == -1) {
perror("fuse: fork() failed");
close(fds[0]);
close(fds[1]);
return -1;
}
if(pid == 0) {
char env[10];
const char *argv[32];
int a = 0;
if(pid == 0) {
char env[10];
const char *argv[32];
int a = 0;
if (quiet) {
int fd = open("/dev/null", O_RDONLY);
dup2(fd, 1);
dup2(fd, 2);
}
if (quiet) {
int fd = open("/dev/null", O_RDONLY);
dup2(fd, 1);
dup2(fd, 2);
}
argv[a++] = FUSERMOUNT_PROG;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = "--";
argv[a++] = mountpoint;
argv[a++] = NULL;
argv[a++] = FUSERMOUNT_PROG;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = "--";
argv[a++] = mountpoint;
argv[a++] = NULL;
close(fds[1]);
fcntl(fds[0], F_SETFD, 0);
snprintf(env, sizeof(env), "%i", fds[0]);
setenv(FUSE_COMMFD_ENV, env, 1);
exec_fusermount(argv);
perror("fuse: failed to exec fusermount");
_exit(1);
}
close(fds[1]);
fcntl(fds[0], F_SETFD, 0);
snprintf(env, sizeof(env), "%i", fds[0]);
setenv(FUSE_COMMFD_ENV, env, 1);
exec_fusermount(argv);
perror("fuse: failed to exec fusermount");
_exit(1);
}
close(fds[0]);
rv = receive_fd(fds[1]);
close(fds[1]);
waitpid(pid, NULL, 0); /* bury zombie */
close(fds[0]);
rv = receive_fd(fds[1]);
close(fds[1]);
waitpid(pid, NULL, 0); /* bury zombie */
return rv;
return rv;
}
int fuse_mount_compat22(const char *mountpoint, const char *opts)
{
return fuse_mount_fusermount(mountpoint, opts, 0);
return fuse_mount_fusermount(mountpoint, opts, 0);
}
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
const char *mnt_opts)
const char *mnt_opts)
{
char tmp[128];
const char *devname = "/dev/fuse";
char *source = NULL;
char *type = NULL;
struct stat stbuf;
int fd;
int res;
char tmp[128];
const char *devname = "/dev/fuse";
char *source = NULL;
char *type = NULL;
struct stat stbuf;
int fd;
int res;
if (!mnt) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
if (!mnt) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
res = lstat(mnt, &stbuf);
if (res == -1) {
fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
mnt, strerror(errno));
return -1;
}
res = lstat(mnt, &stbuf);
if (res == -1) {
fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
mnt, strerror(errno));
return -1;
}
if (!mo->nonempty) {
res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size);
if (res == -1)
return -1;
}
if (!mo->nonempty) {
res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode,
stbuf.st_size);
if (res == -1)
return -1;
}
fd = open(devname, O_RDWR);
if (fd == -1) {
if (errno == ENODEV || errno == ENOENT)
fprintf(stderr,
"fuse: device not found, try 'modprobe fuse' first\n");
else
fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
strerror(errno));
return -1;
}
fd = open(devname, O_RDWR);
if (fd == -1) {
if (errno == ENODEV || errno == ENOENT)
fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n");
else
fprintf(stderr, "fuse: failed to open %s: %s\n",
devname, strerror(errno));
return -1;
}
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
stbuf.st_mode & S_IFMT, getuid(), getgid());
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
if (res == -1)
goto out_close;
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
if (res == -1)
goto out_close;
source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
(mo->subtype ? strlen(mo->subtype) : 0) +
strlen(devname) + 32);
source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
(mo->subtype ? strlen(mo->subtype) : 0) +
strlen(devname) + 32);
type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
if (!type || !source) {
fprintf(stderr, "fuse: failed to allocate memory\n");
goto out_close;
}
type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
if (!type || !source) {
fprintf(stderr, "fuse: failed to allocate memory\n");
goto out_close;
}
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->subtype) {
strcat(type, ".");
strcat(type, mo->subtype);
}
strcpy(source,
mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->subtype) {
strcat(type, ".");
strcat(type, mo->subtype);
}
strcpy(source,
mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
if (res == -1 && errno == ENODEV && mo->subtype) {
/* Probably missing subtype support */
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->fsname) {
if (!mo->blkdev)
sprintf(source, "%s#%s", mo->subtype, mo->fsname);
} else {
strcpy(source, type);
}
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
}
if (res == -1) {
/*
* Maybe kernel doesn't support unprivileged mounts, in this
* case try falling back to fusermount
*/
if (errno == EPERM) {
res = -2;
} else {
int errno_save = errno;
if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
fprintf(stderr, "fuse: 'fuseblk' support missing\n");
else
fprintf(stderr, "fuse: mount failed: %s\n",
strerror(errno_save));
}
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
if (res == -1 && errno == ENODEV && mo->subtype) {
/* Probably missing subtype support */
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->fsname) {
if (!mo->blkdev)
sprintf(source, "%s#%s", mo->subtype,
mo->fsname);
} else {
strcpy(source, type);
}
res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
}
if (res == -1) {
/*
* Maybe kernel doesn't support unprivileged mounts, in this
* case try falling back to fusermount
*/
if (errno == EPERM) {
res = -2;
} else {
int errno_save = errno;
if (mo->blkdev && errno == ENODEV &&
!fuse_mnt_check_fuseblk())
fprintf(stderr,
"fuse: 'fuseblk' support missing\n");
else
fprintf(stderr, "fuse: mount failed: %s\n",
strerror(errno_save));
}
goto out_close;
}
goto out_close;
}
if (geteuid() == 0) {
char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
res = -1;
if (!newmnt)
goto out_umount;
if (geteuid() == 0) {
char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
res = -1;
if (!newmnt)
goto out_umount;
res = fuse_mnt_add_mount("fuse", source, newmnt, type, mnt_opts);
free(newmnt);
if (res == -1)
goto out_umount;
}
res = fuse_mnt_add_mount("fuse", source, newmnt, type,
mnt_opts);
free(newmnt);
if (res == -1)
goto out_umount;
}
return fd;
return fd;
out_umount:
umount2(mnt, 2); /* lazy umount */
out_close:
free(type);
free(source);
close(fd);
return res;
out_umount:
umount2(mnt, 2); /* lazy umount */
out_close:
free(type);
free(source);
close(fd);
return res;
}
static int get_mnt_flag_opts(char **mnt_optsp, int flags)
{
int i;
int i;
if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
return -1;
if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
return -1;
for (i = 0; mount_flags[i].opt != NULL; i++) {
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
return -1;
}
return 0;
for (i = 0; mount_flags[i].opt != NULL; i++) {
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
return -1;
}
return 0;
}
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
{
struct mount_opts mo;
int res = -1;
char *mnt_opts = NULL;
struct mount_opts mo;
int res = -1;
char *mnt_opts = NULL;
memset(&mo, 0, sizeof(mo));
mo.flags = MS_NOSUID | MS_NODEV;
memset(&mo, 0, sizeof(mo));
mo.flags = MS_NOSUID | MS_NODEV;
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
return -1;
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
return -1;
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
res = 0;
if (mo.ishelp)
goto out;
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
res = 0;
if (mo.ishelp)
goto out;
res = -1;
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
goto out;
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
goto out;
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
goto out;
res = -1;
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
goto out;
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
goto out;
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
goto out;
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
if (res == -2) {
if (mo.fusermount_opts &&
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
if (res == -2) {
if (mo.fusermount_opts &&
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
if (mo.subtype) {
char *tmp_opts = NULL;
if (mo.subtype) {
char *tmp_opts = NULL;
res = -1;
if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
free(tmp_opts);
goto out;
}
res = -1;
if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
free(tmp_opts);
goto out;
}
res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
free(tmp_opts);
if (res == -1)
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
} else {
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
}
}
out:
free(mnt_opts);
free(mo.fsname);
free(mo.subtype);
free(mo.fusermount_opts);
free(mo.subtype_opt);
free(mo.kernel_opts);
free(mo.mtab_opts);
return res;
res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
free(tmp_opts);
if (res == -1)
res = fuse_mount_fusermount(mountpoint,
mnt_opts, 0);
} else {
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
}
}
out:
free(mnt_opts);
free(mo.fsname);
free(mo.subtype);
free(mo.fusermount_opts);
free(mo.subtype_opt);
free(mo.kernel_opts);
free(mo.mtab_opts);
return res;
}
FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2");

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2005-2006 Csaba Henk <csaba.henk@creo.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2005-2006 Csaba Henk <csaba.henk@creo.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "fuse_i.h"
@ -22,343 +22,349 @@
#include <string.h>
#include <paths.h>
#define FUSERMOUNT_PROG "mount_fusefs"
#define FUSE_DEV_TRUNK "/dev/fuse"
#define FUSERMOUNT_PROG "mount_fusefs"
#define FUSE_DEV_TRUNK "/dev/fuse"
enum {
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP,
KEY_VERSION,
KEY_KERN
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP,
KEY_VERSION,
KEY_KERN
};
struct mount_opts {
int allow_other;
int allow_root;
int ishelp;
char *kernel_opts;
int allow_other;
int allow_root;
int ishelp;
char *kernel_opts;
};
static const struct fuse_opt fuse_mount_opts[] = {
{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
{ "allow_root", offsetof(struct mount_opts, allow_root), 1 },
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
/* standard FreeBSD mount options */
FUSE_OPT_KEY("dev", KEY_KERN),
FUSE_OPT_KEY("async", KEY_KERN),
FUSE_OPT_KEY("atime", KEY_KERN),
FUSE_OPT_KEY("dev", KEY_KERN),
FUSE_OPT_KEY("exec", KEY_KERN),
FUSE_OPT_KEY("suid", KEY_KERN),
FUSE_OPT_KEY("symfollow", KEY_KERN),
FUSE_OPT_KEY("rdonly", KEY_KERN),
FUSE_OPT_KEY("sync", KEY_KERN),
FUSE_OPT_KEY("union", KEY_KERN),
FUSE_OPT_KEY("userquota", KEY_KERN),
FUSE_OPT_KEY("groupquota", KEY_KERN),
FUSE_OPT_KEY("clusterr", KEY_KERN),
FUSE_OPT_KEY("clusterw", KEY_KERN),
FUSE_OPT_KEY("suiddir", KEY_KERN),
FUSE_OPT_KEY("snapshot", KEY_KERN),
FUSE_OPT_KEY("multilabel", KEY_KERN),
FUSE_OPT_KEY("acls", KEY_KERN),
FUSE_OPT_KEY("force", KEY_KERN),
FUSE_OPT_KEY("update", KEY_KERN),
FUSE_OPT_KEY("ro", KEY_KERN),
FUSE_OPT_KEY("rw", KEY_KERN),
FUSE_OPT_KEY("auto", KEY_KERN),
/* options supported under both Linux and FBSD */
FUSE_OPT_KEY("allow_other", KEY_KERN),
FUSE_OPT_KEY("default_permissions", KEY_KERN),
/* FBSD FUSE specific mount options */
FUSE_OPT_KEY("private", KEY_KERN),
FUSE_OPT_KEY("neglect_shares", KEY_KERN),
FUSE_OPT_KEY("push_symlinks_in", KEY_KERN),
/* stock FBSD mountopt parsing routine lets anything be negated... */
FUSE_OPT_KEY("nodev", KEY_KERN),
FUSE_OPT_KEY("noasync", KEY_KERN),
FUSE_OPT_KEY("noatime", KEY_KERN),
FUSE_OPT_KEY("nodev", KEY_KERN),
FUSE_OPT_KEY("noexec", KEY_KERN),
FUSE_OPT_KEY("nosuid", KEY_KERN),
FUSE_OPT_KEY("nosymfollow", KEY_KERN),
FUSE_OPT_KEY("nordonly", KEY_KERN),
FUSE_OPT_KEY("nosync", KEY_KERN),
FUSE_OPT_KEY("nounion", KEY_KERN),
FUSE_OPT_KEY("nouserquota", KEY_KERN),
FUSE_OPT_KEY("nogroupquota", KEY_KERN),
FUSE_OPT_KEY("noclusterr", KEY_KERN),
FUSE_OPT_KEY("noclusterw", KEY_KERN),
FUSE_OPT_KEY("nosuiddir", KEY_KERN),
FUSE_OPT_KEY("nosnapshot", KEY_KERN),
FUSE_OPT_KEY("nomultilabel", KEY_KERN),
FUSE_OPT_KEY("noacls", KEY_KERN),
FUSE_OPT_KEY("noforce", KEY_KERN),
FUSE_OPT_KEY("noupdate", KEY_KERN),
FUSE_OPT_KEY("noro", KEY_KERN),
FUSE_OPT_KEY("norw", KEY_KERN),
FUSE_OPT_KEY("noauto", KEY_KERN),
FUSE_OPT_KEY("noallow_other", KEY_KERN),
FUSE_OPT_KEY("nodefault_permissions", KEY_KERN),
FUSE_OPT_KEY("noprivate", KEY_KERN),
FUSE_OPT_KEY("noneglect_shares", KEY_KERN),
FUSE_OPT_KEY("nopush_symlinks_in", KEY_KERN),
/* Linux specific mount options, but let just the mount util handle them */
FUSE_OPT_KEY("fsname=", KEY_KERN),
FUSE_OPT_KEY("nonempty", KEY_KERN),
FUSE_OPT_KEY("large_read", KEY_KERN),
FUSE_OPT_KEY("max_read=", KEY_KERN),
FUSE_OPT_END
{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
{ "allow_root", offsetof(struct mount_opts, allow_root), 1 },
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
/* standard FreeBSD mount options */
FUSE_OPT_KEY("dev", KEY_KERN),
FUSE_OPT_KEY("async", KEY_KERN),
FUSE_OPT_KEY("atime", KEY_KERN),
FUSE_OPT_KEY("dev", KEY_KERN),
FUSE_OPT_KEY("exec", KEY_KERN),
FUSE_OPT_KEY("suid", KEY_KERN),
FUSE_OPT_KEY("symfollow", KEY_KERN),
FUSE_OPT_KEY("rdonly", KEY_KERN),
FUSE_OPT_KEY("sync", KEY_KERN),
FUSE_OPT_KEY("union", KEY_KERN),
FUSE_OPT_KEY("userquota", KEY_KERN),
FUSE_OPT_KEY("groupquota", KEY_KERN),
FUSE_OPT_KEY("clusterr", KEY_KERN),
FUSE_OPT_KEY("clusterw", KEY_KERN),
FUSE_OPT_KEY("suiddir", KEY_KERN),
FUSE_OPT_KEY("snapshot", KEY_KERN),
FUSE_OPT_KEY("multilabel", KEY_KERN),
FUSE_OPT_KEY("acls", KEY_KERN),
FUSE_OPT_KEY("force", KEY_KERN),
FUSE_OPT_KEY("update", KEY_KERN),
FUSE_OPT_KEY("ro", KEY_KERN),
FUSE_OPT_KEY("rw", KEY_KERN),
FUSE_OPT_KEY("auto", KEY_KERN),
/* options supported under both Linux and FBSD */
FUSE_OPT_KEY("allow_other", KEY_KERN),
FUSE_OPT_KEY("default_permissions", KEY_KERN),
/* FBSD FUSE specific mount options */
FUSE_OPT_KEY("private", KEY_KERN),
FUSE_OPT_KEY("neglect_shares", KEY_KERN),
FUSE_OPT_KEY("push_symlinks_in", KEY_KERN),
/* stock FBSD mountopt parsing routine lets anything be negated... */
FUSE_OPT_KEY("nodev", KEY_KERN),
FUSE_OPT_KEY("noasync", KEY_KERN),
FUSE_OPT_KEY("noatime", KEY_KERN),
FUSE_OPT_KEY("nodev", KEY_KERN),
FUSE_OPT_KEY("noexec", KEY_KERN),
FUSE_OPT_KEY("nosuid", KEY_KERN),
FUSE_OPT_KEY("nosymfollow", KEY_KERN),
FUSE_OPT_KEY("nordonly", KEY_KERN),
FUSE_OPT_KEY("nosync", KEY_KERN),
FUSE_OPT_KEY("nounion", KEY_KERN),
FUSE_OPT_KEY("nouserquota", KEY_KERN),
FUSE_OPT_KEY("nogroupquota", KEY_KERN),
FUSE_OPT_KEY("noclusterr", KEY_KERN),
FUSE_OPT_KEY("noclusterw", KEY_KERN),
FUSE_OPT_KEY("nosuiddir", KEY_KERN),
FUSE_OPT_KEY("nosnapshot", KEY_KERN),
FUSE_OPT_KEY("nomultilabel", KEY_KERN),
FUSE_OPT_KEY("noacls", KEY_KERN),
FUSE_OPT_KEY("noforce", KEY_KERN),
FUSE_OPT_KEY("noupdate", KEY_KERN),
FUSE_OPT_KEY("noro", KEY_KERN),
FUSE_OPT_KEY("norw", KEY_KERN),
FUSE_OPT_KEY("noauto", KEY_KERN),
FUSE_OPT_KEY("noallow_other", KEY_KERN),
FUSE_OPT_KEY("nodefault_permissions", KEY_KERN),
FUSE_OPT_KEY("noprivate", KEY_KERN),
FUSE_OPT_KEY("noneglect_shares", KEY_KERN),
FUSE_OPT_KEY("nopush_symlinks_in", KEY_KERN),
/*
* Linux specific mount options, but let just the mount util
* handle them
*/
FUSE_OPT_KEY("fsname=", KEY_KERN),
FUSE_OPT_KEY("nonempty", KEY_KERN),
FUSE_OPT_KEY("large_read", KEY_KERN),
FUSE_OPT_KEY("max_read=", KEY_KERN),
FUSE_OPT_END
};
static void mount_help(void)
{
fprintf(stderr,
" -o allow_root allow access to root\n"
);
system(FUSERMOUNT_PROG " --help");
fputc('\n', stderr);
fprintf(stderr,
" -o allow_root allow access to root\n"
);
system(FUSERMOUNT_PROG " --help");
fputc('\n', stderr);
}
static void mount_version(void)
{
system(FUSERMOUNT_PROG " --version");
system(FUSERMOUNT_PROG " --version");
}
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
struct fuse_args *outargs)
{
struct mount_opts *mo = data;
struct mount_opts *mo = data;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_KERN:
return fuse_opt_add_opt(&mo->kernel_opts, arg);
case KEY_KERN:
return fuse_opt_add_opt(&mo->kernel_opts, arg);
case KEY_HELP:
mount_help();
mo->ishelp = 1;
break;
case KEY_HELP:
mount_help();
mo->ishelp = 1;
break;
case KEY_VERSION:
mount_version();
mo->ishelp = 1;
break;
}
return 1;
case KEY_VERSION:
mount_version();
mo->ishelp = 1;
break;
}
return 1;
}
void fuse_unmount_compat22(const char *mountpoint)
{
char dev[128];
char *ssc, *umount_cmd;
FILE *sf;
int rv;
char *seekscript =
"exec 2>/dev/null; " /* error message is annoying in help output */
"/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
"/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
" { if ($3 == %d) print $10; }' | "
"/usr/bin/sort | "
"/usr/bin/uniq | "
"/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
char dev[128];
char *ssc, *umount_cmd;
FILE *sf;
int rv;
char *seekscript =
/* error message is annoying in help output */
"exec 2>/dev/null; "
"/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
"/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
" { if ($3 == %d) print $10; }' | "
"/usr/bin/sort | "
"/usr/bin/uniq | "
"/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
(void) mountpoint;
(void) mountpoint;
/*
* If we don't know the fd, we have to resort to the scripted solution --
* iterating over the fd-s is unpractical, as we don't know how many of
* open files we have. (This could be looked up in procfs -- however,
* that's optional on FBSD; or read out from the kmem -- however, that's
* bound to privileges (in fact, that's what happens when we call the
* setgid kmem fstat(1) utility).
*/
asprintf(&ssc, seekscript, getpid());
/*
* If we don't know the fd, we have to resort to the scripted
* solution -- iterating over the fd-s is unpractical, as we
* don't know how many of open files we have. (This could be
* looked up in procfs -- however, that's optional on FBSD; or
* read out from the kmem -- however, that's bound to
* privileges (in fact, that's what happens when we call the
* setgid kmem fstat(1) utility).
*/
asprintf(&ssc, seekscript, getpid());
errno = 0;
sf = popen(ssc, "r");
if (! sf)
return;
errno = 0;
sf = popen(ssc, "r");
if (! sf)
return;
fgets(dev, sizeof(dev), sf);
rv = pclose(sf);
if (rv)
return;
fgets(dev, sizeof(dev), sf);
rv = pclose(sf);
if (rv)
return;
asprintf(&umount_cmd, "/sbin/umount %s", dev);
system(umount_cmd);
asprintf(&umount_cmd, "/sbin/umount %s", dev);
system(umount_cmd);
}
void fuse_kern_unmount(const char *mountpoint, int fd)
{
char *ep, *umount_cmd, dev[128];
struct stat sbuf;
char *ep, *umount_cmd, dev[128];
struct stat sbuf;
(void)mountpoint;
(void)mountpoint;
if (fstat(fd, &sbuf) == -1)
return;
if (fstat(fd, &sbuf) == -1)
return;
devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
if (strncmp(dev, "fuse", 4))
return;
if (strncmp(dev, "fuse", 4))
return;
strtol(dev + 4, &ep, 10);
if (*ep != '\0')
return;
strtol(dev + 4, &ep, 10);
if (*ep != '\0')
return;
asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev);
system(umount_cmd);
asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev);
system(umount_cmd);
}
/* Check if kernel is doing init in background */
static int init_backgrounded(void)
{
int ibg, len;
int ibg, len;
len = sizeof(ibg);
len = sizeof(ibg);
if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
return 0;
if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
return 0;
return ibg;
return ibg;
}
static int fuse_mount_core(const char *mountpoint, const char *opts)
{
const char *mountprog = FUSERMOUNT_PROG;
int fd;
char *fdnam, *dev;
int pid;
const char *mountprog = FUSERMOUNT_PROG;
int fd;
char *fdnam, *dev;
int pid;
fdnam = getenv("FUSE_DEV_FD");
fdnam = getenv("FUSE_DEV_FD");
if (fdnam) {
char *ep;
if (fdnam) {
char *ep;
fd = strtol(fdnam, &ep, 10);
fd = strtol(fdnam, &ep, 10);
if (*ep != '\0') {
fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
return -1;
}
if (*ep != '\0') {
fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
return -1;
}
if (fd < 0)
return -1;
if (fd < 0)
return -1;
goto mount;
}
goto mount;
}
dev = getenv("FUSE_DEV_NAME");
dev = getenv("FUSE_DEV_NAME");
if (! dev)
dev = FUSE_DEV_TRUNK;
if (! dev)
dev = FUSE_DEV_TRUNK;
if ((fd = open(dev, O_RDWR)) < 0) {
perror("fuse: failed to open fuse device");
return -1;
}
if ((fd = open(dev, O_RDWR)) < 0) {
perror("fuse: failed to open fuse device");
return -1;
}
mount:
if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
goto out;
if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
goto out;
pid = fork();
pid = fork();
if (pid == -1) {
perror("fuse: fork() failed");
close(fd);
return -1;
}
if (pid == -1) {
perror("fuse: fork() failed");
close(fd);
return -1;
}
if (pid == 0) {
if (! init_backgrounded()) {
/*
* If init is not backgrounded, we have to call the mount util
* backgrounded, to avoid deadlock.
*/
if (pid == 0) {
if (! init_backgrounded()) {
/*
* If init is not backgrounded, we have to
* call the mount util backgrounded, to avoid
* deadlock.
*/
pid = fork();
if (pid == -1) {
perror("fuse: fork() failed");
close(fd);
exit(1);
}
}
pid = fork();
if (pid == 0) {
const char *argv[32];
int a = 0;
if (pid == -1) {
perror("fuse: fork() failed");
close(fd);
exit(1);
}
}
if (! fdnam)
asprintf(&fdnam, "%d", fd);
if (pid == 0) {
const char *argv[32];
int a = 0;
argv[a++] = mountprog;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = fdnam;
argv[a++] = mountpoint;
argv[a++] = NULL;
execvp(mountprog, (char **) argv);
perror("fuse: failed to exec mount program");
exit(1);
}
if (! fdnam)
asprintf(&fdnam, "%d", fd);
exit(0);
}
argv[a++] = mountprog;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = fdnam;
argv[a++] = mountpoint;
argv[a++] = NULL;
execvp(mountprog, (char **) argv);
perror("fuse: failed to exec mount program");
exit(1);
}
waitpid(pid, NULL, 0);
exit(0);
}
waitpid(pid, NULL, 0);
out:
return fd;
return fd;
}
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
{
struct mount_opts mo;
int res = -1;
struct mount_opts mo;
int res = -1;
memset(&mo, 0, sizeof(mo));
/* mount util should not try to spawn the daemon */
setenv("MOUNT_FUSEFS_SAFE", "1", 1);
/* to notify the mount util it's called from lib */
setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
memset(&mo, 0, sizeof(mo));
/* mount util should not try to spawn the daemon */
setenv("MOUNT_FUSEFS_SAFE", "1", 1);
/* to notify the mount util it's called from lib */
setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
return -1;
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
return -1;
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
if (mo.ishelp)
return 0;
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
if (mo.ishelp)
return 0;
res = fuse_mount_core(mountpoint, mo.kernel_opts);
out:
free(mo.kernel_opts);
return res;
res = fuse_mount_core(mountpoint, mo.kernel_opts);
out:
free(mo.kernel_opts);
return res;
}
FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");

View File

@ -1,9 +1,9 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include "mount_util.h"
@ -21,220 +21,223 @@
static int mtab_needs_update(const char *mnt)
{
struct stat stbuf;
struct stat stbuf;
/* If mtab is within new mount, don't touch it */
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
_PATH_MOUNTED[strlen(mnt)] == '/')
return 0;
/* If mtab is within new mount, don't touch it */
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
_PATH_MOUNTED[strlen(mnt)] == '/')
return 0;
if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))
return 0;
if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))
return 0;
return 1;
return 1;
}
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
const char *mnt, const char *type, const char *opts)
{
int res;
int status;
int res;
int status;
if (!mtab_needs_update(mnt))
return 0;
if (!mtab_needs_update(mnt))
return 0;
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
setuid(geteuid());
setuid(geteuid());
/*
* hide in a directory, where mount isn't able to resolve
* fsname as a valid path
*/
tmp = mkdtemp(templ);
if (!tmp) {
fprintf(stderr, "%s: failed to create temporary directory\n",
progname);
exit(1);
}
if (chdir(tmp)) {
fprintf(stderr, "%s: failed to chdir to %s: %s\n",
progname, tmp, strerror(errno));
exit(1);
}
rmdir(tmp);
execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
fsname, mnt, NULL);
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname,
strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
/*
* hide in a directory, where mount isn't able to resolve
* fsname as a valid path
*/
tmp = mkdtemp(templ);
if (!tmp) {
fprintf(stderr,
"%s: failed to create temporary directory\n",
progname);
exit(1);
}
if (chdir(tmp)) {
fprintf(stderr, "%s: failed to chdir to %s: %s\n",
progname, tmp, strerror(errno));
exit(1);
}
rmdir(tmp);
execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type,
"-o", opts, fsname, mnt, NULL);
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
return 0;
return 0;
}
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
{
int res;
int status;
int res;
int status;
if (!mtab_needs_update(mnt)) {
res = umount2(mnt, lazy ? 2 : 0);
if (res == -1)
fprintf(stderr, "%s: failed to unmount %s: %s\n", progname,
mnt, strerror(errno));
return res;
}
if (!mtab_needs_update(mnt)) {
res = umount2(mnt, lazy ? 2 : 0);
if (res == -1)
fprintf(stderr, "%s: failed to unmount %s: %s\n",
progname, mnt, strerror(errno));
return res;
}
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
setuid(geteuid());
execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL,
NULL);
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname,
strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
setuid(geteuid());
execl("/bin/umount", "/bin/umount", "-i", mnt,
lazy ? "-l" : NULL, NULL);
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
progname, strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
return 0;
return 0;
}
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
{
char buf[PATH_MAX];
char *copy;
char *dst;
char *end;
char *lastcomp;
const char *toresolv;
char buf[PATH_MAX];
char *copy;
char *dst;
char *end;
char *lastcomp;
const char *toresolv;
if (!orig[0]) {
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
return NULL;
}
if (!orig[0]) {
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
orig);
return NULL;
}
copy = strdup(orig);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return NULL;
}
copy = strdup(orig);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return NULL;
}
toresolv = copy;
lastcomp = NULL;
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
if (end[0] != '/') {
char *tmp;
end[1] = '\0';
tmp = strrchr(copy, '/');
if (tmp == NULL) {
lastcomp = copy;
toresolv = ".";
} else {
lastcomp = tmp + 1;
if (tmp == copy)
toresolv = "/";
}
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
lastcomp = NULL;
toresolv = copy;
}
else if (tmp)
tmp[0] = '\0';
}
if (realpath(toresolv, buf) == NULL) {
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
strerror(errno));
free(copy);
return NULL;
}
if (lastcomp == NULL)
dst = strdup(buf);
else {
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
if (dst) {
unsigned buflen = strlen(buf);
if (buflen && buf[buflen-1] == '/')
sprintf(dst, "%s%s", buf, lastcomp);
else
sprintf(dst, "%s/%s", buf, lastcomp);
}
}
free(copy);
if (dst == NULL)
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return dst;
toresolv = copy;
lastcomp = NULL;
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
if (end[0] != '/') {
char *tmp;
end[1] = '\0';
tmp = strrchr(copy, '/');
if (tmp == NULL) {
lastcomp = copy;
toresolv = ".";
} else {
lastcomp = tmp + 1;
if (tmp == copy)
toresolv = "/";
}
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
lastcomp = NULL;
toresolv = copy;
}
else if (tmp)
tmp[0] = '\0';
}
if (realpath(toresolv, buf) == NULL) {
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
strerror(errno));
free(copy);
return NULL;
}
if (lastcomp == NULL)
dst = strdup(buf);
else {
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
if (dst) {
unsigned buflen = strlen(buf);
if (buflen && buf[buflen-1] == '/')
sprintf(dst, "%s%s", buf, lastcomp);
else
sprintf(dst, "%s/%s", buf, lastcomp);
}
}
free(copy);
if (dst == NULL)
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return dst;
}
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize)
mode_t rootmode, off_t rootsize)
{
int isempty = 1;
int isempty = 1;
if (S_ISDIR(rootmode)) {
struct dirent *ent;
DIR *dp = opendir(mnt);
if (dp == NULL) {
fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n",
progname, strerror(errno));
return -1;
}
while ((ent = readdir(dp)) != NULL) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0) {
isempty = 0;
break;
}
}
closedir(dp);
} else if (rootsize)
isempty = 0;
if (S_ISDIR(rootmode)) {
struct dirent *ent;
DIR *dp = opendir(mnt);
if (dp == NULL) {
fprintf(stderr,
"%s: failed to open mountpoint for reading: %s\n",
progname, strerror(errno));
return -1;
}
while ((ent = readdir(dp)) != NULL) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0) {
isempty = 0;
break;
}
}
closedir(dp);
} else if (rootsize)
isempty = 0;
if (!isempty) {
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
return -1;
}
return 0;
if (!isempty) {
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
return -1;
}
return 0;
}
int fuse_mnt_check_fuseblk(void)
{
char buf[256];
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return 1;
char buf[256];
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return 1;
while (fgets(buf, sizeof(buf), f))
if (strstr(buf, "fuseblk\n")) {
fclose(f);
return 1;
}
while (fgets(buf, sizeof(buf), f))
if (strstr(buf, "fuseblk\n")) {
fclose(f);
return 1;
}
fclose(f);
return 0;
fclose(f);
return 0;
}

View File

@ -1,17 +1,17 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB.
*/
#include <sys/types.h>
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts);
const char *mnt, const char *type, const char *opts);
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize);
mode_t rootmode, off_t rootsize);
int fuse_mnt_check_fuseblk(void);

View File

@ -1,9 +1,9 @@
/*
libulockmgr: Userspace Lock Manager Library
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
libulockmgr: Userspace Lock Manager Library
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
/* #define DEBUG 1 */
@ -22,28 +22,28 @@
#include <sys/wait.h>
struct message {
unsigned intr : 1;
unsigned nofd : 1;
pthread_t thr;
int cmd;
int fd;
struct flock lock;
int error;
unsigned intr : 1;
unsigned nofd : 1;
pthread_t thr;
int cmd;
int fd;
struct flock lock;
int error;
};
struct fd_store {
struct fd_store *next;
int fd;
int inuse;
struct fd_store *next;
int fd;
int inuse;
};
struct owner {
struct owner *next;
struct owner *prev;
struct fd_store *fds;
void *id;
size_t id_len;
int cfd;
struct owner *next;
struct owner *prev;
struct fd_store *fds;
void *id;
size_t id_len;
int cfd;
};
static pthread_mutex_t ulockmgr_lock;
@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
static void list_del_owner(struct owner *owner)
{
struct owner *prev = owner->prev;
struct owner *next = owner->next;
prev->next = next;
next->prev = prev;
struct owner *prev = owner->prev;
struct owner *next = owner->next;
prev->next = next;
next->prev = prev;
}
static void list_add_owner(struct owner *owner, struct owner *next)
{
struct owner *prev = next->prev;
owner->next = next;
owner->prev = prev;
prev->next = owner;
next->prev = owner;
struct owner *prev = next->prev;
owner->next = next;
owner->prev = prev;
prev->next = owner;
next->prev = owner;
}
/*
@ -74,365 +74,367 @@ static void list_add_owner(struct owner *owner, struct owner *next)
* on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
* zero, even if data was available. Retrying the recv will return
* the data in this case.
*/
*/
static int do_recv(int sock, void *buf, size_t len, int flags)
{
int res = recv(sock, buf, len, flags);
if (res == 0)
res = recv(sock, buf, len, flags);
int res = recv(sock, buf, len, flags);
if (res == 0)
res = recv(sock, buf, len, flags);
return res;
return res;
}
static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
int *fdp, int numfds)
int *fdp, int numfds)
{
struct msghdr msg;
struct cmsghdr *p_cmsg;
struct iovec vec;
size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
int res;
struct msghdr msg;
struct cmsghdr *p_cmsg;
struct iovec vec;
size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
int res;
assert(numfds <= MAX_SEND_FDS);
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
p_cmsg = CMSG_FIRSTHDR(&msg);
p_cmsg->cmsg_level = SOL_SOCKET;
p_cmsg->cmsg_type = SCM_RIGHTS;
p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
msg.msg_controllen = p_cmsg->cmsg_len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
vec.iov_base = buf;
vec.iov_len = buflen;
res = sendmsg(sock, &msg, MSG_NOSIGNAL);
if (res == -1) {
perror("libulockmgr: sendmsg");
return -1;
}
if ((size_t) res != buflen) {
fprintf(stderr, "libulockmgr: sendmsg short\n");
return -1;
}
return 0;
assert(numfds <= MAX_SEND_FDS);
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
p_cmsg = CMSG_FIRSTHDR(&msg);
p_cmsg->cmsg_level = SOL_SOCKET;
p_cmsg->cmsg_type = SCM_RIGHTS;
p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
msg.msg_controllen = p_cmsg->cmsg_len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &vec;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
vec.iov_base = buf;
vec.iov_len = buflen;
res = sendmsg(sock, &msg, MSG_NOSIGNAL);
if (res == -1) {
perror("libulockmgr: sendmsg");
return -1;
}
if ((size_t) res != buflen) {
fprintf(stderr, "libulockmgr: sendmsg short\n");
return -1;
}
return 0;
}
static int ulockmgr_start_daemon(void)
{
int sv[2];
int res;
char tmp[64];
int sv[2];
int res;
char tmp[64];
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
return -1;
}
snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
res = system(tmp);
close(sv[0]);
if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
close(sv[1]);
return -1;
}
ulockmgr_cfd = sv[1];
return 0;
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
return -1;
}
snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
res = system(tmp);
close(sv[0]);
if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
close(sv[1]);
return -1;
}
ulockmgr_cfd = sv[1];
return 0;
}
static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
{
int sv[2];
int res;
char c = 'm';
struct owner *o;
int sv[2];
int res;
char c = 'm';
struct owner *o;
if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
return NULL;
if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
return NULL;
o = calloc(1, sizeof(struct owner) + id_len);
if (!o) {
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
return NULL;
}
o->id = o + 1;
o->id_len = id_len;
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
goto out_free;
}
res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
close(sv[0]);
if (res == -1) {
close(ulockmgr_cfd);
ulockmgr_cfd = -1;
goto out_close;
}
o = calloc(1, sizeof(struct owner) + id_len);
if (!o) {
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
return NULL;
}
o->id = o + 1;
o->id_len = id_len;
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
goto out_free;
}
res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
close(sv[0]);
if (res == -1) {
close(ulockmgr_cfd);
ulockmgr_cfd = -1;
goto out_close;
}
o->cfd = sv[1];
memcpy(o->id, id, id_len);
list_add_owner(o, &owner_list);
o->cfd = sv[1];
memcpy(o->id, id, id_len);
list_add_owner(o, &owner_list);
return o;
return o;
out_close:
close(sv[1]);
out_free:
free(o);
return NULL;
out_close:
close(sv[1]);
out_free:
free(o);
return NULL;
}
static int ulockmgr_send_request(struct message *msg, const void *id,
size_t id_len)
size_t id_len)
{
int sv[2];
int cfd;
struct owner *o;
struct fd_store *f = NULL;
struct fd_store *newf = NULL;
struct fd_store **fp;
int fd = msg->fd;
int cmd = msg->cmd;
int res;
int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
msg->lock.l_start == 0 && msg->lock.l_len == 0);
int sv[2];
int cfd;
struct owner *o;
struct fd_store *f = NULL;
struct fd_store *newf = NULL;
struct fd_store **fp;
int fd = msg->fd;
int cmd = msg->cmd;
int res;
int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
msg->lock.l_start == 0 && msg->lock.l_len == 0);
for (o = owner_list.next; o != &owner_list; o = o->next)
if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
break;
for (o = owner_list.next; o != &owner_list; o = o->next)
if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
break;
if (o == &owner_list)
o = NULL;
if (o == &owner_list)
o = NULL;
if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
o = ulockmgr_new_owner(id, id_len);
if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
o = ulockmgr_new_owner(id, id_len);
if (!o) {
if (cmd == F_GETLK) {
res = fcntl(msg->fd, F_GETLK, &msg->lock);
return (res == -1) ? -errno : 0;
} else if (msg->lock.l_type == F_UNLCK)
return 0;
else
return -ENOLCK;
}
if (!o) {
if (cmd == F_GETLK) {
res = fcntl(msg->fd, F_GETLK, &msg->lock);
return (res == -1) ? -errno : 0;
} else if (msg->lock.l_type == F_UNLCK)
return 0;
else
return -ENOLCK;
}
if (unlockall)
msg->nofd = 1;
else {
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
f = *fp;
if (f->fd == fd) {
msg->nofd = 1;
break;
}
}
}
if (unlockall)
msg->nofd = 1;
else {
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
f = *fp;
if (f->fd == fd) {
msg->nofd = 1;
break;
}
}
}
if (!msg->nofd) {
newf = f = calloc(1, sizeof(struct fd_store));
if (!f) {
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
return -ENOLCK;
}
}
if (!msg->nofd) {
newf = f = calloc(1, sizeof(struct fd_store));
if (!f) {
fprintf(stderr, "libulockmgr: failed to allocate memory\n");
return -ENOLCK;
}
}
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
free(newf);
return -ENOLCK;
}
res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
if (res == -1) {
perror("libulockmgr: socketpair");
free(newf);
return -ENOLCK;
}
cfd = sv[1];
sv[1] = msg->fd;
res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
msg->nofd ? 1 : 2);
close(sv[0]);
if (res == -1) {
free(newf);
close(cfd);
return -EIO;
}
cfd = sv[1];
sv[1] = msg->fd;
res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
msg->nofd ? 1 : 2);
close(sv[0]);
if (res == -1) {
free(newf);
close(cfd);
return -EIO;
}
if (newf) {
newf->fd = msg->fd;
newf->next = o->fds;
o->fds = newf;
}
if (f)
f->inuse++;
if (newf) {
newf->fd = msg->fd;
newf->next = o->fds;
o->fds = newf;
}
if (f)
f->inuse++;
res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
if (res == -1) {
perror("libulockmgr: recv");
msg->error = EIO;
} else if (res != sizeof(struct message)) {
fprintf(stderr, "libulockmgr: recv short\n");
msg->error = EIO;
} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
pthread_mutex_unlock(&ulockmgr_lock);
while (1) {
sigset_t old;
sigset_t unblock;
int errno_save;
res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
if (res == -1) {
perror("libulockmgr: recv");
msg->error = EIO;
} else if (res != sizeof(struct message)) {
fprintf(stderr, "libulockmgr: recv short\n");
msg->error = EIO;
} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
pthread_mutex_unlock(&ulockmgr_lock);
while (1) {
sigset_t old;
sigset_t unblock;
int errno_save;
sigemptyset(&unblock);
sigaddset(&unblock, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
errno_save = errno;
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (res == sizeof(struct message))
break;
else if (res >= 0) {
fprintf(stderr, "libulockmgr: recv short\n");
msg->error = EIO;
break;
} else if (errno_save != EINTR) {
errno = errno_save;
perror("libulockmgr: recv");
msg->error = EIO;
break;
}
msg->intr = 1;
res = send(o->cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
if (res == -1) {
perror("libulockmgr: send");
msg->error = EIO;
break;
}
if (res != sizeof(struct message)) {
fprintf(stderr, "libulockmgr: send short\n");
msg->error = EIO;
break;
}
}
pthread_mutex_lock(&ulockmgr_lock);
sigemptyset(&unblock);
sigaddset(&unblock, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
res = do_recv(cfd, msg, sizeof(struct message),
MSG_WAITALL);
errno_save = errno;
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (res == sizeof(struct message))
break;
else if (res >= 0) {
fprintf(stderr, "libulockmgr: recv short\n");
msg->error = EIO;
break;
} else if (errno_save != EINTR) {
errno = errno_save;
perror("libulockmgr: recv");
msg->error = EIO;
break;
}
msg->intr = 1;
res = send(o->cfd, msg, sizeof(struct message),
MSG_NOSIGNAL);
if (res == -1) {
perror("libulockmgr: send");
msg->error = EIO;
break;
}
if (res != sizeof(struct message)) {
fprintf(stderr, "libulockmgr: send short\n");
msg->error = EIO;
break;
}
}
pthread_mutex_lock(&ulockmgr_lock);
}
if (f)
f->inuse--;
close(cfd);
if (unlockall) {
for (fp = &o->fds; *fp;) {
f = *fp;
if (f->fd == fd && !f->inuse) {
*fp = f->next;
free(f);
} else
fp = &f->next;
}
if (!o->fds) {
list_del_owner(o);
close(o->cfd);
free(o);
}
/* Force OK on unlock-all, since it _will_ succeed once the
owner is deleted */
msg->error = 0;
}
}
if (f)
f->inuse--;
close(cfd);
if (unlockall) {
for (fp = &o->fds; *fp;) {
f = *fp;
if (f->fd == fd && !f->inuse) {
*fp = f->next;
free(f);
} else
fp = &f->next;
}
if (!o->fds) {
list_del_owner(o);
close(o->cfd);
free(o);
}
/* Force OK on unlock-all, since it _will_ succeed once the
owner is deleted */
msg->error = 0;
}
return -msg->error;
return -msg->error;
}
#ifdef DEBUG
static uint32_t owner_hash(const unsigned char *id, size_t id_len)
{
uint32_t h = 0;
size_t i;
for (i = 0; i < id_len; i++)
h = ((h << 8) | (h >> 24)) ^ id[i];
uint32_t h = 0;
size_t i;
for (i = 0; i < id_len; i++)
h = ((h << 8) | (h >> 24)) ^ id[i];
return h;
return h;
}
#endif
static int ulockmgr_canonicalize(int fd, struct flock *lock)
{
off_t offset;
if (lock->l_whence == SEEK_CUR) {
offset = lseek(fd, 0, SEEK_CUR);
if (offset == (off_t) -1)
return -errno;
} else if (lock->l_whence == SEEK_END) {
struct stat stbuf;
int res = fstat(fd, &stbuf);
if (res == -1)
return -errno;
off_t offset;
if (lock->l_whence == SEEK_CUR) {
offset = lseek(fd, 0, SEEK_CUR);
if (offset == (off_t) -1)
return -errno;
} else if (lock->l_whence == SEEK_END) {
struct stat stbuf;
int res = fstat(fd, &stbuf);
if (res == -1)
return -errno;
offset = stbuf.st_size;
} else
offset = 0;
offset = stbuf.st_size;
} else
offset = 0;
lock->l_whence = SEEK_SET;
lock->l_start += offset;
lock->l_whence = SEEK_SET;
lock->l_start += offset;
if (lock->l_start < 0)
return -EINVAL;
if (lock->l_start < 0)
return -EINVAL;
if (lock->l_len < 0) {
lock->l_start += lock->l_len;
if (lock->l_start < 0)
return -EINVAL;
lock->l_len = -lock->l_len;
}
if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
return -EINVAL;
if (lock->l_len < 0) {
lock->l_start += lock->l_len;
if (lock->l_start < 0)
return -EINVAL;
lock->l_len = -lock->l_len;
}
if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
return -EINVAL;
return 0;
return 0;
}
int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
size_t owner_len)
size_t owner_len)
{
int err;
struct message msg;
sigset_t old;
sigset_t block;
int err;
struct message msg;
sigset_t old;
sigset_t block;
if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
return -EINVAL;
if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
return -EINVAL;
if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
lock->l_whence != SEEK_END)
return -EINVAL;
if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
lock->l_whence != SEEK_END)
return -EINVAL;
#ifdef DEBUG
fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
owner_hash(owner, owner_len));
fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
owner_hash(owner, owner_len));
#endif
/* Unlock should never block anyway */
if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
cmd = F_SETLK;
/* Unlock should never block anyway */
if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
cmd = F_SETLK;
memset(&msg, 0, sizeof(struct message));
msg.cmd = cmd;
msg.fd = fd;
msg.lock = *lock;
err = ulockmgr_canonicalize(fd, &msg.lock);
if (err)
return err;
memset(&msg, 0, sizeof(struct message));
msg.cmd = cmd;
msg.fd = fd;
msg.lock = *lock;
err = ulockmgr_canonicalize(fd, &msg.lock);
if (err)
return err;
sigemptyset(&block);
sigaddset(&block, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &block, &old);
pthread_mutex_lock(&ulockmgr_lock);
err = ulockmgr_send_request(&msg, owner, owner_len);
pthread_mutex_unlock(&ulockmgr_lock);
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (!err && cmd == F_GETLK) {
if (msg.lock.l_type == F_UNLCK)
lock->l_type = F_UNLCK;
else
*lock = msg.lock;
}
sigemptyset(&block);
sigaddset(&block, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &block, &old);
pthread_mutex_lock(&ulockmgr_lock);
err = ulockmgr_send_request(&msg, owner, owner_len);
pthread_mutex_unlock(&ulockmgr_lock);
pthread_sigmask(SIG_SETMASK, &old, NULL);
if (!err && cmd == F_GETLK) {
if (msg.lock.l_type == F_UNLCK)
lock->l_type = F_UNLCK;
else
*lock = msg.lock;
}
return err;
return err;
}

View File

@ -3,195 +3,195 @@
#include "fuse_kernel.h"
static struct {
const char *name;
const char *name;
} fuse_ll_ops[] = {
[FUSE_LOOKUP] = { "LOOKUP" },
[FUSE_FORGET] = { "FORGET" },
[FUSE_GETATTR] = { "GETATTR" },
[FUSE_SETATTR] = { "SETATTR" },
[FUSE_READLINK] = { "READLINK" },
[FUSE_SYMLINK] = { "SYMLINK" },
[FUSE_MKNOD] = { "MKNOD" },
[FUSE_MKDIR] = { "MKDIR" },
[FUSE_UNLINK] = { "UNLINK" },
[FUSE_RMDIR] = { "RMDIR" },
[FUSE_RENAME] = { "RENAME" },
[FUSE_LINK] = { "LINK" },
[FUSE_OPEN] = { "OPEN" },
[FUSE_READ] = { "READ" },
[FUSE_WRITE] = { "WRITE" },
[FUSE_STATFS] = { "STATFS" },
[FUSE_RELEASE] = { "RELEASE" },
[FUSE_FSYNC] = { "FSYNC" },
[FUSE_SETXATTR] = { "SETXATTR" },
[FUSE_GETXATTR] = { "GETXATTR" },
[FUSE_LISTXATTR] = { "LISTXATTR" },
[FUSE_REMOVEXATTR] = { "REMOVEXATTR" },
[FUSE_FLUSH] = { "FLUSH" },
[FUSE_INIT] = { "INIT" },
[FUSE_OPENDIR] = { "OPENDIR" },
[FUSE_READDIR] = { "READDIR" },
[FUSE_RELEASEDIR] = { "RELEASEDIR" },
[FUSE_FSYNCDIR] = { "FSYNCDIR" },
[FUSE_GETLK] = { "GETLK" },
[FUSE_SETLK] = { "SETLK" },
[FUSE_SETLKW] = { "SETLKW" },
[FUSE_ACCESS] = { "ACCESS" },
[FUSE_CREATE] = { "CREATE" },
[FUSE_INTERRUPT] = { "INTERRUPT" },
[FUSE_BMAP] = { "BMAP" },
[FUSE_DESTROY] = { "DESTROY" },
[FUSE_LOOKUP] = { "LOOKUP" },
[FUSE_FORGET] = { "FORGET" },
[FUSE_GETATTR] = { "GETATTR" },
[FUSE_SETATTR] = { "SETATTR" },
[FUSE_READLINK] = { "READLINK" },
[FUSE_SYMLINK] = { "SYMLINK" },
[FUSE_MKNOD] = { "MKNOD" },
[FUSE_MKDIR] = { "MKDIR" },
[FUSE_UNLINK] = { "UNLINK" },
[FUSE_RMDIR] = { "RMDIR" },
[FUSE_RENAME] = { "RENAME" },
[FUSE_LINK] = { "LINK" },
[FUSE_OPEN] = { "OPEN" },
[FUSE_READ] = { "READ" },
[FUSE_WRITE] = { "WRITE" },
[FUSE_STATFS] = { "STATFS" },
[FUSE_RELEASE] = { "RELEASE" },
[FUSE_FSYNC] = { "FSYNC" },
[FUSE_SETXATTR] = { "SETXATTR" },
[FUSE_GETXATTR] = { "GETXATTR" },
[FUSE_LISTXATTR] = { "LISTXATTR" },
[FUSE_REMOVEXATTR] = { "REMOVEXATTR" },
[FUSE_FLUSH] = { "FLUSH" },
[FUSE_INIT] = { "INIT" },
[FUSE_OPENDIR] = { "OPENDIR" },
[FUSE_READDIR] = { "READDIR" },
[FUSE_RELEASEDIR] = { "RELEASEDIR" },
[FUSE_FSYNCDIR] = { "FSYNCDIR" },
[FUSE_GETLK] = { "GETLK" },
[FUSE_SETLK] = { "SETLK" },
[FUSE_SETLKW] = { "SETLKW" },
[FUSE_ACCESS] = { "ACCESS" },
[FUSE_CREATE] = { "CREATE" },
[FUSE_INTERRUPT] = { "INTERRUPT" },
[FUSE_BMAP] = { "BMAP" },
[FUSE_DESTROY] = { "DESTROY" },
};
#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
static const char *opname(enum fuse_opcode opcode)
{
if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
return "???";
else
return fuse_ll_ops[opcode].name;
if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
return "???";
else
return fuse_ll_ops[opcode].name;
}
static void process_buf(int dir, char *buf, int len)
{
static unsigned long long prevuniq = -1;
static int prevopcode;
static unsigned long long prevuniq = -1;
static int prevopcode;
if (!dir) {
struct fuse_in_header *in = (struct fuse_in_header *) buf;
buf += sizeof(struct fuse_in_header);
if (!dir) {
struct fuse_in_header *in = (struct fuse_in_header *) buf;
buf += sizeof(struct fuse_in_header);
printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n",
(unsigned long long) in->unique,
opname((enum fuse_opcode) in->opcode), in->opcode,
(unsigned long) in->nodeid, in->len, len);
printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n",
(unsigned long long) in->unique,
opname((enum fuse_opcode) in->opcode), in->opcode,
(unsigned long) in->nodeid, in->len, len);
switch (in->opcode) {
case FUSE_READ: {
struct fuse_read_in *arg = (struct fuse_read_in *) buf;
printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n",
arg->fh, arg->offset, arg->size, arg->read_flags,
arg->lock_owner, arg->flags);
break;
}
case FUSE_WRITE: {
struct fuse_write_in *arg = (struct fuse_write_in *) buf;
printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n",
arg->fh, arg->offset, arg->size, arg->write_flags,
arg->lock_owner, arg->flags);
break;
}
}
prevuniq = in->unique;
prevopcode = in->opcode;
} else {
struct fuse_out_header *out = (struct fuse_out_header *) buf;
buf += sizeof(struct fuse_out_header);
switch (in->opcode) {
case FUSE_READ: {
struct fuse_read_in *arg = (struct fuse_read_in *) buf;
printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n",
arg->fh, arg->offset, arg->size, arg->read_flags,
arg->lock_owner, arg->flags);
break;
}
case FUSE_WRITE: {
struct fuse_write_in *arg = (struct fuse_write_in *) buf;
printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n",
arg->fh, arg->offset, arg->size, arg->write_flags,
arg->lock_owner, arg->flags);
break;
}
}
prevuniq = in->unique;
prevopcode = in->opcode;
} else {
struct fuse_out_header *out = (struct fuse_out_header *) buf;
buf += sizeof(struct fuse_out_header);
printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n",
(unsigned long long) out->unique, out->error,
strerror(-out->error), out->len, len);
printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n",
(unsigned long long) out->unique, out->error,
strerror(-out->error), out->len, len);
if (out->unique == prevuniq) {
switch (prevopcode) {
case FUSE_GETATTR: {
struct fuse_attr_out *arg = (struct fuse_attr_out *) buf;
printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n",
arg->attr_valid, arg->attr_valid_nsec,
arg->attr.ino, arg->attr.size, arg->attr.blocks);
break;
}
case FUSE_LOOKUP: {
struct fuse_entry_out *arg = (struct fuse_entry_out *) buf;
printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n",
arg->nodeid, arg->attr_valid, arg->attr_valid_nsec,
arg->attr.ino, arg->attr.size, arg->attr.blocks);
break;
}
}
}
}
if (out->unique == prevuniq) {
switch (prevopcode) {
case FUSE_GETATTR: {
struct fuse_attr_out *arg = (struct fuse_attr_out *) buf;
printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n",
arg->attr_valid, arg->attr_valid_nsec,
arg->attr.ino, arg->attr.size, arg->attr.blocks);
break;
}
case FUSE_LOOKUP: {
struct fuse_entry_out *arg = (struct fuse_entry_out *) buf;
printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n",
arg->nodeid, arg->attr_valid, arg->attr_valid_nsec,
arg->attr.ino, arg->attr.size, arg->attr.blocks);
break;
}
}
}
}
}
int main(void)
{
FILE *in = stdin;
while (1) {
int dir;
int res;
char buf[1048576];
unsigned len = 0;
FILE *in = stdin;
while (1) {
int dir;
int res;
char buf[1048576];
unsigned len = 0;
memset(buf, 0, sizeof(buf));
while (1) {
char str[32];
memset(buf, 0, sizeof(buf));
while (1) {
char str[32];
res = fscanf(in, "%30s", str);
if (res != 1 && feof(in))
return 0;
res = fscanf(in, "%30s", str);
if (res != 1 && feof(in))
return 0;
if (res == 0)
continue;
if (res == 0)
continue;
if (strncmp(str, "read(", 5) == 0) {
dir = 0;
break;
} else if (strncmp(str, "writev(", 7) == 0) {
dir = 1;
break;
}
}
if (strncmp(str, "read(", 5) == 0) {
dir = 0;
break;
} else if (strncmp(str, "writev(", 7) == 0) {
dir = 1;
break;
}
}
while (1) {
int c = getc(in);
if (c == '"') {
while (1) {
int val;
while (1) {
int c = getc(in);
if (c == '"') {
while (1) {
int val;
c = getc(in);
if (c == EOF) {
fprintf(stderr, "eof in string\n");
break;
}
if (c == '\n') {
fprintf(stderr, "eol in string\n");
break;
}
if (c == '"')
break;
if (c != '\\') {
val = c;
} else {
c = getc(in);
switch (c) {
case 'n': val = '\n'; break;
case 'r': val = '\r'; break;
case 't': val = '\t'; break;
case '"': val = '"'; break;
case '\\': val = '\\'; break;
case 'x':
res = scanf("%x", &val);
if (res != 1) {
fprintf(stderr, "parse error\n");
continue;
}
break;
default:
fprintf(stderr, "unknown sequence: '\\%c'\n", c);
continue;
}
}
buf[len++] = val;
}
}
if (c == '\n')
break;
}
process_buf(dir, buf, len);
memset(buf, 0, len);
len = 0;
}
c = getc(in);
if (c == EOF) {
fprintf(stderr, "eof in string\n");
break;
}
if (c == '\n') {
fprintf(stderr, "eol in string\n");
break;
}
if (c == '"')
break;
if (c != '\\') {
val = c;
} else {
c = getc(in);
switch (c) {
case 'n': val = '\n'; break;
case 'r': val = '\r'; break;
case 't': val = '\t'; break;
case '"': val = '"'; break;
case '\\': val = '\\'; break;
case 'x':
res = scanf("%x", &val);
if (res != 1) {
fprintf(stderr, "parse error\n");
continue;
}
break;
default:
fprintf(stderr, "unknown sequence: '\\%c'\n", c);
continue;
}
}
buf[len++] = val;
}
}
if (c == '\n')
break;
}
process_buf(dir, buf, len);
memset(buf, 0, len);
len = 0;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,11 @@
/*
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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -8,184 +16,193 @@ static char *progname;
static char *xstrdup(const char *s)
{
char *t = strdup(s);
if (!t) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
exit(1);
}
return t;
char *t = strdup(s);
if (!t) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
exit(1);
}
return t;
}
static void *xrealloc(void *oldptr, size_t size)
{
void *ptr = realloc(oldptr, size);
if (!ptr) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
exit(1);
}
return ptr;
void *ptr = realloc(oldptr, size);
if (!ptr) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
exit(1);
}
return ptr;
}
static void add_arg(char **cmdp, const char *opt)
{
size_t optlen = strlen(opt);
size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
char *s;
s = cmd + cmdlen;
if (*cmdp)
*s++ = ' ';
size_t optlen = strlen(opt);
size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
char *s;
s = cmd + cmdlen;
if (*cmdp)
*s++ = ' ';
*s++ = '\'';
for (; *opt; opt++) {
if (*opt == '\'') {
*s++ = '\'';
*s++ = '\\';
*s++ = '\'';
*s++ = '\'';
} else
*s++ = *opt;
}
*s++ = '\'';
*s = '\0';
*cmdp = cmd;
*s++ = '\'';
for (; *opt; opt++) {
if (*opt == '\'') {
*s++ = '\'';
*s++ = '\\';
*s++ = '\'';
*s++ = '\'';
} else
*s++ = *opt;
}
*s++ = '\'';
*s = '\0';
*cmdp = cmd;
}
int main(int argc, char *argv[])
{
char *type = NULL;
char *source;
const char *mountpoint;
char *basename;
char *options = NULL;
char *command = NULL;
char *setuid = NULL;
int i;
char *type = NULL;
char *source;
const char *mountpoint;
char *basename;
char *options = NULL;
char *command = NULL;
char *setuid = NULL;
int i;
progname = argv[0];
basename = strrchr(argv[0], '/');
if (basename)
basename++;
else
basename = argv[0];
progname = argv[0];
basename = strrchr(argv[0], '/');
if (basename)
basename++;
else
basename = argv[0];
if (strncmp(basename, "mount.fuse.", 11) == 0)
type = basename + 11;
if (strncmp(basename, "mount.fuseblk.", 14) == 0)
type = basename + 14;
if (strncmp(basename, "mount.fuse.", 11) == 0)
type = basename + 11;
if (strncmp(basename, "mount.fuseblk.", 14) == 0)
type = basename + 14;
if (type && !type[0])
type = NULL;
if (type && !type[0])
type = NULL;
if (argc < 3) {
fprintf(stderr, "usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
progname, type ? "source" : "type#[source]");
exit(1);
}
if (argc < 3) {
fprintf(stderr,
"usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
progname, type ? "source" : "type#[source]");
exit(1);
}
source = argv[1];
if (!source[0])
source = NULL;
source = argv[1];
if (!source[0])
source = NULL;
mountpoint = argv[2];
mountpoint = argv[2];
for (i = 3; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
continue;
} else if (strcmp(argv[i], "-t") == 0) {
i++;
for (i = 3; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
continue;
} else if (strcmp(argv[i], "-t") == 0) {
i++;
if (i == argc) {
fprintf(stderr,
"%s: missing argument to option '-t'\n", progname);
exit(1);
}
type = argv[i];
if (strncmp(type, "fuse.", 5) == 0)
type += 5;
else if (strncmp(type, "fuseblk.", 8) == 0)
type += 8;
if (i == argc) {
fprintf(stderr,
"%s: missing argument to option '-t'\n",
progname);
exit(1);
}
type = argv[i];
if (strncmp(type, "fuse.", 5) == 0)
type += 5;
else if (strncmp(type, "fuseblk.", 8) == 0)
type += 8;
if (!type[0]) {
fprintf(stderr,
"%s: empty type given as argument to option '-t'\n",
progname);
exit(1);
}
} else if (strcmp(argv[i], "-o") == 0) {
char *opts;
char *opt;
i++;
if (i == argc)
break;
if (!type[0]) {
fprintf(stderr,
"%s: empty type given as argument to option '-t'\n",
progname);
exit(1);
}
} else if (strcmp(argv[i], "-o") == 0) {
char *opts;
char *opt;
i++;
if (i == argc)
break;
opts = xstrdup(argv[i]);
opt = strtok(opts, ",");
while (opt) {
int j;
int ignore = 0;
const char *ignore_opts[] = { "", "user", "nouser", "users",
"auto", "noauto", "_netdev",
NULL};
if (strncmp(opt, "setuid=", 7) == 0) {
setuid = xstrdup(opt + 7);
ignore = 1;
}
for (j = 0; ignore_opts[j]; j++)
if (strcmp(opt, ignore_opts[j]) == 0)
ignore = 1;
opts = xstrdup(argv[i]);
opt = strtok(opts, ",");
while (opt) {
int j;
int ignore = 0;
const char *ignore_opts[] = { "",
"user",
"nouser",
"users",
"auto",
"noauto",
"_netdev",
NULL};
if (strncmp(opt, "setuid=", 7) == 0) {
setuid = xstrdup(opt + 7);
ignore = 1;
}
for (j = 0; ignore_opts[j]; j++)
if (strcmp(opt, ignore_opts[j]) == 0)
ignore = 1;
if (!ignore) {
int oldlen = options ? strlen(options) : 0;
options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
if (!oldlen)
strcpy(options, opt);
else {
strcat(options, ",");
strcat(options, opt);
}
}
opt = strtok(NULL, ",");
}
}
}
if (!ignore) {
int oldlen =
options ? strlen(options) : 0;
options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
if (!oldlen)
strcpy(options, opt);
else {
strcat(options, ",");
strcat(options, opt);
}
}
opt = strtok(NULL, ",");
}
}
}
if (!type) {
type = xstrdup(source);
source = strchr(type, '#');
if (source)
*source++ = '\0';
if (!type) {
type = xstrdup(source);
source = strchr(type, '#');
if (source)
*source++ = '\0';
if (!type[0]) {
fprintf(stderr, "%s: empty filesystem type\n", progname);
exit(1);
}
}
if (!type[0]) {
fprintf(stderr, "%s: empty filesystem type\n",
progname);
exit(1);
}
}
add_arg(&command, type);
if (source)
add_arg(&command, source);
add_arg(&command, mountpoint);
if (options) {
add_arg(&command, "-o");
add_arg(&command, options);
}
add_arg(&command, type);
if (source)
add_arg(&command, source);
add_arg(&command, mountpoint);
if (options) {
add_arg(&command, "-o");
add_arg(&command, options);
}
if (setuid && setuid[0]) {
char *sucommand = command;
command = NULL;
add_arg(&command, "su");
add_arg(&command, "-");
add_arg(&command, setuid);
add_arg(&command, "-c");
add_arg(&command, sucommand);
} else if (!getenv("HOME")) {
/* Hack to make filesystems work in the boot environment */
setenv("HOME", "/root", 0);
}
if (setuid && setuid[0]) {
char *sucommand = command;
command = NULL;
add_arg(&command, "su");
add_arg(&command, "-");
add_arg(&command, setuid);
add_arg(&command, "-c");
add_arg(&command, sucommand);
} else if (!getenv("HOME")) {
/* Hack to make filesystems work in the boot environment */
setenv("HOME", "/root", 0);
}
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
strerror(errno));
return 1;
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
strerror(errno));
return 1;
}

View File

@ -1,9 +1,9 @@
/*
ulockmgr_server: Userspace Lock Manager Server
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
ulockmgr_server: Userspace Lock Manager Server
Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
/* #define DEBUG 1 */
@ -23,381 +23,388 @@
#include <sys/wait.h>
struct message {
unsigned intr : 1;
unsigned nofd : 1;
pthread_t thr;
int cmd;
int fd;
struct flock lock;
int error;
unsigned intr : 1;
unsigned nofd : 1;
pthread_t thr;
int cmd;
int fd;
struct flock lock;
int error;
};
struct fd_store {
struct fd_store *next;
int fd;
int origfd;
int inuse;
struct fd_store *next;
int fd;
int origfd;
int inuse;
};
struct owner {
struct fd_store *fds;
pthread_mutex_t lock;
struct fd_store *fds;
pthread_mutex_t lock;
};
struct req_data {
struct owner *o;
int cfd;
struct fd_store *f;
struct message msg;
struct owner *o;
int cfd;
struct fd_store *f;
struct message msg;
};
#define MAX_SEND_FDS 2
static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
int *numfds)
int *numfds)
{
struct msghdr msg;
struct iovec iov;
size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
struct cmsghdr *cmsg;
int res;
int i;
struct msghdr msg;
struct iovec iov;
size_t ccmsg[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
struct cmsghdr *cmsg;
int res;
int i;
assert(*numfds <= MAX_SEND_FDS);
iov.iov_base = buf;
iov.iov_len = buflen;
assert(*numfds <= MAX_SEND_FDS);
iov.iov_base = buf;
iov.iov_len = buflen;
memset(&msg, 0, sizeof(msg));
memset(ccmsg, -1, sizeof(ccmsg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
memset(&msg, 0, sizeof(msg));
memset(ccmsg, -1, sizeof(ccmsg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
res = recvmsg(sock, &msg, MSG_WAITALL);
if (!res) {
/* retry on zero return, see do_recv() in ulockmgr.c */
res = recvmsg(sock, &msg, MSG_WAITALL);
if (!res)
return 0;
}
if (res == -1) {
perror("ulockmgr_server: recvmsg");
return -1;
}
if ((size_t) res != buflen) {
fprintf(stderr, "ulockmgr_server: short message received\n");
return -1;
}
res = recvmsg(sock, &msg, MSG_WAITALL);
if (!res) {
/* retry on zero return, see do_recv() in ulockmgr.c */
res = recvmsg(sock, &msg, MSG_WAITALL);
if (!res)
return 0;
}
if (res == -1) {
perror("ulockmgr_server: recvmsg");
return -1;
}
if ((size_t) res != buflen) {
fprintf(stderr, "ulockmgr_server: short message received\n");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg) {
if (!cmsg->cmsg_type == SCM_RIGHTS) {
fprintf(stderr, "ulockmgr_server: unknown control message %d\n",
cmsg->cmsg_type);
return -1;
}
memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr, "ulockmgr_server: control message truncated\n");
for (i = 0; i < *numfds; i++)
close(fdp[i]);
*numfds = 0;
}
} else {
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr, "ulockmgr_server: control message truncated(*)\n");
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg) {
if (!cmsg->cmsg_type == SCM_RIGHTS) {
fprintf(stderr,
"ulockmgr_server: unknown control message %d\n",
cmsg->cmsg_type);
return -1;
}
memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr,
"ulockmgr_server: control message truncated\n");
for (i = 0; i < *numfds; i++)
close(fdp[i]);
*numfds = 0;
}
} else {
if (msg.msg_flags & MSG_CTRUNC) {
fprintf(stderr,
"ulockmgr_server: control message truncated(*)\n");
/* There's a bug in the Linux kernel, that if not all file
descriptors were allocated, then the cmsg header is not
filled in */
cmsg = (struct cmsghdr *) ccmsg;
memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
for (i = 0; i < *numfds; i++)
close(fdp[i]);
}
*numfds = 0;
}
return res;
/* There's a bug in the Linux kernel, that if
not all file descriptors were allocated,
then the cmsg header is not filled in */
cmsg = (struct cmsghdr *) ccmsg;
memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
for (i = 0; i < *numfds; i++)
close(fdp[i]);
}
*numfds = 0;
}
return res;
}
static int closefrom(int minfd)
{
DIR *dir = opendir("/proc/self/fd");
if (dir) {
int dfd = dirfd(dir);
struct dirent *ent;
while ((ent = readdir(dir))) {
char *end;
int fd = strtol(ent->d_name, &end, 10);
if (ent->d_name[0] && !end[0] && fd >= minfd && fd != dfd)
close(fd);
}
closedir(dir);
}
return 0;
DIR *dir = opendir("/proc/self/fd");
if (dir) {
int dfd = dirfd(dir);
struct dirent *ent;
while ((ent = readdir(dir))) {
char *end;
int fd = strtol(ent->d_name, &end, 10);
if (ent->d_name[0] && !end[0] && fd >= minfd &&
fd != dfd)
close(fd);
}
closedir(dir);
}
return 0;
}
static void send_reply(int cfd, struct message *msg)
{
int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
if (res == -1)
perror("ulockmgr_server: sending reply");
int res = send(cfd, msg, sizeof(struct message), MSG_NOSIGNAL);
if (res == -1)
perror("ulockmgr_server: sending reply");
#ifdef DEBUG
fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error);
fprintf(stderr, "ulockmgr_server: error: %i\n", msg->error);
#endif
}
static void *process_request(void *d_)
{
struct req_data *d = d_;
int res;
struct req_data *d = d_;
int res;
assert(d->msg.cmd == F_SETLKW);
res = fcntl(d->f->fd, F_SETLK, &d->msg.lock);
if (res == -1 && errno == EAGAIN) {
d->msg.error = EAGAIN;
d->msg.thr = pthread_self();
send_reply(d->cfd, &d->msg);
res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock);
}
d->msg.error = (res == -1) ? errno : 0;
pthread_mutex_lock(&d->o->lock);
d->f->inuse--;
pthread_mutex_unlock(&d->o->lock);
send_reply(d->cfd, &d->msg);
close(d->cfd);
free(d);
assert(d->msg.cmd == F_SETLKW);
res = fcntl(d->f->fd, F_SETLK, &d->msg.lock);
if (res == -1 && errno == EAGAIN) {
d->msg.error = EAGAIN;
d->msg.thr = pthread_self();
send_reply(d->cfd, &d->msg);
res = fcntl(d->f->fd, F_SETLKW, &d->msg.lock);
}
d->msg.error = (res == -1) ? errno : 0;
pthread_mutex_lock(&d->o->lock);
d->f->inuse--;
pthread_mutex_unlock(&d->o->lock);
send_reply(d->cfd, &d->msg);
close(d->cfd);
free(d);
return NULL;
return NULL;
}
static void process_message(struct owner *o, struct message *msg, int cfd,
int fd)
int fd)
{
struct fd_store *f = NULL;
struct fd_store *newf = NULL;
struct fd_store **fp;
struct req_data *d;
pthread_t tid;
int res;
struct fd_store *f = NULL;
struct fd_store *newf = NULL;
struct fd_store **fp;
struct req_data *d;
pthread_t tid;
int res;
#ifdef DEBUG
fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n",
msg->cmd, msg->lock.l_type, msg->lock.l_whence, msg->lock.l_start,
msg->lock.l_len);
fprintf(stderr, "ulockmgr_server: %i %i %i %lli %lli\n",
msg->cmd, msg->lock.l_type, msg->lock.l_whence,
msg->lock.l_start, msg->lock.l_len);
#endif
if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
msg->lock.l_start == 0 && msg->lock.l_len == 0) {
for (fp = &o->fds; *fp;) {
f = *fp;
if (f->origfd == msg->fd && !f->inuse) {
close(f->fd);
*fp = f->next;
free(f);
} else
fp = &f->next;
}
if (!msg->nofd)
close(fd);
if (msg->cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
msg->lock.l_start == 0 && msg->lock.l_len == 0) {
for (fp = &o->fds; *fp;) {
f = *fp;
if (f->origfd == msg->fd && !f->inuse) {
close(f->fd);
*fp = f->next;
free(f);
} else
fp = &f->next;
}
if (!msg->nofd)
close(fd);
msg->error = 0;
send_reply(cfd, msg);
close(cfd);
return;
}
msg->error = 0;
send_reply(cfd, msg);
close(cfd);
return;
}
if (msg->nofd) {
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
f = *fp;
if (f->origfd == msg->fd)
break;
}
if (!*fp) {
fprintf(stderr, "ulockmgr_server: fd %i not found\n", msg->fd);
msg->error = EIO;
send_reply(cfd, msg);
close(cfd);
return;
}
} else {
newf = f = malloc(sizeof(struct fd_store));
if (!f) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
return;
}
if (msg->nofd) {
for (fp = &o->fds; *fp; fp = &(*fp)->next) {
f = *fp;
if (f->origfd == msg->fd)
break;
}
if (!*fp) {
fprintf(stderr, "ulockmgr_server: fd %i not found\n",
msg->fd);
msg->error = EIO;
send_reply(cfd, msg);
close(cfd);
return;
}
} else {
newf = f = malloc(sizeof(struct fd_store));
if (!f) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
return;
}
f->fd = fd;
f->origfd = msg->fd;
f->inuse = 0;
}
f->fd = fd;
f->origfd = msg->fd;
f->inuse = 0;
}
if (msg->cmd == F_GETLK || msg->cmd == F_SETLK ||
msg->lock.l_type == F_UNLCK) {
res = fcntl(f->fd, msg->cmd, &msg->lock);
msg->error = (res == -1) ? errno : 0;
send_reply(cfd, msg);
close(cfd);
if (newf) {
newf->next = o->fds;
o->fds = newf;
}
return;
}
if (msg->cmd == F_GETLK || msg->cmd == F_SETLK ||
msg->lock.l_type == F_UNLCK) {
res = fcntl(f->fd, msg->cmd, &msg->lock);
msg->error = (res == -1) ? errno : 0;
send_reply(cfd, msg);
close(cfd);
if (newf) {
newf->next = o->fds;
o->fds = newf;
}
return;
}
d = malloc(sizeof(struct req_data));
if (!d) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
free(newf);
return;
}
d = malloc(sizeof(struct req_data));
if (!d) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
free(newf);
return;
}
f->inuse++;
d->o = o;
d->cfd = cfd;
d->f = f;
d->msg = *msg;
res = pthread_create(&tid, NULL, process_request, d);
if (res) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
free(d);
f->inuse--;
free(newf);
return;
}
f->inuse++;
d->o = o;
d->cfd = cfd;
d->f = f;
d->msg = *msg;
res = pthread_create(&tid, NULL, process_request, d);
if (res) {
msg->error = ENOLCK;
send_reply(cfd, msg);
close(cfd);
free(d);
f->inuse--;
free(newf);
return;
}
if (newf) {
newf->next = o->fds;
o->fds = newf;
}
pthread_detach(tid);
if (newf) {
newf->next = o->fds;
o->fds = newf;
}
pthread_detach(tid);
}
static void sigusr1_handler(int sig)
{
(void) sig;
/* Nothing to do */
(void) sig;
/* Nothing to do */
}
static void process_owner(int cfd)
{
struct owner o;
struct sigaction sa;
struct owner o;
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = sigusr1_handler;
sigemptyset(&sa.sa_mask);
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = sigusr1_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("ulockmgr_server: cannot set sigusr1 signal handler");
exit(1);
}
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("ulockmgr_server: cannot set sigusr1 signal handler");
exit(1);
}
memset(&o, 0, sizeof(struct owner));
pthread_mutex_init(&o.lock, NULL);
while (1) {
struct message msg;
int rfds[2];
int res;
int numfds = 2;
memset(&o, 0, sizeof(struct owner));
pthread_mutex_init(&o.lock, NULL);
while (1) {
struct message msg;
int rfds[2];
int res;
int numfds = 2;
res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds);
if (!res)
break;
if (res == -1)
exit(1);
res = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds);
if (!res)
break;
if (res == -1)
exit(1);
if (msg.intr) {
if (numfds != 0)
fprintf(stderr, "ulockmgr_server: too many fds for intr\n");
pthread_kill(msg.thr, SIGUSR1);
} else {
if (numfds != 2)
continue;
if (msg.intr) {
if (numfds != 0)
fprintf(stderr,
"ulockmgr_server: too many fds for intr\n");
pthread_kill(msg.thr, SIGUSR1);
} else {
if (numfds != 2)
continue;
pthread_mutex_lock(&o.lock);
process_message(&o, &msg, rfds[0], rfds[1]);
pthread_mutex_unlock(&o.lock);
}
}
if (o.fds)
fprintf(stderr, "ulockmgr_server: open file descriptors on exit\n");
pthread_mutex_lock(&o.lock);
process_message(&o, &msg, rfds[0], rfds[1]);
pthread_mutex_unlock(&o.lock);
}
}
if (o.fds)
fprintf(stderr,
"ulockmgr_server: open file descriptors on exit\n");
}
int main(int argc, char *argv[])
{
int nullfd;
char *end;
int cfd;
sigset_t empty;
int nullfd;
char *end;
int cfd;
sigset_t empty;
if (argc != 2 || !argv[1][0])
goto out_inval;
if (argc != 2 || !argv[1][0])
goto out_inval;
cfd = strtol(argv[1], &end, 10);
if (*end)
goto out_inval;
cfd = strtol(argv[1], &end, 10);
if (*end)
goto out_inval;
if (daemon(0, 1) == -1) {
perror("ulockmgr_server: daemon");
exit(1);
}
if (daemon(0, 1) == -1) {
perror("ulockmgr_server: daemon");
exit(1);
}
sigemptyset(&empty);
sigprocmask(SIG_SETMASK, &empty, NULL);
sigemptyset(&empty);
sigprocmask(SIG_SETMASK, &empty, NULL);
if (dup2(cfd, 4) == -1) {
perror("ulockmgr_server: dup2");
exit(1);
}
cfd = 4;
nullfd = open("/dev/null", O_RDWR);
dup2(nullfd, 0);
dup2(nullfd, 1);
close(3);
closefrom(5);
while (1) {
char c;
int sock;
int pid;
int numfds = 1;
int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds);
if (!res)
break;
if (res == -1)
exit(1);
assert(numfds == 1);
if (dup2(cfd, 4) == -1) {
perror("ulockmgr_server: dup2");
exit(1);
}
cfd = 4;
nullfd = open("/dev/null", O_RDWR);
dup2(nullfd, 0);
dup2(nullfd, 1);
close(3);
closefrom(5);
while (1) {
char c;
int sock;
int pid;
int numfds = 1;
int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds);
if (!res)
break;
if (res == -1)
exit(1);
assert(numfds == 1);
pid = fork();
if (pid == -1) {
perror("ulockmgr_server: fork");
close(sock);
continue;
}
if (pid == 0) {
close(cfd);
pid = fork();
if (pid == -1) {
perror("ulockmgr_server: fork");
_exit(1);
}
if (pid == 0)
process_owner(sock);
_exit(0);
}
waitpid(pid, NULL, 0);
close(sock);
}
return 0;
pid = fork();
if (pid == -1) {
perror("ulockmgr_server: fork");
close(sock);
continue;
}
if (pid == 0) {
close(cfd);
pid = fork();
if (pid == -1) {
perror("ulockmgr_server: fork");
_exit(1);
}
if (pid == 0)
process_owner(sock);
_exit(0);
}
waitpid(pid, NULL, 0);
close(sock);
}
return 0;
out_inval:
fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]);
return 1;
out_inval:
fprintf(stderr, "%s should be started by libulockmgr\n", argv[0]);
return 1;
}