121e1553eSJérôme Duval /* 2245aecdaSAxel Dörfler * Copyright 1999, Be Incorporated. All Rights Reserved. 3245aecdaSAxel Dörfler * This file may be used under the terms of the Be Sample Code License. 4245aecdaSAxel Dörfler * 5245aecdaSAxel Dörfler * Copyright 2001, pinc Software. All Rights Reserved. 6245aecdaSAxel Dörfler * 7245aecdaSAxel Dörfler * iso9960/multi-session, 1.0.0 821e1553eSJérôme Duval */ 921e1553eSJérôme Duval 10245aecdaSAxel Dörfler 1121e1553eSJérôme Duval #include <ctype.h> 1221e1553eSJérôme Duval #include <dirent.h> 135b2c5d03SAxel Dörfler #include <errno.h> 145b2c5d03SAxel Dörfler #include <fcntl.h> 155b2c5d03SAxel Dörfler #include <stdio.h> 165b2c5d03SAxel Dörfler #include <stdlib.h> 175b2c5d03SAxel Dörfler #include <string.h> 1821e1553eSJérôme Duval #include <sys/stat.h> 1921e1553eSJérôme Duval #include <time.h> 205b2c5d03SAxel Dörfler #include <unistd.h> 2121e1553eSJérôme Duval 2221e1553eSJérôme Duval #include <KernelExport.h> 2321e1553eSJérôme Duval #include <NodeMonitor.h> 2421e1553eSJérôme Duval #include <fs_interface.h> 2521e1553eSJérôme Duval #include <fs_cache.h> 2621e1553eSJérôme Duval 2721e1553eSJérôme Duval #include <fs_attr.h> 2821e1553eSJérôme Duval #include <fs_info.h> 2921e1553eSJérôme Duval #include <fs_index.h> 3021e1553eSJérôme Duval #include <fs_query.h> 3121e1553eSJérôme Duval #include <fs_volume.h> 3221e1553eSJérôme Duval 3321e1553eSJérôme Duval #include <util/kernel_cpp.h> 3421e1553eSJérôme Duval 35dc9a52b9SAxel Dörfler #include "iso9660.h" 365b2c5d03SAxel Dörfler #include "iso9660_identify.h" 375b2c5d03SAxel Dörfler 385b2c5d03SAxel Dörfler 395b2c5d03SAxel Dörfler //#define TRACE_ISO9660 405b2c5d03SAxel Dörfler #ifdef TRACE_ISO9660 4121e1553eSJérôme Duval # define TRACE(x) dprintf x 4221e1553eSJérôme Duval #else 4321e1553eSJérôme Duval # define TRACE(x) ; 4421e1553eSJérôme Duval #endif 4521e1553eSJérôme Duval 4621e1553eSJérôme Duval 4721e1553eSJérôme Duval struct identify_cookie { 4821e1553eSJérôme Duval iso9660_info info; 4921e1553eSJérôme Duval }; 5021e1553eSJérôme Duval 510eaadd30SMichael Lotz extern fs_volume_ops gISO9660VolumeOps; 520eaadd30SMichael Lotz extern fs_vnode_ops gISO9660VnodeOps; 530eaadd30SMichael Lotz 5421e1553eSJérôme Duval 555b2c5d03SAxel Dörfler // #pragma mark - Scanning 565b2c5d03SAxel Dörfler 575b2c5d03SAxel Dörfler 5821e1553eSJérôme Duval static float 5921e1553eSJérôme Duval fs_identify_partition(int fd, partition_data *partition, void **_cookie) 6021e1553eSJérôme Duval { 615b2c5d03SAxel Dörfler iso9660_info *info = new iso9660_info; 6221e1553eSJérôme Duval 635b2c5d03SAxel Dörfler status_t status = iso9660_fs_identify(fd, info); 645b2c5d03SAxel Dörfler if (status != B_OK) { 655b2c5d03SAxel Dörfler delete info; 665b2c5d03SAxel Dörfler return -1; 675b2c5d03SAxel Dörfler } 6821e1553eSJérôme Duval 695b2c5d03SAxel Dörfler *_cookie = info; 705b2c5d03SAxel Dörfler return 0.6f; 7121e1553eSJérôme Duval } 7221e1553eSJérôme Duval 7321e1553eSJérôme Duval 7421e1553eSJérôme Duval static status_t 7521e1553eSJérôme Duval fs_scan_partition(int fd, partition_data *partition, void *_cookie) 7621e1553eSJérôme Duval { 775b2c5d03SAxel Dörfler iso9660_info *info = (iso9660_info *)_cookie; 7821e1553eSJérôme Duval 7921e1553eSJérôme Duval partition->status = B_PARTITION_VALID; 8021e1553eSJérôme Duval partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ; 8121e1553eSJérôme Duval partition->block_size = ISO_PVD_SIZE; 825b2c5d03SAxel Dörfler partition->content_size = ISO_PVD_SIZE * info->max_blocks; 835b2c5d03SAxel Dörfler partition->content_name = strdup(info->PreferredName()); 845b2c5d03SAxel Dörfler 8521e1553eSJérôme Duval if (partition->content_name == NULL) 8621e1553eSJérôme Duval return B_NO_MEMORY; 8721e1553eSJérôme Duval 8821e1553eSJérôme Duval return B_OK; 8921e1553eSJérôme Duval } 9021e1553eSJérôme Duval 9121e1553eSJérôme Duval 9221e1553eSJérôme Duval static void 9321e1553eSJérôme Duval fs_free_identify_partition_cookie(partition_data *partition, void *_cookie) 9421e1553eSJérôme Duval { 955b2c5d03SAxel Dörfler delete (iso9660_info *)_cookie; 9621e1553eSJérôme Duval } 9721e1553eSJérôme Duval 9821e1553eSJérôme Duval 99ff99132eSAxel Dörfler // #pragma mark - FS hooks 100ff99132eSAxel Dörfler 101ff99132eSAxel Dörfler 10221e1553eSJérôme Duval static status_t 1030eaadd30SMichael Lotz fs_mount(fs_volume *_volume, const char *device, uint32 flags, 1040eaadd30SMichael Lotz const char *args, ino_t *_rootID) 10521e1553eSJérôme Duval { 1065b2c5d03SAxel Dörfler bool allowJoliet = true; 107eb097431SAxel Dörfler iso9660_volume *volume; 10821e1553eSJérôme Duval 10921e1553eSJérôme Duval // Check for a 'nojoliet' parm 11021e1553eSJérôme Duval // all we check for is the existance of 'nojoliet' in the parms. 11121e1553eSJérôme Duval if (args != NULL) { 11221e1553eSJérôme Duval uint32 i; 11321e1553eSJérôme Duval char *spot; 11421e1553eSJérôme Duval char *buf = strdup(args); 11521e1553eSJérôme Duval 11621e1553eSJérôme Duval uint32 len = strlen(buf); 11721e1553eSJérôme Duval // lower case the parms data 11821e1553eSJérôme Duval for (i = 0; i < len + 1; i++) 11921e1553eSJérôme Duval buf[i] = tolower(buf[i]); 12021e1553eSJérôme Duval 12121e1553eSJérôme Duval // look for nojoliet 12221e1553eSJérôme Duval spot = strstr(buf, "nojoliet"); 12321e1553eSJérôme Duval if (spot != NULL) 1245b2c5d03SAxel Dörfler allowJoliet = false; 12521e1553eSJérôme Duval 12621e1553eSJérôme Duval free(buf); 12721e1553eSJérôme Duval } 12821e1553eSJérôme Duval 12921e1553eSJérôme Duval // Try and mount volume as an ISO volume. 130ff99132eSAxel Dörfler status_t result = ISOMount(device, O_RDONLY, &volume, allowJoliet); 131ff99132eSAxel Dörfler if (result == B_OK) { 13221e1553eSJérôme Duval *_rootID = ISO_ROOTNODE_ID; 13321e1553eSJérôme Duval 1340eaadd30SMichael Lotz _volume->private_volume = volume; 1350eaadd30SMichael Lotz _volume->ops = &gISO9660VolumeOps; 1360eaadd30SMichael Lotz volume->volume = _volume; 1370eaadd30SMichael Lotz volume->id = _volume->id; 13821e1553eSJérôme Duval 1390eaadd30SMichael Lotz result = publish_vnode(_volume, *_rootID, &volume->rootDirRec, 1400eaadd30SMichael Lotz &gISO9660VnodeOps, volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0); 141ff99132eSAxel Dörfler if (result != B_OK) { 142ff99132eSAxel Dörfler block_cache_delete(volume->fBlockCache, false); 143ff99132eSAxel Dörfler free(volume); 144ff99132eSAxel Dörfler result = B_ERROR; 145ff99132eSAxel Dörfler } 14621e1553eSJérôme Duval } 14721e1553eSJérôme Duval return result; 14821e1553eSJérôme Duval } 14921e1553eSJérôme Duval 15021e1553eSJérôme Duval 15121e1553eSJérôme Duval static status_t 1520eaadd30SMichael Lotz fs_unmount(fs_volume *_vol) 15321e1553eSJérôme Duval { 15421e1553eSJérôme Duval status_t result = B_NO_ERROR; 155eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 15621e1553eSJérôme Duval 15721e1553eSJérôme Duval TRACE(("fs_unmount - ENTER\n")); 15821e1553eSJérôme Duval 1599d254f45SJérôme Duval // Unlike in BeOS, we need to put the reference to our root node ourselves 1600eaadd30SMichael Lotz put_vnode(_vol, ISO_ROOTNODE_ID); 1619d254f45SJérôme Duval 16221e1553eSJérôme Duval block_cache_delete(ns->fBlockCache, false); 16321e1553eSJérôme Duval close(ns->fdOfSession); 16421e1553eSJérôme Duval result = close(ns->fd); 16521e1553eSJérôme Duval 16621e1553eSJérôme Duval free(ns); 16721e1553eSJérôme Duval 16821e1553eSJérôme Duval TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result))); 16921e1553eSJérôme Duval return result; 17021e1553eSJérôme Duval } 17121e1553eSJérôme Duval 17221e1553eSJérôme Duval 17321e1553eSJérôme Duval static status_t 1740eaadd30SMichael Lotz fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss) 17521e1553eSJérôme Duval { 176eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 17721e1553eSJérôme Duval int i; 17821e1553eSJérôme Duval 17921e1553eSJérôme Duval fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 18021e1553eSJérôme Duval fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT]; 18121e1553eSJérôme Duval fss->io_size = 65536; 18221e1553eSJérôme Duval fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT]; 18321e1553eSJérôme Duval fss->free_blocks = 0; 18421e1553eSJérôme Duval 18521e1553eSJérôme Duval strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name)); 18621e1553eSJérôme Duval 18721e1553eSJérôme Duval strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name)); 188ff99132eSAxel Dörfler for (i = strlen(fss->volume_name) - 1; i >=0 ; i--) { 18921e1553eSJérôme Duval if (fss->volume_name[i] != ' ') 19021e1553eSJérôme Duval break; 191ff99132eSAxel Dörfler } 19221e1553eSJérôme Duval 19321e1553eSJérôme Duval if (i < 0) 19421e1553eSJérôme Duval strcpy(fss->volume_name, "UNKNOWN"); 19521e1553eSJérôme Duval else 19621e1553eSJérôme Duval fss->volume_name[i + 1] = 0; 19721e1553eSJérôme Duval 19821e1553eSJérôme Duval strcpy(fss->fsh_name, "iso9660"); 199ff99132eSAxel Dörfler return B_OK; 20021e1553eSJérôme Duval } 20121e1553eSJérôme Duval 2023b723f79SJérôme Duval 2033b723f79SJérôme Duval static status_t 2040eaadd30SMichael Lotz fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferSize) 2053b723f79SJérôme Duval { 206eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode*)_node->private_node; 2073b723f79SJérôme Duval 208eb097431SAxel Dörfler strlcpy(buffer, node->name, bufferSize); 2093b723f79SJérôme Duval return B_OK; 2103b723f79SJérôme Duval } 2113b723f79SJérôme Duval 2123b723f79SJérôme Duval 21321e1553eSJérôme Duval static status_t 2140eaadd30SMichael Lotz fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID) 21521e1553eSJérôme Duval { 216eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 217eb097431SAxel Dörfler iso9660_inode *baseNode = (iso9660_inode*)_base->private_node; 218eb097431SAxel Dörfler iso9660_inode *newNode = NULL; 21921e1553eSJérôme Duval 220eb097431SAxel Dörfler TRACE(("fs_walk - looking for %s in dir file of length %ld\n", file, 22121e1553eSJérôme Duval baseNode->dataLen[FS_DATA_FORMAT])); 22221e1553eSJérôme Duval 22321e1553eSJérôme Duval if (strcmp(file, ".") == 0) { 22421e1553eSJérôme Duval // base directory 22521e1553eSJérôme Duval TRACE(("fs_walk - found \".\" file.\n")); 22621e1553eSJérôme Duval *_vnodeID = baseNode->id; 2270eaadd30SMichael Lotz return get_vnode(_vol, *_vnodeID, (void **)&newNode); 22821e1553eSJérôme Duval } else if (strcmp(file, "..") == 0) { 22921e1553eSJérôme Duval // parent directory 23021e1553eSJérôme Duval TRACE(("fs_walk - found \"..\" file.\n")); 23121e1553eSJérôme Duval *_vnodeID = baseNode->parID; 2320eaadd30SMichael Lotz return get_vnode(_vol, *_vnodeID, (void **)&newNode); 233ff99132eSAxel Dörfler } 234ff99132eSAxel Dörfler 23521e1553eSJérôme Duval // look up file in the directory 236ff99132eSAxel Dörfler uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT]; 237ff99132eSAxel Dörfler status_t result = ENOENT; 238eb097431SAxel Dörfler size_t totalRead = 0; 239ff99132eSAxel Dörfler off_t block = baseNode->startLBN[FS_DATA_FORMAT]; 240ff99132eSAxel Dörfler bool done = false; 24121e1553eSJérôme Duval 242ff99132eSAxel Dörfler while (totalRead < dataLength && !done) { 24321e1553eSJérôme Duval off_t cachedBlock = block; 244eb097431SAxel Dörfler char* blockData = (char*)block_cache_get(ns->fBlockCache, block); 24521e1553eSJérôme Duval if (blockData != NULL) { 246eb097431SAxel Dörfler size_t bytesRead = 0; 24721e1553eSJérôme Duval off_t blockBytesRead = 0; 248eb097431SAxel Dörfler iso9660_inode node; 24921e1553eSJérôme Duval int initResult; 25021e1553eSJérôme Duval 251eb097431SAxel Dörfler TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer " 252eb097431SAxel Dörfler "%p.\n", block, blockData)); 25321e1553eSJérôme Duval 25421e1553eSJérôme Duval // Move to the next 2-block set if necessary 25521e1553eSJérôme Duval // Don't go over end of buffer, if dir record sits on boundary. 25621e1553eSJérôme Duval 25721e1553eSJérôme Duval while (blockBytesRead < 2 * ns->logicalBlkSize[FS_DATA_FORMAT] 258ff99132eSAxel Dörfler && totalRead + blockBytesRead < dataLength 25921e1553eSJérôme Duval && blockData[0] != 0 260ff99132eSAxel Dörfler && !done) { 261ff99132eSAxel Dörfler initResult = InitNode(&node, blockData, &bytesRead, 262ff99132eSAxel Dörfler ns->joliet_level); 263eb097431SAxel Dörfler TRACE(("fs_walk - InitNode returned %s, filename %s, %lu bytes " 264eb097431SAxel Dörfler "read\n", strerror(initResult), node.name, 265eb097431SAxel Dörfler bytesRead)); 26621e1553eSJérôme Duval 267ff99132eSAxel Dörfler if (initResult == B_OK) { 268eb097431SAxel Dörfler if (!strcmp(node.name, file)) { 26921e1553eSJérôme Duval TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead)); 270ff99132eSAxel Dörfler *_vnodeID = (block << 30) 271ff99132eSAxel Dörfler + (blockBytesRead & 0xffffffff); 27221e1553eSJérôme Duval TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); 27321e1553eSJérôme Duval 2740eaadd30SMichael Lotz result = get_vnode(_vol, *_vnodeID, 275ff99132eSAxel Dörfler (void **)&newNode); 276ff99132eSAxel Dörfler if (result == B_OK) { 27721e1553eSJérôme Duval newNode->parID = baseNode->id; 278ff99132eSAxel Dörfler done = true; 27921e1553eSJérôme Duval } 28021e1553eSJérôme Duval } else { 281eb097431SAxel Dörfler free(node.name); 28221e1553eSJérôme Duval free(node.attr.slName); 28321e1553eSJérôme Duval } 28421e1553eSJérôme Duval } else { 28521e1553eSJérôme Duval result = initResult; 28621e1553eSJérôme Duval if (bytesRead == 0) 28721e1553eSJérôme Duval done = TRUE; 28821e1553eSJérôme Duval } 28921e1553eSJérôme Duval blockData += bytesRead; 29021e1553eSJérôme Duval blockBytesRead += bytesRead; 29121e1553eSJérôme Duval 292eb097431SAxel Dörfler TRACE(("fs_walk - Adding %lu bytes to blockBytes read (total " 293eb097431SAxel Dörfler "%Ld/%lu).\n", bytesRead, blockBytesRead, 294eb097431SAxel Dörfler baseNode->dataLen[FS_DATA_FORMAT])); 29521e1553eSJérôme Duval } 29621e1553eSJérôme Duval totalRead += ns->logicalBlkSize[FS_DATA_FORMAT]; 29721e1553eSJérôme Duval block++; 29821e1553eSJérôme Duval 299eb097431SAxel Dörfler TRACE(("fs_walk - moving to next block %Ld, total read %lu\n", 300eb097431SAxel Dörfler block, totalRead)); 30121e1553eSJérôme Duval block_cache_put(ns->fBlockCache, cachedBlock); 30221e1553eSJérôme Duval 30321e1553eSJérôme Duval } else 30421e1553eSJérôme Duval done = TRUE; 30521e1553eSJérôme Duval } 30621e1553eSJérôme Duval 307ff99132eSAxel Dörfler TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", 308ff99132eSAxel Dörfler strerror(result), *_vnodeID)); 30921e1553eSJérôme Duval return result; 31021e1553eSJérôme Duval } 31121e1553eSJérôme Duval 31221e1553eSJérôme Duval 31321e1553eSJérôme Duval static status_t 3140eaadd30SMichael Lotz fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node, 3150eaadd30SMichael Lotz int *_type, uint32 *_flags, bool reenter) 31621e1553eSJérôme Duval { 317eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume*)_vol->private_volume; 318ff99132eSAxel Dörfler 319eb097431SAxel Dörfler iso9660_inode *newNode = (iso9660_inode*)calloc(sizeof(iso9660_inode), 1); 320ff99132eSAxel Dörfler if (newNode == NULL) 321ff99132eSAxel Dörfler return B_NO_MEMORY; 32221e1553eSJérôme Duval 323ff99132eSAxel Dörfler uint32 pos = vnodeID & 0x3fffffff; 324ff99132eSAxel Dörfler uint32 block = vnodeID >> 30; 32521e1553eSJérôme Duval 326eb097431SAxel Dörfler TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node %p\n", 327ff99132eSAxel Dörfler block, pos, vnodeID, newNode)); 32821e1553eSJérôme Duval 329d02cde30SMichael Lotz if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) { 330d02cde30SMichael Lotz free(newNode); 331ff99132eSAxel Dörfler return B_BAD_VALUE; 332d02cde30SMichael Lotz } 33321e1553eSJérôme Duval 334eb097431SAxel Dörfler char *data = (char *)block_cache_get(ns->fBlockCache, block); 335ff99132eSAxel Dörfler if (data == NULL) { 336ff99132eSAxel Dörfler free(newNode); 337ff99132eSAxel Dörfler return B_IO_ERROR; 338ff99132eSAxel Dörfler } 33921e1553eSJérôme Duval 340ff99132eSAxel Dörfler status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level); 34121e1553eSJérôme Duval block_cache_put(ns->fBlockCache, block); 34221e1553eSJérôme Duval 343ff99132eSAxel Dörfler if (result < B_OK) { 344ff99132eSAxel Dörfler free(newNode); 345ff99132eSAxel Dörfler return result; 34621e1553eSJérôme Duval } 34721e1553eSJérôme Duval 348ff99132eSAxel Dörfler newNode->id = vnodeID; 3490eaadd30SMichael Lotz _node->private_node = newNode; 3500eaadd30SMichael Lotz _node->ops = &gISO9660VnodeOps; 3510eaadd30SMichael Lotz *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH); 3520eaadd30SMichael Lotz *_flags = 0; 353ff99132eSAxel Dörfler 354ff99132eSAxel Dörfler if ((newNode->flags & ISO_ISDIR) == 0) { 355ff99132eSAxel Dörfler newNode->cache = file_cache_create(ns->id, vnodeID, 3563d268edaSAxel Dörfler newNode->dataLen[FS_DATA_FORMAT]); 3575b4cb109SJérôme Duval } 3585b4cb109SJérôme Duval 359ff99132eSAxel Dörfler return B_OK; 36021e1553eSJérôme Duval } 36121e1553eSJérôme Duval 36221e1553eSJérôme Duval 36321e1553eSJérôme Duval static status_t 364eb097431SAxel Dörfler fs_release_vnode(fs_volume* /*_volume*/, fs_vnode* _node, bool /*reenter*/) 36521e1553eSJérôme Duval { 366eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 36721e1553eSJérôme Duval 368eb097431SAxel Dörfler TRACE(("fs_release_vnode - ENTER (%p)\n", node)); 36921e1553eSJérôme Duval 37021e1553eSJérôme Duval if (node->id != ISO_ROOTNODE_ID) { 371eb097431SAxel Dörfler free(node->name); 37221e1553eSJérôme Duval free(node->attr.slName); 373eb097431SAxel Dörfler 3745b4cb109SJérôme Duval if (node->cache != NULL) 3755b4cb109SJérôme Duval file_cache_delete(node->cache); 37621e1553eSJérôme Duval 37721e1553eSJérôme Duval free(node); 37821e1553eSJérôme Duval } 37921e1553eSJérôme Duval 3805b4cb109SJérôme Duval TRACE(("fs_release_vnode - EXIT\n")); 381eb097431SAxel Dörfler return B_OK; 38221e1553eSJérôme Duval } 38321e1553eSJérôme Duval 38421e1553eSJérôme Duval 38521e1553eSJérôme Duval static status_t 3860eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos, 387e6bd90c5SIngo Weinhold const iovec *vecs, size_t count, size_t *_numBytes) 3885b4cb109SJérôme Duval { 389eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 390eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 3915b4cb109SJérôme Duval 392ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 393ff99132eSAxel Dörfler size_t bytesLeft = *_numBytes; 3945b4cb109SJérôme Duval 395ff99132eSAxel Dörfler if (pos >= fileSize) { 396ff99132eSAxel Dörfler *_numBytes = 0; 3975b4cb109SJérôme Duval return B_OK; 3985b4cb109SJérôme Duval } 399ff99132eSAxel Dörfler if (pos + bytesLeft > fileSize) { 400ff99132eSAxel Dörfler bytesLeft = fileSize - pos; 401ff99132eSAxel Dörfler *_numBytes = bytesLeft; 4025b4cb109SJérôme Duval } 4035b4cb109SJérôme Duval 404ff99132eSAxel Dörfler file_io_vec fileVec; 405ff99132eSAxel Dörfler fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT] 406ff99132eSAxel Dörfler * ns->logicalBlkSize[FS_DATA_FORMAT]; 407ff99132eSAxel Dörfler fileVec.length = bytesLeft; 4085b4cb109SJérôme Duval 409ff99132eSAxel Dörfler uint32 vecIndex = 0; 410ff99132eSAxel Dörfler size_t vecOffset = 0; 411ff99132eSAxel Dörfler return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count, 412ff99132eSAxel Dörfler &vecIndex, &vecOffset, &bytesLeft); 4135b4cb109SJérôme Duval } 4145b4cb109SJérôme Duval 4155b4cb109SJérôme Duval 4165b4cb109SJérôme Duval static status_t 4170eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st) 41821e1553eSJérôme Duval { 419eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume*)_vol->private_volume; 420eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode*)_node->private_node; 4213b723f79SJérôme Duval status_t result = B_NO_ERROR; 42221e1553eSJérôme Duval time_t time; 42321e1553eSJérôme Duval 4243b723f79SJérôme Duval TRACE(("fs_read_stat - ENTER\n")); 42521e1553eSJérôme Duval 42621e1553eSJérôme Duval st->st_dev = ns->id; 42721e1553eSJérôme Duval st->st_ino = node->id; 42821e1553eSJérôme Duval st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 42921e1553eSJérôme Duval st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 43021e1553eSJérôme Duval st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 43121e1553eSJérôme Duval st->st_blksize = 65536; 43221e1553eSJérôme Duval st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 43321e1553eSJérôme Duval 43421e1553eSJérôme Duval // Same for file/dir in ISO9660 43521e1553eSJérôme Duval st->st_size = node->dataLen[FS_DATA_FORMAT]; 436*2c348abbSAxel Dörfler st->st_blocks = (st->st_size + 511) / 512; 43721e1553eSJérôme Duval if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 43821e1553eSJérôme Duval st->st_ctime = st->st_mtime = st->st_atime = time; 43921e1553eSJérôme Duval 4403b723f79SJérôme Duval TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 44121e1553eSJérôme Duval 44221e1553eSJérôme Duval return result; 44321e1553eSJérôme Duval } 44421e1553eSJérôme Duval 44521e1553eSJérôme Duval 44621e1553eSJérôme Duval static status_t 4470eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie) 44821e1553eSJérôme Duval { 44921e1553eSJérôme Duval status_t result = B_NO_ERROR; 45021e1553eSJérôme Duval 4510eaadd30SMichael Lotz (void)_vol; 45221e1553eSJérôme Duval (void)cookie; 45321e1553eSJérôme Duval 45421e1553eSJérôme Duval // Do not allow any of the write-like open modes to get by 45521e1553eSJérôme Duval if ((omode == O_WRONLY) || (omode == O_RDWR)) 45621e1553eSJérôme Duval result = EROFS; 45721e1553eSJérôme Duval else if((omode & O_TRUNC) || (omode & O_CREAT)) 45821e1553eSJérôme Duval result = EROFS; 45921e1553eSJérôme Duval 46021e1553eSJérôme Duval return result; 46121e1553eSJérôme Duval } 46221e1553eSJérôme Duval 46321e1553eSJérôme Duval 46421e1553eSJérôme Duval static status_t 4650eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer, 466ff99132eSAxel Dörfler size_t *_length) 46721e1553eSJérôme Duval { 468eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 46921e1553eSJérôme Duval 47021e1553eSJérôme Duval if (node->flags & ISO_ISDIR) 47121e1553eSJérôme Duval return EISDIR; 47221e1553eSJérôme Duval 473ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 4745b4cb109SJérôme Duval 4755b4cb109SJérôme Duval // set/check boundaries for pos/length 476ff99132eSAxel Dörfler if (pos < 0) 4775b4cb109SJérôme Duval return B_BAD_VALUE; 478ff99132eSAxel Dörfler if (pos >= fileSize) { 479ff99132eSAxel Dörfler *_length = 0; 4805b4cb109SJérôme Duval return B_OK; 4815b4cb109SJérôme Duval } 482ff99132eSAxel Dörfler 483ff99132eSAxel Dörfler return file_cache_read(node->cache, NULL, pos, buffer, _length); 48421e1553eSJérôme Duval } 48521e1553eSJérôme Duval 48621e1553eSJérôme Duval 48721e1553eSJérôme Duval static status_t 4880eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie) 48921e1553eSJérôme Duval { 4900eaadd30SMichael Lotz (void)_vol; 4910eaadd30SMichael Lotz (void)_node; 49221e1553eSJérôme Duval (void)cookie; 49321e1553eSJérôme Duval 49421e1553eSJérôme Duval return B_OK; 49521e1553eSJérôme Duval } 49621e1553eSJérôme Duval 497ff99132eSAxel Dörfler 49821e1553eSJérôme Duval static status_t 4990eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 50021e1553eSJérôme Duval { 5010eaadd30SMichael Lotz (void)_vol; 5020eaadd30SMichael Lotz (void)_node; 50321e1553eSJérôme Duval (void)cookie; 50421e1553eSJérôme Duval 50521e1553eSJérôme Duval return B_OK; 50621e1553eSJérôme Duval } 50721e1553eSJérôme Duval 508ff99132eSAxel Dörfler 50921e1553eSJérôme Duval static status_t 5100eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode) 51121e1553eSJérôme Duval { 5120eaadd30SMichael Lotz (void)_vol; 5130eaadd30SMichael Lotz (void)_node; 51421e1553eSJérôme Duval (void)mode; 51521e1553eSJérôme Duval 51621e1553eSJérôme Duval return B_OK; 51721e1553eSJérôme Duval } 51821e1553eSJérôme Duval 519ff99132eSAxel Dörfler 52021e1553eSJérôme Duval static status_t 5210eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize) 52221e1553eSJérôme Duval { 523eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 52421e1553eSJérôme Duval 525ff99132eSAxel Dörfler if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) 526ff99132eSAxel Dörfler return B_BAD_VALUE; 52721e1553eSJérôme Duval 52821e1553eSJérôme Duval size_t length = strlen(node->attr.slName); 52921e1553eSJérôme Duval if (length > *_bufferSize) 5303b723f79SJérôme Duval memcpy(buffer, node->attr.slName, *_bufferSize); 5313b723f79SJérôme Duval else { 53221e1553eSJérôme Duval memcpy(buffer, node->attr.slName, length); 5333b723f79SJérôme Duval *_bufferSize = length; 5343b723f79SJérôme Duval } 53521e1553eSJérôme Duval 536ff99132eSAxel Dörfler return B_OK; 53721e1553eSJérôme Duval } 53821e1553eSJérôme Duval 53921e1553eSJérôme Duval 54021e1553eSJérôme Duval static status_t 541eb097431SAxel Dörfler fs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie) 54221e1553eSJérôme Duval { 543eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 54421e1553eSJérôme Duval 545eb097431SAxel Dörfler TRACE(("fs_open_dir - node is %p\n", node)); 54621e1553eSJérôme Duval 54721e1553eSJérôme Duval if (!(node->flags & ISO_ISDIR)) 548ff99132eSAxel Dörfler return B_NOT_A_DIRECTORY; 54921e1553eSJérôme Duval 550ff99132eSAxel Dörfler dircookie* dirCookie = (dircookie*)malloc(sizeof(dircookie)); 551ff99132eSAxel Dörfler if (dirCookie == NULL) 552ff99132eSAxel Dörfler return B_NO_MEMORY; 553ff99132eSAxel Dörfler 55421e1553eSJérôme Duval dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 55521e1553eSJérôme Duval dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 55621e1553eSJérôme Duval dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 55721e1553eSJérôme Duval dirCookie->pos = 0; 55821e1553eSJérôme Duval dirCookie->id = node->id; 559eb097431SAxel Dörfler *_cookie = (void*)dirCookie; 56021e1553eSJérôme Duval 561ff99132eSAxel Dörfler return B_OK; 56221e1553eSJérôme Duval } 56321e1553eSJérôme Duval 56421e1553eSJérôme Duval 56521e1553eSJérôme Duval static status_t 56644d0dbc8SAxel Dörfler fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, 56744d0dbc8SAxel Dörfler struct dirent *buffer, size_t bufferSize, uint32 *num) 56821e1553eSJérôme Duval { 569eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 57021e1553eSJérôme Duval dircookie *dirCookie = (dircookie *)_cookie; 57121e1553eSJérôme Duval 5725b4cb109SJérôme Duval TRACE(("fs_read_dir - ENTER\n")); 57321e1553eSJérôme Duval 574ff99132eSAxel Dörfler status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize); 57521e1553eSJérôme Duval 57621e1553eSJérôme Duval // If we succeeded, return 1, the number of dirents we read. 577ff99132eSAxel Dörfler if (result == B_OK) 57821e1553eSJérôme Duval *num = 1; 57921e1553eSJérôme Duval else 58021e1553eSJérôme Duval *num = 0; 58121e1553eSJérôme Duval 58221e1553eSJérôme Duval // When you get to the end, don't return an error, just return 58321e1553eSJérôme Duval // a zero in *num. 58421e1553eSJérôme Duval 585eb097431SAxel Dörfler if (result == B_ENTRY_NOT_FOUND) 586ff99132eSAxel Dörfler result = B_OK; 58721e1553eSJérôme Duval 5885b4cb109SJérôme Duval TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result))); 58921e1553eSJérôme Duval return result; 59021e1553eSJérôme Duval } 59121e1553eSJérôme Duval 59221e1553eSJérôme Duval 59321e1553eSJérôme Duval static status_t 5940eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie) 59521e1553eSJérôme Duval { 59621e1553eSJérôme Duval dircookie *cookie = (dircookie*)_cookie; 59721e1553eSJérôme Duval 59821e1553eSJérôme Duval cookie->block = cookie->startBlock; 59921e1553eSJérôme Duval cookie->pos = 0; 600ff99132eSAxel Dörfler return B_OK; 60121e1553eSJérôme Duval } 60221e1553eSJérôme Duval 60321e1553eSJérôme Duval 60421e1553eSJérôme Duval static status_t 6050eaadd30SMichael Lotz fs_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie) 60621e1553eSJérôme Duval { 60721e1553eSJérôme Duval return B_OK; 60821e1553eSJérôme Duval } 60921e1553eSJérôme Duval 61021e1553eSJérôme Duval 61121e1553eSJérôme Duval static status_t 6120eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 61321e1553eSJérôme Duval { 61421e1553eSJérôme Duval free(cookie); 61521e1553eSJérôme Duval return B_OK; 61621e1553eSJérôme Duval } 61721e1553eSJérôme Duval 618ff99132eSAxel Dörfler 61921e1553eSJérôme Duval // #pragma mark - 62021e1553eSJérôme Duval 62121e1553eSJérôme Duval 62221e1553eSJérôme Duval static status_t 62321e1553eSJérôme Duval iso_std_ops(int32 op, ...) 62421e1553eSJérôme Duval { 62521e1553eSJérôme Duval switch (op) { 62621e1553eSJérôme Duval case B_MODULE_INIT: 62721e1553eSJérôme Duval case B_MODULE_UNINIT: 62821e1553eSJérôme Duval return B_OK; 62921e1553eSJérôme Duval default: 63021e1553eSJérôme Duval return B_ERROR; 63121e1553eSJérôme Duval } 63221e1553eSJérôme Duval } 63321e1553eSJérôme Duval 63421e1553eSJérôme Duval 6350eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = { 6360eaadd30SMichael Lotz &fs_unmount, 6370eaadd30SMichael Lotz &fs_read_fs_stat, 6380eaadd30SMichael Lotz NULL, 6390eaadd30SMichael Lotz NULL, 6400eaadd30SMichael Lotz &fs_read_vnode, 6410eaadd30SMichael Lotz 6420eaadd30SMichael Lotz /* index and index directory ops */ 6430eaadd30SMichael Lotz NULL, 6440eaadd30SMichael Lotz NULL, 6450eaadd30SMichael Lotz NULL, 6460eaadd30SMichael Lotz NULL, 6470eaadd30SMichael Lotz NULL, 6480eaadd30SMichael Lotz NULL, 6490eaadd30SMichael Lotz NULL, 6500eaadd30SMichael Lotz NULL, 6510eaadd30SMichael Lotz 6520eaadd30SMichael Lotz /* query ops */ 6530eaadd30SMichael Lotz NULL, 6540eaadd30SMichael Lotz NULL, 6550eaadd30SMichael Lotz NULL, 6560eaadd30SMichael Lotz NULL, 6570eaadd30SMichael Lotz NULL, 6580eaadd30SMichael Lotz 6590eaadd30SMichael Lotz /* FS layer ops */ 6600eaadd30SMichael Lotz NULL, 6610eaadd30SMichael Lotz NULL, 6620eaadd30SMichael Lotz }; 6630eaadd30SMichael Lotz 6640eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = { 6650eaadd30SMichael Lotz &fs_walk, 6660eaadd30SMichael Lotz &fs_get_vnode_name, 6670eaadd30SMichael Lotz &fs_release_vnode, 6680eaadd30SMichael Lotz NULL, 6690eaadd30SMichael Lotz 6700eaadd30SMichael Lotz /* vm-related ops */ 6710eaadd30SMichael Lotz NULL, 6720eaadd30SMichael Lotz &fs_read_pages, 6730eaadd30SMichael Lotz NULL, 6740eaadd30SMichael Lotz 675ec598fe4SIngo Weinhold NULL, // io() 676ec598fe4SIngo Weinhold NULL, // cancel_io() 677ec598fe4SIngo Weinhold 6780eaadd30SMichael Lotz /* cache file access */ 6790eaadd30SMichael Lotz NULL, 6800eaadd30SMichael Lotz 6810eaadd30SMichael Lotz /* common */ 6820eaadd30SMichael Lotz NULL, 6830eaadd30SMichael Lotz NULL, 6840eaadd30SMichael Lotz NULL, 6850eaadd30SMichael Lotz NULL, 6860eaadd30SMichael Lotz NULL, 6870eaadd30SMichael Lotz &fs_read_link, 6880eaadd30SMichael Lotz NULL, 6890eaadd30SMichael Lotz NULL, 6900eaadd30SMichael Lotz NULL, 6910eaadd30SMichael Lotz NULL, 6920eaadd30SMichael Lotz &fs_access, 6930eaadd30SMichael Lotz &fs_read_stat, 6940eaadd30SMichael Lotz NULL, 6950eaadd30SMichael Lotz 6960eaadd30SMichael Lotz /* file */ 6970eaadd30SMichael Lotz NULL, 6980eaadd30SMichael Lotz &fs_open, 6990eaadd30SMichael Lotz &fs_close, 7000eaadd30SMichael Lotz &fs_free_cookie, 7010eaadd30SMichael Lotz &fs_read, 7020eaadd30SMichael Lotz NULL, 7030eaadd30SMichael Lotz 7040eaadd30SMichael Lotz /* dir */ 7050eaadd30SMichael Lotz NULL, 7060eaadd30SMichael Lotz NULL, 7070eaadd30SMichael Lotz &fs_open_dir, 7080eaadd30SMichael Lotz &fs_close_dir, 7090eaadd30SMichael Lotz &fs_free_dir_cookie, 7100eaadd30SMichael Lotz &fs_read_dir, 7110eaadd30SMichael Lotz &fs_rewind_dir, 7120eaadd30SMichael Lotz 7130eaadd30SMichael Lotz /* attribute directory ops */ 7140eaadd30SMichael Lotz NULL, 7150eaadd30SMichael Lotz NULL, 7160eaadd30SMichael Lotz NULL, 7170eaadd30SMichael Lotz NULL, 7180eaadd30SMichael Lotz NULL, 7190eaadd30SMichael Lotz 7200eaadd30SMichael Lotz /* attribute ops */ 7210eaadd30SMichael Lotz NULL, 7220eaadd30SMichael Lotz NULL, 7230eaadd30SMichael Lotz NULL, 7240eaadd30SMichael Lotz NULL, 7250eaadd30SMichael Lotz NULL, 7260eaadd30SMichael Lotz NULL, 7270eaadd30SMichael Lotz NULL, 7280eaadd30SMichael Lotz NULL, 7290eaadd30SMichael Lotz NULL, 7300eaadd30SMichael Lotz NULL, 7310eaadd30SMichael Lotz 7320eaadd30SMichael Lotz /* node and FS layer support */ 7330eaadd30SMichael Lotz NULL, 7340eaadd30SMichael Lotz NULL, 7350eaadd30SMichael Lotz }; 7360eaadd30SMichael Lotz 73721e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = { 73821e1553eSJérôme Duval { 73921e1553eSJérôme Duval "file_systems/iso9660" B_CURRENT_FS_API_VERSION, 74021e1553eSJérôme Duval 0, 74121e1553eSJérôme Duval iso_std_ops, 74221e1553eSJérôme Duval }, 74321e1553eSJérôme Duval 7441da9f5ceSAxel Dörfler "iso9660", // short_name 7451da9f5ceSAxel Dörfler "ISO9660 File System", // pretty_name 74676a8ec23SIngo Weinhold 0, // DDM flags 74721e1553eSJérôme Duval 74821e1553eSJérôme Duval // scanning 74921e1553eSJérôme Duval fs_identify_partition, 75021e1553eSJérôme Duval fs_scan_partition, 75121e1553eSJérôme Duval fs_free_identify_partition_cookie, 75221e1553eSJérôme Duval NULL, // free_partition_content_cookie() 75321e1553eSJérôme Duval 75421e1553eSJérôme Duval &fs_mount, 7550eaadd30SMichael Lotz 7560eaadd30SMichael Lotz /* capability querying */ 7570eaadd30SMichael Lotz NULL, 7580eaadd30SMichael Lotz NULL, 7590eaadd30SMichael Lotz NULL, 7600eaadd30SMichael Lotz NULL, 76121e1553eSJérôme Duval NULL, 76221e1553eSJérôme Duval NULL, 76321e1553eSJérôme Duval 7640eaadd30SMichael Lotz /* shadow partition modifications */ 7650eaadd30SMichael Lotz NULL, 76621e1553eSJérôme Duval 7670eaadd30SMichael Lotz /* writing */ 7680eaadd30SMichael Lotz NULL, 7690eaadd30SMichael Lotz NULL, 7700eaadd30SMichael Lotz NULL, 7710eaadd30SMichael Lotz NULL, 7720eaadd30SMichael Lotz NULL, 7730eaadd30SMichael Lotz NULL, 7740eaadd30SMichael Lotz NULL, 77521e1553eSJérôme Duval }; 77621e1553eSJérôme Duval 77721e1553eSJérôme Duval module_info *modules[] = { 77821e1553eSJérôme Duval (module_info *)&sISO660FileSystem, 77921e1553eSJérôme Duval NULL, 78021e1553eSJérôme Duval }; 78121e1553eSJérôme Duval 782