xref: /haiku/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp (revision 9d254f4567c54256dddbe9e02d582d3856967845)
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 <malloc.h>
2221e1553eSJérôme Duval 
2321e1553eSJérôme Duval #include <KernelExport.h>
2421e1553eSJérôme Duval #include <NodeMonitor.h>
2521e1553eSJérôme Duval #include <fs_interface.h>
2621e1553eSJérôme Duval #include <fs_cache.h>
2721e1553eSJérôme Duval 
2821e1553eSJérôme Duval #include <fs_attr.h>
2921e1553eSJérôme Duval #include <fs_info.h>
3021e1553eSJérôme Duval #include <fs_index.h>
3121e1553eSJérôme Duval #include <fs_query.h>
3221e1553eSJérôme Duval #include <fs_volume.h>
3321e1553eSJérôme Duval 
3421e1553eSJérôme Duval #include <util/kernel_cpp.h>
3521e1553eSJérôme Duval 
3644d56753SJérôme Duval #include "lock.h"
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);
605b4cb109SJérôme Duval static status_t		fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t offset, size_t size,
615b4cb109SJé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 
223*9d254f45SJérôme Duval 	// Unlike in BeOS, we need to put the reference to our root node ourselves
224*9d254f45SJérôme Duval 	put_vnode(ns->id, ISO_ROOTNODE_ID);
225*9d254f45SJérôme Duval 
22621e1553eSJérôme Duval 	block_cache_delete(ns->fBlockCache, false);
22721e1553eSJérôme Duval 	close(ns->fdOfSession);
22821e1553eSJérôme Duval 	result = close(ns->fd);
22921e1553eSJérôme Duval 
23021e1553eSJérôme Duval 	free(ns);
23121e1553eSJérôme Duval 
23221e1553eSJérôme Duval 	TRACE(("fs_unmount - EXIT, result is %s\n", strerror(result)));
23321e1553eSJérôme Duval 	return result;
23421e1553eSJérôme Duval }
23521e1553eSJérôme Duval 
23621e1553eSJérôme Duval 
23721e1553eSJérôme Duval static status_t
23821e1553eSJérôme Duval fs_read_fs_stat(void *_ns, struct fs_info *fss)
23921e1553eSJérôme Duval {
24021e1553eSJérôme Duval 	// Fill in fs_info struct for device.
24121e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
24221e1553eSJérôme Duval 	int i;
24321e1553eSJérôme Duval 
2445b4cb109SJérôme Duval 	TRACE(("fs_read_fs_stat - ENTER\n"));
24521e1553eSJérôme Duval 
24621e1553eSJérôme Duval 	// Fill in device id.
24721e1553eSJérôme Duval 	//fss->dev = ns->fd;
24821e1553eSJérôme Duval 
24921e1553eSJérôme Duval 	// Root vnode ID
25021e1553eSJérôme Duval 	//fss->root = ISO_ROOTNODE_ID;
25121e1553eSJérôme Duval 
25221e1553eSJérôme Duval 	// File system flags.
25321e1553eSJérôme Duval 	fss->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY;
25421e1553eSJérôme Duval 
25521e1553eSJérôme Duval 	// FS block size.
25621e1553eSJérôme Duval 	fss->block_size = ns->logicalBlkSize[FS_DATA_FORMAT];
25721e1553eSJérôme Duval 
25821e1553eSJérôme Duval 	// IO size - specifies buffer size for file copying
25921e1553eSJérôme Duval 	fss->io_size = 65536;
26021e1553eSJérôme Duval 
26121e1553eSJérôme Duval 	// Total blocks?
26221e1553eSJérôme Duval 	fss->total_blocks = ns->volSpaceSize[FS_DATA_FORMAT];
26321e1553eSJérôme Duval 
26421e1553eSJérôme Duval 	// Free blocks = 0, read only
26521e1553eSJérôme Duval 	fss->free_blocks = 0;
26621e1553eSJérôme Duval 
26721e1553eSJérôme Duval 	// Device name.
26821e1553eSJérôme Duval 	strncpy(fss->device_name, ns->devicePath, sizeof(fss->device_name));
26921e1553eSJérôme Duval 
27021e1553eSJérôme Duval 	strncpy(fss->volume_name, ns->volIDString, sizeof(fss->volume_name));
27121e1553eSJérôme Duval 	for (i = strlen(fss->volume_name)-1; i >=0 ; i--)
27221e1553eSJérôme Duval 		if (fss->volume_name[i] != ' ')
27321e1553eSJérôme Duval 			break;
27421e1553eSJérôme Duval 
27521e1553eSJérôme Duval 	if (i < 0)
27621e1553eSJérôme Duval 		strcpy(fss->volume_name, "UNKNOWN");
27721e1553eSJérôme Duval 	else
27821e1553eSJérôme Duval 		fss->volume_name[i + 1] = 0;
27921e1553eSJérôme Duval 
28021e1553eSJérôme Duval 	// File system name
28121e1553eSJérôme Duval 	strcpy(fss->fsh_name, "iso9660");
28221e1553eSJérôme Duval 
2835b4cb109SJérôme Duval 	TRACE(("fs_read_fs_stat - EXIT\n"));
28421e1553eSJérôme Duval 	return 0;
28521e1553eSJérôme Duval }
28621e1553eSJérôme Duval 
2873b723f79SJérôme Duval 
2883b723f79SJérôme Duval static status_t
2893b723f79SJérôme Duval fs_get_vnode_name(void *ns, void *_node, char *buffer, size_t bufferSize)
2903b723f79SJérôme Duval {
2913b723f79SJérôme Duval 	vnode *node = (vnode*)_node;
2923b723f79SJérôme Duval 
2933b723f79SJérôme Duval 	strlcpy(buffer, node->fileIDString, bufferSize);
2943b723f79SJérôme Duval 	return B_OK;
2953b723f79SJérôme Duval }
2963b723f79SJérôme Duval 
2973b723f79SJérôme Duval 
29821e1553eSJérôme Duval /* fs_walk - the walk function just "walks" through a directory looking for
29921e1553eSJérôme Duval 	the specified file. When you find it, call get_vnode on its vnid to init
30021e1553eSJérôme Duval 	it for the kernel.
30121e1553eSJérôme Duval */
30221e1553eSJérôme Duval static status_t
30321e1553eSJérôme Duval fs_walk(void *_ns, void *base, const char *file, vnode_id *_vnodeID, int *_type)
30421e1553eSJérôme Duval {
30521e1553eSJérôme Duval 	/* Starting at the base, find file in the subdir, and return path
30621e1553eSJérôme Duval 		string and vnode id of file. */
30721e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
30821e1553eSJérôme Duval 	vnode *baseNode = (vnode*)base;
30921e1553eSJérôme Duval 	uint32 dataLen = baseNode->dataLen[FS_DATA_FORMAT];
31021e1553eSJérôme Duval 	vnode *newNode = NULL;
31121e1553eSJérôme Duval 	status_t result = ENOENT;
31221e1553eSJérôme Duval 	bool done = FALSE;
31321e1553eSJérôme Duval 	uint32 totalRead = 0;
31421e1553eSJérôme Duval 	off_t block = baseNode->startLBN[FS_DATA_FORMAT];
31521e1553eSJérôme Duval 
31621e1553eSJérôme Duval 	TRACE(("fs_walk - looking for %s in dir file of length %d\n", file,
31721e1553eSJérôme Duval 		baseNode->dataLen[FS_DATA_FORMAT]));
31821e1553eSJérôme Duval 
31921e1553eSJérôme Duval 	if (strcmp(file, ".") == 0)  {
32021e1553eSJérôme Duval 		// base directory
32121e1553eSJérôme Duval 		TRACE(("fs_walk - found \".\" file.\n"));
32221e1553eSJérôme Duval 		*_vnodeID = baseNode->id;
32321e1553eSJérôme Duval 		*_type = S_IFDIR;
32421e1553eSJérôme Duval 		if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
32521e1553eSJérôme Duval     		result = EINVAL;
32621e1553eSJérôme Duval 	    else
32721e1553eSJérôme Duval 	    	result = B_NO_ERROR;
32821e1553eSJérôme Duval 	} else if (strcmp(file, "..") == 0) {
32921e1553eSJérôme Duval 		// parent directory
33021e1553eSJérôme Duval 		TRACE(("fs_walk - found \"..\" file.\n"));
33121e1553eSJérôme Duval 		*_vnodeID = baseNode->parID;
33221e1553eSJérôme Duval 		*_type = S_IFDIR;
33321e1553eSJérôme Duval 		if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
33421e1553eSJérôme Duval 			result = EINVAL;
33521e1553eSJérôme Duval 		else
33621e1553eSJérôme Duval 			result = B_NO_ERROR;
33721e1553eSJérôme Duval 	} else {
33821e1553eSJérôme Duval 		// look up file in the directory
33921e1553eSJérôme Duval 		char *blockData;
34021e1553eSJérôme Duval 
34121e1553eSJérôme Duval 		while ((totalRead < dataLen) && !done) {
34221e1553eSJérôme Duval 			off_t cachedBlock = block;
34321e1553eSJérôme Duval 
34421e1553eSJérôme Duval 			blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
34521e1553eSJérôme Duval 			if (blockData != NULL) {
34621e1553eSJérôme Duval 				int bytesRead = 0;
34721e1553eSJérôme Duval 				off_t blockBytesRead = 0;
34821e1553eSJérôme Duval 				vnode node;
34921e1553eSJérôme Duval 				int initResult;
35021e1553eSJérôme Duval 
35121e1553eSJérôme Duval 				TRACE(("fs_walk - read buffer from disk at LBN %Ld into buffer 0x%x.\n",
35221e1553eSJérôme Duval 					block, blockData));
35321e1553eSJérôme Duval 
35421e1553eSJérôme Duval 				// Move to the next 2-block set if necessary
35521e1553eSJérôme Duval 				// Don't go over end of buffer, if dir record sits on boundary.
35621e1553eSJérôme Duval 
35721e1553eSJérôme Duval 				node.fileIDString = NULL;
35821e1553eSJérôme Duval 				node.attr.slName = NULL;
35921e1553eSJérôme Duval 
36021e1553eSJérôme Duval 				while (blockBytesRead  < 2*ns->logicalBlkSize[FS_DATA_FORMAT]
36121e1553eSJérôme Duval 					&& totalRead + blockBytesRead < dataLen
36221e1553eSJérôme Duval 					&& blockData[0] != 0
36321e1553eSJérôme Duval 					&& !done)
36421e1553eSJérôme Duval 				{
36521e1553eSJérôme Duval 					initResult = InitNode(&node, blockData, &bytesRead, ns->joliet_level);
36621e1553eSJérôme Duval 					TRACE(("fs_walk - InitNode returned %s, filename %s, %d bytes read\n", strerror(initResult), node.fileIDString, bytesRead));
36721e1553eSJérôme Duval 
36821e1553eSJérôme Duval 					if (initResult == B_NO_ERROR) {
36921e1553eSJérôme Duval 						if (strlen(node.fileIDString) == strlen(file)
37021e1553eSJérôme Duval 							&& !strncmp(node.fileIDString, file, strlen(file)))
37121e1553eSJérôme Duval 						{
37221e1553eSJérôme Duval 							TRACE(("fs_walk - success, found vnode at block %Ld, pos %Ld\n", block, blockBytesRead));
37321e1553eSJérôme Duval 							*_vnodeID = (block << 30) + (blockBytesRead & 0xFFFFFFFF);
37421e1553eSJérôme Duval 							TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID));
37521e1553eSJérôme Duval 
37621e1553eSJérôme Duval 							if (get_vnode(ns->id, *_vnodeID, (void **)&newNode) != 0)
37721e1553eSJérôme Duval 								result = EINVAL;
37821e1553eSJérôme Duval 							else {
37921e1553eSJérôme Duval 								newNode->parID = baseNode->id;
38021e1553eSJérôme Duval 								done = TRUE;
38121e1553eSJérôme Duval 								result = B_NO_ERROR;
38221e1553eSJérôme Duval 							}
38321e1553eSJérôme Duval 						} else {
38421e1553eSJérôme Duval 							if (node.fileIDString != NULL) {
38521e1553eSJérôme Duval 								free(node.fileIDString);
38621e1553eSJérôme Duval 								node.fileIDString = NULL;
38721e1553eSJérôme Duval 							}
38821e1553eSJérôme Duval 							if (node.attr.slName != NULL) {
38921e1553eSJérôme Duval 								free(node.attr.slName);
39021e1553eSJérôme Duval 								node.attr.slName = NULL;
39121e1553eSJérôme Duval 							}
39221e1553eSJérôme Duval 						}
39321e1553eSJérôme Duval 					} else {
39421e1553eSJérôme Duval 						result = initResult;
39521e1553eSJérôme Duval 						if (bytesRead == 0)
39621e1553eSJérôme Duval 							done = TRUE;
39721e1553eSJérôme Duval 					}
39821e1553eSJérôme Duval 					blockData += bytesRead;
39921e1553eSJérôme Duval 					blockBytesRead += bytesRead;
40021e1553eSJérôme Duval 
40121e1553eSJérôme Duval 					TRACE(("fs_walk - Adding %d bytes to blockBytes read (total %Ld/%Ld).\n",
40221e1553eSJérôme Duval 						bytesRead, blockBytesRead, baseNode->dataLen[FS_DATA_FORMAT]));
40321e1553eSJérôme Duval 				}
40421e1553eSJérôme Duval 				totalRead += ns->logicalBlkSize[FS_DATA_FORMAT];
40521e1553eSJérôme Duval 				block++;
40621e1553eSJérôme Duval 
40721e1553eSJérôme Duval 				TRACE(("fs_walk - moving to next block %Ld, total read %Ld\n", block, totalRead));
40821e1553eSJérôme Duval 				block_cache_put(ns->fBlockCache, cachedBlock);
40921e1553eSJérôme Duval 
41021e1553eSJérôme Duval 			} else
41121e1553eSJérôme Duval 				done = TRUE;
41221e1553eSJérôme Duval 		}
41321e1553eSJérôme Duval 
4143b723f79SJérôme Duval 		if (newNode)
41521e1553eSJérôme Duval 			*_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode;
41621e1553eSJérôme Duval 
41721e1553eSJérôme Duval 	}
41821e1553eSJérôme Duval 	TRACE(("fs_walk - EXIT, result is %s, vnid is %Lu\n", strerror(result), *_vnodeID));
41921e1553eSJérôme Duval 	return result;
42021e1553eSJérôme Duval }
42121e1553eSJérôme Duval 
42221e1553eSJérôme Duval 
42321e1553eSJérôme Duval static status_t
42421e1553eSJérôme Duval fs_read_vnode(void *_ns, vnode_id vnid, void **node, bool reenter)
42521e1553eSJérôme Duval {
42621e1553eSJérôme Duval 	uint32 block, pos;
42721e1553eSJérôme Duval 	nspace *ns = (nspace*)_ns;
42821e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
42921e1553eSJérôme Duval 	vnode *newNode = (vnode*)calloc(sizeof(vnode), 1);
43021e1553eSJérôme Duval 
43121e1553eSJérôme Duval 	(void)reenter;
43221e1553eSJérôme Duval 
43321e1553eSJérôme Duval 	pos = (vnid & 0x3FFFFFFF);
43421e1553eSJérôme Duval 	block = (vnid >> 30);
43521e1553eSJérôme Duval 
43621e1553eSJérôme Duval 	TRACE(("fs_read_vnode - ENTER, block = %ld, pos = %ld, raw = %Lu node 0x%x\n",
43721e1553eSJérôme Duval 		block, pos, vnid, newNode));
43821e1553eSJérôme Duval 
43921e1553eSJérôme Duval 	if (newNode != NULL) {
44021e1553eSJérôme Duval 		if (vnid == ISO_ROOTNODE_ID) {
44121e1553eSJérôme Duval 			TRACE(("fs_read_vnode - root node requested.\n"));
44221e1553eSJérôme Duval 			memcpy(newNode, &(ns->rootDirRec), sizeof(vnode));
44321e1553eSJérôme Duval 			*node = (void*)newNode;
44421e1553eSJérôme Duval 		} else {
44521e1553eSJérôme Duval 			char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, block, 0, ns->logicalBlkSize[FS_DATA_FORMAT]);
44621e1553eSJérôme Duval 
44721e1553eSJérôme Duval 			if (pos > ns->logicalBlkSize[FS_DATA_FORMAT]) {
44821e1553eSJérôme Duval 				if (blockData != NULL)
44921e1553eSJérôme Duval 					block_cache_put(ns->fBlockCache, block);
45021e1553eSJérôme Duval 
45121e1553eSJérôme Duval 				result = EINVAL;
45221e1553eSJérôme Duval 		 	} else if (blockData != NULL) {
45321e1553eSJérôme Duval 				result = InitNode(newNode, blockData + pos, NULL, ns->joliet_level);
45421e1553eSJérôme Duval 				block_cache_put(ns->fBlockCache, block);
45521e1553eSJérôme Duval 				newNode->id = vnid;
45621e1553eSJérôme Duval 
45721e1553eSJérôme Duval 				TRACE(("fs_read_vnode - init result is %s\n", strerror(result)));
45821e1553eSJérôme Duval 				*node = (void *)newNode;
45921e1553eSJérôme Duval 				TRACE(("fs_read_vnode - new file %s, size %ld\n", newNode->fileIDString, newNode->dataLen[FS_DATA_FORMAT]));
46021e1553eSJérôme Duval 			}
46121e1553eSJérôme Duval 		}
46221e1553eSJérôme Duval 	} else
46321e1553eSJérôme Duval 		result = ENOMEM;
46421e1553eSJérôme Duval 
4655b4cb109SJérôme Duval 	if (result == B_OK && !(newNode->flags & ISO_ISDIR)) {
4665b4cb109SJérôme Duval 		newNode->cache = file_cache_create(ns->id, vnid, newNode->dataLen[FS_DATA_FORMAT], ns->fdOfSession);
4675b4cb109SJérôme Duval 	}
4685b4cb109SJérôme Duval 
46921e1553eSJérôme Duval 	TRACE(("fs_read_vnode - EXIT, result is %s\n", strerror(result)));
47021e1553eSJérôme Duval 	return result;
47121e1553eSJérôme Duval }
47221e1553eSJérôme Duval 
47321e1553eSJérôme Duval 
47421e1553eSJérôme Duval static status_t
47521e1553eSJérôme Duval fs_release_vnode(void *ns, void *_node, bool reenter)
47621e1553eSJérôme Duval {
47721e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
47821e1553eSJérôme Duval 	vnode *node = (vnode*)_node;
47921e1553eSJérôme Duval 
48021e1553eSJérôme Duval 	(void)ns;
48121e1553eSJérôme Duval 	(void)reenter;
48221e1553eSJérôme Duval 
4835b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - ENTER (0x%x)\n", node));
48421e1553eSJérôme Duval 
48521e1553eSJérôme Duval 	if (node != NULL) {
48621e1553eSJérôme Duval 		if (node->id != ISO_ROOTNODE_ID) {
48721e1553eSJérôme Duval 			if (node->fileIDString != NULL)
48821e1553eSJérôme Duval 				free (node->fileIDString);
48921e1553eSJérôme Duval 			if (node->attr.slName != NULL)
49021e1553eSJérôme Duval 				free (node->attr.slName);
4915b4cb109SJérôme Duval 			if (node->cache != NULL)
4925b4cb109SJérôme Duval 				file_cache_delete(node->cache);
49321e1553eSJérôme Duval 
49421e1553eSJérôme Duval 			free(node);
49521e1553eSJérôme Duval 		}
49621e1553eSJérôme Duval 	}
49721e1553eSJérôme Duval 
4985b4cb109SJérôme Duval 	TRACE(("fs_release_vnode - EXIT\n"));
49921e1553eSJérôme Duval 	return result;
50021e1553eSJérôme Duval }
50121e1553eSJérôme Duval 
50221e1553eSJérôme Duval 
50321e1553eSJérôme Duval static status_t
5045b4cb109SJérôme Duval fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t pos, size_t reqLen,
5055b4cb109SJérôme Duval 	struct file_io_vec *vecs, size_t *_count)
5065b4cb109SJérôme Duval {
5075b4cb109SJérôme Duval 	nspace *ns = (nspace *)_fs;			// global stuff
5085b4cb109SJérôme Duval 	vnode *node = (vnode *)_node;		// The read file vnode.
5095b4cb109SJérôme Duval 	uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT];
5105b4cb109SJérôme Duval 	uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize);
5115b4cb109SJérôme Duval 	off_t blockPos = pos % blockSize;
5125b4cb109SJérôme Duval 	off_t numBlocks = 0;
5135b4cb109SJérôme Duval 	uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
5145b4cb109SJérôme Duval 	size_t endLen = 0;
5155b4cb109SJérôme Duval 	size_t startLen =  0;
5165b4cb109SJérôme Duval 	size_t index = 0, max = *_count;
5175b4cb109SJérôme Duval 
5185b4cb109SJérôme Duval 	TRACE(("fs_get_file_map - ENTER (0x%x)\n", node));
5195b4cb109SJérôme Duval 
5205b4cb109SJérôme Duval 	// Allow an open to work on a dir, but no reads
5215b4cb109SJérôme Duval 	if (node->flags & ISO_ISDIR)
5225b4cb109SJérôme Duval 		return EISDIR;
5235b4cb109SJérôme Duval 
5245b4cb109SJérôme Duval 	if (pos < 0)
5255b4cb109SJérôme Duval 		pos = 0;
5265b4cb109SJérôme Duval 	*_count = 0;
5275b4cb109SJérôme Duval 
5285b4cb109SJérôme Duval 	// If passed-in requested length is bigger than file size, change it to
5295b4cb109SJérôme Duval 	// file size.
5305b4cb109SJérôme Duval 	if (reqLen + pos > dataLen)
5315b4cb109SJérôme Duval 		reqLen = dataLen - pos;
5325b4cb109SJérôme Duval 
5335b4cb109SJérôme Duval 	// Compute the length of the partial start-block read, if any.
5345b4cb109SJérôme Duval 	if (reqLen + blockPos <= blockSize)
5355b4cb109SJérôme Duval 		startLen = reqLen;
5365b4cb109SJérôme Duval 	else if (blockPos > 0)
5375b4cb109SJérôme Duval 		startLen = blockSize - blockPos;
5385b4cb109SJérôme Duval 
5395b4cb109SJérôme Duval 	if (blockPos == 0 && reqLen >= blockSize) {
5405b4cb109SJérôme Duval 		TRACE(("Setting startLen to 0\n"));
5415b4cb109SJérôme Duval 		startLen = 0;
5425b4cb109SJérôme Duval 	}
5435b4cb109SJérôme Duval 
5445b4cb109SJérôme Duval 	// Compute the length of the partial end-block read, if any.
5455b4cb109SJérôme Duval 	if (reqLen + blockPos > blockSize)
5465b4cb109SJérôme Duval 		endLen = (reqLen + blockPos) % blockSize;
5475b4cb109SJérôme Duval 
5485b4cb109SJérôme Duval 	// Compute the number of middle blocks to read.
5495b4cb109SJérôme Duval 	numBlocks = ((reqLen - endLen - startLen) /  blockSize);
5505b4cb109SJérôme Duval 
5515b4cb109SJérôme Duval 	if (pos >= dataLen) {
5525b4cb109SJérôme Duval 		// If pos >= file length, return
5535b4cb109SJérôme Duval 		return B_OK;
5545b4cb109SJérôme Duval 	}
5555b4cb109SJérôme Duval 
5565b4cb109SJérôme Duval 	// Read in the first, potentially partial, block.
5575b4cb109SJérôme Duval 	if (startLen > 0) {
5585b4cb109SJérôme Duval 		vecs[index].offset = startBlock * blockSize + blockPos;
5595b4cb109SJérôme Duval 		vecs[index].length = startLen;
5605b4cb109SJérôme Duval 		startBlock++;
5615b4cb109SJérôme Duval 		index++;
5625b4cb109SJérôme Duval 		if (index >= max) {
5635b4cb109SJérôme Duval 			// we're out of file_io_vecs; let's bail out
5645b4cb109SJérôme Duval 			*_count = index;
5655b4cb109SJérôme Duval 			return B_BUFFER_OVERFLOW;
5665b4cb109SJérôme Duval 		}
5675b4cb109SJérôme Duval 	}
5685b4cb109SJérôme Duval 
5695b4cb109SJérôme Duval 	// Read in the middle blocks.
5705b4cb109SJérôme Duval 	if (numBlocks > 0) {
5715b4cb109SJérôme Duval 		for (int32 i=startBlock; i<startBlock+numBlocks; i++) {
5725b4cb109SJérôme Duval 			vecs[index].offset = i * blockSize;
5735b4cb109SJérôme Duval 			vecs[index].length = blockSize;
5745b4cb109SJérôme Duval 			index++;
5755b4cb109SJérôme Duval 			if (index >= max) {
5765b4cb109SJérôme Duval 				// we're out of file_io_vecs; let's bail out
5775b4cb109SJérôme Duval 				*_count = index;
5785b4cb109SJérôme Duval 				return B_BUFFER_OVERFLOW;
5795b4cb109SJérôme Duval 			}
5805b4cb109SJérôme Duval 		}
5815b4cb109SJérôme Duval 	}
5825b4cb109SJérôme Duval 
5835b4cb109SJérôme Duval 	// Read in the last partial block.
5845b4cb109SJérôme Duval 	if (endLen > 0) {
5855b4cb109SJérôme Duval 		off_t endBlock = startBlock + numBlocks;
5865b4cb109SJérôme Duval 		vecs[index].offset = endBlock * blockSize;
5875b4cb109SJérôme Duval 		vecs[index].length = endLen;
5885b4cb109SJérôme Duval 		index++;
5895b4cb109SJérôme Duval 	}
5905b4cb109SJérôme Duval 
5915b4cb109SJérôme Duval 	*_count = index;
5925b4cb109SJérôme Duval 
5935b4cb109SJérôme Duval 	TRACE(("fs_get_file_map - EXIT\n"));
5945b4cb109SJérôme Duval 	return B_OK;
5955b4cb109SJérôme Duval }
5965b4cb109SJérôme Duval 
5975b4cb109SJérôme Duval 
5985b4cb109SJérôme Duval static status_t
59921e1553eSJérôme Duval fs_read_stat(void *_ns, void *_node, struct stat *st)
60021e1553eSJérôme Duval {
60121e1553eSJérôme Duval 	nspace *ns = (nspace*)_ns;
60221e1553eSJérôme Duval 	vnode *node = (vnode*)_node;
6033b723f79SJérôme Duval 	status_t result = B_NO_ERROR;
60421e1553eSJérôme Duval 	time_t time;
60521e1553eSJérôme Duval 
6063b723f79SJérôme Duval 	TRACE(("fs_read_stat - ENTER\n"));
60721e1553eSJérôme Duval 
60821e1553eSJérôme Duval 	st->st_dev = ns->id;
60921e1553eSJérôme Duval 	st->st_ino = node->id;
61021e1553eSJérôme Duval 	st->st_nlink = node->attr.stat[FS_DATA_FORMAT].st_nlink;
61121e1553eSJérôme Duval 	st->st_uid = node->attr.stat[FS_DATA_FORMAT].st_uid;
61221e1553eSJérôme Duval 	st->st_gid = node->attr.stat[FS_DATA_FORMAT].st_gid;
61321e1553eSJérôme Duval 	st->st_blksize = 65536;
61421e1553eSJérôme Duval 	st->st_mode = node->attr.stat[FS_DATA_FORMAT].st_mode;
61521e1553eSJérôme Duval 
61621e1553eSJérôme Duval 	// Same for file/dir in ISO9660
61721e1553eSJérôme Duval 	st->st_size = node->dataLen[FS_DATA_FORMAT];
61821e1553eSJérôme Duval 	if (ConvertRecDate(&(node->recordDate), &time) == B_NO_ERROR)
61921e1553eSJérôme Duval 		st->st_ctime = st->st_mtime = st->st_atime = time;
62021e1553eSJérôme Duval 
6213b723f79SJérôme Duval 	TRACE(("fs_read_stat - EXIT, result is %s\n", strerror(result)));
62221e1553eSJérôme Duval 
62321e1553eSJérôme Duval 	return result;
62421e1553eSJérôme Duval }
62521e1553eSJérôme Duval 
62621e1553eSJérôme Duval 
62721e1553eSJérôme Duval static status_t
62821e1553eSJérôme Duval fs_open(void *_ns, void *_node, int omode, void **cookie)
62921e1553eSJérôme Duval {
63021e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
63121e1553eSJérôme Duval 
63221e1553eSJérôme Duval 	(void)_ns;
63321e1553eSJérôme Duval 	(void)cookie;
63421e1553eSJérôme Duval 
63521e1553eSJérôme Duval 	// Do not allow any of the write-like open modes to get by
63621e1553eSJérôme Duval 	if ((omode == O_WRONLY) || (omode == O_RDWR))
63721e1553eSJérôme Duval 		result = EROFS;
63821e1553eSJérôme Duval 	else if((omode & O_TRUNC) || (omode & O_CREAT))
63921e1553eSJérôme Duval 		result = EROFS;
64021e1553eSJérôme Duval 
64121e1553eSJérôme Duval 	return result;
64221e1553eSJérôme Duval }
64321e1553eSJérôme Duval 
64421e1553eSJérôme Duval 
64521e1553eSJérôme Duval static status_t
64621e1553eSJérôme Duval fs_read(void *_ns, void *_node, void *cookie, off_t pos, void *buf, size_t *len)
64721e1553eSJérôme Duval {
6485b4cb109SJérôme Duval #if 0
64921e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;			// global stuff
65021e1553eSJérôme Duval 	vnode *node = (vnode *)_node;		// The read file vnode.
65121e1553eSJérôme Duval 	uint16 blockSize = ns->logicalBlkSize[FS_DATA_FORMAT];
65221e1553eSJérôme Duval 	uint32 startBlock = node->startLBN[FS_DATA_FORMAT] + (pos / blockSize);
65321e1553eSJérôme Duval 	off_t blockPos = pos % blockSize;
65421e1553eSJérôme Duval 	off_t numBlocks = 0;
65521e1553eSJérôme Duval 	uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
65621e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
65721e1553eSJérôme Duval 	size_t endLen = 0;
65821e1553eSJérôme Duval 	size_t reqLen = *len;
65921e1553eSJérôme Duval 	size_t startLen =  0;
66021e1553eSJérôme Duval 
66121e1553eSJérôme Duval 	(void)cookie;
66221e1553eSJérôme Duval 
66321e1553eSJérôme Duval 	// Allow an open to work on a dir, but no reads
66421e1553eSJérôme Duval 	if (node->flags & ISO_ISDIR)
66521e1553eSJérôme Duval 		return EISDIR;
66621e1553eSJérôme Duval 
66721e1553eSJérôme Duval 	if (pos < 0)
66821e1553eSJérôme Duval 		pos = 0;
66921e1553eSJérôme Duval 	*len = 0;
67021e1553eSJérôme Duval 
67121e1553eSJérôme Duval 	// If passed-in requested length is bigger than file size, change it to
67221e1553eSJérôme Duval 	// file size.
67321e1553eSJérôme Duval 	if (reqLen + pos > dataLen)
67421e1553eSJérôme Duval 		reqLen = dataLen - pos;
67521e1553eSJérôme Duval 
67621e1553eSJérôme Duval 	// Compute the length of the partial start-block read, if any.
67721e1553eSJérôme Duval 
67821e1553eSJérôme Duval 	if (reqLen + blockPos <= blockSize)
67921e1553eSJérôme Duval 		startLen = reqLen;
68021e1553eSJérôme Duval 	else if (blockPos > 0)
68121e1553eSJérôme Duval 		startLen = blockSize - blockPos;
68221e1553eSJérôme Duval 
68321e1553eSJérôme Duval 	if (blockPos == 0 && reqLen >= blockSize) {
68421e1553eSJérôme Duval 		TRACE(("Setting startLen to 0, even block read\n"));
68521e1553eSJérôme Duval 		startLen = 0;
68621e1553eSJérôme Duval 	}
68721e1553eSJérôme Duval 
68821e1553eSJérôme Duval 	// Compute the length of the partial end-block read, if any.
68921e1553eSJérôme Duval 	if (reqLen + blockPos > blockSize)
69021e1553eSJérôme Duval 		endLen = (reqLen + blockPos) % blockSize;
69121e1553eSJérôme Duval 
69221e1553eSJérôme Duval 	// Compute the number of middle blocks to read.
69321e1553eSJérôme Duval 	numBlocks = ((reqLen - endLen - startLen) /  blockSize);
69421e1553eSJérôme Duval 
69521e1553eSJérôme Duval 	//dprintf("fs_read - ENTER, pos is %Ld, len is %lu\n", pos, reqLen);
69621e1553eSJérôme Duval 	//dprintf("fs_read - filename is %s\n", node->fileIDString);
69721e1553eSJérôme Duval 	//dprintf("fs_read - total file length is %lu\n", dataLen);
69821e1553eSJérôme Duval 	//dprintf("fs_read - start block of file is %lu\n", node->startLBN[FS_DATA_FORMAT]);
69921e1553eSJérôme Duval 	//dprintf("fs_read - block pos is %Lu\n", blockPos);
70021e1553eSJérôme Duval 	//dprintf("fs_read - read block will be %lu\n", startBlock);
70121e1553eSJérôme Duval 	//dprintf("fs_read - startLen is %lu\n", startLen);
70221e1553eSJérôme Duval 	//dprintf("fs_read - endLen is %lu\n", endLen);
70321e1553eSJérôme Duval 	//dprintf("fs_read - num blocks to read is %Ld\n", numBlocks);
70421e1553eSJérôme Duval 
70521e1553eSJérôme Duval 	if (pos >= dataLen) {
70621e1553eSJérôme Duval 		// If pos >= file length, return length of 0.
70721e1553eSJérôme Duval 		*len = 0;
70821e1553eSJérôme Duval 		return B_OK;
70921e1553eSJérôme Duval 	}
71021e1553eSJérôme Duval 
71121e1553eSJérôme Duval 	// Read in the first, potentially partial, block.
71221e1553eSJérôme Duval 	if (startLen > 0) {
71321e1553eSJérôme Duval 		off_t cachedBlock = startBlock;
71421e1553eSJérôme Duval 		char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, startBlock, 0, blockSize);
71521e1553eSJérôme Duval 		if (blockData != NULL) {
71621e1553eSJérôme Duval 			//dprintf("fs_read - copying first block, len is %d.\n", startLen);
71721e1553eSJérôme Duval 			memcpy(buf, blockData+blockPos, startLen);
71821e1553eSJérôme Duval 			*len += startLen;
71921e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, cachedBlock);
72021e1553eSJérôme Duval 			startBlock++;
7213b723f79SJérôme Duval 		} else
7223b723f79SJérôme Duval 			result = EIO;
72321e1553eSJérôme Duval 	}
72421e1553eSJérôme Duval 
72521e1553eSJérôme Duval 	// Read in the middle blocks.
72621e1553eSJérôme Duval 	if (numBlocks > 0 && result == B_NO_ERROR) {
72721e1553eSJérôme Duval 		TRACE(("fs_read - getting middle blocks\n"));
7283b723f79SJérôme Duval 		char *endBuf = ((char *)buf) + startLen;
72921e1553eSJérôme Duval 		for (int32 i=startBlock; i<startBlock+numBlocks; i++) {
73021e1553eSJérôme Duval 			char *blockData = (char *)block_cache_get_etc(ns->fBlockCache, i, 0, blockSize);
7313b723f79SJérôme Duval 			memcpy(endBuf, blockData, blockSize);
73221e1553eSJérôme Duval 			*len += blockSize;
7333b723f79SJérôme Duval 			endBuf += blockSize;
73421e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, i);
73521e1553eSJérôme Duval 		}
73621e1553eSJérôme Duval 	}
73721e1553eSJérôme Duval 
73821e1553eSJérôme Duval 	// Read in the last partial block.
73921e1553eSJérôme Duval 	if (result == B_NO_ERROR && endLen > 0) {
74021e1553eSJérôme Duval 		off_t endBlock = startBlock + numBlocks;
74121e1553eSJérôme Duval 		char *endBlockData = (char*)block_cache_get_etc(ns->fBlockCache, endBlock, 0, blockSize);
74221e1553eSJérôme Duval 		if (endBlockData != NULL) {
74321e1553eSJérôme Duval 			char *endBuf = ((char *)buf) + (reqLen - endLen);
74421e1553eSJérôme Duval 
74521e1553eSJérôme Duval 			memcpy(endBuf, endBlockData, endLen);
74621e1553eSJérôme Duval 			block_cache_put(ns->fBlockCache, endBlock);
74721e1553eSJérôme Duval 			*len += endLen;
74821e1553eSJérôme Duval 		} else
74921e1553eSJérôme Duval 			result = EIO;
75021e1553eSJérôme Duval 	}
75121e1553eSJérôme Duval 
75221e1553eSJérôme Duval 	TRACE(("fs_read - EXIT, result is %s\n", strerror(result)));
75321e1553eSJérôme Duval 	return result;
7545b4cb109SJérôme Duval #else
7555b4cb109SJérôme Duval 	vnode *node = (vnode *)_node;           // The read file vnode.
7565b4cb109SJérôme Duval 	uint32 dataLen = node->dataLen[FS_DATA_FORMAT];
7575b4cb109SJérôme Duval 
7585b4cb109SJérôme Duval 	// set/check boundaries for pos/length
7595b4cb109SJérôme Duval 	if (pos < 0) {
7605b4cb109SJérôme Duval 		return B_BAD_VALUE;
7615b4cb109SJérôme Duval 	}
7625b4cb109SJérôme Duval 	if (pos >= dataLen) {
7635b4cb109SJérôme Duval 		// If pos >= file length, return length of 0.
7645b4cb109SJérôme Duval 		*len = 0;
7655b4cb109SJérôme Duval 		return B_OK;
7665b4cb109SJérôme Duval         }
7675b4cb109SJérôme Duval 	return file_cache_read(node->cache, pos, buf, len);
7685b4cb109SJérôme Duval #endif
76921e1553eSJérôme Duval }
77021e1553eSJérôme Duval 
77121e1553eSJérôme Duval 
77221e1553eSJérôme Duval static status_t
77321e1553eSJérôme Duval fs_close(void *ns, void *node, void *cookie)
77421e1553eSJérôme Duval {
77521e1553eSJérôme Duval 	(void)ns;
77621e1553eSJérôme Duval 	(void)node;
77721e1553eSJérôme Duval 	(void)cookie;
77821e1553eSJérôme Duval 
77921e1553eSJérôme Duval 	//dprintf("fs_close - ENTER\n");
78021e1553eSJérôme Duval 	//dprintf("fs_close - EXIT\n");
78121e1553eSJérôme Duval 	return B_OK;
78221e1553eSJérôme Duval }
78321e1553eSJérôme Duval 
78421e1553eSJérôme Duval static status_t
78521e1553eSJérôme Duval fs_free_cookie(void *ns, void *node, void *cookie)
78621e1553eSJérôme Duval {
78721e1553eSJérôme Duval 	(void)ns;
78821e1553eSJérôme Duval 	(void)node;
78921e1553eSJérôme Duval 	(void)cookie;
79021e1553eSJérôme Duval 
79121e1553eSJérôme Duval 	// We don't allocate file cookies, so we do nothing here.
79221e1553eSJérôme Duval 	//dprintf("fs_free_cookie - ENTER\n");
79321e1553eSJérôme Duval 	//if (cookie != NULL) free (cookie);
79421e1553eSJérôme Duval 	//dprintf("fs_free_cookie - EXIT\n");
79521e1553eSJérôme Duval 	return B_OK;
79621e1553eSJérôme Duval }
79721e1553eSJérôme Duval 
79821e1553eSJérôme Duval // fs_access - checks permissions for access.
79921e1553eSJérôme Duval static status_t
80021e1553eSJérôme Duval fs_access(void *ns, void *node, int mode)
80121e1553eSJérôme Duval {
80221e1553eSJérôme Duval 	(void)ns;
80321e1553eSJérôme Duval 	(void)node;
80421e1553eSJérôme Duval 	(void)mode;
80521e1553eSJérôme Duval 
80621e1553eSJérôme Duval 	// ns 	- global, fs-specific struct for device
80721e1553eSJérôme Duval 	// node	- node to check permissions for
80821e1553eSJérôme Duval 	// mode - requested permissions on node.
80921e1553eSJérôme Duval 	//dprintf("fs_access - ENTER\n");
81021e1553eSJérôme Duval 	//dprintf("fs_access - EXIT\n");
81121e1553eSJérôme Duval 	return B_OK;
81221e1553eSJérôme Duval }
81321e1553eSJérôme Duval 
81421e1553eSJérôme Duval static status_t
81521e1553eSJérôme Duval fs_read_link(void *_ns, void *_node, char *buffer, size_t *_bufferSize)
81621e1553eSJérôme Duval {
81721e1553eSJérôme Duval 	vnode *node = (vnode *)_node;
81821e1553eSJérôme Duval 	status_t result = EINVAL;
81921e1553eSJérôme Duval 
82021e1553eSJérôme Duval 	(void)_ns;
82121e1553eSJérôme Duval 
82221e1553eSJérôme Duval 	if (S_ISLNK(node->attr.stat[FS_DATA_FORMAT].st_mode)) {
82321e1553eSJérôme Duval 		size_t length = strlen(node->attr.slName);
82421e1553eSJérôme Duval 		if (length > *_bufferSize)
8253b723f79SJérôme Duval 			memcpy(buffer, node->attr.slName, *_bufferSize);
8263b723f79SJérôme Duval 		else {
82721e1553eSJérôme Duval 			memcpy(buffer, node->attr.slName, length);
8283b723f79SJérôme Duval 			*_bufferSize = length;
8293b723f79SJérôme Duval 		}
83021e1553eSJérôme Duval 
83121e1553eSJérôme Duval 		result = B_NO_ERROR;
83221e1553eSJérôme Duval 	}
83321e1553eSJérôme Duval 
83421e1553eSJérôme Duval 	return result;
83521e1553eSJérôme Duval }
83621e1553eSJérôme Duval 
83721e1553eSJérôme Duval 
83821e1553eSJérôme Duval static status_t
83921e1553eSJérôme Duval fs_open_dir(void *_ns, void *_node, void **cookie)
84021e1553eSJérôme Duval {
84121e1553eSJérôme Duval 	vnode *node = (vnode *)_node;
84221e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
84321e1553eSJérôme Duval 	dircookie *dirCookie = (dircookie *)malloc(sizeof(dircookie));
84421e1553eSJérôme Duval 
84521e1553eSJérôme Duval 	(void)_ns;
84621e1553eSJérôme Duval 
8475b4cb109SJérôme Duval 	TRACE(("fs_open_dir - ENTER, node is 0x%x\n", _node));
84821e1553eSJérôme Duval 
84921e1553eSJérôme Duval 	if (!(node->flags & ISO_ISDIR))
85021e1553eSJérôme Duval 		result = EMFILE;
85121e1553eSJérôme Duval 
85221e1553eSJérôme Duval 	if (dirCookie != NULL) {
85321e1553eSJérôme Duval 		dirCookie->startBlock = node->startLBN[FS_DATA_FORMAT];
85421e1553eSJérôme Duval 		dirCookie->block = node->startLBN[FS_DATA_FORMAT];
85521e1553eSJérôme Duval 		dirCookie->totalSize = node->dataLen[FS_DATA_FORMAT];
85621e1553eSJérôme Duval 		dirCookie->pos = 0;
85721e1553eSJérôme Duval 		dirCookie->id = node->id;
85821e1553eSJérôme Duval 		*cookie = (void *)dirCookie;
85921e1553eSJérôme Duval 	} else
86021e1553eSJérôme Duval 		result = ENOMEM;
86121e1553eSJérôme Duval 
8625b4cb109SJérôme Duval 	TRACE(("fs_open_dir - EXIT\n"));
86321e1553eSJérôme Duval 	return result;
86421e1553eSJérôme Duval }
86521e1553eSJérôme Duval 
86621e1553eSJérôme Duval 
86721e1553eSJérôme Duval static status_t
86821e1553eSJérôme Duval fs_read_dir(void *_ns, void *_node, void *_cookie, struct dirent *buffer,
86921e1553eSJérôme Duval 	size_t bufferSize, uint32 *num)
87021e1553eSJérôme Duval {
87121e1553eSJérôme Duval 	status_t result = B_NO_ERROR;
87221e1553eSJérôme Duval 	nspace *ns = (nspace *)_ns;
87321e1553eSJérôme Duval 	dircookie *dirCookie = (dircookie *)_cookie;
87421e1553eSJérôme Duval 
87521e1553eSJérôme Duval 	(void)_node;
87621e1553eSJérôme Duval 
8775b4cb109SJérôme Duval 	TRACE(("fs_read_dir - ENTER\n"));
87821e1553eSJérôme Duval 
87921e1553eSJérôme Duval 	result = ISOReadDirEnt(ns, dirCookie, buffer, bufferSize);
88021e1553eSJérôme Duval 
88121e1553eSJérôme Duval 	// If we succeeded, return 1, the number of dirents we read.
88221e1553eSJérôme Duval 	if (result == B_NO_ERROR)
88321e1553eSJérôme Duval 		*num = 1;
88421e1553eSJérôme Duval 	else
88521e1553eSJérôme Duval 		*num = 0;
88621e1553eSJérôme Duval 
88721e1553eSJérôme Duval 	// When you get to the end, don't return an error, just return
88821e1553eSJérôme Duval 	// a zero in *num.
88921e1553eSJérôme Duval 
89021e1553eSJérôme Duval 	if (result == ENOENT)
89121e1553eSJérôme Duval 		result = B_NO_ERROR;
89221e1553eSJérôme Duval 
8935b4cb109SJérôme Duval 	TRACE(("fs_read_dir - EXIT, result is %s\n", strerror(result)));
89421e1553eSJérôme Duval 	return result;
89521e1553eSJérôme Duval }
89621e1553eSJérôme Duval 
89721e1553eSJérôme Duval 
89821e1553eSJérôme Duval static status_t
89921e1553eSJérôme Duval fs_rewind_dir(void *ns, void *node, void* _cookie)
90021e1553eSJérôme Duval {
90121e1553eSJérôme Duval 	status_t result = EINVAL;
90221e1553eSJérôme Duval 	dircookie *cookie = (dircookie*)_cookie;
90321e1553eSJérôme Duval 
90421e1553eSJérôme Duval 	(void)ns;
90521e1553eSJérôme Duval 	(void)node;
90621e1553eSJérôme Duval 
9075b4cb109SJérôme Duval 	//dprintf("fs_rewind_dir - ENTER\n");
90821e1553eSJérôme Duval 	if (cookie != NULL) {
90921e1553eSJérôme Duval 		cookie->block = cookie->startBlock;
91021e1553eSJérôme Duval 		cookie->pos = 0;
91121e1553eSJérôme Duval 		result = B_NO_ERROR;
91221e1553eSJérôme Duval 	}
9135b4cb109SJérôme Duval 	//dprintf("fs_rewind_dir - EXIT, result is %s\n", strerror(result));
91421e1553eSJérôme Duval 	return result;
91521e1553eSJérôme Duval }
91621e1553eSJérôme Duval 
91721e1553eSJérôme Duval 
91821e1553eSJérôme Duval static status_t
91921e1553eSJérôme Duval fs_close_dir(void *ns, void *node, void *cookie)
92021e1553eSJérôme Duval {
92121e1553eSJérôme Duval 	(void)ns;
92221e1553eSJérôme Duval 	(void)node;
92321e1553eSJérôme Duval 	(void)cookie;
92421e1553eSJérôme Duval 
92521e1553eSJérôme Duval 	// ns 		- global, fs-specific struct for device
92621e1553eSJérôme Duval 	// node		- directory to close
92721e1553eSJérôme Duval 	// cookie	- current cookie for directory.
9285b4cb109SJérôme Duval 	//dprintf("fs_close_dir - ENTER\n");
9295b4cb109SJérôme Duval 	//dprintf("fs_close_dir - EXIT\n");
93021e1553eSJérôme Duval 	return B_OK;
93121e1553eSJérôme Duval }
93221e1553eSJérôme Duval 
93321e1553eSJérôme Duval 
93421e1553eSJérôme Duval static status_t
93521e1553eSJérôme Duval fs_free_dir_cookie(void *ns, void *node, void *cookie)
93621e1553eSJérôme Duval {
93721e1553eSJérôme Duval 	(void)ns;
93821e1553eSJérôme Duval 	(void)node;
93921e1553eSJérôme Duval 
94021e1553eSJérôme Duval 	// ns 		- global, fs-specific struct for device
94121e1553eSJérôme Duval 	// node		- directory related to cookie
94221e1553eSJérôme Duval 	// cookie	- current cookie for directory, to free.
9435b4cb109SJérôme Duval 	//dprintf("fs_free_dir_cookie - ENTER\n");
94421e1553eSJérôme Duval 	if (cookie != NULL)
94521e1553eSJérôme Duval 		free(cookie);
94621e1553eSJérôme Duval 
9475b4cb109SJérôme Duval 	//dprintf("fs_free_dir_cookie - EXIT\n");
94821e1553eSJérôme Duval 	return B_OK;
94921e1553eSJérôme Duval }
95021e1553eSJérôme Duval 
95121e1553eSJérôme Duval //	#pragma mark -
95221e1553eSJérôme Duval 
95321e1553eSJérôme Duval 
95421e1553eSJérôme Duval static status_t
95521e1553eSJérôme Duval iso_std_ops(int32 op, ...)
95621e1553eSJérôme Duval {
95721e1553eSJérôme Duval 	switch (op) {
95821e1553eSJérôme Duval 		case B_MODULE_INIT:
95921e1553eSJérôme Duval 			return B_OK;
96021e1553eSJérôme Duval 		case B_MODULE_UNINIT:
96121e1553eSJérôme Duval 			return B_OK;
96221e1553eSJérôme Duval 		default:
96321e1553eSJérôme Duval 			return B_ERROR;
96421e1553eSJérôme Duval 	}
96521e1553eSJérôme Duval }
96621e1553eSJérôme Duval 
96721e1553eSJérôme Duval 
96821e1553eSJérôme Duval static file_system_module_info sISO660FileSystem = {
96921e1553eSJérôme Duval 	{
97021e1553eSJérôme Duval 		"file_systems/iso9660" B_CURRENT_FS_API_VERSION,
97121e1553eSJérôme Duval 		0,
97221e1553eSJérôme Duval 		iso_std_ops,
97321e1553eSJérôme Duval 	},
97421e1553eSJérôme Duval 
97521e1553eSJérôme Duval 	"ISO9660 File System",
97621e1553eSJérôme Duval 
97721e1553eSJérôme Duval 	// scanning
97821e1553eSJérôme Duval 	fs_identify_partition,
97921e1553eSJérôme Duval 	fs_scan_partition,
98021e1553eSJérôme Duval 	fs_free_identify_partition_cookie,
98121e1553eSJérôme Duval 	NULL,	// free_partition_content_cookie()
98221e1553eSJérôme Duval 
98321e1553eSJérôme Duval 	&fs_mount,
98421e1553eSJérôme Duval 	&fs_unmount,
98521e1553eSJérôme Duval 	&fs_read_fs_stat,
98621e1553eSJérôme Duval 	NULL,
98721e1553eSJérôme Duval 	NULL,
98821e1553eSJérôme Duval 
98921e1553eSJérôme Duval 	/* vnode operations */
99021e1553eSJérôme Duval 	&fs_walk,
9913b723f79SJérôme Duval 	&fs_get_vnode_name,
99221e1553eSJérôme Duval 	&fs_read_vnode,
99321e1553eSJérôme Duval 	&fs_release_vnode,
99421e1553eSJérôme Duval 	NULL, 	// &fs_remove_vnode()
99521e1553eSJérôme Duval 
99621e1553eSJérôme Duval 	/* VM file access */
99721e1553eSJérôme Duval 	NULL, 	// &fs_can_page
99821e1553eSJérôme Duval 	NULL,	// &fs_read_pages
99921e1553eSJérôme Duval 	NULL, 	// &fs_write_pages
100021e1553eSJérôme Duval 
10015b4cb109SJérôme Duval 	&fs_get_file_map,
100221e1553eSJérôme Duval 
100321e1553eSJérôme Duval 	NULL, 	// &fs_ioctl
100421e1553eSJérôme Duval 	NULL, 	// &fs_set_flags
10053b723f79SJérôme Duval 	NULL,	// &fs_select
10063b723f79SJérôme Duval 	NULL,	// &fs_deselect
100721e1553eSJérôme Duval 	NULL, 	// &fs_fsync
100821e1553eSJérôme Duval 
100921e1553eSJérôme Duval 	&fs_read_link,
101021e1553eSJérôme Duval 	NULL,	// write link
101121e1553eSJérôme Duval 	NULL, 	// &fs_create_symlink,
101221e1553eSJérôme Duval 
101321e1553eSJérôme Duval 	NULL, 	// &fs_link,
101421e1553eSJérôme Duval 	NULL,	// &fs_unlink
101521e1553eSJérôme Duval 	NULL, 	// &fs_rename
101621e1553eSJérôme Duval 
101721e1553eSJérôme Duval 	&fs_access,
101821e1553eSJérôme Duval 	&fs_read_stat,
101921e1553eSJérôme Duval 	NULL, 	// &fs_write_stat
102021e1553eSJérôme Duval 
102121e1553eSJérôme Duval 	/* file operations */
102221e1553eSJérôme Duval 	NULL, 	// &fs_create
102321e1553eSJérôme Duval 	&fs_open,
102421e1553eSJérôme Duval 	&fs_close,
102521e1553eSJérôme Duval 	&fs_free_cookie,
102621e1553eSJérôme Duval 	&fs_read,
102721e1553eSJérôme Duval 	NULL, 	// &fs_write
102821e1553eSJérôme Duval 
102921e1553eSJérôme Duval 	/* directory operations */
103021e1553eSJérôme Duval 	NULL, 	// &fs_create_dir
103121e1553eSJérôme Duval 	NULL, 	// &fs_remove_dir
103221e1553eSJérôme Duval 	&fs_open_dir,
103321e1553eSJérôme Duval 	&fs_close_dir,
103421e1553eSJérôme Duval 	&fs_free_dir_cookie,
103521e1553eSJérôme Duval 	&fs_read_dir,
103621e1553eSJérôme Duval 	&fs_rewind_dir,
103721e1553eSJérôme Duval 
103821e1553eSJérôme Duval 	/* attribute directory operations */
103921e1553eSJérôme Duval 	NULL, 	// &fs_open_attr_dir
104021e1553eSJérôme Duval 	NULL, 	// &fs_close_attr_dir
104121e1553eSJérôme Duval 	NULL,	// &fs_free_attr_dir_cookie
104221e1553eSJérôme Duval 	NULL,	// &fs_read_attr_dir
104321e1553eSJérôme Duval 	NULL,	// &fs_rewind_attr_dir
104421e1553eSJérôme Duval 
104521e1553eSJérôme Duval 	/* attribute operations */
104621e1553eSJérôme Duval 	NULL,	// &fs_create_attr
104721e1553eSJérôme Duval 	NULL, 	// &fs_open_attr
104821e1553eSJérôme Duval 	NULL,	// &fs_close_attr
104921e1553eSJérôme Duval 	NULL,	// &fs_free_attr_cookie
105021e1553eSJérôme Duval 	NULL,	// &fs_read_attr
105121e1553eSJérôme Duval 	NULL,	// &fs_write_attr
105221e1553eSJérôme Duval 
105321e1553eSJérôme Duval 	NULL,	// &fs_read_attr_stat
105421e1553eSJérôme Duval 	NULL,	// &fs_write_attr_stat
105521e1553eSJérôme Duval 	NULL,	// &fs_rename_attr
105621e1553eSJérôme Duval 	NULL,	// &fs_remove_attr
105721e1553eSJérôme Duval 
105821e1553eSJérôme Duval 	/* index directory & index operations */
105921e1553eSJérôme Duval 	NULL,	// &fs_open_index_dir
106021e1553eSJérôme Duval 	NULL,	// &fs_close_index_dir
106121e1553eSJérôme Duval 	NULL,	// &fs_free_index_dir_cookie
106221e1553eSJérôme Duval 	NULL,	// &fs_read_index_dir
106321e1553eSJérôme Duval 	NULL,	// &fs_rewind_index_dir
106421e1553eSJérôme Duval 
106521e1553eSJérôme Duval 	NULL,	// &fs_create_index
106621e1553eSJérôme Duval 	NULL,	// &fs_remove_index
106721e1553eSJérôme Duval 	NULL,	// &fs_stat_index
106821e1553eSJérôme Duval 
106921e1553eSJérôme Duval 	/* query operations */
107021e1553eSJérôme Duval 	NULL,	// &fs_open_query
107121e1553eSJérôme Duval 	NULL,	// &fs_close_query
107221e1553eSJérôme Duval 	NULL,	// &fs_free_query_cookie
107321e1553eSJérôme Duval 	NULL,	// &fs_read_query
107421e1553eSJérôme Duval 	NULL,	// &fs_rewind_query
107521e1553eSJérôme Duval };
107621e1553eSJérôme Duval 
107721e1553eSJérôme Duval module_info *modules[] = {
107821e1553eSJérôme Duval 	(module_info *)&sISO660FileSystem,
107921e1553eSJérôme Duval 	NULL,
108021e1553eSJérôme Duval };
108121e1553eSJérôme Duval 
1082