18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VirtualBox Guest Shared Folders support: Utility functions. 48c2ecf20Sopenharmony_ci * Mainly conversion from/to VirtualBox/Linux data structures. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2006-2018 Oracle Corporation 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/namei.h> 108c2ecf20Sopenharmony_ci#include <linux/nls.h> 118c2ecf20Sopenharmony_ci#include <linux/sizes.h> 128c2ecf20Sopenharmony_ci#include <linux/vfs.h> 138c2ecf20Sopenharmony_ci#include "vfsmod.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct inode *vboxsf_new_inode(struct super_block *sb) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); 188c2ecf20Sopenharmony_ci struct inode *inode; 198c2ecf20Sopenharmony_ci unsigned long flags; 208c2ecf20Sopenharmony_ci int cursor, ret; 218c2ecf20Sopenharmony_ci u32 gen; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci inode = new_inode(sb); 248c2ecf20Sopenharmony_ci if (!inode) 258c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci idr_preload(GFP_KERNEL); 288c2ecf20Sopenharmony_ci spin_lock_irqsave(&sbi->ino_idr_lock, flags); 298c2ecf20Sopenharmony_ci cursor = idr_get_cursor(&sbi->ino_idr); 308c2ecf20Sopenharmony_ci ret = idr_alloc_cyclic(&sbi->ino_idr, inode, 1, 0, GFP_ATOMIC); 318c2ecf20Sopenharmony_ci if (ret >= 0 && ret < cursor) 328c2ecf20Sopenharmony_ci sbi->next_generation++; 338c2ecf20Sopenharmony_ci gen = sbi->next_generation; 348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); 358c2ecf20Sopenharmony_ci idr_preload_end(); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (ret < 0) { 388c2ecf20Sopenharmony_ci iput(inode); 398c2ecf20Sopenharmony_ci return ERR_PTR(ret); 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci inode->i_ino = ret; 438c2ecf20Sopenharmony_ci inode->i_generation = gen; 448c2ecf20Sopenharmony_ci return inode; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* set [inode] attributes based on [info], uid/gid based on [sbi] */ 488c2ecf20Sopenharmony_civoid vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, 498c2ecf20Sopenharmony_ci const struct shfl_fsobjinfo *info) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci const struct shfl_fsobjattr *attr; 528c2ecf20Sopenharmony_ci s64 allocated; 538c2ecf20Sopenharmony_ci int mode; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci attr = &info->attr; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci mode = mode_set(IRUSR); 608c2ecf20Sopenharmony_ci mode |= mode_set(IWUSR); 618c2ecf20Sopenharmony_ci mode |= mode_set(IXUSR); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci mode |= mode_set(IRGRP); 648c2ecf20Sopenharmony_ci mode |= mode_set(IWGRP); 658c2ecf20Sopenharmony_ci mode |= mode_set(IXGRP); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci mode |= mode_set(IROTH); 688c2ecf20Sopenharmony_ci mode |= mode_set(IWOTH); 698c2ecf20Sopenharmony_ci mode |= mode_set(IXOTH); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#undef mode_set 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* We use the host-side values for these */ 748c2ecf20Sopenharmony_ci inode->i_flags |= S_NOATIME | S_NOCMTIME; 758c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &vboxsf_reg_aops; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (SHFL_IS_DIRECTORY(attr->mode)) { 788c2ecf20Sopenharmony_ci inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode; 798c2ecf20Sopenharmony_ci inode->i_mode &= ~sbi->o.dmask; 808c2ecf20Sopenharmony_ci inode->i_mode |= S_IFDIR; 818c2ecf20Sopenharmony_ci inode->i_op = &vboxsf_dir_iops; 828c2ecf20Sopenharmony_ci inode->i_fop = &vboxsf_dir_fops; 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * XXX: this probably should be set to the number of entries 858c2ecf20Sopenharmony_ci * in the directory plus two (. ..) 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci set_nlink(inode, 1); 888c2ecf20Sopenharmony_ci } else if (SHFL_IS_SYMLINK(attr->mode)) { 898c2ecf20Sopenharmony_ci inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; 908c2ecf20Sopenharmony_ci inode->i_mode &= ~sbi->o.fmask; 918c2ecf20Sopenharmony_ci inode->i_mode |= S_IFLNK; 928c2ecf20Sopenharmony_ci inode->i_op = &vboxsf_lnk_iops; 938c2ecf20Sopenharmony_ci set_nlink(inode, 1); 948c2ecf20Sopenharmony_ci } else { 958c2ecf20Sopenharmony_ci inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; 968c2ecf20Sopenharmony_ci inode->i_mode &= ~sbi->o.fmask; 978c2ecf20Sopenharmony_ci inode->i_mode |= S_IFREG; 988c2ecf20Sopenharmony_ci inode->i_op = &vboxsf_reg_iops; 998c2ecf20Sopenharmony_ci inode->i_fop = &vboxsf_reg_fops; 1008c2ecf20Sopenharmony_ci set_nlink(inode, 1); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci inode->i_uid = sbi->o.uid; 1048c2ecf20Sopenharmony_ci inode->i_gid = sbi->o.gid; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci inode->i_size = info->size; 1078c2ecf20Sopenharmony_ci inode->i_blkbits = 12; 1088c2ecf20Sopenharmony_ci /* i_blocks always in units of 512 bytes! */ 1098c2ecf20Sopenharmony_ci allocated = info->allocated + 511; 1108c2ecf20Sopenharmony_ci do_div(allocated, 512); 1118c2ecf20Sopenharmony_ci inode->i_blocks = allocated; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci inode->i_atime = ns_to_timespec64( 1148c2ecf20Sopenharmony_ci info->access_time.ns_relative_to_unix_epoch); 1158c2ecf20Sopenharmony_ci inode->i_ctime = ns_to_timespec64( 1168c2ecf20Sopenharmony_ci info->change_time.ns_relative_to_unix_epoch); 1178c2ecf20Sopenharmony_ci inode->i_mtime = ns_to_timespec64( 1188c2ecf20Sopenharmony_ci info->modification_time.ns_relative_to_unix_epoch); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciint vboxsf_create_at_dentry(struct dentry *dentry, 1228c2ecf20Sopenharmony_ci struct shfl_createparms *params) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); 1258c2ecf20Sopenharmony_ci struct shfl_string *path; 1268c2ecf20Sopenharmony_ci int err; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci path = vboxsf_path_from_dentry(sbi, dentry); 1298c2ecf20Sopenharmony_ci if (IS_ERR(path)) 1308c2ecf20Sopenharmony_ci return PTR_ERR(path); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci err = vboxsf_create(sbi->root, path, params); 1338c2ecf20Sopenharmony_ci __putname(path); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return err; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciint vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, 1398c2ecf20Sopenharmony_ci struct shfl_fsobjinfo *info) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct shfl_createparms params = {}; 1428c2ecf20Sopenharmony_ci int err; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci params.handle = SHFL_HANDLE_NIL; 1458c2ecf20Sopenharmony_ci params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci err = vboxsf_create(sbi->root, path, ¶ms); 1488c2ecf20Sopenharmony_ci if (err) 1498c2ecf20Sopenharmony_ci return err; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (params.result != SHFL_FILE_EXISTS) 1528c2ecf20Sopenharmony_ci return -ENOENT; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (info) 1558c2ecf20Sopenharmony_ci *info = params.info; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciint vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); 1638c2ecf20Sopenharmony_ci struct shfl_string *path; 1648c2ecf20Sopenharmony_ci int err; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci path = vboxsf_path_from_dentry(sbi, dentry); 1678c2ecf20Sopenharmony_ci if (IS_ERR(path)) 1688c2ecf20Sopenharmony_ci return PTR_ERR(path); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci err = vboxsf_stat(sbi, path, info); 1718c2ecf20Sopenharmony_ci __putname(path); 1728c2ecf20Sopenharmony_ci return err; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ciint vboxsf_inode_revalidate(struct dentry *dentry) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi; 1788c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_i; 1798c2ecf20Sopenharmony_ci struct shfl_fsobjinfo info; 1808c2ecf20Sopenharmony_ci struct timespec64 prev_mtime; 1818c2ecf20Sopenharmony_ci struct inode *inode; 1828c2ecf20Sopenharmony_ci int err; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (!dentry || !d_really_is_positive(dentry)) 1858c2ecf20Sopenharmony_ci return -EINVAL; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci inode = d_inode(dentry); 1888c2ecf20Sopenharmony_ci prev_mtime = inode->i_mtime; 1898c2ecf20Sopenharmony_ci sf_i = VBOXSF_I(inode); 1908c2ecf20Sopenharmony_ci sbi = VBOXSF_SBI(dentry->d_sb); 1918c2ecf20Sopenharmony_ci if (!sf_i->force_restat) { 1928c2ecf20Sopenharmony_ci if (time_before(jiffies, dentry->d_time + sbi->o.ttl)) 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci err = vboxsf_stat_dentry(dentry, &info); 1978c2ecf20Sopenharmony_ci if (err) 1988c2ecf20Sopenharmony_ci return err; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci dentry->d_time = jiffies; 2018c2ecf20Sopenharmony_ci sf_i->force_restat = 0; 2028c2ecf20Sopenharmony_ci vboxsf_init_inode(sbi, inode, &info); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * If the file was changed on the host side we need to invalidate the 2068c2ecf20Sopenharmony_ci * page-cache for it. Note this also gets triggered by our own writes, 2078c2ecf20Sopenharmony_ci * this is unavoidable. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci if (timespec64_compare(&inode->i_mtime, &prev_mtime) > 0) 2108c2ecf20Sopenharmony_ci invalidate_inode_pages2(inode->i_mapping); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciint vboxsf_getattr(const struct path *path, struct kstat *kstat, 2168c2ecf20Sopenharmony_ci u32 request_mask, unsigned int flags) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci int err; 2198c2ecf20Sopenharmony_ci struct dentry *dentry = path->dentry; 2208c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 2218c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_i = VBOXSF_I(inode); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci switch (flags & AT_STATX_SYNC_TYPE) { 2248c2ecf20Sopenharmony_ci case AT_STATX_DONT_SYNC: 2258c2ecf20Sopenharmony_ci err = 0; 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case AT_STATX_FORCE_SYNC: 2288c2ecf20Sopenharmony_ci sf_i->force_restat = 1; 2298c2ecf20Sopenharmony_ci fallthrough; 2308c2ecf20Sopenharmony_ci default: 2318c2ecf20Sopenharmony_ci err = vboxsf_inode_revalidate(dentry); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci if (err) 2348c2ecf20Sopenharmony_ci return err; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci generic_fillattr(d_inode(dentry), kstat); 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciint vboxsf_setattr(struct dentry *dentry, struct iattr *iattr) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry)); 2438c2ecf20Sopenharmony_ci struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); 2448c2ecf20Sopenharmony_ci struct shfl_createparms params = {}; 2458c2ecf20Sopenharmony_ci struct shfl_fsobjinfo info = {}; 2468c2ecf20Sopenharmony_ci u32 buf_len; 2478c2ecf20Sopenharmony_ci int err; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci params.handle = SHFL_HANDLE_NIL; 2508c2ecf20Sopenharmony_ci params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS | 2518c2ecf20Sopenharmony_ci SHFL_CF_ACT_FAIL_IF_NEW | 2528c2ecf20Sopenharmony_ci SHFL_CF_ACCESS_ATTR_WRITE; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* this is at least required for Posix hosts */ 2558c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_SIZE) 2568c2ecf20Sopenharmony_ci params.create_flags |= SHFL_CF_ACCESS_WRITE; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci err = vboxsf_create_at_dentry(dentry, ¶ms); 2598c2ecf20Sopenharmony_ci if (err || params.result != SHFL_FILE_EXISTS) 2608c2ecf20Sopenharmony_ci return err ? err : -ENOENT; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0) 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Setting the file size and setting the other attributes has to 2668c2ecf20Sopenharmony_ci * be handled separately. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) { 2698c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_MODE) { 2708c2ecf20Sopenharmony_ci info.attr.mode = mode_set(IRUSR); 2718c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IWUSR); 2728c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IXUSR); 2738c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IRGRP); 2748c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IWGRP); 2758c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IXGRP); 2768c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IROTH); 2778c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IWOTH); 2788c2ecf20Sopenharmony_ci info.attr.mode |= mode_set(IXOTH); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (iattr->ia_mode & S_IFDIR) 2818c2ecf20Sopenharmony_ci info.attr.mode |= SHFL_TYPE_DIRECTORY; 2828c2ecf20Sopenharmony_ci else 2838c2ecf20Sopenharmony_ci info.attr.mode |= SHFL_TYPE_FILE; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_ATIME) 2878c2ecf20Sopenharmony_ci info.access_time.ns_relative_to_unix_epoch = 2888c2ecf20Sopenharmony_ci timespec64_to_ns(&iattr->ia_atime); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_MTIME) 2918c2ecf20Sopenharmony_ci info.modification_time.ns_relative_to_unix_epoch = 2928c2ecf20Sopenharmony_ci timespec64_to_ns(&iattr->ia_mtime); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* 2958c2ecf20Sopenharmony_ci * Ignore ctime (inode change time) as it can't be set 2968c2ecf20Sopenharmony_ci * from userland anyway. 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci buf_len = sizeof(info); 3008c2ecf20Sopenharmony_ci err = vboxsf_fsinfo(sbi->root, params.handle, 3018c2ecf20Sopenharmony_ci SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len, 3028c2ecf20Sopenharmony_ci &info); 3038c2ecf20Sopenharmony_ci if (err) { 3048c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 3058c2ecf20Sopenharmony_ci return err; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* the host may have given us different attr then requested */ 3098c2ecf20Sopenharmony_ci sf_i->force_restat = 1; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci#undef mode_set 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_SIZE) { 3158c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 3168c2ecf20Sopenharmony_ci info.size = iattr->ia_size; 3178c2ecf20Sopenharmony_ci buf_len = sizeof(info); 3188c2ecf20Sopenharmony_ci err = vboxsf_fsinfo(sbi->root, params.handle, 3198c2ecf20Sopenharmony_ci SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len, 3208c2ecf20Sopenharmony_ci &info); 3218c2ecf20Sopenharmony_ci if (err) { 3228c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 3238c2ecf20Sopenharmony_ci return err; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* the host may have given us different attr then requested */ 3278c2ecf20Sopenharmony_ci sf_i->force_restat = 1; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci vboxsf_close(sbi->root, params.handle); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Update the inode with what the host has actually given us. */ 3338c2ecf20Sopenharmony_ci if (sf_i->force_restat) 3348c2ecf20Sopenharmony_ci vboxsf_inode_revalidate(dentry); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* 3408c2ecf20Sopenharmony_ci * [dentry] contains string encoded in coding system that corresponds 3418c2ecf20Sopenharmony_ci * to [sbi]->nls, we must convert it to UTF8 here. 3428c2ecf20Sopenharmony_ci * Returns a shfl_string allocated through __getname (must be freed using 3438c2ecf20Sopenharmony_ci * __putname), or an ERR_PTR on error. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_cistruct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi, 3468c2ecf20Sopenharmony_ci struct dentry *dentry) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct shfl_string *shfl_path; 3498c2ecf20Sopenharmony_ci int path_len, out_len, nb; 3508c2ecf20Sopenharmony_ci char *buf, *path; 3518c2ecf20Sopenharmony_ci wchar_t uni; 3528c2ecf20Sopenharmony_ci u8 *out; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci buf = __getname(); 3558c2ecf20Sopenharmony_ci if (!buf) 3568c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci path = dentry_path_raw(dentry, buf, PATH_MAX); 3598c2ecf20Sopenharmony_ci if (IS_ERR(path)) { 3608c2ecf20Sopenharmony_ci __putname(buf); 3618c2ecf20Sopenharmony_ci return ERR_CAST(path); 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci path_len = strlen(path); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (sbi->nls) { 3668c2ecf20Sopenharmony_ci shfl_path = __getname(); 3678c2ecf20Sopenharmony_ci if (!shfl_path) { 3688c2ecf20Sopenharmony_ci __putname(buf); 3698c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci out = shfl_path->string.utf8; 3738c2ecf20Sopenharmony_ci out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci while (path_len) { 3768c2ecf20Sopenharmony_ci nb = sbi->nls->char2uni(path, path_len, &uni); 3778c2ecf20Sopenharmony_ci if (nb < 0) { 3788c2ecf20Sopenharmony_ci __putname(shfl_path); 3798c2ecf20Sopenharmony_ci __putname(buf); 3808c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci path += nb; 3838c2ecf20Sopenharmony_ci path_len -= nb; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci nb = utf32_to_utf8(uni, out, out_len); 3868c2ecf20Sopenharmony_ci if (nb < 0) { 3878c2ecf20Sopenharmony_ci __putname(shfl_path); 3888c2ecf20Sopenharmony_ci __putname(buf); 3898c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci out += nb; 3928c2ecf20Sopenharmony_ci out_len -= nb; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci *out = 0; 3958c2ecf20Sopenharmony_ci shfl_path->length = out - shfl_path->string.utf8; 3968c2ecf20Sopenharmony_ci shfl_path->size = shfl_path->length + 1; 3978c2ecf20Sopenharmony_ci __putname(buf); 3988c2ecf20Sopenharmony_ci } else { 3998c2ecf20Sopenharmony_ci if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) { 4008c2ecf20Sopenharmony_ci __putname(buf); 4018c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci /* 4048c2ecf20Sopenharmony_ci * dentry_path stores the name at the end of buf, but the 4058c2ecf20Sopenharmony_ci * shfl_string string we return must be properly aligned. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ci shfl_path = (struct shfl_string *)buf; 4088c2ecf20Sopenharmony_ci memmove(shfl_path->string.utf8, path, path_len); 4098c2ecf20Sopenharmony_ci shfl_path->string.utf8[path_len] = 0; 4108c2ecf20Sopenharmony_ci shfl_path->length = path_len; 4118c2ecf20Sopenharmony_ci shfl_path->size = path_len + 1; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return shfl_path; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciint vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len, 4188c2ecf20Sopenharmony_ci const unsigned char *utf8_name, size_t utf8_len) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci const char *in; 4218c2ecf20Sopenharmony_ci char *out; 4228c2ecf20Sopenharmony_ci size_t out_len; 4238c2ecf20Sopenharmony_ci size_t out_bound_len; 4248c2ecf20Sopenharmony_ci size_t in_bound_len; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci in = utf8_name; 4278c2ecf20Sopenharmony_ci in_bound_len = utf8_len; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci out = name; 4308c2ecf20Sopenharmony_ci out_len = 0; 4318c2ecf20Sopenharmony_ci /* Reserve space for terminating 0 */ 4328c2ecf20Sopenharmony_ci out_bound_len = name_bound_len - 1; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci while (in_bound_len) { 4358c2ecf20Sopenharmony_ci int nb; 4368c2ecf20Sopenharmony_ci unicode_t uni; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci nb = utf8_to_utf32(in, in_bound_len, &uni); 4398c2ecf20Sopenharmony_ci if (nb < 0) 4408c2ecf20Sopenharmony_ci return -EINVAL; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci in += nb; 4438c2ecf20Sopenharmony_ci in_bound_len -= nb; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci nb = sbi->nls->uni2char(uni, out, out_bound_len); 4468c2ecf20Sopenharmony_ci if (nb < 0) 4478c2ecf20Sopenharmony_ci return nb; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci out += nb; 4508c2ecf20Sopenharmony_ci out_bound_len -= nb; 4518c2ecf20Sopenharmony_ci out_len += nb; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci *out = 0; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct vboxsf_dir_buf *b; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci b = kmalloc(sizeof(*b), GFP_KERNEL); 4648c2ecf20Sopenharmony_ci if (!b) 4658c2ecf20Sopenharmony_ci return NULL; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL); 4688c2ecf20Sopenharmony_ci if (!b->buf) { 4698c2ecf20Sopenharmony_ci kfree(b); 4708c2ecf20Sopenharmony_ci return NULL; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci b->entries = 0; 4748c2ecf20Sopenharmony_ci b->used = 0; 4758c2ecf20Sopenharmony_ci b->free = DIR_BUFFER_SIZE; 4768c2ecf20Sopenharmony_ci list_add(&b->head, list); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return b; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci list_del(&b->head); 4848c2ecf20Sopenharmony_ci kfree(b->buf); 4858c2ecf20Sopenharmony_ci kfree(b); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistruct vboxsf_dir_info *vboxsf_dir_info_alloc(void) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct vboxsf_dir_info *p; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci p = kmalloc(sizeof(*p), GFP_KERNEL); 4938c2ecf20Sopenharmony_ci if (!p) 4948c2ecf20Sopenharmony_ci return NULL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p->info_list); 4978c2ecf20Sopenharmony_ci return p; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_civoid vboxsf_dir_info_free(struct vboxsf_dir_info *p) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct list_head *list, *pos, *tmp; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci list = &p->info_list; 5058c2ecf20Sopenharmony_ci list_for_each_safe(pos, tmp, list) { 5068c2ecf20Sopenharmony_ci struct vboxsf_dir_buf *b; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci b = list_entry(pos, struct vboxsf_dir_buf, head); 5098c2ecf20Sopenharmony_ci vboxsf_dir_buf_free(b); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci kfree(p); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ciint vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d, 5158c2ecf20Sopenharmony_ci u64 handle) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct vboxsf_dir_buf *b; 5188c2ecf20Sopenharmony_ci u32 entries, size; 5198c2ecf20Sopenharmony_ci int err = 0; 5208c2ecf20Sopenharmony_ci void *buf; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* vboxsf_dirinfo returns 1 on end of dir */ 5238c2ecf20Sopenharmony_ci while (err == 0) { 5248c2ecf20Sopenharmony_ci b = vboxsf_dir_buf_alloc(&sf_d->info_list); 5258c2ecf20Sopenharmony_ci if (!b) { 5268c2ecf20Sopenharmony_ci err = -ENOMEM; 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci buf = b->buf; 5318c2ecf20Sopenharmony_ci size = b->free; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0, 5348c2ecf20Sopenharmony_ci &size, buf, &entries); 5358c2ecf20Sopenharmony_ci if (err < 0) 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci b->entries += entries; 5398c2ecf20Sopenharmony_ci b->free -= size; 5408c2ecf20Sopenharmony_ci b->used += size; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (b && b->used == 0) 5448c2ecf20Sopenharmony_ci vboxsf_dir_buf_free(b); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* -EILSEQ means the host could not translate a filename, ignore */ 5478c2ecf20Sopenharmony_ci if (err > 0 || err == -EILSEQ) 5488c2ecf20Sopenharmony_ci err = 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return err; 5518c2ecf20Sopenharmony_ci} 552