1 // SPDX-License-Identifier: MIT 2 /* 3 * VirtualBox Guest Shared Folders support: Utility functions. 4 * Mainly conversion from/to VirtualBox/Linux data structures. 5 * 6 * Copyright (C) 2006-2018 Oracle Corporation 7 */ 8 9 #include <linux/namei.h> 10 #include <linux/nls.h> 11 #include <linux/sizes.h> 12 #include <linux/pagemap.h> 13 #include <linux/vfs.h> 14 #include "vfsmod.h" 15 16 struct inode *vboxsf_new_inode(struct super_block *sb) 17 { 18 struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); 19 struct inode *inode; 20 unsigned long flags; 21 int cursor, ret; 22 u32 gen; 23 24 inode = new_inode(sb); 25 if (!inode) 26 return ERR_PTR(-ENOMEM); 27 28 idr_preload(GFP_KERNEL); 29 spin_lock_irqsave(&sbi->ino_idr_lock, flags); 30 cursor = idr_get_cursor(&sbi->ino_idr); 31 ret = idr_alloc_cyclic(&sbi->ino_idr, inode, 1, 0, GFP_ATOMIC); 32 if (ret >= 0 && ret < cursor) 33 sbi->next_generation++; 34 gen = sbi->next_generation; 35 spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); 36 idr_preload_end(); 37 38 if (ret < 0) { 39 iput(inode); 40 return ERR_PTR(ret); 41 } 42 43 inode->i_ino = ret; 44 inode->i_generation = gen; 45 return inode; 46 } 47 48 /* set [inode] attributes based on [info], uid/gid based on [sbi] */ 49 int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, 50 const struct shfl_fsobjinfo *info, bool reinit) 51 { 52 const struct shfl_fsobjattr *attr; 53 s64 allocated; 54 umode_t mode; 55 56 attr = &info->attr; 57 58 #define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0) 59 60 mode = mode_set(IRUSR); 61 mode |= mode_set(IWUSR); 62 mode |= mode_set(IXUSR); 63 64 mode |= mode_set(IRGRP); 65 mode |= mode_set(IWGRP); 66 mode |= mode_set(IXGRP); 67 68 mode |= mode_set(IROTH); 69 mode |= mode_set(IWOTH); 70 mode |= mode_set(IXOTH); 71 72 #undef mode_set 73 74 /* We use the host-side values for these */ 75 inode->i_flags |= S_NOATIME | S_NOCMTIME; 76 inode->i_mapping->a_ops = &vboxsf_reg_aops; 77 78 if (SHFL_IS_DIRECTORY(attr->mode)) { 79 if (sbi->o.dmode_set) 80 mode = sbi->o.dmode; 81 mode &= ~sbi->o.dmask; 82 mode |= S_IFDIR; 83 if (!reinit) { 84 inode->i_op = &vboxsf_dir_iops; 85 inode->i_fop = &vboxsf_dir_fops; 86 /* 87 * XXX: this probably should be set to the number of entries 88 * in the directory plus two (. ..) 89 */ 90 set_nlink(inode, 1); 91 } else if (!S_ISDIR(inode->i_mode)) 92 return -ESTALE; 93 inode->i_mode = mode; 94 } else if (SHFL_IS_SYMLINK(attr->mode)) { 95 if (sbi->o.fmode_set) 96 mode = sbi->o.fmode; 97 mode &= ~sbi->o.fmask; 98 mode |= S_IFLNK; 99 if (!reinit) { 100 inode->i_op = &vboxsf_lnk_iops; 101 set_nlink(inode, 1); 102 } else if (!S_ISLNK(inode->i_mode)) 103 return -ESTALE; 104 inode->i_mode = mode; 105 } else { 106 if (sbi->o.fmode_set) 107 mode = sbi->o.fmode; 108 mode &= ~sbi->o.fmask; 109 mode |= S_IFREG; 110 if (!reinit) { 111 inode->i_op = &vboxsf_reg_iops; 112 inode->i_fop = &vboxsf_reg_fops; 113 set_nlink(inode, 1); 114 } else if (!S_ISREG(inode->i_mode)) 115 return -ESTALE; 116 inode->i_mode = mode; 117 } 118 119 inode->i_uid = sbi->o.uid; 120 inode->i_gid = sbi->o.gid; 121 122 inode->i_size = info->size; 123 inode->i_blkbits = 12; 124 /* i_blocks always in units of 512 bytes! */ 125 allocated = info->allocated + 511; 126 do_div(allocated, 512); 127 inode->i_blocks = allocated; 128 129 inode_set_atime_to_ts(inode, 130 ns_to_timespec64(info->access_time.ns_relative_to_unix_epoch)); 131 inode_set_ctime_to_ts(inode, 132 ns_to_timespec64(info->change_time.ns_relative_to_unix_epoch)); 133 inode_set_mtime_to_ts(inode, 134 ns_to_timespec64(info->modification_time.ns_relative_to_unix_epoch)); 135 return 0; 136 } 137 138 int vboxsf_create_at_dentry(struct dentry *dentry, 139 struct shfl_createparms *params) 140 { 141 struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); 142 struct shfl_string *path; 143 int err; 144 145 path = vboxsf_path_from_dentry(sbi, dentry); 146 if (IS_ERR(path)) 147 return PTR_ERR(path); 148 149 err = vboxsf_create(sbi->root, path, params); 150 __putname(path); 151 152 return err; 153 } 154 155 int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, 156 struct shfl_fsobjinfo *info) 157 { 158 struct shfl_createparms params = {}; 159 int err; 160 161 params.handle = SHFL_HANDLE_NIL; 162 params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; 163 164 err = vboxsf_create(sbi->root, path, ¶ms); 165 if (err) 166 return err; 167 168 if (params.result != SHFL_FILE_EXISTS) 169 return -ENOENT; 170 171 if (info) 172 *info = params.info; 173 174 return 0; 175 } 176 177 int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info) 178 { 179 struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); 180 struct shfl_string *path; 181 int err; 182 183 path = vboxsf_path_from_dentry(sbi, dentry); 184 if (IS_ERR(path)) 185 return PTR_ERR(path); 186 187 err = vboxsf_stat(sbi, path, info); 188 __putname(path); 189 return err; 190 } 191 192 int vboxsf_inode_revalidate(struct dentry *dentry) 193 { 194 struct vboxsf_sbi *sbi; 195 struct vboxsf_inode *sf_i; 196 struct shfl_fsobjinfo info; 197 struct timespec64 mtime, prev_mtime; 198 struct inode *inode; 199 int err; 200 201 if (!dentry || !d_really_is_positive(dentry)) 202 return -EINVAL; 203 204 inode = d_inode(dentry); 205 prev_mtime = inode_get_mtime(inode); 206 sf_i = VBOXSF_I(inode); 207 sbi = VBOXSF_SBI(dentry->d_sb); 208 if (!sf_i->force_restat) { 209 if (time_before(jiffies, dentry->d_time + sbi->o.ttl)) 210 return 0; 211 } 212 213 err = vboxsf_stat_dentry(dentry, &info); 214 if (err) 215 return err; 216 217 dentry->d_time = jiffies; 218 sf_i->force_restat = 0; 219 err = vboxsf_init_inode(sbi, inode, &info, true); 220 if (err) 221 return err; 222 223 /* 224 * If the file was changed on the host side we need to invalidate the 225 * page-cache for it. Note this also gets triggered by our own writes, 226 * this is unavoidable. 227 */ 228 mtime = inode_get_mtime(inode); 229 if (timespec64_compare(&mtime, &prev_mtime) > 0) 230 invalidate_inode_pages2(inode->i_mapping); 231 232 return 0; 233 } 234 235 int vboxsf_getattr(struct mnt_idmap *idmap, const struct path *path, 236 struct kstat *kstat, u32 request_mask, unsigned int flags) 237 { 238 int err; 239 struct dentry *dentry = path->dentry; 240 struct inode *inode = d_inode(dentry); 241 struct vboxsf_inode *sf_i = VBOXSF_I(inode); 242 243 switch (flags & AT_STATX_SYNC_TYPE) { 244 case AT_STATX_DONT_SYNC: 245 err = 0; 246 break; 247 case AT_STATX_FORCE_SYNC: 248 sf_i->force_restat = 1; 249 fallthrough; 250 default: 251 err = vboxsf_inode_revalidate(dentry); 252 } 253 if (err) 254 return err; 255 256 generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), kstat); 257 return 0; 258 } 259 260 int vboxsf_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 261 struct iattr *iattr) 262 { 263 struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry)); 264 struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); 265 struct shfl_createparms params = {}; 266 struct shfl_fsobjinfo info = {}; 267 u32 buf_len; 268 int err; 269 270 params.handle = SHFL_HANDLE_NIL; 271 params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS | 272 SHFL_CF_ACT_FAIL_IF_NEW | 273 SHFL_CF_ACCESS_ATTR_WRITE; 274 275 /* this is at least required for Posix hosts */ 276 if (iattr->ia_valid & ATTR_SIZE) 277 params.create_flags |= SHFL_CF_ACCESS_WRITE; 278 279 err = vboxsf_create_at_dentry(dentry, ¶ms); 280 if (err || params.result != SHFL_FILE_EXISTS) 281 return err ? err : -ENOENT; 282 283 #define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0) 284 285 /* 286 * Setting the file size and setting the other attributes has to 287 * be handled separately. 288 */ 289 if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) { 290 if (iattr->ia_valid & ATTR_MODE) { 291 info.attr.mode = mode_set(IRUSR); 292 info.attr.mode |= mode_set(IWUSR); 293 info.attr.mode |= mode_set(IXUSR); 294 info.attr.mode |= mode_set(IRGRP); 295 info.attr.mode |= mode_set(IWGRP); 296 info.attr.mode |= mode_set(IXGRP); 297 info.attr.mode |= mode_set(IROTH); 298 info.attr.mode |= mode_set(IWOTH); 299 info.attr.mode |= mode_set(IXOTH); 300 301 if (iattr->ia_mode & S_IFDIR) 302 info.attr.mode |= SHFL_TYPE_DIRECTORY; 303 else 304 info.attr.mode |= SHFL_TYPE_FILE; 305 } 306 307 if (iattr->ia_valid & ATTR_ATIME) 308 info.access_time.ns_relative_to_unix_epoch = 309 timespec64_to_ns(&iattr->ia_atime); 310 311 if (iattr->ia_valid & ATTR_MTIME) 312 info.modification_time.ns_relative_to_unix_epoch = 313 timespec64_to_ns(&iattr->ia_mtime); 314 315 /* 316 * Ignore ctime (inode change time) as it can't be set 317 * from userland anyway. 318 */ 319 320 buf_len = sizeof(info); 321 err = vboxsf_fsinfo(sbi->root, params.handle, 322 SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len, 323 &info); 324 if (err) { 325 vboxsf_close(sbi->root, params.handle); 326 return err; 327 } 328 329 /* the host may have given us different attr then requested */ 330 sf_i->force_restat = 1; 331 } 332 333 #undef mode_set 334 335 if (iattr->ia_valid & ATTR_SIZE) { 336 memset(&info, 0, sizeof(info)); 337 info.size = iattr->ia_size; 338 buf_len = sizeof(info); 339 err = vboxsf_fsinfo(sbi->root, params.handle, 340 SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len, 341 &info); 342 if (err) { 343 vboxsf_close(sbi->root, params.handle); 344 return err; 345 } 346 347 /* the host may have given us different attr then requested */ 348 sf_i->force_restat = 1; 349 } 350 351 vboxsf_close(sbi->root, params.handle); 352 353 /* Update the inode with what the host has actually given us. */ 354 if (sf_i->force_restat) 355 vboxsf_inode_revalidate(dentry); 356 357 return 0; 358 } 359 360 /* 361 * [dentry] contains string encoded in coding system that corresponds 362 * to [sbi]->nls, we must convert it to UTF8 here. 363 * Returns a shfl_string allocated through __getname (must be freed using 364 * __putname), or an ERR_PTR on error. 365 */ 366 struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi, 367 struct dentry *dentry) 368 { 369 struct shfl_string *shfl_path; 370 int path_len, out_len, nb; 371 char *buf, *path; 372 wchar_t uni; 373 u8 *out; 374 375 buf = __getname(); 376 if (!buf) 377 return ERR_PTR(-ENOMEM); 378 379 path = dentry_path_raw(dentry, buf, PATH_MAX); 380 if (IS_ERR(path)) { 381 __putname(buf); 382 return ERR_CAST(path); 383 } 384 path_len = strlen(path); 385 386 if (sbi->nls) { 387 shfl_path = __getname(); 388 if (!shfl_path) { 389 __putname(buf); 390 return ERR_PTR(-ENOMEM); 391 } 392 393 out = shfl_path->string.utf8; 394 out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1; 395 396 while (path_len) { 397 nb = sbi->nls->char2uni(path, path_len, &uni); 398 if (nb < 0) { 399 __putname(shfl_path); 400 __putname(buf); 401 return ERR_PTR(-EINVAL); 402 } 403 path += nb; 404 path_len -= nb; 405 406 nb = utf32_to_utf8(uni, out, out_len); 407 if (nb < 0) { 408 __putname(shfl_path); 409 __putname(buf); 410 return ERR_PTR(-ENAMETOOLONG); 411 } 412 out += nb; 413 out_len -= nb; 414 } 415 *out = 0; 416 shfl_path->length = out - shfl_path->string.utf8; 417 shfl_path->size = shfl_path->length + 1; 418 __putname(buf); 419 } else { 420 if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) { 421 __putname(buf); 422 return ERR_PTR(-ENAMETOOLONG); 423 } 424 /* 425 * dentry_path stores the name at the end of buf, but the 426 * shfl_string string we return must be properly aligned. 427 */ 428 shfl_path = (struct shfl_string *)buf; 429 memmove(shfl_path->string.utf8, path, path_len); 430 shfl_path->string.utf8[path_len] = 0; 431 shfl_path->length = path_len; 432 shfl_path->size = path_len + 1; 433 } 434 435 return shfl_path; 436 } 437 438 int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len, 439 const unsigned char *utf8_name, size_t utf8_len) 440 { 441 const char *in; 442 char *out; 443 size_t out_bound_len; 444 size_t in_bound_len; 445 446 in = utf8_name; 447 in_bound_len = utf8_len; 448 449 out = name; 450 /* Reserve space for terminating 0 */ 451 out_bound_len = name_bound_len - 1; 452 453 while (in_bound_len) { 454 int nb; 455 unicode_t uni; 456 457 nb = utf8_to_utf32(in, in_bound_len, &uni); 458 if (nb < 0) 459 return -EINVAL; 460 461 in += nb; 462 in_bound_len -= nb; 463 464 nb = sbi->nls->uni2char(uni, out, out_bound_len); 465 if (nb < 0) 466 return nb; 467 468 out += nb; 469 out_bound_len -= nb; 470 } 471 472 *out = 0; 473 474 return 0; 475 } 476 477 static struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list) 478 { 479 struct vboxsf_dir_buf *b; 480 481 b = kmalloc(sizeof(*b), GFP_KERNEL); 482 if (!b) 483 return NULL; 484 485 b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL); 486 if (!b->buf) { 487 kfree(b); 488 return NULL; 489 } 490 491 b->entries = 0; 492 b->used = 0; 493 b->free = DIR_BUFFER_SIZE; 494 list_add(&b->head, list); 495 496 return b; 497 } 498 499 static void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b) 500 { 501 list_del(&b->head); 502 kfree(b->buf); 503 kfree(b); 504 } 505 506 struct vboxsf_dir_info *vboxsf_dir_info_alloc(void) 507 { 508 struct vboxsf_dir_info *p; 509 510 p = kmalloc(sizeof(*p), GFP_KERNEL); 511 if (!p) 512 return NULL; 513 514 INIT_LIST_HEAD(&p->info_list); 515 return p; 516 } 517 518 void vboxsf_dir_info_free(struct vboxsf_dir_info *p) 519 { 520 struct list_head *list, *pos, *tmp; 521 522 list = &p->info_list; 523 list_for_each_safe(pos, tmp, list) { 524 struct vboxsf_dir_buf *b; 525 526 b = list_entry(pos, struct vboxsf_dir_buf, head); 527 vboxsf_dir_buf_free(b); 528 } 529 kfree(p); 530 } 531 532 int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d, 533 u64 handle) 534 { 535 struct vboxsf_dir_buf *b; 536 u32 entries, size; 537 int err = 0; 538 void *buf; 539 540 /* vboxsf_dirinfo returns 1 on end of dir */ 541 while (err == 0) { 542 b = vboxsf_dir_buf_alloc(&sf_d->info_list); 543 if (!b) { 544 err = -ENOMEM; 545 break; 546 } 547 548 buf = b->buf; 549 size = b->free; 550 551 err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0, 552 &size, buf, &entries); 553 if (err < 0) 554 break; 555 556 b->entries += entries; 557 b->free -= size; 558 b->used += size; 559 } 560 561 if (b && b->used == 0) 562 vboxsf_dir_buf_free(b); 563 564 /* -EILSEQ means the host could not translate a filename, ignore */ 565 if (err > 0 || err == -EILSEQ) 566 err = 0; 567 568 return err; 569 } 570
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.