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 41*41b19806SAxel Dörfler // TODO: temporary solution as long as there is no public I/O requests API 42*41b19806SAxel Dörfler #include <io_requests.h> 43*41b19806SAxel Dörfler 445b2c5d03SAxel Dörfler 455b2c5d03SAxel Dörfler //#define TRACE_ISO9660 465b2c5d03SAxel Dörfler #ifdef TRACE_ISO9660 4721e1553eSJérôme Duval # define TRACE(x) dprintf x 4821e1553eSJérôme Duval #else 4921e1553eSJérôme Duval # define TRACE(x) ; 5021e1553eSJérôme Duval #endif 5121e1553eSJérôme Duval 5221e1553eSJérôme Duval 5321e1553eSJérôme Duval struct identify_cookie { 5421e1553eSJérôme Duval iso9660_info info; 5521e1553eSJérôme Duval }; 5621e1553eSJérôme Duval 570eaadd30SMichael Lotz extern fs_volume_ops gISO9660VolumeOps; 580eaadd30SMichael Lotz extern fs_vnode_ops gISO9660VnodeOps; 590eaadd30SMichael Lotz 6021e1553eSJérôme Duval 61*41b19806SAxel Dörfler //! fs_io() callback hook 62*41b19806SAxel Dörfler static status_t 63*41b19806SAxel Dörfler iterative_io_get_vecs_hook(void* cookie, io_request* request, off_t offset, 64*41b19806SAxel Dörfler size_t size, struct file_io_vec* vecs, size_t* _count) 65*41b19806SAxel Dörfler { 66*41b19806SAxel Dörfler iso9660_inode* node = (iso9660_inode*)cookie; 67*41b19806SAxel Dörfler 68*41b19806SAxel Dörfler vecs->offset = offset + node->startLBN[FS_DATA_FORMAT] 69*41b19806SAxel Dörfler * node->volume->logicalBlkSize[FS_DATA_FORMAT]; 70*41b19806SAxel Dörfler vecs->length = size; 71*41b19806SAxel Dörfler 72*41b19806SAxel Dörfler *_count = 1; 73*41b19806SAxel Dörfler 74*41b19806SAxel Dörfler return B_OK; 75*41b19806SAxel Dörfler } 76*41b19806SAxel Dörfler 77*41b19806SAxel Dörfler 78*41b19806SAxel Dörfler //! fs_io() callback hook 79*41b19806SAxel Dörfler static status_t 80*41b19806SAxel Dörfler iterative_io_finished_hook(void* cookie, io_request* request, status_t status, 81*41b19806SAxel Dörfler bool partialTransfer, size_t bytesTransferred) 82*41b19806SAxel Dörfler { 83*41b19806SAxel Dörfler // nothing to do here... 84*41b19806SAxel Dörfler return B_OK; 85*41b19806SAxel Dörfler } 86*41b19806SAxel Dörfler 87*41b19806SAxel Dörfler 885b2c5d03SAxel Dörfler // #pragma mark - Scanning 895b2c5d03SAxel Dörfler 905b2c5d03SAxel Dörfler 9121e1553eSJérôme Duval static float 9221e1553eSJérôme Duval fs_identify_partition(int fd, partition_data* partition, void** _cookie) 9321e1553eSJérôme Duval { 945b2c5d03SAxel Dörfler iso9660_info* info = new iso9660_info; 9521e1553eSJérôme Duval 965b2c5d03SAxel Dörfler status_t status = iso9660_fs_identify(fd, info); 975b2c5d03SAxel Dörfler if (status != B_OK) { 985b2c5d03SAxel Dörfler delete info; 995b2c5d03SAxel Dörfler return -1; 1005b2c5d03SAxel Dörfler } 10121e1553eSJérôme Duval 1025b2c5d03SAxel Dörfler *_cookie = info; 1035b2c5d03SAxel Dörfler return 0.6f; 10421e1553eSJérôme Duval } 10521e1553eSJérôme Duval 10621e1553eSJérôme Duval 10721e1553eSJérôme Duval static status_t 10821e1553eSJérôme Duval fs_scan_partition(int fd, partition_data* partition, void* _cookie) 10921e1553eSJérôme Duval { 1105b2c5d03SAxel Dörfler iso9660_info* info = (iso9660_info*)_cookie; 11121e1553eSJérôme Duval 11221e1553eSJérôme Duval partition->status = B_PARTITION_VALID; 11321e1553eSJérôme Duval partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ; 11421e1553eSJérôme Duval partition->block_size = ISO_PVD_SIZE; 1155b2c5d03SAxel Dörfler partition->content_size = ISO_PVD_SIZE * info->max_blocks; 1165b2c5d03SAxel Dörfler partition->content_name = strdup(info->PreferredName()); 1175b2c5d03SAxel Dörfler 11821e1553eSJérôme Duval if (partition->content_name == NULL) 11921e1553eSJérôme Duval return B_NO_MEMORY; 12021e1553eSJérôme Duval 12121e1553eSJérôme Duval return B_OK; 12221e1553eSJérôme Duval } 12321e1553eSJérôme Duval 12421e1553eSJérôme Duval 12521e1553eSJérôme Duval static void 12621e1553eSJérôme Duval fs_free_identify_partition_cookie(partition_data* partition, void* _cookie) 12721e1553eSJérôme Duval { 1285b2c5d03SAxel Dörfler delete (iso9660_info*)_cookie; 12921e1553eSJérôme Duval } 13021e1553eSJérôme Duval 13121e1553eSJérôme Duval 132ff99132eSAxel Dörfler // #pragma mark - FS hooks 133ff99132eSAxel Dörfler 134ff99132eSAxel Dörfler 13521e1553eSJérôme Duval static status_t 1360eaadd30SMichael Lotz fs_mount(fs_volume* _volume, const char* device, uint32 flags, 1370eaadd30SMichael Lotz const char* args, ino_t* _rootID) 13821e1553eSJérôme Duval { 1395b2c5d03SAxel Dörfler bool allowJoliet = true; 140eb097431SAxel Dörfler iso9660_volume* volume; 14121e1553eSJérôme Duval 14221e1553eSJérôme Duval // Check for a 'nojoliet' parm 14321e1553eSJérôme Duval // all we check for is the existance of 'nojoliet' in the parms. 14421e1553eSJérôme Duval if (args != NULL) { 14521e1553eSJérôme Duval uint32 i; 14621e1553eSJérôme Duval char* spot; 14721e1553eSJérôme Duval char* buf = strdup(args); 14821e1553eSJérôme Duval 14921e1553eSJérôme Duval uint32 len = strlen(buf); 15021e1553eSJérôme Duval // lower case the parms data 15121e1553eSJérôme Duval for (i = 0; i < len + 1; i++) 15221e1553eSJérôme Duval buf[i] = tolower(buf[i]); 15321e1553eSJérôme Duval 15421e1553eSJérôme Duval // look for nojoliet 15521e1553eSJérôme Duval spot = strstr(buf, "nojoliet"); 15621e1553eSJérôme Duval if (spot != NULL) 1575b2c5d03SAxel Dörfler allowJoliet = false; 15821e1553eSJérôme Duval 15921e1553eSJérôme Duval free(buf); 16021e1553eSJérôme Duval } 16121e1553eSJérôme Duval 16221e1553eSJérôme Duval // Try and mount volume as an ISO volume. 163ff99132eSAxel Dörfler status_t result = ISOMount(device, O_RDONLY, &volume, allowJoliet); 164ff99132eSAxel Dörfler if (result == B_OK) { 16521e1553eSJérôme Duval *_rootID = ISO_ROOTNODE_ID; 16621e1553eSJérôme Duval 1670eaadd30SMichael Lotz _volume->private_volume = volume; 1680eaadd30SMichael Lotz _volume->ops = &gISO9660VolumeOps; 1690eaadd30SMichael Lotz volume->volume = _volume; 1700eaadd30SMichael Lotz volume->id = _volume->id; 17121e1553eSJérôme Duval 1720eaadd30SMichael Lotz result = publish_vnode(_volume, *_rootID, &volume->rootDirRec, 173a26c2439SMichael Lotz &gISO9660VnodeOps, 174a26c2439SMichael Lotz volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0); 175ff99132eSAxel Dörfler if (result != B_OK) { 176ff99132eSAxel Dörfler block_cache_delete(volume->fBlockCache, false); 177ff99132eSAxel Dörfler free(volume); 178ff99132eSAxel Dörfler result = B_ERROR; 179ff99132eSAxel Dörfler } 18021e1553eSJérôme Duval } 18121e1553eSJérôme Duval return result; 18221e1553eSJérôme Duval } 18321e1553eSJérôme Duval 18421e1553eSJérôme Duval 18521e1553eSJérôme Duval static status_t 186f0c050f6SAxel Dörfler fs_unmount(fs_volume* _volume) 18721e1553eSJérôme Duval { 18821e1553eSJérôme Duval status_t result = B_NO_ERROR; 189f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 19021e1553eSJérôme Duval 19121e1553eSJérôme Duval TRACE(("fs_unmount - ENTER\n")); 19221e1553eSJérôme Duval 1939d254f45SJérôme Duval // Unlike in BeOS, we need to put the reference to our root node ourselves 194f0c050f6SAxel Dörfler put_vnode(_volume, ISO_ROOTNODE_ID); 1959d254f45SJérôme Duval 196f0c050f6SAxel Dörfler block_cache_delete(volume->fBlockCache, false); 197f0c050f6SAxel Dörfler close(volume->fdOfSession); 198f0c050f6SAxel Dörfler result = close(volume->fd); 19921e1553eSJérôme Duval 200f0c050f6SAxel Dörfler free(volume); 20121e1553eSJérôme Duval 20221e1553eSJérôme Duval TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result))); 20321e1553eSJérôme Duval return result; 20421e1553eSJérôme Duval } 20521e1553eSJérôme Duval 20621e1553eSJérôme Duval 20721e1553eSJérôme Duval static status_t 208f0c050f6SAxel Dörfler fs_read_fs_stat(fs_volume* _volume, struct fs_info* info) 20921e1553eSJérôme Duval { 210f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 211f0c050f6SAxel Dörfler 212f0c050f6SAxel Dörfler info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 213f0c050f6SAxel Dörfler info->block_size = volume->logicalBlkSize[FS_DATA_FORMAT]; 214f0c050f6SAxel Dörfler info->io_size = 65536; 215f0c050f6SAxel Dörfler info->total_blocks = volume->volSpaceSize[FS_DATA_FORMAT]; 216f0c050f6SAxel Dörfler info->free_blocks = 0; 217f0c050f6SAxel Dörfler 218f0c050f6SAxel Dörfler strlcpy(info->device_name, volume->devicePath, sizeof(info->device_name)); 219f0c050f6SAxel Dörfler strlcpy(info->volume_name, volume->volIDString, sizeof(info->volume_name)); 220f0c050f6SAxel Dörfler 221f0c050f6SAxel Dörfler // strip trailing spaces 22221e1553eSJérôme Duval int i; 223f0c050f6SAxel Dörfler for (i = strlen(info->volume_name) - 1; i >=0 ; i--) { 224f0c050f6SAxel Dörfler if (info->volume_name[i] != ' ') 22521e1553eSJérôme Duval break; 226ff99132eSAxel Dörfler } 22721e1553eSJérôme Duval 22821e1553eSJérôme Duval if (i < 0) 229f0c050f6SAxel Dörfler strcpy(info->volume_name, "UNKNOWN"); 23021e1553eSJérôme Duval else 231f0c050f6SAxel Dörfler info->volume_name[i + 1] = 0; 23221e1553eSJérôme Duval 233f0c050f6SAxel Dörfler strcpy(info->fsh_name, "iso9660"); 234ff99132eSAxel Dörfler return B_OK; 23521e1553eSJérôme Duval } 23621e1553eSJérôme Duval 2373b723f79SJérôme Duval 2383b723f79SJérôme Duval static status_t 239f0c050f6SAxel Dörfler fs_get_vnode_name(fs_volume* _volume, fs_vnode* _node, char* buffer, 240f0c050f6SAxel Dörfler size_t bufferSize) 2413b723f79SJérôme Duval { 242eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 2433b723f79SJérôme Duval 244eb097431SAxel Dörfler strlcpy(buffer, node->name, bufferSize); 2453b723f79SJérôme Duval return B_OK; 2463b723f79SJérôme Duval } 2473b723f79SJérôme Duval 2483b723f79SJérôme Duval 24921e1553eSJérôme Duval static status_t 250f0c050f6SAxel Dörfler fs_walk(fs_volume* _volume, fs_vnode* _base, const char* file, ino_t* _vnodeID) 25121e1553eSJérôme Duval { 252f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 253eb097431SAxel Dörfler iso9660_inode* baseNode = (iso9660_inode*)_base->private_node; 254eb097431SAxel Dörfler iso9660_inode* newNode = NULL; 25521e1553eSJérôme Duval 25699d1bfb5SAxel Dörfler TRACE(("fs_walk - looking for %s in dir file of length %d\n", file, 25799d1bfb5SAxel Dörfler (int)baseNode->dataLen[FS_DATA_FORMAT])); 25821e1553eSJérôme Duval 25921e1553eSJérôme Duval if (strcmp(file, ".") == 0) { 26021e1553eSJérôme Duval // base directory 26121e1553eSJérôme Duval TRACE(("fs_walk - found \".\" file.\n")); 26221e1553eSJérôme Duval *_vnodeID = baseNode->id; 263f0c050f6SAxel Dörfler return get_vnode(_volume, *_vnodeID, NULL); 26421e1553eSJérôme Duval } else if (strcmp(file, "..") == 0) { 26521e1553eSJérôme Duval // parent directory 26621e1553eSJérôme Duval TRACE(("fs_walk - found \"..\" file.\n")); 26721e1553eSJérôme Duval *_vnodeID = baseNode->parID; 268f0c050f6SAxel Dörfler return get_vnode(_volume, *_vnodeID, NULL); 269ff99132eSAxel Dörfler } 270ff99132eSAxel Dörfler 27121e1553eSJérôme Duval // look up file in the directory 272ff99132eSAxel Dörfler uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT]; 273ff99132eSAxel Dörfler status_t result = ENOENT; 274eb097431SAxel Dörfler size_t totalRead = 0; 275ff99132eSAxel Dörfler off_t block = baseNode->startLBN[FS_DATA_FORMAT]; 276ff99132eSAxel Dörfler bool done = false; 27721e1553eSJérôme Duval 278ff99132eSAxel Dörfler while (totalRead < dataLength && !done) { 27921e1553eSJérôme Duval off_t cachedBlock = block; 280f0c050f6SAxel Dörfler char* blockData = (char*)block_cache_get(volume->fBlockCache, block); 2812a64cb11SAxel Dörfler if (blockData == NULL) 2822a64cb11SAxel Dörfler break; 2832a64cb11SAxel Dörfler 284eb097431SAxel Dörfler size_t bytesRead = 0; 28521e1553eSJérôme Duval off_t blockBytesRead = 0; 286eb097431SAxel Dörfler iso9660_inode node; 28721e1553eSJérôme Duval int initResult; 28821e1553eSJérôme Duval 289eb097431SAxel Dörfler TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer " 290eb097431SAxel Dörfler "%p.\n", block, blockData)); 29121e1553eSJérôme Duval 2922a64cb11SAxel Dörfler // Move to the next block if necessary 29321e1553eSJérôme Duval // Don't go over end of buffer, if dir record sits on boundary. 29421e1553eSJérôme Duval 295f0c050f6SAxel Dörfler while (blockBytesRead < volume->logicalBlkSize[FS_DATA_FORMAT] 296ff99132eSAxel Dörfler && totalRead + blockBytesRead < dataLength 29721e1553eSJérôme Duval && blockData[0] != 0 298ff99132eSAxel Dörfler && !done) { 299f0c050f6SAxel Dörfler initResult = InitNode(volume, &node, blockData, &bytesRead); 30099d1bfb5SAxel Dörfler TRACE(("fs_walk - InitNode returned %s, filename %s, %u bytes " 30199d1bfb5SAxel Dörfler "read\n", strerror(initResult), node.name, (unsigned)bytesRead)); 30221e1553eSJérôme Duval 303ff99132eSAxel Dörfler if (initResult == B_OK) { 30499d1bfb5SAxel Dörfler if ((node.flags & ISO_IS_ASSOCIATED_FILE) == 0 30599d1bfb5SAxel Dörfler && !strcmp(node.name, file)) { 3062a64cb11SAxel Dörfler TRACE(("fs_walk - success, found vnode at block %Ld, pos " 3072a64cb11SAxel Dörfler "%Ld\n", block, blockBytesRead)); 3082a64cb11SAxel Dörfler 3092a64cb11SAxel Dörfler *_vnodeID = (block << 30) + (blockBytesRead & 0xffffffff); 31021e1553eSJérôme Duval TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID)); 31121e1553eSJérôme Duval 312f0c050f6SAxel Dörfler result = get_vnode(_volume, *_vnodeID, (void**)&newNode); 313ff99132eSAxel Dörfler if (result == B_OK) { 31421e1553eSJérôme Duval newNode->parID = baseNode->id; 315ff99132eSAxel Dörfler done = true; 31621e1553eSJérôme Duval } 31721e1553eSJérôme Duval } else { 318eb097431SAxel Dörfler free(node.name); 31921e1553eSJérôme Duval free(node.attr.slName); 32021e1553eSJérôme Duval } 32121e1553eSJérôme Duval } else { 32221e1553eSJérôme Duval result = initResult; 32321e1553eSJérôme Duval if (bytesRead == 0) 324f47bff08SAxel Dörfler done = true; 32521e1553eSJérôme Duval } 32621e1553eSJérôme Duval blockData += bytesRead; 32721e1553eSJérôme Duval blockBytesRead += bytesRead; 32821e1553eSJérôme Duval 32999d1bfb5SAxel Dörfler TRACE(("fs_walk - Adding %u bytes to blockBytes read (total " 33099d1bfb5SAxel Dörfler "%Ld/%u).\n", (unsigned)bytesRead, blockBytesRead, 33199d1bfb5SAxel Dörfler (unsigned)baseNode->dataLen[FS_DATA_FORMAT])); 33221e1553eSJérôme Duval } 333f0c050f6SAxel Dörfler totalRead += volume->logicalBlkSize[FS_DATA_FORMAT]; 33421e1553eSJérôme Duval block++; 33521e1553eSJérôme Duval 33699d1bfb5SAxel Dörfler TRACE(("fs_walk - moving to next block %Ld, total read %u\n", 33799d1bfb5SAxel Dörfler block, (unsigned)totalRead)); 338f0c050f6SAxel Dörfler block_cache_put(volume->fBlockCache, cachedBlock); 33921e1553eSJérôme Duval } 34021e1553eSJérôme Duval 341ff99132eSAxel Dörfler TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", 342ff99132eSAxel Dörfler strerror(result), *_vnodeID)); 34321e1553eSJérôme Duval return result; 34421e1553eSJérôme Duval } 34521e1553eSJérôme Duval 34621e1553eSJérôme Duval 34721e1553eSJérôme Duval static status_t 348f0c050f6SAxel Dörfler fs_read_vnode(fs_volume* _volume, ino_t vnodeID, fs_vnode* _node, 3490eaadd30SMichael Lotz int* _type, uint32* _flags, bool reenter) 35021e1553eSJérôme Duval { 351f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 352ff99132eSAxel Dörfler 353eb097431SAxel Dörfler iso9660_inode* newNode = (iso9660_inode*)calloc(sizeof(iso9660_inode), 1); 354ff99132eSAxel Dörfler if (newNode == NULL) 355ff99132eSAxel Dörfler return B_NO_MEMORY; 35621e1553eSJérôme Duval 357ff99132eSAxel Dörfler uint32 pos = vnodeID & 0x3fffffff; 358ff99132eSAxel Dörfler uint32 block = vnodeID >> 30; 35921e1553eSJérôme Duval 36099d1bfb5SAxel Dörfler TRACE(("fs_read_vnode - block = %u, pos = %u, raw = %Lu node %p\n", 36199d1bfb5SAxel Dörfler (unsigned)block, (unsigned) pos, vnodeID, newNode)); 36221e1553eSJérôme Duval 363f0c050f6SAxel Dörfler if (pos > volume->logicalBlkSize[FS_DATA_FORMAT]) { 364d02cde30SMichael Lotz free(newNode); 365ff99132eSAxel Dörfler return B_BAD_VALUE; 366d02cde30SMichael Lotz } 36721e1553eSJérôme Duval 368f0c050f6SAxel Dörfler char* data = (char*)block_cache_get(volume->fBlockCache, block); 369ff99132eSAxel Dörfler if (data == NULL) { 370ff99132eSAxel Dörfler free(newNode); 371ff99132eSAxel Dörfler return B_IO_ERROR; 372ff99132eSAxel Dörfler } 37321e1553eSJérôme Duval 374f0c050f6SAxel Dörfler status_t result = InitNode(volume, newNode, data + pos, NULL); 375f0c050f6SAxel Dörfler block_cache_put(volume->fBlockCache, block); 37621e1553eSJérôme Duval 377ff99132eSAxel Dörfler if (result < B_OK) { 378ff99132eSAxel Dörfler free(newNode); 379ff99132eSAxel Dörfler return result; 38021e1553eSJérôme Duval } 38121e1553eSJérôme Duval 382*41b19806SAxel Dörfler newNode->volume = volume; 383ff99132eSAxel Dörfler newNode->id = vnodeID; 384*41b19806SAxel Dörfler 3850eaadd30SMichael Lotz _node->private_node = newNode; 3860eaadd30SMichael Lotz _node->ops = &gISO9660VnodeOps; 38799d1bfb5SAxel Dörfler *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode 38899d1bfb5SAxel Dörfler & ~(S_IWUSR | S_IWGRP | S_IWOTH); 389a26c2439SMichael Lotz *_flags = 0; 390ff99132eSAxel Dörfler 39147a214deSAxel Dörfler if ((newNode->flags & ISO_IS_DIR) == 0) { 392f0c050f6SAxel Dörfler newNode->cache = file_cache_create(volume->id, vnodeID, 3933d268edaSAxel Dörfler newNode->dataLen[FS_DATA_FORMAT]); 3945b4cb109SJérôme Duval } 3955b4cb109SJérôme Duval 396ff99132eSAxel Dörfler return B_OK; 39721e1553eSJérôme Duval } 39821e1553eSJérôme Duval 39921e1553eSJérôme Duval 40021e1553eSJérôme Duval static status_t 401eb097431SAxel Dörfler fs_release_vnode(fs_volume* /*_volume*/, fs_vnode* _node, bool /*reenter*/) 40221e1553eSJérôme Duval { 403eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 40421e1553eSJérôme Duval 405eb097431SAxel Dörfler TRACE(("fs_release_vnode - ENTER (%p)\n", node)); 40621e1553eSJérôme Duval 40721e1553eSJérôme Duval if (node->id != ISO_ROOTNODE_ID) { 408eb097431SAxel Dörfler free(node->name); 40921e1553eSJérôme Duval free(node->attr.slName); 410eb097431SAxel Dörfler 4115b4cb109SJérôme Duval if (node->cache != NULL) 4125b4cb109SJérôme Duval file_cache_delete(node->cache); 41321e1553eSJérôme Duval 41421e1553eSJérôme Duval free(node); 41521e1553eSJérôme Duval } 41621e1553eSJérôme Duval 4175b4cb109SJérôme Duval TRACE(("fs_release_vnode - EXIT\n")); 418eb097431SAxel Dörfler return B_OK; 41921e1553eSJérôme Duval } 42021e1553eSJérôme Duval 42121e1553eSJérôme Duval 42221e1553eSJérôme Duval static status_t 423f0c050f6SAxel Dörfler fs_read_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos, 424e6bd90c5SIngo Weinhold const iovec* vecs, size_t count, size_t* _numBytes) 4255b4cb109SJérôme Duval { 426f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 427eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 4285b4cb109SJérôme Duval 429ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 430ff99132eSAxel Dörfler size_t bytesLeft = *_numBytes; 4315b4cb109SJérôme Duval 432ff99132eSAxel Dörfler if (pos >= fileSize) { 433ff99132eSAxel Dörfler *_numBytes = 0; 4345b4cb109SJérôme Duval return B_OK; 4355b4cb109SJérôme Duval } 436ff99132eSAxel Dörfler if (pos + bytesLeft > fileSize) { 437ff99132eSAxel Dörfler bytesLeft = fileSize - pos; 438ff99132eSAxel Dörfler *_numBytes = bytesLeft; 4395b4cb109SJérôme Duval } 4405b4cb109SJérôme Duval 441ff99132eSAxel Dörfler file_io_vec fileVec; 442ff99132eSAxel Dörfler fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT] 443f0c050f6SAxel Dörfler * volume->logicalBlkSize[FS_DATA_FORMAT]; 444ff99132eSAxel Dörfler fileVec.length = bytesLeft; 4455b4cb109SJérôme Duval 446ff99132eSAxel Dörfler uint32 vecIndex = 0; 447ff99132eSAxel Dörfler size_t vecOffset = 0; 448f0c050f6SAxel Dörfler return read_file_io_vec_pages(volume->fd, &fileVec, 1, vecs, count, 449ff99132eSAxel Dörfler &vecIndex, &vecOffset, &bytesLeft); 4505b4cb109SJérôme Duval } 4515b4cb109SJérôme Duval 4525b4cb109SJérôme Duval 4535b4cb109SJérôme Duval static status_t 454*41b19806SAxel Dörfler fs_io(fs_volume* _volume, fs_vnode* _node, void* _cookie, io_request* request) 455*41b19806SAxel Dörfler { 456*41b19806SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 457*41b19806SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 458*41b19806SAxel Dörfler 459*41b19806SAxel Dörfler if (io_request_is_write(request)) 460*41b19806SAxel Dörfler return B_READ_ONLY_DEVICE; 461*41b19806SAxel Dörfler 462*41b19806SAxel Dörfler if ((node->flags & ISO_IS_DIR) != 0) 463*41b19806SAxel Dörfler return EISDIR; 464*41b19806SAxel Dörfler 465*41b19806SAxel Dörfler return do_iterative_fd_io(volume->fd, request, iterative_io_get_vecs_hook, 466*41b19806SAxel Dörfler iterative_io_finished_hook, node); 467*41b19806SAxel Dörfler } 468*41b19806SAxel Dörfler 469*41b19806SAxel Dörfler 470*41b19806SAxel Dörfler static status_t 471f0c050f6SAxel Dörfler fs_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* st) 47221e1553eSJérôme Duval { 473f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 474eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 4753b723f79SJérôme Duval status_t result = B_NO_ERROR; 47621e1553eSJérôme Duval time_t time; 47721e1553eSJérôme Duval 4783b723f79SJérôme Duval TRACE(("fs_read_stat - ENTER\n")); 47921e1553eSJérôme Duval 480f0c050f6SAxel Dörfler st->st_dev = volume->id; 48121e1553eSJérôme Duval st->st_ino = node->id; 48221e1553eSJérôme Duval st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink; 48321e1553eSJérôme Duval st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid; 48421e1553eSJérôme Duval st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid; 48521e1553eSJérôme Duval st->st_blksize = 65536; 48621e1553eSJérôme Duval st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode; 48721e1553eSJérôme Duval 48821e1553eSJérôme Duval // Same for file/dir in ISO9660 48921e1553eSJérôme Duval st->st_size = node->dataLen[FS_DATA_FORMAT]; 4902c348abbSAxel Dörfler st->st_blocks = (st->st_size + 511) / 512; 49121e1553eSJérôme Duval if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR) 49221e1553eSJérôme Duval st->st_ctime = st->st_mtime = st->st_atime = time; 49321e1553eSJérôme Duval 4943b723f79SJérôme Duval TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result))); 49521e1553eSJérôme Duval 49621e1553eSJérôme Duval return result; 49721e1553eSJérôme Duval } 49821e1553eSJérôme Duval 49921e1553eSJérôme Duval 50021e1553eSJérôme Duval static status_t 501f0c050f6SAxel Dörfler fs_open(fs_volume* /*_volume*/, fs_vnode* _node, int openMode, void** /*cookie*/) 50221e1553eSJérôme Duval { 50321e1553eSJérôme Duval // Do not allow any of the write-like open modes to get by 504f0c050f6SAxel Dörfler if ((openMode & O_RWMASK) == O_WRONLY || (openMode & O_RWMASK) == O_RDWR 505f0c050f6SAxel Dörfler || (openMode & O_TRUNC) != 0 || (openMode & O_CREAT) != 0) 506f0c050f6SAxel Dörfler return EROFS; 50721e1553eSJérôme Duval 508f0c050f6SAxel Dörfler return B_OK; 50921e1553eSJérôme Duval } 51021e1553eSJérôme Duval 51121e1553eSJérôme Duval 51221e1553eSJérôme Duval static status_t 513f0c050f6SAxel Dörfler fs_read(fs_volume* _volume, fs_vnode* _node, void* cookie, off_t pos, 514f0c050f6SAxel Dörfler void* buffer, size_t* _length) 51521e1553eSJérôme Duval { 516eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 51721e1553eSJérôme Duval 51847a214deSAxel Dörfler if ((node->flags & ISO_IS_DIR) != 0) 51921e1553eSJérôme Duval return EISDIR; 52021e1553eSJérôme Duval 521ff99132eSAxel Dörfler uint32 fileSize = node->dataLen[FS_DATA_FORMAT]; 5225b4cb109SJérôme Duval 5235b4cb109SJérôme Duval // set/check boundaries for pos/length 524ff99132eSAxel Dörfler if (pos < 0) 5255b4cb109SJérôme Duval return B_BAD_VALUE; 526ff99132eSAxel Dörfler if (pos >= fileSize) { 527ff99132eSAxel Dörfler *_length = 0; 5285b4cb109SJérôme Duval return B_OK; 5295b4cb109SJérôme Duval } 530ff99132eSAxel Dörfler 531ff99132eSAxel Dörfler return file_cache_read(node->cache, NULL, pos, buffer, _length); 53221e1553eSJérôme Duval } 53321e1553eSJérôme Duval 53421e1553eSJérôme Duval 53521e1553eSJérôme Duval static status_t 536f0c050f6SAxel Dörfler fs_close(fs_volume* /*_volume*/, fs_vnode* /*_node*/, void* /*cookie*/) 53721e1553eSJérôme Duval { 53821e1553eSJérôme Duval return B_OK; 53921e1553eSJérôme Duval } 54021e1553eSJérôme Duval 541ff99132eSAxel Dörfler 54221e1553eSJérôme Duval static status_t 543f0c050f6SAxel Dörfler fs_free_cookie(fs_volume* /*_volume*/, fs_vnode* /*_node*/, void* /*cookie*/) 54421e1553eSJérôme Duval { 54521e1553eSJérôme Duval return B_OK; 54621e1553eSJérôme Duval } 54721e1553eSJérôme Duval 548ff99132eSAxel Dörfler 54921e1553eSJérôme Duval static status_t 550f0c050f6SAxel Dörfler fs_access(fs_volume* /*_volume*/, fs_vnode* /*_node*/, int /*mode*/) 55121e1553eSJérôme Duval { 55221e1553eSJérôme Duval return B_OK; 55321e1553eSJérôme Duval } 55421e1553eSJérôme Duval 555ff99132eSAxel Dörfler 55621e1553eSJérôme Duval static status_t 557f0c050f6SAxel Dörfler fs_read_link(fs_volume* _volume, fs_vnode* _node, char* buffer, 558f0c050f6SAxel Dörfler size_t* _bufferSize) 55921e1553eSJérôme Duval { 560eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 56121e1553eSJérôme Duval 562ff99132eSAxel Dörfler if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) 563ff99132eSAxel Dörfler return B_BAD_VALUE; 56421e1553eSJérôme Duval 56521e1553eSJérôme Duval size_t length = strlen(node->attr.slName); 56621e1553eSJérôme Duval if (length > *_bufferSize) 5673b723f79SJérôme Duval memcpy(buffer, node->attr.slName, *_bufferSize); 5683b723f79SJérôme Duval else { 56921e1553eSJérôme Duval memcpy(buffer, node->attr.slName, length); 5703b723f79SJérôme Duval *_bufferSize = length; 5713b723f79SJérôme Duval } 57221e1553eSJérôme Duval 573ff99132eSAxel Dörfler return B_OK; 57421e1553eSJérôme Duval } 57521e1553eSJérôme Duval 57621e1553eSJérôme Duval 57721e1553eSJérôme Duval static status_t 578eb097431SAxel Dörfler fs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie) 57921e1553eSJérôme Duval { 580eb097431SAxel Dörfler iso9660_inode* node = (iso9660_inode*)_node->private_node; 58121e1553eSJérôme Duval 582eb097431SAxel Dörfler TRACE(("fs_open_dir - node is %p\n", node)); 58321e1553eSJérôme Duval 58447a214deSAxel Dörfler if ((node->flags & ISO_IS_DIR) == 0) 585ff99132eSAxel Dörfler return B_NOT_A_DIRECTORY; 58621e1553eSJérôme Duval 587ff99132eSAxel Dörfler dircookie* dirCookie = (dircookie*)malloc(sizeof(dircookie)); 588ff99132eSAxel Dörfler if (dirCookie == NULL) 589ff99132eSAxel Dörfler return B_NO_MEMORY; 590ff99132eSAxel Dörfler 59121e1553eSJérôme Duval dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT]; 59221e1553eSJérôme Duval dirCookie->block = node->startLBN[FS_DATA_FORMAT]; 59321e1553eSJérôme Duval dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT]; 59421e1553eSJérôme Duval dirCookie->pos = 0; 59521e1553eSJérôme Duval dirCookie->id = node->id; 596eb097431SAxel Dörfler *_cookie = (void*)dirCookie; 59721e1553eSJérôme Duval 598ff99132eSAxel Dörfler return B_OK; 59921e1553eSJérôme Duval } 60021e1553eSJérôme Duval 60121e1553eSJérôme Duval 60221e1553eSJérôme Duval static status_t 603f0c050f6SAxel Dörfler fs_read_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie, 60444d0dbc8SAxel Dörfler struct dirent* buffer, size_t bufferSize, uint32* num) 60521e1553eSJérôme Duval { 606f0c050f6SAxel Dörfler iso9660_volume* volume = (iso9660_volume*)_volume->private_volume; 60721e1553eSJérôme Duval dircookie* dirCookie = (dircookie*)_cookie; 60821e1553eSJérôme Duval 6095b4cb109SJérôme Duval TRACE(("fs_read_dir - ENTER\n")); 61021e1553eSJérôme Duval 611f0c050f6SAxel Dörfler status_t result = ISOReadDirEnt(volume, dirCookie, buffer, bufferSize); 61221e1553eSJérôme Duval 61321e1553eSJérôme Duval // If we succeeded, return 1, the number of dirents we read. 614ff99132eSAxel Dörfler if (result == B_OK) 61521e1553eSJérôme Duval *num = 1; 61621e1553eSJérôme Duval else 61721e1553eSJérôme Duval *num = 0; 61821e1553eSJérôme Duval 61921e1553eSJérôme Duval // When you get to the end, don't return an error, just return 62021e1553eSJérôme Duval // a zero in *num. 62121e1553eSJérôme Duval 622eb097431SAxel Dörfler if (result == B_ENTRY_NOT_FOUND) 623ff99132eSAxel Dörfler result = B_OK; 62421e1553eSJérôme Duval 6255b4cb109SJérôme Duval TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result))); 62621e1553eSJérôme Duval return result; 62721e1553eSJérôme Duval } 62821e1553eSJérôme Duval 62921e1553eSJérôme Duval 63021e1553eSJérôme Duval static status_t 631f0c050f6SAxel Dörfler fs_rewind_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie) 63221e1553eSJérôme Duval { 63321e1553eSJérôme Duval dircookie* cookie = (dircookie*)_cookie; 63421e1553eSJérôme Duval 63521e1553eSJérôme Duval cookie->block = cookie->startBlock; 63621e1553eSJérôme Duval cookie->pos = 0; 637ff99132eSAxel Dörfler return B_OK; 63821e1553eSJérôme Duval } 63921e1553eSJérôme Duval 64021e1553eSJérôme Duval 64121e1553eSJérôme Duval static status_t 642f0c050f6SAxel Dörfler fs_close_dir(fs_volume* _volume, fs_vnode* _node, void* cookie) 64321e1553eSJérôme Duval { 64421e1553eSJérôme Duval return B_OK; 64521e1553eSJérôme Duval } 64621e1553eSJérôme Duval 64721e1553eSJérôme Duval 64821e1553eSJérôme Duval static status_t 649f0c050f6SAxel Dörfler fs_free_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* cookie) 65021e1553eSJérôme Duval { 65121e1553eSJérôme Duval free(cookie); 65221e1553eSJérôme Duval return B_OK; 65321e1553eSJérôme Duval } 65421e1553eSJérôme Duval 655ff99132eSAxel Dörfler 65621e1553eSJérôme Duval // #pragma mark - 65721e1553eSJérôme Duval 65821e1553eSJérôme Duval 65921e1553eSJérôme Duval static status_t 66021e1553eSJérôme Duval iso_std_ops(int32 op, ...) 66121e1553eSJérôme Duval { 66221e1553eSJérôme Duval switch (op) { 66321e1553eSJérôme Duval case B_MODULE_INIT: 66421e1553eSJérôme Duval case B_MODULE_UNINIT: 66521e1553eSJérôme Duval return B_OK; 66621e1553eSJérôme Duval default: 66721e1553eSJérôme Duval return B_ERROR; 66821e1553eSJérôme Duval } 66921e1553eSJérôme Duval } 67021e1553eSJérôme Duval 67121e1553eSJérôme Duval 6720eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = { 6730eaadd30SMichael Lotz &fs_unmount, 6740eaadd30SMichael Lotz &fs_read_fs_stat, 6750eaadd30SMichael Lotz NULL, 6760eaadd30SMichael Lotz NULL, 6770eaadd30SMichael Lotz &fs_read_vnode, 6780eaadd30SMichael Lotz 6790eaadd30SMichael Lotz /* index and index directory ops */ 6800eaadd30SMichael Lotz NULL, 6810eaadd30SMichael Lotz NULL, 6820eaadd30SMichael Lotz NULL, 6830eaadd30SMichael Lotz NULL, 6840eaadd30SMichael Lotz NULL, 6850eaadd30SMichael Lotz NULL, 6860eaadd30SMichael Lotz NULL, 6870eaadd30SMichael Lotz NULL, 6880eaadd30SMichael Lotz 6890eaadd30SMichael Lotz /* query ops */ 6900eaadd30SMichael Lotz NULL, 6910eaadd30SMichael Lotz NULL, 6920eaadd30SMichael Lotz NULL, 6930eaadd30SMichael Lotz NULL, 6940eaadd30SMichael Lotz NULL, 6950eaadd30SMichael Lotz 6960eaadd30SMichael Lotz /* FS layer ops */ 6970eaadd30SMichael Lotz NULL, 6980eaadd30SMichael Lotz NULL, 6990eaadd30SMichael Lotz }; 7000eaadd30SMichael Lotz 7010eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = { 7020eaadd30SMichael Lotz &fs_walk, 7030eaadd30SMichael Lotz &fs_get_vnode_name, 7040eaadd30SMichael Lotz &fs_release_vnode, 7050eaadd30SMichael Lotz NULL, 7060eaadd30SMichael Lotz 7070eaadd30SMichael Lotz /* vm-related ops */ 7080eaadd30SMichael Lotz NULL, 7090eaadd30SMichael Lotz &fs_read_pages, 7100eaadd30SMichael Lotz NULL, 7110eaadd30SMichael Lotz 712*41b19806SAxel Dörfler &fs_io, 713ec598fe4SIngo Weinhold NULL, // cancel_io() 714ec598fe4SIngo Weinhold 7150eaadd30SMichael Lotz /* cache file access */ 7160eaadd30SMichael Lotz NULL, 7170eaadd30SMichael Lotz 7180eaadd30SMichael Lotz /* common */ 7190eaadd30SMichael Lotz NULL, 7200eaadd30SMichael Lotz NULL, 7210eaadd30SMichael Lotz NULL, 7220eaadd30SMichael Lotz NULL, 7230eaadd30SMichael Lotz NULL, 7240eaadd30SMichael Lotz &fs_read_link, 7250eaadd30SMichael Lotz NULL, 7260eaadd30SMichael Lotz NULL, 7270eaadd30SMichael Lotz NULL, 7280eaadd30SMichael Lotz NULL, 7290eaadd30SMichael Lotz &fs_access, 7300eaadd30SMichael Lotz &fs_read_stat, 7310eaadd30SMichael Lotz NULL, 7320eaadd30SMichael Lotz 7330eaadd30SMichael Lotz /* file */ 7340eaadd30SMichael Lotz NULL, 7350eaadd30SMichael Lotz &fs_open, 7360eaadd30SMichael Lotz &fs_close, 7370eaadd30SMichael Lotz &fs_free_cookie, 7380eaadd30SMichael Lotz &fs_read, 7390eaadd30SMichael Lotz NULL, 7400eaadd30SMichael Lotz 7410eaadd30SMichael Lotz /* dir */ 7420eaadd30SMichael Lotz NULL, 7430eaadd30SMichael Lotz NULL, 7440eaadd30SMichael Lotz &fs_open_dir, 7450eaadd30SMichael Lotz &fs_close_dir, 7460eaadd30SMichael Lotz &fs_free_dir_cookie, 7470eaadd30SMichael Lotz &fs_read_dir, 7480eaadd30SMichael Lotz &fs_rewind_dir, 7490eaadd30SMichael Lotz 7500eaadd30SMichael Lotz /* attribute directory ops */ 7510eaadd30SMichael Lotz NULL, 7520eaadd30SMichael Lotz NULL, 7530eaadd30SMichael Lotz NULL, 7540eaadd30SMichael Lotz NULL, 7550eaadd30SMichael Lotz NULL, 7560eaadd30SMichael Lotz 7570eaadd30SMichael Lotz /* attribute ops */ 7580eaadd30SMichael Lotz NULL, 7590eaadd30SMichael Lotz NULL, 7600eaadd30SMichael Lotz NULL, 7610eaadd30SMichael Lotz NULL, 7620eaadd30SMichael Lotz NULL, 7630eaadd30SMichael Lotz NULL, 7640eaadd30SMichael Lotz NULL, 7650eaadd30SMichael Lotz NULL, 7660eaadd30SMichael Lotz NULL, 7670eaadd30SMichael Lotz NULL, 7680eaadd30SMichael Lotz 7690eaadd30SMichael Lotz /* node and FS layer support */ 7700eaadd30SMichael Lotz NULL, 7710eaadd30SMichael Lotz NULL, 7720eaadd30SMichael Lotz }; 7730eaadd30SMichael Lotz 77421e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = { 77521e1553eSJérôme Duval { 77621e1553eSJérôme Duval "file_systems/iso9660" B_CURRENT_FS_API_VERSION, 77721e1553eSJérôme Duval 0, 77821e1553eSJérôme Duval iso_std_ops, 77921e1553eSJérôme Duval }, 78021e1553eSJérôme Duval 7811da9f5ceSAxel Dörfler "iso9660", // short_name 7821da9f5ceSAxel Dörfler "ISO9660 File System", // pretty_name 78376a8ec23SIngo Weinhold 0, // DDM flags 78421e1553eSJérôme Duval 78521e1553eSJérôme Duval // scanning 78621e1553eSJérôme Duval fs_identify_partition, 78721e1553eSJérôme Duval fs_scan_partition, 78821e1553eSJérôme Duval fs_free_identify_partition_cookie, 78921e1553eSJérôme Duval NULL, // free_partition_content_cookie() 79021e1553eSJérôme Duval 79121e1553eSJérôme Duval &fs_mount, 7920eaadd30SMichael Lotz 7930eaadd30SMichael Lotz /* capability querying */ 7940eaadd30SMichael Lotz NULL, 7950eaadd30SMichael Lotz NULL, 7960eaadd30SMichael Lotz NULL, 7970eaadd30SMichael Lotz NULL, 79821e1553eSJérôme Duval NULL, 79921e1553eSJérôme Duval NULL, 80021e1553eSJérôme Duval 8010eaadd30SMichael Lotz /* shadow partition modifications */ 8020eaadd30SMichael Lotz NULL, 80321e1553eSJérôme Duval 8040eaadd30SMichael Lotz /* writing */ 8050eaadd30SMichael Lotz NULL, 8060eaadd30SMichael Lotz NULL, 8070eaadd30SMichael Lotz NULL, 8080eaadd30SMichael Lotz NULL, 8090eaadd30SMichael Lotz NULL, 8100eaadd30SMichael Lotz NULL, 8110eaadd30SMichael Lotz NULL, 81221e1553eSJérôme Duval }; 81321e1553eSJérôme Duval 81421e1553eSJérôme Duval module_info* modules[] = { 81521e1553eSJérôme Duval (module_info*)&sISO660FileSystem, 81621e1553eSJérôme Duval NULL, 81721e1553eSJérôme Duval }; 81821e1553eSJérôme Duval 819