xref: /haiku/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp (revision 5b4cb1093258d3f87512e1538bf78742871243c3)
121e1553eSJérôme Duval /*
221e1553eSJérôme Duval **		Copyright 1999, Be Incorporated.   All Rights Reserved.
321e1553eSJérôme Duval **		This file may be used under the terms of the Be Sample Code License.
421e1553eSJérôme Duval **
521e1553eSJérôme Duval **		Copyright 2001, pinc Software.  All Rights Reserved.
621e1553eSJérôme Duval **
721e1553eSJérôme Duval **		iso9960/multi-session, 1.0.0
821e1553eSJérôme Duval **			2001-03-11: added multi-session support, axeld.
921e1553eSJérôme Duval */
1021e1553eSJérôme Duval 
1121e1553eSJérôme Duval #include <stdlib.h>
1221e1553eSJérôme Duval #include <unistd.h>
1321e1553eSJérôme Duval #include <fcntl.h>
1421e1553eSJérôme Duval #include <errno.h>
1521e1553eSJérôme Duval #include <string.h>
1621e1553eSJérôme Duval #include <ctype.h>
1721e1553eSJérôme Duval #include <stdio.h>
1821e1553eSJérôme Duval #include <dirent.h>
1921e1553eSJérôme Duval #include <sys/stat.h>
2021e1553eSJérôme Duval #include <time.h>
2121e1553eSJérôme Duval #include <lock.h>
2221e1553eSJérôme Duval #include <malloc.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>
3621e1553eSJérôme Duval 
3721e1553eSJérôme Duval #include "iso.h"
3821e1553eSJérôme Duval #include "iso9660.h"
3921e1553eSJérôme Duval 
4021e1553eSJérôme Duval //#define TRACE_ISO9660 1
4121e1553eSJérôme Duval #if TRACE_ISO9660
4221e1553eSJérôme Duval #	define TRACE(x) dprintf x
4321e1553eSJérôme Duval #else
4421e1553eSJérôme Duval #	define TRACE(x) ;
4521e1553eSJérôme Duval #endif
4621e1553eSJérôme Duval 
4721e1553eSJérôme Duval 
4821e1553eSJérôme Duval /*  Start of fundamental (read-only) required functions */
4921e1553eSJérôme Duval static status_t		fs_mount(mount_id mountID, const char *device, uint32 flags,
5021e1553eSJérôme Duval 				const char *args, void **_data, vnode_id *_rootID);
5121e1553eSJérôme Duval static status_t		fs_unmount(void *ns);
5221e1553eSJérôme Duval 
533b723f79SJérôme Duval static status_t		fs_get_vnode_name(void *_ns, void *_node,
543b723f79SJérôme Duval 				char *buffer, size_t bufferSize);
5521e1553eSJérôme Duval static status_t		fs_walk(void *_ns, void *_base, const char *file,
5621e1553eSJérôme Duval 				vnode_id *_vnodeID, int *_type);
5721e1553eSJérôme Duval 
5821e1553eSJérôme Duval static status_t		fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter);
5921e1553eSJérôme Duval static status_t		fs_release_vnode(void *_ns, void *_node, bool reenter);
60*5b4cb109SJérôme Duval static status_t		fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t offset, size_t size,
61*5b4cb109SJérôme Duval 				struct file_io_vec *vecs, size_t *_count);
6221e1553eSJérôme Duval static status_t		fs_read_stat(void *_ns, void *_node, struct stat *st);
6321e1553eSJérôme Duval static status_t		fs_open(void *_ns, void *_node, int omode, void **cookie);
6421e1553eSJérôme Duval static status_t		fs_read(void *_ns, void *_node, void *cookie, off_t pos,
6521e1553eSJérôme Duval 				void *buf, size_t *len);
6621e1553eSJérôme Duval /// fs_free_cookie - free cookie for file created in open.
6721e1553eSJérôme Duval static status_t		fs_free_cookie(void *ns, void *node, void *cookie);
6821e1553eSJérôme Duval static status_t		fs_close(void *ns, void *node, void *cookie);
6921e1553eSJérôme Duval 
7021e1553eSJérôme Duval // fs_access - checks permissions for access.
7121e1553eSJérôme Duval static status_t		fs_access(void *_ns, void *_node, int mode);
7221e1553eSJérôme Duval 
7321e1553eSJérôme Duval // fs_opendir - creates fs-specific "cookie" struct that can tell where
7421e1553eSJérôme Duval //					we are at in the directory list.
7521e1553eSJérôme Duval static status_t		fs_open_dir(void* _ns, void* _node, void** cookie);
7621e1553eSJérôme Duval // fs_readdir - read 1 or more dirents, keep state in cookie, return
7721e1553eSJérôme Duval //					0 when no more entries.
7821e1553eSJérôme Duval static status_t		fs_read_dir(void *_ns, void *_node, void *cookie, struct dirent *buf,
7921e1553eSJérôme Duval 				size_t bufsize, uint32 *_num);
8021e1553eSJérôme Duval // fs_rewinddir - set cookie to represent beginning of directory, so
8121e1553eSJérôme Duval //					later fs_readdir calls start at beginning.
8221e1553eSJérôme Duval static status_t		fs_rewind_dir(void *_ns, void *_node, void *cookie);
8321e1553eSJérôme Duval // fs_closedir - Do whatever you need to to close a directory (sometimes
8421e1553eSJérôme Duval //					nothing), but DON'T free the cookie!
8521e1553eSJérôme Duval static status_t		fs_close_dir(void *_ns, void *_node, void *cookie);
863b723f79SJérôme Duval // fs_free_dircookie - Free the fs-specific cookie struct
8721e1553eSJérôme Duval static status_t		fs_free_dir_cookie(void *_ns, void *_node, void *cookie);
8821e1553eSJérôme Duval 
8921e1553eSJérôme Duval // fs_rfsstat - Fill in fs_info struct for device.
9021e1553eSJérôme Duval static status_t		fs_read_fs_stat(void *_ns, struct fs_info *);
9121e1553eSJérôme Duval 
9221e1553eSJérôme Duval // fs_readlink - Read in the name of a symbolic link.
9321e1553eSJérôme Duval static status_t 	fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize);
9421e1553eSJérôme Duval 
9521e1553eSJérôme Duval 
9621e1553eSJérôme Duval //	#pragma mark - Scanning
9721e1553eSJérôme Duval 
9821e1553eSJérôme Duval struct identify_cookie {
9921e1553eSJérôme Duval 	iso9660_info info;
10021e1553eSJérôme Duval };
10121e1553eSJérôme Duval 
10221e1553eSJérôme Duval 
10321e1553eSJérôme Duval static float
10421e1553eSJérôme Duval fs_identify_partition(int fd, partition_data *partition, void **_cookie)
10521e1553eSJérôme Duval {
10621e1553eSJérôme Duval 	iso9660_info info;
10721e1553eSJérôme Duval 	status_t status = iso9660_fs_identify(fd, &info);
10821e1553eSJérôme Duval 	if (status != B_OK)
10921e1553eSJérôme Duval 		return status;
11021e1553eSJérôme Duval 
11121e1553eSJérôme Duval 	identify_cookie *cookie = new identify_cookie;
11221e1553eSJérôme Duval 	memcpy(&cookie->info, &info, sizeof(info));
11321e1553eSJérôme Duval 
11421e1553eSJérôme Duval 	*_cookie = cookie;
11521e1553eSJérôme Duval 	return 0.8f;
11621e1553eSJérôme Duval }
11721e1553eSJérôme Duval 
11821e1553eSJérôme Duval 
11921e1553eSJérôme Duval static status_t
12021e1553eSJérôme Duval fs_scan_partition(int fd, partition_data *partition, void *_cookie)
12121e1553eSJérôme Duval {
12221e1553eSJérôme Duval 	identify_cookie *cookie = (identify_cookie *)_cookie;
12321e1553eSJérôme Duval 
12421e1553eSJérôme Duval 	partition->status = B_PARTITION_VALID;
12521e1553eSJérôme Duval 	partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ;
12621e1553eSJérôme Duval 	partition->block_size = ISO_PVD_SIZE;
12721e1553eSJérôme Duval 	partition->content_size = ISO_PVD_SIZE * cookie->info.maxBlocks;
12821e1553eSJérôme Duval 	partition->content_name = strdup(cookie->info.get_preferred_volume_name());
12921e1553eSJérôme Duval 	if (partition->content_name == NULL)
13021e1553eSJérôme Duval 		return B_NO_MEMORY;
13121e1553eSJérôme Duval 
13221e1553eSJérôme Duval 	return B_OK;
13321e1553eSJérôme Duval }
13421e1553eSJérôme Duval 
13521e1553eSJérôme Duval 
13621e1553eSJérôme Duval static void
13721e1553eSJérôme Duval fs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
13821e1553eSJérôme Duval {
13921e1553eSJérôme Duval 	identify_cookie *cookie = (identify_cookie *)_cookie;
14021e1553eSJérôme Duval 
14121e1553eSJérôme Duval 	delete cookie;
14221e1553eSJérôme Duval }
14321e1553eSJérôme Duval 
14421e1553eSJérôme Duval 
14521e1553eSJérôme Duval static status_t
14621e1553eSJérôme Duval fs_mount(mount_id mountID, const char *device, uint32 flags,
14721e1553eSJérôme Duval 	const char *args, void **_data, vnode_id *_rootID)
14821e1553eSJérôme Duval {
14921e1553eSJérôme Duval 	/*
15021e1553eSJérôme Duval 	Kernel passes in nspace_id, (representing a disk or partition?)
15121e1553eSJérôme Duval 	and a string representing the device (eg, "/dev/scsi/disk/030/raw)
15221e1553eSJérôme Duval 	Flags will be used for things like specifying read-only mounting.
15321e1553eSJérôme Duval 	parms is parameters passed in as switches from the mount command,
15421e1553eSJérôme Duval 	and len is the length of the otions. data is a pointer to a
15521e1553eSJérôme Duval 	driver-specific struct that should be allocated in this routine.
15621e1553eSJérôme Duval 	It will then be passed back in by the kernel to a number of the other
15721e1553eSJérôme Duval 	fs driver functions. vnid should also be passed back to the kernel,
15821e1553eSJérôme Duval 	representing the vnode id of the root vnode.
15921e1553eSJérôme Duval 	*/
16021e1553eSJérôme Duval 	status_t result = EINVAL;
16121e1553eSJérôme Duval 		// return EINVAL if it's not a device compatible with the driver.
16221e1553eSJérôme Duval 	bool allow_joliet = true;
16321e1553eSJérôme Duval 	nspace *vol;
16421e1553eSJérôme Duval 
16521e1553eSJérôme Duval 	(void)flags;
16621e1553eSJérôme Duval 
16721e1553eSJérôme Duval 	/* Create semaphore if it's not already created. When do we need to
16821e1553eSJérôme Duval 		use semaphores? */
16921e1553eSJérôme Duval 
17021e1553eSJérôme Duval 	// Check for a 'nojoliet' parm
17121e1553eSJérôme Duval 	// all we check for is the existance of 'nojoliet' in the parms.
17221e1553eSJérôme Duval 	if (args != NULL) {
17321e1553eSJérôme Duval 		uint32 i;
17421e1553eSJérôme Duval 		char *spot;
17521e1553eSJérôme Duval 		char *buf = strdup(args);
17621e1553eSJérôme Duval 
17721e1553eSJérôme Duval 		uint32 len = strlen(buf);
17821e1553eSJérôme Duval 		// lower case the parms data
17921e1553eSJérôme Duval 		for (i = 0; i < len + 1; i++)
18021e1553eSJérôme Duval 			buf[i] = tolower(buf[i]);
18121e1553eSJérôme Duval 
18221e1553eSJérôme Duval 		// look for nojoliet
18321e1553eSJérôme Duval 		spot = strstr(buf, "nojoliet");
18421e1553eSJérôme Duval 		if (spot != NULL)
18521e1553eSJérôme Duval 			allow_joliet = false;
18621e1553eSJérôme Duval 
18721e1553eSJérôme Duval 		free(buf);
18821e1553eSJérôme Duval 	}
18921e1553eSJérôme Duval 
19021e1553eSJérôme Duval 	// Try and mount volume as an ISO volume.
19121e1553eSJérôme Duval 	result = ISOMount(device, O_RDONLY, &vol, allow_joliet);
19221e1553eSJérôme Duval 
19321e1553eSJérôme Duval 	// If it is ISO …
19421e1553eSJérôme Duval 	if (result == B_NO_ERROR) {
19521e1553eSJérôme Duval 		//vnode_id rootID = vol->rootDirRec.startLBN[FS_DATA_FORMAT];
19621e1553eSJérôme Duval 		//*vnid = rootID;
19721e1553eSJérôme Duval 		*_rootID = ISO_ROOTNODE_ID;
19821e1553eSJérôme Duval 		*_data = (void*)vol;
19921e1553eSJérôme Duval 
20021e1553eSJérôme Duval 		vol->id = mountID;
20121e1553eSJérôme Duval 
20221e1553eSJérôme Duval 		// You MUST do this. Create the vnode for the root.
20321e1553eSJérôme Duval 		result = publish_vnode(mountID, *_rootID, (void*)&(vol->rootDirRec));
20421e1553eSJérôme Duval 		if (result != B_NO_ERROR) {
20521e1553eSJérôme Duval 			block_cache_delete(vol->fBlockCache, false);
20621e1553eSJérôme Duval 			free(vol);
20721e1553eSJérôme Duval 			result = EINVAL;
20821e1553eSJérôme Duval 		} else
20921e1553eSJérôme Duval 			result = B_NO_ERROR;
21021e1553eSJérôme Duval 	}
21121e1553eSJérôme Duval 	return result;
21221e1553eSJérôme Duval }
21321e1553eSJérôme Duval 
21421e1553eSJérôme Duval 
21521e1553eSJérôme Duval static status_t
21621e1553eSJérôme Duval fs_unmount(void *_ns)
21721e1553eSJérôme Duval {
21821e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
21921e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
22021e1553eSJérôme Duval 
22121e1553eSJérôme Duval 	TRACE(("fs_unmount - ENTER\n"));
22221e1553eSJérôme Duval 
22321e1553eSJérôme Duval 	block_cache_delete(ns->fBlockCache, false);
22421e1553eSJérôme Duval 	close(ns->fdOfSession);
22521e1553eSJérôme Duval 	result = close(ns->fd);
22621e1553eSJérôme Duval 
22721e1553eSJérôme Duval 	free(ns);
22821e1553eSJérôme Duval 
22921e1553eSJérôme Duval 	TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result)));
23021e1553eSJérôme Duval 	return result;
23121e1553eSJérôme Duval }
23221e1553eSJérôme Duval 
23321e1553eSJérôme Duval 
23421e1553eSJérôme Duval static status_t
23521e1553eSJérôme Duval fs_read_fs_stat(void *_ns, struct fs_info *fss)
23621e1553eSJérôme Duval {
23721e1553eSJérôme Duval 	// Fill in fs_info struct for device.
23821e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
23921e1553eSJérôme Duval 	int i;
24021e1553eSJérôme Duval 
241*5b4cb109SJérôme Duval 	TRACE(("fs_read_fs_stat - ENTER\n"));
24221e1553eSJérôme Duval 
24321e1553eSJérôme Duval 	// Fill in device id.
24421e1553eSJérôme Duval 	//fss->dev = ns->fd;
24521e1553eSJérôme Duval 
24621e1553eSJérôme Duval 	// Root vnode ID
24721e1553eSJérôme Duval 	//fss->root = ISO_ROOTNODE_ID;
24821e1553eSJérôme Duval 
24921e1553eSJérôme Duval 	// File system flags.
25021e1553eSJérôme Duval 	fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
25121e1553eSJérôme Duval 
25221e1553eSJérôme Duval 	// FS block size.
25321e1553eSJérôme Duval 	fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT];
25421e1553eSJérôme Duval 
25521e1553eSJérôme Duval 	// IO size - specifies buffer size for file copying
25621e1553eSJérôme Duval 	fss->io_size = 65536;
25721e1553eSJérôme Duval 
25821e1553eSJérôme Duval 	// Total blocks?
25921e1553eSJérôme Duval 	fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT];
26021e1553eSJérôme Duval 
26121e1553eSJérôme Duval 	// Free blocks = 0, read only
26221e1553eSJérôme Duval 	fss->free_blocks = 0;
26321e1553eSJérôme Duval 
26421e1553eSJérôme Duval 	// Device name.
26521e1553eSJérôme Duval 	strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name));
26621e1553eSJérôme Duval 
26721e1553eSJérôme Duval 	strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name));
26821e1553eSJérôme Duval 	for (i = strlen(fss->volume_name)-1; i >=0 ; i--)
26921e1553eSJérôme Duval 		if (fss->volume_name[i] != ' ')
27021e1553eSJérôme Duval 			break;
27121e1553eSJérôme Duval 
27221e1553eSJérôme Duval 	if (i < 0)
27321e1553eSJérôme Duval 		strcpy(fss->volume_name, "UNKNOWN");
27421e1553eSJérôme Duval 	else
27521e1553eSJérôme Duval 		fss->volume_name[i + 1] = 0;
27621e1553eSJérôme Duval 
27721e1553eSJérôme Duval 	// File system name
27821e1553eSJérôme Duval 	strcpy(fss->fsh_name, "iso9660");
27921e1553eSJérôme Duval 
280*5b4cb109SJérôme Duval 	TRACE(("fs_read_fs_stat - EXIT\n"));
28121e1553eSJérôme Duval 	return 0;
28221e1553eSJérôme Duval }
28321e1553eSJérôme Duval 
2843b723f79SJérôme Duval 
2853b723f79SJérôme Duval static status_t
2863b723f79SJérôme Duval fs_get_vnode_name(void *ns, void *_node, char *buffer, size_t bufferSize)
2873b723f79SJérôme Duval {
2883b723f79SJérôme Duval 	vnode *node = (vnode*)_node;
2893b723f79SJérôme Duval 
2903b723f79SJérôme Duval 	strlcpy(buffer, node->fileIDString, bufferSize);
2913b723f79SJérôme Duval 	return B_OK;
2923b723f79SJérôme Duval }
2933b723f79SJérôme Duval 
2943b723f79SJérôme Duval 
29521e1553eSJérôme Duval /* fs_walk - the walk function just "walks" through a directory looking for
29621e1553eSJérôme Duval 	the specified file. When you find it, call get_vnode on its vnid to init
29721e1553eSJérôme Duval 	it for the kernel.
29821e1553eSJérôme Duval */
29921e1553eSJérôme Duval static status_t
30021e1553eSJérôme Duval fs_walk(void *_ns, void *base, const char *file, vnode_id *_vnodeID, int *_type)
30121e1553eSJérôme Duval {
30221e1553eSJérôme Duval 	/* Starting at the base, find file in the subdir, and return path
30321e1553eSJérôme Duval 		string and vnode id of file. */
30421e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
30521e1553eSJérôme Duval 	vnode *baseNode = (vnode*)base;
30621e1553eSJérôme Duval 	uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT];
30721e1553eSJérôme Duval 	vnode *newNode = NULL;
30821e1553eSJérôme Duval 	status_t result = ENOENT;
30921e1553eSJérôme Duval 	bool done = FALSE;
31021e1553eSJérôme Duval 	uint32 totalRead = 0;
31121e1553eSJérôme Duval 	off_t block = baseNode->startLBN[FS_DATA_FORMAT];
31221e1553eSJérôme Duval 
31321e1553eSJérôme Duval 	TRACE(("fs_walk - looking for %s in dir file of length %d\n", file,
31421e1553eSJérôme Duval 		baseNode->dataLen[FS_DATA_FORMAT]));
31521e1553eSJérôme Duval 
31621e1553eSJérôme Duval 	if (strcmp(file, ".") == 0)  {
31721e1553eSJérôme Duval 		// base directory
31821e1553eSJérôme Duval 		TRACE(("fs_walk - found \".\" file.\n"));
31921e1553eSJérôme Duval 		*_vnodeID = baseNode->id;
32021e1553eSJérôme Duval 		*_type = S_IFDIR;
32121e1553eSJérôme Duval 		if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
32221e1553eSJérôme Duval     		result = EINVAL;
32321e1553eSJérôme Duval 	    else
32421e1553eSJérôme Duval 	    	result = B_NO_ERROR;
32521e1553eSJérôme Duval 	} else if (strcmp(file, "..") == 0) {
32621e1553eSJérôme Duval 		// parent directory
32721e1553eSJérôme Duval 		TRACE(("fs_walk - found \"..\" file.\n"));
32821e1553eSJérôme Duval 		*_vnodeID = baseNode->parID;
32921e1553eSJérôme Duval 		*_type = S_IFDIR;
33021e1553eSJérôme Duval 		if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
33121e1553eSJérôme Duval 			result = EINVAL;
33221e1553eSJérôme Duval 		else
33321e1553eSJérôme Duval 			result = B_NO_ERROR;
33421e1553eSJérôme Duval 	} else {
33521e1553eSJérôme Duval 		// look up file in the directory
33621e1553eSJérôme Duval 		char *blockData;
33721e1553eSJérôme Duval 
33821e1553eSJérôme Duval 		while ((totalRead < dataLen) && !done) {
33921e1553eSJérôme Duval 			off_t cachedBlock = block;
34021e1553eSJérôme Duval 
34121e1553eSJérôme Duval 			blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
34221e1553eSJérôme Duval 			if (blockData != NULL) {
34321e1553eSJérôme Duval 				int bytesRead = 0;
34421e1553eSJérôme Duval 				off_t blockBytesRead = 0;
34521e1553eSJérôme Duval 				vnode node;
34621e1553eSJérôme Duval 				int initResult;
34721e1553eSJérôme Duval 
34821e1553eSJérôme Duval 				TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n",
34921e1553eSJérôme Duval 					block, blockData));
35021e1553eSJérôme Duval 
35121e1553eSJérôme Duval 				// Move to the next 2-block set if necessary
35221e1553eSJérôme Duval 				// Don't go over end of buffer, if dir record sits on boundary.
35321e1553eSJérôme Duval 
35421e1553eSJérôme Duval 				node.fileIDString = NULL;
35521e1553eSJérôme Duval 				node.attr.slName = NULL;
35621e1553eSJérôme Duval 
35721e1553eSJérôme Duval 				while (blockBytesRead  < 2*ns->logicalBlkSize[FS_DATA_FORMAT]
35821e1553eSJérôme Duval 					&& totalRead + blockBytesRead < dataLen
35921e1553eSJérôme Duval 					&& blockData[0] != 0
36021e1553eSJérôme Duval 					&& !done)
36121e1553eSJérôme Duval 				{
36221e1553eSJérôme Duval 					initResult = InitNode(&node, blockData, &bytesRead, ns->joliet_level);
36321e1553eSJérôme Duval 					TRACE(("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead));
36421e1553eSJérôme Duval 
36521e1553eSJérôme Duval 					if (initResult == B_NO_ERROR) {
36621e1553eSJérôme Duval 						if (strlen(node.fileIDString) == strlen(file)
36721e1553eSJérôme Duval 							&& !strncmp(node.fileIDString, file, strlen(file)))
36821e1553eSJérôme Duval 						{
36921e1553eSJérôme Duval 							TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead));
37021e1553eSJérôme Duval 							*_vnodeID = (block << 30) + (blockBytesRead & 0xFFFFFFFF);
37121e1553eSJérôme Duval 							TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID));
37221e1553eSJérôme Duval 
37321e1553eSJérôme Duval 							if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
37421e1553eSJérôme Duval 								result = EINVAL;
37521e1553eSJérôme Duval 							else {
37621e1553eSJérôme Duval 								newNode->parID = baseNode->id;
37721e1553eSJérôme Duval 								done = TRUE;
37821e1553eSJérôme Duval 								result = B_NO_ERROR;
37921e1553eSJérôme Duval 							}
38021e1553eSJérôme Duval 						} else {
38121e1553eSJérôme Duval 							if (node.fileIDString != NULL) {
38221e1553eSJérôme Duval 								free(node.fileIDString);
38321e1553eSJérôme Duval 								node.fileIDString = NULL;
38421e1553eSJérôme Duval 							}
38521e1553eSJérôme Duval 							if (node.attr.slName != NULL) {
38621e1553eSJérôme Duval 								free(node.attr.slName);
38721e1553eSJérôme Duval 								node.attr.slName = NULL;
38821e1553eSJérôme Duval 							}
38921e1553eSJérôme Duval 						}
39021e1553eSJérôme Duval 					} else {
39121e1553eSJérôme Duval 						result = initResult;
39221e1553eSJérôme Duval 						if (bytesRead == 0)
39321e1553eSJérôme Duval 							done = TRUE;
39421e1553eSJérôme Duval 					}
39521e1553eSJérôme Duval 					blockData += bytesRead;
39621e1553eSJérôme Duval 					blockBytesRead += bytesRead;
39721e1553eSJérôme Duval 
39821e1553eSJérôme Duval 					TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n",
39921e1553eSJérôme Duval 						bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]));
40021e1553eSJérôme Duval 				}
40121e1553eSJérôme Duval 				totalRead += ns->logicalBlkSize[FS_DATA_FORMAT];
40221e1553eSJérôme Duval 				block++;
40321e1553eSJérôme Duval 
40421e1553eSJérôme Duval 				TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead));
40521e1553eSJérôme Duval 				block_cache_put(ns->fBlockCache, cachedBlock);
40621e1553eSJérôme Duval 
40721e1553eSJérôme Duval 			} else
40821e1553eSJérôme Duval 				done = TRUE;
40921e1553eSJérôme Duval 		}
41021e1553eSJérôme Duval 
4113b723f79SJérôme Duval 		if (newNode)
41221e1553eSJérôme Duval 			*_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode;
41321e1553eSJérôme Duval 
41421e1553eSJérôme Duval 	}
41521e1553eSJérôme Duval 	TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *_vnodeID));
41621e1553eSJérôme Duval 	return result;
41721e1553eSJérôme Duval }
41821e1553eSJérôme Duval 
41921e1553eSJérôme Duval 
42021e1553eSJérôme Duval static status_t
42121e1553eSJérôme Duval fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter)
42221e1553eSJérôme Duval {
42321e1553eSJérôme Duval 	uint32 block, pos;
42421e1553eSJérôme Duval 	nspace *ns = (nspace*)_ns;
42521e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
42621e1553eSJérôme Duval 	vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
42721e1553eSJérôme Duval 
42821e1553eSJérôme Duval 	(void)reenter;
42921e1553eSJérôme Duval 
43021e1553eSJérôme Duval 	pos = (vnid & 0x3FFFFFFF);
43121e1553eSJérôme Duval 	block = (vnid >> 30);
43221e1553eSJérôme Duval 
43321e1553eSJérôme Duval 	TRACE(("fs_read_vnode - ENTER, block = %ld, pos = %ld, raw = %Lu node 0x%x\n",
43421e1553eSJérôme Duval 		block, pos, vnid, newNode));
43521e1553eSJérôme Duval 
43621e1553eSJérôme Duval 	if (newNode != NULL) {
43721e1553eSJérôme Duval 		if (vnid == ISO_ROOTNODE_ID) {
43821e1553eSJérôme Duval 			TRACE(("fs_read_vnode - root node requested.\n"));
43921e1553eSJérôme Duval 			memcpy(newNode, &(ns->rootDirRec), sizeof(vnode));
44021e1553eSJérôme Duval 			*node = (void*)newNode;
44121e1553eSJérôme Duval 		} else {
44221e1553eSJérôme Duval 			char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
44321e1553eSJérôme Duval 
44421e1553eSJérôme Duval 			if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
44521e1553eSJérôme Duval 				if (blockData != NULL)
44621e1553eSJérôme Duval 					block_cache_put(ns->fBlockCache, block);
44721e1553eSJérôme Duval 
44821e1553eSJérôme Duval 				result = EINVAL;
44921e1553eSJérôme Duval 		 	} else if (blockData != NULL) {
45021e1553eSJérôme Duval 				result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level);
45121e1553eSJérôme Duval 				block_cache_put(ns->fBlockCache, block);
45221e1553eSJérôme Duval 				newNode->id = vnid;
45321e1553eSJérôme Duval 
45421e1553eSJérôme Duval 				TRACE(("fs_read_vnode - init result is %s\n", strerror(result)));
45521e1553eSJérôme Duval 				*node = (void *)newNode;
45621e1553eSJérôme Duval 				TRACE(("fs_read_vnode - new file %s, size %ld\n", newNode->fileIDString, newNode->dataLen[FS_DATA_FORMAT]));
45721e1553eSJérôme Duval 			}
45821e1553eSJérôme Duval 		}
45921e1553eSJérôme Duval 	} else
46021e1553eSJérôme Duval 		result = ENOMEM;
46121e1553eSJérôme Duval 
462*5b4cb109SJérôme Duval 	if (result == B_OK && !(newNode->flags & ISO_ISDIR)) {
463*5b4cb109SJérôme Duval 		newNode->cache = file_cache_create(ns->id, vnid, newNode->dataLen[FS_DATA_FORMAT], ns->fdOfSession);
464*5b4cb109SJérôme Duval 	}
465*5b4cb109SJérôme Duval 
46621e1553eSJérôme Duval 	TRACE(("fs_read_vnode - EXIT, result is %s\n", strerror(result)));
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
47221e1553eSJérôme Duval fs_release_vnode(void *ns, void *_node, bool reenter)
47321e1553eSJérôme Duval {
47421e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
47521e1553eSJérôme Duval 	vnode *node = (vnode*)_node;
47621e1553eSJérôme Duval 
47721e1553eSJérôme Duval 	(void)ns;
47821e1553eSJérôme Duval 	(void)reenter;
47921e1553eSJérôme Duval 
480*5b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - ENTER (0x%x)\n", node));
48121e1553eSJérôme Duval 
48221e1553eSJérôme Duval 	if (node != NULL) {
48321e1553eSJérôme Duval 		if (node->id != ISO_ROOTNODE_ID) {
48421e1553eSJérôme Duval 			if (node->fileIDString != NULL)
48521e1553eSJérôme Duval 				free (node->fileIDString);
48621e1553eSJérôme Duval 			if (node->attr.slName != NULL)
48721e1553eSJérôme Duval 				free (node->attr.slName);
488*5b4cb109SJérôme Duval 			if (node->cache != NULL)
489*5b4cb109SJérôme Duval 				file_cache_delete(node->cache);
49021e1553eSJérôme Duval 
49121e1553eSJérôme Duval 			free(node);
49221e1553eSJérôme Duval 		}
49321e1553eSJérôme Duval 	}
49421e1553eSJérôme Duval 
495*5b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - EXIT\n"));
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
501*5b4cb109SJérôme Duval fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t pos, size_t reqLen,
502*5b4cb109SJérôme Duval 	struct file_io_vec *vecs, size_t *_count)
503*5b4cb109SJérôme Duval {
504*5b4cb109SJérôme Duval 	nspace *ns = (nspace *)_fs;			// global stuff
505*5b4cb109SJérôme Duval 	vnode *node = (vnode *)_node;		// The read file vnode.
506*5b4cb109SJérôme Duval 	uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT];
507*5b4cb109SJérôme Duval 	uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize);
508*5b4cb109SJérôme Duval 	off_t blockPos = pos % blockSize;
509*5b4cb109SJérôme Duval 	off_t numBlocks = 0;
510*5b4cb109SJérôme Duval 	uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
511*5b4cb109SJérôme Duval 	size_t endLen = 0;
512*5b4cb109SJérôme Duval 	size_t startLen =  0;
513*5b4cb109SJérôme Duval 	size_t index = 0, max = *_count;
514*5b4cb109SJérôme Duval 
515*5b4cb109SJérôme Duval 	TRACE(("fs_get_file_map - ENTER (0x%x)\n", node));
516*5b4cb109SJérôme Duval 
517*5b4cb109SJérôme Duval 	// Allow an open to work on a dir, but no reads
518*5b4cb109SJérôme Duval 	if (node->flags & ISO_ISDIR)
519*5b4cb109SJérôme Duval 		return EISDIR;
520*5b4cb109SJérôme Duval 
521*5b4cb109SJérôme Duval 	if (pos < 0)
522*5b4cb109SJérôme Duval 		pos = 0;
523*5b4cb109SJérôme Duval 	*_count = 0;
524*5b4cb109SJérôme Duval 
525*5b4cb109SJérôme Duval 	// If passed-in requested length is bigger than file size, change it to
526*5b4cb109SJérôme Duval 	// file size.
527*5b4cb109SJérôme Duval 	if (reqLen + pos > dataLen)
528*5b4cb109SJérôme Duval 		reqLen = dataLen - pos;
529*5b4cb109SJérôme Duval 
530*5b4cb109SJérôme Duval 	// Compute the length of the partial start-block read, if any.
531*5b4cb109SJérôme Duval 	if (reqLen + blockPos <= blockSize)
532*5b4cb109SJérôme Duval 		startLen = reqLen;
533*5b4cb109SJérôme Duval 	else if (blockPos > 0)
534*5b4cb109SJérôme Duval 		startLen = blockSize - blockPos;
535*5b4cb109SJérôme Duval 
536*5b4cb109SJérôme Duval 	if (blockPos == 0 && reqLen >= blockSize) {
537*5b4cb109SJérôme Duval 		TRACE(("Setting startLen to 0\n"));
538*5b4cb109SJérôme Duval 		startLen = 0;
539*5b4cb109SJérôme Duval 	}
540*5b4cb109SJérôme Duval 
541*5b4cb109SJérôme Duval 	// Compute the length of the partial end-block read, if any.
542*5b4cb109SJérôme Duval 	if (reqLen + blockPos > blockSize)
543*5b4cb109SJérôme Duval 		endLen = (reqLen + blockPos) % blockSize;
544*5b4cb109SJérôme Duval 
545*5b4cb109SJérôme Duval 	// Compute the number of middle blocks to read.
546*5b4cb109SJérôme Duval 	numBlocks = ((reqLen - endLen - startLen) /  blockSize);
547*5b4cb109SJérôme Duval 
548*5b4cb109SJérôme Duval 	if (pos >= dataLen) {
549*5b4cb109SJérôme Duval 		// If pos >= file length, return
550*5b4cb109SJérôme Duval 		return B_OK;
551*5b4cb109SJérôme Duval 	}
552*5b4cb109SJérôme Duval 
553*5b4cb109SJérôme Duval 	// Read in the first, potentially partial, block.
554*5b4cb109SJérôme Duval 	if (startLen > 0) {
555*5b4cb109SJérôme Duval 		vecs[index].offset = startBlock * blockSize + blockPos;
556*5b4cb109SJérôme Duval 		vecs[index].length = startLen;
557*5b4cb109SJérôme Duval 		startBlock++;
558*5b4cb109SJérôme Duval 		index++;
559*5b4cb109SJérôme Duval 		if (index >= max) {
560*5b4cb109SJérôme Duval 			// we're out of file_io_vecs; let's bail out
561*5b4cb109SJérôme Duval 			*_count = index;
562*5b4cb109SJérôme Duval 			return B_BUFFER_OVERFLOW;
563*5b4cb109SJérôme Duval 		}
564*5b4cb109SJérôme Duval 	}
565*5b4cb109SJérôme Duval 
566*5b4cb109SJérôme Duval 	// Read in the middle blocks.
567*5b4cb109SJérôme Duval 	if (numBlocks > 0) {
568*5b4cb109SJérôme Duval 		for (int32 i=startBlock; i<startBlock+numBlocks; i++) {
569*5b4cb109SJérôme Duval 			vecs[index].offset = i * blockSize;
570*5b4cb109SJérôme Duval 			vecs[index].length = blockSize;
571*5b4cb109SJérôme Duval 			index++;
572*5b4cb109SJérôme Duval 			if (index >= max) {
573*5b4cb109SJérôme Duval 				// we're out of file_io_vecs; let's bail out
574*5b4cb109SJérôme Duval 				*_count = index;
575*5b4cb109SJérôme Duval 				return B_BUFFER_OVERFLOW;
576*5b4cb109SJérôme Duval 			}
577*5b4cb109SJérôme Duval 		}
578*5b4cb109SJérôme Duval 	}
579*5b4cb109SJérôme Duval 
580*5b4cb109SJérôme Duval 	// Read in the last partial block.
581*5b4cb109SJérôme Duval 	if (endLen > 0) {
582*5b4cb109SJérôme Duval 		off_t endBlock = startBlock + numBlocks;
583*5b4cb109SJérôme Duval 		vecs[index].offset = endBlock * blockSize;
584*5b4cb109SJérôme Duval 		vecs[index].length = endLen;
585*5b4cb109SJérôme Duval 		index++;
586*5b4cb109SJérôme Duval 	}
587*5b4cb109SJérôme Duval 
588*5b4cb109SJérôme Duval 	*_count = index;
589*5b4cb109SJérôme Duval 
590*5b4cb109SJérôme Duval 	TRACE(("fs_get_file_map - EXIT\n"));
591*5b4cb109SJérôme Duval 	return B_OK;
592*5b4cb109SJérôme Duval }
593*5b4cb109SJérôme Duval 
594*5b4cb109SJérôme Duval 
595*5b4cb109SJérôme Duval static status_t
59621e1553eSJérôme Duval fs_read_stat(void *_ns, void *_node, struct stat *st)
59721e1553eSJérôme Duval {
59821e1553eSJérôme Duval 	nspace *ns = (nspace*)_ns;
59921e1553eSJérôme Duval 	vnode *node = (vnode*)_node;
6003b723f79SJérôme Duval 	status_t result = B_NO_ERROR;
60121e1553eSJérôme Duval 	time_t time;
60221e1553eSJérôme Duval 
6033b723f79SJérôme Duval 	TRACE(("fs_read_stat - ENTER\n"));
60421e1553eSJérôme Duval 
60521e1553eSJérôme Duval 	st->st_dev = ns->id;
60621e1553eSJérôme Duval 	st->st_ino = node->id;
60721e1553eSJérôme Duval 	st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink;
60821e1553eSJérôme Duval 	st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid;
60921e1553eSJérôme Duval 	st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid;
61021e1553eSJérôme Duval 	st->st_blksize = 65536;
61121e1553eSJérôme Duval 	st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode;
61221e1553eSJérôme Duval 
61321e1553eSJérôme Duval 	// Same for file/dir in ISO9660
61421e1553eSJérôme Duval 	st->st_size = node->dataLen[FS_DATA_FORMAT];
61521e1553eSJérôme Duval 	if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR)
61621e1553eSJérôme Duval 		st->st_ctime = st->st_mtime = st->st_atime = time;
61721e1553eSJérôme Duval 
6183b723f79SJérôme Duval 	TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result)));
61921e1553eSJérôme Duval 
62021e1553eSJérôme Duval 	return result;
62121e1553eSJérôme Duval }
62221e1553eSJérôme Duval 
62321e1553eSJérôme Duval 
62421e1553eSJérôme Duval static status_t
62521e1553eSJérôme Duval fs_open(void *_ns, void *_node, int omode, void **cookie)
62621e1553eSJérôme Duval {
62721e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
62821e1553eSJérôme Duval 
62921e1553eSJérôme Duval 	(void)_ns;
63021e1553eSJérôme Duval 	(void)cookie;
63121e1553eSJérôme Duval 
63221e1553eSJérôme Duval 	// Do not allow any of the write-like open modes to get by
63321e1553eSJérôme Duval 	if ((omode == O_WRONLY) || (omode == O_RDWR))
63421e1553eSJérôme Duval 		result = EROFS;
63521e1553eSJérôme Duval 	else if((omode & O_TRUNC) || (omode & O_CREAT))
63621e1553eSJérôme Duval 		result = EROFS;
63721e1553eSJérôme Duval 
63821e1553eSJérôme Duval 	return result;
63921e1553eSJérôme Duval }
64021e1553eSJérôme Duval 
64121e1553eSJérôme Duval 
64221e1553eSJérôme Duval static status_t
64321e1553eSJérôme Duval fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len)
64421e1553eSJérôme Duval {
645*5b4cb109SJérôme Duval #if 0
64621e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;			// global stuff
64721e1553eSJérôme Duval 	vnode *node = (vnode *)_node;		// The read file vnode.
64821e1553eSJérôme Duval 	uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT];
64921e1553eSJérôme Duval 	uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize);
65021e1553eSJérôme Duval 	off_t blockPos = pos % blockSize;
65121e1553eSJérôme Duval 	off_t numBlocks = 0;
65221e1553eSJérôme Duval 	uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
65321e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
65421e1553eSJérôme Duval 	size_t endLen = 0;
65521e1553eSJérôme Duval 	size_t reqLen = *len;
65621e1553eSJérôme Duval 	size_t startLen =  0;
65721e1553eSJérôme Duval 
65821e1553eSJérôme Duval 	(void)cookie;
65921e1553eSJérôme Duval 
66021e1553eSJérôme Duval 	// Allow an open to work on a dir, but no reads
66121e1553eSJérôme Duval 	if (node->flags & ISO_ISDIR)
66221e1553eSJérôme Duval 		return EISDIR;
66321e1553eSJérôme Duval 
66421e1553eSJérôme Duval 	if (pos < 0)
66521e1553eSJérôme Duval 		pos = 0;
66621e1553eSJérôme Duval 	*len = 0;
66721e1553eSJérôme Duval 
66821e1553eSJérôme Duval 	// If passed-in requested length is bigger than file size, change it to
66921e1553eSJérôme Duval 	// file size.
67021e1553eSJérôme Duval 	if (reqLen + pos > dataLen)
67121e1553eSJérôme Duval 		reqLen = dataLen - pos;
67221e1553eSJérôme Duval 
67321e1553eSJérôme Duval 	// Compute the length of the partial start-block read, if any.
67421e1553eSJérôme Duval 
67521e1553eSJérôme Duval 	if (reqLen + blockPos <= blockSize)
67621e1553eSJérôme Duval 		startLen = reqLen;
67721e1553eSJérôme Duval 	else if (blockPos > 0)
67821e1553eSJérôme Duval 		startLen = blockSize - blockPos;
67921e1553eSJérôme Duval 
68021e1553eSJérôme Duval 	if (blockPos == 0 && reqLen >= blockSize) {
68121e1553eSJérôme Duval 		TRACE(("Setting startLen to 0, even block read\n"));
68221e1553eSJérôme Duval 		startLen = 0;
68321e1553eSJérôme Duval 	}
68421e1553eSJérôme Duval 
68521e1553eSJérôme Duval 	// Compute the length of the partial end-block read, if any.
68621e1553eSJérôme Duval 	if (reqLen + blockPos > blockSize)
68721e1553eSJérôme Duval 		endLen = (reqLen + blockPos) % blockSize;
68821e1553eSJérôme Duval 
68921e1553eSJérôme Duval 	// Compute the number of middle blocks to read.
69021e1553eSJérôme Duval 	numBlocks = ((reqLen - endLen - startLen) /  blockSize);
69121e1553eSJérôme Duval 
69221e1553eSJérôme Duval 	//dprintf("fs_read - ENTER, pos is %Ld, len is %lu\n", pos, reqLen);
69321e1553eSJérôme Duval 	//dprintf("fs_read - filename is %s\n", node->fileIDString);
69421e1553eSJérôme Duval 	//dprintf("fs_read - total file length is %lu\n", dataLen);
69521e1553eSJérôme Duval 	//dprintf("fs_read - start block of file is %lu\n", node->startLBN[FS_DATA_FORMAT]);
69621e1553eSJérôme Duval 	//dprintf("fs_read - block pos is %Lu\n", blockPos);
69721e1553eSJérôme Duval 	//dprintf("fs_read - read block will be %lu\n", startBlock);
69821e1553eSJérôme Duval 	//dprintf("fs_read - startLen is %lu\n", startLen);
69921e1553eSJérôme Duval 	//dprintf("fs_read - endLen is %lu\n", endLen);
70021e1553eSJérôme Duval 	//dprintf("fs_read - num blocks to read is %Ld\n", numBlocks);
70121e1553eSJérôme Duval 
70221e1553eSJérôme Duval 	if (pos >= dataLen) {
70321e1553eSJérôme Duval 		// If pos >= file length, return length of 0.
70421e1553eSJérôme Duval 		*len = 0;
70521e1553eSJérôme Duval 		return B_OK;
70621e1553eSJérôme Duval 	}
70721e1553eSJérôme Duval 
70821e1553eSJérôme Duval 	// Read in the first, potentially partial, block.
70921e1553eSJérôme Duval 	if (startLen > 0) {
71021e1553eSJérôme Duval 		off_t cachedBlock = startBlock;
71121e1553eSJérôme Duval 		char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, startBlock, 0, blockSize);
71221e1553eSJérôme Duval 		if (blockData != NULL) {
71321e1553eSJérôme Duval 			//dprintf("fs_read - copying first block, len is %d.\n", startLen);
71421e1553eSJérôme Duval 			memcpy(buf, blockData+blockPos, startLen);
71521e1553eSJérôme Duval 			*len += startLen;
71621e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, cachedBlock);
71721e1553eSJérôme Duval 			startBlock++;
7183b723f79SJérôme Duval 		} else
7193b723f79SJérôme Duval 			result = EIO;
72021e1553eSJérôme Duval 	}
72121e1553eSJérôme Duval 
72221e1553eSJérôme Duval 	// Read in the middle blocks.
72321e1553eSJérôme Duval 	if (numBlocks > 0 && result == B_NO_ERROR) {
72421e1553eSJérôme Duval 		TRACE(("fs_read - getting middle blocks\n"));
7253b723f79SJérôme Duval 		char *endBuf = ((char *)buf) + startLen;
72621e1553eSJérôme Duval 		for (int32 i=startBlock; i<startBlock+numBlocks; i++) {
72721e1553eSJérôme Duval 			char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, i, 0, blockSize);
7283b723f79SJérôme Duval 			memcpy(endBuf, blockData, blockSize);
72921e1553eSJérôme Duval 			*len += blockSize;
7303b723f79SJérôme Duval 			endBuf += blockSize;
73121e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, i);
73221e1553eSJérôme Duval 		}
73321e1553eSJérôme Duval 	}
73421e1553eSJérôme Duval 
73521e1553eSJérôme Duval 	// Read in the last partial block.
73621e1553eSJérôme Duval 	if (result == B_NO_ERROR && endLen > 0) {
73721e1553eSJérôme Duval 		off_t endBlock = startBlock + numBlocks;
73821e1553eSJérôme Duval 		char *endBlockData = (char*)block_cache_get_etc(ns->fBlockCache, endBlock, 0, blockSize);
73921e1553eSJérôme Duval 		if (endBlockData != NULL) {
74021e1553eSJérôme Duval 			char *endBuf = ((char *)buf) + (reqLen - endLen);
74121e1553eSJérôme Duval 
74221e1553eSJérôme Duval 			memcpy(endBuf, endBlockData, endLen);
74321e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, endBlock);
74421e1553eSJérôme Duval 			*len += endLen;
74521e1553eSJérôme Duval 		} else
74621e1553eSJérôme Duval 			result = EIO;
74721e1553eSJérôme Duval 	}
74821e1553eSJérôme Duval 
74921e1553eSJérôme Duval 	TRACE(("fs_read - EXIT, result is %s\n", strerror(result)));
75021e1553eSJérôme Duval 	return result;
751*5b4cb109SJérôme Duval #else
752*5b4cb109SJérôme Duval 	vnode *node = (vnode *)_node;           // The read file vnode.
753*5b4cb109SJérôme Duval 	uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
754*5b4cb109SJérôme Duval 
755*5b4cb109SJérôme Duval 	// set/check boundaries for pos/length
756*5b4cb109SJérôme Duval 	if (pos < 0) {
757*5b4cb109SJérôme Duval 		return B_BAD_VALUE;
758*5b4cb109SJérôme Duval 	}
759*5b4cb109SJérôme Duval 	if (pos >= dataLen) {
760*5b4cb109SJérôme Duval 		// If pos >= file length, return length of 0.
761*5b4cb109SJérôme Duval 		*len = 0;
762*5b4cb109SJérôme Duval 		return B_OK;
763*5b4cb109SJérôme Duval         }
764*5b4cb109SJérôme Duval 	return file_cache_read(node->cache, pos, buf, len);
765*5b4cb109SJérôme Duval #endif
76621e1553eSJérôme Duval }
76721e1553eSJérôme Duval 
76821e1553eSJérôme Duval 
76921e1553eSJérôme Duval static status_t
77021e1553eSJérôme Duval fs_close(void *ns, void *node, void *cookie)
77121e1553eSJérôme Duval {
77221e1553eSJérôme Duval 	(void)ns;
77321e1553eSJérôme Duval 	(void)node;
77421e1553eSJérôme Duval 	(void)cookie;
77521e1553eSJérôme Duval 
77621e1553eSJérôme Duval 	//dprintf("fs_close - ENTER\n");
77721e1553eSJérôme Duval 	//dprintf("fs_close - EXIT\n");
77821e1553eSJérôme Duval 	return B_OK;
77921e1553eSJérôme Duval }
78021e1553eSJérôme Duval 
78121e1553eSJérôme Duval static status_t
78221e1553eSJérôme Duval fs_free_cookie(void *ns, void *node, void *cookie)
78321e1553eSJérôme Duval {
78421e1553eSJérôme Duval 	(void)ns;
78521e1553eSJérôme Duval 	(void)node;
78621e1553eSJérôme Duval 	(void)cookie;
78721e1553eSJérôme Duval 
78821e1553eSJérôme Duval 	// We don't allocate file cookies, so we do nothing here.
78921e1553eSJérôme Duval 	//dprintf("fs_free_cookie - ENTER\n");
79021e1553eSJérôme Duval 	//if (cookie != NULL) free (cookie);
79121e1553eSJérôme Duval 	//dprintf("fs_free_cookie - EXIT\n");
79221e1553eSJérôme Duval 	return B_OK;
79321e1553eSJérôme Duval }
79421e1553eSJérôme Duval 
79521e1553eSJérôme Duval // fs_access - checks permissions for access.
79621e1553eSJérôme Duval static status_t
79721e1553eSJérôme Duval fs_access(void *ns, void *node, int mode)
79821e1553eSJérôme Duval {
79921e1553eSJérôme Duval 	(void)ns;
80021e1553eSJérôme Duval 	(void)node;
80121e1553eSJérôme Duval 	(void)mode;
80221e1553eSJérôme Duval 
80321e1553eSJérôme Duval 	// ns 	- global, fs-specific struct for device
80421e1553eSJérôme Duval 	// node	- node to check permissions for
80521e1553eSJérôme Duval 	// mode - requested permissions on node.
80621e1553eSJérôme Duval 	//dprintf("fs_access - ENTER\n");
80721e1553eSJérôme Duval 	//dprintf("fs_access - EXIT\n");
80821e1553eSJérôme Duval 	return B_OK;
80921e1553eSJérôme Duval }
81021e1553eSJérôme Duval 
81121e1553eSJérôme Duval static status_t
81221e1553eSJérôme Duval fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize)
81321e1553eSJérôme Duval {
81421e1553eSJérôme Duval 	vnode *node = (vnode *)_node;
81521e1553eSJérôme Duval 	status_t result = EINVAL;
81621e1553eSJérôme Duval 
81721e1553eSJérôme Duval 	(void)_ns;
81821e1553eSJérôme Duval 
81921e1553eSJérôme Duval 	if (S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) {
82021e1553eSJérôme Duval 		size_t length = strlen(node->attr.slName);
82121e1553eSJérôme Duval 		if (length > *_bufferSize)
8223b723f79SJérôme Duval 			memcpy(buffer, node->attr.slName, *_bufferSize);
8233b723f79SJérôme Duval 		else {
82421e1553eSJérôme Duval 			memcpy(buffer, node->attr.slName, length);
8253b723f79SJérôme Duval 			*_bufferSize = length;
8263b723f79SJérôme Duval 		}
82721e1553eSJérôme Duval 
82821e1553eSJérôme Duval 		result = B_NO_ERROR;
82921e1553eSJérôme Duval 	}
83021e1553eSJérôme Duval 
83121e1553eSJérôme Duval 	return result;
83221e1553eSJérôme Duval }
83321e1553eSJérôme Duval 
83421e1553eSJérôme Duval 
83521e1553eSJérôme Duval static status_t
83621e1553eSJérôme Duval fs_open_dir(void *_ns, void *_node, void **cookie)
83721e1553eSJérôme Duval {
83821e1553eSJérôme Duval 	vnode *node = (vnode *)_node;
83921e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
84021e1553eSJérôme Duval 	dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
84121e1553eSJérôme Duval 
84221e1553eSJérôme Duval 	(void)_ns;
84321e1553eSJérôme Duval 
844*5b4cb109SJérôme Duval 	TRACE(("fs_open_dir - ENTER, node is 0x%x\n", _node));
84521e1553eSJérôme Duval 
84621e1553eSJérôme Duval 	if (!(node->flags & ISO_ISDIR))
84721e1553eSJérôme Duval 		result = EMFILE;
84821e1553eSJérôme Duval 
84921e1553eSJérôme Duval 	if (dirCookie != NULL) {
85021e1553eSJérôme Duval 		dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT];
85121e1553eSJérôme Duval 		dirCookie->block = node->startLBN[FS_DATA_FORMAT];
85221e1553eSJérôme Duval 		dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
85321e1553eSJérôme Duval 		dirCookie->pos = 0;
85421e1553eSJérôme Duval 		dirCookie->id = node->id;
85521e1553eSJérôme Duval 		*cookie = (void *)dirCookie;
85621e1553eSJérôme Duval 	} else
85721e1553eSJérôme Duval 		result = ENOMEM;
85821e1553eSJérôme Duval 
859*5b4cb109SJérôme Duval 	TRACE(("fs_open_dir - EXIT\n"));
86021e1553eSJérôme Duval 	return result;
86121e1553eSJérôme Duval }
86221e1553eSJérôme Duval 
86321e1553eSJérôme Duval 
86421e1553eSJérôme Duval static status_t
86521e1553eSJérôme Duval fs_read_dir(void *_ns, void *_node, void *_cookie, struct dirent *buffer,
86621e1553eSJérôme Duval 	size_t bufferSize, uint32 *num)
86721e1553eSJérôme Duval {
86821e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
86921e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
87021e1553eSJérôme Duval 	dircookie *dirCookie = (dircookie *)_cookie;
87121e1553eSJérôme Duval 
87221e1553eSJérôme Duval 	(void)_node;
87321e1553eSJérôme Duval 
874*5b4cb109SJérôme Duval 	TRACE(("fs_read_dir - ENTER\n"));
87521e1553eSJérôme Duval 
87621e1553eSJérôme Duval 	result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize);
87721e1553eSJérôme Duval 
87821e1553eSJérôme Duval 	// If we succeeded, return 1, the number of dirents we read.
87921e1553eSJérôme Duval 	if (result == B_NO_ERROR)
88021e1553eSJérôme Duval 		*num = 1;
88121e1553eSJérôme Duval 	else
88221e1553eSJérôme Duval 		*num = 0;
88321e1553eSJérôme Duval 
88421e1553eSJérôme Duval 	// When you get to the end, don't return an error, just return
88521e1553eSJérôme Duval 	// a zero in *num.
88621e1553eSJérôme Duval 
88721e1553eSJérôme Duval 	if (result == ENOENT)
88821e1553eSJérôme Duval 		result = B_NO_ERROR;
88921e1553eSJérôme Duval 
890*5b4cb109SJérôme Duval 	TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result)));
89121e1553eSJérôme Duval 	return result;
89221e1553eSJérôme Duval }
89321e1553eSJérôme Duval 
89421e1553eSJérôme Duval 
89521e1553eSJérôme Duval static status_t
89621e1553eSJérôme Duval fs_rewind_dir(void *ns, void *node, void* _cookie)
89721e1553eSJérôme Duval {
89821e1553eSJérôme Duval 	status_t result = EINVAL;
89921e1553eSJérôme Duval 	dircookie *cookie = (dircookie*)_cookie;
90021e1553eSJérôme Duval 
90121e1553eSJérôme Duval 	(void)ns;
90221e1553eSJérôme Duval 	(void)node;
90321e1553eSJérôme Duval 
904*5b4cb109SJérôme Duval 	//dprintf("fs_rewind_dir - ENTER\n");
90521e1553eSJérôme Duval 	if (cookie != NULL) {
90621e1553eSJérôme Duval 		cookie->block = cookie->startBlock;
90721e1553eSJérôme Duval 		cookie->pos = 0;
90821e1553eSJérôme Duval 		result = B_NO_ERROR;
90921e1553eSJérôme Duval 	}
910*5b4cb109SJérôme Duval 	//dprintf("fs_rewind_dir - EXIT, result is %s\n", strerror(result));
91121e1553eSJérôme Duval 	return result;
91221e1553eSJérôme Duval }
91321e1553eSJérôme Duval 
91421e1553eSJérôme Duval 
91521e1553eSJérôme Duval static status_t
91621e1553eSJérôme Duval fs_close_dir(void *ns, void *node, void *cookie)
91721e1553eSJérôme Duval {
91821e1553eSJérôme Duval 	(void)ns;
91921e1553eSJérôme Duval 	(void)node;
92021e1553eSJérôme Duval 	(void)cookie;
92121e1553eSJérôme Duval 
92221e1553eSJérôme Duval 	// ns 		- global, fs-specific struct for device
92321e1553eSJérôme Duval 	// node		- directory to close
92421e1553eSJérôme Duval 	// cookie	- current cookie for directory.
925*5b4cb109SJérôme Duval 	//dprintf("fs_close_dir - ENTER\n");
926*5b4cb109SJérôme Duval 	//dprintf("fs_close_dir - EXIT\n");
92721e1553eSJérôme Duval 	return B_OK;
92821e1553eSJérôme Duval }
92921e1553eSJérôme Duval 
93021e1553eSJérôme Duval 
93121e1553eSJérôme Duval static status_t
93221e1553eSJérôme Duval fs_free_dir_cookie(void *ns, void *node, void *cookie)
93321e1553eSJérôme Duval {
93421e1553eSJérôme Duval 	(void)ns;
93521e1553eSJérôme Duval 	(void)node;
93621e1553eSJérôme Duval 
93721e1553eSJérôme Duval 	// ns 		- global, fs-specific struct for device
93821e1553eSJérôme Duval 	// node		- directory related to cookie
93921e1553eSJérôme Duval 	// cookie	- current cookie for directory, to free.
940*5b4cb109SJérôme Duval 	//dprintf("fs_free_dir_cookie - ENTER\n");
94121e1553eSJérôme Duval 	if (cookie != NULL)
94221e1553eSJérôme Duval 		free(cookie);
94321e1553eSJérôme Duval 
944*5b4cb109SJérôme Duval 	//dprintf("fs_free_dir_cookie - EXIT\n");
94521e1553eSJérôme Duval 	return B_OK;
94621e1553eSJérôme Duval }
94721e1553eSJérôme Duval 
94821e1553eSJérôme Duval //	#pragma mark -
94921e1553eSJérôme Duval 
95021e1553eSJérôme Duval 
95121e1553eSJérôme Duval static status_t
95221e1553eSJérôme Duval iso_std_ops(int32 op, ...)
95321e1553eSJérôme Duval {
95421e1553eSJérôme Duval 	switch (op) {
95521e1553eSJérôme Duval 		case B_MODULE_INIT:
95621e1553eSJérôme Duval 			return B_OK;
95721e1553eSJérôme Duval 		case B_MODULE_UNINIT:
95821e1553eSJérôme Duval 			return B_OK;
95921e1553eSJérôme Duval 		default:
96021e1553eSJérôme Duval 			return B_ERROR;
96121e1553eSJérôme Duval 	}
96221e1553eSJérôme Duval }
96321e1553eSJérôme Duval 
96421e1553eSJérôme Duval 
96521e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = {
96621e1553eSJérôme Duval 	{
96721e1553eSJérôme Duval 		"file_systems/iso9660" B_CURRENT_FS_API_VERSION,
96821e1553eSJérôme Duval 		0,
96921e1553eSJérôme Duval 		iso_std_ops,
97021e1553eSJérôme Duval 	},
97121e1553eSJérôme Duval 
97221e1553eSJérôme Duval 	"ISO9660 File System",
97321e1553eSJérôme Duval 
97421e1553eSJérôme Duval 	// scanning
97521e1553eSJérôme Duval 	fs_identify_partition,
97621e1553eSJérôme Duval 	fs_scan_partition,
97721e1553eSJérôme Duval 	fs_free_identify_partition_cookie,
97821e1553eSJérôme Duval 	NULL,	// free_partition_content_cookie()
97921e1553eSJérôme Duval 
98021e1553eSJérôme Duval 	&fs_mount,
98121e1553eSJérôme Duval 	&fs_unmount,
98221e1553eSJérôme Duval 	&fs_read_fs_stat,
98321e1553eSJérôme Duval 	NULL,
98421e1553eSJérôme Duval 	NULL,
98521e1553eSJérôme Duval 
98621e1553eSJérôme Duval 	/* vnode operations */
98721e1553eSJérôme Duval 	&fs_walk,
9883b723f79SJérôme Duval 	&fs_get_vnode_name,
98921e1553eSJérôme Duval 	&fs_read_vnode,
99021e1553eSJérôme Duval 	&fs_release_vnode,
99121e1553eSJérôme Duval 	NULL, 	// &fs_remove_vnode()
99221e1553eSJérôme Duval 
99321e1553eSJérôme Duval 	/* VM file access */
99421e1553eSJérôme Duval 	NULL, 	// &fs_can_page
99521e1553eSJérôme Duval 	NULL,	// &fs_read_pages
99621e1553eSJérôme Duval 	NULL, 	// &fs_write_pages
99721e1553eSJérôme Duval 
998*5b4cb109SJérôme Duval 	&fs_get_file_map,
99921e1553eSJérôme Duval 
100021e1553eSJérôme Duval 	NULL, 	// &fs_ioctl
100121e1553eSJérôme Duval 	NULL, 	// &fs_set_flags
10023b723f79SJérôme Duval 	NULL,	// &fs_select
10033b723f79SJérôme Duval 	NULL,	// &fs_deselect
100421e1553eSJérôme Duval 	NULL, 	// &fs_fsync
100521e1553eSJérôme Duval 
100621e1553eSJérôme Duval 	&fs_read_link,
100721e1553eSJérôme Duval 	NULL,	// write link
100821e1553eSJérôme Duval 	NULL, 	// &fs_create_symlink,
100921e1553eSJérôme Duval 
101021e1553eSJérôme Duval 	NULL, 	// &fs_link,
101121e1553eSJérôme Duval 	NULL,	// &fs_unlink
101221e1553eSJérôme Duval 	NULL, 	// &fs_rename
101321e1553eSJérôme Duval 
101421e1553eSJérôme Duval 	&fs_access,
101521e1553eSJérôme Duval 	&fs_read_stat,
101621e1553eSJérôme Duval 	NULL, 	// &fs_write_stat
101721e1553eSJérôme Duval 
101821e1553eSJérôme Duval 	/* file operations */
101921e1553eSJérôme Duval 	NULL, 	// &fs_create
102021e1553eSJérôme Duval 	&fs_open,
102121e1553eSJérôme Duval 	&fs_close,
102221e1553eSJérôme Duval 	&fs_free_cookie,
102321e1553eSJérôme Duval 	&fs_read,
102421e1553eSJérôme Duval 	NULL, 	// &fs_write
102521e1553eSJérôme Duval 
102621e1553eSJérôme Duval 	/* directory operations */
102721e1553eSJérôme Duval 	NULL, 	// &fs_create_dir
102821e1553eSJérôme Duval 	NULL, 	// &fs_remove_dir
102921e1553eSJérôme Duval 	&fs_open_dir,
103021e1553eSJérôme Duval 	&fs_close_dir,
103121e1553eSJérôme Duval 	&fs_free_dir_cookie,
103221e1553eSJérôme Duval 	&fs_read_dir,
103321e1553eSJérôme Duval 	&fs_rewind_dir,
103421e1553eSJérôme Duval 
103521e1553eSJérôme Duval 	/* attribute directory operations */
103621e1553eSJérôme Duval 	NULL, 	// &fs_open_attr_dir
103721e1553eSJérôme Duval 	NULL, 	// &fs_close_attr_dir
103821e1553eSJérôme Duval 	NULL,	// &fs_free_attr_dir_cookie
103921e1553eSJérôme Duval 	NULL,	// &fs_read_attr_dir
104021e1553eSJérôme Duval 	NULL,	// &fs_rewind_attr_dir
104121e1553eSJérôme Duval 
104221e1553eSJérôme Duval 	/* attribute operations */
104321e1553eSJérôme Duval 	NULL,	// &fs_create_attr
104421e1553eSJérôme Duval 	NULL, 	// &fs_open_attr
104521e1553eSJérôme Duval 	NULL,	// &fs_close_attr
104621e1553eSJérôme Duval 	NULL,	// &fs_free_attr_cookie
104721e1553eSJérôme Duval 	NULL,	// &fs_read_attr
104821e1553eSJérôme Duval 	NULL,	// &fs_write_attr
104921e1553eSJérôme Duval 
105021e1553eSJérôme Duval 	NULL,	// &fs_read_attr_stat
105121e1553eSJérôme Duval 	NULL,	// &fs_write_attr_stat
105221e1553eSJérôme Duval 	NULL,	// &fs_rename_attr
105321e1553eSJérôme Duval 	NULL,	// &fs_remove_attr
105421e1553eSJérôme Duval 
105521e1553eSJérôme Duval 	/* index directory & index operations */
105621e1553eSJérôme Duval 	NULL,	// &fs_open_index_dir
105721e1553eSJérôme Duval 	NULL,	// &fs_close_index_dir
105821e1553eSJérôme Duval 	NULL,	// &fs_free_index_dir_cookie
105921e1553eSJérôme Duval 	NULL,	// &fs_read_index_dir
106021e1553eSJérôme Duval 	NULL,	// &fs_rewind_index_dir
106121e1553eSJérôme Duval 
106221e1553eSJérôme Duval 	NULL,	// &fs_create_index
106321e1553eSJérôme Duval 	NULL,	// &fs_remove_index
106421e1553eSJérôme Duval 	NULL,	// &fs_stat_index
106521e1553eSJérôme Duval 
106621e1553eSJérôme Duval 	/* query operations */
106721e1553eSJérôme Duval 	NULL,	// &fs_open_query
106821e1553eSJérôme Duval 	NULL,	// &fs_close_query
106921e1553eSJérôme Duval 	NULL,	// &fs_free_query_cookie
107021e1553eSJérôme Duval 	NULL,	// &fs_read_query
107121e1553eSJérôme Duval 	NULL,	// &fs_rewind_query
107221e1553eSJérôme Duval };
107321e1553eSJérôme Duval 
107421e1553eSJérôme Duval module_info *modules[] = {
107521e1553eSJérôme Duval 	(module_info *)&sISO660FileSystem,
107621e1553eSJérôme Duval 	NULL,
107721e1553eSJérôme Duval };
107821e1553eSJérôme Duval 
1079