diff options
Diffstat (limited to 'fs/ubifs/dir.c')
-rw-r--r-- | fs/ubifs/dir.c | 298 |
1 files changed, 255 insertions, 43 deletions
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 8c230da8f3..a16546e615 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -42,15 +42,26 @@ #include "ubifs.h" +/* + * removed in barebox +static int inherit_flags(const struct inode *dir, umode_t mode) + */ + +/* + * removed in barebox +struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, + umode_t mode) + */ + static int dbg_check_name(const struct ubifs_info *c, const struct ubifs_dent_node *dent, - const struct qstr *nm) + const struct fscrypt_name *nm) { if (!dbg_is_chk_gen(c)) return 0; - if (le16_to_cpu(dent->nlen) != nm->len) + if (le16_to_cpu(dent->nlen) != fname_len(nm)) return -EINVAL; - if (memcmp(dent->name, nm->name, nm->len)) + if (memcmp(dent->name, fname_name(nm), fname_len(nm))) return -EINVAL; return 0; } @@ -61,32 +72,52 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, int err; union ubifs_key key; struct inode *inode = NULL; - struct ubifs_dent_node *dent; + struct ubifs_dent_node *dent = NULL; struct ubifs_info *c = dir->i_sb->s_fs_info; + struct fscrypt_name nm; dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); - if (dentry->d_name.len > UBIFS_MAX_NLEN) - return ERR_PTR(-ENAMETOOLONG); + err = fscrypt_prepare_lookup(dir, dentry, flags); + if (err) + return ERR_PTR(err); + + err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); + if (err) + return ERR_PTR(err); + + if (fname_len(&nm) > UBIFS_MAX_NLEN) { + inode = ERR_PTR(-ENAMETOOLONG); + goto done; + } dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); - if (!dent) - return ERR_PTR(-ENOMEM); + if (!dent) { + inode = ERR_PTR(-ENOMEM); + goto done; + } - dent_key_init(c, &key, dir->i_ino, &dentry->d_name); + if (nm.hash) { + ubifs_assert(c, fname_len(&nm) == 0); + ubifs_assert(c, fname_name(&nm) == NULL); + dent_key_init_hash(c, &key, dir->i_ino, nm.hash); + err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash); + } else { + dent_key_init(c, &key, dir->i_ino, &nm); + err = ubifs_tnc_lookup_nm(c, &key, dent, &nm); + } - err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name); if (err) { - if (err == -ENOENT) { + if (err == -ENOENT) dbg_gen("not found"); - goto done; - } - goto out; + else + inode = ERR_PTR(err); + goto done; } - if (dbg_check_name(c, dent, &dentry->d_name)) { - err = -EINVAL; - goto out; + if (dbg_check_name(c, dent, &nm)) { + inode = ERR_PTR(-EINVAL); + goto done; } inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); @@ -97,25 +128,45 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, */ err = PTR_ERR(inode); ubifs_err(c, "dead directory entry '%pd', error %d", - dentry, err); + dentry, err); ubifs_ro_mode(c, err); - goto out; + goto done; + } + + if (ubifs_crypt_is_encrypted(dir) && + (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && + !fscrypt_has_permitted_context(dir, inode)) { + ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu", + dir->i_ino, inode->i_ino); + iput(inode); + inode = ERR_PTR(-EPERM); } done: kfree(dent); - /* - * Note, d_splice_alias() would be required instead if we supported - * NFS. - */ + fscrypt_free_filename(&nm); d_add(dentry, inode); return NULL; - -out: - kfree(dent); - return ERR_PTR(err); } +/* + * removed in barebox +static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) + */ + +/* + * removed in barebox +static int do_tmpfile(struct inode *dir, struct dentry *dentry, + umode_t mode, struct inode **whiteout) + */ + +/* + * removed in barebox +static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry, + umode_t mode) + */ + /** * vfs_dent_type - get VFS directory entry type. * @type: UBIFS directory entry type @@ -165,13 +216,14 @@ static unsigned int vfs_dent_type(uint8_t type) */ static int ubifs_readdir(struct file *file, struct dir_context *ctx) { - int err = 0; - struct qstr nm; + int fstr_real_len = 0, err = 0; + struct fscrypt_name nm; + struct fscrypt_str fstr = {0}; union ubifs_key key; struct ubifs_dent_node *dent; - struct dentry *dentry = file->f_path.dentry; - struct inode *dir = d_inode(dentry); + struct inode *dir = file_inode(file); struct ubifs_info *c = dir->i_sb->s_fs_info; + bool encrypted = ubifs_crypt_is_encrypted(dir); dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos); @@ -182,6 +234,18 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) */ return 0; + if (encrypted) { + err = fscrypt_get_encryption_info(dir); + if (err && err != -ENOKEY) + return err; + + err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr); + if (err) + return err; + + fstr_real_len = fstr.len; + } + if (file->f_version == 0) { /* * The file was seek'ed, which means that @file->private_data @@ -202,12 +266,16 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) /* File positions 0 and 1 correspond to "." and ".." */ if (ctx->pos < 2) { - ubifs_assert(!file->private_data); - dir_emit_dots(file, ctx); + ubifs_assert(c, !file->private_data); + if (!dir_emit_dots(file, ctx)) { + if (encrypted) + fscrypt_fname_free_buffer(&fstr); + return 0; + } /* Find the first entry in TNC and save it */ lowest_dent_key(c, &key, dir->i_ino); - nm.name = NULL; + fname_len(&nm) = 0; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); @@ -225,7 +293,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) * Find the entry corresponding to @ctx->pos or the closest one. */ dent_key_init_hash(c, &key, dir->i_ino, ctx->pos); - nm.name = NULL; + fname_len(&nm) = 0; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); @@ -236,20 +304,39 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) } while (1) { - dbg_gen("feed '%s', ino %llu, new f_pos %#x", - dent->name, (unsigned long long)le64_to_cpu(dent->inum), + dbg_gen("ino %llu, new f_pos %#x", + (unsigned long long)le64_to_cpu(dent->inum), key_hash_flash(c, &dent->key)); - ubifs_assert(le64_to_cpu(dent->ch.sqnum) > + ubifs_assert(c, le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); - nm.len = le16_to_cpu(dent->nlen); - dir_emit(ctx, dent->name, nm.len, + fname_len(&nm) = le16_to_cpu(dent->nlen); + fname_name(&nm) = dent->name; + + if (encrypted) { + fstr.len = fstr_real_len; + + err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, + &dent->key), + le32_to_cpu(dent->cookie), + &nm.disk_name, &fstr); + if (err) + goto out; + } else { + fstr.len = fname_len(&nm); + fstr.name = fname_name(&nm); + } + + if (!dir_emit(ctx, fstr.name, fstr.len, le64_to_cpu(dent->inum), - vfs_dent_type(dent->type)); + vfs_dent_type(dent->type))) { + if (encrypted) + fscrypt_fname_free_buffer(&fstr); + return 0; + } /* Switch to the next entry */ key_read(c, &dent->key, &key); - nm.name = dent->name; dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); @@ -266,6 +353,9 @@ out: kfree(file->private_data); file->private_data = NULL; + if (encrypted) + fscrypt_fname_free_buffer(&fstr); + if (err != -ENOENT) ubifs_err(c, "cannot find next direntry, error %d", err); else @@ -282,10 +372,132 @@ out: return err; } +/* + * removed in barebox +static int ubifs_dir_release(struct inode *dir, struct file *file) + */ + +/* + * removed in barebox +static void lock_2_inodes(struct inode *inode1, struct inode *inode2) + */ + +/* + * removed in barebox +static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) + */ + +/* + * removed in barebox +static int ubifs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) + */ + +/* + * removed in barebox +static int ubifs_unlink(struct inode *dir, struct dentry *dentry) + */ + +/* + * removed in barebox +int ubifs_check_dir_empty(struct inode *dir) + */ + +/* + * removed in barebox +static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) + */ + +/* + * removed in barebox +static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + */ + +/* + * removed in barebox +static int ubifs_mknod(struct inode *dir, struct dentry *dentry, + umode_t mode, dev_t rdev) + */ + +/* + * removed in barebox +static int ubifs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) + */ + +/* + * removed in barebox +static void lock_4_inodes(struct inode *inode1, struct inode *inode2, + struct inode *inode3, struct inode *inode4) + */ + +/* + * removed in barebox +static void unlock_4_inodes(struct inode *inode1, struct inode *inode2, + struct inode *inode3, struct inode *inode4) + */ + +/* + * removed in barebox +static int do_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) + */ + +/* + * removed in barebox +static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) + */ + +/* + * removed in barebox +static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) + */ + +/* + * removed in barebox +int ubifs_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags) + */ + +/* + * removed in barebox +static int ubifs_dir_open(struct inode *dir, struct file *file) + */ + const struct inode_operations ubifs_dir_inode_operations = { .lookup = ubifs_lookup, + .create = NULL, /* not present in barebox */ + .link = NULL, /* not present in barebox */ + .symlink = NULL, /* not present in barebox */ + .unlink = NULL, /* not present in barebox */ + .mkdir = NULL, /* not present in barebox */ + .rmdir = NULL, /* not present in barebox */ +/* .mknod = NULL, not present in barebox */ + .rename = NULL, /* not present in barebox */ +/* .setattr = NULL, not present in barebox */ +/* .getattr = NULL, not present in barebox */ +#ifdef CONFIG_UBIFS_FS_XATTR + .listxattr = NULL, /* not present in barebox */ +#endif +#ifdef CONFIG_UBIFS_ATIME_SUPPORT + .update_time = NULL, /* not present in barebox */ +#endif +/* .tmpfile = NULL, not present in barebox */ }; const struct file_operations ubifs_dir_operations = { - .iterate = ubifs_readdir, +/* .llseek = NULL, not present in barebox */ +/* .release = NULL, not present in barebox */ + .read = NULL, /* not present in barebox */ + .iterate = ubifs_readdir, +/* .fsync = NULL, not present in barebox */ +/* .unlocked_ioctl = NULL, not present in barebox */ +/* .open = NULL, not present in barebox */ +#ifdef CONFIG_COMPAT + .compat_ioctl = NULL, /* not present in barebox */ +#endif }; |