1 //----------------------------------------------------------------------
2 // This software is part of the OpenBeOS distribution and is covered
3 // by the OpenBeOS license.
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>
25 #include "ExtentStream.h"
26 #include "MemoryChunk.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.
49 block_for_offset(off_t pos
, std::list
<Udf::long_address
> &dataSpace
, uint32 blockSize
,
52 status_t error
= pos
>= 0 ? B_OK
: B_BAD_VALUE
;
55 for (std::list
<Udf::long_address
>::const_iterator i
= dataSpace
.begin();
59 if (streamPos
<= pos
&& pos
< streamPos
+i
->length()) {
61 off_t difference
= pos
- streamPos
;
62 block
= i
->block() + difference
/ blockSize
;
65 streamPos
+= i
->length();
68 // Didn't find it, so pos is past the end of the data space
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
)
89 , fUdfVolumeName(udfVolumeName
)
90 , fUdfRevision(udfRevision
)
91 , fUdfDescriptorVersion(udfRevision
<= 0x0150 ? 2 : 3)
92 , fUdfDomainId(udfRevision
== 0x0150 ? Udf::kDomainId150
: Udf::kDomainId201
)
94 , fIsoVolumeName(isoVolumeName
)
95 , fRootDirectory(rootDirectory
? rootDirectory
: "")
96 , fRootDirectoryName(rootDirectory
)
98 , fAllocator(blockSize
)
99 , fPartitionAllocator(0, 257, fAllocator
)
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();
112 _PrintError("Error opening output file: 0x%lx, `%s'", error
,
115 // Check the allocator
117 error
= _Allocator().InitCheck();
119 _PrintError("Error creating block allocator: 0x%lx, `%s'", error
,
123 // Check the block size
125 error
= Udf::get_block_shift(_BlockSize(), fBlockShift
);
127 error
= _BlockSize() >= 512 ? B_OK
: B_BAD_VALUE
;
129 _PrintError("Invalid block size: %ld", blockSize
);
131 // Check that at least one type of filesystem has
134 error
= _DoUdf() || _DoIso() ? B_OK
: B_BAD_VALUE
;
136 _PrintError("No filesystems requested.");
138 // Check the volume names
140 if (_UdfVolumeName().Utf8Length() == 0)
141 _UdfVolumeName().SetTo("(Unnamed UDF Volume)");
142 if (_IsoVolumeName().Utf8Length() == 0)
143 _IsoVolumeName().SetTo("UNNAMED_ISO");
145 error
= _UdfVolumeName().Cs0Length() <= 128 ? B_OK
: B_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
156 _PrintError("Iso volume name too long (%ld bytes, max "
157 "length is 32 bytes.",
158 _IsoVolumeName().Cs0Length());
162 // Check the udf revision
164 error
= _UdfRevision() == 0x0150 || _UdfRevision() == 0x0201
167 _PrintError("Invalid UDF revision 0x%04x", _UdfRevision());
170 // Check the root directory
172 error
= _RootDirectory().InitCheck();
174 _PrintError("Error initializing root directory entry: 0x%lx, `%s'",
175 error
, strerror(error
));
185 UdfBuilder::InitCheck() const
190 /*! \brief Builds the disc image.
195 DEBUG_INIT("UdfBuilder");
196 status_t error
= InitCheck();
200 // Note the time at which we're starting
202 _SetBuildTime(_Stats().StartTime());
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
;
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.
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
);
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
);
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");
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
;
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
);
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
));
278 bytes
= _OutputFile().Zero(vrsBlockSize
-sizeof(bea
));
279 error
= check_size_error(bytes
, vrsBlockSize
-sizeof(bea
));
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
,
289 _PrintUpdate(VERBOSITY_HIGH
, "udf: Reserving space for nsr descriptor");
290 _Allocator().GetNextExtent(vrsBlockSize
, true, extent
);
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
));
298 bytes
= _OutputFile().Zero(vrsBlockSize
-sizeof(nsr
));
299 error
= check_size_error(bytes
, vrsBlockSize
-sizeof(nsr
));
303 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Writing tea descriptor");
304 Udf::volume_structure_descriptor_header
tea(0, Udf::kVSDID_TEA
, 1);
306 _PrintUpdate(VERBOSITY_HIGH
, "udf: Reserving space for tea descriptor");
307 error
= _Allocator().GetNextExtent(vrsBlockSize
, true, extent
);
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
));
315 bytes
= _OutputFile().Zero(vrsBlockSize
-sizeof(tea
));
316 error
= check_size_error(bytes
, vrsBlockSize
-sizeof(tea
));
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");
330 _PrintUpdate(VERBOSITY_HIGH
, "udf: Reserving space for anchor256");
331 error
= _Allocator().GetBlock(256);
333 _PrintUpdate(VERBOSITY_HIGH
, "udf: (location: %ld, length: %ld)",
335 // reserve primary vds (min length = 16 blocks, which is plenty for us)
337 _PrintUpdate(VERBOSITY_HIGH
, "udf: Reserving space for primary vds");
338 error
= _Allocator().GetNextExtent(off_t(16) << _BlockShift(), true, primaryVdsExtent
);
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...
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
);
357 error
= _Allocator().GetNextExtent(off_t(16) << _BlockShift(), true, reserveVdsExtent
);
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());
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;
387 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Writing primary volume descriptor");
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.",
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
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.
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())
449 error
= check_size_error(bytes
, bytesLeft
);
451 // write primary_vd to reserve vds
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())
462 error
= check_size_error(bytes
, bytesLeft
);
467 // write partition descriptor
469 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Writing partition descriptor");
470 // build partition descriptor
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.
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())
509 error
= check_size_error(bytes
, bytesLeft
);
511 // write partition descriptor to reserve vds
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())
522 error
= check_size_error(bytes
, bytesLeft
);
527 // write unallocated space descriptor
529 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Writing unallocated space descriptor");
530 // build freespace descriptor
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.
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())
552 error
= check_size_error(bytes
, bytesLeft
);
554 // write freespace descriptor to reserve vds
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())
565 error
= check_size_error(bytes
, bytesLeft
);
572 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Writing logical volume descriptor");
575 logical
.set_vds_number(vdsNumber
);
576 logical
.character_set() = Udf::kCs0CharacterSet
;
577 error
= (_UdfVolumeName().Cs0Length() <=
578 logical
.logical_volume_identifier().size())
580 // We check the length in the constructor, so this should never
581 // trigger an error, but just to be safe...
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
);
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());
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,
615 logical
.integrity_sequence_extent() = integrityExtent
;
616 Udf::physical_partition_map map
;
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.
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())
641 error
= check_size_error(bytes
, bytesLeft
);
643 // write logical descriptor to reserve vds
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())
654 error
= check_size_error(bytes
, bytesLeft
);
660 // write implementation use descriptor
662 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Writing implementation use descriptor");
663 // build implementationUse descriptor
665 implementationUse
.set_vds_number(vdsNumber
);
666 switch (_UdfRevision()) {
668 implementationUse
.implementation_id() = Udf::kLogicalVolumeInfoId150
;
671 implementationUse
.implementation_id() = Udf::kLogicalVolumeInfoId201
;
674 _PrintError("Invalid udf revision: 0x04x", _UdfRevision());
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())
718 error
= check_size_error(bytes
, bytesLeft
);
720 // write implementationUse descriptor to reserve vds
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())
731 error
= check_size_error(bytes
, bytesLeft
);
736 // write terminating descriptor
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
);
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())
756 error
= check_size_error(bytes
, bytesLeft
);
758 // write terminator to reserve vds
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())
769 error
= check_size_error(bytes
, bytesLeft
);
776 _PrintError("Error writing udf vds: 0x%lx, `%s'",
777 error
, strerror(error
));
781 // Write the file set descriptor
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
);
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())
825 error
= check_size_error(bytes
, bytesLeft
);
829 // Build the rest of the image
831 struct stat rootStats
;
832 error
= _RootDirectory().GetStat(&rootStats
);
834 error
= _ProcessDirectory(_RootDirectory(), "/", rootStats
, rootNode
,
839 _PrintUpdate(VERBOSITY_LOW
, "Finalizing volume");
841 // Rewrite the fsd with the root dir icb
843 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Finalizing file set descriptor");
844 fileset
.root_directory_icb() = rootNode
.icbAddress
;
845 fileset
.tag().set_checksums(fileset
);
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())
855 error
= check_size_error(bytes
, bytesLeft
);
859 // Set the final partition length and rewrite the partition descriptor
861 _PrintUpdate(VERBOSITY_MEDIUM
, "udf: Finalizing partition descriptor");
862 partition
.set_length(_PartitionAllocator().Length());
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())
874 error
= check_size_error(bytes
, bytesLeft
);
876 // write partition descriptor to reserve vds
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())
887 error
= check_size_error(bytes
, bytesLeft
);
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
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());
932 ssize_t bytes
= _OutputFile().WriteAt(off_t(integrityExtent
.location()) << _BlockShift(),
934 error
= check_size_error(bytes
, _BlockSize());
936 // write terminating descriptor
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
);
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
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
);
961 _PrintUpdate(VERBOSITY_HIGH
, "udf: (location: %ld, length: %ld)",
962 blockN
, _BlockSize());
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
986 // Pad the end of the file to an even multiple of the block
987 // size, if necessary
989 _OutputFile().Seek(0, SEEK_END
);
990 uint32 tail
= _OutputFile().Position() % _BlockSize();
992 uint32 padding
= _BlockSize() - tail
;
993 ssize_t bytes
= _OutputFile().Zero(padding
);
994 error
= check_size_error(bytes
, padding
);
997 _Stats().SetImageSize(_OutputFile().Position());
1001 _PrintUpdate(VERBOSITY_LOW
, "Flushing image data");
1002 _OutputFile().Flush();
1005 fListener
.OnCompletion(error
, _Stats());
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).
1013 UdfBuilder::_NextUniqueId()
1015 uint64 result
= fNextUniqueId
++;
1016 if ((fNextUniqueId
& 0xffffffff) == 0) {
1017 fNextUniqueId
|= 0x10;
1018 f32BitIdsNoLongerUnique
= true;
1023 /*! \brief Sets the time at which image building began.
1026 UdfBuilder::_SetBuildTime(time_t 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.
1041 UdfBuilder::_FormatString(char *message
, const char *formatString
, va_list arguments
) const
1043 status_t error
= message
&& formatString
? B_OK
: B_BAD_VALUE
;
1045 vsprintf(message
, formatString
, arguments
);
1051 /*! \brief Outputs a printf()-style error message to the listener.
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"));
1061 char message
[kMaxUpdateStringLength
];
1063 va_start(arguments
, formatString
);
1064 status_t error
= _FormatString(message
, formatString
, arguments
);
1066 fListener
.OnError(message
);
1069 /*! \brief Outputs a printf()-style warning message to the listener.
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"));
1079 char message
[kMaxUpdateStringLength
];
1081 va_start(arguments
, formatString
);
1082 status_t error
= _FormatString(message
, formatString
, arguments
);
1084 fListener
.OnWarning(message
);
1087 /*! \brief Outputs a printf()-style update message to the listener
1088 at the given verbosity level.
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"));
1099 char message
[kMaxUpdateStringLength
];
1101 va_start(arguments
, formatString
);
1102 status_t error
= _FormatString(message
, formatString
, arguments
);
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
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.
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
;
1130 _PrintUpdate(VERBOSITY_LOW
, "Adding `%s'", path
);
1131 BDirectory
directory(&entry
);
1132 error
= directory
.InitCheck();
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
1143 //uint32 isoChars = 0;
1144 while (error
== B_OK
) {
1146 error
= directory
.GetNextEntry(&childEntry
);
1147 if (error
== B_ENTRY_NOT_FOUND
) {
1152 error
= childEntry
.InitCheck();
1155 error
= childEntry
.GetPath(&childPath
);
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
;
1163 error
= childEntry
.GetStat(&childStats
);
1164 if (!error
&& S_ISLNK(childStats
.st_mode
))
1167 _PrintUpdate(VERBOSITY_MEDIUM
, "found child: `%s'", childPath
.Leaf());
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
1187 // Include parent directory entry in data length calculation
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
,
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
,
1227 int extents
= udfDataAddresses
.size();
1229 _PrintUpdate(VERBOSITY_HIGH
, "udf: Reserved %d 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();
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(),
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();
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);
1280 error
= block_for_offset(udfData
->Position(), udfDataAddresses
,
1281 _BlockSize(), block
);
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());
1292 uint16 childDirCount
= 0;
1294 error
= directory
.Rewind();
1295 while (error
== B_OK
) {
1297 error
= directory
.GetNextEntry(&childEntry
);
1298 if (error
== B_ENTRY_NOT_FOUND
) {
1303 error
= childEntry
.InitCheck();
1306 error
= childEntry
.GetPath(&childPath
);
1308 error
= childPath
.InitCheck();
1309 struct stat childStats
;
1311 error
= childEntry
.GetStat(&childStats
);
1313 node_data childNode
;
1314 std::string
childImagePath(path
);
1315 childImagePath
+= (childImagePath
[childImagePath
.length()-1] == '/'
1317 childImagePath
+= childPath
.Leaf();
1319 if (S_ISREG(childStats
.st_mode
)) {
1321 error
= _ProcessFile(childEntry
, childImagePath
.c_str(),
1322 childStats
, childNode
);
1323 } else if (S_ISDIR(childStats
.st_mode
)) {
1325 error
= _ProcessDirectory(childEntry
, childImagePath
.c_str(),
1326 childStats
, childNode
, icbAddress
);
1329 } else if (S_ISLNK(childStats
.st_mode
)) {
1332 _Stats().AddSymlink();
1333 _PrintWarning("No symlink support yet; skipping symlink: `%s'",
1334 childImagePath
.c_str());
1338 // Write iso direntry
1342 Udf::String
udfName(childPath
.Leaf());
1343 uint32 udfNameLength
= udfName
.Cs0Length();
1344 uint32 idLength
= (38)
1346 Udf::MemoryChunk
chunk(idLength
+ 4);
1347 error
= chunk
.InitCheck();
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);
1367 error
= block_for_offset(udfData
->Position(), udfDataAddresses
,
1368 _BlockSize(), block
);
1370 id
->tag().set_location(block
);
1371 id
->tag().set_checksums(*id
, id
->descriptor_size());
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());
1387 error
= chunk
.InitCheck();
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
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
1417 _Stats().AddDirectory();
1418 uint32 totalLength
= udfDataLength
+ _BlockSize();
1419 _Stats().AddDirectoryBytes(totalLength
);
1425 UdfBuilder::_ProcessFile(BEntry
&entry
, const char *path
, struct stat stats
,
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
);
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();
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
,
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
1465 _PrintUpdate(VERBOSITY_MEDIUM
, "Reserving space for file data");
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
);
1472 udfDataAddresses
.empty(); // just in case
1473 udfDataAddresses
.push_back(address
);
1474 udfDataExtents
.push_back(extent
);
1477 // Udf can handle multiple extents if necessary
1478 error
= _PartitionAllocator().GetNextExtents(udfDataLength
, udfDataAddresses
,
1482 int extents
= udfDataAddresses
.size();
1484 _PrintUpdate(VERBOSITY_HIGH
, "udf: Reserved %d 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();
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(),
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;
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());
1520 error
= chunk
.InitCheck();
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
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
1552 off_t totalLength
= udfDataLength
+ _BlockSize();
1553 _Stats().AddFileBytes(totalLength
);