xref: /haiku/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp (revision d02cde3053be75589a08149100011a9f73e6e966)
121e1553eSJérôme Duval /*
2245aecdaSAxel Dörfler  * Copyright 1999, Be Incorporated.   All Rights Reserved.
3245aecdaSAxel Dörfler  * This file may be used under the terms of the Be Sample Code License.
4245aecdaSAxel Dörfler  *
5245aecdaSAxel Dörfler  * Copyright 2001, pinc Software.  All Rights Reserved.
6245aecdaSAxel Dörfler  *
7245aecdaSAxel Dörfler  * iso9960/multi-session, 1.0.0
821e1553eSJérôme Duval  */
921e1553eSJérôme Duval 
10245aecdaSAxel Dörfler 
1121e1553eSJérôme Duval #include <ctype.h>
1221e1553eSJérôme Duval #include <dirent.h>
135b2c5d03SAxel Dörfler #include <errno.h>
145b2c5d03SAxel Dörfler #include <fcntl.h>
155b2c5d03SAxel Dörfler #include <stdio.h>
165b2c5d03SAxel Dörfler #include <stdlib.h>
175b2c5d03SAxel Dörfler #include <string.h>
1821e1553eSJérôme Duval #include <sys/stat.h>
1921e1553eSJérôme Duval #include <time.h>
205b2c5d03SAxel Dörfler #include <unistd.h>
2121e1553eSJérôme Duval 
2221e1553eSJérôme Duval #include <KernelExport.h>
2321e1553eSJérôme Duval #include <NodeMonitor.h>
2421e1553eSJérôme Duval #include <fs_interface.h>
2521e1553eSJérôme Duval #include <fs_cache.h>
2621e1553eSJérôme Duval 
2721e1553eSJérôme Duval #include <fs_attr.h>
2821e1553eSJérôme Duval #include <fs_info.h>
2921e1553eSJérôme Duval #include <fs_index.h>
3021e1553eSJérôme Duval #include <fs_query.h>
3121e1553eSJérôme Duval #include <fs_volume.h>
3221e1553eSJérôme Duval 
3321e1553eSJérôme Duval #include <util/kernel_cpp.h>
3421e1553eSJérôme Duval 
35dc9a52b9SAxel Dörfler #include "iso9660.h"
365b2c5d03SAxel Dörfler #include "iso9660_identify.h"
375b2c5d03SAxel Dörfler 
385b2c5d03SAxel Dörfler 
395b2c5d03SAxel Dörfler //#define TRACE_ISO9660
405b2c5d03SAxel Dörfler #ifdef TRACE_ISO9660
4121e1553eSJérôme Duval #	define TRACE(x) dprintf x
4221e1553eSJérôme Duval #else
4321e1553eSJérôme Duval #	define TRACE(x) ;
4421e1553eSJérôme Duval #endif
4521e1553eSJérôme Duval 
4621e1553eSJérôme Duval 
4721e1553eSJérôme Duval struct identify_cookie {
4821e1553eSJérôme Duval 	iso9660_info info;
4921e1553eSJérôme Duval };
5021e1553eSJérôme Duval 
510eaadd30SMichael Lotz extern fs_volume_ops gISO9660VolumeOps;
520eaadd30SMichael Lotz extern fs_vnode_ops gISO9660VnodeOps;
530eaadd30SMichael Lotz 
5421e1553eSJérôme Duval 
555b2c5d03SAxel Dörfler //	#pragma mark - Scanning
565b2c5d03SAxel Dörfler 
575b2c5d03SAxel Dörfler 
5821e1553eSJérôme Duval static float
5921e1553eSJérôme Duval fs_identify_partition(int fd, partition_data *partition, void **_cookie)
6021e1553eSJérôme Duval {
615b2c5d03SAxel Dörfler 	iso9660_info *info = new iso9660_info;
6221e1553eSJérôme Duval 
635b2c5d03SAxel Dörfler 	status_t status = iso9660_fs_identify(fd, info);
645b2c5d03SAxel Dörfler 	if (status != B_OK) {
655b2c5d03SAxel Dörfler 		delete info;
665b2c5d03SAxel Dörfler 		return -1;
675b2c5d03SAxel Dörfler 	}
6821e1553eSJérôme Duval 
695b2c5d03SAxel Dörfler 	*_cookie = info;
705b2c5d03SAxel Dörfler 	return 0.6f;
7121e1553eSJérôme Duval }
7221e1553eSJérôme Duval 
7321e1553eSJérôme Duval 
7421e1553eSJérôme Duval static status_t
7521e1553eSJérôme Duval fs_scan_partition(int fd, partition_data *partition, void *_cookie)
7621e1553eSJérôme Duval {
775b2c5d03SAxel Dörfler 	iso9660_info *info = (iso9660_info *)_cookie;
7821e1553eSJérôme Duval 
7921e1553eSJérôme Duval 	partition->status = B_PARTITION_VALID;
8021e1553eSJérôme Duval 	partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ;
8121e1553eSJérôme Duval 	partition->block_size = ISO_PVD_SIZE;
825b2c5d03SAxel Dörfler 	partition->content_size = ISO_PVD_SIZE * info->max_blocks;
835b2c5d03SAxel Dörfler 	partition->content_name = strdup(info->PreferredName());
845b2c5d03SAxel Dörfler 
8521e1553eSJérôme Duval 	if (partition->content_name == NULL)
8621e1553eSJérôme Duval 		return B_NO_MEMORY;
8721e1553eSJérôme Duval 
8821e1553eSJérôme Duval 	return B_OK;
8921e1553eSJérôme Duval }
9021e1553eSJérôme Duval 
9121e1553eSJérôme Duval 
9221e1553eSJérôme Duval static void
9321e1553eSJérôme Duval fs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
9421e1553eSJérôme Duval {
955b2c5d03SAxel Dörfler 	delete (iso9660_info *)_cookie;
9621e1553eSJérôme Duval }
9721e1553eSJérôme Duval 
9821e1553eSJérôme Duval 
99ff99132eSAxel Dörfler //	#pragma mark - FS hooks
100ff99132eSAxel Dörfler 
101ff99132eSAxel Dörfler 
10221e1553eSJérôme Duval static status_t
1030eaadd30SMichael Lotz fs_mount(fs_volume *_volume, const char *device, uint32 flags,
1040eaadd30SMichael Lotz 	const char *args, ino_t *_rootID)
10521e1553eSJérôme Duval {
1065b2c5d03SAxel Dörfler 	bool allowJoliet = true;
107ff99132eSAxel Dörfler 	nspace *volume;
10821e1553eSJérôme Duval 
10921e1553eSJérôme Duval 	// Check for a 'nojoliet' parm
11021e1553eSJérôme Duval 	// all we check for is the existance of 'nojoliet' in the parms.
11121e1553eSJérôme Duval 	if (args != NULL) {
11221e1553eSJérôme Duval 		uint32 i;
11321e1553eSJérôme Duval 		char *spot;
11421e1553eSJérôme Duval 		char *buf = strdup(args);
11521e1553eSJérôme Duval 
11621e1553eSJérôme Duval 		uint32 len = strlen(buf);
11721e1553eSJérôme Duval 		// lower case the parms data
11821e1553eSJérôme Duval 		for (i = 0; i < len + 1; i++)
11921e1553eSJérôme Duval 			buf[i] = tolower(buf[i]);
12021e1553eSJérôme Duval 
12121e1553eSJérôme Duval 		// look for nojoliet
12221e1553eSJérôme Duval 		spot = strstr(buf, "nojoliet");
12321e1553eSJérôme Duval 		if (spot != NULL)
1245b2c5d03SAxel Dörfler 			allowJoliet = false;
12521e1553eSJérôme Duval 
12621e1553eSJérôme Duval 		free(buf);
12721e1553eSJérôme Duval 	}
12821e1553eSJérôme Duval 
12921e1553eSJérôme Duval 	// Try and mount volume as an ISO volume.
130ff99132eSAxel Dörfler 	status_t result = ISOMount(device, O_RDONLY, &volume, allowJoliet);
131ff99132eSAxel Dörfler 	if (result == B_OK) {
13221e1553eSJérôme Duval 		*_rootID = ISO_ROOTNODE_ID;
13321e1553eSJérôme Duval 
1340eaadd30SMichael Lotz 		_volume->private_volume = volume;
1350eaadd30SMichael Lotz 		_volume->ops = &gISO9660VolumeOps;
1360eaadd30SMichael Lotz 		volume->volume = _volume;
1370eaadd30SMichael Lotz 		volume->id = _volume->id;
13821e1553eSJérôme Duval 
1390eaadd30SMichael Lotz 		result = publish_vnode(_volume, *_rootID, &volume->rootDirRec,
1400eaadd30SMichael Lotz 			&gISO9660VnodeOps, volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0);
141ff99132eSAxel Dörfler 		if (result != B_OK) {
142ff99132eSAxel Dörfler 			block_cache_delete(volume->fBlockCache, false);
143ff99132eSAxel Dörfler 			free(volume);
144ff99132eSAxel Dörfler 			result = B_ERROR;
145ff99132eSAxel Dörfler 		}
14621e1553eSJérôme Duval 	}
14721e1553eSJérôme Duval 	return result;
14821e1553eSJérôme Duval }
14921e1553eSJérôme Duval 
15021e1553eSJérôme Duval 
15121e1553eSJérôme Duval static status_t
1520eaadd30SMichael Lotz fs_unmount(fs_volume *_vol)
15321e1553eSJérôme Duval {
15421e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
1550eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
15621e1553eSJérôme Duval 
15721e1553eSJérôme Duval 	TRACE(("fs_unmount - ENTER\n"));
15821e1553eSJérôme Duval 
1599d254f45SJérôme Duval 	// Unlike in BeOS, we need to put the reference to our root node ourselves
1600eaadd30SMichael Lotz 	put_vnode(_vol, ISO_ROOTNODE_ID);
1619d254f45SJérôme Duval 
16221e1553eSJérôme Duval 	block_cache_delete(ns->fBlockCache, false);
16321e1553eSJérôme Duval 	close(ns->fdOfSession);
16421e1553eSJérôme Duval 	result = close(ns->fd);
16521e1553eSJérôme Duval 
16621e1553eSJérôme Duval 	free(ns);
16721e1553eSJérôme Duval 
16821e1553eSJérôme Duval 	TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result)));
16921e1553eSJérôme Duval 	return result;
17021e1553eSJérôme Duval }
17121e1553eSJérôme Duval 
17221e1553eSJérôme Duval 
17321e1553eSJérôme Duval static status_t
1740eaadd30SMichael Lotz fs_read_fs_stat(fs_volume *_vol, struct fs_info *fss)
17521e1553eSJérôme Duval {
1760eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
17721e1553eSJérôme Duval 	int i;
17821e1553eSJérôme Duval 
17921e1553eSJérôme Duval 	fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
18021e1553eSJérôme Duval 	fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT];
18121e1553eSJérôme Duval 	fss->io_size = 65536;
18221e1553eSJérôme Duval 	fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT];
18321e1553eSJérôme Duval 	fss->free_blocks = 0;
18421e1553eSJérôme Duval 
18521e1553eSJérôme Duval 	strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name));
18621e1553eSJérôme Duval 
18721e1553eSJérôme Duval 	strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name));
188ff99132eSAxel Dörfler 	for (i = strlen(fss->volume_name) - 1; i >=0 ; i--) {
18921e1553eSJérôme Duval 		if (fss->volume_name[i] != ' ')
19021e1553eSJérôme Duval 			break;
191ff99132eSAxel Dörfler 	}
19221e1553eSJérôme Duval 
19321e1553eSJérôme Duval 	if (i < 0)
19421e1553eSJérôme Duval 		strcpy(fss->volume_name, "UNKNOWN");
19521e1553eSJérôme Duval 	else
19621e1553eSJérôme Duval 		fss->volume_name[i + 1] = 0;
19721e1553eSJérôme Duval 
19821e1553eSJérôme Duval 	strcpy(fss->fsh_name, "iso9660");
199ff99132eSAxel Dörfler 	return B_OK;
20021e1553eSJérôme Duval }
20121e1553eSJérôme Duval 
2023b723f79SJérôme Duval 
2033b723f79SJérôme Duval static status_t
2040eaadd30SMichael Lotz fs_get_vnode_name(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t bufferSize)
2053b723f79SJérôme Duval {
2060eaadd30SMichael Lotz 	vnode *node = (vnode*)_node->private_node;
2073b723f79SJérôme Duval 
2083b723f79SJérôme Duval 	strlcpy(buffer, node->fileIDString, bufferSize);
2093b723f79SJérôme Duval 	return B_OK;
2103b723f79SJérôme Duval }
2113b723f79SJérôme Duval 
2123b723f79SJérôme Duval 
21321e1553eSJérôme Duval static status_t
2140eaadd30SMichael Lotz fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
21521e1553eSJérôme Duval {
2160eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
2170eaadd30SMichael Lotz 	vnode *baseNode = (vnode*)_base->private_node;
21821e1553eSJérôme Duval 	vnode *newNode = NULL;
21921e1553eSJérôme Duval 
22021e1553eSJérôme Duval 	TRACE(("fs_walk - looking for %s in dir file of length %d\n", file,
22121e1553eSJérôme Duval 		baseNode->dataLen[FS_DATA_FORMAT]));
22221e1553eSJérôme Duval 
22321e1553eSJérôme Duval 	if (strcmp(file, ".") == 0)  {
22421e1553eSJérôme Duval 		// base directory
22521e1553eSJérôme Duval 		TRACE(("fs_walk - found \".\" file.\n"));
22621e1553eSJérôme Duval 		*_vnodeID = baseNode->id;
2270eaadd30SMichael Lotz 		return get_vnode(_vol, *_vnodeID, (void **)&newNode);
22821e1553eSJérôme Duval 	} else if (strcmp(file, "..") == 0) {
22921e1553eSJérôme Duval 		// parent directory
23021e1553eSJérôme Duval 		TRACE(("fs_walk - found \"..\" file.\n"));
23121e1553eSJérôme Duval 		*_vnodeID = baseNode->parID;
2320eaadd30SMichael Lotz 		return get_vnode(_vol, *_vnodeID, (void **)&newNode);
233ff99132eSAxel Dörfler 	}
234ff99132eSAxel Dörfler 
23521e1553eSJérôme Duval 	// look up file in the directory
236ff99132eSAxel Dörfler 	uint32 dataLength = baseNode->dataLen[FS_DATA_FORMAT];
237ff99132eSAxel Dörfler 	status_t result = ENOENT;
238ff99132eSAxel Dörfler 	uint32 totalRead = 0;
239ff99132eSAxel Dörfler 	off_t block = baseNode->startLBN[FS_DATA_FORMAT];
240ff99132eSAxel Dörfler 	bool done = false;
24121e1553eSJérôme Duval 
242ff99132eSAxel Dörfler 	while (totalRead < dataLength && !done) {
24321e1553eSJérôme Duval 		off_t cachedBlock = block;
244ff99132eSAxel Dörfler 		char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0,
245ff99132eSAxel Dörfler 			ns->logicalBlkSize[FS_DATA_FORMAT]);
24621e1553eSJérôme Duval 		if (blockData != NULL) {
24721e1553eSJérôme Duval 			int bytesRead = 0;
24821e1553eSJérôme Duval 			off_t blockBytesRead = 0;
24921e1553eSJérôme Duval 			vnode node;
25021e1553eSJérôme Duval 			int initResult;
25121e1553eSJérôme Duval 
25221e1553eSJérôme Duval 			TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n",
25321e1553eSJérôme Duval 				block, blockData));
25421e1553eSJérôme Duval 
25521e1553eSJérôme Duval 			// Move to the next 2-block set if necessary
25621e1553eSJérôme Duval 			// Don't go over end of buffer, if dir record sits on boundary.
25721e1553eSJérôme Duval 
25821e1553eSJérôme Duval 			node.fileIDString = NULL;
25921e1553eSJérôme Duval 			node.attr.slName = NULL;
26021e1553eSJérôme Duval 
26121e1553eSJérôme Duval 			while (blockBytesRead < 2 * ns->logicalBlkSize[FS_DATA_FORMAT]
262ff99132eSAxel Dörfler 				&& totalRead + blockBytesRead < dataLength
26321e1553eSJérôme Duval 				&& blockData[0] != 0
264ff99132eSAxel Dörfler 				&& !done) {
265ff99132eSAxel Dörfler 				initResult = InitNode(&node, blockData, &bytesRead,
266ff99132eSAxel Dörfler 					ns->joliet_level);
26721e1553eSJérôme Duval 				TRACE(("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead));
26821e1553eSJérôme Duval 
269ff99132eSAxel Dörfler 				if (initResult == B_OK) {
270ff99132eSAxel Dörfler 					if (!strcmp(node.fileIDString, file)) {
27121e1553eSJérôme Duval 						TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead));
272ff99132eSAxel Dörfler 						*_vnodeID = (block << 30)
273ff99132eSAxel Dörfler 							+ (blockBytesRead & 0xffffffff);
27421e1553eSJérôme Duval 						TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID));
27521e1553eSJérôme Duval 
2760eaadd30SMichael Lotz 						result = get_vnode(_vol, *_vnodeID,
277ff99132eSAxel Dörfler 							(void **)&newNode);
278ff99132eSAxel Dörfler 						if (result == B_OK) {
27921e1553eSJérôme Duval 							newNode->parID = baseNode->id;
280ff99132eSAxel Dörfler 							done = true;
28121e1553eSJérôme Duval 						}
28221e1553eSJérôme Duval 					} else {
28321e1553eSJérôme Duval 						free(node.fileIDString);
28421e1553eSJérôme Duval 						node.fileIDString = NULL;
28521e1553eSJérôme Duval 						free(node.attr.slName);
28621e1553eSJérôme Duval 						node.attr.slName = NULL;
28721e1553eSJérôme Duval 					}
28821e1553eSJérôme Duval 				} else {
28921e1553eSJérôme Duval 					result = initResult;
29021e1553eSJérôme Duval 					if (bytesRead == 0)
29121e1553eSJérôme Duval 						done = TRUE;
29221e1553eSJérôme Duval 				}
29321e1553eSJérôme Duval 				blockData += bytesRead;
29421e1553eSJérôme Duval 				blockBytesRead += bytesRead;
29521e1553eSJérôme Duval 
29621e1553eSJérôme Duval 				TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n",
29721e1553eSJérôme Duval 					bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]));
29821e1553eSJérôme Duval 			}
29921e1553eSJérôme Duval 			totalRead += ns->logicalBlkSize[FS_DATA_FORMAT];
30021e1553eSJérôme Duval 			block++;
30121e1553eSJérôme Duval 
30221e1553eSJérôme Duval 			TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead));
30321e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, cachedBlock);
30421e1553eSJérôme Duval 
30521e1553eSJérôme Duval 		} else
30621e1553eSJérôme Duval 			done = TRUE;
30721e1553eSJérôme Duval 	}
30821e1553eSJérôme Duval 
309ff99132eSAxel Dörfler 	TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n",
310ff99132eSAxel Dörfler 		strerror(result), *_vnodeID));
31121e1553eSJérôme Duval 	return result;
31221e1553eSJérôme Duval }
31321e1553eSJérôme Duval 
31421e1553eSJérôme Duval 
31521e1553eSJérôme Duval static status_t
3160eaadd30SMichael Lotz fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node,
3170eaadd30SMichael Lotz 	int *_type, uint32 *_flags, bool reenter)
31821e1553eSJérôme Duval {
3190eaadd30SMichael Lotz 	nspace *ns = (nspace*)_vol->private_volume;
320ff99132eSAxel Dörfler 
32121e1553eSJérôme Duval 	vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
322ff99132eSAxel Dörfler 	if (newNode == NULL)
323ff99132eSAxel Dörfler 		return B_NO_MEMORY;
32421e1553eSJérôme Duval 
325ff99132eSAxel Dörfler 	uint32 pos = vnodeID & 0x3fffffff;
326ff99132eSAxel Dörfler 	uint32 block = vnodeID >> 30;
32721e1553eSJérôme Duval 
328ff99132eSAxel Dörfler 	TRACE(("fs_read_vnode - block = %ld, pos = %ld, raw = %Lu node 0x%x\n",
329ff99132eSAxel Dörfler 		block, pos, vnodeID, newNode));
33021e1553eSJérôme Duval 
331*d02cde30SMichael Lotz 	if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
332*d02cde30SMichael Lotz 		free(newNode);
333ff99132eSAxel Dörfler 		return B_BAD_VALUE;
334*d02cde30SMichael Lotz 	}
33521e1553eSJérôme Duval 
336ff99132eSAxel Dörfler 	char *data = (char *)block_cache_get_etc(ns->fBlockCache,
337ff99132eSAxel Dörfler 		block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
338ff99132eSAxel Dörfler 	if (data == NULL) {
339ff99132eSAxel Dörfler 		free(newNode);
340ff99132eSAxel Dörfler 		return B_IO_ERROR;
341ff99132eSAxel Dörfler 	}
34221e1553eSJérôme Duval 
343ff99132eSAxel Dörfler 	status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level);
34421e1553eSJérôme Duval 	block_cache_put(ns->fBlockCache, block);
34521e1553eSJérôme Duval 
346ff99132eSAxel Dörfler 	if (result < B_OK) {
347ff99132eSAxel Dörfler 		free(newNode);
348ff99132eSAxel Dörfler 		return result;
34921e1553eSJérôme Duval 	}
35021e1553eSJérôme Duval 
351ff99132eSAxel Dörfler 	newNode->id = vnodeID;
3520eaadd30SMichael Lotz 	_node->private_node = newNode;
3530eaadd30SMichael Lotz 	_node->ops = &gISO9660VnodeOps;
3540eaadd30SMichael Lotz 	*_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH);
3550eaadd30SMichael Lotz 	*_flags = 0;
356ff99132eSAxel Dörfler 
357ff99132eSAxel Dörfler 	if ((newNode->flags & ISO_ISDIR) == 0) {
358ff99132eSAxel Dörfler 		newNode->cache = file_cache_create(ns->id, vnodeID,
3593d268edaSAxel Dörfler 			newNode->dataLen[FS_DATA_FORMAT]);
3605b4cb109SJérôme Duval 	}
3615b4cb109SJérôme Duval 
362ff99132eSAxel Dörfler 	return B_OK;
36321e1553eSJérôme Duval }
36421e1553eSJérôme Duval 
36521e1553eSJérôme Duval 
36621e1553eSJérôme Duval static status_t
3670eaadd30SMichael Lotz fs_release_vnode(fs_volume *_vol, fs_vnode *_node, bool reenter)
36821e1553eSJérôme Duval {
36921e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
3700eaadd30SMichael Lotz 	vnode *node = (vnode*)_node->private_node;
37121e1553eSJérôme Duval 
3720eaadd30SMichael Lotz 	(void)_vol;
37321e1553eSJérôme Duval 	(void)reenter;
37421e1553eSJérôme Duval 
3755b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - ENTER (0x%x)\n", node));
37621e1553eSJérôme Duval 
37721e1553eSJérôme Duval 	if (node != NULL) {
37821e1553eSJérôme Duval 		if (node->id != ISO_ROOTNODE_ID) {
37921e1553eSJérôme Duval 			if (node->fileIDString != NULL)
38021e1553eSJérôme Duval 				free (node->fileIDString);
38121e1553eSJérôme Duval 			if (node->attr.slName != NULL)
38221e1553eSJérôme Duval 				free (node->attr.slName);
3835b4cb109SJérôme Duval 			if (node->cache != NULL)
3845b4cb109SJérôme Duval 				file_cache_delete(node->cache);
38521e1553eSJérôme Duval 
38621e1553eSJérôme Duval 			free(node);
38721e1553eSJérôme Duval 		}
38821e1553eSJérôme Duval 	}
38921e1553eSJérôme Duval 
3905b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - EXIT\n"));
39121e1553eSJérôme Duval 	return result;
39221e1553eSJérôme Duval }
39321e1553eSJérôme Duval 
39421e1553eSJérôme Duval 
39521e1553eSJérôme Duval static status_t
3960eaadd30SMichael Lotz fs_read_pages(fs_volume *_vol, fs_vnode *_node, void * _cookie, off_t pos,
397e6bd90c5SIngo Weinhold 	const iovec *vecs, size_t count, size_t *_numBytes)
3985b4cb109SJérôme Duval {
3990eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
4000eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
4015b4cb109SJérôme Duval 
402ff99132eSAxel Dörfler 	uint32 fileSize = node->dataLen[FS_DATA_FORMAT];
403ff99132eSAxel Dörfler 	size_t bytesLeft = *_numBytes;
4045b4cb109SJérôme Duval 
405ff99132eSAxel Dörfler 	if (pos >= fileSize) {
406ff99132eSAxel Dörfler 		*_numBytes = 0;
4075b4cb109SJérôme Duval 		return B_OK;
4085b4cb109SJérôme Duval 	}
409ff99132eSAxel Dörfler 	if (pos + bytesLeft > fileSize) {
410ff99132eSAxel Dörfler 		bytesLeft = fileSize - pos;
411ff99132eSAxel Dörfler 		*_numBytes = bytesLeft;
4125b4cb109SJérôme Duval 	}
4135b4cb109SJérôme Duval 
414ff99132eSAxel Dörfler 	file_io_vec fileVec;
415ff99132eSAxel Dörfler 	fileVec.offset = pos + node->startLBN[FS_DATA_FORMAT]
416ff99132eSAxel Dörfler 		* ns->logicalBlkSize[FS_DATA_FORMAT];
417ff99132eSAxel Dörfler 	fileVec.length = bytesLeft;
4185b4cb109SJérôme Duval 
419ff99132eSAxel Dörfler 	uint32 vecIndex = 0;
420ff99132eSAxel Dörfler 	size_t vecOffset = 0;
421ff99132eSAxel Dörfler 	return read_file_io_vec_pages(ns->fd, &fileVec, 1, vecs, count,
422ff99132eSAxel Dörfler 		&vecIndex, &vecOffset, &bytesLeft);
4235b4cb109SJérôme Duval }
4245b4cb109SJérôme Duval 
4255b4cb109SJérôme Duval 
4265b4cb109SJérôme Duval static status_t
4270eaadd30SMichael Lotz fs_read_stat(fs_volume *_vol, fs_vnode *_node, struct stat *st)
42821e1553eSJérôme Duval {
4290eaadd30SMichael Lotz 	nspace *ns = (nspace*)_vol->private_volume;
4300eaadd30SMichael Lotz 	vnode *node = (vnode*)_node->private_node;
4313b723f79SJérôme Duval 	status_t result = B_NO_ERROR;
43221e1553eSJérôme Duval 	time_t time;
43321e1553eSJérôme Duval 
4343b723f79SJérôme Duval 	TRACE(("fs_read_stat - ENTER\n"));
43521e1553eSJérôme Duval 
43621e1553eSJérôme Duval 	st->st_dev = ns->id;
43721e1553eSJérôme Duval 	st->st_ino = node->id;
43821e1553eSJérôme Duval 	st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink;
43921e1553eSJérôme Duval 	st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid;
44021e1553eSJérôme Duval 	st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid;
44121e1553eSJérôme Duval 	st->st_blksize = 65536;
44221e1553eSJérôme Duval 	st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode;
44321e1553eSJérôme Duval 
44421e1553eSJérôme Duval 	// Same for file/dir in ISO9660
44521e1553eSJérôme Duval 	st->st_size = node->dataLen[FS_DATA_FORMAT];
44621e1553eSJérôme Duval 	if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR)
44721e1553eSJérôme Duval 		st->st_ctime = st->st_mtime = st->st_atime = time;
44821e1553eSJérôme Duval 
4493b723f79SJérôme Duval 	TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result)));
45021e1553eSJérôme Duval 
45121e1553eSJérôme Duval 	return result;
45221e1553eSJérôme Duval }
45321e1553eSJérôme Duval 
45421e1553eSJérôme Duval 
45521e1553eSJérôme Duval static status_t
4560eaadd30SMichael Lotz fs_open(fs_volume *_vol, fs_vnode *_node, int omode, void **cookie)
45721e1553eSJérôme Duval {
45821e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
45921e1553eSJérôme Duval 
4600eaadd30SMichael Lotz 	(void)_vol;
46121e1553eSJérôme Duval 	(void)cookie;
46221e1553eSJérôme Duval 
46321e1553eSJérôme Duval 	// Do not allow any of the write-like open modes to get by
46421e1553eSJérôme Duval 	if ((omode == O_WRONLY) || (omode == O_RDWR))
46521e1553eSJérôme Duval 		result = EROFS;
46621e1553eSJérôme Duval 	else if((omode & O_TRUNC) || (omode & O_CREAT))
46721e1553eSJérôme Duval 		result = EROFS;
46821e1553eSJérôme Duval 
46921e1553eSJérôme Duval 	return result;
47021e1553eSJérôme Duval }
47121e1553eSJérôme Duval 
47221e1553eSJérôme Duval 
47321e1553eSJérôme Duval static status_t
4740eaadd30SMichael Lotz fs_read(fs_volume *_vol, fs_vnode *_node, void *cookie, off_t pos, void *buffer,
475ff99132eSAxel Dörfler 	size_t *_length)
47621e1553eSJérôme Duval {
4770eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
47821e1553eSJérôme Duval 
47921e1553eSJérôme Duval 	if (node->flags & ISO_ISDIR)
48021e1553eSJérôme Duval 		return EISDIR;
48121e1553eSJérôme Duval 
482ff99132eSAxel Dörfler 	uint32 fileSize = node->dataLen[FS_DATA_FORMAT];
4835b4cb109SJérôme Duval 
4845b4cb109SJérôme Duval 	// set/check boundaries for pos/length
485ff99132eSAxel Dörfler 	if (pos < 0)
4865b4cb109SJérôme Duval 		return B_BAD_VALUE;
487ff99132eSAxel Dörfler 	if (pos >= fileSize) {
488ff99132eSAxel Dörfler 		*_length = 0;
4895b4cb109SJérôme Duval 		return B_OK;
4905b4cb109SJérôme Duval 	}
491ff99132eSAxel Dörfler 
492ff99132eSAxel Dörfler 	return file_cache_read(node->cache, NULL, pos, buffer, _length);
49321e1553eSJérôme Duval }
49421e1553eSJérôme Duval 
49521e1553eSJérôme Duval 
49621e1553eSJérôme Duval static status_t
4970eaadd30SMichael Lotz fs_close(fs_volume *_vol, fs_vnode *_node, void *cookie)
49821e1553eSJérôme Duval {
4990eaadd30SMichael Lotz 	(void)_vol;
5000eaadd30SMichael Lotz 	(void)_node;
50121e1553eSJérôme Duval 	(void)cookie;
50221e1553eSJérôme Duval 
50321e1553eSJérôme Duval 	return B_OK;
50421e1553eSJérôme Duval }
50521e1553eSJérôme Duval 
506ff99132eSAxel Dörfler 
50721e1553eSJérôme Duval static status_t
5080eaadd30SMichael Lotz fs_free_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie)
50921e1553eSJérôme Duval {
5100eaadd30SMichael Lotz 	(void)_vol;
5110eaadd30SMichael Lotz 	(void)_node;
51221e1553eSJérôme Duval 	(void)cookie;
51321e1553eSJérôme Duval 
51421e1553eSJérôme Duval 	return B_OK;
51521e1553eSJérôme Duval }
51621e1553eSJérôme Duval 
517ff99132eSAxel Dörfler 
51821e1553eSJérôme Duval static status_t
5190eaadd30SMichael Lotz fs_access(fs_volume *_vol, fs_vnode *_node, int mode)
52021e1553eSJérôme Duval {
5210eaadd30SMichael Lotz 	(void)_vol;
5220eaadd30SMichael Lotz 	(void)_node;
52321e1553eSJérôme Duval 	(void)mode;
52421e1553eSJérôme Duval 
52521e1553eSJérôme Duval 	return B_OK;
52621e1553eSJérôme Duval }
52721e1553eSJérôme Duval 
528ff99132eSAxel Dörfler 
52921e1553eSJérôme Duval static status_t
5300eaadd30SMichael Lotz fs_read_link(fs_volume *_vol, fs_vnode *_node, char *buffer, size_t *_bufferSize)
53121e1553eSJérôme Duval {
5320eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
53321e1553eSJérôme Duval 
534ff99132eSAxel Dörfler 	if (!S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode))
535ff99132eSAxel Dörfler 		return B_BAD_VALUE;
53621e1553eSJérôme Duval 
53721e1553eSJérôme Duval 	size_t length = strlen(node->attr.slName);
53821e1553eSJérôme Duval 	if (length > *_bufferSize)
5393b723f79SJérôme Duval 		memcpy(buffer, node->attr.slName, *_bufferSize);
5403b723f79SJérôme Duval 	else {
54121e1553eSJérôme Duval 		memcpy(buffer, node->attr.slName, length);
5423b723f79SJérôme Duval 		*_bufferSize = length;
5433b723f79SJérôme Duval 	}
54421e1553eSJérôme Duval 
545ff99132eSAxel Dörfler 	return B_OK;
54621e1553eSJérôme Duval }
54721e1553eSJérôme Duval 
54821e1553eSJérôme Duval 
54921e1553eSJérôme Duval static status_t
5500eaadd30SMichael Lotz fs_open_dir(fs_volume *_vol, fs_vnode *_node, void **cookie)
55121e1553eSJérôme Duval {
5520eaadd30SMichael Lotz 	vnode *node = (vnode *)_node->private_node;
55321e1553eSJérôme Duval 
554ff99132eSAxel Dörfler 	TRACE(("fs_open_dir - node is 0x%x\n", _node));
55521e1553eSJérôme Duval 
55621e1553eSJérôme Duval 	if (!(node->flags & ISO_ISDIR))
557ff99132eSAxel Dörfler 		return B_NOT_A_DIRECTORY;
55821e1553eSJérôme Duval 
559ff99132eSAxel Dörfler 	dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
560ff99132eSAxel Dörfler 	if (dirCookie == NULL)
561ff99132eSAxel Dörfler 		return B_NO_MEMORY;
562ff99132eSAxel Dörfler 
56321e1553eSJérôme Duval 	dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT];
56421e1553eSJérôme Duval 	dirCookie->block = node->startLBN[FS_DATA_FORMAT];
56521e1553eSJérôme Duval 	dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
56621e1553eSJérôme Duval 	dirCookie->pos = 0;
56721e1553eSJérôme Duval 	dirCookie->id = node->id;
56821e1553eSJérôme Duval 	*cookie = (void *)dirCookie;
56921e1553eSJérôme Duval 
570ff99132eSAxel Dörfler 	return B_OK;
57121e1553eSJérôme Duval }
57221e1553eSJérôme Duval 
57321e1553eSJérôme Duval 
57421e1553eSJérôme Duval static status_t
57544d0dbc8SAxel Dörfler fs_read_dir(fs_volume *_vol, fs_vnode *_node, void *_cookie,
57644d0dbc8SAxel Dörfler 	struct dirent *buffer, size_t bufferSize, uint32 *num)
57721e1553eSJérôme Duval {
5780eaadd30SMichael Lotz 	nspace *ns = (nspace *)_vol->private_volume;
57921e1553eSJérôme Duval 	dircookie *dirCookie = (dircookie *)_cookie;
58021e1553eSJérôme Duval 
5815b4cb109SJérôme Duval 	TRACE(("fs_read_dir - ENTER\n"));
58221e1553eSJérôme Duval 
583ff99132eSAxel Dörfler 	status_t result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize);
58421e1553eSJérôme Duval 
58521e1553eSJérôme Duval 	// If we succeeded, return 1, the number of dirents we read.
586ff99132eSAxel Dörfler 	if (result == B_OK)
58721e1553eSJérôme Duval 		*num = 1;
58821e1553eSJérôme Duval 	else
58921e1553eSJérôme Duval 		*num = 0;
59021e1553eSJérôme Duval 
59121e1553eSJérôme Duval 	// When you get to the end, don't return an error, just return
59221e1553eSJérôme Duval 	// a zero in *num.
59321e1553eSJérôme Duval 
59421e1553eSJérôme Duval 	if (result == ENOENT)
595ff99132eSAxel Dörfler 		result = B_OK;
59621e1553eSJérôme Duval 
5975b4cb109SJérôme Duval 	TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result)));
59821e1553eSJérôme Duval 	return result;
59921e1553eSJérôme Duval }
60021e1553eSJérôme Duval 
60121e1553eSJérôme Duval 
60221e1553eSJérôme Duval static status_t
6030eaadd30SMichael Lotz fs_rewind_dir(fs_volume *_vol, fs_vnode *_node, void* _cookie)
60421e1553eSJérôme Duval {
60521e1553eSJérôme Duval 	dircookie *cookie = (dircookie*)_cookie;
60621e1553eSJérôme Duval 
60721e1553eSJérôme Duval 	cookie->block = cookie->startBlock;
60821e1553eSJérôme Duval 	cookie->pos = 0;
609ff99132eSAxel Dörfler 	return B_OK;
61021e1553eSJérôme Duval }
61121e1553eSJérôme Duval 
61221e1553eSJérôme Duval 
61321e1553eSJérôme Duval static status_t
6140eaadd30SMichael Lotz fs_close_dir(fs_volume *_vol, fs_vnode *_node, void *cookie)
61521e1553eSJérôme Duval {
61621e1553eSJérôme Duval 	return B_OK;
61721e1553eSJérôme Duval }
61821e1553eSJérôme Duval 
61921e1553eSJérôme Duval 
62021e1553eSJérôme Duval static status_t
6210eaadd30SMichael Lotz fs_free_dir_cookie(fs_volume *_vol, fs_vnode *_node, void *cookie)
62221e1553eSJérôme Duval {
62321e1553eSJérôme Duval 	free(cookie);
62421e1553eSJérôme Duval 	return B_OK;
62521e1553eSJérôme Duval }
62621e1553eSJérôme Duval 
627ff99132eSAxel Dörfler 
62821e1553eSJérôme Duval //	#pragma mark -
62921e1553eSJérôme Duval 
63021e1553eSJérôme Duval 
63121e1553eSJérôme Duval static status_t
63221e1553eSJérôme Duval iso_std_ops(int32 op, ...)
63321e1553eSJérôme Duval {
63421e1553eSJérôme Duval 	switch (op) {
63521e1553eSJérôme Duval 		case B_MODULE_INIT:
63621e1553eSJérôme Duval 		case B_MODULE_UNINIT:
63721e1553eSJérôme Duval 			return B_OK;
63821e1553eSJérôme Duval 		default:
63921e1553eSJérôme Duval 			return B_ERROR;
64021e1553eSJérôme Duval 	}
64121e1553eSJérôme Duval }
64221e1553eSJérôme Duval 
64321e1553eSJérôme Duval 
6440eaadd30SMichael Lotz fs_volume_ops gISO9660VolumeOps = {
6450eaadd30SMichael Lotz 	&fs_unmount,
6460eaadd30SMichael Lotz 	&fs_read_fs_stat,
6470eaadd30SMichael Lotz 	NULL,
6480eaadd30SMichael Lotz 	NULL,
6490eaadd30SMichael Lotz 	&fs_read_vnode,
6500eaadd30SMichael Lotz 
6510eaadd30SMichael Lotz 	/* index and index directory ops */
6520eaadd30SMichael Lotz 	NULL,
6530eaadd30SMichael Lotz 	NULL,
6540eaadd30SMichael Lotz 	NULL,
6550eaadd30SMichael Lotz 	NULL,
6560eaadd30SMichael Lotz 	NULL,
6570eaadd30SMichael Lotz 	NULL,
6580eaadd30SMichael Lotz 	NULL,
6590eaadd30SMichael Lotz 	NULL,
6600eaadd30SMichael Lotz 
6610eaadd30SMichael Lotz 	/* query ops */
6620eaadd30SMichael Lotz 	NULL,
6630eaadd30SMichael Lotz 	NULL,
6640eaadd30SMichael Lotz 	NULL,
6650eaadd30SMichael Lotz 	NULL,
6660eaadd30SMichael Lotz 	NULL,
6670eaadd30SMichael Lotz 
6680eaadd30SMichael Lotz 	/* FS layer ops */
6690eaadd30SMichael Lotz 	NULL,
6700eaadd30SMichael Lotz 	NULL,
6710eaadd30SMichael Lotz };
6720eaadd30SMichael Lotz 
6730eaadd30SMichael Lotz fs_vnode_ops gISO9660VnodeOps = {
6740eaadd30SMichael Lotz 	&fs_walk,
6750eaadd30SMichael Lotz 	&fs_get_vnode_name,
6760eaadd30SMichael Lotz 	&fs_release_vnode,
6770eaadd30SMichael Lotz 	NULL,
6780eaadd30SMichael Lotz 
6790eaadd30SMichael Lotz 	/* vm-related ops */
6800eaadd30SMichael Lotz 	NULL,
6810eaadd30SMichael Lotz 	&fs_read_pages,
6820eaadd30SMichael Lotz 	NULL,
6830eaadd30SMichael Lotz 
684ec598fe4SIngo Weinhold 	NULL,	// io()
685ec598fe4SIngo Weinhold 	NULL,	// cancel_io()
686ec598fe4SIngo Weinhold 
6870eaadd30SMichael Lotz 	/* cache file access */
6880eaadd30SMichael Lotz 	NULL,
6890eaadd30SMichael Lotz 
6900eaadd30SMichael Lotz 	/* common */
6910eaadd30SMichael Lotz 	NULL,
6920eaadd30SMichael Lotz 	NULL,
6930eaadd30SMichael Lotz 	NULL,
6940eaadd30SMichael Lotz 	NULL,
6950eaadd30SMichael Lotz 	NULL,
6960eaadd30SMichael Lotz 	&fs_read_link,
6970eaadd30SMichael Lotz 	NULL,
6980eaadd30SMichael Lotz 	NULL,
6990eaadd30SMichael Lotz 	NULL,
7000eaadd30SMichael Lotz 	NULL,
7010eaadd30SMichael Lotz 	&fs_access,
7020eaadd30SMichael Lotz 	&fs_read_stat,
7030eaadd30SMichael Lotz 	NULL,
7040eaadd30SMichael Lotz 
7050eaadd30SMichael Lotz 	/* file */
7060eaadd30SMichael Lotz 	NULL,
7070eaadd30SMichael Lotz 	&fs_open,
7080eaadd30SMichael Lotz 	&fs_close,
7090eaadd30SMichael Lotz 	&fs_free_cookie,
7100eaadd30SMichael Lotz 	&fs_read,
7110eaadd30SMichael Lotz 	NULL,
7120eaadd30SMichael Lotz 
7130eaadd30SMichael Lotz 	/* dir */
7140eaadd30SMichael Lotz 	NULL,
7150eaadd30SMichael Lotz 	NULL,
7160eaadd30SMichael Lotz 	&fs_open_dir,
7170eaadd30SMichael Lotz 	&fs_close_dir,
7180eaadd30SMichael Lotz 	&fs_free_dir_cookie,
7190eaadd30SMichael Lotz 	&fs_read_dir,
7200eaadd30SMichael Lotz 	&fs_rewind_dir,
7210eaadd30SMichael Lotz 
7220eaadd30SMichael Lotz 	/* attribute directory ops */
7230eaadd30SMichael Lotz 	NULL,
7240eaadd30SMichael Lotz 	NULL,
7250eaadd30SMichael Lotz 	NULL,
7260eaadd30SMichael Lotz 	NULL,
7270eaadd30SMichael Lotz 	NULL,
7280eaadd30SMichael Lotz 
7290eaadd30SMichael Lotz 	/* attribute ops */
7300eaadd30SMichael Lotz 	NULL,
7310eaadd30SMichael Lotz 	NULL,
7320eaadd30SMichael Lotz 	NULL,
7330eaadd30SMichael Lotz 	NULL,
7340eaadd30SMichael Lotz 	NULL,
7350eaadd30SMichael Lotz 	NULL,
7360eaadd30SMichael Lotz 	NULL,
7370eaadd30SMichael Lotz 	NULL,
7380eaadd30SMichael Lotz 	NULL,
7390eaadd30SMichael Lotz 	NULL,
7400eaadd30SMichael Lotz 
7410eaadd30SMichael Lotz 	/* node and FS layer support */
7420eaadd30SMichael Lotz 	NULL,
7430eaadd30SMichael Lotz 	NULL,
7440eaadd30SMichael Lotz };
7450eaadd30SMichael Lotz 
74621e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = {
74721e1553eSJérôme Duval 	{
74821e1553eSJérôme Duval 		"file_systems/iso9660" B_CURRENT_FS_API_VERSION,
74921e1553eSJérôme Duval 		0,
75021e1553eSJérôme Duval 		iso_std_ops,
75121e1553eSJérôme Duval 	},
75221e1553eSJérôme Duval 
7531da9f5ceSAxel Dörfler 	"iso9660",					// short_name
7541da9f5ceSAxel Dörfler 	"ISO9660 File System",		// pretty_name
75576a8ec23SIngo Weinhold 	0,							// DDM flags
75621e1553eSJérôme Duval 
75721e1553eSJérôme Duval 	// scanning
75821e1553eSJérôme Duval 	fs_identify_partition,
75921e1553eSJérôme Duval 	fs_scan_partition,
76021e1553eSJérôme Duval 	fs_free_identify_partition_cookie,
76121e1553eSJérôme Duval 	NULL,	// free_partition_content_cookie()
76221e1553eSJérôme Duval 
76321e1553eSJérôme Duval 	&fs_mount,
7640eaadd30SMichael Lotz 
7650eaadd30SMichael Lotz 	/* capability querying */
7660eaadd30SMichael Lotz 	NULL,
7670eaadd30SMichael Lotz 	NULL,
7680eaadd30SMichael Lotz 	NULL,
7690eaadd30SMichael Lotz 	NULL,
77021e1553eSJérôme Duval 	NULL,
77121e1553eSJérôme Duval 	NULL,
77221e1553eSJérôme Duval 
7730eaadd30SMichael Lotz 	/* shadow partition modifications */
7740eaadd30SMichael Lotz 	NULL,
77521e1553eSJérôme Duval 
7760eaadd30SMichael Lotz 	/* writing */
7770eaadd30SMichael Lotz 	NULL,
7780eaadd30SMichael Lotz 	NULL,
7790eaadd30SMichael Lotz 	NULL,
7800eaadd30SMichael Lotz 	NULL,
7810eaadd30SMichael Lotz 	NULL,
7820eaadd30SMichael Lotz 	NULL,
7830eaadd30SMichael Lotz 	NULL,
78421e1553eSJérôme Duval };
78521e1553eSJérôme Duval 
78621e1553eSJérôme Duval module_info *modules[] = {
78721e1553eSJérôme Duval 	(module_info *)&sISO660FileSystem,
78821e1553eSJérôme Duval 	NULL,
78921e1553eSJérôme Duval };
79021e1553eSJérôme Duval 
791