1//----------------------------------------------------------------------
2//  This software is part of the OpenBeOS distribution and is covered
3//  by the OpenBeOS license.
4//
5//  Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6//----------------------------------------------------------------------
7
8/*! \file UdfBuilder.cpp
9
10	Main UDF image building class implementation.
11*/
12
13#include "UdfBuilder.h"
14
15#include <Directory.h>
16#include <Entry.h>
17#include <Node.h>
18#include <OS.h>
19#include <Path.h>
20#include <stdio.h>
21#include <string>
22#include <sys/stat.h>
23
24#include "DString.h"
25#include "ExtentStream.h"
26#include "MemoryChunk.h"
27#include "UdfDebug.h"
28#include "Utils.h"
29
30using Udf::bool_to_string;
31using Udf::check_size_error;
32
33//! Application identifier entity_id
34static const Udf::entity_id kApplicationId(0, "*OpenBeOS makeudfimage");
35
36static const Udf::logical_block_address kNullLogicalBlock(0, 0);
37static const Udf::extent_address kNullExtent(0, 0);
38static const Udf::long_address kNullAddress(0, 0, 0, 0);
39
40/*! \brief Returns the number of the block in which the byte offset specified
41	by \a pos resides in the data space specified by the extents in \a dataSpace.
42
43	Used to figure out the value for Udf::file_id_descriptor::tag::location fields.
44
45	\param block Output parameter into which the block number of interest is stored.
46*/
47static
48status_t
49block_for_offset(off_t pos, std::list<Udf::long_address> &dataSpace, uint32 blockSize,
50                 uint32 &block)
51{
52	status_t error = pos >= 0 ? B_OK : B_BAD_VALUE;
53	if (!error) {
54		off_t streamPos = 0;
55		for (std::list<Udf::long_address>::const_iterator i = dataSpace.begin();
56		       i != dataSpace.end();
57		         i++)
58		{
59			if (streamPos <= pos && pos < streamPos+i->length()) {
60				// Found it
61				off_t difference = pos - streamPos;
62				block = i->block() + difference / blockSize;
63				return B_OK;
64			} else {
65				streamPos += i->length();
66			}
67		}
68		// Didn't find it, so pos is past the end of the data space
69		error = B_ERROR;
70	}
71	return error;
72}
73
74/*! \brief Creates a new UdfBuilder object.
75
76	\param udfRevision The UDF revision to write, formatted as in the UDF
77	       domain id suffix, i.e. UDF 2.50 is represented by 0x0250.
78*/
79UdfBuilder::UdfBuilder(const char *outputFile, uint32 blockSize, bool doUdf,
80                       const char *udfVolumeName, uint16 udfRevision, bool doIso,
81                       const char *isoVolumeName, const char *rootDirectory,
82                       const ProgressListener &listener, bool truncate)
83	: fInitStatus(B_NO_INIT)
84	, fOutputFile(outputFile, B_READ_WRITE | B_CREATE_FILE | (truncate ? B_ERASE_FILE : 0))
85	, fOutputFilename(outputFile)
86	, fBlockSize(blockSize)
87	, fBlockShift(0)
88	, fDoUdf(doUdf)
89	, fUdfVolumeName(udfVolumeName)
90	, fUdfRevision(udfRevision)
91	, fUdfDescriptorVersion(udfRevision <= 0x0150 ? 2 : 3)
92	, fUdfDomainId(udfRevision == 0x0150 ? Udf::kDomainId150 : Udf::kDomainId201)
93	, fDoIso(doIso)
94	, fIsoVolumeName(isoVolumeName)
95	, fRootDirectory(rootDirectory ? rootDirectory : "")
96	, fRootDirectoryName(rootDirectory)
97	, fListener(listener)
98	, fAllocator(blockSize)
99	, fPartitionAllocator(0, 257, fAllocator)
100	, fStatistics()
101	, fBuildTime(0)		// set at start of Build()
102	, fBuildTimeStamp()	// ditto
103	, fNextUniqueId(16)	// Starts at 16 thanks to MacOS... See UDF-2.50 3.2.1
104	, f32BitIdsNoLongerUnique(false) // Set to true once fNextUniqueId requires > 32bits
105{
106	DEBUG_INIT_ETC("UdfBuilder", ("blockSize: %ld, doUdf: %s, doIso: %s",
107	               blockSize, bool_to_string(doUdf), bool_to_string(doIso)));
108
109	// Check the output file
110	status_t error = _OutputFile().InitCheck();
111	if (error) {
112		_PrintError("Error opening output file: 0x%lx, `%s'", error,
113		            strerror(error));
114	}
115	// Check the allocator
116	if (!error) {
117		error = _Allocator().InitCheck();
118		if (error) {
119			_PrintError("Error creating block allocator: 0x%lx, `%s'", error,
120			            strerror(error));
121		}
122	}
123	// Check the block size
124	if (!error) {
125		error = Udf::get_block_shift(_BlockSize(), fBlockShift);
126		if (!error)
127			error = _BlockSize() >= 512 ? B_OK : B_BAD_VALUE;
128		if (error)
129			_PrintError("Invalid block size: %ld", blockSize);
130	}
131	// Check that at least one type of filesystem has
132	// been requested
133	if (!error) {
134		error = _DoUdf() || _DoIso() ? B_OK : B_BAD_VALUE;
135		if (error)
136			_PrintError("No filesystems requested.");
137	}
138	// Check the volume names
139	if (!error) {
140		if (_UdfVolumeName().Utf8Length() == 0)
141			_UdfVolumeName().SetTo("(Unnamed UDF Volume)");
142		if (_IsoVolumeName().Utf8Length() == 0)
143			_IsoVolumeName().SetTo("UNNAMED_ISO");
144		if (_DoUdf()) {
145			error = _UdfVolumeName().Cs0Length() <= 128 ? B_OK : B_ERROR;
146			if (error) {
147				_PrintError("Udf volume name too long (%ld bytes, max "
148				            "length is 128 bytes.",
149				            _UdfVolumeName().Cs0Length());
150			}
151		}
152		if (!error && _DoIso()) {
153			error = _IsoVolumeName().Utf8Length() <= 32 ? B_OK : B_ERROR;
154			// ToDo: Should also check for illegal characters
155			if (error) {
156				_PrintError("Iso volume name too long (%ld bytes, max "
157				            "length is 32 bytes.",
158				            _IsoVolumeName().Cs0Length());
159			}
160		}
161	}
162	// Check the udf revision
163	if (!error) {
164		error = _UdfRevision() == 0x0150 || _UdfRevision() == 0x0201
165		        ? B_OK : B_ERROR;
166		if (error) {
167			_PrintError("Invalid UDF revision 0x%04x", _UdfRevision());
168		}
169	}
170	// Check the root directory
171	if (!error) {
172		error = _RootDirectory().InitCheck();
173		if (error) {
174			_PrintError("Error initializing root directory entry: 0x%lx, `%s'",
175			            error, strerror(error));
176		}
177	}
178
179	if (!error) {
180		fInitStatus = B_OK;
181	}
182}
183
184status_t
185UdfBuilder::InitCheck() const
186{
187	return fInitStatus;
188}
189
190/*! \brief Builds the disc image.
191*/
192status_t
193UdfBuilder::Build()
194{
195	DEBUG_INIT("UdfBuilder");
196	status_t error = InitCheck();
197	if (error)
198		RETURN(error);
199
200	// Note the time at which we're starting
201	fStatistics.Reset();
202	_SetBuildTime(_Stats().StartTime());
203
204	// Udf variables
205	uint16 partitionNumber = 0;
206	Udf::anchor_volume_descriptor anchor256;
207	Udf::anchor_volume_descriptor anchorN;
208	Udf::extent_address primaryVdsExtent;
209	Udf::extent_address reserveVdsExtent;
210	Udf::primary_volume_descriptor primary;
211	Udf::partition_descriptor partition;
212	Udf::unallocated_space_descriptor freespace;
213	Udf::logical_volume_descriptor logical;
214	Udf::implementation_use_descriptor implementationUse;
215	Udf::long_address filesetAddress;
216	Udf::extent_address filesetExtent;
217	Udf::extent_address integrityExtent;
218	Udf::file_set_descriptor fileset;
219	node_data rootNode;
220
221	// Iso variables
222//	Udf::extent_address rootDirentExtent;
223
224
225	_OutputFile().Seek(0, SEEK_SET);
226	fListener.OnStart(fRootDirectoryName.c_str(), fOutputFilename.c_str(),
227	                  _UdfVolumeName().Utf8(), _UdfRevision());
228
229	_PrintUpdate(VERBOSITY_LOW, "Initializing volume");
230
231	// Reserve the first 32KB and zero them out.
232	if (!error) {
233		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing reserved area");
234		const int reservedAreaSize = 32 * 1024;
235		Udf::extent_address extent(0, reservedAreaSize);
236		_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for reserved area");
237		error = _Allocator().GetExtent(extent);
238		if (!error) {
239			_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
240			             extent.location(), extent.length());
241			ssize_t bytes = _OutputFile().Zero(reservedAreaSize);
242			error = check_size_error(bytes, reservedAreaSize);
243		}
244		// Error check
245		if (error) {
246			_PrintError("Error creating reserved area: 0x%lx, `%s'",
247			            error, strerror(error));
248		}
249	}
250
251	const int vrsBlockSize = 2048;
252
253	// Write the iso portion of the vrs
254	if (!error && _DoIso()) {
255		_PrintUpdate(VERBOSITY_MEDIUM, "iso: Writing primary volume descriptor");
256
257		// Error check
258		if (error) {
259			_PrintError("Error writing iso vrs: 0x%lx, `%s'",
260			            error, strerror(error));
261		}
262	}
263
264	// Write the udf portion of the vrs
265	if (!error && _DoUdf()) {
266		Udf::extent_address extent;
267		// Bea
268		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing bea descriptor");
269		_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for bea descriptor");
270		Udf::volume_structure_descriptor_header bea(0, Udf::kVSDID_BEA, 1);
271		error = _Allocator().GetNextExtent(vrsBlockSize, true, extent);
272		if (!error) {
273			_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
274			             extent.location(), extent.length());
275			ssize_t bytes = _OutputFile().Write(&bea, sizeof(bea));
276			error = check_size_error(bytes, sizeof(bea));
277			if (!error) {
278				bytes = _OutputFile().Zero(vrsBlockSize-sizeof(bea));
279				error = check_size_error(bytes, vrsBlockSize-sizeof(bea));
280			}
281		}
282		// Nsr
283		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing nsr descriptor");
284		Udf::volume_structure_descriptor_header nsr(0, _UdfRevision() <= 0x0150
285		                                            ? Udf::kVSDID_ECMA167_2
286		                                            : Udf::kVSDID_ECMA167_3,
287		                                            1);
288		if (!error) {
289			_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for nsr descriptor");
290			_Allocator().GetNextExtent(vrsBlockSize, true, extent);
291		}
292		if (!error) {
293			_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
294			             extent.location(), extent.length());
295			ssize_t bytes = _OutputFile().Write(&nsr, sizeof(nsr));
296			error = check_size_error(bytes, sizeof(nsr));
297			if (!error) {
298				bytes = _OutputFile().Zero(vrsBlockSize-sizeof(nsr));
299				error = check_size_error(bytes, vrsBlockSize-sizeof(nsr));
300			}
301		}
302		// Tea
303		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing tea descriptor");
304		Udf::volume_structure_descriptor_header tea(0, Udf::kVSDID_TEA, 1);
305		if (!error) {
306			_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for tea descriptor");
307			error = _Allocator().GetNextExtent(vrsBlockSize, true, extent);
308		}
309		if (!error) {
310			_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
311			             extent.location(), extent.length());
312			ssize_t bytes = _OutputFile().Write(&tea, sizeof(tea));
313			error = check_size_error(bytes, sizeof(tea));
314			if (!error) {
315				bytes = _OutputFile().Zero(vrsBlockSize-sizeof(tea));
316				error = check_size_error(bytes, vrsBlockSize-sizeof(tea));
317			}
318		}
319		// Error check
320		if (error) {
321			_PrintError("Error writing udf vrs: 0x%lx, `%s'",
322			            error, strerror(error));
323		}
324	}
325
326	// Write the udf anchor256 and volume descriptor sequences
327	if (!error && _DoUdf()) {
328		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing anchor256");
329		// reserve anchor256
330		_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for anchor256");
331		error = _Allocator().GetBlock(256);
332		if (!error)
333			_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
334			             256, _BlockSize());
335		// reserve primary vds (min length = 16 blocks, which is plenty for us)
336		if (!error) {
337			_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for primary vds");
338			error = _Allocator().GetNextExtent(off_t(16) << _BlockShift(), true, primaryVdsExtent);
339			if (!error) {
340				_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
341				             primaryVdsExtent.location(), primaryVdsExtent.length());
342				ssize_t bytes = _OutputFile().ZeroAt(off_t(primaryVdsExtent.location()) << _BlockShift(),
343				                                   primaryVdsExtent.length());
344				error = check_size_error(bytes, primaryVdsExtent.length());
345			}
346		}
347		// reserve reserve vds. try to grab the 16 blocks preceding block 256. if
348		// that fails, just grab any 16. most commercial discs just put the reserve
349		// vds immediately following the primary vds, which seems a bit stupid to me,
350		// now that I think about it...
351		if (!error) {
352			_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for reserve vds");
353			reserveVdsExtent.set_location(256-16);
354			reserveVdsExtent.set_length(off_t(16) << _BlockShift());
355			error = _Allocator().GetExtent(reserveVdsExtent);
356			if (error)
357				error = _Allocator().GetNextExtent(off_t(16) << _BlockShift(), true, reserveVdsExtent);
358			if (!error) {
359				_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
360				             reserveVdsExtent.location(), reserveVdsExtent.length());
361				ssize_t bytes = _OutputFile().ZeroAt(off_t(reserveVdsExtent.location()) << _BlockShift(),
362				                                   reserveVdsExtent.length());
363				error = check_size_error(bytes, reserveVdsExtent.length());
364			}
365		}
366		// write anchor_256
367		if (!error) {
368			anchor256.main_vds() = primaryVdsExtent;
369			anchor256.reserve_vds() = reserveVdsExtent;
370			Udf::descriptor_tag &tag = anchor256.tag();
371			tag.set_id(Udf::TAGID_ANCHOR_VOLUME_DESCRIPTOR_POINTER);
372			tag.set_version(_UdfDescriptorVersion());
373			tag.set_serial_number(0);
374			tag.set_location(256);
375			tag.set_checksums(anchor256);
376			_OutputFile().Seek(off_t(256) << _BlockShift(), SEEK_SET);
377			ssize_t bytes = _OutputFile().Write(&anchor256, sizeof(anchor256));
378			error = check_size_error(bytes, sizeof(anchor256));
379			if (!error && bytes < ssize_t(_BlockSize())) {
380				bytes = _OutputFile().Zero(_BlockSize()-sizeof(anchor256));
381				error = check_size_error(bytes, _BlockSize()-sizeof(anchor256));
382			}
383		}
384		uint32 vdsNumber = 0;
385		// write primary_vd
386		if (!error) {
387			_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing primary volume descriptor");
388			// build primary_vd
389			primary.set_vds_number(vdsNumber);
390			primary.set_primary_volume_descriptor_number(0);
391			uint32 nameLength = _UdfVolumeName().Cs0Length();
392			if (nameLength > primary.volume_identifier().size()-1) {
393				_PrintWarning("udf: Truncating volume name as stored in primary "
394				              "volume descriptor to 31 byte limit. This shouldn't matter, "
395				              "as the complete name is %d bytes long, which is short enough "
396				              "to fit completely in the logical volume descriptor.",
397				              nameLength);
398			}
399			Udf::DString volumeIdField(_UdfVolumeName(),
400			                           primary.volume_identifier().size());
401			memcpy(primary.volume_identifier().data, volumeIdField.String(),
402			       primary.volume_identifier().size());
403			primary.set_volume_sequence_number(1);
404			primary.set_max_volume_sequence_number(1);
405			primary.set_interchange_level(2);
406			primary.set_max_interchange_level(3);
407			primary.set_character_set_list(1);
408			primary.set_max_character_set_list(1);
409			// first 16 chars of volume set id must be unique. first 8 must be
410			// a hex representation of a timestamp
411			char timestamp[9];
412			sprintf(timestamp, "%08lX", _BuildTime());
413			std::string volumeSetId(timestamp);
414			volumeSetId = volumeSetId + "--------" + "(unnamed volume set)";
415			Udf::DString volumeSetIdField(volumeSetId.c_str(),
416			                              primary.volume_set_identifier().size());
417			memcpy(primary.volume_set_identifier().data, volumeSetIdField.String(),
418			       primary.volume_set_identifier().size());
419			primary.descriptor_character_set() = Udf::kCs0CharacterSet;
420			primary.explanatory_character_set() = Udf::kCs0CharacterSet;
421			primary.volume_abstract() = kNullExtent;
422			primary.volume_copyright_notice() = kNullExtent;
423			primary.application_id() = kApplicationId;
424			primary.recording_date_and_time() = _BuildTimeStamp();
425			primary.implementation_id() = Udf::kImplementationId;
426			memset(primary.implementation_use().data, 0,
427			       primary.implementation_use().size());
428			primary.set_predecessor_volume_descriptor_sequence_location(0);
429			primary.set_flags(0);	// ToDo: maybe 1 is more appropriate?
430			memset(primary.reserved().data, 0, primary.reserved().size());
431			primary.tag().set_id(Udf::TAGID_PRIMARY_VOLUME_DESCRIPTOR);
432			primary.tag().set_version(_UdfDescriptorVersion());
433			primary.tag().set_serial_number(0);
434				// note that the checksums haven't been set yet, since the
435				// location is dependent on which sequence (primary or reserve)
436				// the descriptor is currently being written to. Thus we have to
437				// recalculate the checksums for each sequence.
438			DUMP(primary);
439			// write primary_vd to primary vds
440			primary.tag().set_location(primaryVdsExtent.location()+vdsNumber);
441			primary.tag().set_checksums(primary);
442			ssize_t bytes = _OutputFile().WriteAt(off_t(primary.tag().location()) << _BlockShift(),
443			                              &primary, sizeof(primary));
444			error = check_size_error(bytes, sizeof(primary));
445			if (!error && bytes < ssize_t(_BlockSize())) {
446				ssize_t bytesLeft = _BlockSize() - bytes;
447				bytes = _OutputFile().ZeroAt((off_t(primary.tag().location()) << _BlockShift())
448				                             + bytes, bytesLeft);
449				error = check_size_error(bytes, bytesLeft);
450			}
451			// write primary_vd to reserve vds
452			if (!error) {
453				primary.tag().set_location(reserveVdsExtent.location()+vdsNumber);
454				primary.tag().set_checksums(primary);
455				ssize_t bytes = _OutputFile().WriteAt(off_t(primary.tag().location()) << _BlockShift(),
456	        			                              &primary, sizeof(primary));
457				error = check_size_error(bytes, sizeof(primary));
458				if (!error && bytes < ssize_t(_BlockSize())) {
459					ssize_t bytesLeft = _BlockSize() - bytes;
460					bytes = _OutputFile().ZeroAt(off_t((primary.tag().location()) << _BlockShift())
461					                             + bytes, bytesLeft);
462					error = check_size_error(bytes, bytesLeft);
463				}
464			}
465		}
466
467		// write partition descriptor
468		if (!error) {
469			_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing partition descriptor");
470			// build partition descriptor
471	 		vdsNumber++;
472			partition.set_vds_number(vdsNumber);
473			partition.set_partition_flags(1);
474			partition.set_partition_number(partitionNumber);
475			partition.partition_contents() = _UdfRevision() <= 0x0150
476			                                 ? Udf::kPartitionContentsId1xx
477			                                 : Udf::kPartitionContentsId2xx;
478			memset(partition.partition_contents_use().data, 0,
479			       partition.partition_contents_use().size());
480			partition.set_access_type(Udf::ACCESS_READ_ONLY);
481			partition.set_start(_Allocator().Tail());
482			partition.set_length(0);
483				// Can't set the length till we've built most of rest of the image,
484				// so we'll set it to 0 now and fix it once we know how big
485				// the partition really is.
486			partition.implementation_id() = Udf::kImplementationId;
487			memset(partition.implementation_use().data, 0,
488			       partition.implementation_use().size());
489			memset(partition.reserved().data, 0,
490			       partition.reserved().size());
491			partition.tag().set_id(Udf::TAGID_PARTITION_DESCRIPTOR);
492			partition.tag().set_version(_UdfDescriptorVersion());
493			partition.tag().set_serial_number(0);
494				// note that the checksums haven't been set yet, since the
495				// location is dependent on which sequence (primary or reserve)
496				// the descriptor is currently being written to. Thus we have to
497				// recalculate the checksums for each sequence.
498			DUMP(partition);
499			// write partition descriptor to primary vds
500			partition.tag().set_location(primaryVdsExtent.location()+vdsNumber);
501			partition.tag().set_checksums(partition);
502			ssize_t bytes = _OutputFile().WriteAt(off_t(partition.tag().location()) << _BlockShift(),
503			                              &partition, sizeof(partition));
504			error = check_size_error(bytes, sizeof(partition));
505			if (!error && bytes < ssize_t(_BlockSize())) {
506				ssize_t bytesLeft = _BlockSize() - bytes;
507				bytes = _OutputFile().ZeroAt((off_t(partition.tag().location()) << _BlockShift())
508				                             + bytes, bytesLeft);
509				error = check_size_error(bytes, bytesLeft);
510			}
511			// write partition descriptor to reserve vds
512			if (!error) {
513				partition.tag().set_location(reserveVdsExtent.location()+vdsNumber);
514				partition.tag().set_checksums(partition);
515				ssize_t bytes = _OutputFile().WriteAt(off_t(partition.tag().location()) << _BlockShift(),
516	        			                              &partition, sizeof(partition));
517				error = check_size_error(bytes, sizeof(partition));
518				if (!error && bytes < ssize_t(_BlockSize())) {
519					ssize_t bytesLeft = _BlockSize() - bytes;
520					bytes = _OutputFile().ZeroAt((off_t(partition.tag().location()) << _BlockShift())
521					                             + bytes, bytesLeft);
522					error = check_size_error(bytes, bytesLeft);
523				}
524			}
525		}
526
527		// write unallocated space descriptor
528		if (!error) {
529			_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing unallocated space descriptor");
530			// build freespace descriptor
531	 		vdsNumber++;
532			freespace.set_vds_number(vdsNumber);
533			freespace.set_allocation_descriptor_count(0);
534			freespace.tag().set_id(Udf::TAGID_UNALLOCATED_SPACE_DESCRIPTOR);
535			freespace.tag().set_version(_UdfDescriptorVersion());
536			freespace.tag().set_serial_number(0);
537				// note that the checksums haven't been set yet, since the
538				// location is dependent on which sequence (primary or reserve)
539				// the descriptor is currently being written to. Thus we have to
540				// recalculate the checksums for each sequence.
541			DUMP(freespace);
542			// write freespace descriptor to primary vds
543			freespace.tag().set_location(primaryVdsExtent.location()+vdsNumber);
544			freespace.tag().set_checksums(freespace);
545			ssize_t bytes = _OutputFile().WriteAt(off_t(freespace.tag().location()) << _BlockShift(),
546			                              &freespace, sizeof(freespace));
547			error = check_size_error(bytes, sizeof(freespace));
548			if (!error && bytes < ssize_t(_BlockSize())) {
549				ssize_t bytesLeft = _BlockSize() - bytes;
550				bytes = _OutputFile().ZeroAt((off_t(freespace.tag().location()) << _BlockShift())
551				                             + bytes, bytesLeft);
552				error = check_size_error(bytes, bytesLeft);
553			}
554			// write freespace descriptor to reserve vds
555			if (!error) {
556				freespace.tag().set_location(reserveVdsExtent.location()+vdsNumber);
557				freespace.tag().set_checksums(freespace);
558				ssize_t bytes = _OutputFile().WriteAt(off_t(freespace.tag().location()) << _BlockShift(),
559	        			                              &freespace, sizeof(freespace));
560				error = check_size_error(bytes, sizeof(freespace));
561				if (!error && bytes < ssize_t(_BlockSize())) {
562					ssize_t bytesLeft = _BlockSize() - bytes;
563					bytes = _OutputFile().ZeroAt((off_t(freespace.tag().location()) << _BlockShift())
564					                             + bytes, bytesLeft);
565					error = check_size_error(bytes, bytesLeft);
566				}
567			}
568		}
569
570		// write logical_vd
571		if (!error) {
572			_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing logical volume descriptor");
573			// build logical_vd
574	 		vdsNumber++;
575	 		logical.set_vds_number(vdsNumber);
576	 		logical.character_set() = Udf::kCs0CharacterSet;
577	 		error = (_UdfVolumeName().Cs0Length() <=
578	 		        logical.logical_volume_identifier().size())
579	 		          ? B_OK : B_ERROR;
580	 			// We check the length in the constructor, so this should never
581	 			// trigger an error, but just to be safe...
582	 		if (!error) {
583				Udf::DString volumeIdField(_UdfVolumeName(),
584				                           logical.logical_volume_identifier().size());
585				memcpy(logical.logical_volume_identifier().data, volumeIdField.String(),
586				       logical.logical_volume_identifier().size());
587				logical.set_logical_block_size(_BlockSize());
588				logical.domain_id() = _UdfDomainId();
589				memset(logical.logical_volume_contents_use().data, 0,
590				       logical.logical_volume_contents_use().size());
591				// Allocate a block for the file set descriptor
592				_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for file set descriptor");
593				error = _PartitionAllocator().GetNextExtent(_BlockSize(), true,
594				                                            filesetAddress, filesetExtent);
595				if (!error) {
596					_PrintUpdate(VERBOSITY_HIGH, "udf: (partition: %d, location: %ld, "
597					             "length: %ld) => (location: %ld, length: %ld)",
598					             filesetAddress.partition(), filesetAddress.block(),
599					             filesetAddress.length(), filesetExtent.location(),
600					             filesetExtent.length());
601				}
602			}
603			if (!error) {
604				logical.file_set_address() = filesetAddress;
605				logical.set_map_table_length(sizeof(Udf::physical_partition_map));
606				logical.set_partition_map_count(1);
607				logical.implementation_id() = Udf::kImplementationId;
608				memset(logical.implementation_use().data, 0,
609				       logical.implementation_use().size());
610				// Allocate a couple of blocks for the integrity sequence
611				error = _Allocator().GetNextExtent(_BlockSize()*2, true,
612				                                   integrityExtent);
613			}
614			if (!error) {
615				logical.integrity_sequence_extent() = integrityExtent;
616				Udf::physical_partition_map map;
617				map.set_type(1);
618				map.set_length(6);
619				map.set_volume_sequence_number(1);
620				map.set_partition_number(partitionNumber);
621				memcpy(logical.partition_maps(), &map, sizeof(map));
622				logical.tag().set_id(Udf::TAGID_LOGICAL_VOLUME_DESCRIPTOR);
623				logical.tag().set_version(_UdfDescriptorVersion());
624				logical.tag().set_serial_number(0);
625					// note that the checksums haven't been set yet, since the
626					// location is dependent on which sequence (primary or reserve)
627					// the descriptor is currently being written to. Thus we have to
628					// recalculate the checksums for each sequence.
629				DUMP(logical);
630				// write partition descriptor to primary vds
631				uint32 logicalSize = Udf::kLogicalVolumeDescriptorBaseSize + sizeof(map);
632				logical.tag().set_location(primaryVdsExtent.location()+vdsNumber);
633				logical.tag().set_checksums(logical, logicalSize);
634				ssize_t bytes = _OutputFile().WriteAt(off_t(logical.tag().location()) << _BlockShift(),
635				                              &logical, logicalSize);
636				error = check_size_error(bytes, logicalSize);
637				if (!error && bytes < ssize_t(_BlockSize())) {
638					ssize_t bytesLeft = _BlockSize() - bytes;
639					bytes = _OutputFile().ZeroAt((off_t(logical.tag().location()) << _BlockShift())
640					                             + bytes, bytesLeft);
641					error = check_size_error(bytes, bytesLeft);
642				}
643				// write logical descriptor to reserve vds
644				if (!error) {
645					logical.tag().set_location(reserveVdsExtent.location()+vdsNumber);
646					logical.tag().set_checksums(logical, logicalSize);
647					ssize_t bytes = _OutputFile().WriteAt(off_t(logical.tag().location()) << _BlockShift(),
648		        			                              &logical, sizeof(logical));
649					error = check_size_error(bytes, sizeof(logical));
650					if (!error && bytes < ssize_t(_BlockSize())) {
651						ssize_t bytesLeft = _BlockSize() - bytes;
652						bytes = _OutputFile().ZeroAt((off_t(logical.tag().location()) << _BlockShift())
653						                             + bytes, bytesLeft);
654						error = check_size_error(bytes, bytesLeft);
655					}
656				}
657			}
658		}
659
660		// write implementation use descriptor
661		if (!error) {
662			_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing implementation use descriptor");
663			// build implementationUse descriptor
664	 		vdsNumber++;
665			implementationUse.set_vds_number(vdsNumber);
666			switch (_UdfRevision()) {
667				case 0x0150:
668					implementationUse.implementation_id() = Udf::kLogicalVolumeInfoId150;
669					break;
670				case 0x0201:
671					implementationUse.implementation_id() = Udf::kLogicalVolumeInfoId201;
672					break;
673				default:
674					_PrintError("Invalid udf revision: 0x04x", _UdfRevision());
675					error = B_ERROR;
676			}
677			ssize_t bytes = 0;
678			if (!error) {
679				Udf::logical_volume_info &info = implementationUse.info();
680				info.character_set() = Udf::kCs0CharacterSet;
681				Udf::DString logicalVolumeId(_UdfVolumeName(),
682				                           	 info.logical_volume_id().size());
683				memcpy(info.logical_volume_id().data, logicalVolumeId.String(),
684				       info.logical_volume_id().size());
685				Udf::DString info1("Logical Volume Info #1",
686				                   info.logical_volume_info_1().size());
687				memcpy(info.logical_volume_info_1().data, info1.String(),
688				       info.logical_volume_info_1().size());
689				Udf::DString info2("Logical Volume Info #2",
690				                   info.logical_volume_info_2().size());
691				memcpy(info.logical_volume_info_2().data, info2.String(),
692				       info.logical_volume_info_2().size());
693				Udf::DString info3("Logical Volume Info #3",
694				                   info.logical_volume_info_3().size());
695				memcpy(info.logical_volume_info_3().data, info3.String(),
696				       info.logical_volume_info_3().size());
697				info.implementation_id() = Udf::kImplementationId;
698				memset(info.implementation_use().data, 0, info.implementation_use().size());
699				implementationUse.tag().set_id(Udf::TAGID_IMPLEMENTATION_USE_VOLUME_DESCRIPTOR);
700				implementationUse.tag().set_version(_UdfDescriptorVersion());
701				implementationUse.tag().set_serial_number(0);
702					// note that the checksums haven't been set yet, since the
703					// location is dependent on which sequence (primary or reserve)
704					// the descriptor is currently being written to. Thus we have to
705					// recalculate the checksums for each sequence.
706				DUMP(implementationUse);
707				// write implementationUse descriptor to primary vds
708				implementationUse.tag().set_location(primaryVdsExtent.location()+vdsNumber);
709				implementationUse.tag().set_checksums(implementationUse);
710				bytes = _OutputFile().WriteAt(off_t(implementationUse.tag().location()) << _BlockShift(),
711				                              &implementationUse, sizeof(implementationUse));
712				error = check_size_error(bytes, sizeof(implementationUse));
713			}
714			if (!error && bytes < ssize_t(_BlockSize())) {
715				ssize_t bytesLeft = _BlockSize() - bytes;
716				bytes = _OutputFile().ZeroAt((off_t(implementationUse.tag().location()) << _BlockShift())
717				                             + bytes, bytesLeft);
718				error = check_size_error(bytes, bytesLeft);
719			}
720			// write implementationUse descriptor to reserve vds
721			if (!error) {
722				implementationUse.tag().set_location(reserveVdsExtent.location()+vdsNumber);
723				implementationUse.tag().set_checksums(implementationUse);
724				ssize_t bytes = _OutputFile().WriteAt(off_t(implementationUse.tag().location()) << _BlockShift(),
725	        			                              &implementationUse, sizeof(implementationUse));
726				error = check_size_error(bytes, sizeof(implementationUse));
727				if (!error && bytes < ssize_t(_BlockSize())) {
728					ssize_t bytesLeft = _BlockSize() - bytes;
729					bytes = _OutputFile().ZeroAt((off_t(implementationUse.tag().location()) << _BlockShift())
730					                             + bytes, bytesLeft);
731					error = check_size_error(bytes, bytesLeft);
732				}
733			}
734		}
735
736		// write terminating descriptor
737		if (!error) {
738	 		vdsNumber++;
739			Udf::terminating_descriptor terminator;
740			terminator.tag().set_id(Udf::TAGID_TERMINATING_DESCRIPTOR);
741			terminator.tag().set_version(_UdfDescriptorVersion());
742			terminator.tag().set_serial_number(0);
743			terminator.tag().set_location(integrityExtent.location()+1);
744			terminator.tag().set_checksums(terminator);
745			DUMP(terminator);
746			// write terminator to primary vds
747			terminator.tag().set_location(primaryVdsExtent.location()+vdsNumber);
748			terminator.tag().set_checksums(terminator);
749			ssize_t bytes = _OutputFile().WriteAt(off_t(terminator.tag().location()) << _BlockShift(),
750			                              &terminator, sizeof(terminator));
751			error = check_size_error(bytes, sizeof(terminator));
752			if (!error && bytes < ssize_t(_BlockSize())) {
753				ssize_t bytesLeft = _BlockSize() - bytes;
754				bytes = _OutputFile().ZeroAt((off_t(terminator.tag().location()) << _BlockShift())
755				                             + bytes, bytesLeft);
756				error = check_size_error(bytes, bytesLeft);
757			}
758			// write terminator to reserve vds
759			if (!error) {
760				terminator.tag().set_location(reserveVdsExtent.location()+vdsNumber);
761				terminator.tag().set_checksums(terminator);
762				ssize_t bytes = _OutputFile().WriteAt(off_t(terminator.tag().location()) << _BlockShift(),
763	        			                              &terminator, sizeof(terminator));
764				error = check_size_error(bytes, sizeof(terminator));
765				if (!error && bytes < ssize_t(_BlockSize())) {
766					ssize_t bytesLeft = _BlockSize() - bytes;
767					bytes = _OutputFile().ZeroAt((off_t(terminator.tag().location()) << _BlockShift())
768					                             + bytes, bytesLeft);
769					error = check_size_error(bytes, bytesLeft);
770				}
771			}
772		}
773
774		// Error check
775		if (error) {
776			_PrintError("Error writing udf vds: 0x%lx, `%s'",
777			            error, strerror(error));
778		}
779	}
780
781	// Write the file set descriptor
782	if (!error) {
783		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing file set descriptor");
784		fileset.recording_date_and_time() = _BuildTimeStamp();
785		fileset.set_interchange_level(3);
786		fileset.set_max_interchange_level(3);
787		fileset.set_character_set_list(1);
788		fileset.set_max_character_set_list(1);
789		fileset.set_file_set_number(0);
790		fileset.set_file_set_descriptor_number(0);
791		fileset.logical_volume_id_character_set() = Udf::kCs0CharacterSet;
792		Udf::DString volumeIdField(_UdfVolumeName(),
793		                           fileset.logical_volume_id().size());
794		memcpy(fileset.logical_volume_id().data, volumeIdField.String(),
795		       fileset.logical_volume_id().size());
796		fileset.file_set_id_character_set() = Udf::kCs0CharacterSet;
797		Udf::DString filesetIdField(_UdfVolumeName(),
798		                           fileset.file_set_id().size());
799		memcpy(fileset.file_set_id().data, filesetIdField.String(),
800		       fileset.file_set_id().size());
801		memset(fileset.copyright_file_id().data, 0,
802		       fileset.copyright_file_id().size());
803		memset(fileset.abstract_file_id().data, 0,
804		       fileset.abstract_file_id().size());
805		fileset.root_directory_icb() = kNullAddress;
806		fileset.domain_id() = _UdfDomainId();
807		fileset.next_extent() = kNullAddress;
808		fileset.system_stream_directory_icb() = kNullAddress;
809		memset(fileset.reserved().data, 0,
810		       fileset.reserved().size());
811		fileset.tag().set_id(Udf::TAGID_FILE_SET_DESCRIPTOR);
812		fileset.tag().set_version(_UdfDescriptorVersion());
813		fileset.tag().set_serial_number(0);
814		fileset.tag().set_location(filesetAddress.block());
815		fileset.tag().set_checksums(fileset);
816		DUMP(fileset);
817		// write fsd
818		ssize_t bytes = _OutputFile().WriteAt(off_t(filesetExtent.location()) << _BlockShift(),
819       			                              &fileset, sizeof(fileset));
820		error = check_size_error(bytes, sizeof(fileset));
821		if (!error && bytes < ssize_t(_BlockSize())) {
822			ssize_t bytesLeft = _BlockSize() - bytes;
823			bytes = _OutputFile().ZeroAt((off_t(filesetExtent.location()) << _BlockShift())
824			                             + bytes, bytesLeft);
825			error = check_size_error(bytes, bytesLeft);
826		}
827	}
828
829	// Build the rest of the image
830	if (!error) {
831		struct stat rootStats;
832		error = _RootDirectory().GetStat(&rootStats);
833		if (!error)
834			error = _ProcessDirectory(_RootDirectory(), "/", rootStats, rootNode,
835			                          kNullAddress, true);
836	}
837
838	if (!error)
839		_PrintUpdate(VERBOSITY_LOW, "Finalizing volume");
840
841	// Rewrite the fsd with the root dir icb
842	if (!error) {
843		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Finalizing file set descriptor");
844		fileset.root_directory_icb() = rootNode.icbAddress;
845		fileset.tag().set_checksums(fileset);
846		DUMP(fileset);
847		// write fsd
848		ssize_t bytes = _OutputFile().WriteAt(off_t(filesetExtent.location()) << _BlockShift(),
849       			                              &fileset, sizeof(fileset));
850		error = check_size_error(bytes, sizeof(fileset));
851		if (!error && bytes < ssize_t(_BlockSize())) {
852			ssize_t bytesLeft = _BlockSize() - bytes;
853			bytes = _OutputFile().ZeroAt((off_t(filesetExtent.location()) << _BlockShift())
854			                             + bytes, bytesLeft);
855			error = check_size_error(bytes, bytesLeft);
856		}
857	}
858
859	// Set the final partition length and rewrite the partition descriptor
860	if (!error) {
861		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Finalizing partition descriptor");
862		partition.set_length(_PartitionAllocator().Length());
863		DUMP(partition);
864		// write partition descriptor to primary vds
865		partition.tag().set_location(primaryVdsExtent.location()+partition.vds_number());
866		partition.tag().set_checksums(partition);
867		ssize_t bytes = _OutputFile().WriteAt(off_t(partition.tag().location()) << _BlockShift(),
868		                              &partition, sizeof(partition));
869		error = check_size_error(bytes, sizeof(partition));
870		if (!error && bytes < ssize_t(_BlockSize())) {
871			ssize_t bytesLeft = _BlockSize() - bytes;
872			bytes = _OutputFile().ZeroAt((off_t(partition.tag().location()) << _BlockShift())
873			                             + bytes, bytesLeft);
874			error = check_size_error(bytes, bytesLeft);
875		}
876		// write partition descriptor to reserve vds
877		if (!error) {
878			partition.tag().set_location(reserveVdsExtent.location()+partition.vds_number());
879			partition.tag().set_checksums(partition);
880			ssize_t bytes = _OutputFile().WriteAt(off_t(partition.tag().location()) << _BlockShift(),
881        			                              &partition, sizeof(partition));
882			error = check_size_error(bytes, sizeof(partition));
883			if (!error && bytes < ssize_t(_BlockSize())) {
884				ssize_t bytesLeft = _BlockSize() - bytes;
885				bytes = _OutputFile().ZeroAt((off_t(partition.tag().location()) << _BlockShift())
886				                             + bytes, bytesLeft);
887				error = check_size_error(bytes, bytesLeft);
888			}
889		}
890		// Error check
891		if (error) {
892			_PrintError("Error writing udf vds: 0x%lx, `%s'",
893			            error, strerror(error));
894		}
895	}
896
897	// Write the integrity sequence
898	if (!error && _DoUdf()) {
899		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing logical volume integrity sequence");
900		Udf::MemoryChunk chunk(_BlockSize());
901		error = chunk.InitCheck();
902		// write closed integrity descriptor
903		if (!error) {
904			memset(chunk.Data(), 0, _BlockSize());
905			Udf::logical_volume_integrity_descriptor *lvid =
906				reinterpret_cast<Udf::logical_volume_integrity_descriptor*>(chunk.Data());
907			lvid->recording_time() = Udf::timestamp(real_time_clock());
908				// recording time must be later than all file access times
909			lvid->set_integrity_type(Udf::INTEGRITY_CLOSED);
910			lvid->next_integrity_extent() = kNullExtent;
911			memset(lvid->logical_volume_contents_use().data, 0,
912			       lvid->logical_volume_contents_use().size());
913			lvid->set_next_unique_id(_NextUniqueId());
914			lvid->set_partition_count(1);
915			lvid->set_implementation_use_length(
916				Udf::logical_volume_integrity_descriptor::minimum_implementation_use_length);
917			lvid->free_space_table()[0] = 0;
918			lvid->size_table()[0] = _PartitionAllocator().Length();
919			lvid->implementation_id() = Udf::kImplementationId;
920			lvid->set_file_count(_Stats().Files());
921			lvid->set_directory_count(_Stats().Directories());
922			lvid->set_minimum_udf_read_revision(_UdfRevision());
923			lvid->set_minimum_udf_write_revision(_UdfRevision());
924			lvid->set_maximum_udf_write_revision(_UdfRevision());
925			lvid->tag().set_id(Udf::TAGID_LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR);
926			lvid->tag().set_version(_UdfDescriptorVersion());
927			lvid->tag().set_serial_number(0);
928			lvid->tag().set_location(integrityExtent.location());
929			lvid->tag().set_checksums(*lvid, lvid->descriptor_size());
930			PDUMP(lvid);
931			// write lvid
932			ssize_t bytes = _OutputFile().WriteAt(off_t(integrityExtent.location()) << _BlockShift(),
933	       			                              lvid, _BlockSize());
934			error = check_size_error(bytes, _BlockSize());
935		}
936		// write terminating descriptor
937		if (!error) {
938			memset(chunk.Data(), 0, _BlockSize());
939			Udf::terminating_descriptor *terminator	=
940				reinterpret_cast<Udf::terminating_descriptor*>(chunk.Data());
941			terminator->tag().set_id(Udf::TAGID_TERMINATING_DESCRIPTOR);
942			terminator->tag().set_version(_UdfDescriptorVersion());
943			terminator->tag().set_serial_number(0);
944			terminator->tag().set_location(integrityExtent.location()+1);
945			terminator->tag().set_checksums(*terminator);
946			PDUMP(terminator);
947			// write terminator
948			ssize_t bytes = _OutputFile().WriteAt(off_t((integrityExtent.location()+1)) << _BlockShift(),
949	       			                              terminator, _BlockSize());
950			error = check_size_error(bytes, _BlockSize());
951		}
952	}
953
954	// reserve and write anchorN
955	if (!error) {
956		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing anchorN");
957		_PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for anchorN");
958		uint32 blockN = _Allocator().Tail();
959		error = _Allocator().GetBlock(blockN);
960		if (!error)
961			_PrintUpdate(VERBOSITY_HIGH, "udf: (location: %ld, length: %ld)",
962			             blockN, _BlockSize());
963		if (!error) {
964			anchorN.main_vds() = primaryVdsExtent;
965			anchorN.reserve_vds() = reserveVdsExtent;
966			Udf::descriptor_tag &tag = anchorN.tag();
967			tag.set_id(Udf::TAGID_ANCHOR_VOLUME_DESCRIPTOR_POINTER);
968			tag.set_version(_UdfDescriptorVersion());
969			tag.set_serial_number(0);
970			tag.set_location(blockN);
971			tag.set_checksums(anchorN);
972			_OutputFile().Seek(off_t(blockN) << _BlockShift(), SEEK_SET);
973			ssize_t bytes = _OutputFile().Write(&anchorN, sizeof(anchorN));
974			error = check_size_error(bytes, sizeof(anchorN));
975			if (!error && bytes < ssize_t(_BlockSize())) {
976				bytes = _OutputFile().Zero(_BlockSize()-sizeof(anchorN));
977				error = check_size_error(bytes, _BlockSize()-sizeof(anchorN));
978			}
979		}
980	}
981
982	// NOTE: After this point, no more blocks may be allocated without jacking
983	// up anchorN's position as the last block in the volume. So don't allocate
984	// any, damn it.
985
986	// Pad the end of the file to an even multiple of the block
987	// size, if necessary
988	if (!error) {
989		_OutputFile().Seek(0, SEEK_END);
990		uint32 tail = _OutputFile().Position() % _BlockSize();
991		if (tail > 0) {
992			uint32 padding = _BlockSize() - tail;
993			ssize_t bytes = _OutputFile().Zero(padding);
994			error = check_size_error(bytes, padding);
995		}
996		if (!error)
997			_Stats().SetImageSize(_OutputFile().Position());
998	}
999
1000	if (!error) {
1001		_PrintUpdate(VERBOSITY_LOW, "Flushing image data");
1002		_OutputFile().Flush();
1003	}
1004
1005	fListener.OnCompletion(error, _Stats());
1006	RETURN(error);
1007}
1008
1009/*! \brief Returns the next unique id, then increments the id (the lower
1010	32-bits of which wrap to 16 instead of 0, per UDF-2.50 3.2.1.1).
1011*/
1012uint64
1013UdfBuilder::_NextUniqueId()
1014{
1015	uint64 result = fNextUniqueId++;
1016	if ((fNextUniqueId & 0xffffffff) == 0) {
1017		fNextUniqueId |= 0x10;
1018		f32BitIdsNoLongerUnique = true;
1019	}
1020	return result;
1021}
1022
1023/*! \brief Sets the time at which image building began.
1024*/
1025void
1026UdfBuilder::_SetBuildTime(time_t time)
1027{
1028	fBuildTime = time;
1029	Udf::timestamp stamp(time);
1030	fBuildTimeStamp = stamp;
1031}
1032
1033/*! \brief Uses vsprintf() to output the given format string and arguments
1034	into the given message string.
1035
1036	va_start() must be called prior to calling this function to obtain the
1037	\a arguments parameter, but va_end() must *not* be called upon return,
1038	as this function takes the liberty of doing so for you.
1039*/
1040status_t
1041UdfBuilder::_FormatString(char *message, const char *formatString, va_list arguments) const
1042{
1043	status_t error = message && formatString ? B_OK : B_BAD_VALUE;
1044	if (!error) {
1045		vsprintf(message, formatString, arguments);
1046		va_end(arguments);
1047	}
1048	return error;
1049}
1050
1051/*! \brief Outputs a printf()-style error message to the listener.
1052*/
1053void
1054UdfBuilder::_PrintError(const char *formatString, ...) const
1055{
1056	if (!formatString) {
1057		DEBUG_INIT_ETC("UdfBuilder", ("formatString: `%s'", formatString));
1058		PRINT(("ERROR: _PrintError() called with NULL format string!\n"));
1059		return;
1060	}
1061	char message[kMaxUpdateStringLength];
1062	va_list arguments;
1063	va_start(arguments, formatString);
1064	status_t error = _FormatString(message, formatString, arguments);
1065	if (!error)
1066		fListener.OnError(message);
1067}
1068
1069/*! \brief Outputs a printf()-style warning message to the listener.
1070*/
1071void
1072UdfBuilder::_PrintWarning(const char *formatString, ...) const
1073{
1074	if (!formatString) {
1075		DEBUG_INIT_ETC("UdfBuilder", ("formatString: `%s'", formatString));
1076		PRINT(("ERROR: _PrintWarning() called with NULL format string!\n"));
1077		return;
1078	}
1079	char message[kMaxUpdateStringLength];
1080	va_list arguments;
1081	va_start(arguments, formatString);
1082	status_t error = _FormatString(message, formatString, arguments);
1083	if (!error)
1084		fListener.OnWarning(message);
1085}
1086
1087/*! \brief Outputs a printf()-style update message to the listener
1088	at the given verbosity level.
1089*/
1090void
1091UdfBuilder::_PrintUpdate(VerbosityLevel level, const char *formatString, ...) const
1092{
1093	if (!formatString) {
1094		DEBUG_INIT_ETC("UdfBuilder", ("level: %d, formatString: `%s'",
1095		               level, formatString));
1096		PRINT(("ERROR: _PrintUpdate() called with NULL format string!\n"));
1097		return;
1098	}
1099	char message[kMaxUpdateStringLength];
1100	va_list arguments;
1101	va_start(arguments, formatString);
1102	status_t error = _FormatString(message, formatString, arguments);
1103	if (!error)
1104		fListener.OnUpdate(level, message);
1105}
1106
1107/*! \brief Processes the given directory and its children.
1108
1109	\param entry The directory to process.
1110	\param path Pathname of the directory with respect to the fileset
1111	            in construction.
1112	\param node Output parameter into which the icb address and dataspace
1113	            information for the processed directory is placed.
1114	\param isRootDirectory Used to signal that the directory being processed
1115	                       is the root directory, since said directory has
1116	                       a special unique id assigned to it.
1117*/
1118status_t
1119UdfBuilder::_ProcessDirectory(BEntry &entry, const char *path, struct stat stats,
1120                              node_data &node, Udf::long_address parentIcbAddress,
1121                              bool isRootDirectory)
1122{
1123	DEBUG_INIT_ETC("UdfBuilder", ("path: `%s'", path));
1124	uint32 udfDataLength = 0;
1125	uint64 udfUniqueId = isRootDirectory ? 0 : _NextUniqueId();
1126		// file entry id must be numerically lower than unique id's
1127		// in all fids that reference it, thus we allocate it now.
1128	status_t error = entry.InitCheck() == B_OK && path ? B_OK : B_BAD_VALUE;
1129	if (!error) {
1130		_PrintUpdate(VERBOSITY_LOW, "Adding `%s'", path);
1131		BDirectory directory(&entry);
1132		error = directory.InitCheck();
1133		if (!error) {
1134
1135			// Max length of a udf file identifier Cs0 string
1136			const uint32 maxUdfIdLength = _BlockSize() - (38);
1137
1138			_PrintUpdate(VERBOSITY_MEDIUM, "Gathering statistics");
1139
1140			// Figure out how many file identifier characters we have
1141			// for each filesystem
1142			uint32 entries = 0;
1143			//uint32 isoChars = 0;
1144			while (error == B_OK) {
1145				BEntry childEntry;
1146				error = directory.GetNextEntry(&childEntry);
1147				if (error == B_ENTRY_NOT_FOUND) {
1148					error = B_OK;
1149					break;
1150				}
1151				if (!error)
1152					error = childEntry.InitCheck();
1153				if (!error) {
1154					BPath childPath;
1155					error = childEntry.GetPath(&childPath);
1156					if (!error)
1157						error = childPath.InitCheck();
1158					// Skip symlinks until we add symlink support; this
1159					// allows graceful skipping of them later on instead
1160					// of stopping with a fatal error
1161					struct stat childStats;
1162					if (!error)
1163						error = childEntry.GetStat(&childStats);
1164					if (!error && S_ISLNK(childStats.st_mode))
1165						continue;
1166					if (!error) {
1167						_PrintUpdate(VERBOSITY_MEDIUM, "found child: `%s'", childPath.Leaf());
1168						entries++;
1169						// Determine udf char count
1170						Udf::String name(childPath.Leaf());
1171						uint32 udfLength = name.Cs0Length();
1172						udfLength = maxUdfIdLength >= udfLength
1173						            ? udfLength : maxUdfIdLength;
1174						Udf::file_id_descriptor id;
1175						id.set_id_length(udfLength);
1176						id.set_implementation_use_length(0);
1177						udfDataLength += id.total_length();
1178						// Determine iso char count
1179						// isoChars += ???
1180					}
1181				}
1182			}
1183
1184//			entries = 0;
1185//			udfChars = 0;
1186
1187			// Include parent directory entry in data length calculation
1188			if (!error) {
1189				Udf::file_id_descriptor id;
1190				id.set_id_length(0);
1191				id.set_implementation_use_length(0);
1192				udfDataLength += id.total_length();
1193			}
1194
1195			_PrintUpdate(VERBOSITY_MEDIUM, "children: %ld", entries);
1196			_PrintUpdate(VERBOSITY_MEDIUM, "udf: data length: %ld", udfDataLength);
1197
1198			// Reserve iso dir entry space
1199
1200			// Reserve udf icb space
1201			Udf::long_address icbAddress;
1202			Udf::extent_address icbExtent;
1203			if (!error && _DoUdf()) {
1204				_PrintUpdate(VERBOSITY_MEDIUM, "udf: Reserving space for icb");
1205				error = _PartitionAllocator().GetNextExtent(_BlockSize(), true, icbAddress,
1206				                                            icbExtent);
1207				if (!error) {
1208					_PrintUpdate(VERBOSITY_HIGH, "udf: (partition: %d, location: %ld, "
1209					             "length: %ld) => (location: %ld, length: %ld)",
1210					             icbAddress.partition(), icbAddress.block(),
1211					             icbAddress.length(), icbExtent.location(),
1212					             icbExtent.length());
1213					node.icbAddress = icbAddress;
1214				}
1215			}
1216
1217			DataStream *udfData = NULL;
1218			std::list<Udf::extent_address> udfDataExtents;
1219			std::list<Udf::long_address> &udfDataAddresses = node.udfData;
1220
1221			// Reserve udf dir data space
1222			if (!error && _DoUdf()) {
1223				_PrintUpdate(VERBOSITY_MEDIUM, "udf: Reserving space for directory data");
1224				error = _PartitionAllocator().GetNextExtents(udfDataLength, udfDataAddresses,
1225				                                            udfDataExtents);
1226				if (!error) {
1227					int extents = udfDataAddresses.size();
1228					if (extents > 1)
1229						_PrintUpdate(VERBOSITY_HIGH, "udf: Reserved %d extents",
1230						             extents);
1231					std::list<Udf::long_address>::iterator a;
1232					std::list<Udf::extent_address>::iterator e;
1233					for (a = udfDataAddresses.begin(), e = udfDataExtents.begin();
1234					       a != udfDataAddresses.end() && e != udfDataExtents.end();
1235					         a++, e++)
1236					{
1237						_PrintUpdate(VERBOSITY_HIGH, "udf: (partition: %d, location: %ld, "
1238						             "length: %ld) => (location: %ld, length: %ld)",
1239						             a->partition(), a->block(), a->length(), e->location(),
1240						             e->length());
1241					}
1242				}
1243				if (!error) {
1244					udfData = new(nothrow) ExtentStream(_OutputFile(), udfDataExtents, _BlockSize());
1245					error = udfData ? B_OK : B_NO_MEMORY;
1246				}
1247			}
1248
1249			uint32 udfAllocationDescriptorsLength = udfDataAddresses.size()
1250			                                        * sizeof(Udf::long_address);
1251
1252			// Process attributes
1253			uint16 attributeCount = 0;
1254
1255			// Write iso parent directory
1256
1257			// Write udf parent directory fid
1258			if (!error && _DoUdf()) {
1259				Udf::MemoryChunk chunk((38) + 4);
1260				error = chunk.InitCheck();
1261				if (!error) {
1262					memset(chunk.Data(), 0, (38) + 4);
1263					Udf::file_id_descriptor *parent =
1264						reinterpret_cast<Udf::file_id_descriptor*>(chunk.Data());
1265					parent->set_version_number(1);
1266					// Clear characteristics to false, then set
1267					// those that need to be true
1268					parent->set_characteristics(0);
1269					parent->set_is_directory(true);
1270					parent->set_is_parent(true);
1271					parent->set_id_length(0);
1272					parent->icb() = isRootDirectory ? icbAddress : parentIcbAddress;
1273					if (!isRootDirectory)
1274						parent->icb().set_unique_id(uint32(_NextUniqueId()));
1275					parent->set_implementation_use_length(0);
1276					parent->tag().set_id(Udf::TAGID_FILE_ID_DESCRIPTOR);
1277					parent->tag().set_version(_UdfDescriptorVersion());
1278					parent->tag().set_serial_number(0);
1279					uint32 block;
1280					error = block_for_offset(udfData->Position(), udfDataAddresses,
1281					                              _BlockSize(), block);
1282					if (!error) {
1283						parent->tag().set_location(block);
1284						parent->tag().set_checksums(*parent, parent->descriptor_size());
1285						ssize_t bytes = udfData->Write(parent, parent->total_length());
1286						error = check_size_error(bytes, parent->total_length());
1287					}
1288				}
1289			}
1290
1291			// Process children
1292			uint16 childDirCount = 0;
1293			if (!error)
1294				error = directory.Rewind();
1295			while (error == B_OK) {
1296				BEntry childEntry;
1297				error = directory.GetNextEntry(&childEntry);
1298				if (error == B_ENTRY_NOT_FOUND) {
1299					error = B_OK;
1300					break;
1301				}
1302				if (!error)
1303					error = childEntry.InitCheck();
1304				if (!error) {
1305					BPath childPath;
1306					error = childEntry.GetPath(&childPath);
1307					if (!error)
1308						error = childPath.InitCheck();
1309					struct stat childStats;
1310					if (!error)
1311						error = childEntry.GetStat(&childStats);
1312					if (!error) {
1313						node_data childNode;
1314						std::string childImagePath(path);
1315						childImagePath += (childImagePath[childImagePath.length()-1] == '/'
1316						                  ? "" : "/");
1317						childImagePath += childPath.Leaf();
1318						// Process child
1319						if (S_ISREG(childStats.st_mode)) {
1320							// Regular file
1321							error = _ProcessFile(childEntry, childImagePath.c_str(),
1322							                          childStats, childNode);
1323						} else if (S_ISDIR(childStats.st_mode)) {
1324							// Directory
1325							error = _ProcessDirectory(childEntry, childImagePath.c_str(),
1326							                          childStats, childNode, icbAddress);
1327							if (!error)
1328								childDirCount++;
1329						} else if (S_ISLNK(childStats.st_mode)) {
1330							// Symlink
1331							// For now, skip it
1332							_Stats().AddSymlink();
1333							_PrintWarning("No symlink support yet; skipping symlink: `%s'",
1334							              childImagePath.c_str());
1335							continue;
1336						}
1337
1338						// Write iso direntry
1339
1340						// Write udf fid
1341						if (!error) {
1342							Udf::String udfName(childPath.Leaf());
1343							uint32 udfNameLength = udfName.Cs0Length();
1344							uint32 idLength = (38)
1345							                  + udfNameLength;
1346							Udf::MemoryChunk chunk(idLength + 4);
1347							error = chunk.InitCheck();
1348							if (!error) {
1349								memset(chunk.Data(), 0, idLength + 4);
1350								Udf::file_id_descriptor *id =
1351									reinterpret_cast<Udf::file_id_descriptor*>(chunk.Data());
1352								id->set_version_number(1);
1353								// Clear characteristics to false, then set
1354								// those that need to be true
1355								id->set_characteristics(0);
1356								id->set_is_directory(S_ISDIR(childStats.st_mode));
1357								id->set_is_parent(false);
1358								id->set_id_length(udfNameLength);
1359								id->icb() = childNode.icbAddress;
1360								id->icb().set_unique_id(uint32(_NextUniqueId()));
1361								id->set_implementation_use_length(0);
1362								memcpy(id->id(), udfName.Cs0(), udfNameLength);
1363								id->tag().set_id(Udf::TAGID_FILE_ID_DESCRIPTOR);
1364								id->tag().set_version(_UdfDescriptorVersion());
1365								id->tag().set_serial_number(0);
1366								uint32 block;
1367								error = block_for_offset(udfData->Position(), udfDataAddresses,
1368								                              _BlockSize(), block);
1369								if (!error) {
1370									id->tag().set_location(block);
1371									id->tag().set_checksums(*id, id->descriptor_size());
1372									PDUMP(id);
1373									PRINT(("pos: %Ld\n", udfData->Position()));
1374									ssize_t bytes = udfData->Write(id, id->total_length());
1375									PRINT(("pos: %Ld\n", udfData->Position()));
1376									error = check_size_error(bytes, id->total_length());
1377								}
1378							}
1379						}
1380					}
1381				}
1382			}
1383
1384			// Build and write udf icb
1385			Udf::MemoryChunk chunk(_BlockSize());
1386			if (!error)
1387				error = chunk.InitCheck();
1388			if (!error) {
1389				memset(chunk.Data(), 0, _BlockSize());
1390				uint8 fileType = Udf::ICB_TYPE_DIRECTORY;
1391				uint16 linkCount = 1 + attributeCount + childDirCount;
1392				if (_UdfRevision() <= 0x0150) {
1393					error = _WriteFileEntry(
1394						reinterpret_cast<Udf::file_icb_entry*>(chunk.Data()),
1395						fileType, linkCount, udfDataLength, udfDataLength,
1396						stats, udfUniqueId, udfAllocationDescriptorsLength,
1397						Udf::TAGID_FILE_ENTRY,
1398						icbAddress, icbExtent, udfDataAddresses
1399					);
1400				} else {
1401					error = _WriteFileEntry(
1402						reinterpret_cast<Udf::extended_file_icb_entry*>(chunk.Data()),
1403						fileType, linkCount, udfDataLength, udfDataLength,
1404						stats, udfUniqueId, udfAllocationDescriptorsLength,
1405						Udf::TAGID_EXTENDED_FILE_ENTRY,
1406						icbAddress, icbExtent, udfDataAddresses
1407					);
1408				}
1409			}
1410
1411			delete udfData;
1412			udfData = NULL;
1413		}
1414	}
1415
1416	if (!error) {
1417		_Stats().AddDirectory();
1418		uint32 totalLength = udfDataLength + _BlockSize();
1419		_Stats().AddDirectoryBytes(totalLength);
1420	}
1421	RETURN(error);
1422}
1423
1424status_t
1425UdfBuilder::_ProcessFile(BEntry &entry, const char *path, struct stat stats,
1426                         node_data &node)
1427{
1428	DEBUG_INIT_ETC("UdfBuilder", ("path: `%s'", path));
1429	status_t error = entry.InitCheck() == B_OK && path ? B_OK : B_BAD_VALUE;
1430	off_t udfDataLength = stats.st_size;
1431	if (udfDataLength > ULONG_MAX && _DoIso()) {
1432		_PrintError("File `%s' too large for iso9660 filesystem (filesize: %Lu bytes, max: %lu bytes)",
1433		            path, udfDataLength, ULONG_MAX);
1434		error = B_ERROR;
1435	}
1436	if (!error) {
1437		_PrintUpdate(VERBOSITY_LOW, "Adding `%s' (%s)", path,
1438		             bytes_to_string(stats.st_size).c_str());
1439		BFile file(&entry, B_READ_ONLY);
1440		error = file.InitCheck();
1441		if (!error) {
1442			// Reserve udf icb space
1443			Udf::long_address icbAddress;
1444			Udf::extent_address icbExtent;
1445			if (!error && _DoUdf()) {
1446				_PrintUpdate(VERBOSITY_MEDIUM, "udf: Reserving space for icb");
1447				error = _PartitionAllocator().GetNextExtent(_BlockSize(), true, icbAddress,
1448				                                            icbExtent);
1449				if (!error) {
1450					_PrintUpdate(VERBOSITY_HIGH, "udf: (partition: %d, location: %ld, "
1451					             "length: %ld) => (location: %ld, length: %ld)",
1452					             icbAddress.partition(), icbAddress.block(),
1453					             icbAddress.length(), icbExtent.location(),
1454					             icbExtent.length());
1455					node.icbAddress = icbAddress;
1456				}
1457			}
1458
1459			DataStream *udfData = NULL;
1460			std::list<Udf::extent_address> udfDataExtents;
1461			std::list<Udf::long_address> &udfDataAddresses = node.udfData;
1462
1463			// Reserve iso/udf data space
1464			if (!error) {
1465				_PrintUpdate(VERBOSITY_MEDIUM, "Reserving space for file data");
1466				if (_DoIso()) {
1467					// Reserve a contiguous extent, as iso requires
1468					Udf::long_address address;
1469					Udf::extent_address extent;
1470					error = _PartitionAllocator().GetNextExtent(udfDataLength, true, address, extent);
1471					if (!error) {
1472						udfDataAddresses.empty();	// just in case
1473						udfDataAddresses.push_back(address);
1474						udfDataExtents.push_back(extent);
1475					}
1476				} else {
1477					// Udf can handle multiple extents if necessary
1478					error = _PartitionAllocator().GetNextExtents(udfDataLength, udfDataAddresses,
1479				                                                 udfDataExtents);
1480				}
1481				if (!error) {
1482					int extents = udfDataAddresses.size();
1483					if (extents > 1)
1484						_PrintUpdate(VERBOSITY_HIGH, "udf: Reserved %d extents",
1485						             extents);
1486					std::list<Udf::long_address>::iterator a;
1487					std::list<Udf::extent_address>::iterator e;
1488					for (a = udfDataAddresses.begin(), e = udfDataExtents.begin();
1489					       a != udfDataAddresses.end() && e != udfDataExtents.end();
1490					         a++, e++)
1491					{
1492						_PrintUpdate(VERBOSITY_HIGH, "udf: (partition: %d, location: %ld, "
1493						             "length: %ld) => (location: %ld, length: %ld)",
1494						             a->partition(), a->block(), a->length(), e->location(),
1495						             e->length());
1496					}
1497				}
1498				if (!error) {
1499					udfData = new(nothrow) ExtentStream(_OutputFile(), udfDataExtents, _BlockSize());
1500					error = udfData ? B_OK : B_NO_MEMORY;
1501				}
1502			}
1503
1504			uint32 udfAllocationDescriptorsLength = udfDataAddresses.size()
1505			                                        * sizeof(Udf::long_address);
1506
1507			// Process attributes
1508			uint16 attributeCount = 0;
1509
1510			// Write file data
1511			if (!error) {
1512				_PrintUpdate(VERBOSITY_MEDIUM, "Writing file data");
1513				ssize_t bytes = udfData->Write(file, udfDataLength);
1514				error = check_size_error(bytes, udfDataLength);
1515			}
1516
1517			// Build and write udf icb
1518			Udf::MemoryChunk chunk(_BlockSize());
1519			if (!error)
1520				error = chunk.InitCheck();
1521			if (!error) {
1522				memset(chunk.Data(), 0, _BlockSize());
1523				uint8 fileType = Udf::ICB_TYPE_REGULAR_FILE;
1524				uint16 linkCount = 1 + attributeCount;
1525				uint64 uniqueId = _NextUniqueId();
1526				if (_UdfRevision() <= 0x0150) {
1527					error = _WriteFileEntry(
1528						reinterpret_cast<Udf::file_icb_entry*>(chunk.Data()),
1529						fileType, linkCount, udfDataLength, udfDataLength,
1530						stats, uniqueId, udfAllocationDescriptorsLength,
1531						Udf::TAGID_FILE_ENTRY,
1532						icbAddress, icbExtent, udfDataAddresses
1533					);
1534				} else {
1535					error = _WriteFileEntry(
1536						reinterpret_cast<Udf::extended_file_icb_entry*>(chunk.Data()),
1537						fileType, linkCount, udfDataLength, udfDataLength,
1538						stats, uniqueId, udfAllocationDescriptorsLength,
1539						Udf::TAGID_EXTENDED_FILE_ENTRY,
1540						icbAddress, icbExtent, udfDataAddresses
1541					);
1542				}
1543			}
1544
1545			delete udfData;
1546			udfData = NULL;
1547		}
1548	}
1549
1550	if (!error) {
1551		_Stats().AddFile();
1552		off_t totalLength = udfDataLength + _BlockSize();
1553		_Stats().AddFileBytes(totalLength);
1554	}
1555	RETURN(error);
1556}
1557
1558