1 /* 2 ** Copyright 1999, Be Incorporated. All Rights Reserved. 3 ** This file may be used under the terms of the Be Sample Code License. 4 ** 5 ** Copyright 2001, pinc Software. All Rights Reserved. 6 ** 7 ** iso9960/multi-session, 1.0.0 8 ** 2001-03-11: added multi-session support, axeld. 9 */ 10 11 #include <stdlib.h> 12 #include <unistd.h> 13 #include <fcntl.h> 14 #include <errno.h> 15 #include <string.h> 16 #include <ctype.h> 17 #include <stdio.h> 18 #include <dirent.h> 19 #include <sys/stat.h> 20 #include <time.h> 21 #include <lock.h> 22 #include <malloc.h> 23 24 #include <KernelExport.h> 25 #include <NodeMonitor.h> 26 #include <fs_interface.h> 27 #include <fs_cache.h> 28 29 #include <fs_attr.h> 30 #include <fs_info.h> 31 #include <fs_index.h> 32 #include <fs_query.h> 33 #include <fs_volume.h> 34 35 #include <util/kernel_cpp.h> 36 37 #include "iso.h" 38 #include "iso9660.h" 39 40 //#define TRACE_ISO9660 1 41 #if TRACE_ISO9660 42 # define TRACE(x) dprintf x 43 #else 44 # define TRACE(x) ; 45 #endif 46 47 48 /* Start of fundamental (read-only) required functions */ 49 static status_t fs_mount(mount_id mountID, const char *device, uint32 flags, 50 const char *args, void **_data, vnode_id *_rootID); 51 static status_t fs_unmount(void *ns); 52 53 static status_t fs_get_vnode_name(void *_ns, void *_node, 54 char *buffer, size_t bufferSize); 55 static status_t fs_walk(void *_ns, void *_base, const char *file, 56 vnode_id *_vnodeID, int *_type); 57 58 static status_t fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter); 59 static status_t fs_release_vnode(void *_ns, void *_node, bool reenter); 60 static status_t fs_read_stat(void *_ns, void *_node, struct stat *st); 61 static status_t fs_open(void *_ns, void *_node, int omode, void **cookie); 62 static status_t fs_read(void *_ns, void *_node, void *cookie, off_t pos, 63 void *buf, size_t *len); 64 /// fs_free_cookie - free cookie for file created in open. 65 static status_t fs_free_cookie(void *ns, void *node, void *cookie); 66 static status_t fs_close(void *ns, void *node, void *cookie); 67 68 // fs_access - checks permissions for access. 69 static status_t fs_access(void *_ns, void *_node, int mode); 70 71 // fs_opendir - creates fs-specific "cookie" struct that can tell where 72 // we are at in the directory list. 73 static status_t fs_open_dir(void* _ns, void* _node, void** cookie); 74 // fs_readdir - read 1 or more dirents, keep state in cookie, return 75 // 0 when no more entries. 76 static status_t fs_read_dir(void *_ns, void *_node, void *cookie, struct dirent *buf, 77 size_t bufsize, uint32 *_num); 78 // fs_rewinddir - set cookie to represent beginning of directory, so 79 // later fs_readdir calls start at beginning. 80 static status_t fs_rewind_dir(void *_ns, void *_node, void *cookie); 81 // fs_closedir - Do whatever you need to to close a directory (sometimes 82 // nothing), but DON'T free the cookie! 83 static status_t fs_close_dir(void *_ns, void *_node, void *cookie); 84 // fs_free_dircookie - Free the fs-specific cookie struct 85 static status_t fs_free_dir_cookie(void *_ns, void *_node, void *cookie); 86 87 // fs_rfsstat - Fill in fs_info struct for device. 88 static status_t fs_read_fs_stat(void *_ns, struct fs_info *); 89 90 // fs_readlink - Read in the name of a symbolic link. 91 static status_t fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize); 92 93 94 // #pragma mark - Scanning 95 96 struct identify_cookie { 97 iso9660_info info; 98 }; 99 100 101 static float 102 fs_identify_partition(int fd, partition_data *partition, void **_cookie) 103 { 104 iso9660_info info; 105 status_t status = iso9660_fs_identify(fd, &info); 106 if (status != B_OK) 107 return status; 108 109 identify_cookie *cookie = new identify_cookie; 110 memcpy(&cookie->info, &info, sizeof(info)); 111 112 *_cookie = cookie; 113 return 0.8f; 114 } 115 116 117 static status_t 118 fs_scan_partition(int fd, partition_data *partition, void *_cookie) 119 { 120 identify_cookie *cookie = (identify_cookie *)_cookie; 121 122 partition->status = B_PARTITION_VALID; 123 partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ; 124 partition->block_size = ISO_PVD_SIZE; 125 partition->content_size = ISO_PVD_SIZE * cookie->info.maxBlocks; 126 partition->content_name = strdup(cookie->info.get_preferred_volume_name()); 127 if (partition->content_name == NULL) 128 return B_NO_MEMORY; 129 130 return B_OK; 131 } 132 133 134 static void 135 fs_free_identify_partition_cookie(partition_data *partition, void *_cookie) 136 { 137 identify_cookie *cookie = (identify_cookie *)_cookie; 138 139 delete cookie; 140 } 141 142 143 static status_t 144 fs_mount(mount_id mountID, const char *device, uint32 flags, 145 const char *args, void **_data, vnode_id *_rootID) 146 { 147 /* 148 Kernel passes in nspace_id, (representing a disk or partition?) 149 and a string representing the device (eg, "/dev/scsi/disk/030/raw) 150 Flags will be used for things like specifying read-only mounting. 151 parms is parameters passed in as switches from the mount command, 152 and len is the length of the otions. data is a pointer to a 153 driver-specific struct that should be allocated in this routine. 154 It will then be passed back in by the kernel to a number of the other 155 fs driver functions. vnid should also be passed back to the kernel, 156 representing the vnode id of the root vnode. 157 */ 158 status_t result = EINVAL; 159 // return EINVAL if it's not a device compatible with the driver. 160 bool allow_joliet = true; 161 nspace *vol; 162 163 (void)flags; 164 165 /* Create semaphore if it's not already created. When do we need to 166 use semaphores? */ 167 168 // Check for a 'nojoliet' parm 169 // all we check for is the existance of 'nojoliet' in the parms. 170 if (args != NULL) { 171 uint32 i; 172 char *spot; 173 char *buf = strdup(args); 174 175 uint32 len = strlen(buf); 176 // lower case the parms data 177 for (i = 0; i < len + 1; i++) 178 buf[i] = tolower(buf[i]); 179 180 // look for nojoliet 181 spot = strstr(buf, "nojoliet"); 182 if (spot != NULL) 183 allow_joliet = false; 184 185 free(buf); 186 } 187 188 // Try and mount volume as an ISO volume. 189 result = ISOMount(device, O_RDONLY, &vol, allow_joliet); 190 191 // If it is ISO … 192 if (result == B_NO_ERROR) { 193 //vnode_id rootID = vol->rootDirRec.startLBN[FS_DATA_FORMAT]; 194 //*vnid = rootID; 195 *_rootID = ISO_ROOTNODE_ID; 196 *_data = (void*)vol; 197 198 vol->id = mountID; 199 200 // You MUST do this. Create the vnode for the root. 201 result = publish_vnode(mountID, *_rootID, (void*)&(vol->rootDirRec)); 202 if (result != B_NO_ERROR) { 203 block_cache_delete(vol->fBlockCache, false); 204 free(vol); 205 result = EINVAL; 206 } else 207 result = B_NO_ERROR; 208 } 209 return result; 210 } 211 212 213 static status_t 214 fs_unmount(void *_ns) 215 { 216 status_t result = B_NO_ERROR; 217 nspace *ns = (nspace *)_ns; 218 219 TRACE(("fs_unmount - ENTER\n")); 220 221 block_cache_delete(ns->fBlockCache, false); 222 close(ns->fdOfSession); 223 result = close(ns->fd); 224 225 free(ns); 226 227 TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result))); 228 return result; 229 } 230 231 232 static status_t 233 fs_read_fs_stat(void *_ns, struct fs_info *fss) 234 { 235 // Fill in fs_info struct for device. 236 nspace *ns = (nspace *)_ns; 237 int i; 238 239 TRACE(("fs_rfsstat - ENTER\n")); 240 241 // Fill in device id. 242 //fss->dev = ns->fd; 243 244 // Root vnode ID 245 //fss->root = ISO_ROOTNODE_ID; 246 247 // File system flags. 248 fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 249 250 // FS block size. 251 fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT]; 252 253 // IO size - specifies buffer size for file copying 254 fss->io_size = 65536; 255 256 // Total blocks? 257 fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT]; 258 259 // Free blocks = 0, read only 260 fss->free_blocks = 0; 261 262 // Device name. 263 strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name)); 264 265 strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name)); 266 for (i = strlen(fss->volume_name)-1; i >=0 ; i--) 267 if (fss->volume_name[i] != ' ') 268 break; 269 270 if (i < 0) 271 strcpy(fss->volume_name, "UNKNOWN"); 272 else 273 fss->volume_name[i + 1] = 0; 274 275 // File system name 276 strcpy(fss->fsh_name, "iso9660"); 277 278 TRACE(("fs_rfsstat - EXIT\n")); 279 return 0; 280 } 281 282 283 static status_t 284 fs_get_vnode_name(void *ns, void *_node, char *buffer, size_t bufferSize) 285 { 286 vnode *node = (vnode*)_node; 287 288 strlcpy(buffer, node->fileIDString, bufferSize); 289 return B_OK; 290 } 291 292 293 /* fs_walk - the walk function just "walks" through a directory looking for 294 the specified file. When you find it, call get_vnode on its vnid to init 295 it for the kernel. 296 */ 297 static status_t 298 fs_walk(void *_ns, void *base, const char *file, vnode_id *_vnodeID, int *_type) 299 { 300 /* Starting at the base, find file in the subdir, and return path 301 string and vnode id of file. */ 302 nspace *ns = (nspace *)_ns; 303 vnode *baseNode = (vnode*)base; 304 uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT]; 305 vnode *newNode = NULL; 306 status_t result = ENOENT; 307 bool done = FALSE; 308 uint32 totalRead = 0; 309 off_t block = baseNode->startLBN[FS_DATA_FORMAT]; 310 311 TRACE(("fs_walk - looking for %s in dir file of length %d\n", file, 312 baseNode->dataLen[FS_DATA_FORMAT])); 313 314 if (strcmp(file, ".") == 0) { 315 // base directory 316 TRACE(("fs_walk - found \".\" file.\n")); 317 *_vnodeID = baseNode->id; 318 *_type = S_IFDIR; 319 if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0) 320 result = EINVAL; 321 else 322 result = B_NO_ERROR; 323 } else if (strcmp(file, "..") == 0) { 324 // parent directory 325 TRACE(("fs_walk - found \"..\" file.\n")); 326 *_vnodeID = baseNode->parID; 327 *_type = S_IFDIR; 328 if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0) 329 result = EINVAL; 330 else 331 result = B_NO_ERROR; 332 } else { 333 // look up file in the directory 334 char *blockData; 335 336 while ((totalRead < dataLen) && !done) { 337 off_t cachedBlock = block; 338 339 blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); 340 if (blockData != NULL) { 341 int bytesRead = 0; 342 off_t blockBytesRead = 0; 343 vnode node; 344 int initResult; 345 346 TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n", 347 block, blockData)); 348 349 // Move to the next 2-block set if necessary 350 // Don't go over end of buffer, if dir record sits on boundary. 351 352 node.fileIDString = NULL; 353 node.attr.slName = NULL; 354 355 while (blockBytesRead < 2*ns->logicalBlkSize[FS_DATA_FORMAT] 356 && totalRead + blockBytesRead < dataLen 357 && blockData[0] != 0 358 && !done) 359 { 360 initResult = InitNode(&node, blockData, &bytesRead, ns->joliet_level); 361 TRACE(("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead)); 362 363 if (initResult == B_NO_ERROR) { 364 if (strlen(node.fileIDString) == strlen(file) 365 && !strncmp(node.fileIDString, file, strlen(file))) 366 { 367 TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead)); 368 *_vnodeID = (block << 30) + (blockBytesRead & 0xFFFFFFFF); 369 TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); 370 371 if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0) 372 result = EINVAL; 373 else { 374 newNode->parID = baseNode->id; 375 done = TRUE; 376 result = B_NO_ERROR; 377 } 378 } else { 379 if (node.fileIDString != NULL) { 380 free(node.fileIDString); 381 node.fileIDString = NULL; 382 } 383 if (node.attr.slName != NULL) { 384 free(node.attr.slName); 385 node.attr.slName = NULL; 386 } 387 } 388 } else { 389 result = initResult; 390 if (bytesRead == 0) 391 done = TRUE; 392 } 393 blockData += bytesRead; 394 blockBytesRead += bytesRead; 395 396 TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n", 397 bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT])); 398 } 399 totalRead += ns->logicalBlkSize[FS_DATA_FORMAT]; 400 block++; 401 402 TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead)); 403 block_cache_put(ns->fBlockCache, cachedBlock); 404 405 } else 406 done = TRUE; 407 } 408 409 if (newNode) 410 *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode; 411 412 } 413 TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *_vnodeID)); 414 return result; 415 } 416 417 418 static status_t 419 fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter) 420 { 421 uint32 block, pos; 422 nspace *ns = (nspace*)_ns; 423 status_t result = B_NO_ERROR; 424 vnode *newNode = (vnode*)calloc(sizeof(vnode), 1); 425 426 (void)reenter; 427 428 pos = (vnid & 0x3FFFFFFF); 429 block = (vnid >> 30); 430 431 TRACE(("fs_read_vnode - ENTER, block = %ld, pos = %ld, raw = %Lu node 0x%x\n", 432 block, pos, vnid, newNode)); 433 434 if (newNode != NULL) { 435 if (vnid == ISO_ROOTNODE_ID) { 436 TRACE(("fs_read_vnode - root node requested.\n")); 437 memcpy(newNode, &(ns->rootDirRec), sizeof(vnode)); 438 *node = (void*)newNode; 439 } else { 440 char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); 441 442 if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) { 443 if (blockData != NULL) 444 block_cache_put(ns->fBlockCache, block); 445 446 result = EINVAL; 447 } else if (blockData != NULL) { 448 result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level); 449 block_cache_put(ns->fBlockCache, block); 450 newNode->id = vnid; 451 452 TRACE(("fs_read_vnode - init result is %s\n", strerror(result))); 453 *node = (void *)newNode; 454 TRACE(("fs_read_vnode - new file %s, size %ld\n", newNode->fileIDString, newNode->dataLen[FS_DATA_FORMAT])); 455 } 456 } 457 } else 458 result = ENOMEM; 459 460 TRACE(("fs_read_vnode - EXIT, result is %s\n", strerror(result))); 461 return result; 462 } 463 464 465 static status_t 466 fs_release_vnode(void *ns, void *_node, bool reenter) 467 { 468 status_t result = B_NO_ERROR; 469 vnode *node = (vnode*)_node; 470 471 (void)ns; 472 (void)reenter; 473 474 TRACE(("fs_write_vnode - ENTER (0x%x)\n", node)); 475 476 if (node != NULL) { 477 if (node->id != ISO_ROOTNODE_ID) { 478 if (node->fileIDString != NULL) 479 free (node->fileIDString); 480 if (node->attr.slName != NULL) 481 free (node->attr.slName); 482 483 free(node); 484 } 485 } 486 487 TRACE(("fs_write_vnode - EXIT\n")); 488 return result; 489 } 490 491 492 static status_t 493 fs_read_stat(void *_ns, void *_node, struct stat *st) 494 { 495 nspace *ns = (nspace*)_ns; 496 vnode *node = (vnode*)_node; 497 status_t result = B_NO_ERROR; 498 time_t time; 499 500 TRACE(("fs_read_stat - ENTER\n")); 501 502 st->st_dev = ns->id; 503 st->st_ino = node->id; 504 st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 505 st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 506 st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 507 st->st_blksize = 65536; 508 st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 509 510 // Same for file/dir in ISO9660 511 st->st_size = node->dataLen[FS_DATA_FORMAT]; 512 if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 513 st->st_ctime = st->st_mtime = st->st_atime = time; 514 515 TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 516 517 return result; 518 } 519 520 521 static status_t 522 fs_open(void *_ns, void *_node, int omode, void **cookie) 523 { 524 status_t result = B_NO_ERROR; 525 526 (void)_ns; 527 (void)cookie; 528 529 // Do not allow any of the write-like open modes to get by 530 if ((omode == O_WRONLY) || (omode == O_RDWR)) 531 result = EROFS; 532 else if((omode & O_TRUNC) || (omode & O_CREAT)) 533 result = EROFS; 534 535 return result; 536 } 537 538 539 static status_t 540 fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len) 541 { 542 nspace *ns = (nspace *)_ns; // global stuff 543 vnode *node = (vnode *)_node; // The read file vnode. 544 uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT]; 545 uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize); 546 off_t blockPos = pos % blockSize; 547 off_t numBlocks = 0; 548 uint32 dataLen = node->dataLen[FS_DATA_FORMAT]; 549 status_t result = B_NO_ERROR; 550 size_t endLen = 0; 551 size_t reqLen = *len; 552 size_t startLen = 0; 553 554 (void)cookie; 555 556 // Allow an open to work on a dir, but no reads 557 if (node->flags & ISO_ISDIR) 558 return EISDIR; 559 560 if (pos < 0) 561 pos = 0; 562 *len = 0; 563 564 // If passed-in requested length is bigger than file size, change it to 565 // file size. 566 if (reqLen + pos > dataLen) 567 reqLen = dataLen - pos; 568 569 // Compute the length of the partial start-block read, if any. 570 571 if (reqLen + blockPos <= blockSize) 572 startLen = reqLen; 573 else if (blockPos > 0) 574 startLen = blockSize - blockPos; 575 576 if (blockPos == 0 && reqLen >= blockSize) { 577 TRACE(("Setting startLen to 0, even block read\n")); 578 startLen = 0; 579 } 580 581 // Compute the length of the partial end-block read, if any. 582 if (reqLen + blockPos > blockSize) 583 endLen = (reqLen + blockPos) % blockSize; 584 585 // Compute the number of middle blocks to read. 586 numBlocks = ((reqLen - endLen - startLen) / blockSize); 587 588 //dprintf("fs_read - ENTER, pos is %Ld, len is %lu\n", pos, reqLen); 589 //dprintf("fs_read - filename is %s\n", node->fileIDString); 590 //dprintf("fs_read - total file length is %lu\n", dataLen); 591 //dprintf("fs_read - start block of file is %lu\n", node->startLBN[FS_DATA_FORMAT]); 592 //dprintf("fs_read - block pos is %Lu\n", blockPos); 593 //dprintf("fs_read - read block will be %lu\n", startBlock); 594 //dprintf("fs_read - startLen is %lu\n", startLen); 595 //dprintf("fs_read - endLen is %lu\n", endLen); 596 //dprintf("fs_read - num blocks to read is %Ld\n", numBlocks); 597 598 if (pos >= dataLen) { 599 // If pos >= file length, return length of 0. 600 *len = 0; 601 return B_OK; 602 } 603 604 // Read in the first, potentially partial, block. 605 if (startLen > 0) { 606 off_t cachedBlock = startBlock; 607 char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, startBlock, 0, blockSize); 608 if (blockData != NULL) { 609 //dprintf("fs_read - copying first block, len is %d.\n", startLen); 610 memcpy(buf, blockData+blockPos, startLen); 611 *len += startLen; 612 block_cache_put(ns->fBlockCache, cachedBlock); 613 startBlock++; 614 } else 615 result = EIO; 616 } 617 618 // Read in the middle blocks. 619 if (numBlocks > 0 && result == B_NO_ERROR) { 620 TRACE(("fs_read - getting middle blocks\n")); 621 char *endBuf = ((char *)buf) + startLen; 622 for (int32 i=startBlock; i<startBlock+numBlocks; i++) { 623 char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, i, 0, blockSize); 624 memcpy(endBuf, blockData, blockSize); 625 *len += blockSize; 626 endBuf += blockSize; 627 block_cache_put(ns->fBlockCache, i); 628 } 629 } 630 631 // Read in the last partial block. 632 if (result == B_NO_ERROR && endLen > 0) { 633 off_t endBlock = startBlock + numBlocks; 634 char *endBlockData = (char*)block_cache_get_etc(ns->fBlockCache, endBlock, 0, blockSize); 635 if (endBlockData != NULL) { 636 char *endBuf = ((char *)buf) + (reqLen - endLen); 637 638 memcpy(endBuf, endBlockData, endLen); 639 block_cache_put(ns->fBlockCache, endBlock); 640 *len += endLen; 641 } else 642 result = EIO; 643 } 644 645 TRACE(("fs_read - EXIT, result is %s\n", strerror(result))); 646 return result; 647 } 648 649 650 static status_t 651 fs_close(void *ns, void *node, void *cookie) 652 { 653 (void)ns; 654 (void)node; 655 (void)cookie; 656 657 //dprintf("fs_close - ENTER\n"); 658 //dprintf("fs_close - EXIT\n"); 659 return B_OK; 660 } 661 662 static status_t 663 fs_free_cookie(void *ns, void *node, void *cookie) 664 { 665 (void)ns; 666 (void)node; 667 (void)cookie; 668 669 // We don't allocate file cookies, so we do nothing here. 670 //dprintf("fs_free_cookie - ENTER\n"); 671 //if (cookie != NULL) free (cookie); 672 //dprintf("fs_free_cookie - EXIT\n"); 673 return B_OK; 674 } 675 676 // fs_access - checks permissions for access. 677 static status_t 678 fs_access(void *ns, void *node, int mode) 679 { 680 (void)ns; 681 (void)node; 682 (void)mode; 683 684 // ns - global, fs-specific struct for device 685 // node - node to check permissions for 686 // mode - requested permissions on node. 687 //dprintf("fs_access - ENTER\n"); 688 //dprintf("fs_access - EXIT\n"); 689 return B_OK; 690 } 691 692 static status_t 693 fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize) 694 { 695 vnode *node = (vnode *)_node; 696 status_t result = EINVAL; 697 698 (void)_ns; 699 700 if (S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) { 701 size_t length = strlen(node->attr.slName); 702 if (length > *_bufferSize) 703 memcpy(buffer, node->attr.slName, *_bufferSize); 704 else { 705 memcpy(buffer, node->attr.slName, length); 706 *_bufferSize = length; 707 } 708 709 result = B_NO_ERROR; 710 } 711 712 return result; 713 } 714 715 716 static status_t 717 fs_open_dir(void *_ns, void *_node, void **cookie) 718 { 719 vnode *node = (vnode *)_node; 720 status_t result = B_NO_ERROR; 721 dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie)); 722 723 (void)_ns; 724 725 TRACE(("fs_opendir - ENTER, node is 0x%x\n", _node)); 726 727 if (!(node->flags & ISO_ISDIR)) 728 result = EMFILE; 729 730 if (dirCookie != NULL) { 731 dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 732 dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 733 dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 734 dirCookie->pos = 0; 735 dirCookie->id = node->id; 736 *cookie = (void *)dirCookie; 737 } else 738 result = ENOMEM; 739 740 TRACE(("fs_opendir - EXIT\n")); 741 return result; 742 } 743 744 745 static status_t 746 fs_read_dir(void *_ns, void *_node, void *_cookie, struct dirent *buffer, 747 size_t bufferSize, uint32 *num) 748 { 749 status_t result = B_NO_ERROR; 750 nspace *ns = (nspace *)_ns; 751 dircookie *dirCookie = (dircookie *)_cookie; 752 753 (void)_node; 754 755 TRACE(("fs_readdir - ENTER\n")); 756 757 result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize); 758 759 // If we succeeded, return 1, the number of dirents we read. 760 if (result == B_NO_ERROR) 761 *num = 1; 762 else 763 *num = 0; 764 765 // When you get to the end, don't return an error, just return 766 // a zero in *num. 767 768 if (result == ENOENT) 769 result = B_NO_ERROR; 770 771 TRACE(("fs_readdir - EXIT, result is %s\n", strerror(result))); 772 return result; 773 } 774 775 776 static status_t 777 fs_rewind_dir(void *ns, void *node, void* _cookie) 778 { 779 status_t result = EINVAL; 780 dircookie *cookie = (dircookie*)_cookie; 781 782 (void)ns; 783 (void)node; 784 785 //dprintf("fs_rewinddir - ENTER\n"); 786 if (cookie != NULL) { 787 cookie->block = cookie->startBlock; 788 cookie->pos = 0; 789 result = B_NO_ERROR; 790 } 791 //dprintf("fs_rewinddir - EXIT, result is %s\n", strerror(result)); 792 return result; 793 } 794 795 796 static status_t 797 fs_close_dir(void *ns, void *node, void *cookie) 798 { 799 (void)ns; 800 (void)node; 801 (void)cookie; 802 803 // ns - global, fs-specific struct for device 804 // node - directory to close 805 // cookie - current cookie for directory. 806 //dprintf("fs_closedir - ENTER\n"); 807 //dprintf("fs_closedir - EXIT\n"); 808 return B_OK; 809 } 810 811 812 static status_t 813 fs_free_dir_cookie(void *ns, void *node, void *cookie) 814 { 815 (void)ns; 816 (void)node; 817 818 // ns - global, fs-specific struct for device 819 // node - directory related to cookie 820 // cookie - current cookie for directory, to free. 821 //dprintf("fs_free_dircookie - ENTER\n"); 822 if (cookie != NULL) 823 free(cookie); 824 825 //dprintf("fs_free_dircookie - EXIT\n"); 826 return B_OK; 827 } 828 829 // #pragma mark - 830 831 832 static status_t 833 iso_std_ops(int32 op, ...) 834 { 835 switch (op) { 836 case B_MODULE_INIT: 837 return B_OK; 838 case B_MODULE_UNINIT: 839 return B_OK; 840 default: 841 return B_ERROR; 842 } 843 } 844 845 846 static file_system_module_info sISO660FileSystem = { 847 { 848 "file_systems/iso9660" B_CURRENT_FS_API_VERSION, 849 0, 850 iso_std_ops, 851 }, 852 853 "ISO9660 File System", 854 855 // scanning 856 fs_identify_partition, 857 fs_scan_partition, 858 fs_free_identify_partition_cookie, 859 NULL, // free_partition_content_cookie() 860 861 &fs_mount, 862 &fs_unmount, 863 &fs_read_fs_stat, 864 NULL, 865 NULL, 866 867 /* vnode operations */ 868 &fs_walk, 869 &fs_get_vnode_name, 870 &fs_read_vnode, 871 &fs_release_vnode, 872 NULL, // &fs_remove_vnode() 873 874 /* VM file access */ 875 NULL, // &fs_can_page 876 NULL, // &fs_read_pages 877 NULL, // &fs_write_pages 878 879 NULL, // &fs_get_file_map 880 881 NULL, // &fs_ioctl 882 NULL, // &fs_set_flags 883 NULL, // &fs_select 884 NULL, // &fs_deselect 885 NULL, // &fs_fsync 886 887 &fs_read_link, 888 NULL, // write link 889 NULL, // &fs_create_symlink, 890 891 NULL, // &fs_link, 892 NULL, // &fs_unlink 893 NULL, // &fs_rename 894 895 &fs_access, 896 &fs_read_stat, 897 NULL, // &fs_write_stat 898 899 /* file operations */ 900 NULL, // &fs_create 901 &fs_open, 902 &fs_close, 903 &fs_free_cookie, 904 &fs_read, 905 NULL, // &fs_write 906 907 /* directory operations */ 908 NULL, // &fs_create_dir 909 NULL, // &fs_remove_dir 910 &fs_open_dir, 911 &fs_close_dir, 912 &fs_free_dir_cookie, 913 &fs_read_dir, 914 &fs_rewind_dir, 915 916 /* attribute directory operations */ 917 NULL, // &fs_open_attr_dir 918 NULL, // &fs_close_attr_dir 919 NULL, // &fs_free_attr_dir_cookie 920 NULL, // &fs_read_attr_dir 921 NULL, // &fs_rewind_attr_dir 922 923 /* attribute operations */ 924 NULL, // &fs_create_attr 925 NULL, // &fs_open_attr 926 NULL, // &fs_close_attr 927 NULL, // &fs_free_attr_cookie 928 NULL, // &fs_read_attr 929 NULL, // &fs_write_attr 930 931 NULL, // &fs_read_attr_stat 932 NULL, // &fs_write_attr_stat 933 NULL, // &fs_rename_attr 934 NULL, // &fs_remove_attr 935 936 /* index directory & index operations */ 937 NULL, // &fs_open_index_dir 938 NULL, // &fs_close_index_dir 939 NULL, // &fs_free_index_dir_cookie 940 NULL, // &fs_read_index_dir 941 NULL, // &fs_rewind_index_dir 942 943 NULL, // &fs_create_index 944 NULL, // &fs_remove_index 945 NULL, // &fs_stat_index 946 947 /* query operations */ 948 NULL, // &fs_open_query 949 NULL, // &fs_close_query 950 NULL, // &fs_free_query_cookie 951 NULL, // &fs_read_query 952 NULL, // &fs_rewind_query 953 }; 954 955 module_info *modules[] = { 956 (module_info *)&sISO660FileSystem, 957 NULL, 958 }; 959 960