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 331*d02cde30SMichael Lotz if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) { 332*d02cde30SMichael Lotz free(newNode); 333ff99132eSAxel Dörfler return B_BAD_VALUE; 334*d02cde30SMichael Lotz } 33521e1553eSJérôme Duval 336ff99132eSAxel Dörfler char *data = (char *)block_cache_get_etc(ns->fBlockCache, 337ff99132eSAxel Dörfler block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]); 338ff99132eSAxel Dörfler if (data == NULL) { 339ff99132eSAxel Dörfler free(newNode); 340ff99132eSAxel Dörfler return B_IO_ERROR; 341ff99132eSAxel Dörfler } 34221e1553eSJérôme Duval 343ff99132eSAxel Dörfler status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level); 34421e1553eSJérôme Duval block_cache_put(ns->fBlockCache, block); 34521e1553eSJérôme Duval 346ff99132eSAxel Dörfler if (result < B_OK) { 347ff99132eSAxel Dörfler free(newNode); 348ff99132eSAxel Dörfler return result; 34921e1553eSJérôme Duval } 35021e1553eSJérôme Duval 351ff99132eSAxel Dörfler newNode->id = vnodeID; 3520eaadd30SMichael Lotz _node->private_node = newNode; 3530eaadd30SMichael Lotz _node->ops = &gISO9660VnodeOps; 3540eaadd30SMichael Lotz *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH); 3550eaadd30SMichael Lotz *_flags = 0; 356ff99132eSAxel Dörfler 357ff99132eSAxel Dörfler if ((newNode->flags & ISO_ISDIR) == 0) { 358ff99132eSAxel Dörfler newNode->cache = file_cache_create(ns->id, vnodeID, 3593d268edaSAxel Dörfler newNode->dataLen[FS_DATA_FORMAT]); 3605b4cb109SJérôme Duval } 3615b4cb109SJérôme Duval 362ff99132eSAxel Dörfler return B_OK; 36321e1553eSJérôme Duval } 36421e1553eSJérôme Duval 36521e1553eSJérôme Duval 36621e1553eSJérôme Duval static status_t 3670eaadd30SMichael Lotz fs_release_vnode(fs_volume *_vol, fs_vnode *_node, bool reenter) 36821e1553eSJérôme Duval { 36921e1553eSJérôme Duval status_t result = B_NO_ERROR; 3700eaadd30SMichael Lotz vnode *node = (vnode*)_node->private_node; 37121e1553eSJérôme Duval 3720eaadd30SMichael Lotz (void)_vol; 37321e1553eSJérôme Duval (void)reenter; 37421e1553eSJérôme Duval 3755b4cb109SJérôme Duval TRACE(("fs_release_vnode - ENTER (0x%x)\n", node)); 37621e1553eSJérôme Duval 37721e1553eSJérôme Duval if (node != NULL) { 37821e1553eSJérôme Duval if (node->id != ISO_ROOTNODE_ID) { 37921e1553eSJérôme Duval if (node->fileIDString != NULL) 38021e1553eSJérôme Duval free (node->fileIDString); 38121e1553eSJérôme Duval if (node->attr.slName != NULL) 38221e1553eSJérôme Duval free (node->attr.slName); 3835b4cb109SJérôme Duval if (node->cache != NULL) 3845b4cb109SJérôme Duval file_cache_delete(node->cache); 38521e1553eSJérôme Duval 38621e1553eSJérôme Duval free(node); 38721e1553eSJérôme Duval } 38821e1553eSJérôme Duval } 38921e1553eSJérôme Duval 3905b4cb109SJérôme Duval TRACE(("fs_release_vnode - EXIT\n")); 39121e1553eSJérôme Duval return result; 39221e1553eSJérôme Duval } 39321e1553eSJérôme Duval 39421e1553eSJérôme Duval 39521e1553eSJérôme Duval static status_t 3960eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos, 397e6bd90c5SIngo Weinhold const iovec *vecs, size_t count, size_t *_numBytes) 3985b4cb109SJérôme Duval { 3990eaadd30SMichael Lotz nspace *ns = (nspace *)_vol->private_volume; 4000eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 4015b4cb109SJérôme Duval 402ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 403ff99132eSAxel Dörfler size_t bytesLeft = *_numBytes; 4045b4cb109SJérôme Duval 405ff99132eSAxel Dörfler if (pos >= fileSize) { 406ff99132eSAxel Dörfler *_numBytes = 0; 4075b4cb109SJérôme Duval return B_OK; 4085b4cb109SJérôme Duval } 409ff99132eSAxel Dörfler if (pos + bytesLeft > fileSize) { 410ff99132eSAxel Dörfler bytesLeft = fileSize - pos; 411ff99132eSAxel Dörfler *_numBytes = bytesLeft; 4125b4cb109SJérôme Duval } 4135b4cb109SJérôme Duval 414ff99132eSAxel Dörfler file_io_vec fileVec; 415ff99132eSAxel Dörfler fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT] 416ff99132eSAxel Dörfler * ns->logicalBlkSize[FS_DATA_FORMAT]; 417ff99132eSAxel Dörfler fileVec.length = bytesLeft; 4185b4cb109SJérôme Duval 419ff99132eSAxel Dörfler uint32 vecIndex = 0; 420ff99132eSAxel Dörfler size_t vecOffset = 0; 421ff99132eSAxel Dörfler return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count, 422ff99132eSAxel Dörfler &vecIndex, &vecOffset, &bytesLeft); 4235b4cb109SJérôme Duval } 4245b4cb109SJérôme Duval 4255b4cb109SJérôme Duval 4265b4cb109SJérôme Duval static status_t 4270eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st) 42821e1553eSJérôme Duval { 4290eaadd30SMichael Lotz nspace *ns = (nspace*)_vol->private_volume; 4300eaadd30SMichael Lotz vnode *node = (vnode*)_node->private_node; 4313b723f79SJérôme Duval status_t result = B_NO_ERROR; 43221e1553eSJérôme Duval time_t time; 43321e1553eSJérôme Duval 4343b723f79SJérôme Duval TRACE(("fs_read_stat - ENTER\n")); 43521e1553eSJérôme Duval 43621e1553eSJérôme Duval st->st_dev = ns->id; 43721e1553eSJérôme Duval st->st_ino = node->id; 43821e1553eSJérôme Duval st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 43921e1553eSJérôme Duval st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 44021e1553eSJérôme Duval st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 44121e1553eSJérôme Duval st->st_blksize = 65536; 44221e1553eSJérôme Duval st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 44321e1553eSJérôme Duval 44421e1553eSJérôme Duval // Same for file/dir in ISO9660 44521e1553eSJérôme Duval st->st_size = node->dataLen[FS_DATA_FORMAT]; 44621e1553eSJérôme Duval if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 44721e1553eSJérôme Duval st->st_ctime = st->st_mtime = st->st_atime = time; 44821e1553eSJérôme Duval 4493b723f79SJérôme Duval TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 45021e1553eSJérôme Duval 45121e1553eSJérôme Duval return result; 45221e1553eSJérôme Duval } 45321e1553eSJérôme Duval 45421e1553eSJérôme Duval 45521e1553eSJérôme Duval static status_t 4560eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie) 45721e1553eSJérôme Duval { 45821e1553eSJérôme Duval status_t result = B_NO_ERROR; 45921e1553eSJérôme Duval 4600eaadd30SMichael Lotz (void)_vol; 46121e1553eSJérôme Duval (void)cookie; 46221e1553eSJérôme Duval 46321e1553eSJérôme Duval // Do not allow any of the write-like open modes to get by 46421e1553eSJérôme Duval if ((omode == O_WRONLY) || (omode == O_RDWR)) 46521e1553eSJérôme Duval result = EROFS; 46621e1553eSJérôme Duval else if((omode & O_TRUNC) || (omode & O_CREAT)) 46721e1553eSJérôme Duval result = EROFS; 46821e1553eSJérôme Duval 46921e1553eSJérôme Duval return result; 47021e1553eSJérôme Duval } 47121e1553eSJérôme Duval 47221e1553eSJérôme Duval 47321e1553eSJérôme Duval static status_t 4740eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer, 475ff99132eSAxel Dörfler size_t *_length) 47621e1553eSJérôme Duval { 4770eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 47821e1553eSJérôme Duval 47921e1553eSJérôme Duval if (node->flags & ISO_ISDIR) 48021e1553eSJérôme Duval return EISDIR; 48121e1553eSJérôme Duval 482ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 4835b4cb109SJérôme Duval 4845b4cb109SJérôme Duval // set/check boundaries for pos/length 485ff99132eSAxel Dörfler if (pos < 0) 4865b4cb109SJérôme Duval return B_BAD_VALUE; 487ff99132eSAxel Dörfler if (pos >= fileSize) { 488ff99132eSAxel Dörfler *_length = 0; 4895b4cb109SJérôme Duval return B_OK; 4905b4cb109SJérôme Duval } 491ff99132eSAxel Dörfler 492ff99132eSAxel Dörfler return file_cache_read(node->cache, NULL, pos, buffer, _length); 49321e1553eSJérôme Duval } 49421e1553eSJérôme Duval 49521e1553eSJérôme Duval 49621e1553eSJérôme Duval static status_t 4970eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie) 49821e1553eSJérôme Duval { 4990eaadd30SMichael Lotz (void)_vol; 5000eaadd30SMichael Lotz (void)_node; 50121e1553eSJérôme Duval (void)cookie; 50221e1553eSJérôme Duval 50321e1553eSJérôme Duval return B_OK; 50421e1553eSJérôme Duval } 50521e1553eSJérôme Duval 506ff99132eSAxel Dörfler 50721e1553eSJérôme Duval static status_t 5080eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 50921e1553eSJérôme Duval { 5100eaadd30SMichael Lotz (void)_vol; 5110eaadd30SMichael Lotz (void)_node; 51221e1553eSJérôme Duval (void)cookie; 51321e1553eSJérôme Duval 51421e1553eSJérôme Duval return B_OK; 51521e1553eSJérôme Duval } 51621e1553eSJérôme Duval 517ff99132eSAxel Dörfler 51821e1553eSJérôme Duval static status_t 5190eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode) 52021e1553eSJérôme Duval { 5210eaadd30SMichael Lotz (void)_vol; 5220eaadd30SMichael Lotz (void)_node; 52321e1553eSJérôme Duval (void)mode; 52421e1553eSJérôme Duval 52521e1553eSJérôme Duval return B_OK; 52621e1553eSJérôme Duval } 52721e1553eSJérôme Duval 528ff99132eSAxel Dörfler 52921e1553eSJérôme Duval static status_t 5300eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize) 53121e1553eSJérôme Duval { 5320eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 53321e1553eSJérôme Duval 534ff99132eSAxel Dörfler if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) 535ff99132eSAxel Dörfler return B_BAD_VALUE; 53621e1553eSJérôme Duval 53721e1553eSJérôme Duval size_t length = strlen(node->attr.slName); 53821e1553eSJérôme Duval if (length > *_bufferSize) 5393b723f79SJérôme Duval memcpy(buffer, node->attr.slName, *_bufferSize); 5403b723f79SJérôme Duval else { 54121e1553eSJérôme Duval memcpy(buffer, node->attr.slName, length); 5423b723f79SJérôme Duval *_bufferSize = length; 5433b723f79SJérôme Duval } 54421e1553eSJérôme Duval 545ff99132eSAxel Dörfler return B_OK; 54621e1553eSJérôme Duval } 54721e1553eSJérôme Duval 54821e1553eSJérôme Duval 54921e1553eSJérôme Duval static status_t 5500eaadd30SMichael Lotz fs_open_dir(fs_volume *_vol, fs_vnode *_node, void **cookie) 55121e1553eSJérôme Duval { 5520eaadd30SMichael Lotz vnode *node = (vnode *)_node->private_node; 55321e1553eSJérôme Duval 554ff99132eSAxel Dörfler TRACE(("fs_open_dir - node is 0x%x\n", _node)); 55521e1553eSJérôme Duval 55621e1553eSJérôme Duval if (!(node->flags & ISO_ISDIR)) 557ff99132eSAxel Dörfler return B_NOT_A_DIRECTORY; 55821e1553eSJérôme Duval 559ff99132eSAxel Dörfler dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie)); 560ff99132eSAxel Dörfler if (dirCookie == NULL) 561ff99132eSAxel Dörfler return B_NO_MEMORY; 562ff99132eSAxel Dörfler 56321e1553eSJérôme Duval dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 56421e1553eSJérôme Duval dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 56521e1553eSJérôme Duval dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 56621e1553eSJérôme Duval dirCookie->pos = 0; 56721e1553eSJérôme Duval dirCookie->id = node->id; 56821e1553eSJérôme Duval *cookie = (void *)dirCookie; 56921e1553eSJérôme Duval 570ff99132eSAxel Dörfler return B_OK; 57121e1553eSJérôme Duval } 57221e1553eSJérôme Duval 57321e1553eSJérôme Duval 57421e1553eSJérôme Duval static status_t 57544d0dbc8SAxel Dörfler fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, 57644d0dbc8SAxel Dörfler struct dirent *buffer, size_t bufferSize, uint32 *num) 57721e1553eSJérôme Duval { 5780eaadd30SMichael Lotz nspace *ns = (nspace *)_vol->private_volume; 57921e1553eSJérôme Duval dircookie *dirCookie = (dircookie *)_cookie; 58021e1553eSJérôme Duval 5815b4cb109SJérôme Duval TRACE(("fs_read_dir - ENTER\n")); 58221e1553eSJérôme Duval 583ff99132eSAxel Dörfler status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize); 58421e1553eSJérôme Duval 58521e1553eSJérôme Duval // If we succeeded, return 1, the number of dirents we read. 586ff99132eSAxel Dörfler if (result == B_OK) 58721e1553eSJérôme Duval *num = 1; 58821e1553eSJérôme Duval else 58921e1553eSJérôme Duval *num = 0; 59021e1553eSJérôme Duval 59121e1553eSJérôme Duval // When you get to the end, don't return an error, just return 59221e1553eSJérôme Duval // a zero in *num. 59321e1553eSJérôme Duval 59421e1553eSJérôme Duval if (result == ENOENT) 595ff99132eSAxel Dörfler result = B_OK; 59621e1553eSJérôme Duval 5975b4cb109SJérôme Duval TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result))); 59821e1553eSJérôme Duval return result; 59921e1553eSJérôme Duval } 60021e1553eSJérôme Duval 60121e1553eSJérôme Duval 60221e1553eSJérôme Duval static status_t 6030eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie) 60421e1553eSJérôme Duval { 60521e1553eSJérôme Duval dircookie *cookie = (dircookie*)_cookie; 60621e1553eSJérôme Duval 60721e1553eSJérôme Duval cookie->block = cookie->startBlock; 60821e1553eSJérôme Duval cookie->pos = 0; 609ff99132eSAxel Dörfler return B_OK; 61021e1553eSJérôme Duval } 61121e1553eSJérôme Duval 61221e1553eSJérôme Duval 61321e1553eSJérôme Duval static status_t 6140eaadd30SMichael Lotz fs_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie) 61521e1553eSJérôme Duval { 61621e1553eSJérôme Duval return B_OK; 61721e1553eSJérôme Duval } 61821e1553eSJérôme Duval 61921e1553eSJérôme Duval 62021e1553eSJérôme Duval static status_t 6210eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 62221e1553eSJérôme Duval { 62321e1553eSJérôme Duval free(cookie); 62421e1553eSJérôme Duval return B_OK; 62521e1553eSJérôme Duval } 62621e1553eSJérôme Duval 627ff99132eSAxel Dörfler 62821e1553eSJérôme Duval // #pragma mark - 62921e1553eSJérôme Duval 63021e1553eSJérôme Duval 63121e1553eSJérôme Duval static status_t 63221e1553eSJérôme Duval iso_std_ops(int32 op, ...) 63321e1553eSJérôme Duval { 63421e1553eSJérôme Duval switch (op) { 63521e1553eSJérôme Duval case B_MODULE_INIT: 63621e1553eSJérôme Duval case B_MODULE_UNINIT: 63721e1553eSJérôme Duval return B_OK; 63821e1553eSJérôme Duval default: 63921e1553eSJérôme Duval return B_ERROR; 64021e1553eSJérôme Duval } 64121e1553eSJérôme Duval } 64221e1553eSJérôme Duval 64321e1553eSJérôme Duval 6440eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = { 6450eaadd30SMichael Lotz &fs_unmount, 6460eaadd30SMichael Lotz &fs_read_fs_stat, 6470eaadd30SMichael Lotz NULL, 6480eaadd30SMichael Lotz NULL, 6490eaadd30SMichael Lotz &fs_read_vnode, 6500eaadd30SMichael Lotz 6510eaadd30SMichael Lotz /* index and index directory ops */ 6520eaadd30SMichael Lotz NULL, 6530eaadd30SMichael Lotz NULL, 6540eaadd30SMichael Lotz NULL, 6550eaadd30SMichael Lotz NULL, 6560eaadd30SMichael Lotz NULL, 6570eaadd30SMichael Lotz NULL, 6580eaadd30SMichael Lotz NULL, 6590eaadd30SMichael Lotz NULL, 6600eaadd30SMichael Lotz 6610eaadd30SMichael Lotz /* query ops */ 6620eaadd30SMichael Lotz NULL, 6630eaadd30SMichael Lotz NULL, 6640eaadd30SMichael Lotz NULL, 6650eaadd30SMichael Lotz NULL, 6660eaadd30SMichael Lotz NULL, 6670eaadd30SMichael Lotz 6680eaadd30SMichael Lotz /* FS layer ops */ 6690eaadd30SMichael Lotz NULL, 6700eaadd30SMichael Lotz NULL, 6710eaadd30SMichael Lotz }; 6720eaadd30SMichael Lotz 6730eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = { 6740eaadd30SMichael Lotz &fs_walk, 6750eaadd30SMichael Lotz &fs_get_vnode_name, 6760eaadd30SMichael Lotz &fs_release_vnode, 6770eaadd30SMichael Lotz NULL, 6780eaadd30SMichael Lotz 6790eaadd30SMichael Lotz /* vm-related ops */ 6800eaadd30SMichael Lotz NULL, 6810eaadd30SMichael Lotz &fs_read_pages, 6820eaadd30SMichael Lotz NULL, 6830eaadd30SMichael Lotz 684ec598fe4SIngo Weinhold NULL, // io() 685ec598fe4SIngo Weinhold NULL, // cancel_io() 686ec598fe4SIngo Weinhold 6870eaadd30SMichael Lotz /* cache file access */ 6880eaadd30SMichael Lotz NULL, 6890eaadd30SMichael Lotz 6900eaadd30SMichael Lotz /* common */ 6910eaadd30SMichael Lotz NULL, 6920eaadd30SMichael Lotz NULL, 6930eaadd30SMichael Lotz NULL, 6940eaadd30SMichael Lotz NULL, 6950eaadd30SMichael Lotz NULL, 6960eaadd30SMichael Lotz &fs_read_link, 6970eaadd30SMichael Lotz NULL, 6980eaadd30SMichael Lotz NULL, 6990eaadd30SMichael Lotz NULL, 7000eaadd30SMichael Lotz NULL, 7010eaadd30SMichael Lotz &fs_access, 7020eaadd30SMichael Lotz &fs_read_stat, 7030eaadd30SMichael Lotz NULL, 7040eaadd30SMichael Lotz 7050eaadd30SMichael Lotz /* file */ 7060eaadd30SMichael Lotz NULL, 7070eaadd30SMichael Lotz &fs_open, 7080eaadd30SMichael Lotz &fs_close, 7090eaadd30SMichael Lotz &fs_free_cookie, 7100eaadd30SMichael Lotz &fs_read, 7110eaadd30SMichael Lotz NULL, 7120eaadd30SMichael Lotz 7130eaadd30SMichael Lotz /* dir */ 7140eaadd30SMichael Lotz NULL, 7150eaadd30SMichael Lotz NULL, 7160eaadd30SMichael Lotz &fs_open_dir, 7170eaadd30SMichael Lotz &fs_close_dir, 7180eaadd30SMichael Lotz &fs_free_dir_cookie, 7190eaadd30SMichael Lotz &fs_read_dir, 7200eaadd30SMichael Lotz &fs_rewind_dir, 7210eaadd30SMichael Lotz 7220eaadd30SMichael Lotz /* attribute directory ops */ 7230eaadd30SMichael Lotz NULL, 7240eaadd30SMichael Lotz NULL, 7250eaadd30SMichael Lotz NULL, 7260eaadd30SMichael Lotz NULL, 7270eaadd30SMichael Lotz NULL, 7280eaadd30SMichael Lotz 7290eaadd30SMichael Lotz /* attribute ops */ 7300eaadd30SMichael Lotz NULL, 7310eaadd30SMichael Lotz NULL, 7320eaadd30SMichael Lotz NULL, 7330eaadd30SMichael Lotz NULL, 7340eaadd30SMichael Lotz NULL, 7350eaadd30SMichael Lotz NULL, 7360eaadd30SMichael Lotz NULL, 7370eaadd30SMichael Lotz NULL, 7380eaadd30SMichael Lotz NULL, 7390eaadd30SMichael Lotz NULL, 7400eaadd30SMichael Lotz 7410eaadd30SMichael Lotz /* node and FS layer support */ 7420eaadd30SMichael Lotz NULL, 7430eaadd30SMichael Lotz NULL, 7440eaadd30SMichael Lotz }; 7450eaadd30SMichael Lotz 74621e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = { 74721e1553eSJérôme Duval { 74821e1553eSJérôme Duval "file_systems/iso9660" B_CURRENT_FS_API_VERSION, 74921e1553eSJérôme Duval 0, 75021e1553eSJérôme Duval iso_std_ops, 75121e1553eSJérôme Duval }, 75221e1553eSJérôme Duval 7531da9f5ceSAxel Dörfler "iso9660", // short_name 7541da9f5ceSAxel Dörfler "ISO9660 File System", // pretty_name 75576a8ec23SIngo Weinhold 0, // DDM flags 75621e1553eSJérôme Duval 75721e1553eSJérôme Duval // scanning 75821e1553eSJérôme Duval fs_identify_partition, 75921e1553eSJérôme Duval fs_scan_partition, 76021e1553eSJérôme Duval fs_free_identify_partition_cookie, 76121e1553eSJérôme Duval NULL, // free_partition_content_cookie() 76221e1553eSJérôme Duval 76321e1553eSJérôme Duval &fs_mount, 7640eaadd30SMichael Lotz 7650eaadd30SMichael Lotz /* capability querying */ 7660eaadd30SMichael Lotz NULL, 7670eaadd30SMichael Lotz NULL, 7680eaadd30SMichael Lotz NULL, 7690eaadd30SMichael Lotz NULL, 77021e1553eSJérôme Duval NULL, 77121e1553eSJérôme Duval NULL, 77221e1553eSJérôme Duval 7730eaadd30SMichael Lotz /* shadow partition modifications */ 7740eaadd30SMichael Lotz NULL, 77521e1553eSJérôme Duval 7760eaadd30SMichael Lotz /* writing */ 7770eaadd30SMichael Lotz NULL, 7780eaadd30SMichael Lotz NULL, 7790eaadd30SMichael Lotz NULL, 7800eaadd30SMichael Lotz NULL, 7810eaadd30SMichael Lotz NULL, 7820eaadd30SMichael Lotz NULL, 7830eaadd30SMichael Lotz NULL, 78421e1553eSJérôme Duval }; 78521e1553eSJérôme Duval 78621e1553eSJérôme Duval module_info *modules[] = { 78721e1553eSJérôme Duval (module_info *)&sISO660FileSystem, 78821e1553eSJérôme Duval NULL, 78921e1553eSJérôme Duval }; 79021e1553eSJérôme Duval 791