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> 12f47bff08SAxel Dörfler 13f47bff08SAxel Dörfler #ifndef FS_SHELL 1421e1553eSJérôme Duval # include <dirent.h> 155b2c5d03SAxel Dörfler # include <errno.h> 165b2c5d03SAxel Dörfler # include <fcntl.h> 175b2c5d03SAxel Dörfler # include <stdio.h> 185b2c5d03SAxel Dörfler # include <stdlib.h> 195b2c5d03SAxel Dörfler # include <string.h> 2021e1553eSJérôme Duval # include <sys/stat.h> 2121e1553eSJérôme Duval # include <time.h> 225b2c5d03SAxel Dörfler # include <unistd.h> 2321e1553eSJérôme Duval 2421e1553eSJérôme Duval # include <KernelExport.h> 2521e1553eSJérôme Duval # include <NodeMonitor.h> 2621e1553eSJérôme Duval # include <fs_interface.h> 2721e1553eSJérôme Duval # include <fs_cache.h> 2821e1553eSJérôme Duval 2921e1553eSJérôme Duval # include <fs_attr.h> 3021e1553eSJérôme Duval # include <fs_info.h> 3121e1553eSJérôme Duval # include <fs_index.h> 3221e1553eSJérôme Duval # include <fs_query.h> 3321e1553eSJérôme Duval # include <fs_volume.h> 3421e1553eSJérôme Duval 3521e1553eSJérôme Duval # include <util/kernel_cpp.h> 36f47bff08SAxel Dörfler #endif 3721e1553eSJérôme Duval 38dc9a52b9SAxel Dörfler #include "iso9660.h" 395b2c5d03SAxel Dörfler #include "iso9660_identify.h" 405b2c5d03SAxel Dörfler 415b2c5d03SAxel Dörfler 425b2c5d03SAxel Dörfler //#define TRACE_ISO9660 435b2c5d03SAxel Dörfler #ifdef TRACE_ISO9660 4421e1553eSJérôme Duval # define TRACE(x) dprintf x 4521e1553eSJérôme Duval #else 4621e1553eSJérôme Duval # define TRACE(x) ; 4721e1553eSJérôme Duval #endif 4821e1553eSJérôme Duval 4921e1553eSJérôme Duval 5021e1553eSJérôme Duval struct identify_cookie { 5121e1553eSJérôme Duval iso9660_info info; 5221e1553eSJérôme Duval }; 5321e1553eSJérôme Duval 540eaadd30SMichael Lotz extern fs_volume_ops gISO9660VolumeOps; 550eaadd30SMichael Lotz extern fs_vnode_ops gISO9660VnodeOps; 560eaadd30SMichael Lotz 5721e1553eSJérôme Duval 585b2c5d03SAxel Dörfler // #pragma mark - Scanning 595b2c5d03SAxel Dörfler 605b2c5d03SAxel Dörfler 6121e1553eSJérôme Duval static float 6221e1553eSJérôme Duval fs_identify_partition(int fd, partition_data *partition, void **_cookie) 6321e1553eSJérôme Duval { 645b2c5d03SAxel Dörfler iso9660_info *info = new iso9660_info; 6521e1553eSJérôme Duval 665b2c5d03SAxel Dörfler status_t status = iso9660_fs_identify(fd, info); 675b2c5d03SAxel Dörfler if (status != B_OK) { 685b2c5d03SAxel Dörfler delete info; 695b2c5d03SAxel Dörfler return -1; 705b2c5d03SAxel Dörfler } 7121e1553eSJérôme Duval 725b2c5d03SAxel Dörfler *_cookie = info; 735b2c5d03SAxel Dörfler return 0.6f; 7421e1553eSJérôme Duval } 7521e1553eSJérôme Duval 7621e1553eSJérôme Duval 7721e1553eSJérôme Duval static status_t 7821e1553eSJérôme Duval fs_scan_partition(int fd, partition_data *partition, void *_cookie) 7921e1553eSJérôme Duval { 805b2c5d03SAxel Dörfler iso9660_info *info = (iso9660_info *)_cookie; 8121e1553eSJérôme Duval 8221e1553eSJérôme Duval partition->status = B_PARTITION_VALID; 8321e1553eSJérôme Duval partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ; 8421e1553eSJérôme Duval partition->block_size = ISO_PVD_SIZE; 855b2c5d03SAxel Dörfler partition->content_size = ISO_PVD_SIZE * info->max_blocks; 865b2c5d03SAxel Dörfler partition->content_name = strdup(info->PreferredName()); 875b2c5d03SAxel Dörfler 8821e1553eSJérôme Duval if (partition->content_name == NULL) 8921e1553eSJérôme Duval return B_NO_MEMORY; 9021e1553eSJérôme Duval 9121e1553eSJérôme Duval return B_OK; 9221e1553eSJérôme Duval } 9321e1553eSJérôme Duval 9421e1553eSJérôme Duval 9521e1553eSJérôme Duval static void 9621e1553eSJérôme Duval fs_free_identify_partition_cookie(partition_data *partition, void *_cookie) 9721e1553eSJérôme Duval { 985b2c5d03SAxel Dörfler delete (iso9660_info *)_cookie; 9921e1553eSJérôme Duval } 10021e1553eSJérôme Duval 10121e1553eSJérôme Duval 102ff99132eSAxel Dörfler // #pragma mark - FS hooks 103ff99132eSAxel Dörfler 104ff99132eSAxel Dörfler 10521e1553eSJérôme Duval static status_t 1060eaadd30SMichael Lotz fs_mount(fs_volume *_volume, const char *device, uint32 flags, 1070eaadd30SMichael Lotz const char *args, ino_t *_rootID) 10821e1553eSJérôme Duval { 1095b2c5d03SAxel Dörfler bool allowJoliet = true; 110eb097431SAxel Dörfler iso9660_volume *volume; 11121e1553eSJérôme Duval 11221e1553eSJérôme Duval // Check for a 'nojoliet' parm 11321e1553eSJérôme Duval // all we check for is the existance of 'nojoliet' in the parms. 11421e1553eSJérôme Duval if (args != NULL) { 11521e1553eSJérôme Duval uint32 i; 11621e1553eSJérôme Duval char *spot; 11721e1553eSJérôme Duval char *buf = strdup(args); 11821e1553eSJérôme Duval 11921e1553eSJérôme Duval uint32 len = strlen(buf); 12021e1553eSJérôme Duval // lower case the parms data 12121e1553eSJérôme Duval for (i = 0; i < len + 1; i++) 12221e1553eSJérôme Duval buf[i] = tolower(buf[i]); 12321e1553eSJérôme Duval 12421e1553eSJérôme Duval // look for nojoliet 12521e1553eSJérôme Duval spot = strstr(buf, "nojoliet"); 12621e1553eSJérôme Duval if (spot != NULL) 1275b2c5d03SAxel Dörfler allowJoliet = false; 12821e1553eSJérôme Duval 12921e1553eSJérôme Duval free(buf); 13021e1553eSJérôme Duval } 13121e1553eSJérôme Duval 13221e1553eSJérôme Duval // Try and mount volume as an ISO volume. 133ff99132eSAxel Dörfler status_t result = ISOMount(device, O_RDONLY, &volume, allowJoliet); 134ff99132eSAxel Dörfler if (result == B_OK) { 13521e1553eSJérôme Duval *_rootID = ISO_ROOTNODE_ID; 13621e1553eSJérôme Duval 1370eaadd30SMichael Lotz _volume->private_volume = volume; 1380eaadd30SMichael Lotz _volume->ops = &gISO9660VolumeOps; 1390eaadd30SMichael Lotz volume->volume = _volume; 1400eaadd30SMichael Lotz volume->id = _volume->id; 14121e1553eSJérôme Duval 1420eaadd30SMichael Lotz result = publish_vnode(_volume, *_rootID, &volume->rootDirRec, 143a26c2439SMichael Lotz &gISO9660VnodeOps, 144a26c2439SMichael Lotz volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0); 145ff99132eSAxel Dörfler if (result != B_OK) { 146ff99132eSAxel Dörfler block_cache_delete(volume->fBlockCache, false); 147ff99132eSAxel Dörfler free(volume); 148ff99132eSAxel Dörfler result = B_ERROR; 149ff99132eSAxel Dörfler } 15021e1553eSJérôme Duval } 15121e1553eSJérôme Duval return result; 15221e1553eSJérôme Duval } 15321e1553eSJérôme Duval 15421e1553eSJérôme Duval 15521e1553eSJérôme Duval static status_t 1560eaadd30SMichael Lotz fs_unmount(fs_volume *_vol) 15721e1553eSJérôme Duval { 15821e1553eSJérôme Duval status_t result = B_NO_ERROR; 159eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 16021e1553eSJérôme Duval 16121e1553eSJérôme Duval TRACE(("fs_unmount - ENTER\n")); 16221e1553eSJérôme Duval 1639d254f45SJérôme Duval // Unlike in BeOS, we need to put the reference to our root node ourselves 1640eaadd30SMichael Lotz put_vnode(_vol, ISO_ROOTNODE_ID); 1659d254f45SJérôme Duval 16621e1553eSJérôme Duval block_cache_delete(ns->fBlockCache, false); 16721e1553eSJérôme Duval close(ns->fdOfSession); 16821e1553eSJérôme Duval result = close(ns->fd); 16921e1553eSJérôme Duval 17021e1553eSJérôme Duval free(ns); 17121e1553eSJérôme Duval 17221e1553eSJérôme Duval TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result))); 17321e1553eSJérôme Duval return result; 17421e1553eSJérôme Duval } 17521e1553eSJérôme Duval 17621e1553eSJérôme Duval 17721e1553eSJérôme Duval static status_t 1780eaadd30SMichael Lotz fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss) 17921e1553eSJérôme Duval { 180eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 18121e1553eSJérôme Duval int i; 18221e1553eSJérôme Duval 18321e1553eSJérôme Duval fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 18421e1553eSJérôme Duval fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT]; 18521e1553eSJérôme Duval fss->io_size = 65536; 18621e1553eSJérôme Duval fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT]; 18721e1553eSJérôme Duval fss->free_blocks = 0; 18821e1553eSJérôme Duval 18921e1553eSJérôme Duval strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name)); 19021e1553eSJérôme Duval 19121e1553eSJérôme Duval strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name)); 192ff99132eSAxel Dörfler for (i = strlen(fss->volume_name) - 1; i >=0 ; i--) { 19321e1553eSJérôme Duval if (fss->volume_name[i] != ' ') 19421e1553eSJérôme Duval break; 195ff99132eSAxel Dörfler } 19621e1553eSJérôme Duval 19721e1553eSJérôme Duval if (i < 0) 19821e1553eSJérôme Duval strcpy(fss->volume_name, "UNKNOWN"); 19921e1553eSJérôme Duval else 20021e1553eSJérôme Duval fss->volume_name[i + 1] = 0; 20121e1553eSJérôme Duval 20221e1553eSJérôme Duval strcpy(fss->fsh_name, "iso9660"); 203ff99132eSAxel Dörfler return B_OK; 20421e1553eSJérôme Duval } 20521e1553eSJérôme Duval 2063b723f79SJérôme Duval 2073b723f79SJérôme Duval static status_t 2080eaadd30SMichael Lotz fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferSize) 2093b723f79SJérôme Duval { 210eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode*)_node->private_node; 2113b723f79SJérôme Duval 212eb097431SAxel Dörfler strlcpy(buffer, node->name, bufferSize); 2133b723f79SJérôme Duval return B_OK; 2143b723f79SJérôme Duval } 2153b723f79SJérôme Duval 2163b723f79SJérôme Duval 21721e1553eSJérôme Duval static status_t 2180eaadd30SMichael Lotz fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID) 21921e1553eSJérôme Duval { 220eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 221eb097431SAxel Dörfler iso9660_inode *baseNode = (iso9660_inode*)_base->private_node; 222eb097431SAxel Dörfler iso9660_inode *newNode = NULL; 22321e1553eSJérôme Duval 224eb097431SAxel Dörfler TRACE(("fs_walk - looking for %s in dir file of length %ld\n", file, 22521e1553eSJérôme Duval baseNode->dataLen[FS_DATA_FORMAT])); 22621e1553eSJérôme Duval 22721e1553eSJérôme Duval if (strcmp(file, ".") == 0) { 22821e1553eSJérôme Duval // base directory 22921e1553eSJérôme Duval TRACE(("fs_walk - found \".\" file.\n")); 23021e1553eSJérôme Duval *_vnodeID = baseNode->id; 23149004dc7SMichael Lotz return get_vnode(_vol, *_vnodeID, NULL); 23221e1553eSJérôme Duval } else if (strcmp(file, "..") == 0) { 23321e1553eSJérôme Duval // parent directory 23421e1553eSJérôme Duval TRACE(("fs_walk - found \"..\" file.\n")); 23521e1553eSJérôme Duval *_vnodeID = baseNode->parID; 23649004dc7SMichael Lotz return get_vnode(_vol, *_vnodeID, NULL); 237ff99132eSAxel Dörfler } 238ff99132eSAxel Dörfler 23921e1553eSJérôme Duval // look up file in the directory 240ff99132eSAxel Dörfler uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT]; 241ff99132eSAxel Dörfler status_t result = ENOENT; 242eb097431SAxel Dörfler size_t totalRead = 0; 243ff99132eSAxel Dörfler off_t block = baseNode->startLBN[FS_DATA_FORMAT]; 244ff99132eSAxel Dörfler bool done = false; 24521e1553eSJérôme Duval 246ff99132eSAxel Dörfler while (totalRead < dataLength && !done) { 24721e1553eSJérôme Duval off_t cachedBlock = block; 248eb097431SAxel Dörfler char* blockData = (char*)block_cache_get(ns->fBlockCache, block); 249*2a64cb11SAxel Dörfler if (blockData == NULL) 250*2a64cb11SAxel Dörfler break; 251*2a64cb11SAxel Dörfler 252eb097431SAxel Dörfler size_t bytesRead = 0; 25321e1553eSJérôme Duval off_t blockBytesRead = 0; 254eb097431SAxel Dörfler iso9660_inode node; 25521e1553eSJérôme Duval int initResult; 25621e1553eSJérôme Duval 257eb097431SAxel Dörfler TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer " 258eb097431SAxel Dörfler "%p.\n", block, blockData)); 25921e1553eSJérôme Duval 260*2a64cb11SAxel Dörfler // Move to the next block if necessary 26121e1553eSJérôme Duval // Don't go over end of buffer, if dir record sits on boundary. 26221e1553eSJérôme Duval 263*2a64cb11SAxel Dörfler while (blockBytesRead < ns->logicalBlkSize[FS_DATA_FORMAT] 264ff99132eSAxel Dörfler && totalRead + blockBytesRead < dataLength 26521e1553eSJérôme Duval && blockData[0] != 0 266ff99132eSAxel Dörfler && !done) { 267ff99132eSAxel Dörfler initResult = InitNode(&node, blockData, &bytesRead, 268ff99132eSAxel Dörfler ns->joliet_level); 269eb097431SAxel Dörfler TRACE(("fs_walk - InitNode returned %s, filename %s, %lu bytes " 270eb097431SAxel Dörfler "read\n", strerror(initResult), node.name, 271eb097431SAxel Dörfler bytesRead)); 27221e1553eSJérôme Duval 273ff99132eSAxel Dörfler if (initResult == B_OK) { 274eb097431SAxel Dörfler if (!strcmp(node.name, file)) { 275*2a64cb11SAxel Dörfler TRACE(("fs_walk - success, found vnode at block %Ld, pos " 276*2a64cb11SAxel Dörfler "%Ld\n", block, blockBytesRead)); 277*2a64cb11SAxel Dörfler 278*2a64cb11SAxel Dörfler *_vnodeID = (block << 30) + (blockBytesRead & 0xffffffff); 27921e1553eSJérôme Duval TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); 28021e1553eSJérôme Duval 2810eaadd30SMichael Lotz result = get_vnode(_vol, *_vnodeID, 28249004dc7SMichael Lotz (void **)&newNode); 283ff99132eSAxel Dörfler if (result == B_OK) { 28421e1553eSJérôme Duval newNode->parID = baseNode->id; 285ff99132eSAxel Dörfler done = true; 28621e1553eSJérôme Duval } 28721e1553eSJérôme Duval } else { 288eb097431SAxel Dörfler free(node.name); 28921e1553eSJérôme Duval free(node.attr.slName); 29021e1553eSJérôme Duval } 29121e1553eSJérôme Duval } else { 29221e1553eSJérôme Duval result = initResult; 29321e1553eSJérôme Duval if (bytesRead == 0) 294f47bff08SAxel Dörfler done = true; 29521e1553eSJérôme Duval } 29621e1553eSJérôme Duval blockData += bytesRead; 29721e1553eSJérôme Duval blockBytesRead += bytesRead; 29821e1553eSJérôme Duval 299eb097431SAxel Dörfler TRACE(("fs_walk - Adding %lu bytes to blockBytes read (total " 300eb097431SAxel Dörfler "%Ld/%lu).\n", bytesRead, blockBytesRead, 301eb097431SAxel Dörfler baseNode->dataLen[FS_DATA_FORMAT])); 30221e1553eSJérôme Duval } 30321e1553eSJérôme Duval totalRead += ns->logicalBlkSize[FS_DATA_FORMAT]; 30421e1553eSJérôme Duval block++; 30521e1553eSJérôme Duval 306eb097431SAxel Dörfler TRACE(("fs_walk - moving to next block %Ld, total read %lu\n", 307eb097431SAxel Dörfler block, totalRead)); 30821e1553eSJérôme Duval block_cache_put(ns->fBlockCache, cachedBlock); 30921e1553eSJérôme Duval } 31021e1553eSJérôme Duval 311ff99132eSAxel Dörfler TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", 312ff99132eSAxel Dörfler strerror(result), *_vnodeID)); 31321e1553eSJérôme Duval return result; 31421e1553eSJérôme Duval } 31521e1553eSJérôme Duval 31621e1553eSJérôme Duval 31721e1553eSJérôme Duval static status_t 3180eaadd30SMichael Lotz fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node, 3190eaadd30SMichael Lotz int *_type, uint32 *_flags, bool reenter) 32021e1553eSJérôme Duval { 321eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume*)_vol->private_volume; 322ff99132eSAxel Dörfler 323eb097431SAxel Dörfler iso9660_inode *newNode = (iso9660_inode*)calloc(sizeof(iso9660_inode), 1); 324ff99132eSAxel Dörfler if (newNode == NULL) 325ff99132eSAxel Dörfler return B_NO_MEMORY; 32621e1553eSJérôme Duval 327ff99132eSAxel Dörfler uint32 pos = vnodeID & 0x3fffffff; 328ff99132eSAxel Dörfler uint32 block = vnodeID >> 30; 32921e1553eSJérôme Duval 330eb097431SAxel Dörfler TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node %p\n", 331ff99132eSAxel Dörfler block, pos, vnodeID, newNode)); 33221e1553eSJérôme Duval 333d02cde30SMichael Lotz if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) { 334d02cde30SMichael Lotz free(newNode); 335ff99132eSAxel Dörfler return B_BAD_VALUE; 336d02cde30SMichael Lotz } 33721e1553eSJérôme Duval 338eb097431SAxel Dörfler char *data = (char *)block_cache_get(ns->fBlockCache, block); 339ff99132eSAxel Dörfler if (data == NULL) { 340ff99132eSAxel Dörfler free(newNode); 341ff99132eSAxel Dörfler return B_IO_ERROR; 342ff99132eSAxel Dörfler } 34321e1553eSJérôme Duval 344ff99132eSAxel Dörfler status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level); 34521e1553eSJérôme Duval block_cache_put(ns->fBlockCache, block); 34621e1553eSJérôme Duval 347ff99132eSAxel Dörfler if (result < B_OK) { 348ff99132eSAxel Dörfler free(newNode); 349ff99132eSAxel Dörfler return result; 35021e1553eSJérôme Duval } 35121e1553eSJérôme Duval 352ff99132eSAxel Dörfler newNode->id = vnodeID; 3530eaadd30SMichael Lotz _node->private_node = newNode; 3540eaadd30SMichael Lotz _node->ops = &gISO9660VnodeOps; 3550eaadd30SMichael Lotz *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH); 356a26c2439SMichael Lotz *_flags = 0; 357ff99132eSAxel Dörfler 358ff99132eSAxel Dörfler if ((newNode->flags & ISO_ISDIR) == 0) { 359ff99132eSAxel Dörfler newNode->cache = file_cache_create(ns->id, vnodeID, 3603d268edaSAxel Dörfler newNode->dataLen[FS_DATA_FORMAT]); 3615b4cb109SJérôme Duval } 3625b4cb109SJérôme Duval 363ff99132eSAxel Dörfler return B_OK; 36421e1553eSJérôme Duval } 36521e1553eSJérôme Duval 36621e1553eSJérôme Duval 36721e1553eSJérôme Duval static status_t 368eb097431SAxel Dörfler fs_release_vnode(fs_volume* /*_volume*/, fs_vnode* _node, bool /*reenter*/) 36921e1553eSJérôme Duval { 370eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 37121e1553eSJérôme Duval 372eb097431SAxel Dörfler TRACE(("fs_release_vnode - ENTER (%p)\n", node)); 37321e1553eSJérôme Duval 37421e1553eSJérôme Duval if (node->id != ISO_ROOTNODE_ID) { 375eb097431SAxel Dörfler free(node->name); 37621e1553eSJérôme Duval free(node->attr.slName); 377eb097431SAxel Dörfler 3785b4cb109SJérôme Duval if (node->cache != NULL) 3795b4cb109SJérôme Duval file_cache_delete(node->cache); 38021e1553eSJérôme Duval 38121e1553eSJérôme Duval free(node); 38221e1553eSJérôme Duval } 38321e1553eSJérôme Duval 3845b4cb109SJérôme Duval TRACE(("fs_release_vnode - EXIT\n")); 385eb097431SAxel Dörfler return B_OK; 38621e1553eSJérôme Duval } 38721e1553eSJérôme Duval 38821e1553eSJérôme Duval 38921e1553eSJérôme Duval static status_t 3900eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos, 391e6bd90c5SIngo Weinhold const iovec *vecs, size_t count, size_t *_numBytes) 3925b4cb109SJérôme Duval { 393eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 394eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 3955b4cb109SJérôme Duval 396ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 397ff99132eSAxel Dörfler size_t bytesLeft = *_numBytes; 3985b4cb109SJérôme Duval 399ff99132eSAxel Dörfler if (pos >= fileSize) { 400ff99132eSAxel Dörfler *_numBytes = 0; 4015b4cb109SJérôme Duval return B_OK; 4025b4cb109SJérôme Duval } 403ff99132eSAxel Dörfler if (pos + bytesLeft > fileSize) { 404ff99132eSAxel Dörfler bytesLeft = fileSize - pos; 405ff99132eSAxel Dörfler *_numBytes = bytesLeft; 4065b4cb109SJérôme Duval } 4075b4cb109SJérôme Duval 408ff99132eSAxel Dörfler file_io_vec fileVec; 409ff99132eSAxel Dörfler fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT] 410ff99132eSAxel Dörfler * ns->logicalBlkSize[FS_DATA_FORMAT]; 411ff99132eSAxel Dörfler fileVec.length = bytesLeft; 4125b4cb109SJérôme Duval 413ff99132eSAxel Dörfler uint32 vecIndex = 0; 414ff99132eSAxel Dörfler size_t vecOffset = 0; 415ff99132eSAxel Dörfler return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count, 416ff99132eSAxel Dörfler &vecIndex, &vecOffset, &bytesLeft); 4175b4cb109SJérôme Duval } 4185b4cb109SJérôme Duval 4195b4cb109SJérôme Duval 4205b4cb109SJérôme Duval static status_t 4210eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st) 42221e1553eSJérôme Duval { 423eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume*)_vol->private_volume; 424eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode*)_node->private_node; 4253b723f79SJérôme Duval status_t result = B_NO_ERROR; 42621e1553eSJérôme Duval time_t time; 42721e1553eSJérôme Duval 4283b723f79SJérôme Duval TRACE(("fs_read_stat - ENTER\n")); 42921e1553eSJérôme Duval 43021e1553eSJérôme Duval st->st_dev = ns->id; 43121e1553eSJérôme Duval st->st_ino = node->id; 43221e1553eSJérôme Duval st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 43321e1553eSJérôme Duval st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 43421e1553eSJérôme Duval st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 43521e1553eSJérôme Duval st->st_blksize = 65536; 43621e1553eSJérôme Duval st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 43721e1553eSJérôme Duval 43821e1553eSJérôme Duval // Same for file/dir in ISO9660 43921e1553eSJérôme Duval st->st_size = node->dataLen[FS_DATA_FORMAT]; 4402c348abbSAxel Dörfler st->st_blocks = (st->st_size + 511) / 512; 44121e1553eSJérôme Duval if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 44221e1553eSJérôme Duval st->st_ctime = st->st_mtime = st->st_atime = time; 44321e1553eSJérôme Duval 4443b723f79SJérôme Duval TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 44521e1553eSJérôme Duval 44621e1553eSJérôme Duval return result; 44721e1553eSJérôme Duval } 44821e1553eSJérôme Duval 44921e1553eSJérôme Duval 45021e1553eSJérôme Duval static status_t 4510eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie) 45221e1553eSJérôme Duval { 45321e1553eSJérôme Duval status_t result = B_NO_ERROR; 45421e1553eSJérôme Duval 4550eaadd30SMichael Lotz (void)_vol; 45621e1553eSJérôme Duval (void)cookie; 45721e1553eSJérôme Duval 45821e1553eSJérôme Duval // Do not allow any of the write-like open modes to get by 45921e1553eSJérôme Duval if ((omode == O_WRONLY) || (omode == O_RDWR)) 46021e1553eSJérôme Duval result = EROFS; 46121e1553eSJérôme Duval else if((omode & O_TRUNC) || (omode & O_CREAT)) 46221e1553eSJérôme Duval result = EROFS; 46321e1553eSJérôme Duval 46421e1553eSJérôme Duval return result; 46521e1553eSJérôme Duval } 46621e1553eSJérôme Duval 46721e1553eSJérôme Duval 46821e1553eSJérôme Duval static status_t 4690eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer, 470ff99132eSAxel Dörfler size_t *_length) 47121e1553eSJérôme Duval { 472eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 47321e1553eSJérôme Duval 47421e1553eSJérôme Duval if (node->flags & ISO_ISDIR) 47521e1553eSJérôme Duval return EISDIR; 47621e1553eSJérôme Duval 477ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 4785b4cb109SJérôme Duval 4795b4cb109SJérôme Duval // set/check boundaries for pos/length 480ff99132eSAxel Dörfler if (pos < 0) 4815b4cb109SJérôme Duval return B_BAD_VALUE; 482ff99132eSAxel Dörfler if (pos >= fileSize) { 483ff99132eSAxel Dörfler *_length = 0; 4845b4cb109SJérôme Duval return B_OK; 4855b4cb109SJérôme Duval } 486ff99132eSAxel Dörfler 487ff99132eSAxel Dörfler return file_cache_read(node->cache, NULL, pos, buffer, _length); 48821e1553eSJérôme Duval } 48921e1553eSJérôme Duval 49021e1553eSJérôme Duval 49121e1553eSJérôme Duval static status_t 4920eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie) 49321e1553eSJérôme Duval { 4940eaadd30SMichael Lotz (void)_vol; 4950eaadd30SMichael Lotz (void)_node; 49621e1553eSJérôme Duval (void)cookie; 49721e1553eSJérôme Duval 49821e1553eSJérôme Duval return B_OK; 49921e1553eSJérôme Duval } 50021e1553eSJérôme Duval 501ff99132eSAxel Dörfler 50221e1553eSJérôme Duval static status_t 5030eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 50421e1553eSJérôme Duval { 5050eaadd30SMichael Lotz (void)_vol; 5060eaadd30SMichael Lotz (void)_node; 50721e1553eSJérôme Duval (void)cookie; 50821e1553eSJérôme Duval 50921e1553eSJérôme Duval return B_OK; 51021e1553eSJérôme Duval } 51121e1553eSJérôme Duval 512ff99132eSAxel Dörfler 51321e1553eSJérôme Duval static status_t 5140eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode) 51521e1553eSJérôme Duval { 5160eaadd30SMichael Lotz (void)_vol; 5170eaadd30SMichael Lotz (void)_node; 51821e1553eSJérôme Duval (void)mode; 51921e1553eSJérôme Duval 52021e1553eSJérôme Duval return B_OK; 52121e1553eSJérôme Duval } 52221e1553eSJérôme Duval 523ff99132eSAxel Dörfler 52421e1553eSJérôme Duval static status_t 5250eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize) 52621e1553eSJérôme Duval { 527eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 52821e1553eSJérôme Duval 529ff99132eSAxel Dörfler if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) 530ff99132eSAxel Dörfler return B_BAD_VALUE; 53121e1553eSJérôme Duval 53221e1553eSJérôme Duval size_t length = strlen(node->attr.slName); 53321e1553eSJérôme Duval if (length > *_bufferSize) 5343b723f79SJérôme Duval memcpy(buffer, node->attr.slName, *_bufferSize); 5353b723f79SJérôme Duval else { 53621e1553eSJérôme Duval memcpy(buffer, node->attr.slName, length); 5373b723f79SJérôme Duval *_bufferSize = length; 5383b723f79SJérôme Duval } 53921e1553eSJérôme Duval 540ff99132eSAxel Dörfler return B_OK; 54121e1553eSJérôme Duval } 54221e1553eSJérôme Duval 54321e1553eSJérôme Duval 54421e1553eSJérôme Duval static status_t 545eb097431SAxel Dörfler fs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie) 54621e1553eSJérôme Duval { 547eb097431SAxel Dörfler iso9660_inode *node = (iso9660_inode *)_node->private_node; 54821e1553eSJérôme Duval 549eb097431SAxel Dörfler TRACE(("fs_open_dir - node is %p\n", node)); 55021e1553eSJérôme Duval 55121e1553eSJérôme Duval if (!(node->flags & ISO_ISDIR)) 552ff99132eSAxel Dörfler return B_NOT_A_DIRECTORY; 55321e1553eSJérôme Duval 554ff99132eSAxel Dörfler dircookie* dirCookie = (dircookie*)malloc(sizeof(dircookie)); 555ff99132eSAxel Dörfler if (dirCookie == NULL) 556ff99132eSAxel Dörfler return B_NO_MEMORY; 557ff99132eSAxel Dörfler 55821e1553eSJérôme Duval dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 55921e1553eSJérôme Duval dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 56021e1553eSJérôme Duval dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 56121e1553eSJérôme Duval dirCookie->pos = 0; 56221e1553eSJérôme Duval dirCookie->id = node->id; 563eb097431SAxel Dörfler *_cookie = (void*)dirCookie; 56421e1553eSJérôme Duval 565ff99132eSAxel Dörfler return B_OK; 56621e1553eSJérôme Duval } 56721e1553eSJérôme Duval 56821e1553eSJérôme Duval 56921e1553eSJérôme Duval static status_t 57044d0dbc8SAxel Dörfler fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, 57144d0dbc8SAxel Dörfler struct dirent *buffer, size_t bufferSize, uint32 *num) 57221e1553eSJérôme Duval { 573eb097431SAxel Dörfler iso9660_volume *ns = (iso9660_volume *)_vol->private_volume; 57421e1553eSJérôme Duval dircookie *dirCookie = (dircookie *)_cookie; 57521e1553eSJérôme Duval 5765b4cb109SJérôme Duval TRACE(("fs_read_dir - ENTER\n")); 57721e1553eSJérôme Duval 578ff99132eSAxel Dörfler status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize); 57921e1553eSJérôme Duval 58021e1553eSJérôme Duval // If we succeeded, return 1, the number of dirents we read. 581ff99132eSAxel Dörfler if (result == B_OK) 58221e1553eSJérôme Duval *num = 1; 58321e1553eSJérôme Duval else 58421e1553eSJérôme Duval *num = 0; 58521e1553eSJérôme Duval 58621e1553eSJérôme Duval // When you get to the end, don't return an error, just return 58721e1553eSJérôme Duval // a zero in *num. 58821e1553eSJérôme Duval 589eb097431SAxel Dörfler if (result == B_ENTRY_NOT_FOUND) 590ff99132eSAxel Dörfler result = B_OK; 59121e1553eSJérôme Duval 5925b4cb109SJérôme Duval TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result))); 59321e1553eSJérôme Duval return result; 59421e1553eSJérôme Duval } 59521e1553eSJérôme Duval 59621e1553eSJérôme Duval 59721e1553eSJérôme Duval static status_t 5980eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie) 59921e1553eSJérôme Duval { 60021e1553eSJérôme Duval dircookie *cookie = (dircookie*)_cookie; 60121e1553eSJérôme Duval 60221e1553eSJérôme Duval cookie->block = cookie->startBlock; 60321e1553eSJérôme Duval cookie->pos = 0; 604ff99132eSAxel Dörfler return B_OK; 60521e1553eSJérôme Duval } 60621e1553eSJérôme Duval 60721e1553eSJérôme Duval 60821e1553eSJérôme Duval static status_t 6090eaadd30SMichael Lotz fs_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie) 61021e1553eSJérôme Duval { 61121e1553eSJérôme Duval return B_OK; 61221e1553eSJérôme Duval } 61321e1553eSJérôme Duval 61421e1553eSJérôme Duval 61521e1553eSJérôme Duval static status_t 6160eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie) 61721e1553eSJérôme Duval { 61821e1553eSJérôme Duval free(cookie); 61921e1553eSJérôme Duval return B_OK; 62021e1553eSJérôme Duval } 62121e1553eSJérôme Duval 622ff99132eSAxel Dörfler 62321e1553eSJérôme Duval // #pragma mark - 62421e1553eSJérôme Duval 62521e1553eSJérôme Duval 62621e1553eSJérôme Duval static status_t 62721e1553eSJérôme Duval iso_std_ops(int32 op, ...) 62821e1553eSJérôme Duval { 62921e1553eSJérôme Duval switch (op) { 63021e1553eSJérôme Duval case B_MODULE_INIT: 63121e1553eSJérôme Duval case B_MODULE_UNINIT: 63221e1553eSJérôme Duval return B_OK; 63321e1553eSJérôme Duval default: 63421e1553eSJérôme Duval return B_ERROR; 63521e1553eSJérôme Duval } 63621e1553eSJérôme Duval } 63721e1553eSJérôme Duval 63821e1553eSJérôme Duval 6390eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = { 6400eaadd30SMichael Lotz &fs_unmount, 6410eaadd30SMichael Lotz &fs_read_fs_stat, 6420eaadd30SMichael Lotz NULL, 6430eaadd30SMichael Lotz NULL, 6440eaadd30SMichael Lotz &fs_read_vnode, 6450eaadd30SMichael Lotz 6460eaadd30SMichael Lotz /* index and index directory ops */ 6470eaadd30SMichael Lotz NULL, 6480eaadd30SMichael Lotz NULL, 6490eaadd30SMichael Lotz NULL, 6500eaadd30SMichael Lotz NULL, 6510eaadd30SMichael Lotz NULL, 6520eaadd30SMichael Lotz NULL, 6530eaadd30SMichael Lotz NULL, 6540eaadd30SMichael Lotz NULL, 6550eaadd30SMichael Lotz 6560eaadd30SMichael Lotz /* query ops */ 6570eaadd30SMichael Lotz NULL, 6580eaadd30SMichael Lotz NULL, 6590eaadd30SMichael Lotz NULL, 6600eaadd30SMichael Lotz NULL, 6610eaadd30SMichael Lotz NULL, 6620eaadd30SMichael Lotz 6630eaadd30SMichael Lotz /* FS layer ops */ 6640eaadd30SMichael Lotz NULL, 6650eaadd30SMichael Lotz NULL, 6660eaadd30SMichael Lotz }; 6670eaadd30SMichael Lotz 6680eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = { 6690eaadd30SMichael Lotz &fs_walk, 6700eaadd30SMichael Lotz &fs_get_vnode_name, 6710eaadd30SMichael Lotz &fs_release_vnode, 6720eaadd30SMichael Lotz NULL, 6730eaadd30SMichael Lotz 6740eaadd30SMichael Lotz /* vm-related ops */ 6750eaadd30SMichael Lotz NULL, 6760eaadd30SMichael Lotz &fs_read_pages, 6770eaadd30SMichael Lotz NULL, 6780eaadd30SMichael Lotz 679ec598fe4SIngo Weinhold NULL, // io() 680ec598fe4SIngo Weinhold NULL, // cancel_io() 681ec598fe4SIngo Weinhold 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