1#define _BUILDING_fs 1 2 3#include "betalk.h" 4#include "nfs_add_on.h" 5 6#ifndef BONE_VERSION 7#include "ksocket.h" 8#else 9#include <sys/socket_module.h> 10#endif 11 12#include <errno.h> 13#include <string.h> 14#include <KernelExport.h> 15#include <sys/stat.h> 16#include <dirent.h> 17#include <SupportDefs.h> 18 19 20_EXPORT vnode_ops fs_entry = 21{ 22 (op_read_vnode *) &fs_read_vnode, 23 (op_write_vnode *) &fs_write_vnode, 24 (op_remove_vnode *) &fs_remove_vnode, 25 (op_secure_vnode *) &fs_secure_vnode, 26 (op_walk *) &fs_walk, 27 (op_access *) &fs_access, 28 (op_create *) &fs_create, 29 (op_mkdir *) &fs_mkdir, 30 (op_symlink *) &fs_symlink, 31 NULL, // &fs_link, 32 (op_rename *) &fs_rename, 33 (op_unlink *) &fs_unlink, 34 (op_rmdir *) &fs_rmdir, 35 (op_readlink *) &fs_readlink, 36 (op_opendir *) &fs_opendir, 37 (op_closedir *) &fs_closedir, 38 (op_free_cookie *) &fs_free_dircookie, 39 (op_rewinddir *) &fs_rewinddir, 40 (op_readdir *) &fs_readdir, 41 (op_open *) &fs_open, 42 (op_close *) &fs_close, 43 (op_free_cookie *) &fs_free_cookie, 44 (op_read *) &fs_read, 45 (op_write *) &fs_write, 46 NULL, // &fs_readv 47 NULL, // &fs_writev 48 NULL, // &fs_ioctl, 49 NULL, // &fs_setflags, 50 (op_rstat *) &fs_rstat, 51 (op_wstat *) &fs_wstat, 52 NULL, // &fs_fsync, 53 NULL, // &fs_initialize, 54 (op_mount *) &fs_mount, 55 (op_unmount *) &fs_unmount, 56 NULL, // &fs_sync, 57 (op_rfsstat *) &fs_rfsstat, 58 (op_wfsstat *) &fs_wfsstat, 59 NULL, // &fs_select 60 NULL, // &fs_deselect 61 (op_open_indexdir *) &fs_open_indexdir, 62 (op_close_indexdir *) &fs_close_indexdir, 63 (op_free_cookie *) &fs_free_indexdircookie, 64 (op_rewind_indexdir *) &fs_rewind_indexdir, 65 (op_read_indexdir *) &fs_read_indexdir, 66 (op_create_index *) &fsCreateIndex, 67 (op_remove_index *) &fsRemoveIndex, 68 NULL, // &fs_rename_index, 69 (op_stat_index *) &fsStatIndex, 70 (op_open_attrdir *) &fs_open_attribdir, 71 (op_close_attrdir *) &fs_close_attribdir, 72 (op_free_cookie *) &fs_free_attribdircookie, 73 (op_rewind_attrdir *) &fs_rewind_attribdir, 74 (op_read_attrdir *) &fs_read_attribdir, 75 (op_write_attr *) &fs_write_attrib, 76 (op_read_attr *) &fs_read_attrib, 77 (op_remove_attr *) &fs_remove_attrib, 78 NULL, // &fs_rename_attrib, 79 (op_stat_attr *) &fs_stat_attrib, 80 (op_open_query *) &fsOpenQuery, 81 (op_close_query *) &fsCloseQuery, 82 (op_free_cookie *) &fsFreeQueryCookie, 83 (op_read_query *) &fsReadQuery 84}; 85 86_EXPORT int32 api_version = B_CUR_FS_API_VERSION; 87 88#ifdef BONE_VERSION 89 90struct bone_socket_info *bone_module = NULL; 91 92// bone_init() 93// 94bool bone_init() 95{ 96 // Get a pointer to the BONE module. 97 get_module(BONE_SOCKET_MODULE, (module_info **) &bone_module); 98 return (bone_module != NULL); 99} 100 101// bone_cleanup() 102// 103void bone_cleanup() 104{ 105 put_module(BONE_SOCKET_MODULE); 106} 107#endif 108 109fs_node *create_node(fs_nspace *ns, vnode_id dir_vnid, const char *name, vnode_id file_vnid, bool newVnid) 110{ 111 fs_node *newNode, *dupNode; 112 bool obsolete_nodes = false; 113 114 while (acquire_sem(ns->sem) == B_INTERRUPTED); 115 116 // Check to see if we find a node with this vnid. If we do, we need to know if it 117 // is the same file. This can be determined by examining the parent directory vnid 118 // and the filename. If everything matches, just return that node. 119 dupNode = getDuplicateVnid(ns, file_vnid); 120 if (dupNode) 121 { 122 // If it looks like this vnid, smells like this vnid, and tastes like this vnid, 123 // it must be this vnid. Alright, there's one exception -- symbolic links. These 124 // have the same vnid, but another name. 125 if (dupNode->parent == dir_vnid) 126 if (strcmp(dupNode->name, name) == 0) 127 { 128 release_sem(ns->sem); 129 return dupNode; 130 } 131 132 // If we still found a vnid, but the parent directory vnid or filename don't 133 // match, then the original file is gone and another file has taken this vnid. 134 // Another user caused this change, which isn't registered with the local 135 // system's vnid table. In this case we adjust our internal node, and notify 136 // any listeners that the file has been renamed. Note that if this is the user 137 // that renamed the file, a duplicate notify_listener() call will be made by 138 // fs_rename(), but this seems to have no adverse effect. 139 dprintf("DUP VNID: %s, %s\n", name, dupNode->name); 140// dprintf("notify_listener(B_ENTRY_MOVED, %s, %lu); -- duplicate vnid notice\n", name, file_vnid); 141// notify_listener(B_ENTRY_MOVED, ns->nsid, dupNode->parent, dir_vnid, file_vnid, name); 142// dupNode->parent = dir_vnid; 143// strcpy(dupNode->name, name); 144// release_sem(ns->sem); 145// return dupNode; 146 } 147 148 // Well, we now know we have a unique vnid. However, it is possible that the same 149 // file exists in our list under a different vnid. If a file is deleted, then re-created 150 // by another user and assigned a different vnid, then our existing vnid is obsolete 151 // and we must abandon it in favor of the replacement. Are we having fun yet? 152 dupNode = getDuplicateName(ns, dir_vnid, name); 153 if (dupNode) 154 if (dupNode->vnid != file_vnid) 155 { 156 dprintf("DUP NAME: %s (%lu)\n", dupNode->name, dupNode->vnid); 157 remove_obsolete_node(ns, dupNode); 158 obsolete_nodes = true; 159 } 160 161 newNode = (fs_node *) malloc(sizeof(fs_node)); 162 if (newNode) 163 { 164 // Initialize the members of this new node. 165 newNode->parent = dir_vnid; 166 strcpy(newNode->name, name); 167 newNode->vnid = file_vnid; 168 169 // Link the node in the list by making it the head. 170 newNode->next = ns->first; 171 ns->first = newNode; 172 173 // If we're creating a new file, or we just had to delete our old vnid-cookie pair 174 // above, then we need to register this vnid with the newly created node. 175 if (newVnid || obsolete_nodes) 176 new_vnode(ns->nsid, file_vnid, newNode); 177 178 dprintf("NEW NODE: %s (%lu)\n", name, file_vnid); 179// print_vnode_list(ns); 180 } 181 182 release_sem(ns->sem); 183 184 if (obsolete_nodes) 185 notify_listener(B_ENTRY_CREATED, ns->nsid, dir_vnid, 0, file_vnid, name); 186 187 return newNode; 188} 189 190void print_vnode_list(fs_nspace *ns) 191{ 192 fs_node *current; 193 194 dprintf(" --- VNODE LIST --------------------------\n"); 195 current = ns->first; 196 while (current) 197 { 198 dprintf(" %-35s %lu\n", current->name, current->vnid); 199 current = current->next; 200 } 201 dprintf(" --- END OF LIST -------------------------\n"); 202} 203 204void remove_obsolete_node(fs_nspace *ns, fs_node *node) 205{ 206 release_sem(ns->sem); 207 208 remove_node(ns, node->vnid); 209 210 dprintf(" Notifying others that %s (%lu) was removed\n", node->name, node->vnid); 211 remove_vnode(ns->nsid, node->vnid); 212 put_vnode(ns->nsid, node->vnid); 213 notify_listener(B_ENTRY_REMOVED, ns->nsid, node->parent, 0, node->vnid, node->name); 214 215 while (acquire_sem(ns->sem) == B_INTERRUPTED); 216} 217 218void rename_node(fs_nspace *ns, vnode_id old_dir_vnid, const char *oldname, vnode_id new_dir_vnid, const char *newname, vnode_id file_vnid) 219{ 220 fs_node *current; 221 222 while (acquire_sem(ns->sem) == B_INTERRUPTED); 223 224 // Check to see if we find a node with this vnid. If we do, we need to know if it 225 // is the same file. This can be determined by examining the parent directory vnid 226 // and the filename. If everything matches, rename the node to the new name. 227 current = ns->first; 228 while (current) 229 { 230 if (current->vnid == file_vnid) 231 if (current->parent == old_dir_vnid) 232 if (strcmp(current->name, oldname) == 0) 233 { 234 strcpy(current->name, newname); 235 current->parent = new_dir_vnid; 236 break; 237 } 238 239 current = current->next; 240 } 241 242 release_sem(ns->sem); 243} 244 245fs_node *getDuplicateVnid(fs_nspace *ns, vnode_id vnid) 246{ 247 fs_node *current; 248 249 current = ns->first; 250 while (current && current->vnid != vnid) 251 current = current->next; 252 253 return current; 254} 255 256fs_node *getDuplicateName(fs_nspace *ns, vnode_id parent, const char *name) 257{ 258 fs_node *current; 259 260 current = ns->first; 261 while (current) 262 { 263 if (current->parent == parent) 264 if (strcmp(current->name, name) == 0) 265 break; 266 267 current = current->next; 268 } 269 270 return current; 271} 272 273void remove_node(fs_nspace *ns, vnode_id vnid) 274{ 275 fs_node *current; 276 fs_node *previous; 277 278 while (acquire_sem(ns->sem) == B_INTERRUPTED); 279 280 current = ns->first; 281 previous = NULL; 282 283 while (current && current->vnid != vnid) 284 { 285 previous = current; 286 current = current->next; 287 } 288 289 if (current) 290 { 291 if (previous) 292 previous->next = current->next; 293 else 294 ns->first = current->next; 295 296 free(current); 297 } 298 299 release_sem(ns->sem); 300} 301 302// fs_read_vnode() 303// 304// Description: Allocate resources required to load the specified vnid. Also returns 305// a reference to the vnode via the supplied pointer. 306// 307// Parameters: 308// ns (in): Private file system structure 309// vnid (in): vnid of the vnode to load 310// r (in): ?? 311// node (out): A reference to the vnode loaded 312// 313// Returns: 314// B_OK if everything is successful, or 315// EINVAL if the specified vnid is not found 316// 317extern int fs_read_vnode(fs_nspace *ns, vnode_id vnid, char r, fs_node **node) 318{ 319 fs_node *current; 320 321//dprintf("fs_read_vnode()\n"); 322 *node = NULL; 323 324 // If we need to acquire the semaphone to search the list, do so now. 325 if (!r) 326 while (acquire_sem(ns->sem) == B_INTERRUPTED); 327 328 current = ns->first; 329 while (current && current->vnid != vnid) 330 current = current->next; 331 332 // TODO: shouldn't we release the semaphore here? 333 // If the specified parameter is non-null, then return the node we found. 334 if (current && node) 335 *node = current; 336 337 // Release the semaphore if necessary. 338 if (!r) 339 release_sem(ns->sem); 340 341 return (current ? B_OK : EINVAL); 342} 343 344// fs_write_vnode() 345// 346// Description: Free resources allocated with the sister function fs_read_vnode(). 347// Parameters: 348// ns (in): Private file system structure 349// node (in): Node that can be freed 350// r (in): ?? 351// Returns: 352// B_OK if everything is successful (always in our case) 353// 354extern int fs_write_vnode(fs_nspace *ns, fs_node *node, char r) 355{ 356//dprintf("fs_write_vnode()\n"); 357 // In our case, there aren't any resources to free, so there isn't anything 358 // for this function to do but return successfully. 359 return B_OK; 360} 361 362// fs_walk() 363// 364// Description: This function is the single file system location where a path is 365// traversed by name. Given a directory handle and a file name, this function returns 366// the vnid of the file if it indeed exists. 367// 368// Parameters: 369// ns (in): Private file system structure 370// base (in): File handle of the directory to look in 371// file (in): Name of the file to look for 372// newpath (out): Name of the real file if the given file is a symbolic link 373// vnid (out): Vnid of the file given by "file" 374// 375// Returns: 376// B_OK if everything is successful, 377// Otherwise an error code detailing the problem 378// 379extern int fs_walk(fs_nspace *ns, fs_node *base, const char *file, char **newpath, vnode_id *vnid) 380{ 381 bool isLink; 382 void *dummy; 383 status_t result; 384 385//dprintf("fs_walk()\n"); 386 // If the file specified is the current directory, then that parameter provides 387 // the necessary vnid. Also note that the current directory entry cannot be a 388 // symbolic link. 389 if (!strcmp(".", file)) 390 { 391 *vnid = base->vnid; 392 isLink = false; 393 } 394 else 395 { 396 struct stat st; 397 status_t result; 398 399 // Look up the requested entry, getting the stat structure and file handle 400 // filled in. 401 if ((result = btLookup(ns, base->vnid, file, vnid, &st)) != B_OK) 402 return result; 403 404 // The vnid is the resulting file's inode. Once this is established, insert 405 // the new node in our list. 406 if (create_node(ns, base->vnid, file, *vnid, false) == NULL) 407 return ENOMEM; 408 409 isLink = S_ISLNK(st.st_mode); 410 } 411 412 if ((result = get_vnode(ns->nsid, *vnid, (void **) &dummy)) < B_OK) 413 return result; 414 415 // If we've found a symbolic link, and the supplied character pointer is non-null, 416 // then the vnode layer is looking for the actual path. 417 if (isLink && newpath) 418 { 419 char path[B_PATH_NAME_LENGTH + 1]; 420 size_t pathLen = B_PATH_NAME_LENGTH; 421 422 if ((result = fs_readlink(ns, dummy, path, &pathLen)) < B_OK) 423 { 424 put_vnode(ns->nsid, *vnid); 425 return result; 426 } 427 428 path[pathLen] = 0; 429 result = new_path(path, newpath); 430 431 if (result < B_OK) 432 { 433 put_vnode(ns->nsid, *vnid); 434 return result; 435 } 436 437 return put_vnode(ns->nsid, *vnid); 438 } 439 440 return B_OK; 441} 442 443// fs_opendir() 444// 445extern int fs_opendir(fs_nspace *ns, fs_node *node, btCookie **cookie) 446{ 447 struct stat st; 448 status_t result; 449 450//dprintf("fs_opendir()\n"); 451 // Do a basic stat() on this file to verify we indeed have a directory. 452 // If we cannot obtain this information, we have an even bigger problem. 453 if ((result = btStat(ns, node->vnid, &st)) < B_OK) 454 return result; 455 456 // Now that we have the right information, verify we're looking at a directory. 457 if (!S_ISDIR(st.st_mode)) 458 return ENOTDIR; 459 460 // Allocate and initialize the cookie. 461 *cookie = (btCookie *) malloc(sizeof(btCookie)); 462 if (!*cookie) 463 return ENOMEM; 464 465 memset((*cookie)->opaque, 0, BT_COOKIE_SIZE); 466 (*cookie)->lpbCache = false; 467 (*cookie)->eof = false; 468 469 return B_OK; 470} 471 472// fs_closedir() 473// 474extern int fs_closedir(fs_nspace *ns, fs_node *node, btCookie *cookie) 475{ 476//dprintf("fs_closedir()\n"); 477 btEmptyLPBCache(cookie); 478 return B_OK; 479} 480 481// fs_rewinddir() 482// 483extern int fs_rewinddir(fs_nspace *ns, fs_node *node, btCookie *cookie) 484{ 485//dprintf("fs_rewinddir()\n"); 486 memset(cookie->opaque, 0, BT_COOKIE_SIZE); 487 cookie->eof = false; 488 btEmptyLPBCache(cookie); 489 return B_OK; 490} 491 492// fs_readdir() 493// 494extern int fs_readdir(fs_nspace *ns, fs_node *node, btCookie *cookie, long *num, struct dirent *buf, size_t bufsize) 495{ 496 status_t result; 497 vnode_id vnid; 498 char *filename; 499 long max, bufContent; 500 int32 value; 501 502//dprintf("fs_readdir()\n"); 503 max = *num; 504 *num = 0; 505 506 // Cause the directory to be read. 507 while ((result = btReadDir(ns, node->vnid, &vnid, &filename, cookie)) == B_OK) 508 { 509 if (strcmp(filename, ".") && strcmp(filename, "..")) 510 { 511 create_node(ns, node->vnid, filename, vnid, false); 512 513// dirCount = bufsize / sizeof(struct dirent); 514// pktCount = BT_MAX_IO_BUFFER / sizeof(struct dirent); 515// dirCount = min((), ()); 516 517 bufContent = 2 * (sizeof(dev_t) + sizeof(ino_t)) + sizeof(unsigned short) + strlen(filename) + 1; 518 if (bufsize < bufContent) 519 return B_OK; 520 521 buf->d_dev = ns->nsid; 522 buf->d_pdev = ns->nsid; 523 buf->d_ino = vnid; 524 buf->d_pino = node->vnid; 525 buf->d_reclen = bufContent; 526 strcpy(buf->d_name, filename); 527 528 bufsize -= bufContent; 529 buf = (struct dirent *)((char *) buf + bufContent); 530 531 (*num)++; 532 } 533 534 free(filename); 535 536 if (*num == max) 537 return B_OK; 538 } 539 540 return B_OK; 541} 542 543// fs_free_dircookie() 544// 545extern int fs_free_dircookie(fs_nspace *ns, fs_node *node, btCookie *cookie) 546{ 547//dprintf("fs_free_dircookie()\n"); 548 if (cookie) 549 { 550 btEmptyLPBCache(cookie); 551 free(cookie); 552 } 553 554 return B_OK; 555} 556 557// fs_rstat() 558// 559extern int fs_rstat(fs_nspace *ns, fs_node *node, struct stat *st) 560{ 561 status_t result; 562 563//dprintf("fs_rstat()\n"); 564 if ((result = btStat(ns, node->vnid, st)) < B_OK) 565 return result; 566 567 st->st_dev = ns->nsid; 568 return B_OK; 569} 570 571// fs_mount() 572// 573extern int fs_mount(nspace_id nsid, const char *devname, ulong flags, struct mount_bt_params *parms, size_t len, fs_nspace **data, vnode_id *vnid) 574{ 575 status_t result; 576 fs_nspace *ns; 577 fs_node *rootNode; 578 struct stat st; 579 580 result = EINVAL; 581 582dprintf("fs_mount running\n"); 583 // If we didn't receive any mount parameters, we won't know the server to connect to, 584 // or the folder to be shared. 585 if (parms == NULL) 586 return EINVAL; 587 588 // Initialize the ksocket library for kernel-based network communication. 589#ifndef BONE_VERSION 590 if ((result = ksocket_init()) < B_OK) 591 return result; 592#else 593 if (!bone_init()) 594 return ENETUNREACH; 595#endif 596 597dprintf("net initialized\n"); 598 // Allocate our private file system information block. 599 ns = (fs_nspace *) malloc(sizeof(fs_nspace)); 600 ns->nsid = nsid; 601 ns->dnlcRoot = NULL; 602 603 // Copy over the parameters specified, including the server, folder, user and group 604 // IDs, and so on. 605 ns->params.serverIP = parms->serverIP; 606 ns->params.server = strdup(parms->server); 607 ns->params.export = strdup(parms->export); 608 ns->params.uid = parms->uid; 609 ns->params.gid = parms->gid; 610 ns->params.hostname = strdup(parms->hostname); 611 ns->params.folder = strdup(parms->folder); 612 613 // The password is a binary token that is of fixed length, but can contain null characters. 614 // A strdup() therefore won't capture the entire string. Manually copying the data is the 615 // only reliable way. 616 strcpy(ns->params.user, parms->user); 617 memcpy(ns->params.password, parms->password, BT_AUTH_TOKEN_LENGTH); 618 ns->params.password[BT_AUTH_TOKEN_LENGTH] = 0; 619 620 // Now connect to the remote server. The socket returned will be used for all future 621 // communication with that server. 622 ns->s = btConnect(ns, ns->params.serverIP, BT_TCPIP_PORT); 623 if (ns->s != INVALID_SOCKET) 624 { 625 dprintf("connection established\n"); 626 ns->xid = 0; 627 628 btRPCInit(ns); 629 630 // Create a semaphore for exclusive access to the vnode list when we need to scan 631 // for a particular vnode. 632 ns->sem = create_sem(1, "VNode List Semaphore"); 633 if (ns->sem > 0) 634 { 635 dprintf("vnode semaphore created\n"); 636 if (initManagedData(&ns->dnlcData)) 637 { 638 dprintf("managed data struct initialized\n"); 639 // The system should own this semaphore. 640 set_sem_owner(ns->sem, B_SYSTEM_TEAM); 641 642 // Allocate the root node. 643 rootNode = (fs_node *) malloc(sizeof(fs_node)); 644 rootNode->next = NULL; 645 646 // Let the server know we are mounting the exported folder. This operation 647 // will return the root node file handle. 648 result = btMount(ns, ns->params.export, ns->params.user, ns->params.password, &rootNode->vnid); 649 if (result == B_OK) 650 { 651 ns->rootid = rootNode->vnid; 652 *vnid = ns->rootid; 653 654 result = new_vnode(nsid, *vnid, rootNode); 655 if (result == B_OK) 656 { 657 *data = ns; 658 ns->first = rootNode; 659 notify_listener(B_DEVICE_MOUNTED, ns->nsid, 0, 0, 0, NULL); 660 dprintf("Mount successful."); 661 return B_OK; 662 } 663 } 664 else dprintf("Mount failed %d\n", result); 665 666 // We've failed. The first step is to free the root node we allocated, and 667 // release the semaphore we created as well. 668 free(rootNode); 669 closeManagedData(&ns->dnlcData); 670 } 671 672 delete_sem(ns->sem); 673 } 674 675 // Disconnect from the server. 676 btDisconnect(ns); 677 btRPCClose(ns); 678 } 679 else 680 result = EHOSTUNREACH; 681 682 // De-allocate our private file system structure and all the string space we duplicated 683 // on startup. 684 free(ns->params.hostname); 685 free(ns->params.folder); 686 free(ns->params.export); 687 free(ns->params.server); 688 free(ns); 689 690#ifndef BONE_VERSION 691 ksocket_cleanup(); 692#else 693 bone_cleanup(); 694#endif 695 696 return result; 697} 698 699extern int fs_unmount(fs_nspace *ns) 700{ 701//dprintf("fs_unmount()\n"); 702 notify_listener(B_DEVICE_UNMOUNTED, ns->nsid, 0, 0, 0, NULL); 703 704 btDisconnect(ns); 705 btRPCClose(ns); 706 707 free(ns->params.hostname); 708 free(ns->params.folder); 709 free(ns->params.export); 710 free(ns->params.server); 711 712 while (acquire_sem(ns->sem) == B_INTERRUPTED); 713 714 while (ns->first) 715 { 716 fs_node *next = ns->first->next; 717 free(ns->first); 718 ns->first = next; 719 } 720 721 release_sem(ns->sem); 722 delete_sem(ns->sem); 723 724 ns->s = INVALID_SOCKET; 725 free(ns); 726 727#ifndef BONE_VERSION 728 ksocket_cleanup(); 729#else 730 bone_cleanup(); 731#endif 732 733 return B_OK; 734} 735 736// fs_rfsstat() 737// 738extern int fs_rfsstat(fs_nspace *ns, struct fs_info *info) 739{ 740 bt_fsinfo fsinfo; 741 int result; 742 743//dprintf("fs_rfsstat()\n"); 744 result = btGetFSInfo(ns, ns->rootid, &fsinfo); 745 if (result == B_OK) 746 { 747 info->dev = ns->nsid; 748 info->root = ns->rootid; 749 info->flags = B_FS_IS_SHARED | B_FS_IS_PERSISTENT | 750 B_FS_HAS_MIME | B_FS_HAS_ATTR | B_FS_HAS_QUERY; 751 info->block_size = fsinfo.blockSize; 752 info->io_size = 8192; 753 info->total_blocks = fsinfo.totalBlocks; 754 info->free_blocks = fsinfo.freeBlocks; 755 info->total_nodes = 0; 756 info->free_nodes = 0; 757 strcpy(info->device_name, "BeServed Shared Volume"); 758 strcpy(info->volume_name, ns->params.folder); 759 strcpy(info->fsh_name, ""); 760 } 761 762 return result; 763} 764 765// fs_open() 766// 767extern int fs_open(fs_nspace *ns, fs_node *node, int omode, fs_file_cookie **cookie) 768{ 769 struct stat st; 770 status_t result; 771 772//dprintf("fs_open()\n"); 773 if ((result = btStat(ns, node->vnid, &st)) < B_OK) 774 return result; 775 776 if (S_ISDIR(st.st_mode)) 777 { 778 *cookie = NULL; 779 return B_OK; // permit opening of directories 780 } 781 782 *cookie = (fs_file_cookie *) malloc(sizeof(fs_file_cookie)); 783 (*cookie)->omode = omode; 784 (*cookie)->original_size = st.st_size; 785 (*cookie)->st = st; 786 787 return B_OK; 788} 789 790// fs_close() 791// 792extern int fs_close(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie) 793{ 794//dprintf("fs_close()\n"); 795 if (cookie && (cookie->omode & O_RDWR || cookie->omode & O_WRONLY)) 796 return notify_listener(B_STAT_CHANGED, ns->nsid, 0, 0, node->vnid, NULL); 797 798 return B_OK; 799} 800 801// fs_free_cookie() 802// 803extern int fs_free_cookie(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie) 804{ 805//dprintf("fs_free_cookie()\n"); 806 if (cookie) 807 free(cookie); 808 809 return B_OK; 810} 811 812// fs_read() 813// 814extern int fs_read(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, void *buf, size_t *len) 815{ 816//dprintf("fs_read()\n"); 817 if (!len) 818 return B_ERROR; 819 820 // If we weren't given proper file system or vnode pointers, something is awry. 821 if (!ns || !node || !buf) 822 return B_ERROR; 823 824 // Do not permit reading directories. 825 if (!cookie) 826 return EISDIR; 827 828 *len = btRead(ns, node->vnid, pos, *len, buf); 829 830 return B_OK; 831} 832 833extern int fs_write(fs_nspace *ns, fs_node *node, fs_file_cookie *cookie, off_t pos, const void *buf, size_t *len) 834{ 835//dprintf("fs_write()\n"); 836 // Do not permit writing directories. 837 if (!cookie) 838 return EISDIR; 839 840 if (cookie->omode & O_APPEND) 841 pos += cookie->original_size; 842 843 *len = btWrite(ns, node->vnid, pos, *len, buf); 844 btStat(ns, node->vnid, &cookie->st); 845 846 return B_OK; 847} 848 849extern int fs_wstat(fs_nspace *ns, fs_node *node, struct stat *st, long mask) 850{ 851 int error; 852 853//dprintf("fs_wstat()\n"); 854 error = btWStat(ns, node->vnid, st, mask); 855 if (error != B_OK) 856 return error; 857 858 return notify_listener(B_STAT_CHANGED, ns->nsid, 0, 0, node->vnid, NULL); 859} 860 861extern int fs_wfsstat(fs_nspace *ns, struct fs_info *info, long mask) 862{ 863//dprintf("fs_wfsstat()\n"); 864 return B_OK; 865} 866 867extern int fs_create(fs_nspace *ns, fs_node *dir, const char *name, int omode, int perms, vnode_id *vnid, 868 fs_file_cookie **cookie) 869{ 870 struct stat st; 871 status_t result; 872 int error; 873 874//dprintf("fs_create()\n"); 875 result = btLookup(ns, dir->vnid, name, vnid, &st); 876 877 if (result == B_OK) 878 { 879 void *dummy; 880 create_node(ns, dir->vnid, name, *vnid, false); 881 882 if ((result = get_vnode(ns->nsid, *vnid, (void **) &dummy)) < B_OK) 883 return result; 884 885 if (S_ISDIR(st.st_mode)) 886 return EISDIR; 887 888 if (omode & O_EXCL) 889 return EEXIST; 890 891 if (omode & O_TRUNC) 892 if ((result = btTruncate(ns, *vnid, 0L)) < B_OK) 893 return result; 894 895 *cookie = (fs_file_cookie *) malloc(sizeof(fs_file_cookie)); 896 (*cookie)->omode = omode; 897 (*cookie)->original_size = st.st_size; 898 (*cookie)->st = st; 899 900 return B_OK; 901 } 902 else if (result != ENOENT) 903 return result; 904 else 905 { 906 uint8 *replyBuf; 907 int32 status; 908 fs_node *newNode; 909 910 if (!(omode & O_CREAT)) 911 return ENOENT; 912 913 error = btCreate(ns, dir->vnid, name, vnid, omode, perms, &st); 914 if (error != B_OK) 915 return error; 916 917 newNode = create_node(ns, dir->vnid, name, *vnid, true); 918 919 *cookie = (fs_file_cookie *) malloc(sizeof(fs_file_cookie)); 920 (*cookie)->omode = omode; 921 (*cookie)->original_size = st.st_size; 922 (*cookie)->st = st; 923 924 return notify_listener(B_ENTRY_CREATED, ns->nsid, dir->vnid, 0, *vnid, name); 925 } 926} 927 928extern int fs_unlink(fs_nspace *ns, fs_node *dir, const char *name) 929{ 930 fs_node *newNode; 931 fs_node *dummy; 932 struct stat st; 933 vnode_id vnid; 934 int error; 935 936//dprintf("fs_unlink()\n"); 937 error = btLookup(ns, dir->vnid, name, &vnid, &st); 938 if (error != B_OK) 939 return error; 940 941 create_node(ns, dir->vnid, name, vnid, false); 942 943 error = get_vnode(ns->nsid, vnid, (void **) &dummy); 944 if (error != B_OK) 945 return error; 946 947 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) 948 return EISDIR; 949 950 error = remove_vnode(ns->nsid, vnid); 951 if (error != B_OK) 952 return error; 953 954 error = put_vnode(ns->nsid, vnid); 955 if (error != B_OK) 956 return error; 957 958 error = btUnlink(ns, dir->vnid, name); 959 if (error != B_OK) 960 return error; 961 962 return notify_listener(B_ENTRY_REMOVED, ns->nsid, dir->vnid, 0, vnid, name); 963} 964 965extern int fs_remove_vnode(fs_nspace *ns, fs_node *node, char r) 966{ 967//dprintf("fs_remove_vnode()\n"); 968 remove_node(ns, node->vnid); 969 return B_OK; 970} 971 972// fs_secure_vnode() 973// 974// Description: Given a node, this function determines whether the user has the 975// required permission to access it. This is currently unimplemented in BFS, and 976// we consequently dismiss it here as well. 977// 978extern int fs_secure_vnode(fs_nspace *ns, fs_node *node) 979{ 980//dprintf("fs_secure_vnode()\n"); 981 return B_OK; 982} 983 984extern int fs_mkdir(fs_nspace *ns, fs_node *dir, const char *name, int perms) 985{ 986 fs_node *newNode; 987 struct stat st; 988 vnode_id vnid; 989 int error; 990 991//dprintf("fs_mkdir()\n"); 992 error = btLookup(ns, dir->vnid, name, &vnid, &st); 993 if (error == B_OK) 994 { 995 void *dummy; 996 error = get_vnode(ns->nsid, vnid, (void **) &dummy); 997 if (error != B_OK) 998 return error; 999 1000 return EEXIST; 1001 } 1002 else if (error != ENOENT) 1003 return error; 1004 1005 error = btCreateDir(ns, dir->vnid, name, perms | S_IFDIR, &vnid, &st); 1006 if (error != B_OK) 1007 return error; 1008 1009 create_node(ns, dir->vnid, name, vnid, false); 1010 return notify_listener(B_ENTRY_CREATED, ns->nsid, dir->vnid, 0, vnid, name); 1011} 1012 1013extern int fs_rename(fs_nspace *ns, fs_node *olddir, const char *oldname, fs_node *newdir, const char *newname) 1014{ 1015 struct stat st; 1016 fs_node *oldNode; 1017 vnode_id vnid; 1018 int error; 1019 1020//dprintf("fs_rename()\n"); 1021 error = btLookup(ns, newdir->vnid, newname, &vnid, &st); 1022 if (error == B_OK) 1023 { 1024 if (S_ISREG(st.st_mode)) 1025 error = fs_unlink(ns, newdir, newname); 1026 else 1027 error = fs_rmdir(ns, newdir, newname); 1028 1029 if (error != B_OK) 1030 return error; 1031 } 1032 1033 error = btLookup(ns, olddir->vnid, oldname, &vnid, &st); 1034 if (error != B_OK) 1035 return error; 1036 1037 error = btRename(ns, olddir->vnid, oldname, newdir->vnid, newname); 1038 if (error != B_OK) 1039 return error; 1040 1041 rename_node(ns, olddir->vnid, oldname, newdir->vnid, newname, vnid); 1042 1043 return notify_listener(B_ENTRY_MOVED, ns->nsid, olddir->vnid, newdir->vnid, vnid, newname); 1044} 1045 1046extern int fs_rmdir(fs_nspace *ns, fs_node *dir, const char *name) 1047{ 1048 fs_node *newNode; 1049 fs_node *dummy; 1050 vnode_id vnid; 1051 struct stat st; 1052 int error; 1053 1054//dprintf("fs_rmdir()\n"); 1055 error = btLookup(ns, dir->vnid, name, &vnid, &st); 1056 if (error != B_OK) 1057 return error; 1058 1059 create_node(ns, dir->vnid, name, vnid, false); 1060 1061 error = get_vnode(ns->nsid, vnid, (void **) &dummy); 1062 if (error != B_OK) 1063 return error; 1064 1065 if (!S_ISDIR(st.st_mode)) 1066 return ENOTDIR; 1067 1068 error = remove_vnode(ns->nsid, vnid); 1069 if (error != B_OK) 1070 return error; 1071 1072 error = put_vnode(ns->nsid, vnid); 1073 if (error != B_OK) 1074 return error; 1075 1076 error = btDeleteDir(ns, dir->vnid, name); 1077 if (error != B_OK) 1078 return error; 1079 1080 return notify_listener(B_ENTRY_REMOVED, ns->nsid, dir->vnid, 0, vnid, name); 1081} 1082 1083extern int fs_readlink(fs_nspace *ns, fs_node *node, char *buf, size_t *bufsize) 1084{ 1085//dprintf("fs_readlink()\n"); 1086 return btReadLink(ns, node->vnid, buf, bufsize); 1087} 1088 1089extern int fs_symlink(fs_nspace *ns, fs_node *dir, const char *name, const char *path) 1090{ 1091 struct stat st; 1092 vnode_id vnid; 1093 int error; 1094 1095//dprintf("fs_symlink()\n"); 1096 error = btLookup(ns, dir->vnid, name, &vnid, &st); 1097 if (error == B_OK) 1098 { 1099 void *dummy; 1100 if ((error = get_vnode(ns->nsid, vnid, (void **) &dummy)) < B_OK) 1101 return error; 1102 1103 return EEXIST; 1104 } 1105 else if (error != ENOENT) 1106 return error; 1107 1108 error = btSymLink(ns, dir->vnid, name, path); 1109 if (error != B_OK) 1110 return error; 1111 1112 error = btLookup(ns, dir->vnid, name, &vnid, &st); 1113 if (error != B_OK) 1114 return error; 1115 1116 create_node(ns, dir->vnid, name, vnid, false); 1117 1118 error = notify_listener(B_ENTRY_CREATED, ns->nsid, dir->vnid, 0, vnid, name); 1119 return error; 1120} 1121 1122// fs_access() 1123// 1124// Description: This function implements the access() system call. 1125// 1126int fs_access(void *ns, void *node, int mode) 1127{ 1128//dprintf("fs_access()\n"); 1129 return B_OK; 1130} 1131 1132int fs_read_attrib(fs_nspace *ns, fs_node *node, const char *name, int type, void *buf, size_t *len, off_t pos) 1133{ 1134 int bytes; 1135 1136 // Automatically deny reading Tracker attributes. 1137//dprintf("fs_read_attrib()\n"); 1138 if (strncmp(name, "_trk/", 5) == 0) 1139 { 1140 errno = B_ENTRY_NOT_FOUND; 1141 return -1; 1142 } 1143 1144 bytes = btReadAttrib(ns, node->vnid, name, type, buf, *len, pos); 1145 if (bytes == -1) 1146 return -1; 1147 1148 *len = bytes; 1149 return B_OK; 1150} 1151 1152int fs_write_attrib(fs_nspace *ns, fs_node *node, const char *name, int type, const void *buf, size_t *len, off_t pos) 1153{ 1154 int bytes; 1155 1156//dprintf("fs_write_attrib()\n"); 1157 // Automatically deny reading Tracker attributes. 1158 if (strncmp(name, "_trk/", 5) == 0) 1159 { 1160 errno = B_ENTRY_NOT_FOUND; 1161 return -1; 1162 } 1163 1164 bytes = btWriteAttrib(ns, node->vnid, name, type, buf, *len, pos); 1165 if (bytes == -1) 1166 return -1; 1167 1168 *len = bytes; 1169 notify_listener(B_ATTR_CHANGED, ns->nsid, 0, 0, node->vnid, node->name); 1170 return B_OK; 1171} 1172 1173// fs_open_attribdir() 1174// 1175extern int fs_open_attribdir(fs_nspace *ns, fs_node *node, btCookie **cookie) 1176{ 1177 struct stat st; 1178 int error; 1179 1180//dprintf("fs_open_attribdir()\n"); 1181 // Do a basic stat() on this file to verify we indeed have a valid file. 1182 // If we cannot obtain this information, we have an even bigger problem. 1183 if ((error = btStat(ns, node->vnid, &st)) < B_OK) 1184 return error; 1185 1186 // Allocate and initialize the cookie. 1187 *cookie = (btCookie *) malloc(sizeof(btCookie)); 1188 if (!*cookie) 1189 return ENOMEM; 1190 1191 memset((*cookie)->opaque, 0, BT_COOKIE_SIZE); 1192 (*cookie)->lpbCache = false; 1193 (*cookie)->eof = false; 1194 1195 return B_OK; 1196} 1197 1198// fs_close_attribdir() 1199// 1200extern int fs_close_attribdir(fs_nspace *ns, fs_node *node, btCookie *cookie) 1201{ 1202//dprintf("fs_close_attribdir()\n"); 1203 btEmptyLPBCache(cookie); 1204 return B_OK; 1205} 1206 1207// fs_rewind_attribdir() 1208// 1209extern int fs_rewind_attribdir(fs_nspace *ns, fs_node *node, btCookie *cookie) 1210{ 1211//dprintf("fs_rewind_attribdir()\n"); 1212 if (cookie) 1213 { 1214 memset(cookie->opaque, 0, BT_COOKIE_SIZE); 1215 btEmptyLPBCache(cookie); 1216 cookie->eof = false; 1217 } 1218 1219 return B_OK; 1220} 1221 1222extern int fs_read_attribdir(fs_nspace *ns, fs_node *node, btCookie *cookie, long *num, struct dirent *buf, size_t bufsize) 1223{ 1224 status_t result; 1225 char *attrName; 1226 long max; 1227 1228//dprintf("fs_read_attribdir()\n"); 1229 max = *num; 1230 *num = 0; 1231 1232 // Cause the directory to be read. 1233 while ((result = btReadAttribDir(ns, node->vnid, &attrName, cookie)) == B_OK) 1234 { 1235 if (strncmp(attrName, "_trk/", 5) != 0) 1236 { 1237 if (bufsize < 2 * (sizeof(dev_t) + sizeof(ino_t)) + sizeof(unsigned short) + strlen(attrName) + 1) 1238 return B_OK; 1239 1240 buf->d_dev = 0; 1241 buf->d_pdev = 0; 1242 buf->d_ino = 0; 1243 buf->d_pino = 0; 1244 buf->d_reclen = 2 * (sizeof(dev_t) + sizeof(ino_t)) + sizeof(unsigned short) + strlen(attrName) + 1; 1245 strcpy(buf->d_name, attrName); 1246 1247 bufsize -= buf->d_reclen; 1248 buf = (struct dirent *)((char *) buf + buf->d_reclen); 1249 1250 (*num)++; 1251 } 1252 1253 free(attrName); 1254 1255 if (*num == max) 1256 break; 1257 } 1258 1259 return B_OK; 1260} 1261 1262// fs_free_attribdircookie() 1263// 1264extern int fs_free_attribdircookie(fs_nspace *ns, btCookie *cookie) 1265{ 1266//dprintf("fs_free_attribdircookie()\n"); 1267// if (cookie) 1268// { 1269// btEmptyLPBCache(cookie); 1270// free(cookie); 1271// } 1272 1273 return B_OK; 1274} 1275 1276// fs_remove_attrib() 1277// 1278extern int fs_remove_attrib(fs_nspace *ns, fs_node *node, const char *name) 1279{ 1280//dprintf("fs_remove_attrib()\n"); 1281 // Automatically deny removing Tracker attributes. 1282 if (strncmp(name, "_trk/", 5) == 0) 1283 { 1284 errno = B_ENTRY_NOT_FOUND; 1285 return -1; 1286 } 1287 1288 return btRemoveAttrib(ns, node->vnid, name); 1289} 1290 1291// fs_stat_attrib() 1292// 1293extern int fs_stat_attrib(fs_nspace *ns, fs_node *node, const char *name, struct attr_info *buf) 1294{ 1295 buf->type = 0; 1296 buf->size = 0; 1297 1298//dprintf("fs_stat_attrib()\n"); 1299 // Automatically deny reading Tracker attributes. 1300 if (strncmp(name, "_trk/", 5) == 0) 1301 { 1302 errno = B_ENTRY_NOT_FOUND; 1303 return -1; 1304 } 1305 1306 return btStatAttrib(ns, node->vnid, name, buf); 1307} 1308 1309// fs_open_indexdir() 1310// 1311extern int fs_open_indexdir(fs_nspace *ns, btCookie **cookie) 1312{ 1313//dprintf("fs_open_indexdir()\n"); 1314 // Allocate and initialize the cookie. 1315 *cookie = (btCookie *) malloc(sizeof(btCookie)); 1316 memset ((*cookie)->opaque, 0, BT_COOKIE_SIZE); 1317 (*cookie)->eof = false; 1318 1319 return B_OK; 1320} 1321 1322// fs_close_indexdir() 1323// 1324extern int fs_close_indexdir(fs_nspace *ns, btCookie *cookie) 1325{ 1326//dprintf("fs_close_indexdir()\n"); 1327 return B_OK; 1328} 1329 1330// fs_rewind_indexdir() 1331// 1332extern int fs_rewind_indexdir(fs_nspace *ns, btCookie *cookie) 1333{ 1334//dprintf("fs_rewind_indexdir()\n"); 1335 memset(cookie->opaque, 0, BT_COOKIE_SIZE); 1336 cookie->eof = false; 1337 return B_OK; 1338} 1339 1340// fs_read_indexdir() 1341// 1342extern int fs_read_indexdir(fs_nspace *ns, btCookie *cookie, long *num, struct dirent *buf, size_t bufsize) 1343{ 1344 status_t result; 1345 char indexName[100]; 1346 long max; 1347 1348//dprintf("fs_read_indexdir()\n"); 1349 max = *num; 1350 *num = 0; 1351 1352 // Cause the directory to be read. 1353 while ((result = btReadIndexDir(ns, indexName, sizeof(indexName) - 1, cookie)) == B_OK) 1354 { 1355 if (bufsize < 2 * (sizeof(dev_t) + sizeof(ino_t)) + sizeof(unsigned short) + strlen(indexName) + 1) 1356 return B_OK; 1357 1358 buf->d_dev = 0; 1359 buf->d_pdev = 0; 1360 buf->d_ino = 0; 1361 buf->d_pino = 0; 1362 buf->d_reclen = 2 * (sizeof(dev_t) + sizeof(ino_t)) + sizeof(unsigned short) + strlen(indexName) + 1; 1363 strcpy(buf->d_name, indexName); 1364 1365 bufsize -= buf->d_reclen; 1366 buf = (struct dirent *)((char *) buf + buf->d_reclen); 1367 1368 (*num)++; 1369 1370 if (*num == max) 1371 return B_OK; 1372 } 1373 1374 return B_OK; 1375} 1376 1377// fs_free_indexdircookie() 1378// 1379extern int fs_free_indexdircookie(fs_nspace *ns, btCookie *cookie) 1380{ 1381//dprintf("fs_free_indexdircookie()\n"); 1382 if (cookie) 1383 free(cookie); 1384 1385 return B_OK; 1386} 1387 1388extern int fsCreateIndex(fs_nspace *ns, const char *name, int type, int flags) 1389{ 1390//dprintf("fs_create_index()\n"); 1391 return btCreateIndex(ns, name, type, flags); 1392} 1393 1394extern int fsRemoveIndex(fs_nspace *ns, const char *name) 1395{ 1396//dprintf("fs_remove_index()\n"); 1397 return btRemoveIndex(ns, name); 1398} 1399 1400extern int fsStatIndex(fs_nspace *ns, const char *name, struct index_info *buf) 1401{ 1402//dprintf("fs_stat_index()\n"); 1403 buf->type = 0; 1404 buf->size = 0; 1405 buf->modification_time = 0; 1406 buf->creation_time = 0; 1407 buf->uid = 0; 1408 buf->gid = 0; 1409 1410 return btStatIndex(ns, name, buf); 1411} 1412 1413extern int fsOpenQuery(fs_nspace *ns, const char *query, ulong flags, port_id port, long token, btQueryCookie **cookie) 1414{ 1415//dprintf("fs_openquery()\n"); 1416 // Allocate and initialize the cookie. 1417 *cookie = (btQueryCookie *) malloc(sizeof(btQueryCookie)); 1418 memset ((*cookie)->opaque, 0, BT_COOKIE_SIZE); 1419 (*cookie)->query = strdup(query); 1420 1421 return B_OK; 1422} 1423 1424extern int fsCloseQuery(fs_nspace *ns, btQueryCookie *cookie) 1425{ 1426//dprintf("fs_closequery()\n"); 1427 return B_OK; 1428} 1429 1430extern int fsReadQuery(fs_nspace *ns, btQueryCookie *cookie, long *num, struct dirent *buf, size_t bufsize) 1431{ 1432 char *filename; 1433 vnode_id vnid, parent; 1434 long max, bufContent; 1435 1436//dprintf("fs_readquery()\n"); 1437 max = *num; 1438 *num = 0; 1439 1440 while (btReadQuery(ns, &filename, &vnid, &parent, cookie) == B_OK) 1441 { 1442 bufContent = 2 * (sizeof(dev_t) + sizeof(ino_t)) + sizeof(unsigned short) + strlen(filename) + 1; 1443 if (bufsize < bufContent) 1444 return B_OK; 1445 1446 buf->d_dev = ns->nsid; 1447 buf->d_pdev = ns->nsid; 1448 buf->d_ino = vnid; 1449 buf->d_pino = parent; 1450 buf->d_reclen = bufContent; 1451 strcpy(buf->d_name, filename); 1452 1453 bufsize -= bufContent; 1454 buf = (struct dirent *)((char *) buf + bufContent); 1455 1456 free(filename); 1457 1458 (*num)++; 1459 if (*num == max) 1460 break; 1461 } 1462 1463 return B_OK; 1464} 1465 1466extern int fsFreeQueryCookie(fs_nspace *ns, btQueryCookie *cookie) 1467{ 1468//dprintf("fs_freequerycookie()\n"); 1469 if (cookie) 1470 { 1471 if (cookie->query) 1472 free(cookie->query); 1473 1474 free(cookie); 1475 } 1476 1477 return B_OK; 1478} 1479