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