ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) { ssize_t res; int off; res = vfs_listxattr(ovl_dentry_real(dentry), list, size); if (res <= 0 || size == 0) return res; if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE) return res; /* filter out private xattrs */ for (off = 0; off < res;) { char *s = list + off; size_t slen = strlen(s) + 1; BUG_ON(off + slen > res); if (ovl_is_private_xattr(s)) { res -= slen; memmove(s, s + slen, res - off); } else { off += slen; } } return res; }
static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd) { void *ret; struct dentry *realdentry; struct inode *realinode; realdentry = ovl_dentry_real(dentry); realinode = realdentry->d_inode; if (WARN_ON(!realinode->i_op->follow_link)) return ERR_PTR(-EPERM); ret = realinode->i_op->follow_link(realdentry, nd); if (IS_ERR(ret)) return ret; if (realinode->i_op->put_link) { struct ovl_link_data *data; data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL); if (!data) { realinode->i_op->put_link(realdentry, nd, ret); return ERR_PTR(-ENOMEM); } data->realdentry = realdentry; data->cookie = ret; return data; } else { return NULL; } }
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) { struct dentry *realdentry = ovl_dentry_real(dentry); ssize_t res; size_t len; char *s; const struct cred *old_cred; old_cred = ovl_override_creds(dentry->d_sb); res = vfs_listxattr(realdentry, list, size); revert_creds(old_cred); if (res <= 0 || size == 0) return res; /* filter out private xattrs */ for (s = list, len = res; len;) { size_t slen = strnlen(s, len) + 1; /* underlying fs providing us with an broken xattr list? */ if (WARN_ON(slen > len)) return -EIO; len -= slen; if (!ovl_can_list(s)) { res -= slen; memmove(s, s + slen, len); } else { s += slen; } } return res; }
static const char *ovl_follow_link(struct dentry *dentry, void **cookie) { struct dentry *realdentry; struct inode *realinode; struct ovl_link_data *data = NULL; const char *ret; realdentry = ovl_dentry_real(dentry); realinode = realdentry->d_inode; if (WARN_ON(!realinode->i_op->follow_link)) return ERR_PTR(-EPERM); if (realinode->i_op->put_link) { data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL); if (!data) return ERR_PTR(-ENOMEM); data->realdentry = realdentry; } ret = realinode->i_op->follow_link(realdentry, cookie); if (IS_ERR_OR_NULL(ret)) { kfree(data); return ret; } if (data) data->cookie = *cookie; *cookie = data; return ret; }
ssize_t ovl_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && ovl_is_private_xattr(name)) return -ENODATA; return vfs_getxattr(ovl_dentry_real(dentry), name, value, size); }
int ovl_setattr(struct dentry *dentry, struct iattr *attr) { int err; struct dentry *upperdentry; /* * Check for permissions before trying to copy-up. This is redundant * since it will be rechecked later by ->setattr() on upper dentry. But * without this, copy-up can be triggered by just about anybody. * * We don't initialize inode->size, which just means that * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not * check for a swapfile (which this won't be anyway). */ err = inode_change_ok(dentry->d_inode, attr); if (err) return err; err = ovl_want_write(dentry); if (err) goto out; if (attr->ia_valid & ATTR_SIZE) { struct inode *realinode = d_inode(ovl_dentry_real(dentry)); err = -ETXTBSY; if (atomic_read(&realinode->i_writecount) < 0) goto out_drop_write; } err = ovl_copy_up(dentry); if (!err) { struct inode *winode = NULL; upperdentry = ovl_dentry_upper(dentry); if (attr->ia_valid & ATTR_SIZE) { winode = d_inode(upperdentry); err = get_write_access(winode); if (err) goto out_drop_write; } inode_lock(upperdentry->d_inode); err = notify_change(upperdentry, attr, NULL); if (!err) ovl_copyattr(upperdentry->d_inode, dentry->d_inode); inode_unlock(upperdentry->d_inode); if (winode) put_write_access(winode); } out_drop_write: ovl_drop_write(dentry); out: return err; }
ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size) { struct dentry *realdentry = ovl_dentry_real(dentry); if (ovl_is_private_xattr(name)) return -ENODATA; return vfs_getxattr(realdentry, name, value, size); }
int ovl_xattr_get(struct dentry *dentry, const char *name, void *value, size_t size) { struct dentry *realdentry = ovl_dentry_real(dentry); ssize_t res; const struct cred *old_cred; old_cred = ovl_override_creds(dentry->d_sb); res = vfs_getxattr(realdentry, name, value, size); revert_creds(old_cred); return res; }
static const char *ovl_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { const struct cred *old_cred; const char *p; if (!dentry) return ERR_PTR(-ECHILD); old_cred = ovl_override_creds(dentry->d_sb); p = vfs_get_link(ovl_dentry_real(dentry), done); revert_creds(old_cred); return p; }
static const char *ovl_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { struct dentry *realdentry; struct inode *realinode; if (!dentry) return ERR_PTR(-ECHILD); realdentry = ovl_dentry_real(dentry); realinode = realdentry->d_inode; if (WARN_ON(!realinode->i_op->get_link)) return ERR_PTR(-EPERM); return realinode->i_op->get_link(realdentry, realinode, done); }