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; 107ff99132eSAxel Dörfler nspace *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; 1550eaadd30SMichael Lotz nspace *ns = (nspace *)_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 { 1760eaadd30SMichael Lotz nspace *ns = (nspace *)_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 { 2060eaadd30SMichael Lotz vnode *node = (vnode*)_node->private_node; 2073b723f79SJérôme Duval 2083b723f79SJérôme Duval strlcpy(buffer, node->fileIDString, 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 { 2160eaadd30SMichael Lotz nspace *ns = (nspace *)_vol->private_volume; 2170eaadd30SMichael Lotz vnode *baseNode = (vnode*)_base->private_node; 21821e1553eSJérôme Duval vnode *newNode = NULL; 21921e1553eSJérôme Duval 22021e1553eSJérôme Duval TRACE(("fs_walk - looking for %s in dir file of length %d\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; 238ff99132eSAxel Dörfler uint32 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; 244ff99132eSAxel Dörfler char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, 245ff99132eSAxel Dörfler ns->logicalBlkSize[FS_DATA_FORMAT]); 24621e1553eSJérôme Duval if (blockData != NULL) { 24721e1553eSJérôme Duval int bytesRead = 0; 24821e1553eSJérôme Duval off_t blockBytesRead = 0; 24921e1553eSJérôme Duval vnode node; 25021e1553eSJérôme Duval int initResult; 25121e1553eSJérôme Duval 25221e1553eSJérôme Duval TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n", 25321e1553eSJérôme Duval 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 node.fileIDString = NULL; 25921e1553eSJérôme Duval node.attr.slName = NULL; 26021e1553eSJérôme Duval 26121e1553eSJérôme Duval while (blockBytesRead < 2 * ns->logicalBlkSize[FS_DATA_FORMAT] 262ff99132eSAxel Dörfler && totalRead + blockBytesRead < dataLength 26321e1553eSJérôme Duval && blockData[0] != 0 264ff99132eSAxel Dörfler && !done) { 265ff99132eSAxel Dörfler initResult = InitNode(&node, blockData, &bytesRead, 266ff99132eSAxel Dörfler ns->joliet_level); 26721e1553eSJérôme Duval TRACE(("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead)); 26821e1553eSJérôme Duval 269ff99132eSAxel Dörfler if (initResult == B_OK) { 270ff99132eSAxel Dörfler if (!strcmp(node.fileIDString, file)) { 27121e1553eSJérôme Duval TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead)); 272ff99132eSAxel Dörfler *_vnodeID = (block << 30) 273ff99132eSAxel Dörfler + (blockBytesRead & 0xffffffff); 27421e1553eSJérôme Duval TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); 27521e1553eSJérôme Duval 2760eaadd30SMichael Lotz result = get_vnode(_vol, *_vnodeID, 277ff99132eSAxel Dörfler (void **)&newNode); 278ff99132eSAxel Dörfler if (result == B_OK) { 27921e1553eSJérôme Duval newNode->parID = baseNode->id; 280ff99132eSAxel Dörfler done = true; 28121e1553eSJérôme Duval } 28221e1553eSJérôme Duval } else { 28321e1553eSJérôme Duval free(node.fileIDString); 28421e1553eSJérôme Duval node.fileIDString = NULL; 28521e1553eSJérôme Duval free(node.attr.slName); 28621e1553eSJérôme Duval node.attr.slName = NULL; 28721e1553eSJérôme Duval } 28821e1553eSJérôme Duval } else { 28921e1553eSJérôme Duval result = initResult; 29021e1553eSJérôme Duval if (bytesRead == 0) 29121e1553eSJérôme Duval done = TRUE; 29221e1553eSJérôme Duval } 29321e1553eSJérôme Duval blockData += bytesRead; 29421e1553eSJérôme Duval blockBytesRead += bytesRead; 29521e1553eSJérôme Duval 29621e1553eSJérôme Duval TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n", 29721e1553eSJérôme Duval bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT])); 29821e1553eSJérôme Duval } 29921e1553eSJérôme Duval totalRead += ns->logicalBlkSize[FS_DATA_FORMAT]; 30021e1553eSJérôme Duval block++; 30121e1553eSJérôme Duval 30221e1553eSJérôme Duval TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead)); 30321e1553eSJérôme Duval block_cache_put(ns->fBlockCache, cachedBlock); 30421e1553eSJérôme Duval 30521e1553eSJérôme Duval } else 30621e1553eSJérôme Duval done = TRUE; 30721e1553eSJérôme Duval } 30821e1553eSJérôme Duval 309ff99132eSAxel Dörfler TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", 310ff99132eSAxel Dörfler strerror(result), *_vnodeID)); 31121e1553eSJérôme Duval return result; 31221e1553eSJérôme Duval } 31321e1553eSJérôme Duval 31421e1553eSJérôme Duval 31521e1553eSJérôme Duval static status_t 3160eaadd30SMichael Lotz fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node, 3170eaadd30SMichael Lotz int *_type, uint32 *_flags, bool reenter) 31821e1553eSJérôme Duval { 3190eaadd30SMichael Lotz nspace *ns = (nspace*)_vol->private_volume; 320ff99132eSAxel Dörfler 32121e1553eSJérôme Duval vnode *newNode = (vnode*)calloc(sizeof(vnode), 1); 322ff99132eSAxel Dörfler if (newNode == NULL) 323ff99132eSAxel Dörfler return B_NO_MEMORY; 32421e1553eSJérôme Duval 325ff99132eSAxel Dörfler uint32 pos = vnodeID & 0x3fffffff; 326ff99132eSAxel Dörfler uint32 block = vnodeID >> 30; 32721e1553eSJérôme Duval 328ff99132eSAxel Dörfler TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node 0x%x\n", 329ff99132eSAxel Dörfler block, pos, vnodeID, newNode)); 33021e1553eSJérôme Duval 331ff99132eSAxel Dörfler if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) 332ff99132eSAxel Dörfler return B_BAD_VALUE; 33321e1553eSJérôme Duval 334ff99132eSAxel Dörfler char *data = (char *)block_cache_get_etc(ns->fBlockCache, 335ff99132eSAxel Dörfler block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); 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); 3530eaadd30SMichael 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 3650eaadd30SMichael Lotz fs_release_vnode(fs_volume *_vol, fs_vnode *_node, bool reenter) 36621e1553eSJérôme Duval { 36721e1553eSJérôme Duval status_t result = B_NO_ERROR; 3680eaadd30SMichael Lotz vnode *node = (vnode*)_node->private_node; 36921e1553eSJérôme Duval 3700eaadd30SMichael Lotz (void)_vol; 37121e1553eSJérôme Duval (void)reenter; 37221e1553eSJérôme Duval 3735b4cb109SJérôme Duval TRACE(("fs_release_vnode - ENTER (0x%x)\n", node)); 37421e1553eSJérôme Duval 37521e1553eSJérôme Duval if (node != NULL) { 37621e1553eSJérôme Duval if (node->id != ISO_ROOTNODE_ID) { 37721e1553eSJérôme Duval if (node->fileIDString != NULL) 37821e1553eSJérôme Duval free (node->fileIDString); 37921e1553eSJérôme Duval if (node->attr.slName != NULL) 38021e1553eSJérôme Duval free (node->attr.slName); 3815b4cb109SJérôme Duval if (node->cache != NULL) 3825b4cb109SJérôme Duval file_cache_delete(node->cache); 38321e1553eSJérôme Duval 38421e1553eSJérôme Duval free(node); 38521e1553eSJérôme Duval } 38621e1553eSJérôme Duval } 38721e1553eSJérôme Duval 3885b4cb109SJérôme Duval TRACE(("fs_release_vnode - EXIT\n")); 38921e1553eSJérôme Duval return result; 39021e1553eSJérôme Duval } 39121e1553eSJérôme Duval 39221e1553eSJérôme Duval 39321e1553eSJérôme Duval static status_t 3940eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos, 395*e6bd90c5SIngo Weinhold const iovec *vecs, size_t count, size_t *_numBytes) 3965b4cb109SJérôme Duval { 3970eaadd30SMichael Lotz nspace *ns = (nspace *)_vol->private_volume; 3980eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 3995b4cb109SJérôme Duval 400ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 401ff99132eSAxel Dörfler size_t bytesLeft = *_numBytes; 4025b4cb109SJérôme Duval 403ff99132eSAxel Dörfler if (pos >= fileSize) { 404ff99132eSAxel Dörfler *_numBytes = 0; 4055b4cb109SJérôme Duval return B_OK; 4065b4cb109SJérôme Duval } 407ff99132eSAxel Dörfler if (pos + bytesLeft > fileSize) { 408ff99132eSAxel Dörfler bytesLeft = fileSize - pos; 409ff99132eSAxel Dörfler *_numBytes = bytesLeft; 4105b4cb109SJérôme Duval } 4115b4cb109SJérôme Duval 412ff99132eSAxel Dörfler file_io_vec fileVec; 413ff99132eSAxel Dörfler fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT] 414ff99132eSAxel Dörfler * ns->logicalBlkSize[FS_DATA_FORMAT]; 415ff99132eSAxel Dörfler fileVec.length = bytesLeft; 4165b4cb109SJérôme Duval 417ff99132eSAxel Dörfler uint32 vecIndex = 0; 418ff99132eSAxel Dörfler size_t vecOffset = 0; 419ff99132eSAxel Dörfler return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count, 420ff99132eSAxel Dörfler &vecIndex, &vecOffset, &bytesLeft); 4215b4cb109SJérôme Duval } 4225b4cb109SJérôme Duval 4235b4cb109SJérôme Duval 4245b4cb109SJérôme Duval static status_t 4250eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st) 42621e1553eSJérôme Duval { 4270eaadd30SMichael Lotz nspace *ns = (nspace*)_vol->private_volume; 4280eaadd30SMichael Lotz vnode *node = (vnode*)_node->private_node; 4293b723f79SJérôme Duval status_t result = B_NO_ERROR; 43021e1553eSJérôme Duval time_t time; 43121e1553eSJérôme Duval 4323b723f79SJérôme Duval TRACE(("fs_read_stat - ENTER\n")); 43321e1553eSJérôme Duval 43421e1553eSJérôme Duval st->st_dev = ns->id; 43521e1553eSJérôme Duval st->st_ino = node->id; 43621e1553eSJérôme Duval st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 43721e1553eSJérôme Duval st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 43821e1553eSJérôme Duval st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 43921e1553eSJérôme Duval st->st_blksize = 65536; 44021e1553eSJérôme Duval st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 44121e1553eSJérôme Duval 44221e1553eSJérôme Duval // Same for file/dir in ISO9660 44321e1553eSJérôme Duval st->st_size = node->dataLen[FS_DATA_FORMAT]; 44421e1553eSJérôme Duval if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 44521e1553eSJérôme Duval st->st_ctime = st->st_mtime = st->st_atime = time; 44621e1553eSJérôme Duval 4473b723f79SJérôme Duval TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 44821e1553eSJérôme Duval 44921e1553eSJérôme Duval return result; 45021e1553eSJérôme Duval } 45121e1553eSJérôme Duval 45221e1553eSJérôme Duval 45321e1553eSJérôme Duval static status_t 4540eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie) 45521e1553eSJérôme Duval { 45621e1553eSJérôme Duval status_t result = B_NO_ERROR; 45721e1553eSJérôme Duval 4580eaadd30SMichael Lotz (void)_vol; 45921e1553eSJérôme Duval (void)cookie; 46021e1553eSJérôme Duval 46121e1553eSJérôme Duval // Do not allow any of the write-like open modes to get by 46221e1553eSJérôme Duval if ((omode == O_WRONLY) || (omode == O_RDWR)) 46321e1553eSJérôme Duval result = EROFS; 46421e1553eSJérôme Duval else if((omode & O_TRUNC) || (omode & O_CREAT)) 46521e1553eSJérôme Duval result = EROFS; 46621e1553eSJérôme Duval 46721e1553eSJérôme Duval return result; 46821e1553eSJérôme Duval } 46921e1553eSJérôme Duval 47021e1553eSJérôme Duval 47121e1553eSJérôme Duval static status_t 4720eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer, 473ff99132eSAxel Dörfler size_t *_length) 47421e1553eSJérôme Duval { 4750eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 47621e1553eSJérôme Duval 47721e1553eSJérôme Duval if (node->flags & ISO_ISDIR) 47821e1553eSJérôme Duval return EISDIR; 47921e1553eSJérôme Duval 480ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 4815b4cb109SJérôme Duval 4825b4cb109SJérôme Duval // set/check boundaries for pos/length 483ff99132eSAxel Dörfler if (pos < 0) 4845b4cb109SJérôme Duval return B_BAD_VALUE; 485ff99132eSAxel Dörfler if (pos >= fileSize) { 486ff99132eSAxel Dörfler *_length = 0; 4875b4cb109SJérôme Duval return B_OK; 4885b4cb109SJérôme Duval } 489ff99132eSAxel Dörfler 490ff99132eSAxel Dörfler return file_cache_read(node->cache, NULL, pos, buffer, _length); 49121e1553eSJérôme Duval } 49221e1553eSJérôme Duval 49321e1553eSJérôme Duval 49421e1553eSJérôme Duval static status_t 4950eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie) 49621e1553eSJérôme Duval { 4970eaadd30SMichael Lotz (void)_vol; 4980eaadd30SMichael Lotz (void)_node; 49921e1553eSJérôme Duval (void)cookie; 50021e1553eSJérôme Duval 50121e1553eSJérôme Duval return B_OK; 50221e1553eSJérôme Duval } 50321e1553eSJérôme Duval 504ff99132eSAxel Dörfler 50521e1553eSJérôme Duval static status_t 5060eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 50721e1553eSJérôme Duval { 5080eaadd30SMichael Lotz (void)_vol; 5090eaadd30SMichael Lotz (void)_node; 51021e1553eSJérôme Duval (void)cookie; 51121e1553eSJérôme Duval 51221e1553eSJérôme Duval return B_OK; 51321e1553eSJérôme Duval } 51421e1553eSJérôme Duval 515ff99132eSAxel Dörfler 51621e1553eSJérôme Duval static status_t 5170eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode) 51821e1553eSJérôme Duval { 5190eaadd30SMichael Lotz (void)_vol; 5200eaadd30SMichael Lotz (void)_node; 52121e1553eSJérôme Duval (void)mode; 52221e1553eSJérôme Duval 52321e1553eSJérôme Duval return B_OK; 52421e1553eSJérôme Duval } 52521e1553eSJérôme Duval 526ff99132eSAxel Dörfler 52721e1553eSJérôme Duval static status_t 5280eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize) 52921e1553eSJérôme Duval { 5300eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 53121e1553eSJérôme Duval 532ff99132eSAxel Dörfler if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) 533ff99132eSAxel Dörfler return B_BAD_VALUE; 53421e1553eSJérôme Duval 53521e1553eSJérôme Duval size_t length = strlen(node->attr.slName); 53621e1553eSJérôme Duval if (length > *_bufferSize) 5373b723f79SJérôme Duval memcpy(buffer, node->attr.slName, *_bufferSize); 5383b723f79SJérôme Duval else { 53921e1553eSJérôme Duval memcpy(buffer, node->attr.slName, length); 5403b723f79SJérôme Duval *_bufferSize = length; 5413b723f79SJérôme Duval } 54221e1553eSJérôme Duval 543ff99132eSAxel Dörfler return B_OK; 54421e1553eSJérôme Duval } 54521e1553eSJérôme Duval 54621e1553eSJérôme Duval 54721e1553eSJérôme Duval static status_t 5480eaadd30SMichael Lotz fs_open_dir(fs_volume *_vol, fs_vnode *_node, void **cookie) 54921e1553eSJérôme Duval { 5500eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 55121e1553eSJérôme Duval 552ff99132eSAxel Dörfler TRACE(("fs_open_dir - node is 0x%x\n", _node)); 55321e1553eSJérôme Duval 55421e1553eSJérôme Duval if (!(node->flags & ISO_ISDIR)) 555ff99132eSAxel Dörfler return B_NOT_A_DIRECTORY; 55621e1553eSJérôme Duval 557ff99132eSAxel Dörfler dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie)); 558ff99132eSAxel Dörfler if (dirCookie == NULL) 559ff99132eSAxel Dörfler return B_NO_MEMORY; 560ff99132eSAxel Dörfler 56121e1553eSJérôme Duval dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 56221e1553eSJérôme Duval dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 56321e1553eSJérôme Duval dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 56421e1553eSJérôme Duval dirCookie->pos = 0; 56521e1553eSJérôme Duval dirCookie->id = node->id; 56621e1553eSJérôme Duval *cookie = (void *)dirCookie; 56721e1553eSJérôme Duval 568ff99132eSAxel Dörfler return B_OK; 56921e1553eSJérôme Duval } 57021e1553eSJérôme Duval 57121e1553eSJérôme Duval 57221e1553eSJérôme Duval static status_t 5730eaadd30SMichael Lotz fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *buffer, 57421e1553eSJérôme Duval size_t bufferSize, uint32 *num) 57521e1553eSJérôme Duval { 5760eaadd30SMichael Lotz nspace *ns = (nspace *)_vol->private_volume; 57721e1553eSJérôme Duval dircookie *dirCookie = (dircookie *)_cookie; 57821e1553eSJérôme Duval 5795b4cb109SJérôme Duval TRACE(("fs_read_dir - ENTER\n")); 58021e1553eSJérôme Duval 581ff99132eSAxel Dörfler status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize); 58221e1553eSJérôme Duval 58321e1553eSJérôme Duval // If we succeeded, return 1, the number of dirents we read. 584ff99132eSAxel Dörfler if (result == B_OK) 58521e1553eSJérôme Duval *num = 1; 58621e1553eSJérôme Duval else 58721e1553eSJérôme Duval *num = 0; 58821e1553eSJérôme Duval 58921e1553eSJérôme Duval // When you get to the end, don't return an error, just return 59021e1553eSJérôme Duval // a zero in *num. 59121e1553eSJérôme Duval 59221e1553eSJérôme Duval if (result == ENOENT) 593ff99132eSAxel Dörfler result = B_OK; 59421e1553eSJérôme Duval 5955b4cb109SJérôme Duval TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result))); 59621e1553eSJérôme Duval return result; 59721e1553eSJérôme Duval } 59821e1553eSJérôme Duval 59921e1553eSJérôme Duval 60021e1553eSJérôme Duval static status_t 6010eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie) 60221e1553eSJérôme Duval { 60321e1553eSJérôme Duval dircookie *cookie = (dircookie*)_cookie; 60421e1553eSJérôme Duval 60521e1553eSJérôme Duval cookie->block = cookie->startBlock; 60621e1553eSJérôme Duval cookie->pos = 0; 607ff99132eSAxel Dörfler 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_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie) 61321e1553eSJérôme Duval { 61421e1553eSJérôme Duval return B_OK; 61521e1553eSJérôme Duval } 61621e1553eSJérôme Duval 61721e1553eSJérôme Duval 61821e1553eSJérôme Duval static status_t 6190eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 62021e1553eSJérôme Duval { 62121e1553eSJérôme Duval free(cookie); 62221e1553eSJérôme Duval return B_OK; 62321e1553eSJérôme Duval } 62421e1553eSJérôme Duval 625ff99132eSAxel Dörfler 62621e1553eSJérôme Duval // #pragma mark - 62721e1553eSJérôme Duval 62821e1553eSJérôme Duval 62921e1553eSJérôme Duval static status_t 63021e1553eSJérôme Duval iso_std_ops(int32 op, ...) 63121e1553eSJérôme Duval { 63221e1553eSJérôme Duval switch (op) { 63321e1553eSJérôme Duval case B_MODULE_INIT: 63421e1553eSJérôme Duval case B_MODULE_UNINIT: 63521e1553eSJérôme Duval return B_OK; 63621e1553eSJérôme Duval default: 63721e1553eSJérôme Duval return B_ERROR; 63821e1553eSJérôme Duval } 63921e1553eSJérôme Duval } 64021e1553eSJérôme Duval 64121e1553eSJérôme Duval 6420eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = { 6430eaadd30SMichael Lotz &fs_unmount, 6440eaadd30SMichael Lotz &fs_read_fs_stat, 6450eaadd30SMichael Lotz NULL, 6460eaadd30SMichael Lotz NULL, 6470eaadd30SMichael Lotz &fs_read_vnode, 6480eaadd30SMichael Lotz 6490eaadd30SMichael Lotz /* index and index directory ops */ 6500eaadd30SMichael Lotz NULL, 6510eaadd30SMichael Lotz NULL, 6520eaadd30SMichael Lotz NULL, 6530eaadd30SMichael Lotz NULL, 6540eaadd30SMichael Lotz NULL, 6550eaadd30SMichael Lotz NULL, 6560eaadd30SMichael Lotz NULL, 6570eaadd30SMichael Lotz NULL, 6580eaadd30SMichael Lotz 6590eaadd30SMichael Lotz /* query ops */ 6600eaadd30SMichael Lotz NULL, 6610eaadd30SMichael Lotz NULL, 6620eaadd30SMichael Lotz NULL, 6630eaadd30SMichael Lotz NULL, 6640eaadd30SMichael Lotz NULL, 6650eaadd30SMichael Lotz 6660eaadd30SMichael Lotz /* FS layer ops */ 6670eaadd30SMichael Lotz NULL, 6680eaadd30SMichael Lotz NULL, 6690eaadd30SMichael Lotz }; 6700eaadd30SMichael Lotz 6710eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = { 6720eaadd30SMichael Lotz &fs_walk, 6730eaadd30SMichael Lotz &fs_get_vnode_name, 6740eaadd30SMichael Lotz &fs_release_vnode, 6750eaadd30SMichael Lotz NULL, 6760eaadd30SMichael Lotz 6770eaadd30SMichael Lotz /* vm-related ops */ 6780eaadd30SMichael Lotz NULL, 6790eaadd30SMichael Lotz &fs_read_pages, 6800eaadd30SMichael Lotz NULL, 6810eaadd30SMichael Lotz 6820eaadd30SMichael Lotz /* cache file access */ 6830eaadd30SMichael Lotz NULL, 6840eaadd30SMichael Lotz 6850eaadd30SMichael Lotz /* common */ 6860eaadd30SMichael Lotz NULL, 6870eaadd30SMichael Lotz NULL, 6880eaadd30SMichael Lotz NULL, 6890eaadd30SMichael Lotz NULL, 6900eaadd30SMichael Lotz NULL, 6910eaadd30SMichael Lotz &fs_read_link, 6920eaadd30SMichael Lotz NULL, 6930eaadd30SMichael Lotz NULL, 6940eaadd30SMichael Lotz NULL, 6950eaadd30SMichael Lotz NULL, 6960eaadd30SMichael Lotz &fs_access, 6970eaadd30SMichael Lotz &fs_read_stat, 6980eaadd30SMichael Lotz NULL, 6990eaadd30SMichael Lotz 7000eaadd30SMichael Lotz /* file */ 7010eaadd30SMichael Lotz NULL, 7020eaadd30SMichael Lotz &fs_open, 7030eaadd30SMichael Lotz &fs_close, 7040eaadd30SMichael Lotz &fs_free_cookie, 7050eaadd30SMichael Lotz &fs_read, 7060eaadd30SMichael Lotz NULL, 7070eaadd30SMichael Lotz 7080eaadd30SMichael Lotz /* dir */ 7090eaadd30SMichael Lotz NULL, 7100eaadd30SMichael Lotz NULL, 7110eaadd30SMichael Lotz &fs_open_dir, 7120eaadd30SMichael Lotz &fs_close_dir, 7130eaadd30SMichael Lotz &fs_free_dir_cookie, 7140eaadd30SMichael Lotz &fs_read_dir, 7150eaadd30SMichael Lotz &fs_rewind_dir, 7160eaadd30SMichael Lotz 7170eaadd30SMichael Lotz /* attribute directory ops */ 7180eaadd30SMichael Lotz NULL, 7190eaadd30SMichael Lotz NULL, 7200eaadd30SMichael Lotz NULL, 7210eaadd30SMichael Lotz NULL, 7220eaadd30SMichael Lotz NULL, 7230eaadd30SMichael Lotz 7240eaadd30SMichael Lotz /* attribute ops */ 7250eaadd30SMichael Lotz NULL, 7260eaadd30SMichael Lotz NULL, 7270eaadd30SMichael Lotz NULL, 7280eaadd30SMichael Lotz NULL, 7290eaadd30SMichael Lotz NULL, 7300eaadd30SMichael Lotz NULL, 7310eaadd30SMichael Lotz NULL, 7320eaadd30SMichael Lotz NULL, 7330eaadd30SMichael Lotz NULL, 7340eaadd30SMichael Lotz NULL, 7350eaadd30SMichael Lotz 7360eaadd30SMichael Lotz /* node and FS layer support */ 7370eaadd30SMichael Lotz NULL, 7380eaadd30SMichael Lotz NULL, 7390eaadd30SMichael Lotz }; 7400eaadd30SMichael Lotz 74121e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = { 74221e1553eSJérôme Duval { 74321e1553eSJérôme Duval "file_systems/iso9660" B_CURRENT_FS_API_VERSION, 74421e1553eSJérôme Duval 0, 74521e1553eSJérôme Duval iso_std_ops, 74621e1553eSJérôme Duval }, 74721e1553eSJérôme Duval 7481da9f5ceSAxel Dörfler "iso9660", // short_name 7491da9f5ceSAxel Dörfler "ISO9660 File System", // pretty_name 75076a8ec23SIngo Weinhold 0, // DDM flags 75121e1553eSJérôme Duval 75221e1553eSJérôme Duval // scanning 75321e1553eSJérôme Duval fs_identify_partition, 75421e1553eSJérôme Duval fs_scan_partition, 75521e1553eSJérôme Duval fs_free_identify_partition_cookie, 75621e1553eSJérôme Duval NULL, // free_partition_content_cookie() 75721e1553eSJérôme Duval 75821e1553eSJérôme Duval &fs_mount, 7590eaadd30SMichael Lotz 7600eaadd30SMichael Lotz /* capability querying */ 7610eaadd30SMichael Lotz NULL, 7620eaadd30SMichael Lotz NULL, 7630eaadd30SMichael Lotz NULL, 7640eaadd30SMichael Lotz NULL, 76521e1553eSJérôme Duval NULL, 76621e1553eSJérôme Duval NULL, 76721e1553eSJérôme Duval 7680eaadd30SMichael Lotz /* shadow partition modifications */ 7690eaadd30SMichael Lotz NULL, 77021e1553eSJérôme Duval 7710eaadd30SMichael Lotz /* writing */ 7720eaadd30SMichael Lotz NULL, 7730eaadd30SMichael Lotz NULL, 7740eaadd30SMichael Lotz NULL, 7750eaadd30SMichael Lotz NULL, 7760eaadd30SMichael Lotz NULL, 7770eaadd30SMichael Lotz NULL, 7780eaadd30SMichael Lotz NULL, 77921e1553eSJérôme Duval }; 78021e1553eSJérôme Duval 78121e1553eSJérôme Duval module_info *modules[] = { 78221e1553eSJérôme Duval (module_info *)&sISO660FileSystem, 78321e1553eSJérôme Duval NULL, 78421e1553eSJérôme Duval }; 78521e1553eSJérôme Duval 786