+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
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;
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
+ .ftruncate = xmp_ftruncate,
.utime = xmp_utime,
.open = xmp_open,
.read = xmp_read,
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);
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
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,
FUSE_SETLK = 32,
FUSE_SETLKW = 33,
FUSE_ACCESS = 34,
- FUSE_CREATE = 35
+ FUSE_CREATE = 35,
+ FUSE_FSETATTR = 36
};
/* Conservative buffer size for the client */
struct fuse_attr attr;
};
+struct fuse_fsetattr_in {
+ __u64 fh;
+ struct fuse_setattr_in setattr;
+};
+
struct fuse_open_in {
__u32 flags;
__u32 mode;
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);
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;
}
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;
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)
case FUSE_SETLKW: return "SETLKW";
case FUSE_ACCESS: return "ACCESS";
case FUSE_CREATE: return "CREATE";
+ case FUSE_FSETATTR: return "FSETATTR";
default: return "???";
}
}
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)
{
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:
return 0;
}
-
int test_truncate(int len)
{
const char *data = testdata;
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;
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)
{
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);
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);