static int fuse_atomic_open(struct inode *dir, struct dentry *entry, struct file *file, unsigned flags, umode_t mode, int *opened) { int err; struct fuse_conn *fc = get_fuse_conn(dir); struct dentry *res = NULL; if (d_unhashed(entry)) { res = fuse_lookup(dir, entry, 0); if (IS_ERR(res)) return PTR_ERR(res); if (res) entry = res; } if (!(flags & O_CREAT) || entry->d_inode) goto no_open; /* Only creates */ *opened |= FILE_CREATED; if (fc->no_create) goto mknod; err = fuse_create_open(dir, entry, file, flags, mode, opened); if (err == -ENOSYS) { fc->no_create = 1; goto mknod; } out_dput: dput(res); return err; mknod: err = fuse_mknod(dir, entry, mode, 0); if (err) goto out_dput; no_open: return finish_no_open(file, res); }
/* * Set attributes, and at the same time refresh them. * * Truncation is slightly complicated, because the 'truncate' request * may fail, in which case we don't want to touch the mapping. * vmtruncate() doesn't allow for this case. So do the rlimit * checking by hand and call vmtruncate() only after the file has * actually been truncated. */ static int fuse_setattr(struct dentry *entry, struct iattr *attr) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_req *req; struct fuse_setattr_in inarg; struct fuse_attr_out outarg; int err; int is_truncate = 0; if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { err = inode_change_ok(inode, attr); if (err) return err; } if (attr->ia_valid & ATTR_SIZE) { unsigned long limit; is_truncate = 1; #ifdef KERNEL_2_6_10_PLUS limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; #else limit = current->rlim[RLIMIT_FSIZE].rlim_cur; #endif if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { send_sig(SIGXFSZ, current, 0); return -EFBIG; } } req = fuse_get_request(fc); if (!req) return -EINTR; memset(&inarg, 0, sizeof(inarg)); iattr_to_fattr(attr, &inarg); req->in.h.opcode = FUSE_SETATTR; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->in.numargs = 1; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; req->out.numargs = 1; req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); if (!err) { if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { #ifndef KERNEL_2_6_12_PLUS if (get_node_id(inode) != FUSE_ROOT_ID) make_bad_inode(inode); #else make_bad_inode(inode); #endif err = -EIO; } else { if (is_truncate) { loff_t origsize = i_size_read(inode); i_size_write(inode, outarg.attr.size); if (origsize > outarg.attr.size) vmtruncate(inode, outarg.attr.size); } fuse_change_attributes(inode, &outarg.attr); fi->i_time = time_to_jiffies(outarg.attr_valid, outarg.attr_valid_nsec); } } else if (err == -EINTR) fuse_invalidate_attr(inode); return err; } #ifdef KERNEL_2_6 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat) { struct inode *inode = entry->d_inode; int err = fuse_revalidate(entry); if (!err) generic_fillattr(inode, stat); return err; } #else /* KERNEL_2_6 */ static struct dentry *fuse_lookup_2_4(struct inode *dir, struct dentry *entry) { return fuse_lookup(dir, entry, NULL); }