xref: /haiku/src/add-ons/kernel/file_systems/udf/Volume.cpp (revision 3f4628f1ae403c7ed9fbf20851c0cf03a206a7b7)
129008bcfSTyler Dauwalder //----------------------------------------------------------------------
229008bcfSTyler Dauwalder //  This software is part of the OpenBeOS distribution and is covered
329008bcfSTyler Dauwalder //  by the OpenBeOS license.
429008bcfSTyler Dauwalder //
529008bcfSTyler Dauwalder //  Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
629008bcfSTyler Dauwalder //  Mad props to Axel Dörfler and his BFS implementation, from which
729008bcfSTyler Dauwalder //  this UDF implementation draws much influence (and a little code :-P).
829008bcfSTyler Dauwalder //----------------------------------------------------------------------
929008bcfSTyler Dauwalder #include "Volume.h"
1029008bcfSTyler Dauwalder 
11*3f4628f1STyler Dauwalder #include "Icb.h"
120d383564STyler Dauwalder #include "MemoryChunk.h"
1329008bcfSTyler Dauwalder 
14*3f4628f1STyler Dauwalder using namespace Udf;
1529008bcfSTyler Dauwalder 
1629008bcfSTyler Dauwalder //----------------------------------------------------------------------
1729008bcfSTyler Dauwalder // Volume
1829008bcfSTyler Dauwalder //----------------------------------------------------------------------
1929008bcfSTyler Dauwalder 
2029008bcfSTyler Dauwalder /*! \brief Creates an unmounted volume with the given id.
2129008bcfSTyler Dauwalder */
2229008bcfSTyler Dauwalder Volume::Volume(nspace_id id)
23*3f4628f1STyler Dauwalder 	: fId(id)
2429008bcfSTyler Dauwalder 	, fDevice(0)
2529008bcfSTyler Dauwalder 	, fReadOnly(false)
26*3f4628f1STyler Dauwalder 	, fStart(0)
274ac73018STyler Dauwalder 	, fBlockSize(0)
284ac73018STyler Dauwalder 	, fInitStatus(B_UNINITIALIZED)
29*3f4628f1STyler Dauwalder 	, fRootIcb(NULL)
3029008bcfSTyler Dauwalder {
3129008bcfSTyler Dauwalder }
3229008bcfSTyler Dauwalder 
3329008bcfSTyler Dauwalder status_t
3429008bcfSTyler Dauwalder Volume::Identify(int device, off_t base)
3529008bcfSTyler Dauwalder {
3629008bcfSTyler Dauwalder 	return B_ERROR;
3729008bcfSTyler Dauwalder }
3829008bcfSTyler Dauwalder 
3929008bcfSTyler Dauwalder /*! \brief Attempts to mount the given device.
40*3f4628f1STyler Dauwalder 
41*3f4628f1STyler Dauwalder 	\param volumeStart The block on the given device whereat the volume begins.
42*3f4628f1STyler Dauwalder 	\param volumeLength The block length of the volume on the given device.
4329008bcfSTyler Dauwalder */
4429008bcfSTyler Dauwalder status_t
454ac73018STyler Dauwalder Volume::Mount(const char *deviceName, off_t volumeStart, off_t volumeLength,
464ac73018STyler Dauwalder               uint32 flags, uint32 blockSize)
4729008bcfSTyler Dauwalder {
48565457fdSTyler Dauwalder 	DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "Volume",
49565457fdSTyler Dauwalder 		("devName = `%s'", deviceName));
5029008bcfSTyler Dauwalder 	if (!deviceName)
5129008bcfSTyler Dauwalder 		RETURN_ERROR(B_BAD_VALUE);
524ac73018STyler Dauwalder 	if (_InitStatus() == B_INITIALIZED)
534ac73018STyler Dauwalder 		RETURN_ERROR(B_BUSY);
544ac73018STyler Dauwalder 			// Already mounted, thank you for asking
5529008bcfSTyler Dauwalder 
5629008bcfSTyler Dauwalder 	fReadOnly = flags & B_READ_ONLY;
57*3f4628f1STyler Dauwalder 	fStart = volumeStart;
584ac73018STyler Dauwalder 	fLength = volumeLength;
594ac73018STyler Dauwalder 	fBlockSize = blockSize;
6029008bcfSTyler Dauwalder 
6129008bcfSTyler Dauwalder 	// Open the device, trying read only if readwrite fails
6229008bcfSTyler Dauwalder 	fDevice = open(deviceName, fReadOnly ? O_RDONLY : O_RDWR);
6329008bcfSTyler Dauwalder 	if (fDevice < B_OK && !fReadOnly) {
6429008bcfSTyler Dauwalder 		fReadOnly = true;
6529008bcfSTyler Dauwalder 		fDevice = open(deviceName, O_RDONLY);
6629008bcfSTyler Dauwalder 	}
6729008bcfSTyler Dauwalder 	if (fDevice < B_OK)
6829008bcfSTyler Dauwalder 		RETURN_ERROR(fDevice);
6929008bcfSTyler Dauwalder 
7029008bcfSTyler Dauwalder 	// If the device is actually a normal file, try to disable the cache
7129008bcfSTyler Dauwalder 	// for the file in the parent filesystem
7229008bcfSTyler Dauwalder 	struct stat stat;
734ac73018STyler Dauwalder 	status_t err = fstat(fDevice, &stat) < 0 ? B_ERROR : B_OK;
7429008bcfSTyler Dauwalder 	if (!err) {
7529008bcfSTyler Dauwalder 		if (stat.st_mode & S_IFREG && ioctl(fDevice, IOCTL_FILE_UNCACHED_IO, NULL) < 0) {
764ac73018STyler Dauwalder 			// Apparently it's a bad thing if you can't disable the file
774ac73018STyler Dauwalder 			// cache for a non-device disk image you're trying to mount...
784ac73018STyler Dauwalder 			DIE(("Unable to disable cache of underlying file system. "
794ac73018STyler Dauwalder 			     "I hear that's bad. :-(\n"));
8029008bcfSTyler Dauwalder 		}
814ac73018STyler Dauwalder 		// So far so good. The device is ready to be accessed now.
824ac73018STyler Dauwalder 		fInitStatus = B_DEVICE_INITIALIZED;
8329008bcfSTyler Dauwalder 	}
8429008bcfSTyler Dauwalder 
8529008bcfSTyler Dauwalder 	// Now identify the volume
864ac73018STyler Dauwalder 	if (!err)
874ac73018STyler Dauwalder 		err = _Identify();
8829008bcfSTyler Dauwalder 
89*3f4628f1STyler Dauwalder 	// Success, create a vnode for the root
90*3f4628f1STyler Dauwalder 	if (!err)
91*3f4628f1STyler Dauwalder 		err = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb());
92*3f4628f1STyler Dauwalder 
93*3f4628f1STyler Dauwalder 	RETURN(err);
944ac73018STyler Dauwalder }
954ac73018STyler Dauwalder 
96*3f4628f1STyler Dauwalder 
970d383564STyler Dauwalder off_t
980d383564STyler Dauwalder Volume::_MapAddress(udf_extent_address address)
990d383564STyler Dauwalder {
1000d383564STyler Dauwalder 	return address.location() * BlockSize();
1010d383564STyler Dauwalder }
1020d383564STyler Dauwalder 
103*3f4628f1STyler Dauwalder 
104*3f4628f1STyler Dauwalder /*! \brief Maps the given \c udf_long_address to an absolute block address.
105*3f4628f1STyler Dauwalder */
106*3f4628f1STyler Dauwalder status_t
107*3f4628f1STyler Dauwalder Volume::_MapBlock(udf_long_address address, off_t *mappedBlock)
1080d383564STyler Dauwalder {
109*3f4628f1STyler Dauwalder 	DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
110*3f4628f1STyler Dauwalder 		address.block(), address.partition(), mappedBlock));
111*3f4628f1STyler Dauwalder 	status_t err = mappedBlock ? B_OK : B_BAD_VALUE;
112*3f4628f1STyler Dauwalder 	if (!err)
113*3f4628f1STyler Dauwalder 		err = _InitStatus() >= B_LOGICAL_VOLUME_INITIALIZED ? B_OK : B_NO_INIT;
114*3f4628f1STyler Dauwalder 	if (!err) {
115*3f4628f1STyler Dauwalder 		udf_partition_descriptor* partition = fPartitionMap.Find(address.partition());
116*3f4628f1STyler Dauwalder 		err = partition ? B_OK : B_BAD_ADDRESS;
117*3f4628f1STyler Dauwalder 		if (!err) {
118*3f4628f1STyler Dauwalder 			*mappedBlock = Start() + partition->start() + address.block();
119*3f4628f1STyler Dauwalder 		}
120*3f4628f1STyler Dauwalder 		if (!err) {
121*3f4628f1STyler Dauwalder 			PRINT(("mapped to block %lld\n", *mappedBlock));
122*3f4628f1STyler Dauwalder 		}
123*3f4628f1STyler Dauwalder 	}
124*3f4628f1STyler Dauwalder 	RETURN_ERROR(err);
125*3f4628f1STyler Dauwalder }
126*3f4628f1STyler Dauwalder 
127*3f4628f1STyler Dauwalder /*! \brief Maps the given \c udf_long_address to an absolute byte address.
128*3f4628f1STyler Dauwalder */
129*3f4628f1STyler Dauwalder status_t
130*3f4628f1STyler Dauwalder Volume::_MapAddress(udf_long_address address, off_t *mappedAddress)
131*3f4628f1STyler Dauwalder {
132*3f4628f1STyler Dauwalder 	DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
133*3f4628f1STyler Dauwalder 		address.block(), address.partition(), mappedAddress));
134*3f4628f1STyler Dauwalder 	status_t err = _MapBlock(address, mappedAddress);
135*3f4628f1STyler Dauwalder 	if (!err)
136*3f4628f1STyler Dauwalder 		*mappedAddress = *mappedAddress * BlockSize();
137*3f4628f1STyler Dauwalder 	if (!err) {
138*3f4628f1STyler Dauwalder 		PRINT(("mapped to address %lld\n", *mappedAddress));
139*3f4628f1STyler Dauwalder 	}
140*3f4628f1STyler Dauwalder 	RETURN_ERROR(err);
1410d383564STyler Dauwalder }
1420d383564STyler Dauwalder 
1430d383564STyler Dauwalder off_t
1440d383564STyler Dauwalder Volume::_MapAddress(udf_short_address address)
1450d383564STyler Dauwalder {
1460d383564STyler Dauwalder 	return 0;
1470d383564STyler Dauwalder }
1480d383564STyler Dauwalder 
149*3f4628f1STyler Dauwalder /*status_t
1500d383564STyler Dauwalder Volume::_Read(udf_extent_address address, ssize_t length, void *data)
1510d383564STyler Dauwalder {
1520d383564STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
1530d383564STyler Dauwalder 	off_t mappedAddress = _MapAddress(address);
1540d383564STyler Dauwalder 	status_t err = data ? B_OK : B_BAD_VALUE;
1550d383564STyler Dauwalder 	if (!err) {
1560d383564STyler Dauwalder 		ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
1570d383564STyler Dauwalder 		if (bytesRead != (ssize_t)BlockSize()) {
1580d383564STyler Dauwalder 			err = B_IO_ERROR;
1590d383564STyler Dauwalder 			PRINT(("read_pos(pos:%lld, len:%ld) failed with: 0x%lx\n", mappedAddress,
1600d383564STyler Dauwalder 			       length, bytesRead));
1610d383564STyler Dauwalder 		}
1620d383564STyler Dauwalder 	}
163*3f4628f1STyler Dauwalder 	RETURN(err);
1640d383564STyler Dauwalder }
165*3f4628f1STyler Dauwalder */
1660d383564STyler Dauwalder 
167*3f4628f1STyler Dauwalder /*template <class AddressType>
168*3f4628f1STyler Dauwalder status_t
169*3f4628f1STyler Dauwalder Volume::_Read(AddressType address, ssize_t length, void *data)
170*3f4628f1STyler Dauwalder {
171*3f4628f1STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
172*3f4628f1STyler Dauwalder 	off_t mappedAddress;
173*3f4628f1STyler Dauwalder 	status_t err = data ? B_OK : B_BAD_VALUE;
174*3f4628f1STyler Dauwalder 	if (!err)
175*3f4628f1STyler Dauwalder 		err = _MapAddress(address, &mappedAddress);
176*3f4628f1STyler Dauwalder 	if (!err) {
177*3f4628f1STyler Dauwalder 		ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
178*3f4628f1STyler Dauwalder 		if (bytesRead != (ssize_t)BlockSize()) {
179*3f4628f1STyler Dauwalder 			err = B_IO_ERROR;
180*3f4628f1STyler Dauwalder 			PRINT(("read_pos(pos:%lld, len:%ld) failed with: 0x%lx\n", mappedAddress,
181*3f4628f1STyler Dauwalder 			       length, bytesRead));
182*3f4628f1STyler Dauwalder 		}
183*3f4628f1STyler Dauwalder 	}
184*3f4628f1STyler Dauwalder 	RETURN(err);
185*3f4628f1STyler Dauwalder }
186*3f4628f1STyler Dauwalder */
1874ac73018STyler Dauwalder /*!	\brief Walks through the volume recognition and descriptor sequences,
1884ac73018STyler Dauwalder 	gathering volume description info as it goes.
1894ac73018STyler Dauwalder 
1904ac73018STyler Dauwalder 	Note that the 512 avdp location is, technically speaking, only valid on
1914ac73018STyler Dauwalder 	unlosed CD-R media in the absense of an avdp at 256. For now I'm not
1924ac73018STyler Dauwalder 	bothering with such silly details, and instead am just checking for it
1934ac73018STyler Dauwalder 	last.
1944ac73018STyler Dauwalder */
1954ac73018STyler Dauwalder status_t
1964ac73018STyler Dauwalder Volume::_Identify()
1974ac73018STyler Dauwalder {
198565457fdSTyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
1994ac73018STyler Dauwalder 
2004ac73018STyler Dauwalder 	status_t err = _InitStatus() == B_DEVICE_INITIALIZED ? B_OK : B_BAD_VALUE;
2014ac73018STyler Dauwalder 
2024ac73018STyler Dauwalder 	// Check for a valid volume recognition sequence
2034ac73018STyler Dauwalder 	if (!err)
2044ac73018STyler Dauwalder 		err = _WalkVolumeRecognitionSequence();
2054ac73018STyler Dauwalder 
2064ac73018STyler Dauwalder 	// Now hunt down a volume descriptor sequence from one of
2074ac73018STyler Dauwalder 	// the anchor volume pointers (if there are any).
2080d383564STyler Dauwalder 	if (!err)
2090d383564STyler Dauwalder 		err = _WalkAnchorVolumeDescriptorSequences();
2104ac73018STyler Dauwalder 
2110d383564STyler Dauwalder 	// At this point we've found a valid set of volume descriptors. We
2120d383564STyler Dauwalder 	// now need to investigate the file set descriptor pointed to by
2130d383564STyler Dauwalder 	// the logical volume descriptor
214*3f4628f1STyler Dauwalder 	if (!err) {
215*3f4628f1STyler Dauwalder 		fInitStatus = B_LOGICAL_VOLUME_INITIALIZED;
2160d383564STyler Dauwalder 		err = _InitFileSetDescriptor();
217*3f4628f1STyler Dauwalder 	}
2184ac73018STyler Dauwalder 
2194ac73018STyler Dauwalder 	RETURN(err);
2204ac73018STyler Dauwalder }
2214ac73018STyler Dauwalder 
222565457fdSTyler Dauwalder /*! \brief Walks the iso9660/ecma-167 volume recognition sequence, returning
223565457fdSTyler Dauwalder 	\c B_OK if the presence of a UDF filesystem on this volume is likely.
224565457fdSTyler Dauwalder 
225565457fdSTyler Dauwalder 	\return \c B_OK: An ECMA-167 vsd was found, or at least one extended area
226565457fdSTyler Dauwalder 	                 vsd was found and no ECMA-168 vsds were found.
227565457fdSTyler Dauwalder 	\return "error code": Only iso9660 vsds were found, an ECMA-168 vsd was
228565457fdSTyler Dauwalder 	                      found (but no ECMA-167 vsd), or an error occurred.
229565457fdSTyler Dauwalder */
2304ac73018STyler Dauwalder status_t
2314ac73018STyler Dauwalder Volume::_WalkVolumeRecognitionSequence()
2324ac73018STyler Dauwalder {
233565457fdSTyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
2344ac73018STyler Dauwalder 	// vrs starts at block 16. Each volume structure descriptor (vsd)
2354ac73018STyler Dauwalder 	// should be one block long. We're expecting to find 0 or more iso9660
2364ac73018STyler Dauwalder 	// vsd's followed by some ECMA-167 vsd's.
2370d383564STyler Dauwalder 	MemoryChunk chunk(BlockSize());
2380d383564STyler Dauwalder 	status_t err = chunk.InitCheck();
2394ac73018STyler Dauwalder 	if (!err) {
2404ac73018STyler Dauwalder 		bool foundISO = false;
2414ac73018STyler Dauwalder 		bool foundExtended = false;
2424ac73018STyler Dauwalder 		bool foundECMA167 = false;
2434ac73018STyler Dauwalder 		bool foundECMA168 = false;
2444ac73018STyler Dauwalder 		bool foundBoot = false;
2454ac73018STyler Dauwalder 		for (uint32 block = 16; true; block++) {
2464ac73018STyler Dauwalder 	    	PRINT(("block %ld: ", block))
247565457fdSTyler Dauwalder 			off_t address = AddressForRelativeBlock(block);
2480d383564STyler Dauwalder 			ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
2494ac73018STyler Dauwalder 			if (bytesRead == (ssize_t)BlockSize())
2504ac73018STyler Dauwalder 		    {
2510d383564STyler Dauwalder 		    	udf_volume_structure_descriptor_header* descriptor =
2520d383564STyler Dauwalder 		    	  reinterpret_cast<udf_volume_structure_descriptor_header*>(chunk.Data());
2530d383564STyler Dauwalder 				if (descriptor->id_matches(kVSDID_ISO)) {
2544ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ISO9660 descriptor\n"));
2554ac73018STyler Dauwalder 					foundISO = true;
2560d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_BEA)) {
2574ac73018STyler Dauwalder 					SIMPLE_PRINT(("found BEA descriptor\n"));
2584ac73018STyler Dauwalder 					foundExtended = true;
2590d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_TEA)) {
2604ac73018STyler Dauwalder 					SIMPLE_PRINT(("found TEA descriptor\n"));
2614ac73018STyler Dauwalder 					foundExtended = true;
2620d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_ECMA167_2)) {
2634ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ECMA-167 rev 2 descriptor\n"));
2644ac73018STyler Dauwalder 					foundECMA167 = true;
2650d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_ECMA167_3)) {
2664ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ECMA-167 rev 3 descriptor\n"));
2674ac73018STyler Dauwalder 					foundECMA167 = true;
2680d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_BOOT)) {
2694ac73018STyler Dauwalder 					SIMPLE_PRINT(("found boot descriptor\n"));
2704ac73018STyler Dauwalder 					foundBoot = true;
2710d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_ECMA168)) {
2724ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ECMA-168 descriptor\n"));
2734ac73018STyler Dauwalder 					foundECMA168 = true;
2744ac73018STyler Dauwalder 				} else {
2750d383564STyler Dauwalder 					SIMPLE_PRINT(("found invalid descriptor, id = `%.5s'\n", descriptor->id));
2764ac73018STyler Dauwalder 					break;
2774ac73018STyler Dauwalder 				}
2784ac73018STyler Dauwalder 			} else {
2794ac73018STyler Dauwalder 				SIMPLE_PRINT(("read_pos(pos:%lld, len:%ld) failed with: 0x%lx\n", address,
2804ac73018STyler Dauwalder 				        BlockSize(), bytesRead));
2814ac73018STyler Dauwalder 				break;
2824ac73018STyler Dauwalder 			}
2834ac73018STyler Dauwalder 		}
2844ac73018STyler Dauwalder 
2854ac73018STyler Dauwalder 		// If we find an ECMA-167 descriptor, OR if we find a beginning
2864ac73018STyler Dauwalder 		// or terminating extended area descriptor with NO ECMA-168
2874ac73018STyler Dauwalder 		// descriptors, we return B_OK to signal that we should go
2884ac73018STyler Dauwalder 		// looking for valid anchors.
2894ac73018STyler Dauwalder 		err = foundECMA167 || (foundExtended && !foundECMA168) ? B_OK : B_ERROR;
2904ac73018STyler Dauwalder 	}
2914ac73018STyler Dauwalder 
2924ac73018STyler Dauwalder 	RETURN(err);
2934ac73018STyler Dauwalder }
2944ac73018STyler Dauwalder 
2954ac73018STyler Dauwalder status_t
2960d383564STyler Dauwalder Volume::_WalkAnchorVolumeDescriptorSequences()
2970d383564STyler Dauwalder {
2980d383564STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
2990d383564STyler Dauwalder 		const uint8 avds_location_count = 4;
3000d383564STyler Dauwalder 		const off_t avds_locations[avds_location_count] = { 256,
3010d383564STyler Dauwalder 		                                                    Length()-256,
3020d383564STyler Dauwalder 		                                                    Length(),
3030d383564STyler Dauwalder 		                                                    512,
3040d383564STyler Dauwalder 		                                                  };
3050d383564STyler Dauwalder 		bool found_vds = false;
3060d383564STyler Dauwalder 
3070d383564STyler Dauwalder 		for (int32 i = 0; i < avds_location_count; i++) {
3080d383564STyler Dauwalder 			off_t block = avds_locations[i];
3090d383564STyler Dauwalder 			off_t address = AddressForRelativeBlock(block);
3100d383564STyler Dauwalder 			MemoryChunk chunk(BlockSize());
3110d383564STyler Dauwalder 			udf_anchor_descriptor *anchor = NULL;
3120d383564STyler Dauwalder 
3130d383564STyler Dauwalder 			status_t anchorErr = chunk.InitCheck();
3140d383564STyler Dauwalder 			if (!anchorErr) {
3150d383564STyler Dauwalder 				ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
3160d383564STyler Dauwalder 				anchorErr = bytesRead == (ssize_t)BlockSize() ? B_OK : B_IO_ERROR;
3170d383564STyler Dauwalder 				if (anchorErr) {
3180d383564STyler Dauwalder 					PRINT(("block %lld: read_pos(pos:%lld, len:%ld) failed with error 0x%lx\n",
3190d383564STyler Dauwalder 					       block, address, BlockSize(), bytesRead));
3200d383564STyler Dauwalder 				}
3210d383564STyler Dauwalder 			}
3220d383564STyler Dauwalder 			if (!anchorErr) {
3230d383564STyler Dauwalder 				anchor = reinterpret_cast<udf_anchor_descriptor*>(chunk.Data());
3240d383564STyler Dauwalder 				anchorErr = anchor->tag().init_check(block);
3250d383564STyler Dauwalder 				if (anchorErr) {
3260d383564STyler Dauwalder 					PRINT(("block %lld: invalid anchor\n", block));
3270d383564STyler Dauwalder 				} else {
3280d383564STyler Dauwalder 					PRINT(("block %lld: valid anchor\n", block));
3290d383564STyler Dauwalder 				}
3300d383564STyler Dauwalder 			}
3310d383564STyler Dauwalder 			if (!anchorErr) {
3320d383564STyler Dauwalder 				PRINT(("block %lld: anchor:\n", block));
3330d383564STyler Dauwalder 				PDUMP(anchor);
3340d383564STyler Dauwalder 				// Found an avds, so try the main sequence first, then
3350d383564STyler Dauwalder 				// the reserve sequence if the main one fails.
3360d383564STyler Dauwalder 				anchorErr = _WalkVolumeDescriptorSequence(anchor->main_vds());
3370d383564STyler Dauwalder 				if (anchorErr)
3380d383564STyler Dauwalder 					anchorErr = _WalkVolumeDescriptorSequence(anchor->reserve_vds());
3390d383564STyler Dauwalder 
3400d383564STyler Dauwalder 
3410d383564STyler Dauwalder 			}
3420d383564STyler Dauwalder 			if (!anchorErr) {
3430d383564STyler Dauwalder 				PRINT(("block %lld: found valid vds\n", avds_locations[i]));
3440d383564STyler Dauwalder 				found_vds = true;
3450d383564STyler Dauwalder 				break;
3460d383564STyler Dauwalder 			} //else {
3470d383564STyler Dauwalder 				// Both failed, so loop around and try another avds
3480d383564STyler Dauwalder //				PRINT(("block %lld: vds search failed\n", avds_locations[i]));
3490d383564STyler Dauwalder //			}
3500d383564STyler Dauwalder 		}
3510d383564STyler Dauwalder 		status_t err = found_vds ? B_OK : B_ERROR;
3520d383564STyler Dauwalder 		RETURN(err);
3530d383564STyler Dauwalder }
3540d383564STyler Dauwalder 
3550d383564STyler Dauwalder status_t
3560d383564STyler Dauwalder Volume::_WalkVolumeDescriptorSequence(udf_extent_address extent)
3574ac73018STyler Dauwalder {
358565457fdSTyler Dauwalder 	DEBUG_INIT_ETC(CF_PRIVATE | CF_VOLUME_OPS, "Volume", ("loc:%ld, len:%ld",
359565457fdSTyler Dauwalder 	           extent.location(), extent.length()));
360565457fdSTyler Dauwalder 	uint32 count = extent.length()/BlockSize();
3610d383564STyler Dauwalder 
3620d383564STyler Dauwalder 	bool foundLogicalVD = false;
3630d383564STyler Dauwalder 
364565457fdSTyler Dauwalder 	for (uint32 i = 0; i < count; i++)
365565457fdSTyler Dauwalder 	{
366565457fdSTyler Dauwalder 		off_t block = extent.location()+i;
367565457fdSTyler Dauwalder 		off_t address = AddressForRelativeBlock(block);
3680d383564STyler Dauwalder 		MemoryChunk chunk(BlockSize());
3690d383564STyler Dauwalder 		udf_tag *tag = NULL;
3700d383564STyler Dauwalder 
3710d383564STyler Dauwalder 		PRINT(("descriptor #%ld (block %lld):\n", i, block));
3720d383564STyler Dauwalder 
3730d383564STyler Dauwalder 		status_t err = chunk.InitCheck();
374565457fdSTyler Dauwalder 		if (!err) {
3750d383564STyler Dauwalder 			ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
376565457fdSTyler Dauwalder 			err = bytesRead == (ssize_t)BlockSize() ? B_OK : B_IO_ERROR;
377565457fdSTyler Dauwalder 			if (err) {
378565457fdSTyler Dauwalder 				PRINT(("block %lld: read_pos(pos:%lld, len:%ld) failed with error 0x%lx\n",
379565457fdSTyler Dauwalder 				       block, address, BlockSize(), bytesRead));
380565457fdSTyler Dauwalder 			}
381565457fdSTyler Dauwalder 		}
382565457fdSTyler Dauwalder 		if (!err) {
3830d383564STyler Dauwalder 			tag = reinterpret_cast<udf_tag*>(chunk.Data());
3840d383564STyler Dauwalder 			err = tag->init_check(block);
3850d383564STyler Dauwalder 		}
3860d383564STyler Dauwalder 		if (!err) {
3870d383564STyler Dauwalder 			// Now decide what type of descriptor we have
3880d383564STyler Dauwalder 			switch (tag->id()) {
3890d383564STyler Dauwalder 				case TAGID_UNDEFINED:
3900d383564STyler Dauwalder 					break;
3910d383564STyler Dauwalder 
3920d383564STyler Dauwalder 				case TAGID_PRIMARY_VOLUME_DESCRIPTOR:
3930d383564STyler Dauwalder 				{
3940d383564STyler Dauwalder 					udf_primary_descriptor *primary = reinterpret_cast<udf_primary_descriptor*>(tag);
3950d383564STyler Dauwalder 					PDUMP(primary);
3960d383564STyler Dauwalder 					break;
3970d383564STyler Dauwalder 				}
3980d383564STyler Dauwalder 
3990d383564STyler Dauwalder 				case TAGID_ANCHOR_VOLUME_DESCRIPTOR_POINTER:
4000d383564STyler Dauwalder 					break;
4010d383564STyler Dauwalder 
4020d383564STyler Dauwalder 				case TAGID_VOLUME_DESCRIPTOR_POINTER:
4030d383564STyler Dauwalder 					break;
4040d383564STyler Dauwalder 
4050d383564STyler Dauwalder 				case TAGID_IMPLEMENTATION_USE_VOLUME_DESCRIPTOR:
4060d383564STyler Dauwalder 				{
4070d383564STyler Dauwalder 					udf_implementation_use_descriptor *imp_use = reinterpret_cast<udf_implementation_use_descriptor*>(tag);
4080d383564STyler Dauwalder 					PDUMP(imp_use);
4090d383564STyler Dauwalder 					break;
4100d383564STyler Dauwalder 				}
4110d383564STyler Dauwalder 
4120d383564STyler Dauwalder 				case TAGID_PARTITION_DESCRIPTOR:
4130d383564STyler Dauwalder 				{
4140d383564STyler Dauwalder 					udf_partition_descriptor *partition = reinterpret_cast<udf_partition_descriptor*>(tag);
4150d383564STyler Dauwalder 					PDUMP(partition);
4160d383564STyler Dauwalder 					if (partition->tag().init_check(block) == B_OK) {
4170d383564STyler Dauwalder 						udf_partition_descriptor *current = fPartitionMap.Find(partition->partition_number());
4180d383564STyler Dauwalder 						if (!current || current->vds_number() < partition->vds_number()) {
4190d383564STyler Dauwalder 							PRINT(("adding partition #%d with vds_number %ld to partition map\n",
4200d383564STyler Dauwalder 							       partition->partition_number(), partition->vds_number()));
4210d383564STyler Dauwalder 							fPartitionMap.Add(partition);
4220d383564STyler Dauwalder 						}
4230d383564STyler Dauwalder 					}
4240d383564STyler Dauwalder 					break;
4250d383564STyler Dauwalder 				}
4260d383564STyler Dauwalder 
4270d383564STyler Dauwalder 				case TAGID_LOGICAL_VOLUME_DESCRIPTOR:
4280d383564STyler Dauwalder 				{
4290d383564STyler Dauwalder 					udf_logical_descriptor *logical = reinterpret_cast<udf_logical_descriptor*>(tag);
4300d383564STyler Dauwalder 					PDUMP(logical);
4310d383564STyler Dauwalder 					if (foundLogicalVD) {
4320d383564STyler Dauwalder 						// Keep the vd with the highest vds_number
4330d383564STyler Dauwalder 						if (logical->vds_number() > fLogicalVD.vds_number())
4340d383564STyler Dauwalder 							fLogicalVD = *(logical);
435565457fdSTyler Dauwalder 					} else {
4360d383564STyler Dauwalder 						fLogicalVD = *(logical);
4370d383564STyler Dauwalder 						foundLogicalVD = true;
4380d383564STyler Dauwalder 					}
4390d383564STyler Dauwalder 					break;
4400d383564STyler Dauwalder 				}
4410d383564STyler Dauwalder 
4420d383564STyler Dauwalder 				case TAGID_UNALLOCATED_SPACE_DESCRIPTOR:
4430d383564STyler Dauwalder 				{
4440d383564STyler Dauwalder 					udf_unallocated_space_descriptor *unallocated = reinterpret_cast<udf_unallocated_space_descriptor*>(tag);
4450d383564STyler Dauwalder 					PDUMP(unallocated);
4460d383564STyler Dauwalder 					break;
4470d383564STyler Dauwalder 				}
4480d383564STyler Dauwalder 
4490d383564STyler Dauwalder 				case TAGID_TERMINATING_DESCRIPTOR:
4500d383564STyler Dauwalder 				{
4510d383564STyler Dauwalder 					udf_terminating_descriptor *terminating = reinterpret_cast<udf_terminating_descriptor*>(tag);
4520d383564STyler Dauwalder 					PDUMP(terminating);
4530d383564STyler Dauwalder 					break;
4540d383564STyler Dauwalder 				}
4550d383564STyler Dauwalder 
4560d383564STyler Dauwalder 				case TAGID_LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR:
4570d383564STyler Dauwalder 					// Not found in this descriptor sequence
4580d383564STyler Dauwalder 					break;
4590d383564STyler Dauwalder 
4600d383564STyler Dauwalder 				default:
4610d383564STyler Dauwalder 					break;
4620d383564STyler Dauwalder 
463565457fdSTyler Dauwalder 			}
464565457fdSTyler Dauwalder 		}
465565457fdSTyler Dauwalder 	}
4664ac73018STyler Dauwalder 
4670d383564STyler Dauwalder 	status_t err = foundLogicalVD ? B_OK : B_ERROR;
4680d383564STyler Dauwalder 	if (!err) {
4690d383564STyler Dauwalder 		PRINT(("partition map:\n"));
4700d383564STyler Dauwalder 		DUMP(fPartitionMap);
4710d383564STyler Dauwalder 	}
4720d383564STyler Dauwalder 	RETURN(err);
47329008bcfSTyler Dauwalder }
47429008bcfSTyler Dauwalder 
4750d383564STyler Dauwalder status_t
4760d383564STyler Dauwalder Volume::_InitFileSetDescriptor()
4770d383564STyler Dauwalder {
4780d383564STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
4790d383564STyler Dauwalder 	MemoryChunk chunk(fLogicalVD.file_set_address().length());
4800d383564STyler Dauwalder 
4810d383564STyler Dauwalder 	status_t err = chunk.InitCheck();
4820d383564STyler Dauwalder 	if (!err) {
483*3f4628f1STyler Dauwalder //		err = Read(ad, fLogicalVD.file_set_address().length(), chunk.Data());
484*3f4628f1STyler Dauwalder 		err = Read(fLogicalVD.file_set_address(), fLogicalVD.file_set_address().length(), chunk.Data());
485*3f4628f1STyler Dauwalder 		if (!err) {
486*3f4628f1STyler Dauwalder 			udf_file_set_descriptor *fileSet = reinterpret_cast<udf_file_set_descriptor*>(chunk.Data());
4870d383564STyler Dauwalder 			fileSet->tag().init_check(0);
4880d383564STyler Dauwalder 			PDUMP(fileSet);
489*3f4628f1STyler Dauwalder 			fRootIcb = new Icb(this, fileSet->root_directory_icb());
490*3f4628f1STyler Dauwalder 			err = fRootIcb ? fRootIcb->InitCheck() : B_NO_MEMORY;
4910d383564STyler Dauwalder 		}
4920d383564STyler Dauwalder 	}
493*3f4628f1STyler Dauwalder 
494*3f4628f1STyler Dauwalder 	RETURN(err);
495*3f4628f1STyler Dauwalder }
496*3f4628f1STyler Dauwalder 
497