fix
diff --git a/ChangeLog b/ChangeLog
index faf3559..c44e8ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-08-25 Miklos Szeredi <miklos@szeredi.hu>
+
+ * lib: add userspace side of ftruncate() method for experimentation
+
2005-08-23 Miklos Szeredi <miklos@szeredi.hu>
* lib: add userspace side of create() method for experimentation
diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c
index a1d2283..17bd77e 100644
--- a/example/fusexmp_fh.c
+++ b/example/fusexmp_fh.c
@@ -193,6 +193,20 @@
return 0;
}
+static int xmp_ftruncate(const char *path, off_t size,
+ struct fuse_file_info *fi)
+{
+ int res;
+
+ (void) path;
+
+ res = ftruncate(fi->fh, size);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
static int xmp_utime(const char *path, struct utimbuf *buf)
{
int res;
@@ -353,6 +367,7 @@
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
+ .ftruncate = xmp_ftruncate,
.utime = xmp_utime,
.open = xmp_open,
.read = xmp_read,
diff --git a/example/hello_ll.c b/example/hello_ll.c
index f5a2baf..882f2cd 100644
--- a/example/hello_ll.c
+++ b/example/hello_ll.c
@@ -40,10 +40,13 @@
return 0;
}
-static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino)
+static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
struct stat stbuf;
+ (void) fi;
+
memset(&stbuf, 0, sizeof(stbuf));
if (hello_stat(ino, &stbuf) == -1)
fuse_reply_err(req, ENOENT);
diff --git a/include/fuse.h b/include/fuse.h
index 6251158..39982dc 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -313,6 +313,8 @@
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 *);
};
/** Extra context that may be needed by some filesystems
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index a8e3e3e..a1c475e 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -78,9 +78,9 @@
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);
+ 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);
+ int to_set, struct fuse_file_info *fi);
void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
void (*readlink)(fuse_req_t req, fuse_ino_t ino);
void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h
index aa6b298..e1d8a0c 100644
--- a/kernel/fuse_kernel.h
+++ b/kernel/fuse_kernel.h
@@ -107,7 +107,8 @@
FUSE_SETLK = 32,
FUSE_SETLKW = 33,
FUSE_ACCESS = 34,
- FUSE_CREATE = 35
+ FUSE_CREATE = 35,
+ FUSE_FSETATTR = 36
};
/* Conservative buffer size for the client */
@@ -163,6 +164,11 @@
struct fuse_attr attr;
};
+struct fuse_fsetattr_in {
+ __u64 fh;
+ struct fuse_setattr_in setattr;
+};
+
struct fuse_open_in {
__u32 flags;
__u32 mode;
diff --git a/lib/fuse.c b/lib/fuse.c
index 237dee1..7f8ed3d 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -612,13 +612,16 @@
fuse_reply_none(req);
}
-static void fuse_getattr(fuse_req_t req, fuse_ino_t ino)
+static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
struct fuse *f = req_fuse_prepare(req);
struct stat buf;
char *path;
int err;
+ (void) fi;
+
err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
path = get_path(f, ino);
@@ -661,12 +664,15 @@
return err;
}
-static int do_truncate(struct fuse *f, const char *path, struct stat *attr)
+static int do_truncate(struct fuse *f, const char *path, struct stat *attr,
+ struct fuse_file_info *fi)
{
int err;
err = -ENOSYS;
- if (f->op.truncate)
+ if (fi && f->op.ftruncate)
+ err = f->op.ftruncate(path, attr->st_size, fi);
+ else if (f->op.truncate)
err = f->op.truncate(path, attr->st_size);
return err;
@@ -686,7 +692,7 @@
}
static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
- int valid)
+ int valid, struct fuse_file_info *fi)
{
struct fuse *f = req_fuse_prepare(req);
struct stat buf;
@@ -705,7 +711,7 @@
if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
err = do_chown(f, path, attr, valid);
if (!err && (valid & FUSE_SET_ATTR_SIZE))
- err = do_truncate(f, path, attr);
+ err = do_truncate(f, path, attr, fi);
if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
err = do_utime(f, path, attr);
if (!err)
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 893f723..3bbc296 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -74,6 +74,7 @@
case FUSE_SETLKW: return "SETLKW";
case FUSE_ACCESS: return "ACCESS";
case FUSE_CREATE: return "CREATE";
+ case FUSE_FSETATTR: return "FSETATTR";
default: return "???";
}
}
@@ -394,23 +395,33 @@
static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
{
if (req->f->op.getattr)
- req->f->op.getattr(req, nodeid);
+ req->f->op.getattr(req, nodeid, NULL);
else
fuse_reply_err(req, ENOSYS);
}
static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
- struct fuse_setattr_in *arg)
+ struct fuse_setattr_in *arg, struct fuse_file_info *fi)
{
if (req->f->op.setattr) {
struct stat stbuf;
memset(&stbuf, 0, sizeof(stbuf));
convert_attr(&arg->attr, &stbuf);
- req->f->op.setattr(req, nodeid, &stbuf, arg->valid);
+ req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
} else
fuse_reply_err(req, ENOSYS);
}
+static void do_fsetattr(fuse_req_t req, fuse_ino_t nodeid,
+ struct fuse_fsetattr_in *arg)
+{
+ struct fuse_file_info fi;
+
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ do_setattr(req, nodeid, &arg->setattr, &fi);
+}
+
static void do_access(fuse_req_t req, fuse_ino_t nodeid,
struct fuse_access_in *arg)
{
@@ -813,7 +824,11 @@
break;
case FUSE_SETATTR:
- do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
+ do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg, NULL);
+ break;
+
+ case FUSE_FSETATTR:
+ do_fsetattr(req, in->nodeid, (struct fuse_fsetattr_in *) inarg);
break;
case FUSE_READLINK:
diff --git a/test/test.c b/test/test.c
index 0f409ad..3fba745 100644
--- a/test/test.c
+++ b/test/test.c
@@ -364,7 +364,6 @@
return 0;
}
-
int test_truncate(int len)
{
const char *data = testdata;
@@ -412,6 +411,73 @@
return 0;
}
+int test_ftruncate(int len, int mode)
+{
+ const char *data = testdata;
+ int datalen = testdatalen;
+ int res;
+ int fd;
+
+ start_test("ftruncate(%u) mode: 0%03o", len, mode);
+ res = create_file(testfile, data, datalen);
+ if (res == -1)
+ return -1;
+
+ fd = open(testfile, O_WRONLY);
+ if (fd == -1) {
+ PERROR("open");
+ return -1;
+ }
+
+ res = fchmod(fd, mode);
+ if (res == -1) {
+ PERROR("fchmod");
+ close(fd);
+ return -1;
+ }
+ res = check_mode(testfile, mode);
+ if (res == -1) {
+ close(fd);
+ return -1;
+ }
+ res = ftruncate(fd, len);
+ if (res == -1) {
+ PERROR("ftruncate");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ res = check_size(testfile, len);
+ if (res == -1)
+ return -1;
+
+ if (len > 0) {
+ if (len <= datalen) {
+ res = check_data(testfile, data, 0, len);
+ if (res == -1)
+ return -1;
+ } else {
+ res = check_data(testfile, data, 0, datalen);
+ if (res == -1)
+ return -1;
+ res = check_data(testfile, zerodata, datalen, len - datalen);
+ if (res == -1)
+ return -1;
+ }
+ }
+ res = unlink(testfile);
+ if (res == -1) {
+ PERROR("unlink");
+ return -1;
+ }
+ res = check_nonexist(testfile2);
+ if (res == -1)
+ return -1;
+
+ success();
+ return 0;
+}
+
static int test_create(void)
{
const char *data = testdata;
@@ -612,6 +678,49 @@
return 0;
}
+#define test_open_acc(flags, mode, err) do_test_open_acc(flags, #flags, mode, err)
+
+static int do_test_open_acc(int flags, const char *flags_str, int mode, int err)
+{
+ const char *data = testdata;
+ int datalen = testdatalen;
+ int res;
+ int fd;
+
+ start_test("open_acc(%s) mode: 0%03o error: '%s'", flags_str, mode,
+ strerror(err));
+ unlink(testfile);
+ res = create_file(testfile, data, datalen);
+ if (res == -1)
+ return -1;
+
+ res = chmod(testfile, mode);
+ if (res == -1) {
+ PERROR("chmod");
+ return -1;
+ }
+
+ res = check_mode(testfile, mode);
+ if (res == -1)
+ return -1;
+
+ fd = open(testfile, flags);
+ if (fd == -1) {
+ if (err != errno) {
+ PERROR("open");
+ return -1;
+ }
+ } else {
+ if (err) {
+ ERROR("open should have failed");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ }
+ success();
+ return 0;
+}
static int test_symlink(void)
{
@@ -849,6 +958,13 @@
err += test_truncate(testdatalen / 2);
err += test_truncate(testdatalen);
err += test_truncate(testdatalen + 100);
+ err += test_ftruncate(0, 0600);
+ err += test_ftruncate(testdatalen / 2, 0600);
+ err += test_ftruncate(testdatalen, 0600);
+ err += test_ftruncate(testdatalen + 100, 0600);
+ err += test_ftruncate(0, 0400);
+ err += test_ftruncate(0, 0200);
+ err += test_ftruncate(0, 0000);
err += test_open(0, O_RDONLY, 0);
err += test_open(1, O_RDONLY, 0);
err += test_open(1, O_RDWR, 0);
@@ -872,6 +988,19 @@
err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600);
err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000);
err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000);
+ err += test_open_acc(O_RDONLY, 0600, 0);
+ err += test_open_acc(O_WRONLY, 0600, 0);
+ err += test_open_acc(O_RDWR, 0600, 0);
+ err += test_open_acc(O_RDONLY, 0400, 0);
+ err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES);
+ err += test_open_acc(O_WRONLY, 0400, EACCES);
+ err += test_open_acc(O_RDWR, 0400, EACCES);
+ err += test_open_acc(O_RDONLY, 0200, EACCES);
+ err += test_open_acc(O_WRONLY, 0200, 0);
+ err += test_open_acc(O_RDWR, 0200, EACCES);
+ err += test_open_acc(O_RDONLY, 0000, EACCES);
+ err += test_open_acc(O_WRONLY, 0000, EACCES);
+ err += test_open_acc(O_RDWR, 0000, EACCES);
unlink(testfile);
unlink(testfile2);