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, 140a26c2439SMichael Lotz &gISO9660VnodeOps, 141a26c2439SMichael Lotz volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0); 142ff99132eSAxel Dörfler if (result != B_OK) { 143ff99132eSAxel Dörfler block_cache_delete(volume->fBlockCache, false); 144ff99132eSAxel Dörfler free(volume); 145ff99132eSAxel Dörfler result = B_ERROR; 146ff99132eSAxel Dörfler } 14721e1553eSJérôme Duval } 14821e1553eSJérôme Duval return result; 14921e1553eSJérôme Duval } 15021e1553eSJérôme Duval 15121e1553eSJérôme Duval 15221e1553eSJérôme Duval static status_t 1530eaadd30SMichael Lotz fs_unmount(fs_volume *_vol) 15421e1553eSJérôme Duval { 15521e1553eSJérôme Duval status_t result = B_NO_ERROR; 156eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 15721e1553eSJérôme Duval 15821e1553eSJérôme Duval TRACE(("fs_unmount - ENTER\n")); 15921e1553eSJérôme Duval 1609d254f45SJérôme Duval // Unlike in BeOS, we need to put the reference to our root node ourselves 1610eaadd30SMichael Lotz put_vnode(_vol, ISO_ROOTNODE_ID); 1629d254f45SJérôme Duval 16321e1553eSJérôme Duval block_cache_delete(ns->fBlockCache, false); 16421e1553eSJérôme Duval close(ns->fdOfSession); 16521e1553eSJérôme Duval result = close(ns->fd); 16621e1553eSJérôme Duval 16721e1553eSJérôme Duval free(ns); 16821e1553eSJérôme Duval 16921e1553eSJérôme Duval TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result))); 17021e1553eSJérôme Duval return result; 17121e1553eSJérôme Duval } 17221e1553eSJérôme Duval 17321e1553eSJérôme Duval 17421e1553eSJérôme Duval static status_t 1750eaadd30SMichael Lotz fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss) 17621e1553eSJérôme Duval { 177eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 17821e1553eSJérôme Duval int i; 17921e1553eSJérôme Duval 18021e1553eSJérôme Duval fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 18121e1553eSJérôme Duval fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT]; 18221e1553eSJérôme Duval fss->io_size = 65536; 18321e1553eSJérôme Duval fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT]; 18421e1553eSJérôme Duval fss->free_blocks = 0; 18521e1553eSJérôme Duval 18621e1553eSJérôme Duval strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name)); 18721e1553eSJérôme Duval 18821e1553eSJérôme Duval strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name)); 189ff99132eSAxel Dörfler for (i = strlen(fss->volume_name) - 1; i >=0 ; i--) { 19021e1553eSJérôme Duval if (fss->volume_name[i] != ' ') 19121e1553eSJérôme Duval break; 192ff99132eSAxel Dörfler } 19321e1553eSJérôme Duval 19421e1553eSJérôme Duval if (i < 0) 19521e1553eSJérôme Duval strcpy(fss->volume_name, "UNKNOWN"); 19621e1553eSJérôme Duval else 19721e1553eSJérôme Duval fss->volume_name[i + 1] = 0; 19821e1553eSJérôme Duval 19921e1553eSJérôme Duval strcpy(fss->fsh_name, "iso9660"); 200ff99132eSAxel Dörfler return B_OK; 20121e1553eSJérôme Duval } 20221e1553eSJérôme Duval 2033b723f79SJérôme Duval 2043b723f79SJérôme Duval static status_t 2050eaadd30SMichael Lotz fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferSize) 2063b723f79SJérôme Duval { 207eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode*)_node->private_node; 2083b723f79SJérôme Duval 209eb097431SAxel Dörfler strlcpy(buffer, node->name, bufferSize); 2103b723f79SJérôme Duval return B_OK; 2113b723f79SJérôme Duval } 2123b723f79SJérôme Duval 2133b723f79SJérôme Duval 21421e1553eSJérôme Duval static status_t 2150eaadd30SMichael Lotz fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID) 21621e1553eSJérôme Duval { 217eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 218eb097431SAxel Dörfler iso9660_inode *baseNode = (iso9660_inode*)_base->private_node; 219eb097431SAxel Dörfler iso9660_inode *newNode = NULL; 22021e1553eSJérôme Duval 221eb097431SAxel Dörfler TRACE(("fs_walk - looking for %s in dir file of length %ld\n", file, 22221e1553eSJérôme Duval baseNode->dataLen[FS_DATA_FORMAT])); 22321e1553eSJérôme Duval 22421e1553eSJérôme Duval if (strcmp(file, ".") == 0) { 22521e1553eSJérôme Duval // base directory 22621e1553eSJérôme Duval TRACE(("fs_walk - found \".\" file.\n")); 22721e1553eSJérôme Duval *_vnodeID = baseNode->id; 228*49004dc7SMichael Lotz return get_vnode(_vol, *_vnodeID, NULL); 22921e1553eSJérôme Duval } else if (strcmp(file, "..") == 0) { 23021e1553eSJérôme Duval // parent directory 23121e1553eSJérôme Duval TRACE(("fs_walk - found \"..\" file.\n")); 23221e1553eSJérôme Duval *_vnodeID = baseNode->parID; 233*49004dc7SMichael Lotz return get_vnode(_vol, *_vnodeID, NULL); 234ff99132eSAxel Dörfler } 235ff99132eSAxel Dörfler 23621e1553eSJérôme Duval // look up file in the directory 237ff99132eSAxel Dörfler uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT]; 238ff99132eSAxel Dörfler status_t result = ENOENT; 239eb097431SAxel Dörfler size_t totalRead = 0; 240ff99132eSAxel Dörfler off_t block = baseNode->startLBN[FS_DATA_FORMAT]; 241ff99132eSAxel Dörfler bool done = false; 24221e1553eSJérôme Duval 243ff99132eSAxel Dörfler while (totalRead < dataLength && !done) { 24421e1553eSJérôme Duval off_t cachedBlock = block; 245eb097431SAxel Dörfler char* blockData = (char*)block_cache_get(ns->fBlockCache, block); 24621e1553eSJérôme Duval if (blockData != NULL) { 247eb097431SAxel Dörfler size_t bytesRead = 0; 24821e1553eSJérôme Duval off_t blockBytesRead = 0; 249eb097431SAxel Dörfler iso9660_inode node; 25021e1553eSJérôme Duval int initResult; 25121e1553eSJérôme Duval 252eb097431SAxel Dörfler TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer " 253eb097431SAxel Dörfler "%p.\n", block, blockData)); 25421e1553eSJérôme Duval 25521e1553eSJérôme Duval // Move to the next 2-block set if necessary 25621e1553eSJérôme Duval // Don't go over end of buffer, if dir record sits on boundary. 25721e1553eSJérôme Duval 25821e1553eSJérôme Duval while (blockBytesRead < 2 * ns->logicalBlkSize[FS_DATA_FORMAT] 259ff99132eSAxel Dörfler && totalRead + blockBytesRead < dataLength 26021e1553eSJérôme Duval && blockData[0] != 0 261ff99132eSAxel Dörfler && !done) { 262ff99132eSAxel Dörfler initResult = InitNode(&node, blockData, &bytesRead, 263ff99132eSAxel Dörfler ns->joliet_level); 264eb097431SAxel Dörfler TRACE(("fs_walk - InitNode returned %s, filename %s, %lu bytes " 265eb097431SAxel Dörfler "read\n", strerror(initResult), node.name, 266eb097431SAxel Dörfler bytesRead)); 26721e1553eSJérôme Duval 268ff99132eSAxel Dörfler if (initResult == B_OK) { 269eb097431SAxel Dörfler if (!strcmp(node.name, file)) { 27021e1553eSJérôme Duval TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead)); 271ff99132eSAxel Dörfler *_vnodeID = (block << 30) 272ff99132eSAxel Dörfler + (blockBytesRead & 0xffffffff); 27321e1553eSJérôme Duval TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); 27421e1553eSJérôme Duval 2750eaadd30SMichael Lotz result = get_vnode(_vol, *_vnodeID, 276*49004dc7SMichael Lotz (void **)&newNode); 277ff99132eSAxel Dörfler if (result == B_OK) { 27821e1553eSJérôme Duval newNode->parID = baseNode->id; 279ff99132eSAxel Dörfler done = true; 28021e1553eSJérôme Duval } 28121e1553eSJérôme Duval } else { 282eb097431SAxel Dörfler free(node.name); 28321e1553eSJérôme Duval free(node.attr.slName); 28421e1553eSJérôme Duval } 28521e1553eSJérôme Duval } else { 28621e1553eSJérôme Duval result = initResult; 28721e1553eSJérôme Duval if (bytesRead == 0) 28821e1553eSJérôme Duval done = TRUE; 28921e1553eSJérôme Duval } 29021e1553eSJérôme Duval blockData += bytesRead; 29121e1553eSJérôme Duval blockBytesRead += bytesRead; 29221e1553eSJérôme Duval 293eb097431SAxel Dörfler TRACE(("fs_walk - Adding %lu bytes to blockBytes read (total " 294eb097431SAxel Dörfler "%Ld/%lu).\n", bytesRead, blockBytesRead, 295eb097431SAxel Dörfler baseNode->dataLen[FS_DATA_FORMAT])); 29621e1553eSJérôme Duval } 29721e1553eSJérôme Duval totalRead += ns->logicalBlkSize[FS_DATA_FORMAT]; 29821e1553eSJérôme Duval block++; 29921e1553eSJérôme Duval 300eb097431SAxel Dörfler TRACE(("fs_walk - moving to next block %Ld, total read %lu\n", 301eb097431SAxel Dörfler block, totalRead)); 30221e1553eSJérôme Duval block_cache_put(ns->fBlockCache, cachedBlock); 30321e1553eSJérôme Duval 30421e1553eSJérôme Duval } else 30521e1553eSJérôme Duval done = TRUE; 30621e1553eSJérôme Duval } 30721e1553eSJérôme Duval 308ff99132eSAxel Dörfler TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", 309ff99132eSAxel Dörfler strerror(result), *_vnodeID)); 31021e1553eSJérôme Duval return result; 31121e1553eSJérôme Duval } 31221e1553eSJérôme Duval 31321e1553eSJérôme Duval 31421e1553eSJérôme Duval static status_t 3150eaadd30SMichael Lotz fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node, 3160eaadd30SMichael Lotz int *_type, uint32 *_flags, bool reenter) 31721e1553eSJérôme Duval { 318eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume*)_vol->private_volume; 319ff99132eSAxel Dörfler 320eb097431SAxel Dörfler iso9660_inode *newNode = (iso9660_inode*)calloc(sizeof(iso9660_inode), 1); 321ff99132eSAxel Dörfler if (newNode == NULL) 322ff99132eSAxel Dörfler return B_NO_MEMORY; 32321e1553eSJérôme Duval 324ff99132eSAxel Dörfler uint32 pos = vnodeID & 0x3fffffff; 325ff99132eSAxel Dörfler uint32 block = vnodeID >> 30; 32621e1553eSJérôme Duval 327eb097431SAxel Dörfler TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node %p\n", 328ff99132eSAxel Dörfler block, pos, vnodeID, newNode)); 32921e1553eSJérôme Duval 330d02cde30SMichael Lotz if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) { 331d02cde30SMichael Lotz free(newNode); 332ff99132eSAxel Dörfler return B_BAD_VALUE; 333d02cde30SMichael Lotz } 33421e1553eSJérôme Duval 335eb097431SAxel Dörfler char *data = (char *)block_cache_get(ns->fBlockCache, block); 336ff99132eSAxel Dörfler if (data == NULL) { 337ff99132eSAxel Dörfler free(newNode); 338ff99132eSAxel Dörfler return B_IO_ERROR; 339ff99132eSAxel Dörfler } 34021e1553eSJérôme Duval 341ff99132eSAxel Dörfler status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level); 34221e1553eSJérôme Duval block_cache_put(ns->fBlockCache, block); 34321e1553eSJérôme Duval 344ff99132eSAxel Dörfler if (result < B_OK) { 345ff99132eSAxel Dörfler free(newNode); 346ff99132eSAxel Dörfler return result; 34721e1553eSJérôme Duval } 34821e1553eSJérôme Duval 349ff99132eSAxel Dörfler newNode->id = vnodeID; 3500eaadd30SMichael Lotz _node->private_node = newNode; 3510eaadd30SMichael Lotz _node->ops = &gISO9660VnodeOps; 3520eaadd30SMichael Lotz *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH); 353a26c2439SMichael Lotz *_flags = 0; 354ff99132eSAxel Dörfler 355ff99132eSAxel Dörfler if ((newNode->flags & ISO_ISDIR) == 0) { 356ff99132eSAxel Dörfler newNode->cache = file_cache_create(ns->id, vnodeID, 3573d268edaSAxel Dörfler newNode->dataLen[FS_DATA_FORMAT]); 3585b4cb109SJérôme Duval } 3595b4cb109SJérôme Duval 360ff99132eSAxel Dörfler return B_OK; 36121e1553eSJérôme Duval } 36221e1553eSJérôme Duval 36321e1553eSJérôme Duval 36421e1553eSJérôme Duval static status_t 365eb097431SAxel Dörfler fs_release_vnode(fs_volume* /*_volume*/, fs_vnode* _node, bool /*reenter*/) 36621e1553eSJérôme Duval { 367eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 36821e1553eSJérôme Duval 369eb097431SAxel Dörfler TRACE(("fs_release_vnode - ENTER (%p)\n", node)); 37021e1553eSJérôme Duval 37121e1553eSJérôme Duval if (node->id != ISO_ROOTNODE_ID) { 372eb097431SAxel Dörfler free(node->name); 37321e1553eSJérôme Duval free(node->attr.slName); 374eb097431SAxel Dörfler 3755b4cb109SJérôme Duval if (node->cache != NULL) 3765b4cb109SJérôme Duval file_cache_delete(node->cache); 37721e1553eSJérôme Duval 37821e1553eSJérôme Duval free(node); 37921e1553eSJérôme Duval } 38021e1553eSJérôme Duval 3815b4cb109SJérôme Duval TRACE(("fs_release_vnode - EXIT\n")); 382eb097431SAxel Dörfler return B_OK; 38321e1553eSJérôme Duval } 38421e1553eSJérôme Duval 38521e1553eSJérôme Duval 38621e1553eSJérôme Duval static status_t 3870eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos, 388e6bd90c5SIngo Weinhold const iovec *vecs, size_t count, size_t *_numBytes) 3895b4cb109SJérôme Duval { 390eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 391eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 3925b4cb109SJérôme Duval 393ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 394ff99132eSAxel Dörfler size_t bytesLeft = *_numBytes; 3955b4cb109SJérôme Duval 396ff99132eSAxel Dörfler if (pos >= fileSize) { 397ff99132eSAxel Dörfler *_numBytes = 0; 3985b4cb109SJérôme Duval return B_OK; 3995b4cb109SJérôme Duval } 400ff99132eSAxel Dörfler if (pos + bytesLeft > fileSize) { 401ff99132eSAxel Dörfler bytesLeft = fileSize - pos; 402ff99132eSAxel Dörfler *_numBytes = bytesLeft; 4035b4cb109SJérôme Duval } 4045b4cb109SJérôme Duval 405ff99132eSAxel Dörfler file_io_vec fileVec; 406ff99132eSAxel Dörfler fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT] 407ff99132eSAxel Dörfler * ns->logicalBlkSize[FS_DATA_FORMAT]; 408ff99132eSAxel Dörfler fileVec.length = bytesLeft; 4095b4cb109SJérôme Duval 410ff99132eSAxel Dörfler uint32 vecIndex = 0; 411ff99132eSAxel Dörfler size_t vecOffset = 0; 412ff99132eSAxel Dörfler return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count, 413ff99132eSAxel Dörfler &vecIndex, &vecOffset, &bytesLeft); 4145b4cb109SJérôme Duval } 4155b4cb109SJérôme Duval 4165b4cb109SJérôme Duval 4175b4cb109SJérôme Duval static status_t 4180eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st) 41921e1553eSJérôme Duval { 420eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume*)_vol->private_volume; 421eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode*)_node->private_node; 4223b723f79SJérôme Duval status_t result = B_NO_ERROR; 42321e1553eSJérôme Duval time_t time; 42421e1553eSJérôme Duval 4253b723f79SJérôme Duval TRACE(("fs_read_stat - ENTER\n")); 42621e1553eSJérôme Duval 42721e1553eSJérôme Duval st->st_dev = ns->id; 42821e1553eSJérôme Duval st->st_ino = node->id; 42921e1553eSJérôme Duval st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 43021e1553eSJérôme Duval st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 43121e1553eSJérôme Duval st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 43221e1553eSJérôme Duval st->st_blksize = 65536; 43321e1553eSJérôme Duval st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 43421e1553eSJérôme Duval 43521e1553eSJérôme Duval // Same for file/dir in ISO9660 43621e1553eSJérôme Duval st->st_size = node->dataLen[FS_DATA_FORMAT]; 4372c348abbSAxel Dörfler st->st_blocks = (st->st_size + 511) / 512; 43821e1553eSJérôme Duval if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 43921e1553eSJérôme Duval st->st_ctime = st->st_mtime = st->st_atime = time; 44021e1553eSJérôme Duval 4413b723f79SJérôme Duval TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 44221e1553eSJérôme Duval 44321e1553eSJérôme Duval return result; 44421e1553eSJérôme Duval } 44521e1553eSJérôme Duval 44621e1553eSJérôme Duval 44721e1553eSJérôme Duval static status_t 4480eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie) 44921e1553eSJérôme Duval { 45021e1553eSJérôme Duval status_t result = B_NO_ERROR; 45121e1553eSJérôme Duval 4520eaadd30SMichael Lotz (void)_vol; 45321e1553eSJérôme Duval (void)cookie; 45421e1553eSJérôme Duval 45521e1553eSJérôme Duval // Do not allow any of the write-like open modes to get by 45621e1553eSJérôme Duval if ((omode == O_WRONLY) || (omode == O_RDWR)) 45721e1553eSJérôme Duval result = EROFS; 45821e1553eSJérôme Duval else if((omode & O_TRUNC) || (omode & O_CREAT)) 45921e1553eSJérôme Duval result = EROFS; 46021e1553eSJérôme Duval 46121e1553eSJérôme Duval return result; 46221e1553eSJérôme Duval } 46321e1553eSJérôme Duval 46421e1553eSJérôme Duval 46521e1553eSJérôme Duval static status_t 4660eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer, 467ff99132eSAxel Dörfler size_t *_length) 46821e1553eSJérôme Duval { 469eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 47021e1553eSJérôme Duval 47121e1553eSJérôme Duval if (node->flags & ISO_ISDIR) 47221e1553eSJérôme Duval return EISDIR; 47321e1553eSJérôme Duval 474ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 4755b4cb109SJérôme Duval 4765b4cb109SJérôme Duval // set/check boundaries for pos/length 477ff99132eSAxel Dörfler if (pos < 0) 4785b4cb109SJérôme Duval return B_BAD_VALUE; 479ff99132eSAxel Dörfler if (pos >= fileSize) { 480ff99132eSAxel Dörfler *_length = 0; 4815b4cb109SJérôme Duval return B_OK; 4825b4cb109SJérôme Duval } 483ff99132eSAxel Dörfler 484ff99132eSAxel Dörfler return file_cache_read(node->cache, NULL, pos, buffer, _length); 48521e1553eSJérôme Duval } 48621e1553eSJérôme Duval 48721e1553eSJérôme Duval 48821e1553eSJérôme Duval static status_t 4890eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie) 49021e1553eSJérôme Duval { 4910eaadd30SMichael Lotz (void)_vol; 4920eaadd30SMichael Lotz (void)_node; 49321e1553eSJérôme Duval (void)cookie; 49421e1553eSJérôme Duval 49521e1553eSJérôme Duval return B_OK; 49621e1553eSJérôme Duval } 49721e1553eSJérôme Duval 498ff99132eSAxel Dörfler 49921e1553eSJérôme Duval static status_t 5000eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 50121e1553eSJérôme Duval { 5020eaadd30SMichael Lotz (void)_vol; 5030eaadd30SMichael Lotz (void)_node; 50421e1553eSJérôme Duval (void)cookie; 50521e1553eSJérôme Duval 50621e1553eSJérôme Duval return B_OK; 50721e1553eSJérôme Duval } 50821e1553eSJérôme Duval 509ff99132eSAxel Dörfler 51021e1553eSJérôme Duval static status_t 5110eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode) 51221e1553eSJérôme Duval { 5130eaadd30SMichael Lotz (void)_vol; 5140eaadd30SMichael Lotz (void)_node; 51521e1553eSJérôme Duval (void)mode; 51621e1553eSJérôme Duval 51721e1553eSJérôme Duval return B_OK; 51821e1553eSJérôme Duval } 51921e1553eSJérôme Duval 520ff99132eSAxel Dörfler 52121e1553eSJérôme Duval static status_t 5220eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize) 52321e1553eSJérôme Duval { 524eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 52521e1553eSJérôme Duval 526ff99132eSAxel Dörfler if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) 527ff99132eSAxel Dörfler return B_BAD_VALUE; 52821e1553eSJérôme Duval 52921e1553eSJérôme Duval size_t length = strlen(node->attr.slName); 53021e1553eSJérôme Duval if (length > *_bufferSize) 5313b723f79SJérôme Duval memcpy(buffer, node->attr.slName, *_bufferSize); 5323b723f79SJérôme Duval else { 53321e1553eSJérôme Duval memcpy(buffer, node->attr.slName, length); 5343b723f79SJérôme Duval *_bufferSize = length; 5353b723f79SJérôme Duval } 53621e1553eSJérôme Duval 537ff99132eSAxel Dörfler return B_OK; 53821e1553eSJérôme Duval } 53921e1553eSJérôme Duval 54021e1553eSJérôme Duval 54121e1553eSJérôme Duval static status_t 542eb097431SAxel Dörfler fs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie) 54321e1553eSJérôme Duval { 544eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 54521e1553eSJérôme Duval 546eb097431SAxel Dörfler TRACE(("fs_open_dir - node is %p\n", node)); 54721e1553eSJérôme Duval 54821e1553eSJérôme Duval if (!(node->flags & ISO_ISDIR)) 549ff99132eSAxel Dörfler return B_NOT_A_DIRECTORY; 55021e1553eSJérôme Duval 551ff99132eSAxel Dörfler dircookie* dirCookie = (dircookie*)malloc(sizeof(dircookie)); 552ff99132eSAxel Dörfler if (dirCookie == NULL) 553ff99132eSAxel Dörfler return B_NO_MEMORY; 554ff99132eSAxel Dörfler 55521e1553eSJérôme Duval dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 55621e1553eSJérôme Duval dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 55721e1553eSJérôme Duval dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 55821e1553eSJérôme Duval dirCookie->pos = 0; 55921e1553eSJérôme Duval dirCookie->id = node->id; 560eb097431SAxel Dörfler *_cookie = (void*)dirCookie; 56121e1553eSJérôme Duval 562ff99132eSAxel Dörfler return B_OK; 56321e1553eSJérôme Duval } 56421e1553eSJérôme Duval 56521e1553eSJérôme Duval 56621e1553eSJérôme Duval static status_t 56744d0dbc8SAxel Dörfler fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, 56844d0dbc8SAxel Dörfler struct dirent *buffer, size_t bufferSize, uint32 *num) 56921e1553eSJérôme Duval { 570eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 57121e1553eSJérôme Duval dircookie *dirCookie = (dircookie *)_cookie; 57221e1553eSJérôme Duval 5735b4cb109SJérôme Duval TRACE(("fs_read_dir - ENTER\n")); 57421e1553eSJérôme Duval 575ff99132eSAxel Dörfler status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize); 57621e1553eSJérôme Duval 57721e1553eSJérôme Duval // If we succeeded, return 1, the number of dirents we read. 578ff99132eSAxel Dörfler if (result == B_OK) 57921e1553eSJérôme Duval *num = 1; 58021e1553eSJérôme Duval else 58121e1553eSJérôme Duval *num = 0; 58221e1553eSJérôme Duval 58321e1553eSJérôme Duval // When you get to the end, don't return an error, just return 58421e1553eSJérôme Duval // a zero in *num. 58521e1553eSJérôme Duval 586eb097431SAxel Dörfler if (result == B_ENTRY_NOT_FOUND) 587ff99132eSAxel Dörfler result = B_OK; 58821e1553eSJérôme Duval 5895b4cb109SJérôme Duval TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result))); 59021e1553eSJérôme Duval return result; 59121e1553eSJérôme Duval } 59221e1553eSJérôme Duval 59321e1553eSJérôme Duval 59421e1553eSJérôme Duval static status_t 5950eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie) 59621e1553eSJérôme Duval { 59721e1553eSJérôme Duval dircookie *cookie = (dircookie*)_cookie; 59821e1553eSJérôme Duval 59921e1553eSJérôme Duval cookie->block = cookie->startBlock; 60021e1553eSJérôme Duval cookie->pos = 0; 601ff99132eSAxel Dörfler return B_OK; 60221e1553eSJérôme Duval } 60321e1553eSJérôme Duval 60421e1553eSJérôme Duval 60521e1553eSJérôme Duval static status_t 6060eaadd30SMichael Lotz fs_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie) 60721e1553eSJérôme Duval { 60821e1553eSJérôme Duval return B_OK; 60921e1553eSJérôme Duval } 61021e1553eSJérôme Duval 61121e1553eSJérôme Duval 61221e1553eSJérôme Duval static status_t 6130eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 61421e1553eSJérôme Duval { 61521e1553eSJérôme Duval free(cookie); 61621e1553eSJérôme Duval return B_OK; 61721e1553eSJérôme Duval } 61821e1553eSJérôme Duval 619ff99132eSAxel Dörfler 62021e1553eSJérôme Duval // #pragma mark - 62121e1553eSJérôme Duval 62221e1553eSJérôme Duval 62321e1553eSJérôme Duval static status_t 62421e1553eSJérôme Duval iso_std_ops(int32 op, ...) 62521e1553eSJérôme Duval { 62621e1553eSJérôme Duval switch (op) { 62721e1553eSJérôme Duval case B_MODULE_INIT: 62821e1553eSJérôme Duval case B_MODULE_UNINIT: 62921e1553eSJérôme Duval return B_OK; 63021e1553eSJérôme Duval default: 63121e1553eSJérôme Duval return B_ERROR; 63221e1553eSJérôme Duval } 63321e1553eSJérôme Duval } 63421e1553eSJérôme Duval 63521e1553eSJérôme Duval 6360eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = { 6370eaadd30SMichael Lotz &fs_unmount, 6380eaadd30SMichael Lotz &fs_read_fs_stat, 6390eaadd30SMichael Lotz NULL, 6400eaadd30SMichael Lotz NULL, 6410eaadd30SMichael Lotz &fs_read_vnode, 6420eaadd30SMichael Lotz 6430eaadd30SMichael Lotz /* index and index directory ops */ 6440eaadd30SMichael Lotz NULL, 6450eaadd30SMichael Lotz NULL, 6460eaadd30SMichael Lotz NULL, 6470eaadd30SMichael Lotz NULL, 6480eaadd30SMichael Lotz NULL, 6490eaadd30SMichael Lotz NULL, 6500eaadd30SMichael Lotz NULL, 6510eaadd30SMichael Lotz NULL, 6520eaadd30SMichael Lotz 6530eaadd30SMichael Lotz /* query ops */ 6540eaadd30SMichael Lotz NULL, 6550eaadd30SMichael Lotz NULL, 6560eaadd30SMichael Lotz NULL, 6570eaadd30SMichael Lotz NULL, 6580eaadd30SMichael Lotz NULL, 6590eaadd30SMichael Lotz 6600eaadd30SMichael Lotz /* FS layer ops */ 6610eaadd30SMichael Lotz NULL, 6620eaadd30SMichael Lotz NULL, 6630eaadd30SMichael Lotz }; 6640eaadd30SMichael Lotz 6650eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = { 6660eaadd30SMichael Lotz &fs_walk, 6670eaadd30SMichael Lotz &fs_get_vnode_name, 6680eaadd30SMichael Lotz &fs_release_vnode, 6690eaadd30SMichael Lotz NULL, 6700eaadd30SMichael Lotz 6710eaadd30SMichael Lotz /* vm-related ops */ 6720eaadd30SMichael Lotz NULL, 6730eaadd30SMichael Lotz &fs_read_pages, 6740eaadd30SMichael Lotz NULL, 6750eaadd30SMichael Lotz 676ec598fe4SIngo Weinhold NULL, // io() 677ec598fe4SIngo Weinhold NULL, // cancel_io() 678ec598fe4SIngo Weinhold 6790eaadd30SMichael Lotz /* cache file access */ 6800eaadd30SMichael Lotz NULL, 6810eaadd30SMichael Lotz 6820eaadd30SMichael Lotz /* common */ 6830eaadd30SMichael Lotz NULL, 6840eaadd30SMichael Lotz NULL, 6850eaadd30SMichael Lotz NULL, 6860eaadd30SMichael Lotz NULL, 6870eaadd30SMichael Lotz NULL, 6880eaadd30SMichael Lotz &fs_read_link, 6890eaadd30SMichael Lotz NULL, 6900eaadd30SMichael Lotz NULL, 6910eaadd30SMichael Lotz NULL, 6920eaadd30SMichael Lotz NULL, 6930eaadd30SMichael Lotz &fs_access, 6940eaadd30SMichael Lotz &fs_read_stat, 6950eaadd30SMichael Lotz NULL, 6960eaadd30SMichael Lotz 6970eaadd30SMichael Lotz /* file */ 6980eaadd30SMichael Lotz NULL, 6990eaadd30SMichael Lotz &fs_open, 7000eaadd30SMichael Lotz &fs_close, 7010eaadd30SMichael Lotz &fs_free_cookie, 7020eaadd30SMichael Lotz &fs_read, 7030eaadd30SMichael Lotz NULL, 7040eaadd30SMichael Lotz 7050eaadd30SMichael Lotz /* dir */ 7060eaadd30SMichael Lotz NULL, 7070eaadd30SMichael Lotz NULL, 7080eaadd30SMichael Lotz &fs_open_dir, 7090eaadd30SMichael Lotz &fs_close_dir, 7100eaadd30SMichael Lotz &fs_free_dir_cookie, 7110eaadd30SMichael Lotz &fs_read_dir, 7120eaadd30SMichael Lotz &fs_rewind_dir, 7130eaadd30SMichael Lotz 7140eaadd30SMichael Lotz /* attribute directory ops */ 7150eaadd30SMichael Lotz NULL, 7160eaadd30SMichael Lotz NULL, 7170eaadd30SMichael Lotz NULL, 7180eaadd30SMichael Lotz NULL, 7190eaadd30SMichael Lotz NULL, 7200eaadd30SMichael Lotz 7210eaadd30SMichael Lotz /* attribute ops */ 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 NULL, 7320eaadd30SMichael Lotz 7330eaadd30SMichael Lotz /* node and FS layer support */ 7340eaadd30SMichael Lotz NULL, 7350eaadd30SMichael Lotz NULL, 7360eaadd30SMichael Lotz }; 7370eaadd30SMichael Lotz 73821e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = { 73921e1553eSJérôme Duval { 74021e1553eSJérôme Duval "file_systems/iso9660" B_CURRENT_FS_API_VERSION, 74121e1553eSJérôme Duval 0, 74221e1553eSJérôme Duval iso_std_ops, 74321e1553eSJérôme Duval }, 74421e1553eSJérôme Duval 7451da9f5ceSAxel Dörfler "iso9660", // short_name 7461da9f5ceSAxel Dörfler "ISO9660 File System", // pretty_name 74776a8ec23SIngo Weinhold 0, // DDM flags 74821e1553eSJérôme Duval 74921e1553eSJérôme Duval // scanning 75021e1553eSJérôme Duval fs_identify_partition, 75121e1553eSJérôme Duval fs_scan_partition, 75221e1553eSJérôme Duval fs_free_identify_partition_cookie, 75321e1553eSJérôme Duval NULL, // free_partition_content_cookie() 75421e1553eSJérôme Duval 75521e1553eSJérôme Duval &fs_mount, 7560eaadd30SMichael Lotz 7570eaadd30SMichael Lotz /* capability querying */ 7580eaadd30SMichael Lotz NULL, 7590eaadd30SMichael Lotz NULL, 7600eaadd30SMichael Lotz NULL, 7610eaadd30SMichael Lotz NULL, 76221e1553eSJérôme Duval NULL, 76321e1553eSJérôme Duval NULL, 76421e1553eSJérôme Duval 7650eaadd30SMichael Lotz /* shadow partition modifications */ 7660eaadd30SMichael Lotz NULL, 76721e1553eSJérôme Duval 7680eaadd30SMichael Lotz /* writing */ 7690eaadd30SMichael Lotz NULL, 7700eaadd30SMichael Lotz NULL, 7710eaadd30SMichael Lotz NULL, 7720eaadd30SMichael Lotz NULL, 7730eaadd30SMichael Lotz NULL, 7740eaadd30SMichael Lotz NULL, 7750eaadd30SMichael Lotz NULL, 77621e1553eSJérôme Duval }; 77721e1553eSJérôme Duval 77821e1553eSJérôme Duval module_info *modules[] = { 77921e1553eSJérôme Duval (module_info *)&sISO660FileSystem, 78021e1553eSJérôme Duval NULL, 78121e1553eSJérôme Duval }; 78221e1553eSJérôme Duval 783