1 // SPDX-License-Identifier: MIT 2 /* 3 * VirtualBox Guest Shared Folders support: Directory inode and file operations 4 * 5 * Copyright (C) 2006-2018 Oracle Corporation 6 */ 7 8 #include <linux/namei.h> 9 #include <linux/vbox_utils.h> 10 #include "vfsmod.h" 11 12 static int vboxsf_dir_open(struct inode *inode, struct file *file) 13 { 14 struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); 15 struct shfl_createparms params = {}; 16 struct vboxsf_dir_info *sf_d; 17 int err; 18 19 sf_d = vboxsf_dir_info_alloc(); 20 if (!sf_d) 21 return -ENOMEM; 22 23 params.handle = SHFL_HANDLE_NIL; 24 params.create_flags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | 25 SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; 26 27 err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); 28 if (err) 29 goto err_free_dir_info; 30 31 if (params.result != SHFL_FILE_EXISTS) { 32 err = -ENOENT; 33 goto err_close; 34 } 35 36 err = vboxsf_dir_read_all(sbi, sf_d, params.handle); 37 if (err) 38 goto err_close; 39 40 vboxsf_close(sbi->root, params.handle); 41 file->private_data = sf_d; 42 return 0; 43 44 err_close: 45 vboxsf_close(sbi->root, params.handle); 46 err_free_dir_info: 47 vboxsf_dir_info_free(sf_d); 48 return err; 49 } 50 51 static int vboxsf_dir_release(struct inode *inode, struct file *file) 52 { 53 if (file->private_data) 54 vboxsf_dir_info_free(file->private_data); 55 56 return 0; 57 } 58 59 static unsigned int vboxsf_get_d_type(u32 mode) 60 { 61 unsigned int d_type; 62 63 switch (mode & SHFL_TYPE_MASK) { 64 case SHFL_TYPE_FIFO: 65 d_type = DT_FIFO; 66 break; 67 case SHFL_TYPE_DEV_CHAR: 68 d_type = DT_CHR; 69 break; 70 case SHFL_TYPE_DIRECTORY: 71 d_type = DT_DIR; 72 break; 73 case SHFL_TYPE_DEV_BLOCK: 74 d_type = DT_BLK; 75 break; 76 case SHFL_TYPE_FILE: 77 d_type = DT_REG; 78 break; 79 case SHFL_TYPE_SYMLINK: 80 d_type = DT_LNK; 81 break; 82 case SHFL_TYPE_SOCKET: 83 d_type = DT_SOCK; 84 break; 85 case SHFL_TYPE_WHITEOUT: 86 d_type = DT_WHT; 87 break; 88 default: 89 d_type = DT_UNKNOWN; 90 break; 91 } 92 return d_type; 93 } 94 95 static bool vboxsf_dir_emit(struct file *dir, struct dir_context *ctx) 96 { 97 struct vboxsf_sbi *sbi = VBOXSF_SBI(file_inode(dir)->i_sb); 98 struct vboxsf_dir_info *sf_d = dir->private_data; 99 struct shfl_dirinfo *info; 100 struct vboxsf_dir_buf *b; 101 unsigned int d_type; 102 loff_t i, cur = 0; 103 ino_t fake_ino; 104 void *end; 105 int err; 106 107 list_for_each_entry(b, &sf_d->info_list, head) { 108 try_next_entry: 109 if (ctx->pos >= cur + b->entries) { 110 cur += b->entries; 111 continue; 112 } 113 114 /* 115 * Note the vboxsf_dir_info objects we are iterating over here 116 * are variable sized, so the info pointer may end up being 117 * unaligned. This is how we get the data from the host. 118 * Since vboxsf is only supported on x86 machines this is not 119 * a problem. 120 */ 121 for (i = 0, info = b->buf; i < ctx->pos - cur; i++) { 122 end = &info->name.string.utf8[info->name.size]; 123 /* Only happens if the host gives us corrupt data */ 124 if (WARN_ON(end > (b->buf + b->used))) 125 return false; 126 info = end; 127 } 128 129 end = &info->name.string.utf8[info->name.size]; 130 if (WARN_ON(end > (b->buf + b->used))) 131 return false; 132 133 /* Info now points to the right entry, emit it. */ 134 d_type = vboxsf_get_d_type(info->info.attr.mode); 135 136 /* 137 * On 32-bit systems pos is 64-bit signed, while ino is 32-bit 138 * unsigned so fake_ino may overflow, check for this. 139 */ 140 if ((ino_t)(ctx->pos + 1) != (u64)(ctx->pos + 1)) { 141 vbg_err("vboxsf: fake ino overflow, truncating dir\n"); 142 return false; 143 } 144 fake_ino = ctx->pos + 1; 145 146 if (sbi->nls) { 147 char d_name[NAME_MAX]; 148 149 err = vboxsf_nlscpy(sbi, d_name, NAME_MAX, 150 info->name.string.utf8, 151 info->name.length); 152 if (err) { 153 /* skip erroneous entry and proceed */ 154 ctx->pos += 1; 155 goto try_next_entry; 156 } 157 158 return dir_emit(ctx, d_name, strlen(d_name), 159 fake_ino, d_type); 160 } 161 162 return dir_emit(ctx, info->name.string.utf8, info->name.length, 163 fake_ino, d_type); 164 } 165 166 return false; 167 } 168 169 static int vboxsf_dir_iterate(struct file *dir, struct dir_context *ctx) 170 { 171 bool emitted; 172 173 do { 174 emitted = vboxsf_dir_emit(dir, ctx); 175 if (emitted) 176 ctx->pos += 1; 177 } while (emitted); 178 179 return 0; 180 } 181 182 WRAP_DIR_ITER(vboxsf_dir_iterate) // FIXME! 183 const struct file_operations vboxsf_dir_fops = { 184 .open = vboxsf_dir_open, 185 .iterate_shared = shared_vboxsf_dir_iterate, 186 .release = vboxsf_dir_release, 187 .read = generic_read_dir, 188 .llseek = generic_file_llseek, 189 }; 190 191 /* 192 * This is called during name resolution/lookup to check if the @dentry in 193 * the cache is still valid. the job is handled by vboxsf_inode_revalidate. 194 */ 195 static int vboxsf_dentry_revalidate(struct dentry *dentry, unsigned int flags) 196 { 197 if (flags & LOOKUP_RCU) 198 return -ECHILD; 199 200 if (d_really_is_positive(dentry)) 201 return vboxsf_inode_revalidate(dentry) == 0; 202 else 203 return vboxsf_stat_dentry(dentry, NULL) == -ENOENT; 204 } 205 206 const struct dentry_operations vboxsf_dentry_ops = { 207 .d_revalidate = vboxsf_dentry_revalidate 208 }; 209 210 /* iops */ 211 212 static struct dentry *vboxsf_dir_lookup(struct inode *parent, 213 struct dentry *dentry, 214 unsigned int flags) 215 { 216 struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 217 struct shfl_fsobjinfo fsinfo; 218 struct inode *inode; 219 int err; 220 221 dentry->d_time = jiffies; 222 223 err = vboxsf_stat_dentry(dentry, &fsinfo); 224 if (err) { 225 inode = (err == -ENOENT) ? NULL : ERR_PTR(err); 226 } else { 227 inode = vboxsf_new_inode(parent->i_sb); 228 if (!IS_ERR(inode)) 229 vboxsf_init_inode(sbi, inode, &fsinfo, false); 230 } 231 232 return d_splice_alias(inode, dentry); 233 } 234 235 static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry, 236 struct shfl_fsobjinfo *info) 237 { 238 struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 239 struct vboxsf_inode *sf_i; 240 struct inode *inode; 241 242 inode = vboxsf_new_inode(parent->i_sb); 243 if (IS_ERR(inode)) 244 return PTR_ERR(inode); 245 246 sf_i = VBOXSF_I(inode); 247 /* The host may have given us different attr then requested */ 248 sf_i->force_restat = 1; 249 vboxsf_init_inode(sbi, inode, info, false); 250 251 d_instantiate(dentry, inode); 252 253 return 0; 254 } 255 256 static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry, 257 umode_t mode, bool is_dir, bool excl, u64 *handle_ret) 258 { 259 struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); 260 struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 261 struct shfl_createparms params = {}; 262 int err; 263 264 params.handle = SHFL_HANDLE_NIL; 265 params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACCESS_READWRITE; 266 if (is_dir) 267 params.create_flags |= SHFL_CF_DIRECTORY; 268 if (excl) 269 params.create_flags |= SHFL_CF_ACT_FAIL_IF_EXISTS; 270 271 params.info.attr.mode = (mode & 0777) | 272 (is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE); 273 params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING; 274 275 err = vboxsf_create_at_dentry(dentry, ¶ms); 276 if (err) 277 return err; 278 279 if (params.result != SHFL_FILE_CREATED) 280 return -EPERM; 281 282 err = vboxsf_dir_instantiate(parent, dentry, ¶ms.info); 283 if (err) 284 goto out; 285 286 /* parent directory access/change time changed */ 287 sf_parent_i->force_restat = 1; 288 289 out: 290 if (err == 0 && handle_ret) 291 *handle_ret = params.handle; 292 else 293 vboxsf_close(sbi->root, params.handle); 294 295 return err; 296 } 297 298 static int vboxsf_dir_mkfile(struct mnt_idmap *idmap, 299 struct inode *parent, struct dentry *dentry, 300 umode_t mode, bool excl) 301 { 302 return vboxsf_dir_create(parent, dentry, mode, false, excl, NULL); 303 } 304 305 static int vboxsf_dir_mkdir(struct mnt_idmap *idmap, 306 struct inode *parent, struct dentry *dentry, 307 umode_t mode) 308 { 309 return vboxsf_dir_create(parent, dentry, mode, true, true, NULL); 310 } 311 312 static int vboxsf_dir_atomic_open(struct inode *parent, struct dentry *dentry, 313 struct file *file, unsigned int flags, umode_t mode) 314 { 315 struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 316 struct vboxsf_handle *sf_handle; 317 struct dentry *res = NULL; 318 u64 handle; 319 int err; 320 321 if (d_in_lookup(dentry)) { 322 res = vboxsf_dir_lookup(parent, dentry, 0); 323 if (IS_ERR(res)) 324 return PTR_ERR(res); 325 326 if (res) 327 dentry = res; 328 } 329 330 /* Only creates */ 331 if (!(flags & O_CREAT) || d_really_is_positive(dentry)) 332 return finish_no_open(file, res); 333 334 err = vboxsf_dir_create(parent, dentry, mode, false, flags & O_EXCL, &handle); 335 if (err) 336 goto out; 337 338 sf_handle = vboxsf_create_sf_handle(d_inode(dentry), handle, SHFL_CF_ACCESS_READWRITE); 339 if (IS_ERR(sf_handle)) { 340 vboxsf_close(sbi->root, handle); 341 err = PTR_ERR(sf_handle); 342 goto out; 343 } 344 345 err = finish_open(file, dentry, generic_file_open); 346 if (err) { 347 /* This also closes the handle passed to vboxsf_create_sf_handle() */ 348 vboxsf_release_sf_handle(d_inode(dentry), sf_handle); 349 goto out; 350 } 351 352 file->private_data = sf_handle; 353 file->f_mode |= FMODE_CREATED; 354 out: 355 dput(res); 356 return err; 357 } 358 359 static int vboxsf_dir_unlink(struct inode *parent, struct dentry *dentry) 360 { 361 struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 362 struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); 363 struct inode *inode = d_inode(dentry); 364 struct shfl_string *path; 365 u32 flags; 366 int err; 367 368 if (S_ISDIR(inode->i_mode)) 369 flags = SHFL_REMOVE_DIR; 370 else 371 flags = SHFL_REMOVE_FILE; 372 373 if (S_ISLNK(inode->i_mode)) 374 flags |= SHFL_REMOVE_SYMLINK; 375 376 path = vboxsf_path_from_dentry(sbi, dentry); 377 if (IS_ERR(path)) 378 return PTR_ERR(path); 379 380 err = vboxsf_remove(sbi->root, path, flags); 381 __putname(path); 382 if (err) 383 return err; 384 385 /* parent directory access/change time changed */ 386 sf_parent_i->force_restat = 1; 387 388 return 0; 389 } 390 391 static int vboxsf_dir_rename(struct mnt_idmap *idmap, 392 struct inode *old_parent, 393 struct dentry *old_dentry, 394 struct inode *new_parent, 395 struct dentry *new_dentry, 396 unsigned int flags) 397 { 398 struct vboxsf_sbi *sbi = VBOXSF_SBI(old_parent->i_sb); 399 struct vboxsf_inode *sf_old_parent_i = VBOXSF_I(old_parent); 400 struct vboxsf_inode *sf_new_parent_i = VBOXSF_I(new_parent); 401 u32 shfl_flags = SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS; 402 struct shfl_string *old_path, *new_path; 403 int err; 404 405 if (flags) 406 return -EINVAL; 407 408 old_path = vboxsf_path_from_dentry(sbi, old_dentry); 409 if (IS_ERR(old_path)) 410 return PTR_ERR(old_path); 411 412 new_path = vboxsf_path_from_dentry(sbi, new_dentry); 413 if (IS_ERR(new_path)) { 414 err = PTR_ERR(new_path); 415 goto err_put_old_path; 416 } 417 418 if (d_inode(old_dentry)->i_mode & S_IFDIR) 419 shfl_flags = 0; 420 421 err = vboxsf_rename(sbi->root, old_path, new_path, shfl_flags); 422 if (err == 0) { 423 /* parent directories access/change time changed */ 424 sf_new_parent_i->force_restat = 1; 425 sf_old_parent_i->force_restat = 1; 426 } 427 428 __putname(new_path); 429 err_put_old_path: 430 __putname(old_path); 431 return err; 432 } 433 434 static int vboxsf_dir_symlink(struct mnt_idmap *idmap, 435 struct inode *parent, struct dentry *dentry, 436 const char *symname) 437 { 438 struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); 439 struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); 440 int symname_size = strlen(symname) + 1; 441 struct shfl_string *path, *ssymname; 442 struct shfl_fsobjinfo info; 443 int err; 444 445 path = vboxsf_path_from_dentry(sbi, dentry); 446 if (IS_ERR(path)) 447 return PTR_ERR(path); 448 449 ssymname = kmalloc(SHFLSTRING_HEADER_SIZE + symname_size, GFP_KERNEL); 450 if (!ssymname) { 451 __putname(path); 452 return -ENOMEM; 453 } 454 ssymname->length = symname_size - 1; 455 ssymname->size = symname_size; 456 memcpy(ssymname->string.utf8, symname, symname_size); 457 458 err = vboxsf_symlink(sbi->root, path, ssymname, &info); 459 kfree(ssymname); 460 __putname(path); 461 if (err) { 462 /* -EROFS means symlinks are note support -> -EPERM */ 463 return (err == -EROFS) ? -EPERM : err; 464 } 465 466 err = vboxsf_dir_instantiate(parent, dentry, &info); 467 if (err) 468 return err; 469 470 /* parent directory access/change time changed */ 471 sf_parent_i->force_restat = 1; 472 return 0; 473 } 474 475 const struct inode_operations vboxsf_dir_iops = { 476 .lookup = vboxsf_dir_lookup, 477 .create = vboxsf_dir_mkfile, 478 .mkdir = vboxsf_dir_mkdir, 479 .atomic_open = vboxsf_dir_atomic_open, 480 .rmdir = vboxsf_dir_unlink, 481 .unlink = vboxsf_dir_unlink, 482 .rename = vboxsf_dir_rename, 483 .symlink = vboxsf_dir_symlink, 484 .getattr = vboxsf_getattr, 485 .setattr = vboxsf_setattr, 486 }; 487
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.