xref: /haiku/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp (revision e6bd90c58dbae64f3b464edcff90dcb06e63a716)
121e1553eSJérôme Duval /*
2245aecdaSAxel Dörfler  * Copyright 1999, Be Incorporated.   All Rights Reserved.
3245aecdaSAxel Dörfler  * This file may be used under the terms of the Be Sample Code License.
4245aecdaSAxel Dörfler  *
5245aecdaSAxel Dörfler  * Copyright 2001, pinc Software.  All Rights Reserved.
6245aecdaSAxel Dörfler  *
7245aecdaSAxel Dörfler  * iso9960/multi-session, 1.0.0
821e1553eSJérôme Duval  */
921e1553eSJérôme Duval 
10245aecdaSAxel Dörfler 
1121e1553eSJérôme Duval #include <ctype.h>
1221e1553eSJérôme Duval #include <dirent.h>
135b2c5d03SAxel Dörfler #include <errno.h>
145b2c5d03SAxel Dörfler #include <fcntl.h>
155b2c5d03SAxel Dörfler #include <stdio.h>
165b2c5d03SAxel Dörfler #include <stdlib.h>
175b2c5d03SAxel Dörfler #include <string.h>
1821e1553eSJérôme Duval #include <sys/stat.h>
1921e1553eSJérôme Duval #include <time.h>
205b2c5d03SAxel Dörfler #include <unistd.h>
2121e1553eSJérôme Duval 
2221e1553eSJérôme Duval #include <KernelExport.h>
2321e1553eSJérôme Duval #include <NodeMonitor.h>
2421e1553eSJérôme Duval #include <fs_interface.h>
2521e1553eSJérôme Duval #include <fs_cache.h>
2621e1553eSJérôme Duval 
2721e1553eSJérôme Duval #include <fs_attr.h>
2821e1553eSJérôme Duval #include <fs_info.h>
2921e1553eSJérôme Duval #include <fs_index.h>
3021e1553eSJérôme Duval #include <fs_query.h>
3121e1553eSJérôme Duval #include <fs_volume.h>
3221e1553eSJérôme Duval 
3321e1553eSJérôme Duval #include <util/kernel_cpp.h>
3421e1553eSJérôme Duval 
35dc9a52b9SAxel Dörfler #include "iso9660.h"
365b2c5d03SAxel Dörfler #include "iso9660_identify.h"
375b2c5d03SAxel Dörfler 
385b2c5d03SAxel Dörfler 
395b2c5d03SAxel Dörfler //#define TRACE_ISO9660
405b2c5d03SAxel Dörfler #ifdef TRACE_ISO9660
4121e1553eSJérôme Duval #	define TRACE(x) dprintf x
4221e1553eSJérôme Duval #else
4321e1553eSJérôme Duval #	define TRACE(x) ;
4421e1553eSJérôme Duval #endif
4521e1553eSJérôme Duval 
4621e1553eSJérôme Duval 
4721e1553eSJérôme Duval struct identify_cookie {
4821e1553eSJérôme Duval 	iso9660_info info;
4921e1553eSJérôme Duval };
5021e1553eSJérôme Duval 
510eaadd30SMichael Lotz extern fs_volume_ops gISO9660VolumeOps;
520eaadd30SMichael Lotz extern fs_vnode_ops gISO9660VnodeOps;
530eaadd30SMichael Lotz 
5421e1553eSJérôme Duval 
555b2c5d03SAxel Dörfler //	#pragma mark - Scanning
565b2c5d03SAxel Dörfler 
575b2c5d03SAxel Dörfler 
5821e1553eSJérôme Duval static float
5921e1553eSJérôme Duval fs_identify_partition(int fd, partition_data *partition, void **_cookie)
6021e1553eSJérôme Duval {
615b2c5d03SAxel Dörfler 	iso9660_info *info = new iso9660_info;
6221e1553eSJérôme Duval 
635b2c5d03SAxel Dörfler 	status_t status = iso9660_fs_identify(fd, info);
645b2c5d03SAxel Dörfler 	if (status != B_OK) {
655b2c5d03SAxel Dörfler 		delete info;
665b2c5d03SAxel Dörfler 		return -1;
675b2c5d03SAxel Dörfler 	}
6821e1553eSJérôme Duval 
695b2c5d03SAxel Dörfler 	*_cookie = info;
705b2c5d03SAxel Dörfler 	return 0.6f;
7121e1553eSJérôme Duval }
7221e1553eSJérôme Duval 
7321e1553eSJérôme Duval 
7421e1553eSJérôme Duval static status_t
7521e1553eSJérôme Duval fs_scan_partition(int fd, partition_data *partition, void *_cookie)
7621e1553eSJérôme Duval {
775b2c5d03SAxel Dörfler 	iso9660_info *info = (iso9660_info *)_cookie;
7821e1553eSJérôme Duval 
7921e1553eSJérôme Duval 	partition->status = B_PARTITION_VALID;
8021e1553eSJérôme Duval 	partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ;
8121e1553eSJérôme Duval 	partition->block_size = ISO_PVD_SIZE;
825b2c5d03SAxel Dörfler 	partition->content_size = ISO_PVD_SIZE * info->max_blocks;
835b2c5d03SAxel Dörfler 	partition->content_name = strdup(info->PreferredName());
845b2c5d03SAxel Dörfler 
8521e1553eSJérôme Duval 	if (partition->content_name == NULL)
8621e1553eSJérôme Duval 		return B_NO_MEMORY;
8721e1553eSJérôme Duval 
8821e1553eSJérôme Duval 	return B_OK;
8921e1553eSJérôme Duval }
9021e1553eSJérôme Duval 
9121e1553eSJérôme Duval 
9221e1553eSJérôme Duval static void
9321e1553eSJérôme Duval fs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
9421e1553eSJérôme Duval {
955b2c5d03SAxel Dörfler 	delete (iso9660_info *)_cookie;
9621e1553eSJérôme Duval }
9721e1553eSJérôme Duval 
9821e1553eSJérôme Duval 
99ff99132eSAxel Dörfler //	#pragma mark - FS hooks
100ff99132eSAxel Dörfler 
101ff99132eSAxel Dörfler 
10221e1553eSJérôme Duval static status_t
1030eaadd30SMichael Lotz fs_mount(fs_volume *_volume, const char *device, uint32 flags,
1040eaadd30SMichael Lotz 	const char *args, ino_t *_rootID)
10521e1553eSJérôme Duval {
1065b2c5d03SAxel Dörfler 	bool allowJoliet = true;
107ff99132eSAxel Dörfler 	nspace *volume;
10821e1553eSJérôme Duval 
10921e1553eSJérôme Duval 	// Check for a 'nojoliet' parm
11021e1553eSJérôme Duval 	// all we check for is the existance of 'nojoliet' in the parms.
11121e1553eSJérôme Duval 	if (args != NULL) {
11221e1553eSJérôme Duval 		uint32 i;
11321e1553eSJérôme Duval 		char *spot;
11421e1553eSJérôme Duval 		char *buf = strdup(args);
11521e1553eSJérôme Duval 
11621e1553eSJérôme Duval 		uint32 len = strlen(buf);
11721e1553eSJérôme Duval 		// lower case the parms data
11821e1553eSJérôme Duval 		for (i = 0; i < len + 1; i++)
11921e1553eSJérôme Duval 			buf[i] = tolower(buf[i]);
12021e1553eSJérôme Duval 
12121e1553eSJérôme Duval 		// look for nojoliet
12221e1553eSJérôme Duval 		spot = strstr(buf, "nojoliet");
12321e1553eSJérôme Duval 		if (spot != NULL)
1245b2c5d03SAxel Dörfler 			allowJoliet = false;
12521e1553eSJérôme Duval 
12621e1553eSJérôme Duval 		free(buf);
12721e1553eSJérôme Duval 	}
12821e1553eSJérôme Duval 
12921e1553eSJérôme Duval 	// Try and mount volume as an ISO volume.
130ff99132eSAxel Dörfler 	status_t result = ISOMount(device, O_RDONLY, &volume, allowJoliet);
131ff99132eSAxel Dörfler 	if (result == B_OK) {
13221e1553eSJérôme Duval 		*_rootID = ISO_ROOTNODE_ID;
13321e1553eSJérôme Duval 
1340eaadd30SMichael Lotz 		_volume->private_volume = volume;
1350eaadd30SMichael Lotz 		_volume->ops = &gISO9660VolumeOps;
1360eaadd30SMichael Lotz 		volume->volume = _volume;
1370eaadd30SMichael Lotz 		volume->id = _volume->id;
13821e1553eSJérôme Duval 
1390eaadd30SMichael Lotz 		result = publish_vnode(_volume, *_rootID, &volume->rootDirRec,
1400eaadd30SMichael Lotz 			&gISO9660VnodeOps, volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0);
141ff99132eSAxel Dörfler 		if (result != B_OK) {
142ff99132eSAxel Dörfler 			block_cache_delete(volume->fBlockCache, false);
143ff99132eSAxel Dörfler 			free(volume);
144ff99132eSAxel Dörfler 			result = B_ERROR;
145ff99132eSAxel Dörfler 		}
14621e1553eSJérôme Duval 	}
14721e1553eSJérôme Duval 	return result;
14821e1553eSJérôme Duval }
14921e1553eSJérôme Duval 
15021e1553eSJérôme Duval 
15121e1553eSJérôme Duval static status_t
1520eaadd30SMichael Lotz fs_unmount(fs_volume *_vol)
15321e1553eSJérôme Duval {
15421e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
1550eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
15621e1553eSJérôme Duval 
15721e1553eSJérôme Duval 	TRACE(("fs_unmount - ENTER\n"));
15821e1553eSJérôme Duval 
1599d254f45SJérôme Duval 	// Unlike in BeOS, we need to put the reference to our root node ourselves
1600eaadd30SMichael Lotz 	put_vnode(_vol, ISO_ROOTNODE_ID);
1619d254f45SJérôme Duval 
16221e1553eSJérôme Duval 	block_cache_delete(ns->fBlockCache, false);
16321e1553eSJérôme Duval 	close(ns->fdOfSession);
16421e1553eSJérôme Duval 	result = close(ns->fd);
16521e1553eSJérôme Duval 
16621e1553eSJérôme Duval 	free(ns);
16721e1553eSJérôme Duval 
16821e1553eSJérôme Duval 	TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result)));
16921e1553eSJérôme Duval 	return result;
17021e1553eSJérôme Duval }
17121e1553eSJérôme Duval 
17221e1553eSJérôme Duval 
17321e1553eSJérôme Duval static status_t
1740eaadd30SMichael Lotz fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss)
17521e1553eSJérôme Duval {
1760eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
17721e1553eSJérôme Duval 	int i;
17821e1553eSJérôme Duval 
17921e1553eSJérôme Duval 	fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
18021e1553eSJérôme Duval 	fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT];
18121e1553eSJérôme Duval 	fss->io_size = 65536;
18221e1553eSJérôme Duval 	fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT];
18321e1553eSJérôme Duval 	fss->free_blocks = 0;
18421e1553eSJérôme Duval 
18521e1553eSJérôme Duval 	strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name));
18621e1553eSJérôme Duval 
18721e1553eSJérôme Duval 	strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name));
188ff99132eSAxel Dörfler 	for (i = strlen(fss->volume_name) - 1; i >=0 ; i--) {
18921e1553eSJérôme Duval 		if (fss->volume_name[i] != ' ')
19021e1553eSJérôme Duval 			break;
191ff99132eSAxel Dörfler 	}
19221e1553eSJérôme Duval 
19321e1553eSJérôme Duval 	if (i < 0)
19421e1553eSJérôme Duval 		strcpy(fss->volume_name, "UNKNOWN");
19521e1553eSJérôme Duval 	else
19621e1553eSJérôme Duval 		fss->volume_name[i + 1] = 0;
19721e1553eSJérôme Duval 
19821e1553eSJérôme Duval 	strcpy(fss->fsh_name, "iso9660");
199ff99132eSAxel Dörfler 	return B_OK;
20021e1553eSJérôme Duval }
20121e1553eSJérôme Duval 
2023b723f79SJérôme Duval 
2033b723f79SJérôme Duval static status_t
2040eaadd30SMichael Lotz fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferSize)
2053b723f79SJérôme Duval {
2060eaadd30SMichael Lotz 	vnode *node = (vnode*)_node->private_node;
2073b723f79SJérôme Duval 
2083b723f79SJérôme Duval 	strlcpy(buffer, node->fileIDString, bufferSize);
2093b723f79SJérôme Duval 	return B_OK;
2103b723f79SJérôme Duval }
2113b723f79SJérôme Duval 
2123b723f79SJérôme Duval 
21321e1553eSJérôme Duval static status_t
2140eaadd30SMichael Lotz fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
21521e1553eSJérôme Duval {
2160eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
2170eaadd30SMichael Lotz 	vnode *baseNode = (vnode*)_base->private_node;
21821e1553eSJérôme Duval 	vnode *newNode = NULL;
21921e1553eSJérôme Duval 
22021e1553eSJérôme Duval 	TRACE(("fs_walk - looking for %s in dir file of length %d\n", file,
22121e1553eSJérôme Duval 		baseNode->dataLen[FS_DATA_FORMAT]));
22221e1553eSJérôme Duval 
22321e1553eSJérôme Duval 	if (strcmp(file, ".") == 0)  {
22421e1553eSJérôme Duval 		// base directory
22521e1553eSJérôme Duval 		TRACE(("fs_walk - found \".\" file.\n"));
22621e1553eSJérôme Duval 		*_vnodeID = baseNode->id;
2270eaadd30SMichael Lotz 		return get_vnode(_vol, *_vnodeID, (void **)&newNode);
22821e1553eSJérôme Duval 	} else if (strcmp(file, "..") == 0) {
22921e1553eSJérôme Duval 		// parent directory
23021e1553eSJérôme Duval 		TRACE(("fs_walk - found \"..\" file.\n"));
23121e1553eSJérôme Duval 		*_vnodeID = baseNode->parID;
2320eaadd30SMichael Lotz 		return get_vnode(_vol, *_vnodeID, (void **)&newNode);
233ff99132eSAxel Dörfler 	}
234ff99132eSAxel Dörfler 
23521e1553eSJérôme Duval 	// look up file in the directory
236ff99132eSAxel Dörfler 	uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT];
237ff99132eSAxel Dörfler 	status_t result = ENOENT;
238ff99132eSAxel Dörfler 	uint32 totalRead = 0;
239ff99132eSAxel Dörfler 	off_t block = baseNode->startLBN[FS_DATA_FORMAT];
240ff99132eSAxel Dörfler 	bool done = false;
24121e1553eSJérôme Duval 
242ff99132eSAxel Dörfler 	while (totalRead < dataLength && !done) {
24321e1553eSJérôme Duval 		off_t cachedBlock = block;
244ff99132eSAxel Dörfler 		char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0,
245ff99132eSAxel Dörfler 			ns->logicalBlkSize[FS_DATA_FORMAT]);
24621e1553eSJérôme Duval 		if (blockData != NULL) {
24721e1553eSJérôme Duval 			int bytesRead = 0;
24821e1553eSJérôme Duval 			off_t blockBytesRead = 0;
24921e1553eSJérôme Duval 			vnode node;
25021e1553eSJérôme Duval 			int initResult;
25121e1553eSJérôme Duval 
25221e1553eSJérôme Duval 			TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n",
25321e1553eSJérôme Duval 				block, blockData));
25421e1553eSJérôme Duval 
25521e1553eSJérôme Duval 			// Move to the next 2-block set if necessary
25621e1553eSJérôme Duval 			// Don't go over end of buffer, if dir record sits on boundary.
25721e1553eSJérôme Duval 
25821e1553eSJérôme Duval 			node.fileIDString = NULL;
25921e1553eSJérôme Duval 			node.attr.slName = NULL;
26021e1553eSJérôme Duval 
26121e1553eSJérôme Duval 			while (blockBytesRead < 2 * ns->logicalBlkSize[FS_DATA_FORMAT]
262ff99132eSAxel Dörfler 				&& totalRead + blockBytesRead < dataLength
26321e1553eSJérôme Duval 				&& blockData[0] != 0
264ff99132eSAxel Dörfler 				&& !done) {
265ff99132eSAxel Dörfler 				initResult = InitNode(&node, blockData, &bytesRead,
266ff99132eSAxel Dörfler 					ns->joliet_level);
26721e1553eSJérôme Duval 				TRACE(("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead));
26821e1553eSJérôme Duval 
269ff99132eSAxel Dörfler 				if (initResult == B_OK) {
270ff99132eSAxel Dörfler 					if (!strcmp(node.fileIDString, file)) {
27121e1553eSJérôme Duval 						TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead));
272ff99132eSAxel Dörfler 						*_vnodeID = (block << 30)
273ff99132eSAxel Dörfler 							+ (blockBytesRead & 0xffffffff);
27421e1553eSJérôme Duval 						TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID));
27521e1553eSJérôme Duval 
2760eaadd30SMichael Lotz 						result = get_vnode(_vol, *_vnodeID,
277ff99132eSAxel Dörfler 							(void **)&newNode);
278ff99132eSAxel Dörfler 						if (result == B_OK) {
27921e1553eSJérôme Duval 							newNode->parID = baseNode->id;
280ff99132eSAxel Dörfler 							done = true;
28121e1553eSJérôme Duval 						}
28221e1553eSJérôme Duval 					} else {
28321e1553eSJérôme Duval 						free(node.fileIDString);
28421e1553eSJérôme Duval 						node.fileIDString = NULL;
28521e1553eSJérôme Duval 						free(node.attr.slName);
28621e1553eSJérôme Duval 						node.attr.slName = NULL;
28721e1553eSJérôme Duval 					}
28821e1553eSJérôme Duval 				} else {
28921e1553eSJérôme Duval 					result = initResult;
29021e1553eSJérôme Duval 					if (bytesRead == 0)
29121e1553eSJérôme Duval 						done = TRUE;
29221e1553eSJérôme Duval 				}
29321e1553eSJérôme Duval 				blockData += bytesRead;
29421e1553eSJérôme Duval 				blockBytesRead += bytesRead;
29521e1553eSJérôme Duval 
29621e1553eSJérôme Duval 				TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n",
29721e1553eSJérôme Duval 					bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]));
29821e1553eSJérôme Duval 			}
29921e1553eSJérôme Duval 			totalRead += ns->logicalBlkSize[FS_DATA_FORMAT];
30021e1553eSJérôme Duval 			block++;
30121e1553eSJérôme Duval 
30221e1553eSJérôme Duval 			TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead));
30321e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, cachedBlock);
30421e1553eSJérôme Duval 
30521e1553eSJérôme Duval 		} else
30621e1553eSJérôme Duval 			done = TRUE;
30721e1553eSJérôme Duval 	}
30821e1553eSJérôme Duval 
309ff99132eSAxel Dörfler 	TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n",
310ff99132eSAxel Dörfler 		strerror(result), *_vnodeID));
31121e1553eSJérôme Duval 	return result;
31221e1553eSJérôme Duval }
31321e1553eSJérôme Duval 
31421e1553eSJérôme Duval 
31521e1553eSJérôme Duval static status_t
3160eaadd30SMichael Lotz fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node,
3170eaadd30SMichael Lotz 	int *_type, uint32 *_flags, bool reenter)
31821e1553eSJérôme Duval {
3190eaadd30SMichael Lotz 	nspace *ns = (nspace*)_vol->private_volume;
320ff99132eSAxel Dörfler 
32121e1553eSJérôme Duval 	vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
322ff99132eSAxel Dörfler 	if (newNode == NULL)
323ff99132eSAxel Dörfler 		return B_NO_MEMORY;
32421e1553eSJérôme Duval 
325ff99132eSAxel Dörfler 	uint32 pos = vnodeID & 0x3fffffff;
326ff99132eSAxel Dörfler 	uint32 block = vnodeID >> 30;
32721e1553eSJérôme Duval 
328ff99132eSAxel Dörfler 	TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node 0x%x\n",
329ff99132eSAxel Dörfler 		block, pos, vnodeID, newNode));
33021e1553eSJérôme Duval 
331ff99132eSAxel Dörfler 	if (pos > ns->logicalBlkSize[FS_DATA_FORMAT])
332ff99132eSAxel Dörfler 		return B_BAD_VALUE;
33321e1553eSJérôme Duval 
334ff99132eSAxel Dörfler 	char *data = (char *)block_cache_get_etc(ns->fBlockCache,
335ff99132eSAxel Dörfler 		block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
336ff99132eSAxel Dörfler 	if (data == NULL) {
337ff99132eSAxel Dörfler 		free(newNode);
338ff99132eSAxel Dörfler 		return B_IO_ERROR;
339ff99132eSAxel Dörfler 	}
34021e1553eSJérôme Duval 
341ff99132eSAxel Dörfler 	status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level);
34221e1553eSJérôme Duval 	block_cache_put(ns->fBlockCache, block);
34321e1553eSJérôme Duval 
344ff99132eSAxel Dörfler 	if (result < B_OK) {
345ff99132eSAxel Dörfler 		free(newNode);
346ff99132eSAxel Dörfler 		return result;
34721e1553eSJérôme Duval 	}
34821e1553eSJérôme Duval 
349ff99132eSAxel Dörfler 	newNode->id = vnodeID;
3500eaadd30SMichael Lotz 	_node->private_node = newNode;
3510eaadd30SMichael Lotz 	_node->ops = &gISO9660VnodeOps;
3520eaadd30SMichael Lotz 	*_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH);
3530eaadd30SMichael Lotz 	*_flags = 0;
354ff99132eSAxel Dörfler 
355ff99132eSAxel Dörfler 	if ((newNode->flags & ISO_ISDIR) == 0) {
356ff99132eSAxel Dörfler 		newNode->cache = file_cache_create(ns->id, vnodeID,
3573d268edaSAxel Dörfler 			newNode->dataLen[FS_DATA_FORMAT]);
3585b4cb109SJérôme Duval 	}
3595b4cb109SJérôme Duval 
360ff99132eSAxel Dörfler 	return B_OK;
36121e1553eSJérôme Duval }
36221e1553eSJérôme Duval 
36321e1553eSJérôme Duval 
36421e1553eSJérôme Duval static status_t
3650eaadd30SMichael Lotz fs_release_vnode(fs_volume *_vol, fs_vnode *_node, bool reenter)
36621e1553eSJérôme Duval {
36721e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
3680eaadd30SMichael Lotz 	vnode *node = (vnode*)_node->private_node;
36921e1553eSJérôme Duval 
3700eaadd30SMichael Lotz 	(void)_vol;
37121e1553eSJérôme Duval 	(void)reenter;
37221e1553eSJérôme Duval 
3735b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - ENTER (0x%x)\n", node));
37421e1553eSJérôme Duval 
37521e1553eSJérôme Duval 	if (node != NULL) {
37621e1553eSJérôme Duval 		if (node->id != ISO_ROOTNODE_ID) {
37721e1553eSJérôme Duval 			if (node->fileIDString != NULL)
37821e1553eSJérôme Duval 				free (node->fileIDString);
37921e1553eSJérôme Duval 			if (node->attr.slName != NULL)
38021e1553eSJérôme Duval 				free (node->attr.slName);
3815b4cb109SJérôme Duval 			if (node->cache != NULL)
3825b4cb109SJérôme Duval 				file_cache_delete(node->cache);
38321e1553eSJérôme Duval 
38421e1553eSJérôme Duval 			free(node);
38521e1553eSJérôme Duval 		}
38621e1553eSJérôme Duval 	}
38721e1553eSJérôme Duval 
3885b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - EXIT\n"));
38921e1553eSJérôme Duval 	return result;
39021e1553eSJérôme Duval }
39121e1553eSJérôme Duval 
39221e1553eSJérôme Duval 
39321e1553eSJérôme Duval static status_t
3940eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos,
395*e6bd90c5SIngo Weinhold 	const iovec *vecs, size_t count, size_t *_numBytes)
3965b4cb109SJérôme Duval {
3970eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
3980eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
3995b4cb109SJérôme Duval 
400ff99132eSAxel Dörfler 	uint32 fileSize = node->dataLen[FS_DATA_FORMAT];
401ff99132eSAxel Dörfler 	size_t bytesLeft = *_numBytes;
4025b4cb109SJérôme Duval 
403ff99132eSAxel Dörfler 	if (pos >= fileSize) {
404ff99132eSAxel Dörfler 		*_numBytes = 0;
4055b4cb109SJérôme Duval 		return B_OK;
4065b4cb109SJérôme Duval 	}
407ff99132eSAxel Dörfler 	if (pos + bytesLeft > fileSize) {
408ff99132eSAxel Dörfler 		bytesLeft = fileSize - pos;
409ff99132eSAxel Dörfler 		*_numBytes = bytesLeft;
4105b4cb109SJérôme Duval 	}
4115b4cb109SJérôme Duval 
412ff99132eSAxel Dörfler 	file_io_vec fileVec;
413ff99132eSAxel Dörfler 	fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT]
414ff99132eSAxel Dörfler 		* ns->logicalBlkSize[FS_DATA_FORMAT];
415ff99132eSAxel Dörfler 	fileVec.length = bytesLeft;
4165b4cb109SJérôme Duval 
417ff99132eSAxel Dörfler 	uint32 vecIndex = 0;
418ff99132eSAxel Dörfler 	size_t vecOffset = 0;
419ff99132eSAxel Dörfler 	return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count,
420ff99132eSAxel Dörfler 		&vecIndex, &vecOffset, &bytesLeft);
4215b4cb109SJérôme Duval }
4225b4cb109SJérôme Duval 
4235b4cb109SJérôme Duval 
4245b4cb109SJérôme Duval static status_t
4250eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st)
42621e1553eSJérôme Duval {
4270eaadd30SMichael Lotz 	nspace *ns = (nspace*)_vol->private_volume;
4280eaadd30SMichael Lotz 	vnode *node = (vnode*)_node->private_node;
4293b723f79SJérôme Duval 	status_t result = B_NO_ERROR;
43021e1553eSJérôme Duval 	time_t time;
43121e1553eSJérôme Duval 
4323b723f79SJérôme Duval 	TRACE(("fs_read_stat - ENTER\n"));
43321e1553eSJérôme Duval 
43421e1553eSJérôme Duval 	st->st_dev = ns->id;
43521e1553eSJérôme Duval 	st->st_ino = node->id;
43621e1553eSJérôme Duval 	st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink;
43721e1553eSJérôme Duval 	st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid;
43821e1553eSJérôme Duval 	st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid;
43921e1553eSJérôme Duval 	st->st_blksize = 65536;
44021e1553eSJérôme Duval 	st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode;
44121e1553eSJérôme Duval 
44221e1553eSJérôme Duval 	// Same for file/dir in ISO9660
44321e1553eSJérôme Duval 	st->st_size = node->dataLen[FS_DATA_FORMAT];
44421e1553eSJérôme Duval 	if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR)
44521e1553eSJérôme Duval 		st->st_ctime = st->st_mtime = st->st_atime = time;
44621e1553eSJérôme Duval 
4473b723f79SJérôme Duval 	TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result)));
44821e1553eSJérôme Duval 
44921e1553eSJérôme Duval 	return result;
45021e1553eSJérôme Duval }
45121e1553eSJérôme Duval 
45221e1553eSJérôme Duval 
45321e1553eSJérôme Duval static status_t
4540eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie)
45521e1553eSJérôme Duval {
45621e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
45721e1553eSJérôme Duval 
4580eaadd30SMichael Lotz 	(void)_vol;
45921e1553eSJérôme Duval 	(void)cookie;
46021e1553eSJérôme Duval 
46121e1553eSJérôme Duval 	// Do not allow any of the write-like open modes to get by
46221e1553eSJérôme Duval 	if ((omode == O_WRONLY) || (omode == O_RDWR))
46321e1553eSJérôme Duval 		result = EROFS;
46421e1553eSJérôme Duval 	else if((omode & O_TRUNC) || (omode & O_CREAT))
46521e1553eSJérôme Duval 		result = EROFS;
46621e1553eSJérôme Duval 
46721e1553eSJérôme Duval 	return result;
46821e1553eSJérôme Duval }
46921e1553eSJérôme Duval 
47021e1553eSJérôme Duval 
47121e1553eSJérôme Duval static status_t
4720eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer,
473ff99132eSAxel Dörfler 	size_t *_length)
47421e1553eSJérôme Duval {
4750eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
47621e1553eSJérôme Duval 
47721e1553eSJérôme Duval 	if (node->flags & ISO_ISDIR)
47821e1553eSJérôme Duval 		return EISDIR;
47921e1553eSJérôme Duval 
480ff99132eSAxel Dörfler 	uint32 fileSize = node->dataLen[FS_DATA_FORMAT];
4815b4cb109SJérôme Duval 
4825b4cb109SJérôme Duval 	// set/check boundaries for pos/length
483ff99132eSAxel Dörfler 	if (pos < 0)
4845b4cb109SJérôme Duval 		return B_BAD_VALUE;
485ff99132eSAxel Dörfler 	if (pos >= fileSize) {
486ff99132eSAxel Dörfler 		*_length = 0;
4875b4cb109SJérôme Duval 		return B_OK;
4885b4cb109SJérôme Duval 	}
489ff99132eSAxel Dörfler 
490ff99132eSAxel Dörfler 	return file_cache_read(node->cache, NULL, pos, buffer, _length);
49121e1553eSJérôme Duval }
49221e1553eSJérôme Duval 
49321e1553eSJérôme Duval 
49421e1553eSJérôme Duval static status_t
4950eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie)
49621e1553eSJérôme Duval {
4970eaadd30SMichael Lotz 	(void)_vol;
4980eaadd30SMichael Lotz 	(void)_node;
49921e1553eSJérôme Duval 	(void)cookie;
50021e1553eSJérôme Duval 
50121e1553eSJérôme Duval 	return B_OK;
50221e1553eSJérôme Duval }
50321e1553eSJérôme Duval 
504ff99132eSAxel Dörfler 
50521e1553eSJérôme Duval static status_t
5060eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie)
50721e1553eSJérôme Duval {
5080eaadd30SMichael Lotz 	(void)_vol;
5090eaadd30SMichael Lotz 	(void)_node;
51021e1553eSJérôme Duval 	(void)cookie;
51121e1553eSJérôme Duval 
51221e1553eSJérôme Duval 	return B_OK;
51321e1553eSJérôme Duval }
51421e1553eSJérôme Duval 
515ff99132eSAxel Dörfler 
51621e1553eSJérôme Duval static status_t
5170eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode)
51821e1553eSJérôme Duval {
5190eaadd30SMichael Lotz 	(void)_vol;
5200eaadd30SMichael Lotz 	(void)_node;
52121e1553eSJérôme Duval 	(void)mode;
52221e1553eSJérôme Duval 
52321e1553eSJérôme Duval 	return B_OK;
52421e1553eSJérôme Duval }
52521e1553eSJérôme Duval 
526ff99132eSAxel Dörfler 
52721e1553eSJérôme Duval static status_t
5280eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize)
52921e1553eSJérôme Duval {
5300eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
53121e1553eSJérôme Duval 
532ff99132eSAxel Dörfler 	if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode))
533ff99132eSAxel Dörfler 		return B_BAD_VALUE;
53421e1553eSJérôme Duval 
53521e1553eSJérôme Duval 	size_t length = strlen(node->attr.slName);
53621e1553eSJérôme Duval 	if (length > *_bufferSize)
5373b723f79SJérôme Duval 		memcpy(buffer, node->attr.slName, *_bufferSize);
5383b723f79SJérôme Duval 	else {
53921e1553eSJérôme Duval 		memcpy(buffer, node->attr.slName, length);
5403b723f79SJérôme Duval 		*_bufferSize = length;
5413b723f79SJérôme Duval 	}
54221e1553eSJérôme Duval 
543ff99132eSAxel Dörfler 	return B_OK;
54421e1553eSJérôme Duval }
54521e1553eSJérôme Duval 
54621e1553eSJérôme Duval 
54721e1553eSJérôme Duval static status_t
5480eaadd30SMichael Lotz fs_open_dir(fs_volume *_vol, fs_vnode *_node, void **cookie)
54921e1553eSJérôme Duval {
5500eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
55121e1553eSJérôme Duval 
552ff99132eSAxel Dörfler 	TRACE(("fs_open_dir - node is 0x%x\n", _node));
55321e1553eSJérôme Duval 
55421e1553eSJérôme Duval 	if (!(node->flags & ISO_ISDIR))
555ff99132eSAxel Dörfler 		return B_NOT_A_DIRECTORY;
55621e1553eSJérôme Duval 
557ff99132eSAxel Dörfler 	dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
558ff99132eSAxel Dörfler 	if (dirCookie == NULL)
559ff99132eSAxel Dörfler 		return B_NO_MEMORY;
560ff99132eSAxel Dörfler 
56121e1553eSJérôme Duval 	dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT];
56221e1553eSJérôme Duval 	dirCookie->block = node->startLBN[FS_DATA_FORMAT];
56321e1553eSJérôme Duval 	dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
56421e1553eSJérôme Duval 	dirCookie->pos = 0;
56521e1553eSJérôme Duval 	dirCookie->id = node->id;
56621e1553eSJérôme Duval 	*cookie = (void *)dirCookie;
56721e1553eSJérôme Duval 
568ff99132eSAxel Dörfler 	return B_OK;
56921e1553eSJérôme Duval }
57021e1553eSJérôme Duval 
57121e1553eSJérôme Duval 
57221e1553eSJérôme Duval static status_t
5730eaadd30SMichael Lotz fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie, struct dirent *buffer,
57421e1553eSJérôme Duval 	size_t bufferSize, uint32 *num)
57521e1553eSJérôme Duval {
5760eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
57721e1553eSJérôme Duval 	dircookie *dirCookie = (dircookie *)_cookie;
57821e1553eSJérôme Duval 
5795b4cb109SJérôme Duval 	TRACE(("fs_read_dir - ENTER\n"));
58021e1553eSJérôme Duval 
581ff99132eSAxel Dörfler 	status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize);
58221e1553eSJérôme Duval 
58321e1553eSJérôme Duval 	// If we succeeded, return 1, the number of dirents we read.
584ff99132eSAxel Dörfler 	if (result == B_OK)
58521e1553eSJérôme Duval 		*num = 1;
58621e1553eSJérôme Duval 	else
58721e1553eSJérôme Duval 		*num = 0;
58821e1553eSJérôme Duval 
58921e1553eSJérôme Duval 	// When you get to the end, don't return an error, just return
59021e1553eSJérôme Duval 	// a zero in *num.
59121e1553eSJérôme Duval 
59221e1553eSJérôme Duval 	if (result == ENOENT)
593ff99132eSAxel Dörfler 		result = B_OK;
59421e1553eSJérôme Duval 
5955b4cb109SJérôme Duval 	TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result)));
59621e1553eSJérôme Duval 	return result;
59721e1553eSJérôme Duval }
59821e1553eSJérôme Duval 
59921e1553eSJérôme Duval 
60021e1553eSJérôme Duval static status_t
6010eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie)
60221e1553eSJérôme Duval {
60321e1553eSJérôme Duval 	dircookie *cookie = (dircookie*)_cookie;
60421e1553eSJérôme Duval 
60521e1553eSJérôme Duval 	cookie->block = cookie->startBlock;
60621e1553eSJérôme Duval 	cookie->pos = 0;
607ff99132eSAxel Dörfler 	return B_OK;
60821e1553eSJérôme Duval }
60921e1553eSJérôme Duval 
61021e1553eSJérôme Duval 
61121e1553eSJérôme Duval static status_t
6120eaadd30SMichael Lotz fs_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie)
61321e1553eSJérôme Duval {
61421e1553eSJérôme Duval 	return B_OK;
61521e1553eSJérôme Duval }
61621e1553eSJérôme Duval 
61721e1553eSJérôme Duval 
61821e1553eSJérôme Duval static status_t
6190eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie)
62021e1553eSJérôme Duval {
62121e1553eSJérôme Duval 	free(cookie);
62221e1553eSJérôme Duval 	return B_OK;
62321e1553eSJérôme Duval }
62421e1553eSJérôme Duval 
625ff99132eSAxel Dörfler 
62621e1553eSJérôme Duval //	#pragma mark -
62721e1553eSJérôme Duval 
62821e1553eSJérôme Duval 
62921e1553eSJérôme Duval static status_t
63021e1553eSJérôme Duval iso_std_ops(int32 op, ...)
63121e1553eSJérôme Duval {
63221e1553eSJérôme Duval 	switch (op) {
63321e1553eSJérôme Duval 		case B_MODULE_INIT:
63421e1553eSJérôme Duval 		case B_MODULE_UNINIT:
63521e1553eSJérôme Duval 			return B_OK;
63621e1553eSJérôme Duval 		default:
63721e1553eSJérôme Duval 			return B_ERROR;
63821e1553eSJérôme Duval 	}
63921e1553eSJérôme Duval }
64021e1553eSJérôme Duval 
64121e1553eSJérôme Duval 
6420eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = {
6430eaadd30SMichael Lotz 	&fs_unmount,
6440eaadd30SMichael Lotz 	&fs_read_fs_stat,
6450eaadd30SMichael Lotz 	NULL,
6460eaadd30SMichael Lotz 	NULL,
6470eaadd30SMichael Lotz 	&fs_read_vnode,
6480eaadd30SMichael Lotz 
6490eaadd30SMichael Lotz 	/* index and index directory ops */
6500eaadd30SMichael Lotz 	NULL,
6510eaadd30SMichael Lotz 	NULL,
6520eaadd30SMichael Lotz 	NULL,
6530eaadd30SMichael Lotz 	NULL,
6540eaadd30SMichael Lotz 	NULL,
6550eaadd30SMichael Lotz 	NULL,
6560eaadd30SMichael Lotz 	NULL,
6570eaadd30SMichael Lotz 	NULL,
6580eaadd30SMichael Lotz 
6590eaadd30SMichael Lotz 	/* query ops */
6600eaadd30SMichael Lotz 	NULL,
6610eaadd30SMichael Lotz 	NULL,
6620eaadd30SMichael Lotz 	NULL,
6630eaadd30SMichael Lotz 	NULL,
6640eaadd30SMichael Lotz 	NULL,
6650eaadd30SMichael Lotz 
6660eaadd30SMichael Lotz 	/* FS layer ops */
6670eaadd30SMichael Lotz 	NULL,
6680eaadd30SMichael Lotz 	NULL,
6690eaadd30SMichael Lotz };
6700eaadd30SMichael Lotz 
6710eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = {
6720eaadd30SMichael Lotz 	&fs_walk,
6730eaadd30SMichael Lotz 	&fs_get_vnode_name,
6740eaadd30SMichael Lotz 	&fs_release_vnode,
6750eaadd30SMichael Lotz 	NULL,
6760eaadd30SMichael Lotz 
6770eaadd30SMichael Lotz 	/* vm-related ops */
6780eaadd30SMichael Lotz 	NULL,
6790eaadd30SMichael Lotz 	&fs_read_pages,
6800eaadd30SMichael Lotz 	NULL,
6810eaadd30SMichael Lotz 
6820eaadd30SMichael Lotz 	/* cache file access */
6830eaadd30SMichael Lotz 	NULL,
6840eaadd30SMichael Lotz 
6850eaadd30SMichael Lotz 	/* common */
6860eaadd30SMichael Lotz 	NULL,
6870eaadd30SMichael Lotz 	NULL,
6880eaadd30SMichael Lotz 	NULL,
6890eaadd30SMichael Lotz 	NULL,
6900eaadd30SMichael Lotz 	NULL,
6910eaadd30SMichael Lotz 	&fs_read_link,
6920eaadd30SMichael Lotz 	NULL,
6930eaadd30SMichael Lotz 	NULL,
6940eaadd30SMichael Lotz 	NULL,
6950eaadd30SMichael Lotz 	NULL,
6960eaadd30SMichael Lotz 	&fs_access,
6970eaadd30SMichael Lotz 	&fs_read_stat,
6980eaadd30SMichael Lotz 	NULL,
6990eaadd30SMichael Lotz 
7000eaadd30SMichael Lotz 	/* file */
7010eaadd30SMichael Lotz 	NULL,
7020eaadd30SMichael Lotz 	&fs_open,
7030eaadd30SMichael Lotz 	&fs_close,
7040eaadd30SMichael Lotz 	&fs_free_cookie,
7050eaadd30SMichael Lotz 	&fs_read,
7060eaadd30SMichael Lotz 	NULL,
7070eaadd30SMichael Lotz 
7080eaadd30SMichael Lotz 	/* dir */
7090eaadd30SMichael Lotz 	NULL,
7100eaadd30SMichael Lotz 	NULL,
7110eaadd30SMichael Lotz 	&fs_open_dir,
7120eaadd30SMichael Lotz 	&fs_close_dir,
7130eaadd30SMichael Lotz 	&fs_free_dir_cookie,
7140eaadd30SMichael Lotz 	&fs_read_dir,
7150eaadd30SMichael Lotz 	&fs_rewind_dir,
7160eaadd30SMichael Lotz 
7170eaadd30SMichael Lotz 	/* attribute directory ops */
7180eaadd30SMichael Lotz 	NULL,
7190eaadd30SMichael Lotz 	NULL,
7200eaadd30SMichael Lotz 	NULL,
7210eaadd30SMichael Lotz 	NULL,
7220eaadd30SMichael Lotz 	NULL,
7230eaadd30SMichael Lotz 
7240eaadd30SMichael Lotz 	/* attribute ops */
7250eaadd30SMichael Lotz 	NULL,
7260eaadd30SMichael Lotz 	NULL,
7270eaadd30SMichael Lotz 	NULL,
7280eaadd30SMichael Lotz 	NULL,
7290eaadd30SMichael Lotz 	NULL,
7300eaadd30SMichael Lotz 	NULL,
7310eaadd30SMichael Lotz 	NULL,
7320eaadd30SMichael Lotz 	NULL,
7330eaadd30SMichael Lotz 	NULL,
7340eaadd30SMichael Lotz 	NULL,
7350eaadd30SMichael Lotz 
7360eaadd30SMichael Lotz 	/* node and FS layer support */
7370eaadd30SMichael Lotz 	NULL,
7380eaadd30SMichael Lotz 	NULL,
7390eaadd30SMichael Lotz };
7400eaadd30SMichael Lotz 
74121e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = {
74221e1553eSJérôme Duval 	{
74321e1553eSJérôme Duval 		"file_systems/iso9660" B_CURRENT_FS_API_VERSION,
74421e1553eSJérôme Duval 		0,
74521e1553eSJérôme Duval 		iso_std_ops,
74621e1553eSJérôme Duval 	},
74721e1553eSJérôme Duval 
7481da9f5ceSAxel Dörfler 	"iso9660",					// short_name
7491da9f5ceSAxel Dörfler 	"ISO9660 File System",		// pretty_name
75076a8ec23SIngo Weinhold 	0,							// DDM flags
75121e1553eSJérôme Duval 
75221e1553eSJérôme Duval 	// scanning
75321e1553eSJérôme Duval 	fs_identify_partition,
75421e1553eSJérôme Duval 	fs_scan_partition,
75521e1553eSJérôme Duval 	fs_free_identify_partition_cookie,
75621e1553eSJérôme Duval 	NULL,	// free_partition_content_cookie()
75721e1553eSJérôme Duval 
75821e1553eSJérôme Duval 	&fs_mount,
7590eaadd30SMichael Lotz 
7600eaadd30SMichael Lotz 	/* capability querying */
7610eaadd30SMichael Lotz 	NULL,
7620eaadd30SMichael Lotz 	NULL,
7630eaadd30SMichael Lotz 	NULL,
7640eaadd30SMichael Lotz 	NULL,
76521e1553eSJérôme Duval 	NULL,
76621e1553eSJérôme Duval 	NULL,
76721e1553eSJérôme Duval 
7680eaadd30SMichael Lotz 	/* shadow partition modifications */
7690eaadd30SMichael Lotz 	NULL,
77021e1553eSJérôme Duval 
7710eaadd30SMichael Lotz 	/* writing */
7720eaadd30SMichael Lotz 	NULL,
7730eaadd30SMichael Lotz 	NULL,
7740eaadd30SMichael Lotz 	NULL,
7750eaadd30SMichael Lotz 	NULL,
7760eaadd30SMichael Lotz 	NULL,
7770eaadd30SMichael Lotz 	NULL,
7780eaadd30SMichael Lotz 	NULL,
77921e1553eSJérôme Duval };
78021e1553eSJérôme Duval 
78121e1553eSJérôme Duval module_info *modules[] = {
78221e1553eSJérôme Duval 	(module_info *)&sISO660FileSystem,
78321e1553eSJérôme Duval 	NULL,
78421e1553eSJérôme Duval };
78521e1553eSJérôme Duval 
786