xref: /haiku/src/add-ons/kernel/file_systems/udf/Volume.cpp (revision a71fd51283d32ca7072b5c66a88a1c6a8122d119)
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 
113f4628f1STyler Dauwalder #include "Icb.h"
120d383564STyler Dauwalder #include "MemoryChunk.h"
1329008bcfSTyler Dauwalder 
143f4628f1STyler 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)
233f4628f1STyler Dauwalder 	: fId(id)
2429008bcfSTyler Dauwalder 	, fDevice(0)
2529008bcfSTyler Dauwalder 	, fReadOnly(false)
263f4628f1STyler Dauwalder 	, fStart(0)
274ac73018STyler Dauwalder 	, fBlockSize(0)
28*a71fd512STyler Dauwalder 	, fBlockShift(0)
294ac73018STyler Dauwalder 	, fInitStatus(B_UNINITIALIZED)
303f4628f1STyler Dauwalder 	, fRootIcb(NULL)
3129008bcfSTyler Dauwalder {
3229008bcfSTyler Dauwalder }
3329008bcfSTyler Dauwalder 
3429008bcfSTyler Dauwalder status_t
3529008bcfSTyler Dauwalder Volume::Identify(int device, off_t base)
3629008bcfSTyler Dauwalder {
3729008bcfSTyler Dauwalder 	return B_ERROR;
3829008bcfSTyler Dauwalder }
3929008bcfSTyler Dauwalder 
4029008bcfSTyler Dauwalder /*! \brief Attempts to mount the given device.
413f4628f1STyler Dauwalder 
423f4628f1STyler Dauwalder 	\param volumeStart The block on the given device whereat the volume begins.
433f4628f1STyler Dauwalder 	\param volumeLength The block length of the volume on the given device.
4429008bcfSTyler Dauwalder */
4529008bcfSTyler Dauwalder status_t
464ac73018STyler Dauwalder Volume::Mount(const char *deviceName, off_t volumeStart, off_t volumeLength,
474ac73018STyler Dauwalder               uint32 flags, uint32 blockSize)
4829008bcfSTyler Dauwalder {
49565457fdSTyler Dauwalder 	DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "Volume",
50565457fdSTyler Dauwalder 		("devName = `%s'", deviceName));
5129008bcfSTyler Dauwalder 	if (!deviceName)
5229008bcfSTyler Dauwalder 		RETURN_ERROR(B_BAD_VALUE);
534ac73018STyler Dauwalder 	if (_InitStatus() == B_INITIALIZED)
544ac73018STyler Dauwalder 		RETURN_ERROR(B_BUSY);
554ac73018STyler Dauwalder 			// Already mounted, thank you for asking
5629008bcfSTyler Dauwalder 
57*a71fd512STyler Dauwalder 	// Check the block size
58*a71fd512STyler Dauwalder 	uint32 bitCount = 0;
59*a71fd512STyler Dauwalder 	for (int i = 0; i < 32; i++) {
60*a71fd512STyler Dauwalder 		// Zero out all bits except bit i
61*a71fd512STyler Dauwalder 		uint32 block = blockSize & (uint32(1) << i);
62*a71fd512STyler Dauwalder 		if (block) {
63*a71fd512STyler Dauwalder 			if (++bitCount > 1) {
64*a71fd512STyler Dauwalder 				PRINT(("Block size must be a power of two! (blockSize = %ld)\n", blockSize));
65*a71fd512STyler Dauwalder 				RETURN(B_BAD_VALUE);
66*a71fd512STyler Dauwalder 			} else {
67*a71fd512STyler Dauwalder 				fBlockShift = i;
68*a71fd512STyler Dauwalder 				PRINT(("BlockShift() = %ld\n", BlockShift()));
69*a71fd512STyler Dauwalder 			}
70*a71fd512STyler Dauwalder 		}
71*a71fd512STyler Dauwalder 	}
72*a71fd512STyler Dauwalder 
7329008bcfSTyler Dauwalder 	fReadOnly = flags & B_READ_ONLY;
743f4628f1STyler Dauwalder 	fStart = volumeStart;
754ac73018STyler Dauwalder 	fLength = volumeLength;
764ac73018STyler Dauwalder 	fBlockSize = blockSize;
7729008bcfSTyler Dauwalder 
7829008bcfSTyler Dauwalder 	// Open the device, trying read only if readwrite fails
7929008bcfSTyler Dauwalder 	fDevice = open(deviceName, fReadOnly ? O_RDONLY : O_RDWR);
8029008bcfSTyler Dauwalder 	if (fDevice < B_OK && !fReadOnly) {
8129008bcfSTyler Dauwalder 		fReadOnly = true;
8229008bcfSTyler Dauwalder 		fDevice = open(deviceName, O_RDONLY);
8329008bcfSTyler Dauwalder 	}
8429008bcfSTyler Dauwalder 	if (fDevice < B_OK)
8529008bcfSTyler Dauwalder 		RETURN_ERROR(fDevice);
8629008bcfSTyler Dauwalder 
8729008bcfSTyler Dauwalder 	// If the device is actually a normal file, try to disable the cache
8829008bcfSTyler Dauwalder 	// for the file in the parent filesystem
8929008bcfSTyler Dauwalder 	struct stat stat;
904ac73018STyler Dauwalder 	status_t err = fstat(fDevice, &stat) < 0 ? B_ERROR : B_OK;
9129008bcfSTyler Dauwalder 	if (!err) {
9229008bcfSTyler Dauwalder 		if (stat.st_mode & S_IFREG && ioctl(fDevice, IOCTL_FILE_UNCACHED_IO, NULL) < 0) {
934ac73018STyler Dauwalder 			// Apparently it's a bad thing if you can't disable the file
944ac73018STyler Dauwalder 			// cache for a non-device disk image you're trying to mount...
954ac73018STyler Dauwalder 			DIE(("Unable to disable cache of underlying file system. "
964ac73018STyler Dauwalder 			     "I hear that's bad. :-(\n"));
9729008bcfSTyler Dauwalder 		}
984ac73018STyler Dauwalder 		// So far so good. The device is ready to be accessed now.
994ac73018STyler Dauwalder 		fInitStatus = B_DEVICE_INITIALIZED;
10029008bcfSTyler Dauwalder 	}
10129008bcfSTyler Dauwalder 
102*a71fd512STyler Dauwalder 	err = init_cache_for_device(Device(), Length());
103*a71fd512STyler Dauwalder 	if (!err) {
10429008bcfSTyler Dauwalder 		// Now identify the volume
1054ac73018STyler Dauwalder 		err = _Identify();
106*a71fd512STyler Dauwalder 		if (!err) {
1073f4628f1STyler Dauwalder 			// Success, create a vnode for the root
1083f4628f1STyler Dauwalder 			err = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb());
109*a71fd512STyler Dauwalder 			if (err) {
110*a71fd512STyler Dauwalder 				PRINT(("Error create vnode for root icb! error = 0x%lx, `%s'\n",
111*a71fd512STyler Dauwalder 				       err, strerror(err)));
112*a71fd512STyler Dauwalder 			}
113*a71fd512STyler Dauwalder 		} else {
114*a71fd512STyler Dauwalder 			PRINT(("Error identifying a valid Udf volume! error = 0x%lx, `%s'\n",
115*a71fd512STyler Dauwalder 				   err, strerror(err)));
116*a71fd512STyler Dauwalder 		}
117*a71fd512STyler Dauwalder 	} else {
118*a71fd512STyler Dauwalder 		PRINT(("Error initializing buffer cache! error = 0x%lx, `%s'\n",
119*a71fd512STyler Dauwalder 		       err, strerror(err)));
120*a71fd512STyler Dauwalder 	}
121*a71fd512STyler Dauwalder 
1223f4628f1STyler Dauwalder 
1233f4628f1STyler Dauwalder 	RETURN(err);
1244ac73018STyler Dauwalder }
1254ac73018STyler Dauwalder 
126*a71fd512STyler Dauwalder const char*
127*a71fd512STyler Dauwalder Volume::Name() const {
128*a71fd512STyler Dauwalder 	return fName.String();
129*a71fd512STyler Dauwalder }
1303f4628f1STyler Dauwalder 
1310d383564STyler Dauwalder off_t
132*a71fd512STyler Dauwalder Volume::MapAddress(udf_extent_address address)
1330d383564STyler Dauwalder {
1340d383564STyler Dauwalder 	return address.location() * BlockSize();
1350d383564STyler Dauwalder }
1360d383564STyler Dauwalder 
1373f4628f1STyler Dauwalder 
1383f4628f1STyler Dauwalder /*! \brief Maps the given \c udf_long_address to an absolute block address.
1393f4628f1STyler Dauwalder */
1403f4628f1STyler Dauwalder status_t
141*a71fd512STyler Dauwalder Volume::MapBlock(udf_long_address address, off_t *mappedBlock)
1420d383564STyler Dauwalder {
1433f4628f1STyler Dauwalder 	DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
1443f4628f1STyler Dauwalder 		address.block(), address.partition(), mappedBlock));
1453f4628f1STyler Dauwalder 	status_t err = mappedBlock ? B_OK : B_BAD_VALUE;
1463f4628f1STyler Dauwalder 	if (!err)
1473f4628f1STyler Dauwalder 		err = _InitStatus() >= B_LOGICAL_VOLUME_INITIALIZED ? B_OK : B_NO_INIT;
1483f4628f1STyler Dauwalder 	if (!err) {
1493f4628f1STyler Dauwalder 		udf_partition_descriptor* partition = fPartitionMap.Find(address.partition());
1503f4628f1STyler Dauwalder 		err = partition ? B_OK : B_BAD_ADDRESS;
1513f4628f1STyler Dauwalder 		if (!err) {
1523f4628f1STyler Dauwalder 			*mappedBlock = Start() + partition->start() + address.block();
1533f4628f1STyler Dauwalder 		}
1543f4628f1STyler Dauwalder 		if (!err) {
1553f4628f1STyler Dauwalder 			PRINT(("mapped to block %lld\n", *mappedBlock));
1563f4628f1STyler Dauwalder 		}
1573f4628f1STyler Dauwalder 	}
158*a71fd512STyler Dauwalder 	RETURN(err);
1593f4628f1STyler Dauwalder }
1603f4628f1STyler Dauwalder 
1613f4628f1STyler Dauwalder /*! \brief Maps the given \c udf_long_address to an absolute byte address.
1623f4628f1STyler Dauwalder */
1633f4628f1STyler Dauwalder status_t
164*a71fd512STyler Dauwalder Volume::MapAddress(udf_long_address address, off_t *mappedAddress)
1653f4628f1STyler Dauwalder {
1663f4628f1STyler Dauwalder 	DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
1673f4628f1STyler Dauwalder 		address.block(), address.partition(), mappedAddress));
168*a71fd512STyler Dauwalder 	status_t err = MapBlock(address, mappedAddress);
1693f4628f1STyler Dauwalder 	if (!err)
1703f4628f1STyler Dauwalder 		*mappedAddress = *mappedAddress * BlockSize();
1713f4628f1STyler Dauwalder 	if (!err) {
1723f4628f1STyler Dauwalder 		PRINT(("mapped to address %lld\n", *mappedAddress));
1733f4628f1STyler Dauwalder 	}
1743f4628f1STyler Dauwalder 	RETURN_ERROR(err);
1750d383564STyler Dauwalder }
1760d383564STyler Dauwalder 
1770d383564STyler Dauwalder off_t
178*a71fd512STyler Dauwalder Volume::MapAddress(udf_short_address address)
1790d383564STyler Dauwalder {
1800d383564STyler Dauwalder 	return 0;
1810d383564STyler Dauwalder }
1820d383564STyler Dauwalder 
1833f4628f1STyler Dauwalder /*status_t
1840d383564STyler Dauwalder Volume::_Read(udf_extent_address address, ssize_t length, void *data)
1850d383564STyler Dauwalder {
1860d383564STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
187*a71fd512STyler Dauwalder 	off_t mappedAddress = MapAddress(address);
1880d383564STyler Dauwalder 	status_t err = data ? B_OK : B_BAD_VALUE;
1890d383564STyler Dauwalder 	if (!err) {
1900d383564STyler Dauwalder 		ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
1910d383564STyler Dauwalder 		if (bytesRead != (ssize_t)BlockSize()) {
1920d383564STyler Dauwalder 			err = B_IO_ERROR;
1930d383564STyler Dauwalder 			PRINT(("read_pos(pos:%lld, len:%ld) failed with: 0x%lx\n", mappedAddress,
1940d383564STyler Dauwalder 			       length, bytesRead));
1950d383564STyler Dauwalder 		}
1960d383564STyler Dauwalder 	}
1973f4628f1STyler Dauwalder 	RETURN(err);
1980d383564STyler Dauwalder }
1993f4628f1STyler Dauwalder */
2000d383564STyler Dauwalder 
2013f4628f1STyler Dauwalder /*template <class AddressType>
2023f4628f1STyler Dauwalder status_t
2033f4628f1STyler Dauwalder Volume::_Read(AddressType address, ssize_t length, void *data)
2043f4628f1STyler Dauwalder {
2053f4628f1STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
2063f4628f1STyler Dauwalder 	off_t mappedAddress;
2073f4628f1STyler Dauwalder 	status_t err = data ? B_OK : B_BAD_VALUE;
2083f4628f1STyler Dauwalder 	if (!err)
209*a71fd512STyler Dauwalder 		err = MapAddress(address, &mappedAddress);
2103f4628f1STyler Dauwalder 	if (!err) {
2113f4628f1STyler Dauwalder 		ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
2123f4628f1STyler Dauwalder 		if (bytesRead != (ssize_t)BlockSize()) {
2133f4628f1STyler Dauwalder 			err = B_IO_ERROR;
2143f4628f1STyler Dauwalder 			PRINT(("read_pos(pos:%lld, len:%ld) failed with: 0x%lx\n", mappedAddress,
2153f4628f1STyler Dauwalder 			       length, bytesRead));
2163f4628f1STyler Dauwalder 		}
2173f4628f1STyler Dauwalder 	}
2183f4628f1STyler Dauwalder 	RETURN(err);
2193f4628f1STyler Dauwalder }
2203f4628f1STyler Dauwalder */
2214ac73018STyler Dauwalder /*!	\brief Walks through the volume recognition and descriptor sequences,
2224ac73018STyler Dauwalder 	gathering volume description info as it goes.
2234ac73018STyler Dauwalder 
2244ac73018STyler Dauwalder 	Note that the 512 avdp location is, technically speaking, only valid on
2254ac73018STyler Dauwalder 	unlosed CD-R media in the absense of an avdp at 256. For now I'm not
2264ac73018STyler Dauwalder 	bothering with such silly details, and instead am just checking for it
2274ac73018STyler Dauwalder 	last.
2284ac73018STyler Dauwalder */
2294ac73018STyler Dauwalder status_t
2304ac73018STyler Dauwalder Volume::_Identify()
2314ac73018STyler Dauwalder {
232565457fdSTyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
2334ac73018STyler Dauwalder 
2344ac73018STyler Dauwalder 	status_t err = _InitStatus() == B_DEVICE_INITIALIZED ? B_OK : B_BAD_VALUE;
2354ac73018STyler Dauwalder 
2364ac73018STyler Dauwalder 	// Check for a valid volume recognition sequence
2374ac73018STyler Dauwalder 	if (!err)
2384ac73018STyler Dauwalder 		err = _WalkVolumeRecognitionSequence();
2394ac73018STyler Dauwalder 
2404ac73018STyler Dauwalder 	// Now hunt down a volume descriptor sequence from one of
2414ac73018STyler Dauwalder 	// the anchor volume pointers (if there are any).
2420d383564STyler Dauwalder 	if (!err)
2430d383564STyler Dauwalder 		err = _WalkAnchorVolumeDescriptorSequences();
2444ac73018STyler Dauwalder 
2450d383564STyler Dauwalder 	// At this point we've found a valid set of volume descriptors. We
2460d383564STyler Dauwalder 	// now need to investigate the file set descriptor pointed to by
2470d383564STyler Dauwalder 	// the logical volume descriptor
2483f4628f1STyler Dauwalder 	if (!err) {
2493f4628f1STyler Dauwalder 		fInitStatus = B_LOGICAL_VOLUME_INITIALIZED;
250*a71fd512STyler Dauwalder 		fName.SetTo(fLogicalVD.logical_volume_identifier());
2510d383564STyler Dauwalder 		err = _InitFileSetDescriptor();
2523f4628f1STyler Dauwalder 	}
2534ac73018STyler Dauwalder 
2544ac73018STyler Dauwalder 	RETURN(err);
2554ac73018STyler Dauwalder }
2564ac73018STyler Dauwalder 
257565457fdSTyler Dauwalder /*! \brief Walks the iso9660/ecma-167 volume recognition sequence, returning
258565457fdSTyler Dauwalder 	\c B_OK if the presence of a UDF filesystem on this volume is likely.
259565457fdSTyler Dauwalder 
260565457fdSTyler Dauwalder 	\return \c B_OK: An ECMA-167 vsd was found, or at least one extended area
261565457fdSTyler Dauwalder 	                 vsd was found and no ECMA-168 vsds were found.
262565457fdSTyler Dauwalder 	\return "error code": Only iso9660 vsds were found, an ECMA-168 vsd was
263565457fdSTyler Dauwalder 	                      found (but no ECMA-167 vsd), or an error occurred.
264565457fdSTyler Dauwalder */
2654ac73018STyler Dauwalder status_t
2664ac73018STyler Dauwalder Volume::_WalkVolumeRecognitionSequence()
2674ac73018STyler Dauwalder {
268565457fdSTyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
2694ac73018STyler Dauwalder 	// vrs starts at block 16. Each volume structure descriptor (vsd)
2704ac73018STyler Dauwalder 	// should be one block long. We're expecting to find 0 or more iso9660
2714ac73018STyler Dauwalder 	// vsd's followed by some ECMA-167 vsd's.
2720d383564STyler Dauwalder 	MemoryChunk chunk(BlockSize());
2730d383564STyler Dauwalder 	status_t err = chunk.InitCheck();
2744ac73018STyler Dauwalder 	if (!err) {
2754ac73018STyler Dauwalder 		bool foundISO = false;
2764ac73018STyler Dauwalder 		bool foundExtended = false;
2774ac73018STyler Dauwalder 		bool foundECMA167 = false;
2784ac73018STyler Dauwalder 		bool foundECMA168 = false;
2794ac73018STyler Dauwalder 		bool foundBoot = false;
2804ac73018STyler Dauwalder 		for (uint32 block = 16; true; block++) {
2814ac73018STyler Dauwalder 	    	PRINT(("block %ld: ", block))
282565457fdSTyler Dauwalder 			off_t address = AddressForRelativeBlock(block);
2830d383564STyler Dauwalder 			ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
2844ac73018STyler Dauwalder 			if (bytesRead == (ssize_t)BlockSize())
2854ac73018STyler Dauwalder 		    {
2860d383564STyler Dauwalder 		    	udf_volume_structure_descriptor_header* descriptor =
2870d383564STyler Dauwalder 		    	  reinterpret_cast<udf_volume_structure_descriptor_header*>(chunk.Data());
2880d383564STyler Dauwalder 				if (descriptor->id_matches(kVSDID_ISO)) {
2894ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ISO9660 descriptor\n"));
2904ac73018STyler Dauwalder 					foundISO = true;
2910d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_BEA)) {
2924ac73018STyler Dauwalder 					SIMPLE_PRINT(("found BEA descriptor\n"));
2934ac73018STyler Dauwalder 					foundExtended = true;
2940d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_TEA)) {
2954ac73018STyler Dauwalder 					SIMPLE_PRINT(("found TEA descriptor\n"));
2964ac73018STyler Dauwalder 					foundExtended = true;
2970d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_ECMA167_2)) {
2984ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ECMA-167 rev 2 descriptor\n"));
2994ac73018STyler Dauwalder 					foundECMA167 = true;
3000d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_ECMA167_3)) {
3014ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ECMA-167 rev 3 descriptor\n"));
3024ac73018STyler Dauwalder 					foundECMA167 = true;
3030d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_BOOT)) {
3044ac73018STyler Dauwalder 					SIMPLE_PRINT(("found boot descriptor\n"));
3054ac73018STyler Dauwalder 					foundBoot = true;
3060d383564STyler Dauwalder 				} else if (descriptor->id_matches(kVSDID_ECMA168)) {
3074ac73018STyler Dauwalder 					SIMPLE_PRINT(("found ECMA-168 descriptor\n"));
3084ac73018STyler Dauwalder 					foundECMA168 = true;
3094ac73018STyler Dauwalder 				} else {
3100d383564STyler Dauwalder 					SIMPLE_PRINT(("found invalid descriptor, id = `%.5s'\n", descriptor->id));
3114ac73018STyler Dauwalder 					break;
3124ac73018STyler Dauwalder 				}
3134ac73018STyler Dauwalder 			} else {
3144ac73018STyler Dauwalder 				SIMPLE_PRINT(("read_pos(pos:%lld, len:%ld) failed with: 0x%lx\n", address,
3154ac73018STyler Dauwalder 				        BlockSize(), bytesRead));
3164ac73018STyler Dauwalder 				break;
3174ac73018STyler Dauwalder 			}
3184ac73018STyler Dauwalder 		}
3194ac73018STyler Dauwalder 
3204ac73018STyler Dauwalder 		// If we find an ECMA-167 descriptor, OR if we find a beginning
3214ac73018STyler Dauwalder 		// or terminating extended area descriptor with NO ECMA-168
3224ac73018STyler Dauwalder 		// descriptors, we return B_OK to signal that we should go
3234ac73018STyler Dauwalder 		// looking for valid anchors.
3244ac73018STyler Dauwalder 		err = foundECMA167 || (foundExtended && !foundECMA168) ? B_OK : B_ERROR;
3254ac73018STyler Dauwalder 	}
3264ac73018STyler Dauwalder 
3274ac73018STyler Dauwalder 	RETURN(err);
3284ac73018STyler Dauwalder }
3294ac73018STyler Dauwalder 
3304ac73018STyler Dauwalder status_t
3310d383564STyler Dauwalder Volume::_WalkAnchorVolumeDescriptorSequences()
3320d383564STyler Dauwalder {
3330d383564STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
3340d383564STyler Dauwalder 		const uint8 avds_location_count = 4;
3350d383564STyler Dauwalder 		const off_t avds_locations[avds_location_count] = { 256,
3360d383564STyler Dauwalder 		                                                    Length()-256,
3370d383564STyler Dauwalder 		                                                    Length(),
3380d383564STyler Dauwalder 		                                                    512,
3390d383564STyler Dauwalder 		                                                  };
3400d383564STyler Dauwalder 		bool found_vds = false;
3410d383564STyler Dauwalder 
3420d383564STyler Dauwalder 		for (int32 i = 0; i < avds_location_count; i++) {
3430d383564STyler Dauwalder 			off_t block = avds_locations[i];
3440d383564STyler Dauwalder 			off_t address = AddressForRelativeBlock(block);
3450d383564STyler Dauwalder 			MemoryChunk chunk(BlockSize());
3460d383564STyler Dauwalder 			udf_anchor_descriptor *anchor = NULL;
3470d383564STyler Dauwalder 
3480d383564STyler Dauwalder 			status_t anchorErr = chunk.InitCheck();
3490d383564STyler Dauwalder 			if (!anchorErr) {
3500d383564STyler Dauwalder 				ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
3510d383564STyler Dauwalder 				anchorErr = bytesRead == (ssize_t)BlockSize() ? B_OK : B_IO_ERROR;
3520d383564STyler Dauwalder 				if (anchorErr) {
3530d383564STyler Dauwalder 					PRINT(("block %lld: read_pos(pos:%lld, len:%ld) failed with error 0x%lx\n",
3540d383564STyler Dauwalder 					       block, address, BlockSize(), bytesRead));
3550d383564STyler Dauwalder 				}
3560d383564STyler Dauwalder 			}
3570d383564STyler Dauwalder 			if (!anchorErr) {
3580d383564STyler Dauwalder 				anchor = reinterpret_cast<udf_anchor_descriptor*>(chunk.Data());
3590d383564STyler Dauwalder 				anchorErr = anchor->tag().init_check(block);
3600d383564STyler Dauwalder 				if (anchorErr) {
3610d383564STyler Dauwalder 					PRINT(("block %lld: invalid anchor\n", block));
3620d383564STyler Dauwalder 				} else {
3630d383564STyler Dauwalder 					PRINT(("block %lld: valid anchor\n", block));
3640d383564STyler Dauwalder 				}
3650d383564STyler Dauwalder 			}
3660d383564STyler Dauwalder 			if (!anchorErr) {
3670d383564STyler Dauwalder 				PRINT(("block %lld: anchor:\n", block));
3680d383564STyler Dauwalder 				PDUMP(anchor);
3690d383564STyler Dauwalder 				// Found an avds, so try the main sequence first, then
3700d383564STyler Dauwalder 				// the reserve sequence if the main one fails.
3710d383564STyler Dauwalder 				anchorErr = _WalkVolumeDescriptorSequence(anchor->main_vds());
3720d383564STyler Dauwalder 				if (anchorErr)
3730d383564STyler Dauwalder 					anchorErr = _WalkVolumeDescriptorSequence(anchor->reserve_vds());
3740d383564STyler Dauwalder 
3750d383564STyler Dauwalder 
3760d383564STyler Dauwalder 			}
3770d383564STyler Dauwalder 			if (!anchorErr) {
3780d383564STyler Dauwalder 				PRINT(("block %lld: found valid vds\n", avds_locations[i]));
3790d383564STyler Dauwalder 				found_vds = true;
3800d383564STyler Dauwalder 				break;
3810d383564STyler Dauwalder 			} //else {
3820d383564STyler Dauwalder 				// Both failed, so loop around and try another avds
3830d383564STyler Dauwalder //				PRINT(("block %lld: vds search failed\n", avds_locations[i]));
3840d383564STyler Dauwalder //			}
3850d383564STyler Dauwalder 		}
3860d383564STyler Dauwalder 		status_t err = found_vds ? B_OK : B_ERROR;
3870d383564STyler Dauwalder 		RETURN(err);
3880d383564STyler Dauwalder }
3890d383564STyler Dauwalder 
3900d383564STyler Dauwalder status_t
3910d383564STyler Dauwalder Volume::_WalkVolumeDescriptorSequence(udf_extent_address extent)
3924ac73018STyler Dauwalder {
393565457fdSTyler Dauwalder 	DEBUG_INIT_ETC(CF_PRIVATE | CF_VOLUME_OPS, "Volume", ("loc:%ld, len:%ld",
394565457fdSTyler Dauwalder 	           extent.location(), extent.length()));
395565457fdSTyler Dauwalder 	uint32 count = extent.length()/BlockSize();
3960d383564STyler Dauwalder 
3970d383564STyler Dauwalder 	bool foundLogicalVD = false;
3980d383564STyler Dauwalder 
399565457fdSTyler Dauwalder 	for (uint32 i = 0; i < count; i++)
400565457fdSTyler Dauwalder 	{
401565457fdSTyler Dauwalder 		off_t block = extent.location()+i;
402565457fdSTyler Dauwalder 		off_t address = AddressForRelativeBlock(block);
4030d383564STyler Dauwalder 		MemoryChunk chunk(BlockSize());
4040d383564STyler Dauwalder 		udf_tag *tag = NULL;
4050d383564STyler Dauwalder 
4060d383564STyler Dauwalder 		PRINT(("descriptor #%ld (block %lld):\n", i, block));
4070d383564STyler Dauwalder 
4080d383564STyler Dauwalder 		status_t err = chunk.InitCheck();
409565457fdSTyler Dauwalder 		if (!err) {
4100d383564STyler Dauwalder 			ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
411565457fdSTyler Dauwalder 			err = bytesRead == (ssize_t)BlockSize() ? B_OK : B_IO_ERROR;
412565457fdSTyler Dauwalder 			if (err) {
413565457fdSTyler Dauwalder 				PRINT(("block %lld: read_pos(pos:%lld, len:%ld) failed with error 0x%lx\n",
414565457fdSTyler Dauwalder 				       block, address, BlockSize(), bytesRead));
415565457fdSTyler Dauwalder 			}
416565457fdSTyler Dauwalder 		}
417565457fdSTyler Dauwalder 		if (!err) {
4180d383564STyler Dauwalder 			tag = reinterpret_cast<udf_tag*>(chunk.Data());
4190d383564STyler Dauwalder 			err = tag->init_check(block);
4200d383564STyler Dauwalder 		}
4210d383564STyler Dauwalder 		if (!err) {
4220d383564STyler Dauwalder 			// Now decide what type of descriptor we have
4230d383564STyler Dauwalder 			switch (tag->id()) {
4240d383564STyler Dauwalder 				case TAGID_UNDEFINED:
4250d383564STyler Dauwalder 					break;
4260d383564STyler Dauwalder 
4270d383564STyler Dauwalder 				case TAGID_PRIMARY_VOLUME_DESCRIPTOR:
4280d383564STyler Dauwalder 				{
4290d383564STyler Dauwalder 					udf_primary_descriptor *primary = reinterpret_cast<udf_primary_descriptor*>(tag);
4300d383564STyler Dauwalder 					PDUMP(primary);
4310d383564STyler Dauwalder 					break;
4320d383564STyler Dauwalder 				}
4330d383564STyler Dauwalder 
4340d383564STyler Dauwalder 				case TAGID_ANCHOR_VOLUME_DESCRIPTOR_POINTER:
4350d383564STyler Dauwalder 					break;
4360d383564STyler Dauwalder 
4370d383564STyler Dauwalder 				case TAGID_VOLUME_DESCRIPTOR_POINTER:
4380d383564STyler Dauwalder 					break;
4390d383564STyler Dauwalder 
4400d383564STyler Dauwalder 				case TAGID_IMPLEMENTATION_USE_VOLUME_DESCRIPTOR:
4410d383564STyler Dauwalder 				{
4420d383564STyler Dauwalder 					udf_implementation_use_descriptor *imp_use = reinterpret_cast<udf_implementation_use_descriptor*>(tag);
4430d383564STyler Dauwalder 					PDUMP(imp_use);
4440d383564STyler Dauwalder 					break;
4450d383564STyler Dauwalder 				}
4460d383564STyler Dauwalder 
4470d383564STyler Dauwalder 				case TAGID_PARTITION_DESCRIPTOR:
4480d383564STyler Dauwalder 				{
4490d383564STyler Dauwalder 					udf_partition_descriptor *partition = reinterpret_cast<udf_partition_descriptor*>(tag);
4500d383564STyler Dauwalder 					PDUMP(partition);
4510d383564STyler Dauwalder 					if (partition->tag().init_check(block) == B_OK) {
4520d383564STyler Dauwalder 						udf_partition_descriptor *current = fPartitionMap.Find(partition->partition_number());
4530d383564STyler Dauwalder 						if (!current || current->vds_number() < partition->vds_number()) {
4540d383564STyler Dauwalder 							PRINT(("adding partition #%d with vds_number %ld to partition map\n",
4550d383564STyler Dauwalder 							       partition->partition_number(), partition->vds_number()));
4560d383564STyler Dauwalder 							fPartitionMap.Add(partition);
4570d383564STyler Dauwalder 						}
4580d383564STyler Dauwalder 					}
4590d383564STyler Dauwalder 					break;
4600d383564STyler Dauwalder 				}
4610d383564STyler Dauwalder 
4620d383564STyler Dauwalder 				case TAGID_LOGICAL_VOLUME_DESCRIPTOR:
4630d383564STyler Dauwalder 				{
4640d383564STyler Dauwalder 					udf_logical_descriptor *logical = reinterpret_cast<udf_logical_descriptor*>(tag);
4650d383564STyler Dauwalder 					PDUMP(logical);
4660d383564STyler Dauwalder 					if (foundLogicalVD) {
4670d383564STyler Dauwalder 						// Keep the vd with the highest vds_number
4680d383564STyler Dauwalder 						if (logical->vds_number() > fLogicalVD.vds_number())
4690d383564STyler Dauwalder 							fLogicalVD = *(logical);
470565457fdSTyler Dauwalder 					} else {
4710d383564STyler Dauwalder 						fLogicalVD = *(logical);
4720d383564STyler Dauwalder 						foundLogicalVD = true;
4730d383564STyler Dauwalder 					}
4740d383564STyler Dauwalder 					break;
4750d383564STyler Dauwalder 				}
4760d383564STyler Dauwalder 
4770d383564STyler Dauwalder 				case TAGID_UNALLOCATED_SPACE_DESCRIPTOR:
4780d383564STyler Dauwalder 				{
4790d383564STyler Dauwalder 					udf_unallocated_space_descriptor *unallocated = reinterpret_cast<udf_unallocated_space_descriptor*>(tag);
4800d383564STyler Dauwalder 					PDUMP(unallocated);
4810d383564STyler Dauwalder 					break;
4820d383564STyler Dauwalder 				}
4830d383564STyler Dauwalder 
4840d383564STyler Dauwalder 				case TAGID_TERMINATING_DESCRIPTOR:
4850d383564STyler Dauwalder 				{
4860d383564STyler Dauwalder 					udf_terminating_descriptor *terminating = reinterpret_cast<udf_terminating_descriptor*>(tag);
4870d383564STyler Dauwalder 					PDUMP(terminating);
4880d383564STyler Dauwalder 					break;
4890d383564STyler Dauwalder 				}
4900d383564STyler Dauwalder 
4910d383564STyler Dauwalder 				case TAGID_LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR:
4920d383564STyler Dauwalder 					// Not found in this descriptor sequence
4930d383564STyler Dauwalder 					break;
4940d383564STyler Dauwalder 
4950d383564STyler Dauwalder 				default:
4960d383564STyler Dauwalder 					break;
4970d383564STyler Dauwalder 
498565457fdSTyler Dauwalder 			}
499565457fdSTyler Dauwalder 		}
500565457fdSTyler Dauwalder 	}
5014ac73018STyler Dauwalder 
5020d383564STyler Dauwalder 	status_t err = foundLogicalVD ? B_OK : B_ERROR;
5030d383564STyler Dauwalder 	if (!err) {
5040d383564STyler Dauwalder 		PRINT(("partition map:\n"));
5050d383564STyler Dauwalder 		DUMP(fPartitionMap);
5060d383564STyler Dauwalder 	}
5070d383564STyler Dauwalder 	RETURN(err);
50829008bcfSTyler Dauwalder }
50929008bcfSTyler Dauwalder 
5100d383564STyler Dauwalder status_t
5110d383564STyler Dauwalder Volume::_InitFileSetDescriptor()
5120d383564STyler Dauwalder {
5130d383564STyler Dauwalder 	DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
5140d383564STyler Dauwalder 	MemoryChunk chunk(fLogicalVD.file_set_address().length());
5150d383564STyler Dauwalder 
5160d383564STyler Dauwalder 	status_t err = chunk.InitCheck();
5170d383564STyler Dauwalder 	if (!err) {
5183f4628f1STyler Dauwalder //		err = Read(ad, fLogicalVD.file_set_address().length(), chunk.Data());
5193f4628f1STyler Dauwalder 		err = Read(fLogicalVD.file_set_address(), fLogicalVD.file_set_address().length(), chunk.Data());
5203f4628f1STyler Dauwalder 		if (!err) {
5213f4628f1STyler Dauwalder 			udf_file_set_descriptor *fileSet = reinterpret_cast<udf_file_set_descriptor*>(chunk.Data());
5220d383564STyler Dauwalder 			fileSet->tag().init_check(0);
5230d383564STyler Dauwalder 			PDUMP(fileSet);
5243f4628f1STyler Dauwalder 			fRootIcb = new Icb(this, fileSet->root_directory_icb());
5253f4628f1STyler Dauwalder 			err = fRootIcb ? fRootIcb->InitCheck() : B_NO_MEMORY;
5260d383564STyler Dauwalder 		}
5270d383564STyler Dauwalder 	}
5283f4628f1STyler Dauwalder 
5293f4628f1STyler Dauwalder 	RETURN(err);
5303f4628f1STyler Dauwalder }
5313f4628f1STyler Dauwalder 
532