Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * VirtualBox Guest Shared Folders support: Directory inode and file operations
0004  *
0005  * Copyright (C) 2006-2018 Oracle Corporation
0006  */
0007 
0008 #include <linux/namei.h>
0009 #include <linux/vbox_utils.h>
0010 #include "vfsmod.h"
0011 
0012 static int vboxsf_dir_open(struct inode *inode, struct file *file)
0013 {
0014     struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
0015     struct shfl_createparms params = {};
0016     struct vboxsf_dir_info *sf_d;
0017     int err;
0018 
0019     sf_d = vboxsf_dir_info_alloc();
0020     if (!sf_d)
0021         return -ENOMEM;
0022 
0023     params.handle = SHFL_HANDLE_NIL;
0024     params.create_flags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS |
0025                   SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ;
0026 
0027     err = vboxsf_create_at_dentry(file_dentry(file), &params);
0028     if (err)
0029         goto err_free_dir_info;
0030 
0031     if (params.result != SHFL_FILE_EXISTS) {
0032         err = -ENOENT;
0033         goto err_close;
0034     }
0035 
0036     err = vboxsf_dir_read_all(sbi, sf_d, params.handle);
0037     if (err)
0038         goto err_close;
0039 
0040     vboxsf_close(sbi->root, params.handle);
0041     file->private_data = sf_d;
0042     return 0;
0043 
0044 err_close:
0045     vboxsf_close(sbi->root, params.handle);
0046 err_free_dir_info:
0047     vboxsf_dir_info_free(sf_d);
0048     return err;
0049 }
0050 
0051 static int vboxsf_dir_release(struct inode *inode, struct file *file)
0052 {
0053     if (file->private_data)
0054         vboxsf_dir_info_free(file->private_data);
0055 
0056     return 0;
0057 }
0058 
0059 static unsigned int vboxsf_get_d_type(u32 mode)
0060 {
0061     unsigned int d_type;
0062 
0063     switch (mode & SHFL_TYPE_MASK) {
0064     case SHFL_TYPE_FIFO:
0065         d_type = DT_FIFO;
0066         break;
0067     case SHFL_TYPE_DEV_CHAR:
0068         d_type = DT_CHR;
0069         break;
0070     case SHFL_TYPE_DIRECTORY:
0071         d_type = DT_DIR;
0072         break;
0073     case SHFL_TYPE_DEV_BLOCK:
0074         d_type = DT_BLK;
0075         break;
0076     case SHFL_TYPE_FILE:
0077         d_type = DT_REG;
0078         break;
0079     case SHFL_TYPE_SYMLINK:
0080         d_type = DT_LNK;
0081         break;
0082     case SHFL_TYPE_SOCKET:
0083         d_type = DT_SOCK;
0084         break;
0085     case SHFL_TYPE_WHITEOUT:
0086         d_type = DT_WHT;
0087         break;
0088     default:
0089         d_type = DT_UNKNOWN;
0090         break;
0091     }
0092     return d_type;
0093 }
0094 
0095 static bool vboxsf_dir_emit(struct file *dir, struct dir_context *ctx)
0096 {
0097     struct vboxsf_sbi *sbi = VBOXSF_SBI(file_inode(dir)->i_sb);
0098     struct vboxsf_dir_info *sf_d = dir->private_data;
0099     struct shfl_dirinfo *info;
0100     struct vboxsf_dir_buf *b;
0101     unsigned int d_type;
0102     loff_t i, cur = 0;
0103     ino_t fake_ino;
0104     void *end;
0105     int err;
0106 
0107     list_for_each_entry(b, &sf_d->info_list, head) {
0108 try_next_entry:
0109         if (ctx->pos >= cur + b->entries) {
0110             cur += b->entries;
0111             continue;
0112         }
0113 
0114         /*
0115          * Note the vboxsf_dir_info objects we are iterating over here
0116          * are variable sized, so the info pointer may end up being
0117          * unaligned. This is how we get the data from the host.
0118          * Since vboxsf is only supported on x86 machines this is not
0119          * a problem.
0120          */
0121         for (i = 0, info = b->buf; i < ctx->pos - cur; i++) {
0122             end = &info->name.string.utf8[info->name.size];
0123             /* Only happens if the host gives us corrupt data */
0124             if (WARN_ON(end > (b->buf + b->used)))
0125                 return false;
0126             info = end;
0127         }
0128 
0129         end = &info->name.string.utf8[info->name.size];
0130         if (WARN_ON(end > (b->buf + b->used)))
0131             return false;
0132 
0133         /* Info now points to the right entry, emit it. */
0134         d_type = vboxsf_get_d_type(info->info.attr.mode);
0135 
0136         /*
0137          * On 32-bit systems pos is 64-bit signed, while ino is 32-bit
0138          * unsigned so fake_ino may overflow, check for this.
0139          */
0140         if ((ino_t)(ctx->pos + 1) != (u64)(ctx->pos + 1)) {
0141             vbg_err("vboxsf: fake ino overflow, truncating dir\n");
0142             return false;
0143         }
0144         fake_ino = ctx->pos + 1;
0145 
0146         if (sbi->nls) {
0147             char d_name[NAME_MAX];
0148 
0149             err = vboxsf_nlscpy(sbi, d_name, NAME_MAX,
0150                         info->name.string.utf8,
0151                         info->name.length);
0152             if (err) {
0153                 /* skip erroneous entry and proceed */
0154                 ctx->pos += 1;
0155                 goto try_next_entry;
0156             }
0157 
0158             return dir_emit(ctx, d_name, strlen(d_name),
0159                     fake_ino, d_type);
0160         }
0161 
0162         return dir_emit(ctx, info->name.string.utf8, info->name.length,
0163                 fake_ino, d_type);
0164     }
0165 
0166     return false;
0167 }
0168 
0169 static int vboxsf_dir_iterate(struct file *dir, struct dir_context *ctx)
0170 {
0171     bool emitted;
0172 
0173     do {
0174         emitted = vboxsf_dir_emit(dir, ctx);
0175         if (emitted)
0176             ctx->pos += 1;
0177     } while (emitted);
0178 
0179     return 0;
0180 }
0181 
0182 const struct file_operations vboxsf_dir_fops = {
0183     .open = vboxsf_dir_open,
0184     .iterate = vboxsf_dir_iterate,
0185     .release = vboxsf_dir_release,
0186     .read = generic_read_dir,
0187     .llseek = generic_file_llseek,
0188 };
0189 
0190 /*
0191  * This is called during name resolution/lookup to check if the @dentry in
0192  * the cache is still valid. the job is handled by vboxsf_inode_revalidate.
0193  */
0194 static int vboxsf_dentry_revalidate(struct dentry *dentry, unsigned int flags)
0195 {
0196     if (flags & LOOKUP_RCU)
0197         return -ECHILD;
0198 
0199     if (d_really_is_positive(dentry))
0200         return vboxsf_inode_revalidate(dentry) == 0;
0201     else
0202         return vboxsf_stat_dentry(dentry, NULL) == -ENOENT;
0203 }
0204 
0205 const struct dentry_operations vboxsf_dentry_ops = {
0206     .d_revalidate = vboxsf_dentry_revalidate
0207 };
0208 
0209 /* iops */
0210 
0211 static struct dentry *vboxsf_dir_lookup(struct inode *parent,
0212                     struct dentry *dentry,
0213                     unsigned int flags)
0214 {
0215     struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
0216     struct shfl_fsobjinfo fsinfo;
0217     struct inode *inode;
0218     int err;
0219 
0220     dentry->d_time = jiffies;
0221 
0222     err = vboxsf_stat_dentry(dentry, &fsinfo);
0223     if (err) {
0224         inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
0225     } else {
0226         inode = vboxsf_new_inode(parent->i_sb);
0227         if (!IS_ERR(inode))
0228             vboxsf_init_inode(sbi, inode, &fsinfo, false);
0229     }
0230 
0231     return d_splice_alias(inode, dentry);
0232 }
0233 
0234 static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry,
0235                   struct shfl_fsobjinfo *info)
0236 {
0237     struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
0238     struct vboxsf_inode *sf_i;
0239     struct inode *inode;
0240 
0241     inode = vboxsf_new_inode(parent->i_sb);
0242     if (IS_ERR(inode))
0243         return PTR_ERR(inode);
0244 
0245     sf_i = VBOXSF_I(inode);
0246     /* The host may have given us different attr then requested */
0247     sf_i->force_restat = 1;
0248     vboxsf_init_inode(sbi, inode, info, false);
0249 
0250     d_instantiate(dentry, inode);
0251 
0252     return 0;
0253 }
0254 
0255 static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry,
0256                  umode_t mode, bool is_dir, bool excl, u64 *handle_ret)
0257 {
0258     struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent);
0259     struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
0260     struct shfl_createparms params = {};
0261     int err;
0262 
0263     params.handle = SHFL_HANDLE_NIL;
0264     params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACCESS_READWRITE;
0265     if (is_dir)
0266         params.create_flags |= SHFL_CF_DIRECTORY;
0267     if (excl)
0268         params.create_flags |= SHFL_CF_ACT_FAIL_IF_EXISTS;
0269 
0270     params.info.attr.mode = (mode & 0777) |
0271                 (is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE);
0272     params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING;
0273 
0274     err = vboxsf_create_at_dentry(dentry, &params);
0275     if (err)
0276         return err;
0277 
0278     if (params.result != SHFL_FILE_CREATED)
0279         return -EPERM;
0280 
0281     err = vboxsf_dir_instantiate(parent, dentry, &params.info);
0282     if (err)
0283         goto out;
0284 
0285     /* parent directory access/change time changed */
0286     sf_parent_i->force_restat = 1;
0287 
0288 out:
0289     if (err == 0 && handle_ret)
0290         *handle_ret = params.handle;
0291     else
0292         vboxsf_close(sbi->root, params.handle);
0293 
0294     return err;
0295 }
0296 
0297 static int vboxsf_dir_mkfile(struct user_namespace *mnt_userns,
0298                  struct inode *parent, struct dentry *dentry,
0299                  umode_t mode, bool excl)
0300 {
0301     return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL);
0302 }
0303 
0304 static int vboxsf_dir_mkdir(struct user_namespace *mnt_userns,
0305                 struct inode *parent, struct dentry *dentry,
0306                 umode_t mode)
0307 {
0308     return vboxsf_dir_create(parent, dentry, mode, true, true, NULL);
0309 }
0310 
0311 static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry,
0312                   struct file *file, unsigned int flags, umode_t mode)
0313 {
0314     struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
0315     struct vboxsf_handle *sf_handle;
0316     struct dentry *res = NULL;
0317     u64 handle;
0318     int err;
0319 
0320     if (d_in_lookup(dentry)) {
0321         res = vboxsf_dir_lookup(parent, dentry, 0);
0322         if (IS_ERR(res))
0323             return PTR_ERR(res);
0324 
0325         if (res)
0326             dentry = res;
0327     }
0328 
0329     /* Only creates */
0330     if (!(flags & O_CREAT) || d_really_is_positive(dentry))
0331         return finish_no_open(file, res);
0332 
0333     err = vboxsf_dir_create(parent, dentry, mode, false, flags & O_EXCL, &handle);
0334     if (err)
0335         goto out;
0336 
0337     sf_handle = vboxsf_create_sf_handle(d_inode(dentry), handle, SHFL_CF_ACCESS_READWRITE);
0338     if (IS_ERR(sf_handle)) {
0339         vboxsf_close(sbi->root, handle);
0340         err = PTR_ERR(sf_handle);
0341         goto out;
0342     }
0343 
0344     err = finish_open(file, dentry, generic_file_open);
0345     if (err) {
0346         /* This also closes the handle passed to vboxsf_create_sf_handle() */
0347         vboxsf_release_sf_handle(d_inode(dentry), sf_handle);
0348         goto out;
0349     }
0350 
0351     file->private_data = sf_handle;
0352     file->f_mode |= FMODE_CREATED;
0353 out:
0354     dput(res);
0355     return err;
0356 }
0357 
0358 static int vboxsf_dir_unlink(struct inode *parent, struct dentry *dentry)
0359 {
0360     struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
0361     struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent);
0362     struct inode *inode = d_inode(dentry);
0363     struct shfl_string *path;
0364     u32 flags;
0365     int err;
0366 
0367     if (S_ISDIR(inode->i_mode))
0368         flags = SHFL_REMOVE_DIR;
0369     else
0370         flags = SHFL_REMOVE_FILE;
0371 
0372     if (S_ISLNK(inode->i_mode))
0373         flags |= SHFL_REMOVE_SYMLINK;
0374 
0375     path = vboxsf_path_from_dentry(sbi, dentry);
0376     if (IS_ERR(path))
0377         return PTR_ERR(path);
0378 
0379     err = vboxsf_remove(sbi->root, path, flags);
0380     __putname(path);
0381     if (err)
0382         return err;
0383 
0384     /* parent directory access/change time changed */
0385     sf_parent_i->force_restat = 1;
0386 
0387     return 0;
0388 }
0389 
0390 static int vboxsf_dir_rename(struct user_namespace *mnt_userns,
0391                  struct inode *old_parent,
0392                  struct dentry *old_dentry,
0393                  struct inode *new_parent,
0394                  struct dentry *new_dentry,
0395                  unsigned int flags)
0396 {
0397     struct vboxsf_sbi *sbi = VBOXSF_SBI(old_parent->i_sb);
0398     struct vboxsf_inode *sf_old_parent_i = VBOXSF_I(old_parent);
0399     struct vboxsf_inode *sf_new_parent_i = VBOXSF_I(new_parent);
0400     u32 shfl_flags = SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS;
0401     struct shfl_string *old_path, *new_path;
0402     int err;
0403 
0404     if (flags)
0405         return -EINVAL;
0406 
0407     old_path = vboxsf_path_from_dentry(sbi, old_dentry);
0408     if (IS_ERR(old_path))
0409         return PTR_ERR(old_path);
0410 
0411     new_path = vboxsf_path_from_dentry(sbi, new_dentry);
0412     if (IS_ERR(new_path)) {
0413         err = PTR_ERR(new_path);
0414         goto err_put_old_path;
0415     }
0416 
0417     if (d_inode(old_dentry)->i_mode & S_IFDIR)
0418         shfl_flags = 0;
0419 
0420     err = vboxsf_rename(sbi->root, old_path, new_path, shfl_flags);
0421     if (err == 0) {
0422         /* parent directories access/change time changed */
0423         sf_new_parent_i->force_restat = 1;
0424         sf_old_parent_i->force_restat = 1;
0425     }
0426 
0427     __putname(new_path);
0428 err_put_old_path:
0429     __putname(old_path);
0430     return err;
0431 }
0432 
0433 static int vboxsf_dir_symlink(struct user_namespace *mnt_userns,
0434                   struct inode *parent, struct dentry *dentry,
0435                   const char *symname)
0436 {
0437     struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent);
0438     struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb);
0439     int symname_size = strlen(symname) + 1;
0440     struct shfl_string *path, *ssymname;
0441     struct shfl_fsobjinfo info;
0442     int err;
0443 
0444     path = vboxsf_path_from_dentry(sbi, dentry);
0445     if (IS_ERR(path))
0446         return PTR_ERR(path);
0447 
0448     ssymname = kmalloc(SHFLSTRING_HEADER_SIZE + symname_size, GFP_KERNEL);
0449     if (!ssymname) {
0450         __putname(path);
0451         return -ENOMEM;
0452     }
0453     ssymname->length = symname_size - 1;
0454     ssymname->size = symname_size;
0455     memcpy(ssymname->string.utf8, symname, symname_size);
0456 
0457     err = vboxsf_symlink(sbi->root, path, ssymname, &info);
0458     kfree(ssymname);
0459     __putname(path);
0460     if (err) {
0461         /* -EROFS means symlinks are note support -> -EPERM */
0462         return (err == -EROFS) ? -EPERM : err;
0463     }
0464 
0465     err = vboxsf_dir_instantiate(parent, dentry, &info);
0466     if (err)
0467         return err;
0468 
0469     /* parent directory access/change time changed */
0470     sf_parent_i->force_restat = 1;
0471     return 0;
0472 }
0473 
0474 const struct inode_operations vboxsf_dir_iops = {
0475     .lookup  = vboxsf_dir_lookup,
0476     .create  = vboxsf_dir_mkfile,
0477     .mkdir   = vboxsf_dir_mkdir,
0478     .atomic_open = vboxsf_dir_atomic_open,
0479     .rmdir   = vboxsf_dir_unlink,
0480     .unlink  = vboxsf_dir_unlink,
0481     .rename  = vboxsf_dir_rename,
0482     .symlink = vboxsf_dir_symlink,
0483     .getattr = vboxsf_getattr,
0484     .setattr = vboxsf_setattr,
0485 };