18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VirtualBox Guest Shared Folders support: Directory inode and file operations 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2018 Oracle Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/namei.h> 98c2ecf20Sopenharmony_ci#include <linux/vbox_utils.h> 108c2ecf20Sopenharmony_ci#include "vfsmod.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic int vboxsf_dir_open(struct inode *inode, struct file *file) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); 158c2ecf20Sopenharmony_ci struct shfl_createparms params = {}; 168c2ecf20Sopenharmony_ci struct vboxsf_dir_info *sf_d; 178c2ecf20Sopenharmony_ci int err; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci sf_d = vboxsf_dir_info_alloc(); 208c2ecf20Sopenharmony_ci if (!sf_d) 218c2ecf20Sopenharmony_ci return -ENOMEM; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci params.handle = SHFL_HANDLE_NIL; 248c2ecf20Sopenharmony_ci params.create_flags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | 258c2ecf20Sopenharmony_ci SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); 288c2ecf20Sopenharmony_ci if (err) 298c2ecf20Sopenharmony_ci goto err_free_dir_info; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (params.result != SHFL_FILE_EXISTS) { 328c2ecf20Sopenharmony_ci err = -ENOENT; 338c2ecf20Sopenharmony_ci goto err_close; 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci err = vboxsf_dir_read_all(sbi, sf_d, params.handle); 378c2ecf20Sopenharmony_ci if (err) 388c2ecf20Sopenharmony_ci goto err_close; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 418c2ecf20Sopenharmony_ci file->private_data = sf_d; 428c2ecf20Sopenharmony_ci return 0; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cierr_close: 458c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 468c2ecf20Sopenharmony_cierr_free_dir_info: 478c2ecf20Sopenharmony_ci vboxsf_dir_info_free(sf_d); 488c2ecf20Sopenharmony_ci return err; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int vboxsf_dir_release(struct inode *inode, struct file *file) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci if (file->private_data) 548c2ecf20Sopenharmony_ci vboxsf_dir_info_free(file->private_data); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic unsigned int vboxsf_get_d_type(u32 mode) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci unsigned int d_type; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci switch (mode & SHFL_TYPE_MASK) { 648c2ecf20Sopenharmony_ci case SHFL_TYPE_FIFO: 658c2ecf20Sopenharmony_ci d_type = DT_FIFO; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci case SHFL_TYPE_DEV_CHAR: 688c2ecf20Sopenharmony_ci d_type = DT_CHR; 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci case SHFL_TYPE_DIRECTORY: 718c2ecf20Sopenharmony_ci d_type = DT_DIR; 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci case SHFL_TYPE_DEV_BLOCK: 748c2ecf20Sopenharmony_ci d_type = DT_BLK; 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case SHFL_TYPE_FILE: 778c2ecf20Sopenharmony_ci d_type = DT_REG; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci case SHFL_TYPE_SYMLINK: 808c2ecf20Sopenharmony_ci d_type = DT_LNK; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci case SHFL_TYPE_SOCKET: 838c2ecf20Sopenharmony_ci d_type = DT_SOCK; 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case SHFL_TYPE_WHITEOUT: 868c2ecf20Sopenharmony_ci d_type = DT_WHT; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci d_type = DT_UNKNOWN; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci return d_type; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic bool vboxsf_dir_emit(struct file *dir, struct dir_context *ctx) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(file_inode(dir)->i_sb); 988c2ecf20Sopenharmony_ci struct vboxsf_dir_info *sf_d = dir->private_data; 998c2ecf20Sopenharmony_ci struct shfl_dirinfo *info; 1008c2ecf20Sopenharmony_ci struct vboxsf_dir_buf *b; 1018c2ecf20Sopenharmony_ci unsigned int d_type; 1028c2ecf20Sopenharmony_ci loff_t i, cur = 0; 1038c2ecf20Sopenharmony_ci ino_t fake_ino; 1048c2ecf20Sopenharmony_ci void *end; 1058c2ecf20Sopenharmony_ci int err; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci list_for_each_entry(b, &sf_d->info_list, head) { 1088c2ecf20Sopenharmony_citry_next_entry: 1098c2ecf20Sopenharmony_ci if (ctx->pos >= cur + b->entries) { 1108c2ecf20Sopenharmony_ci cur += b->entries; 1118c2ecf20Sopenharmony_ci continue; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* 1158c2ecf20Sopenharmony_ci * Note the vboxsf_dir_info objects we are iterating over here 1168c2ecf20Sopenharmony_ci * are variable sized, so the info pointer may end up being 1178c2ecf20Sopenharmony_ci * unaligned. This is how we get the data from the host. 1188c2ecf20Sopenharmony_ci * Since vboxsf is only supported on x86 machines this is not 1198c2ecf20Sopenharmony_ci * a problem. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci for (i = 0, info = b->buf; i < ctx->pos - cur; i++) { 1228c2ecf20Sopenharmony_ci end = &info->name.string.utf8[info->name.size]; 1238c2ecf20Sopenharmony_ci /* Only happens if the host gives us corrupt data */ 1248c2ecf20Sopenharmony_ci if (WARN_ON(end > (b->buf + b->used))) 1258c2ecf20Sopenharmony_ci return false; 1268c2ecf20Sopenharmony_ci info = end; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci end = &info->name.string.utf8[info->name.size]; 1308c2ecf20Sopenharmony_ci if (WARN_ON(end > (b->buf + b->used))) 1318c2ecf20Sopenharmony_ci return false; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Info now points to the right entry, emit it. */ 1348c2ecf20Sopenharmony_ci d_type = vboxsf_get_d_type(info->info.attr.mode); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * On 32-bit systems pos is 64-bit signed, while ino is 32-bit 1388c2ecf20Sopenharmony_ci * unsigned so fake_ino may overflow, check for this. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci if ((ino_t)(ctx->pos + 1) != (u64)(ctx->pos + 1)) { 1418c2ecf20Sopenharmony_ci vbg_err("vboxsf: fake ino overflow, truncating dir\n"); 1428c2ecf20Sopenharmony_ci return false; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci fake_ino = ctx->pos + 1; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (sbi->nls) { 1478c2ecf20Sopenharmony_ci char d_name[NAME_MAX]; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci err = vboxsf_nlscpy(sbi, d_name, NAME_MAX, 1508c2ecf20Sopenharmony_ci info->name.string.utf8, 1518c2ecf20Sopenharmony_ci info->name.length); 1528c2ecf20Sopenharmony_ci if (err) { 1538c2ecf20Sopenharmony_ci /* skip erroneous entry and proceed */ 1548c2ecf20Sopenharmony_ci ctx->pos += 1; 1558c2ecf20Sopenharmony_ci goto try_next_entry; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return dir_emit(ctx, d_name, strlen(d_name), 1598c2ecf20Sopenharmony_ci fake_ino, d_type); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return dir_emit(ctx, info->name.string.utf8, info->name.length, 1638c2ecf20Sopenharmony_ci fake_ino, d_type); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return false; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int vboxsf_dir_iterate(struct file *dir, struct dir_context *ctx) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci bool emitted; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci do { 1748c2ecf20Sopenharmony_ci emitted = vboxsf_dir_emit(dir, ctx); 1758c2ecf20Sopenharmony_ci if (emitted) 1768c2ecf20Sopenharmony_ci ctx->pos += 1; 1778c2ecf20Sopenharmony_ci } while (emitted); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciconst struct file_operations vboxsf_dir_fops = { 1838c2ecf20Sopenharmony_ci .open = vboxsf_dir_open, 1848c2ecf20Sopenharmony_ci .iterate = vboxsf_dir_iterate, 1858c2ecf20Sopenharmony_ci .release = vboxsf_dir_release, 1868c2ecf20Sopenharmony_ci .read = generic_read_dir, 1878c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * This is called during name resolution/lookup to check if the @dentry in 1928c2ecf20Sopenharmony_ci * the cache is still valid. the job is handled by vboxsf_inode_revalidate. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_cistatic int vboxsf_dentry_revalidate(struct dentry *dentry, unsigned int flags) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci if (flags & LOOKUP_RCU) 1978c2ecf20Sopenharmony_ci return -ECHILD; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (d_really_is_positive(dentry)) 2008c2ecf20Sopenharmony_ci return vboxsf_inode_revalidate(dentry) == 0; 2018c2ecf20Sopenharmony_ci else 2028c2ecf20Sopenharmony_ci return vboxsf_stat_dentry(dentry, NULL) == -ENOENT; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciconst struct dentry_operations vboxsf_dentry_ops = { 2068c2ecf20Sopenharmony_ci .d_revalidate = vboxsf_dentry_revalidate 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* iops */ 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic struct dentry *vboxsf_dir_lookup(struct inode *parent, 2128c2ecf20Sopenharmony_ci struct dentry *dentry, 2138c2ecf20Sopenharmony_ci unsigned int flags) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 2168c2ecf20Sopenharmony_ci struct shfl_fsobjinfo fsinfo; 2178c2ecf20Sopenharmony_ci struct inode *inode; 2188c2ecf20Sopenharmony_ci int err; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci dentry->d_time = jiffies; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci err = vboxsf_stat_dentry(dentry, &fsinfo); 2238c2ecf20Sopenharmony_ci if (err) { 2248c2ecf20Sopenharmony_ci inode = (err == -ENOENT) ? NULL : ERR_PTR(err); 2258c2ecf20Sopenharmony_ci } else { 2268c2ecf20Sopenharmony_ci inode = vboxsf_new_inode(parent->i_sb); 2278c2ecf20Sopenharmony_ci if (!IS_ERR(inode)) 2288c2ecf20Sopenharmony_ci vboxsf_init_inode(sbi, inode, &fsinfo); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry, 2358c2ecf20Sopenharmony_ci struct shfl_fsobjinfo *info) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 2388c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_i; 2398c2ecf20Sopenharmony_ci struct inode *inode; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci inode = vboxsf_new_inode(parent->i_sb); 2428c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 2438c2ecf20Sopenharmony_ci return PTR_ERR(inode); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci sf_i = VBOXSF_I(inode); 2468c2ecf20Sopenharmony_ci /* The host may have given us different attr then requested */ 2478c2ecf20Sopenharmony_ci sf_i->force_restat = 1; 2488c2ecf20Sopenharmony_ci vboxsf_init_inode(sbi, inode, info); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int vboxsf_dir_create(struct inode *parent, struct dentry *dentry, 2568c2ecf20Sopenharmony_ci umode_t mode, bool is_dir, bool excl, u64 *handle_ret) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); 2598c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 2608c2ecf20Sopenharmony_ci struct shfl_createparms params = {}; 2618c2ecf20Sopenharmony_ci int err; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci params.handle = SHFL_HANDLE_NIL; 2648c2ecf20Sopenharmony_ci params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACCESS_READWRITE; 2658c2ecf20Sopenharmony_ci if (is_dir) 2668c2ecf20Sopenharmony_ci params.create_flags |= SHFL_CF_DIRECTORY; 2678c2ecf20Sopenharmony_ci if (excl) 2688c2ecf20Sopenharmony_ci params.create_flags |= SHFL_CF_ACT_FAIL_IF_EXISTS; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci params.info.attr.mode = (mode & 0777) | 2718c2ecf20Sopenharmony_ci (is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE); 2728c2ecf20Sopenharmony_ci params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci err = vboxsf_create_at_dentry(dentry, ¶ms); 2758c2ecf20Sopenharmony_ci if (err) 2768c2ecf20Sopenharmony_ci return err; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (params.result != SHFL_FILE_CREATED) 2798c2ecf20Sopenharmony_ci return -EPERM; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci err = vboxsf_dir_instantiate(parent, dentry, ¶ms.info); 2828c2ecf20Sopenharmony_ci if (err) 2838c2ecf20Sopenharmony_ci goto out; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* parent directory access/change time changed */ 2868c2ecf20Sopenharmony_ci sf_parent_i->force_restat = 1; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciout: 2898c2ecf20Sopenharmony_ci if (err == 0 && handle_ret) 2908c2ecf20Sopenharmony_ci *handle_ret = params.handle; 2918c2ecf20Sopenharmony_ci else 2928c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return err; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int vboxsf_dir_mkfile(struct inode *parent, struct dentry *dentry, 2988c2ecf20Sopenharmony_ci umode_t mode, bool excl) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int vboxsf_dir_mkdir(struct inode *parent, struct dentry *dentry, 3048c2ecf20Sopenharmony_ci umode_t mode) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci return vboxsf_dir_create(parent, dentry, mode, true, true, NULL); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry, 3108c2ecf20Sopenharmony_ci struct file *file, unsigned int flags, umode_t mode) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 3138c2ecf20Sopenharmony_ci struct vboxsf_handle *sf_handle; 3148c2ecf20Sopenharmony_ci struct dentry *res = NULL; 3158c2ecf20Sopenharmony_ci u64 handle; 3168c2ecf20Sopenharmony_ci int err; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (d_in_lookup(dentry)) { 3198c2ecf20Sopenharmony_ci res = vboxsf_dir_lookup(parent, dentry, 0); 3208c2ecf20Sopenharmony_ci if (IS_ERR(res)) 3218c2ecf20Sopenharmony_ci return PTR_ERR(res); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (res) 3248c2ecf20Sopenharmony_ci dentry = res; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Only creates */ 3288c2ecf20Sopenharmony_ci if (!(flags & O_CREAT) || d_really_is_positive(dentry)) 3298c2ecf20Sopenharmony_ci return finish_no_open(file, res); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = vboxsf_dir_create(parent, dentry, mode, false, flags & O_EXCL, &handle); 3328c2ecf20Sopenharmony_ci if (err) 3338c2ecf20Sopenharmony_ci goto out; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci sf_handle = vboxsf_create_sf_handle(d_inode(dentry), handle, SHFL_CF_ACCESS_READWRITE); 3368c2ecf20Sopenharmony_ci if (IS_ERR(sf_handle)) { 3378c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, handle); 3388c2ecf20Sopenharmony_ci err = PTR_ERR(sf_handle); 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci err = finish_open(file, dentry, generic_file_open); 3438c2ecf20Sopenharmony_ci if (err) { 3448c2ecf20Sopenharmony_ci /* This also closes the handle passed to vboxsf_create_sf_handle() */ 3458c2ecf20Sopenharmony_ci vboxsf_release_sf_handle(d_inode(dentry), sf_handle); 3468c2ecf20Sopenharmony_ci goto out; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci file->private_data = sf_handle; 3508c2ecf20Sopenharmony_ci file->f_mode |= FMODE_CREATED; 3518c2ecf20Sopenharmony_ciout: 3528c2ecf20Sopenharmony_ci dput(res); 3538c2ecf20Sopenharmony_ci return err; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int vboxsf_dir_unlink(struct inode *parent, struct dentry *dentry) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 3598c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); 3608c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 3618c2ecf20Sopenharmony_ci struct shfl_string *path; 3628c2ecf20Sopenharmony_ci u32 flags; 3638c2ecf20Sopenharmony_ci int err; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 3668c2ecf20Sopenharmony_ci flags = SHFL_REMOVE_DIR; 3678c2ecf20Sopenharmony_ci else 3688c2ecf20Sopenharmony_ci flags = SHFL_REMOVE_FILE; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 3718c2ecf20Sopenharmony_ci flags |= SHFL_REMOVE_SYMLINK; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci path = vboxsf_path_from_dentry(sbi, dentry); 3748c2ecf20Sopenharmony_ci if (IS_ERR(path)) 3758c2ecf20Sopenharmony_ci return PTR_ERR(path); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci err = vboxsf_remove(sbi->root, path, flags); 3788c2ecf20Sopenharmony_ci __putname(path); 3798c2ecf20Sopenharmony_ci if (err) 3808c2ecf20Sopenharmony_ci return err; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* parent directory access/change time changed */ 3838c2ecf20Sopenharmony_ci sf_parent_i->force_restat = 1; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int vboxsf_dir_rename(struct inode *old_parent, 3898c2ecf20Sopenharmony_ci struct dentry *old_dentry, 3908c2ecf20Sopenharmony_ci struct inode *new_parent, 3918c2ecf20Sopenharmony_ci struct dentry *new_dentry, 3928c2ecf20Sopenharmony_ci unsigned int flags) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(old_parent->i_sb); 3958c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_old_parent_i = VBOXSF_I(old_parent); 3968c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_new_parent_i = VBOXSF_I(new_parent); 3978c2ecf20Sopenharmony_ci u32 shfl_flags = SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS; 3988c2ecf20Sopenharmony_ci struct shfl_string *old_path, *new_path; 3998c2ecf20Sopenharmony_ci int err; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (flags) 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci old_path = vboxsf_path_from_dentry(sbi, old_dentry); 4058c2ecf20Sopenharmony_ci if (IS_ERR(old_path)) 4068c2ecf20Sopenharmony_ci return PTR_ERR(old_path); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci new_path = vboxsf_path_from_dentry(sbi, new_dentry); 4098c2ecf20Sopenharmony_ci if (IS_ERR(new_path)) { 4108c2ecf20Sopenharmony_ci err = PTR_ERR(new_path); 4118c2ecf20Sopenharmony_ci goto err_put_old_path; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (d_inode(old_dentry)->i_mode & S_IFDIR) 4158c2ecf20Sopenharmony_ci shfl_flags = 0; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci err = vboxsf_rename(sbi->root, old_path, new_path, shfl_flags); 4188c2ecf20Sopenharmony_ci if (err == 0) { 4198c2ecf20Sopenharmony_ci /* parent directories access/change time changed */ 4208c2ecf20Sopenharmony_ci sf_new_parent_i->force_restat = 1; 4218c2ecf20Sopenharmony_ci sf_old_parent_i->force_restat = 1; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci __putname(new_path); 4258c2ecf20Sopenharmony_cierr_put_old_path: 4268c2ecf20Sopenharmony_ci __putname(old_path); 4278c2ecf20Sopenharmony_ci return err; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int vboxsf_dir_symlink(struct inode *parent, struct dentry *dentry, 4318c2ecf20Sopenharmony_ci const char *symname) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); 4348c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 4358c2ecf20Sopenharmony_ci int symname_size = strlen(symname) + 1; 4368c2ecf20Sopenharmony_ci struct shfl_string *path, *ssymname; 4378c2ecf20Sopenharmony_ci struct shfl_fsobjinfo info; 4388c2ecf20Sopenharmony_ci int err; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci path = vboxsf_path_from_dentry(sbi, dentry); 4418c2ecf20Sopenharmony_ci if (IS_ERR(path)) 4428c2ecf20Sopenharmony_ci return PTR_ERR(path); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ssymname = kmalloc(SHFLSTRING_HEADER_SIZE + symname_size, GFP_KERNEL); 4458c2ecf20Sopenharmony_ci if (!ssymname) { 4468c2ecf20Sopenharmony_ci __putname(path); 4478c2ecf20Sopenharmony_ci return -ENOMEM; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci ssymname->length = symname_size - 1; 4508c2ecf20Sopenharmony_ci ssymname->size = symname_size; 4518c2ecf20Sopenharmony_ci memcpy(ssymname->string.utf8, symname, symname_size); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci err = vboxsf_symlink(sbi->root, path, ssymname, &info); 4548c2ecf20Sopenharmony_ci kfree(ssymname); 4558c2ecf20Sopenharmony_ci __putname(path); 4568c2ecf20Sopenharmony_ci if (err) { 4578c2ecf20Sopenharmony_ci /* -EROFS means symlinks are note support -> -EPERM */ 4588c2ecf20Sopenharmony_ci return (err == -EROFS) ? -EPERM : err; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci err = vboxsf_dir_instantiate(parent, dentry, &info); 4628c2ecf20Sopenharmony_ci if (err) 4638c2ecf20Sopenharmony_ci return err; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* parent directory access/change time changed */ 4668c2ecf20Sopenharmony_ci sf_parent_i->force_restat = 1; 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ciconst struct inode_operations vboxsf_dir_iops = { 4718c2ecf20Sopenharmony_ci .lookup = vboxsf_dir_lookup, 4728c2ecf20Sopenharmony_ci .create = vboxsf_dir_mkfile, 4738c2ecf20Sopenharmony_ci .mkdir = vboxsf_dir_mkdir, 4748c2ecf20Sopenharmony_ci .atomic_open = vboxsf_dir_atomic_open, 4758c2ecf20Sopenharmony_ci .rmdir = vboxsf_dir_unlink, 4768c2ecf20Sopenharmony_ci .unlink = vboxsf_dir_unlink, 4778c2ecf20Sopenharmony_ci .rename = vboxsf_dir_rename, 4788c2ecf20Sopenharmony_ci .symlink = vboxsf_dir_symlink, 4798c2ecf20Sopenharmony_ci .getattr = vboxsf_getattr, 4808c2ecf20Sopenharmony_ci .setattr = vboxsf_setattr, 4818c2ecf20Sopenharmony_ci}; 482