xref: /haiku/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp (revision 41b19806916cc348ced2be49fd2779e6bc55e7c9)
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