Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / bin / makeudfimage / UdfBuilder.cpp
blobe4cf7e5de15aa57e0dbe20893ca3162a9d0f3c9f
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 //----------------------------------------------------------------------
8 /*! \file UdfBuilder.cpp
10 Main UDF image building class implementation.
13 #include "UdfBuilder.h"
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>
24 #include "DString.h"
25 #include "ExtentStream.h"
26 #include "MemoryChunk.h"
27 #include "UdfDebug.h"
28 #include "Utils.h"
30 using Udf::bool_to_string;
31 using Udf::check_size_error;
33 //! Application identifier entity_id
34 static const Udf::entity_id kApplicationId(0, "*OpenBeOS makeudfimage");
36 static const Udf::logical_block_address kNullLogicalBlock(0, 0);
37 static const Udf::extent_address kNullExtent(0, 0);
38 static const Udf::long_address kNullAddress(0, 0, 0, 0);
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.
43 Used to figure out the value for Udf::file_id_descriptor::tag::location fields.
45 \param block Output parameter into which the block number of interest is stored.
47 static
48 status_t
49 block_for_offset(off_t pos, std::list<Udf::long_address> &dataSpace, uint32 blockSize,
50 uint32 &block)
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++)
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();
68 // Didn't find it, so pos is past the end of the data space
69 error = B_ERROR;
71 return error;
74 /*! \brief Creates a new UdfBuilder object.
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.
79 UdfBuilder::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
106 DEBUG_INIT_ETC("UdfBuilder", ("blockSize: %ld, doUdf: %s, doIso: %s",
107 blockSize, bool_to_string(doUdf), bool_to_string(doIso)));
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));
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));
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);
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.");
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());
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());
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());
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));
179 if (!error) {
180 fInitStatus = B_OK;
184 status_t
185 UdfBuilder::InitCheck() const
187 return fInitStatus;
190 /*! \brief Builds the disc image.
192 status_t
193 UdfBuilder::Build()
195 DEBUG_INIT("UdfBuilder");
196 status_t error = InitCheck();
197 if (error)
198 RETURN(error);
200 // Note the time at which we're starting
201 fStatistics.Reset();
202 _SetBuildTime(_Stats().StartTime());
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;
221 // Iso variables
222 // Udf::extent_address rootDirentExtent;
225 _OutputFile().Seek(0, SEEK_SET);
226 fListener.OnStart(fRootDirectoryName.c_str(), fOutputFilename.c_str(),
227 _UdfVolumeName().Utf8(), _UdfRevision());
229 _PrintUpdate(VERBOSITY_LOW, "Initializing volume");
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);
244 // Error check
245 if (error) {
246 _PrintError("Error creating reserved area: 0x%lx, `%s'",
247 error, strerror(error));
251 const int vrsBlockSize = 2048;
253 // Write the iso portion of the vrs
254 if (!error && _DoIso()) {
255 _PrintUpdate(VERBOSITY_MEDIUM, "iso: Writing primary volume descriptor");
257 // Error check
258 if (error) {
259 _PrintError("Error writing iso vrs: 0x%lx, `%s'",
260 error, strerror(error));
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));
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,
288 if (!error) {
289 _PrintUpdate(VERBOSITY_HIGH, "udf: Reserving space for nsr descriptor");
290 _Allocator().GetNextExtent(vrsBlockSize, true, extent);
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));
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);
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));
319 // Error check
320 if (error) {
321 _PrintError("Error writing udf vrs: 0x%lx, `%s'",
322 error, strerror(error));
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());
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());
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));
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);
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);
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);
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);
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);
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);
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);
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());
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);
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);
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);
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;
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));
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);
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);
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);
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);
774 // Error check
775 if (error) {
776 _PrintError("Error writing udf vds: 0x%lx, `%s'",
777 error, strerror(error));
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);
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);
838 if (!error)
839 _PrintUpdate(VERBOSITY_LOW, "Finalizing volume");
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);
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);
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);
890 // Error check
891 if (error) {
892 _PrintError("Error writing udf vds: 0x%lx, `%s'",
893 error, strerror(error));
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());
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());
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));
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.
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);
996 if (!error)
997 _Stats().SetImageSize(_OutputFile().Position());
1000 if (!error) {
1001 _PrintUpdate(VERBOSITY_LOW, "Flushing image data");
1002 _OutputFile().Flush();
1005 fListener.OnCompletion(error, _Stats());
1006 RETURN(error);
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).
1012 uint64
1013 UdfBuilder::_NextUniqueId()
1015 uint64 result = fNextUniqueId++;
1016 if ((fNextUniqueId & 0xffffffff) == 0) {
1017 fNextUniqueId |= 0x10;
1018 f32BitIdsNoLongerUnique = true;
1020 return result;
1023 /*! \brief Sets the time at which image building began.
1025 void
1026 UdfBuilder::_SetBuildTime(time_t time)
1028 fBuildTime = time;
1029 Udf::timestamp stamp(time);
1030 fBuildTimeStamp = stamp;
1033 /*! \brief Uses vsprintf() to output the given format string and arguments
1034 into the given message string.
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.
1040 status_t
1041 UdfBuilder::_FormatString(char *message, const char *formatString, va_list arguments) const
1043 status_t error = message && formatString ? B_OK : B_BAD_VALUE;
1044 if (!error) {
1045 vsprintf(message, formatString, arguments);
1046 va_end(arguments);
1048 return error;
1051 /*! \brief Outputs a printf()-style error message to the listener.
1053 void
1054 UdfBuilder::_PrintError(const char *formatString, ...) const
1056 if (!formatString) {
1057 DEBUG_INIT_ETC("UdfBuilder", ("formatString: `%s'", formatString));
1058 PRINT(("ERROR: _PrintError() called with NULL format string!\n"));
1059 return;
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);
1069 /*! \brief Outputs a printf()-style warning message to the listener.
1071 void
1072 UdfBuilder::_PrintWarning(const char *formatString, ...) const
1074 if (!formatString) {
1075 DEBUG_INIT_ETC("UdfBuilder", ("formatString: `%s'", formatString));
1076 PRINT(("ERROR: _PrintWarning() called with NULL format string!\n"));
1077 return;
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);
1087 /*! \brief Outputs a printf()-style update message to the listener
1088 at the given verbosity level.
1090 void
1091 UdfBuilder::_PrintUpdate(VerbosityLevel level, const char *formatString, ...) const
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;
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);
1107 /*! \brief Processes the given directory and its children.
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.
1118 status_t
1119 UdfBuilder::_ProcessDirectory(BEntry &entry, const char *path, struct stat stats,
1120 node_data &node, Udf::long_address parentIcbAddress,
1121 bool isRootDirectory)
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) {
1135 // Max length of a udf file identifier Cs0 string
1136 const uint32 maxUdfIdLength = _BlockSize() - (38);
1138 _PrintUpdate(VERBOSITY_MEDIUM, "Gathering statistics");
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;
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 += ???
1184 // entries = 0;
1185 // udfChars = 0;
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();
1195 _PrintUpdate(VERBOSITY_MEDIUM, "children: %ld", entries);
1196 _PrintUpdate(VERBOSITY_MEDIUM, "udf: data length: %ld", udfDataLength);
1198 // Reserve iso dir entry space
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;
1217 DataStream *udfData = NULL;
1218 std::list<Udf::extent_address> udfDataExtents;
1219 std::list<Udf::long_address> &udfDataAddresses = node.udfData;
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++)
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());
1243 if (!error) {
1244 udfData = new(nothrow) ExtentStream(_OutputFile(), udfDataExtents, _BlockSize());
1245 error = udfData ? B_OK : B_NO_MEMORY;
1249 uint32 udfAllocationDescriptorsLength = udfDataAddresses.size()
1250 * sizeof(Udf::long_address);
1252 // Process attributes
1253 uint16 attributeCount = 0;
1255 // Write iso parent directory
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());
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;
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;
1338 // Write iso direntry
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());
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
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
1411 delete udfData;
1412 udfData = NULL;
1416 if (!error) {
1417 _Stats().AddDirectory();
1418 uint32 totalLength = udfDataLength + _BlockSize();
1419 _Stats().AddDirectoryBytes(totalLength);
1421 RETURN(error);
1424 status_t
1425 UdfBuilder::_ProcessFile(BEntry &entry, const char *path, struct stat stats,
1426 node_data &node)
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;
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;
1459 DataStream *udfData = NULL;
1460 std::list<Udf::extent_address> udfDataExtents;
1461 std::list<Udf::long_address> &udfDataAddresses = node.udfData;
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);
1476 } else {
1477 // Udf can handle multiple extents if necessary
1478 error = _PartitionAllocator().GetNextExtents(udfDataLength, udfDataAddresses,
1479 udfDataExtents);
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++)
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());
1498 if (!error) {
1499 udfData = new(nothrow) ExtentStream(_OutputFile(), udfDataExtents, _BlockSize());
1500 error = udfData ? B_OK : B_NO_MEMORY;
1504 uint32 udfAllocationDescriptorsLength = udfDataAddresses.size()
1505 * sizeof(Udf::long_address);
1507 // Process attributes
1508 uint16 attributeCount = 0;
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);
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
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
1545 delete udfData;
1546 udfData = NULL;
1550 if (!error) {
1551 _Stats().AddFile();
1552 off_t totalLength = udfDataLength + _BlockSize();
1553 _Stats().AddFileBytes(totalLength);
1555 RETURN(error);