int ovl_removexattr(struct dentry *dentry, const char *name) { int err; struct path realpath; enum ovl_path_type type; err = ovl_want_write(dentry); if (err) goto out; if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && ovl_is_private_xattr(name)) goto out_drop_write; type = ovl_path_real(dentry, &realpath); if (type == OVL_PATH_LOWER) { err = vfs_getxattr(realpath.dentry, name, NULL, 0); if (err < 0) goto out_drop_write; err = ovl_copy_up(dentry); if (err) goto out_drop_write; ovl_path_upper(dentry, &realpath); } err = vfs_removexattr(realpath.dentry, name); out_drop_write: ovl_drop_write(dentry); out: return err; }
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 struct dentry *ovl_check_empty_and_clear(struct dentry *dentry) { int err; struct dentry *ret = NULL; enum ovl_path_type type = ovl_path_type(dentry); LIST_HEAD(list); err = ovl_check_empty_dir(dentry, &list); if (err) { ret = ERR_PTR(err); goto out_free; } /* * When removing an empty opaque directory, then it makes no sense to * replace it with an exact replica of itself. * * If no upperdentry then skip clearing whiteouts. * * Can race with copy-up, since we don't hold the upperdir mutex. * Doesn't matter, since copy-up can't create a non-empty directory * from an empty one. */ if (OVL_TYPE_UPPER(type) && OVL_TYPE_MERGE(type)) ret = ovl_clear_empty(dentry, &list); out_free: ovl_cache_free(&list); return ret; }
int ovl_removexattr(struct dentry *dentry, const char *name) { int err; struct path realpath; enum ovl_path_type type; if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && ovl_is_private_xattr(name)) return -ENODATA; type = ovl_path_real(dentry, &realpath); if (type == OVL_PATH_LOWER) { err = vfs_getxattr(realpath.dentry, name, NULL, 0); if (err < 0) return err; err = ovl_copy_up(dentry); if (err) return err; ovl_path_upper(dentry, &realpath); } return vfs_removexattr(realpath.dentry, name); }
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); }
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) { enum ovl_path_type type = ovl_path_type(dentry); if (!OVL_TYPE_UPPER(type)) ovl_path_lower(dentry, path); else ovl_path_upper(dentry, path); return type; }
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) { enum ovl_path_type type = ovl_path_type(dentry); if (type == OVL_PATH_LOWER) ovl_path_lower(dentry, path); else ovl_path_upper(dentry, path); return type; }
static bool ovl_type_origin(struct dentry *dentry) { return OVL_TYPE_ORIGIN(ovl_path_type(dentry)); }
static bool ovl_type_merge(struct dentry *dentry) { return OVL_TYPE_MERGE(ovl_path_type(dentry)); }