mirror of
https://github.com/libfuse/libfuse.git
synced 2024-11-23 12:14:15 +08:00
change indenting
This commit is contained in:
parent
918f0ad95b
commit
cdb8b79bad
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
797
include/fuse.h
797
include/fuse.h
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
4695
lib/fuse.c
File diff suppressed because it is too large
Load Diff
22
lib/fuse_i.h
22
lib/fuse_i.h
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
1751
lib/fuse_lowlevel.c
1751
lib/fuse_lowlevel.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
|
130
lib/fuse_mt.c
130
lib/fuse_mt.c
@ -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@");
|
||||
|
500
lib/fuse_opt.c
500
lib/fuse_opt.c
@ -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 */
|
||||
|
@ -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__
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
512
lib/helper.c
512
lib/helper.c
@ -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
858
lib/mount.c
858
lib/mount.c
@ -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");
|
||||
|
514
lib/mount_bsd.c
514
lib/mount_bsd.c
@ -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");
|
||||
|
367
lib/mount_util.c
367
lib/mount_util.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
646
lib/ulockmgr.c
646
lib/ulockmgr.c
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
2184
test/test.c
2184
test/test.c
File diff suppressed because it is too large
Load Diff
1407
util/fusermount.c
1407
util/fusermount.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user