1 2 #include "fsdriver.h" 3 #include <minix/ds.h> 4 #include <sys/mman.h> 5 6 static int fsdriver_vmcache; /* have we used the VM cache? */ 7 8 /* 9 * Process a READSUPER request from VFS. 10 */ 11 int 12 fsdriver_readsuper(const struct fsdriver * __restrict fdp, 13 const message * __restrict m_in, message * __restrict m_out) 14 { 15 struct fsdriver_node root_node; 16 char label[DS_MAX_KEYLEN]; 17 cp_grant_id_t label_grant; 18 size_t label_len; 19 unsigned int flags, res_flags; 20 dev_t dev; 21 int r; 22 23 dev = m_in->m_vfs_fs_readsuper.device; 24 label_grant = m_in->m_vfs_fs_readsuper.grant; 25 label_len = m_in->m_vfs_fs_readsuper.path_len; 26 flags = m_in->m_vfs_fs_readsuper.flags; 27 28 if (fdp->fdr_mount == NULL) 29 return ENOSYS; 30 31 if (fsdriver_mounted) { 32 printf("fsdriver: attempt to mount multiple times\n"); 33 return EBUSY; 34 } 35 36 if ((r = fsdriver_getname(m_in->m_source, label_grant, label_len, 37 label, sizeof(label), FALSE /*not_empty*/)) != OK) 38 return r; 39 40 if (fdp->fdr_driver != NULL) 41 fdp->fdr_driver(dev, label); 42 43 res_flags = RES_NOFLAGS; 44 45 r = fdp->fdr_mount(dev, flags, &root_node, &res_flags); 46 47 if (r == OK) { 48 /* This one we can set on the file system's behalf. */ 49 if ((fdp->fdr_peek != NULL && fdp->fdr_bpeek != NULL) || 50 major(dev) == NONE_MAJOR) 51 res_flags |= RES_HASPEEK; 52 53 m_out->m_fs_vfs_readsuper.inode = root_node.fn_ino_nr; 54 m_out->m_fs_vfs_readsuper.mode = root_node.fn_mode; 55 m_out->m_fs_vfs_readsuper.file_size = root_node.fn_size; 56 m_out->m_fs_vfs_readsuper.uid = root_node.fn_uid; 57 m_out->m_fs_vfs_readsuper.gid = root_node.fn_gid; 58 m_out->m_fs_vfs_readsuper.flags = res_flags; 59 60 /* Update library-local state. */ 61 fsdriver_mounted = TRUE; 62 fsdriver_device = dev; 63 fsdriver_root = root_node.fn_ino_nr; 64 fsdriver_vmcache = FALSE; 65 } 66 67 return r; 68 } 69 70 /* 71 * Process an UNMOUNT request from VFS. 72 */ 73 int 74 fsdriver_unmount(const struct fsdriver * __restrict fdp, 75 const message * __restrict __unused m_in, 76 message * __restrict __unused m_out) 77 { 78 79 if (fdp->fdr_unmount != NULL) 80 fdp->fdr_unmount(); 81 82 /* If we used mmap emulation, clear any cached blocks from VM. */ 83 if (fsdriver_vmcache) 84 vm_clear_cache(fsdriver_device); 85 86 /* Update library-local state. */ 87 fsdriver_mounted = FALSE; 88 89 return OK; 90 } 91 92 /* 93 * Process a PUTNODE request from VFS. 94 */ 95 int 96 fsdriver_putnode(const struct fsdriver * __restrict fdp, 97 const message * __restrict m_in, message * __restrict __unused m_out) 98 { 99 ino_t ino_nr; 100 unsigned int count; 101 102 ino_nr = m_in->m_vfs_fs_putnode.inode; 103 count = m_in->m_vfs_fs_putnode.count; 104 105 if (count == 0 || count > INT_MAX) { 106 printf("fsdriver: invalid reference count\n"); 107 return EINVAL; 108 } 109 110 if (fdp->fdr_putnode != NULL) 111 return fdp->fdr_putnode(ino_nr, count); 112 else 113 return OK; 114 } 115 116 /* 117 * Process a NEWNODE request from VFS. 118 */ 119 int 120 fsdriver_newnode(const struct fsdriver * __restrict fdp, 121 const message * __restrict m_in, message * __restrict m_out) 122 { 123 struct fsdriver_node node; 124 mode_t mode; 125 uid_t uid; 126 gid_t gid; 127 dev_t dev; 128 int r; 129 130 mode = m_in->m_vfs_fs_newnode.mode; 131 uid = m_in->m_vfs_fs_newnode.uid; 132 gid = m_in->m_vfs_fs_newnode.gid; 133 dev = m_in->m_vfs_fs_newnode.device; 134 135 if (fdp->fdr_newnode == NULL) 136 return ENOSYS; 137 138 if ((r = fdp->fdr_newnode(mode, uid, gid, dev, &node)) == OK) { 139 m_out->m_fs_vfs_newnode.inode = node.fn_ino_nr; 140 m_out->m_fs_vfs_newnode.mode = node.fn_mode; 141 m_out->m_fs_vfs_newnode.file_size = node.fn_size; 142 m_out->m_fs_vfs_newnode.uid = node.fn_uid; 143 m_out->m_fs_vfs_newnode.gid = node.fn_gid; 144 m_out->m_fs_vfs_newnode.device = node.fn_dev; 145 } 146 147 return r; 148 } 149 150 /* 151 * Process a read or write request from VFS. 152 */ 153 static int 154 read_write(const struct fsdriver * __restrict fdp, 155 const message * __restrict m_in, message * __restrict m_out, int call) 156 { 157 struct fsdriver_data data; 158 ino_t ino_nr; 159 off_t pos; 160 size_t nbytes; 161 ssize_t r; 162 163 ino_nr = m_in->m_vfs_fs_readwrite.inode; 164 pos = m_in->m_vfs_fs_readwrite.seek_pos; 165 nbytes = m_in->m_vfs_fs_readwrite.nbytes; 166 167 if (pos < 0 || nbytes > SSIZE_MAX) 168 return EINVAL; 169 170 data.endpt = m_in->m_source; 171 data.grant = m_in->m_vfs_fs_readwrite.grant; 172 data.size = nbytes; 173 174 if (call == FSC_WRITE) 175 r = fdp->fdr_write(ino_nr, &data, nbytes, pos, call); 176 else 177 r = fdp->fdr_read(ino_nr, &data, nbytes, pos, call); 178 179 if (r >= 0) { 180 pos += r; 181 182 m_out->m_fs_vfs_readwrite.seek_pos = pos; 183 m_out->m_fs_vfs_readwrite.nbytes = r; 184 r = OK; 185 } 186 187 return r; 188 } 189 190 /* 191 * Process a READ request from VFS. 192 */ 193 int 194 fsdriver_read(const struct fsdriver * __restrict fdp, 195 const message * __restrict m_in, message * __restrict m_out) 196 { 197 198 if (fdp->fdr_read == NULL) 199 return ENOSYS; 200 201 return read_write(fdp, m_in, m_out, FSC_READ); 202 } 203 204 /* 205 * Process a WRITE request from VFS. 206 */ 207 int 208 fsdriver_write(const struct fsdriver * __restrict fdp, 209 const message * __restrict m_in, message * __restrict m_out) 210 { 211 212 if (fdp->fdr_write == NULL) 213 return ENOSYS; 214 215 return read_write(fdp, m_in, m_out, FSC_WRITE); 216 } 217 218 /* 219 * A read-based peek implementation. This allows file systems that do not have 220 * a buffer cache and do not implement peek, to support a limited form of mmap. 221 * We map in a block, fill it by calling the file system's read function, tell 222 * VM about the page, and then unmap the block again. We tell VM not to cache 223 * the block beyond its immediate use for the mmap request, so as to prevent 224 * potentially stale data from being cached--at the cost of performance. 225 */ 226 static ssize_t 227 builtin_peek(const struct fsdriver * __restrict fdp, ino_t ino_nr, 228 size_t nbytes, off_t pos) 229 { 230 static u32_t flags = 0; /* storage for the VMMC_ flags of all blocks */ 231 static off_t dev_off = 0; /* fake device offset, see below */ 232 struct fsdriver_data data; 233 char *buf; 234 ssize_t r; 235 236 if ((buf = mmap(NULL, nbytes, PROT_READ | PROT_WRITE, 237 MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) 238 return ENOMEM; 239 240 data.endpt = SELF; 241 data.grant = (cp_grant_id_t)buf; 242 data.size = nbytes; 243 244 r = fdp->fdr_read(ino_nr, &data, nbytes, pos, FSC_READ); 245 246 if (r >= 0) { 247 if ((size_t)r < nbytes) 248 memset(&buf[r], 0, nbytes - r); 249 250 /* 251 * VM uses serialized communication to VFS. Since the page is 252 * to be used only once, VM will use and then discard it before 253 * sending a new peek request. Thus, it should be safe to 254 * reuse the same device offset all the time. However, relying 255 * on assumptions in protocols elsewhere a bit dangerous, so we 256 * use an ever-increasing device offset just to be safe. 257 */ 258 r = vm_set_cacheblock(buf, fsdriver_device, dev_off, ino_nr, 259 pos, &flags, nbytes, VMSF_ONCE); 260 261 if (r == OK) { 262 fsdriver_vmcache = TRUE; 263 264 dev_off += nbytes; 265 266 r = nbytes; 267 } 268 } 269 270 munmap(buf, nbytes); 271 272 return r; 273 } 274 275 /* 276 * Process a PEEK request from VFS. 277 */ 278 int 279 fsdriver_peek(const struct fsdriver * __restrict fdp, 280 const message * __restrict m_in, message * __restrict __unused m_out) 281 { 282 ino_t ino_nr; 283 off_t pos; 284 size_t nbytes; 285 ssize_t r; 286 287 ino_nr = m_in->m_vfs_fs_readwrite.inode; 288 pos = m_in->m_vfs_fs_readwrite.seek_pos; 289 nbytes = m_in->m_vfs_fs_readwrite.nbytes; 290 291 if (pos < 0 || nbytes > SSIZE_MAX) 292 return EINVAL; 293 294 if (fdp->fdr_peek == NULL) { 295 if (major(fsdriver_device) != NONE_MAJOR) 296 return ENOSYS; 297 298 /* 299 * For file systems that have no backing device, emulate peek 300 * support by reading into temporary buffers and passing these 301 * to VM. 302 */ 303 r = builtin_peek(fdp, ino_nr, nbytes, pos); 304 } else 305 r = fdp->fdr_peek(ino_nr, NULL /*data*/, nbytes, pos, 306 FSC_PEEK); 307 308 /* Do not return a new position. */ 309 if (r >= 0) { 310 m_out->m_fs_vfs_readwrite.nbytes = r; 311 r = OK; 312 } 313 314 return r; 315 } 316 317 /* 318 * Process a GETDENTS request from VFS. 319 */ 320 int 321 fsdriver_getdents(const struct fsdriver * __restrict fdp, 322 const message * __restrict m_in, message * __restrict m_out) 323 { 324 struct fsdriver_data data; 325 ino_t ino_nr; 326 off_t pos; 327 size_t nbytes; 328 ssize_t r; 329 330 ino_nr = m_in->m_vfs_fs_getdents.inode; 331 pos = m_in->m_vfs_fs_getdents.seek_pos; 332 nbytes = m_in->m_vfs_fs_getdents.mem_size; 333 334 if (fdp->fdr_getdents == NULL) 335 return ENOSYS; 336 337 if (pos < 0 || nbytes > SSIZE_MAX) 338 return EINVAL; 339 340 data.endpt = m_in->m_source; 341 data.grant = m_in->m_vfs_fs_getdents.grant; 342 data.size = nbytes; 343 344 r = fdp->fdr_getdents(ino_nr, &data, nbytes, &pos); 345 346 if (r >= 0) { 347 m_out->m_fs_vfs_getdents.seek_pos = pos; 348 m_out->m_fs_vfs_getdents.nbytes = r; 349 r = OK; 350 } 351 352 return r; 353 } 354 355 /* 356 * Process a FTRUNC request from VFS. 357 */ 358 int 359 fsdriver_trunc(const struct fsdriver * __restrict fdp, 360 const message * __restrict m_in, message * __restrict __unused m_out) 361 { 362 ino_t ino_nr; 363 off_t start_pos, end_pos; 364 365 ino_nr = m_in->m_vfs_fs_ftrunc.inode; 366 start_pos = m_in->m_vfs_fs_ftrunc.trc_start; 367 end_pos = m_in->m_vfs_fs_ftrunc.trc_end; 368 369 if (start_pos < 0 || end_pos < 0) 370 return EINVAL; 371 372 if (fdp->fdr_trunc == NULL) 373 return ENOSYS; 374 375 return fdp->fdr_trunc(ino_nr, start_pos, end_pos); 376 } 377 378 /* 379 * Process a INHIBREAD request from VFS. 380 */ 381 int 382 fsdriver_inhibread(const struct fsdriver * __restrict fdp, 383 const message * __restrict m_in, message * __restrict __unused m_out) 384 { 385 ino_t ino_nr; 386 387 ino_nr = m_in->m_vfs_fs_inhibread.inode; 388 389 if (fdp->fdr_seek != NULL) 390 fdp->fdr_seek(ino_nr); 391 392 return OK; 393 } 394 395 /* 396 * Process a CREATE request from VFS. 397 */ 398 int 399 fsdriver_create(const struct fsdriver * __restrict fdp, 400 const message * __restrict m_in, message * __restrict m_out) 401 { 402 struct fsdriver_node node; 403 char name[NAME_MAX+1]; 404 cp_grant_id_t grant; 405 size_t len; 406 ino_t dir_nr; 407 mode_t mode; 408 uid_t uid; 409 gid_t gid; 410 int r; 411 412 grant = m_in->m_vfs_fs_create.grant; 413 len = m_in->m_vfs_fs_create.path_len; 414 dir_nr = m_in->m_vfs_fs_create.inode; 415 mode = m_in->m_vfs_fs_create.mode; 416 uid = m_in->m_vfs_fs_create.uid; 417 gid = m_in->m_vfs_fs_create.gid; 418 419 if (fdp->fdr_create == NULL) 420 return ENOSYS; 421 422 if ((r = fsdriver_getname(m_in->m_source, grant, len, name, 423 sizeof(name), TRUE /*not_empty*/)) != OK) 424 return r; 425 426 if (!strcmp(name, ".") || !strcmp(name, "..")) 427 return EEXIST; 428 429 if ((r = fdp->fdr_create(dir_nr, name, mode, uid, gid, &node)) == OK) { 430 m_out->m_fs_vfs_create.inode = node.fn_ino_nr; 431 m_out->m_fs_vfs_create.mode = node.fn_mode; 432 m_out->m_fs_vfs_create.file_size = node.fn_size; 433 m_out->m_fs_vfs_create.uid = node.fn_uid; 434 m_out->m_fs_vfs_create.gid = node.fn_gid; 435 } 436 437 return r; 438 } 439 440 /* 441 * Process a MKDIR request from VFS. 442 */ 443 int 444 fsdriver_mkdir(const struct fsdriver * __restrict fdp, 445 const message * __restrict m_in, message * __restrict __unused m_out) 446 { 447 char name[NAME_MAX+1]; 448 cp_grant_id_t grant; 449 size_t path_len; 450 ino_t dir_nr; 451 mode_t mode; 452 uid_t uid; 453 gid_t gid; 454 int r; 455 456 grant = m_in->m_vfs_fs_mkdir.grant; 457 path_len = m_in->m_vfs_fs_mkdir.path_len; 458 dir_nr = m_in->m_vfs_fs_mkdir.inode; 459 mode = m_in->m_vfs_fs_mkdir.mode; 460 uid = m_in->m_vfs_fs_mkdir.uid; 461 gid = m_in->m_vfs_fs_mkdir.gid; 462 463 if (fdp->fdr_mkdir == NULL) 464 return ENOSYS; 465 466 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name, 467 sizeof(name), TRUE /*not_empty*/)) != OK) 468 return r; 469 470 if (!strcmp(name, ".") || !strcmp(name, "..")) 471 return EEXIST; 472 473 return fdp->fdr_mkdir(dir_nr, name, mode, uid, gid); 474 } 475 476 /* 477 * Process a MKNOD request from VFS. 478 */ 479 int 480 fsdriver_mknod(const struct fsdriver * __restrict fdp, 481 const message * __restrict m_in, message * __restrict __unused m_out) 482 { 483 char name[NAME_MAX+1]; 484 cp_grant_id_t grant; 485 size_t path_len; 486 ino_t dir_nr; 487 mode_t mode; 488 uid_t uid; 489 gid_t gid; 490 dev_t dev; 491 int r; 492 493 grant = m_in->m_vfs_fs_mknod.grant; 494 path_len = m_in->m_vfs_fs_mknod.path_len; 495 dir_nr = m_in->m_vfs_fs_mknod.inode; 496 mode = m_in->m_vfs_fs_mknod.mode; 497 uid = m_in->m_vfs_fs_mknod.uid; 498 gid = m_in->m_vfs_fs_mknod.gid; 499 dev = m_in->m_vfs_fs_mknod.device; 500 501 if (fdp->fdr_mknod == NULL) 502 return ENOSYS; 503 504 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name, 505 sizeof(name), TRUE /*not_empty*/)) != OK) 506 return r; 507 508 if (!strcmp(name, ".") || !strcmp(name, "..")) 509 return EEXIST; 510 511 return fdp->fdr_mknod(dir_nr, name, mode, uid, gid, dev); 512 } 513 514 /* 515 * Process a LINK request from VFS. 516 */ 517 int 518 fsdriver_link(const struct fsdriver * __restrict fdp, 519 const message * __restrict m_in, message * __restrict __unused m_out) 520 { 521 char name[NAME_MAX+1]; 522 cp_grant_id_t grant; 523 size_t path_len; 524 ino_t dir_nr, ino_nr; 525 int r; 526 527 grant = m_in->m_vfs_fs_link.grant; 528 path_len = m_in->m_vfs_fs_link.path_len; 529 dir_nr = m_in->m_vfs_fs_link.dir_ino; 530 ino_nr = m_in->m_vfs_fs_link.inode; 531 532 if (fdp->fdr_link == NULL) 533 return ENOSYS; 534 535 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name, 536 sizeof(name), TRUE /*not_empty*/)) != OK) 537 return r; 538 539 if (!strcmp(name, ".") || !strcmp(name, "..")) 540 return EEXIST; 541 542 return fdp->fdr_link(dir_nr, name, ino_nr); 543 } 544 545 /* 546 * Process an UNLINK request from VFS. 547 */ 548 int 549 fsdriver_unlink(const struct fsdriver * __restrict fdp, 550 const message * __restrict m_in, message * __restrict __unused m_out) 551 { 552 char name[NAME_MAX+1]; 553 cp_grant_id_t grant; 554 size_t path_len; 555 ino_t dir_nr; 556 int r; 557 558 grant = m_in->m_vfs_fs_unlink.grant; 559 path_len = m_in->m_vfs_fs_unlink.path_len; 560 dir_nr = m_in->m_vfs_fs_unlink.inode; 561 562 if (fdp->fdr_unlink == NULL) 563 return ENOSYS; 564 565 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name, 566 sizeof(name), TRUE /*not_empty*/)) != OK) 567 return r; 568 569 if (!strcmp(name, ".") || !strcmp(name, "..")) 570 return EPERM; 571 572 return fdp->fdr_unlink(dir_nr, name, FSC_UNLINK); 573 } 574 575 /* 576 * Process a RMDIR request from VFS. 577 */ 578 int 579 fsdriver_rmdir(const struct fsdriver * __restrict fdp, 580 const message * __restrict m_in, message * __restrict __unused m_out) 581 { 582 char name[NAME_MAX+1]; 583 cp_grant_id_t grant; 584 size_t path_len; 585 ino_t dir_nr; 586 int r; 587 588 grant = m_in->m_vfs_fs_unlink.grant; 589 path_len = m_in->m_vfs_fs_unlink.path_len; 590 dir_nr = m_in->m_vfs_fs_unlink.inode; 591 592 if (fdp->fdr_rmdir == NULL) 593 return ENOSYS; 594 595 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name, 596 sizeof(name), TRUE /*not_empty*/)) != OK) 597 return r; 598 599 if (!strcmp(name, ".")) 600 return EINVAL; 601 602 if (!strcmp(name, "..")) 603 return ENOTEMPTY; 604 605 return fdp->fdr_rmdir(dir_nr, name, FSC_RMDIR); 606 } 607 608 /* 609 * Process a RENAME request from VFS. 610 */ 611 int 612 fsdriver_rename(const struct fsdriver * __restrict fdp, 613 const message * __restrict m_in, message * __restrict __unused m_out) 614 { 615 char old_name[NAME_MAX+1], new_name[NAME_MAX+1]; 616 cp_grant_id_t old_grant, new_grant; 617 size_t old_len, new_len; 618 ino_t old_dir_nr, new_dir_nr; 619 int r; 620 621 old_grant = m_in->m_vfs_fs_rename.grant_old; 622 old_len = m_in->m_vfs_fs_rename.len_old; 623 old_dir_nr = m_in->m_vfs_fs_rename.dir_old; 624 new_grant = m_in->m_vfs_fs_rename.grant_new; 625 new_len = m_in->m_vfs_fs_rename.len_new; 626 new_dir_nr = m_in->m_vfs_fs_rename.dir_new; 627 628 if (fdp->fdr_rename == NULL) 629 return ENOSYS; 630 631 if ((r = fsdriver_getname(m_in->m_source, old_grant, old_len, old_name, 632 sizeof(old_name), TRUE /*not_empty*/)) != OK) 633 return r; 634 635 if (!strcmp(old_name, ".") || !strcmp(old_name, "..")) 636 return EINVAL; 637 638 if ((r = fsdriver_getname(m_in->m_source, new_grant, new_len, new_name, 639 sizeof(new_name), TRUE /*not_empty*/)) != OK) 640 return r; 641 642 if (!strcmp(new_name, ".") || !strcmp(new_name, "..")) 643 return EINVAL; 644 645 return fdp->fdr_rename(old_dir_nr, old_name, new_dir_nr, new_name); 646 } 647 648 /* 649 * Process a SLINK request from VFS. 650 */ 651 int 652 fsdriver_slink(const struct fsdriver * __restrict fdp, 653 const message * __restrict m_in, message * __restrict __unused m_out) 654 { 655 struct fsdriver_data data; 656 char name[NAME_MAX+1]; 657 cp_grant_id_t grant; 658 size_t path_len; 659 ino_t dir_nr; 660 uid_t uid; 661 gid_t gid; 662 int r; 663 664 grant = m_in->m_vfs_fs_slink.grant_path; 665 path_len = m_in->m_vfs_fs_slink.path_len; 666 dir_nr = m_in->m_vfs_fs_slink.inode; 667 uid = m_in->m_vfs_fs_slink.uid; 668 gid = m_in->m_vfs_fs_slink.gid; 669 670 if (fdp->fdr_slink == NULL) 671 return ENOSYS; 672 673 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name, 674 sizeof(name), TRUE /*not_empty*/)) != OK) 675 return r; 676 677 if (!strcmp(name, ".") || !strcmp(name, "..")) 678 return EEXIST; 679 680 data.endpt = m_in->m_source; 681 data.grant = m_in->m_vfs_fs_slink.grant_target; 682 data.size = m_in->m_vfs_fs_slink.mem_size; 683 684 return fdp->fdr_slink(dir_nr, name, uid, gid, &data, data.size); 685 } 686 687 /* 688 * Process a RDLINK request from VFS. 689 */ 690 int 691 fsdriver_rdlink(const struct fsdriver * __restrict fdp, 692 const message * __restrict m_in, message * __restrict m_out) 693 { 694 struct fsdriver_data data; 695 ssize_t r; 696 697 if (fdp->fdr_rdlink == NULL) 698 return ENOSYS; 699 700 data.endpt = m_in->m_source; 701 data.grant = m_in->m_vfs_fs_rdlink.grant; 702 data.size = m_in->m_vfs_fs_rdlink.mem_size; 703 704 r = fdp->fdr_rdlink(m_in->m_vfs_fs_rdlink.inode, &data, data.size); 705 706 if (r >= 0) { 707 m_out->m_fs_vfs_rdlink.nbytes = r; 708 r = OK; 709 } 710 711 return r; 712 } 713 714 /* 715 * Process a STAT request from VFS. 716 */ 717 int 718 fsdriver_stat(const struct fsdriver * __restrict fdp, 719 const message * __restrict m_in, message * __restrict __unused m_out) 720 { 721 struct stat buf; 722 cp_grant_id_t grant; 723 ino_t ino_nr; 724 int r; 725 726 ino_nr = m_in->m_vfs_fs_stat.inode; 727 grant = m_in->m_vfs_fs_stat.grant; 728 729 if (fdp->fdr_stat == NULL) 730 return ENOSYS; 731 732 memset(&buf, 0, sizeof(buf)); 733 buf.st_dev = fsdriver_device; 734 buf.st_ino = ino_nr; 735 736 if ((r = fdp->fdr_stat(ino_nr, &buf)) == OK) 737 r = sys_safecopyto(m_in->m_source, grant, 0, (vir_bytes)&buf, 738 (phys_bytes)sizeof(buf)); 739 740 return r; 741 } 742 743 /* 744 * Process a CHOWN request from VFS. 745 */ 746 int 747 fsdriver_chown(const struct fsdriver * __restrict fdp, 748 const message * __restrict m_in, message * __restrict m_out) 749 { 750 ino_t ino_nr; 751 uid_t uid; 752 gid_t gid; 753 mode_t mode; 754 int r; 755 756 ino_nr = m_in->m_vfs_fs_chown.inode; 757 uid = m_in->m_vfs_fs_chown.uid; 758 gid = m_in->m_vfs_fs_chown.gid; 759 760 if (fdp->fdr_chown == NULL) 761 return ENOSYS; 762 763 if ((r = fdp->fdr_chown(ino_nr, uid, gid, &mode)) == OK) 764 m_out->m_fs_vfs_chown.mode = mode; 765 766 return r; 767 } 768 769 /* 770 * Process a CHMOD request from VFS. 771 */ 772 int 773 fsdriver_chmod(const struct fsdriver * __restrict fdp, 774 const message * __restrict m_in, message * __restrict m_out) 775 { 776 ino_t ino_nr; 777 mode_t mode; 778 int r; 779 780 ino_nr = m_in->m_vfs_fs_chmod.inode; 781 mode = m_in->m_vfs_fs_chmod.mode; 782 783 if (fdp->fdr_chmod == NULL) 784 return ENOSYS; 785 786 if ((r = fdp->fdr_chmod(ino_nr, &mode)) == OK) 787 m_out->m_fs_vfs_chmod.mode = mode; 788 789 return r; 790 } 791 792 /* 793 * Process a UTIME request from VFS. 794 */ 795 int 796 fsdriver_utime(const struct fsdriver * __restrict fdp, 797 const message * __restrict m_in, message * __restrict __unused m_out) 798 { 799 ino_t ino_nr; 800 struct timespec atime, mtime; 801 802 ino_nr = m_in->m_vfs_fs_utime.inode; 803 atime.tv_sec = m_in->m_vfs_fs_utime.actime; 804 atime.tv_nsec = m_in->m_vfs_fs_utime.acnsec; 805 mtime.tv_sec = m_in->m_vfs_fs_utime.modtime; 806 mtime.tv_nsec = m_in->m_vfs_fs_utime.modnsec; 807 808 if (fdp->fdr_utime == NULL) 809 return ENOSYS; 810 811 return fdp->fdr_utime(ino_nr, &atime, &mtime); 812 } 813 814 /* 815 * Process a MOUNTPOINT request from VFS. 816 */ 817 int 818 fsdriver_mountpoint(const struct fsdriver * __restrict fdp, 819 const message * __restrict m_in, message * __restrict __unused m_out) 820 { 821 ino_t ino_nr; 822 823 ino_nr = m_in->m_vfs_fs_mountpoint.inode; 824 825 if (fdp->fdr_mountpt == NULL) 826 return ENOSYS; 827 828 return fdp->fdr_mountpt(ino_nr); 829 } 830 831 /* 832 * Process a STATVFS request from VFS. 833 */ 834 int 835 fsdriver_statvfs(const struct fsdriver * __restrict fdp, 836 const message * __restrict m_in, message * __restrict __unused m_out) 837 { 838 struct statvfs buf; 839 int r; 840 841 if (fdp->fdr_statvfs == NULL) 842 return ENOSYS; 843 844 memset(&buf, 0, sizeof(buf)); 845 846 if ((r = fdp->fdr_statvfs(&buf)) != OK) 847 return r; 848 849 return sys_safecopyto(m_in->m_source, m_in->m_vfs_fs_statvfs.grant, 0, 850 (vir_bytes)&buf, (phys_bytes)sizeof(buf)); 851 } 852 853 /* 854 * Process a SYNC request from VFS. 855 */ 856 int 857 fsdriver_sync(const struct fsdriver * __restrict fdp, 858 const message * __restrict __unused m_in, 859 message * __restrict __unused m_out) 860 { 861 862 if (fdp->fdr_sync != NULL) 863 fdp->fdr_sync(); 864 865 return OK; 866 } 867 868 /* 869 * Process a NEW_DRIVER request from VFS. 870 */ 871 int 872 fsdriver_newdriver(const struct fsdriver * __restrict fdp, 873 const message * __restrict m_in, message * __restrict __unused m_out) 874 { 875 char label[DS_MAX_KEYLEN]; 876 cp_grant_id_t grant; 877 size_t path_len; 878 dev_t dev; 879 int r; 880 881 dev = m_in->m_vfs_fs_new_driver.device; 882 grant = m_in->m_vfs_fs_new_driver.grant; 883 path_len = m_in->m_vfs_fs_new_driver.path_len; 884 885 if (fdp->fdr_driver == NULL) 886 return OK; 887 888 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, label, 889 sizeof(label), FALSE /*not_empty*/)) != OK) 890 return r; 891 892 fdp->fdr_driver(dev, label); 893 894 return OK; 895 } 896 897 /* 898 * Process a block read or write request from VFS. 899 */ 900 static ssize_t 901 bread_bwrite(const struct fsdriver * __restrict fdp, 902 const message * __restrict m_in, message * __restrict m_out, int call) 903 { 904 struct fsdriver_data data; 905 dev_t dev; 906 off_t pos; 907 size_t nbytes; 908 ssize_t r; 909 910 dev = m_in->m_vfs_fs_breadwrite.device; 911 pos = m_in->m_vfs_fs_breadwrite.seek_pos; 912 nbytes = m_in->m_vfs_fs_breadwrite.nbytes; 913 914 if (pos < 0 || nbytes > SSIZE_MAX) 915 return EINVAL; 916 917 data.endpt = m_in->m_source; 918 data.grant = m_in->m_vfs_fs_breadwrite.grant; 919 data.size = nbytes; 920 921 if (call == FSC_WRITE) 922 r = fdp->fdr_bwrite(dev, &data, nbytes, pos, call); 923 else 924 r = fdp->fdr_bread(dev, &data, nbytes, pos, call); 925 926 if (r >= 0) { 927 pos += r; 928 929 m_out->m_fs_vfs_breadwrite.seek_pos = pos; 930 m_out->m_fs_vfs_breadwrite.nbytes = r; 931 r = OK; 932 } 933 934 return r; 935 } 936 937 /* 938 * Process a BREAD request from VFS. 939 */ 940 ssize_t 941 fsdriver_bread(const struct fsdriver * __restrict fdp, 942 const message * __restrict m_in, message * __restrict m_out) 943 { 944 945 if (fdp->fdr_bread == NULL) 946 return ENOSYS; 947 948 return bread_bwrite(fdp, m_in, m_out, FSC_READ); 949 } 950 951 /* 952 * Process a BWRITE request from VFS. 953 */ 954 ssize_t 955 fsdriver_bwrite(const struct fsdriver * __restrict fdp, 956 const message * __restrict m_in, message * __restrict m_out) 957 { 958 959 if (fdp->fdr_bwrite == NULL) 960 return ENOSYS; 961 962 return bread_bwrite(fdp, m_in, m_out, FSC_WRITE); 963 } 964 965 /* 966 * Process a BPEEK request from VFS. 967 */ 968 int 969 fsdriver_bpeek(const struct fsdriver * __restrict fdp, 970 const message * __restrict m_in, message * __restrict __unused m_out) 971 { 972 dev_t dev; 973 off_t pos; 974 size_t nbytes; 975 ssize_t r; 976 977 dev = m_in->m_vfs_fs_breadwrite.device; 978 pos = m_in->m_vfs_fs_breadwrite.seek_pos; 979 nbytes = m_in->m_vfs_fs_breadwrite.nbytes; 980 981 if (fdp->fdr_bpeek == NULL) 982 return ENOSYS; 983 984 if (pos < 0 || nbytes > SSIZE_MAX) 985 return EINVAL; 986 987 r = fdp->fdr_bpeek(dev, NULL /*data*/, nbytes, pos, FSC_PEEK); 988 989 /* Do not return a new position. */ 990 if (r >= 0) { 991 m_out->m_fs_vfs_breadwrite.nbytes = r; 992 r = OK; 993 } 994 995 return r; 996 } 997 998 /* 999 * Process a FLUSH request from VFS. 1000 */ 1001 int 1002 fsdriver_flush(const struct fsdriver * __restrict fdp, 1003 const message * __restrict m_in, message * __restrict __unused m_out) 1004 { 1005 dev_t dev; 1006 1007 dev = m_in->m_vfs_fs_flush.device; 1008 1009 if (fdp->fdr_bflush != NULL) 1010 fdp->fdr_bflush(dev); 1011 1012 return OK; 1013 } 1014