hrev44688 adds 1 changeset to branch 'master' old head: c58a87027a546012b0b6a25e1ab098d618bbf266 new head: c530d46cca3cb9bde36e243e634796eb2e17a23a ---------------------------------------------------------------------------- c530d46: UDF: support for metadata partition (feature from 2.50) * added Icb::FindBlock() to find block in extents. * MetadataPartition uses extents descriptors found in the metadatafile to lookup blocks on a physical partition * uses struct timespec instead of time_t * added init_entities() to call C++ structures constructors. This is called at module initialization, C++ constructors are currently not called when a kernel module is loaded. * tested with a sample bluray ISO. [ JÃrÃme Duval <jerome.duval@xxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev44688 Commit: c530d46cca3cb9bde36e243e634796eb2e17a23a URL: http://cgit.haiku-os.org/haiku/commit/?id=c530d46 Author: JÃrÃme Duval <jerome.duval@xxxxxxxxx> Date: Tue Oct 9 20:35:26 2012 UTC ---------------------------------------------------------------------------- 13 files changed, 441 insertions(+), 160 deletions(-) src/add-ons/kernel/file_systems/udf/Icb.cpp | 111 ++++++++++++++-- src/add-ons/kernel/file_systems/udf/Icb.h | 19 ++- .../kernel/file_systems/udf/MetadataPartition.cpp | 48 +++++-- .../kernel/file_systems/udf/MetadataPartition.h | 24 ++-- .../kernel/file_systems/udf/Recognition.cpp | 29 +++- src/add-ons/kernel/file_systems/udf/Recognition.h | 20 +-- .../kernel/file_systems/udf/UdfStructures.cpp | 62 ++++++--- .../kernel/file_systems/udf/UdfStructures.h | 99 ++++++++++---- src/add-ons/kernel/file_systems/udf/Utils.cpp | 103 ++++++++------ src/add-ons/kernel/file_systems/udf/Utils.h | 2 +- src/add-ons/kernel/file_systems/udf/Volume.cpp | 52 +++++++- src/add-ons/kernel/file_systems/udf/Volume.h | 4 + .../kernel/file_systems/udf/kernel_interface.cpp | 28 +++- ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/udf/Icb.cpp b/src/add-ons/kernel/file_systems/udf/Icb.cpp index 8092a58..faf1f9c 100644 --- a/src/add-ons/kernel/file_systems/udf/Icb.cpp +++ b/src/add-ons/kernel/file_systems/udf/Icb.cpp @@ -1,6 +1,7 @@ /* - * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2010, Michael Lotz, mmlr@xxxxxxxxx + * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx * Distributed under the terms of the MIT License. */ @@ -104,6 +105,7 @@ Icb::Icb(Volume *volume, long_address address) fData(volume), fInitStatus(B_NO_INIT), fId(to_vnode_id(address)), + fPartition(address.partition()), fFileEntry(&fData), fExtendedEntry(&fData), fFileCache(NULL), @@ -177,17 +179,105 @@ Icb::InitCheck() } -time_t -Icb::AccessTime() +void +Icb::GetAccessTime(struct timespec ×pec) const { - return make_time(_FileEntry()->access_date_and_time()); + timestamp ts; + if ((_Tag().id() == TAGID_EXTENDED_FILE_ENTRY)) + ts = _ExtendedEntry()->access_date_and_time(); + else + ts = _FileEntry()->access_date_and_time(); + + if (decode_time(ts, timespec) != B_OK) { + decode_time( + fVolume->PrimaryVolumeDescriptor()->recording_date_and_time(), + timespec); + } } -time_t -Icb::ModificationTime() +void +Icb::GetModificationTime(struct timespec ×pec) const +{ + timestamp ts; + if ((_Tag().id() == TAGID_EXTENDED_FILE_ENTRY)) + ts = _ExtendedEntry()->modification_date_and_time(); + else + ts = _FileEntry()->modification_date_and_time(); + + if (decode_time(ts, timespec) != B_OK) { + decode_time( + fVolume->PrimaryVolumeDescriptor()->recording_date_and_time(), + timespec); + } +} + + +status_t +Icb::FindBlock(uint32 logicalBlock, off_t &block) { - return make_time(_FileEntry()->modification_date_and_time()); + off_t pos = logicalBlock << fVolume->BlockShift(); + if (uint64(pos) >= Length()) { + block = -1; + return B_ERROR; + } + + DEBUG_INIT_ETC("Icb", ("pos: %lld", pos)); + + status_t status = B_OK; + long_address extent; + bool isEmpty = false; + + switch (_IcbTag().descriptor_flags()) { + case ICB_DESCRIPTOR_TYPE_SHORT: { + TRACE(("Icb::FindBlock: descriptor type -> short\n")); + AllocationDescriptorList<ShortDescriptorAccessor> list(this, + ShortDescriptorAccessor(fPartition)); + status = list.FindExtent(pos, &extent, &isEmpty); + if (status != B_OK) { + TRACE_ERROR(("Icb::FindBlock: error finding extent for offset %Ld. " + "status = 0x%lx `%s'\n", pos, status, strerror(status))); + } + break; + } + + case ICB_DESCRIPTOR_TYPE_LONG: { + TRACE(("Icb::FindBlock: descriptor type -> long\n")); + AllocationDescriptorList<LongDescriptorAccessor> list(this); + status = list.FindExtent(pos, &extent, &isEmpty); + if (status != B_OK) { + TRACE_ERROR(("Icb::FindBlock: error finding extent for offset %Ld. " + "status = 0x%lx `%s'\n", pos, status, strerror(status))); + } + break; + } + + case ICB_DESCRIPTOR_TYPE_EXTENDED: { + TRACE(("Icb::FindBlock: descriptor type -> extended\n")); +// AllocationDescriptorList<ExtendedDescriptorAccessor> list(this, ExtendedDescriptorAccessor(0)); +// RETURN(_Read(list, pos, buffer, length, block)); + RETURN(B_ERROR); + break; + } + + case ICB_DESCRIPTOR_TYPE_EMBEDDED: { + TRACE(("Icb::FindBlock: descriptor type: embedded\n")); + RETURN(B_ERROR); + break; + } + + default: + TRACE(("Icb::FindBlock: invalid icb descriptor flags! (flags = %d)\n", + _IcbTag().descriptor_flags())); + RETURN(B_BAD_VALUE); + break; + } + + if (status == B_OK) { + block = extent.block(); + TRACE(("Icb::FindBlock: block %lld\n", block)); + } + return status; } @@ -205,13 +295,16 @@ Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block) return B_OK; } + DEBUG_INIT_ETC("Icb", ("pos: %lld, length: %ld", pos, *length)); + if (fFileCache != NULL) return file_cache_read(fFileCache, NULL, pos, buffer, length); switch (_IcbTag().descriptor_flags()) { case ICB_DESCRIPTOR_TYPE_SHORT: { TRACE(("Icb::Read: descriptor type -> short\n")); - AllocationDescriptorList<ShortDescriptorAccessor> list(this, ShortDescriptorAccessor(0)); + AllocationDescriptorList<ShortDescriptorAccessor> list(this, + ShortDescriptorAccessor(fPartition)); RETURN(_Read(list, pos, buffer, length, block)); break; } @@ -445,7 +538,7 @@ Icb::Find(const char *filename, ino_t *id) TRACE(("Icb::Find: filename = `%s', id = %p\n", filename, id)); if (!filename || !id) - RETURN(B_BAD_VALUE); + return B_BAD_VALUE; DirectoryIterator *i; status_t status = GetDirectoryIterator(&i); diff --git a/src/add-ons/kernel/file_systems/udf/Icb.h b/src/add-ons/kernel/file_systems/udf/Icb.h index 7fac386..fd3893a 100644 --- a/src/add-ons/kernel/file_systems/udf/Icb.h +++ b/src/add-ons/kernel/file_systems/udf/Icb.h @@ -1,4 +1,5 @@ /* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxxx * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx * Distributed under the terms of the MIT License. @@ -96,14 +97,15 @@ public: uint64 Length() { return _FileEntry()->information_length(); } mode_t Mode() { return (IsDirectory() ? S_IFDIR : S_IFREG) | S_IRUSR | S_IRGRP | S_IROTH; } - time_t AccessTime(); - time_t ModificationTime(); + void GetAccessTime(struct timespec ×pec) const; + void GetModificationTime(struct timespec ×pec) const; uint8 *AllocationDescriptors() { return _AbstractEntry()->AllocationDescriptors(); } uint32 AllocationDescriptorsSize() { return _AbstractEntry()->AllocationDescriptorsLength(); } + status_t FindBlock(uint32 logicalBlock, off_t &block); status_t Read(off_t pos, void *buffer, size_t *length, uint32 *block = NULL); @@ -120,15 +122,17 @@ public: Volume *GetVolume() const { return fVolume; } private: - AbstractFileEntry *_AbstractEntry() { return (_Tag().id() + AbstractFileEntry *_AbstractEntry() const { return (_Tag().id() == TAGID_EXTENDED_FILE_ENTRY) ? (AbstractFileEntry *)&fExtendedEntry : (AbstractFileEntry *)&fFileEntry; } - descriptor_tag &_Tag() { return ((icb_header *)fData.Block())->tag(); } - icb_entry_tag &_IcbTag() { return ((icb_header *)fData.Block())->icb_tag(); } - file_icb_entry *_FileEntry() { return (file_icb_entry *)fData.Block(); } - extended_file_icb_entry &_ExtendedEntry() { return *(extended_file_icb_entry *)fData.Block(); } + descriptor_tag &_Tag() const { return ((icb_header *)fData.Block())->tag(); } + icb_entry_tag &_IcbTag() const { return ((icb_header *)fData.Block())->icb_tag(); } + file_icb_entry *_FileEntry() const + { return (file_icb_entry *)fData.Block(); } + extended_file_icb_entry *_ExtendedEntry() const + { return (extended_file_icb_entry *)fData.Block(); } template<class DescriptorList> status_t _GetFileMap(DescriptorList &list, off_t offset, @@ -143,6 +147,7 @@ private: status_t fInitStatus; ino_t fId; SinglyLinkedList<DirectoryIterator> fIteratorList; + uint16 fPartition; FileEntry<file_icb_entry> fFileEntry; FileEntry<extended_file_icb_entry> fExtendedEntry; void * fFileCache; diff --git a/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp b/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp index a652672..2c58a2c 100644 --- a/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp +++ b/src/add-ons/kernel/file_systems/udf/MetadataPartition.cpp @@ -1,29 +1,45 @@ +/* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx + * This file may be used under the terms of the MIT License. + */ + + #include "MetadataPartition.h" -#define B_NOT_IMPLEMENTED B_ERROR +#include "Icb.h" /*! \brief Creates a new MetadataPartition object. */ -MetadataPartition::MetadataPartition(Partition &parentPartition, - uint32 metadataFileLocation, - uint32 metadataMirrorFileLocation, - uint32 metadataBitmapFileLocation, - uint32 allocationUnitSize, - uint16 alignmentUnitSize, - bool metadataIsDuplicated) - : fParentPartition(parentPartition) - , fAllocationUnitSize(allocationUnitSize) - , fAlignmentUnitSize(alignmentUnitSize) - , fMetadataIsDuplicated(metadataIsDuplicated) - , fInitStatus(B_NO_INIT) +MetadataPartition::MetadataPartition(Volume *volume, + uint16 parentNumber, Partition &parentPartition, uint32 metadataFileLocation, + uint32 metadataMirrorFileLocation, uint32 metadataBitmapFileLocation, + uint32 allocationUnitSize, uint16 alignmentUnitSize, + bool metadataIsDuplicated) + : fPartition(parentNumber), + fParentPartition(parentPartition), + fAllocationUnitSize(allocationUnitSize), + fAlignmentUnitSize(alignmentUnitSize), + fMetadataIsDuplicated(metadataIsDuplicated), + fInitStatus(B_NO_INIT), + fMetadataIcb(NULL) { + long_address address; + address.set_to(metadataFileLocation, fPartition); + + fMetadataIcb = new(nothrow) Icb(volume, address); + if (fMetadataIcb == NULL || fMetadataIcb->InitCheck() != B_OK) + fInitStatus = B_NO_MEMORY; + + fInitStatus = B_OK; } /*! \brief Destroys the MetadataPartition object. */ MetadataPartition::~MetadataPartition() { + delete fMetadataIcb; } /*! \brief Maps the given logical block to a physical block on disc. @@ -31,7 +47,11 @@ MetadataPartition::~MetadataPartition() status_t MetadataPartition::MapBlock(uint32 logicalBlock, off_t &physicalBlock) { - return B_NOT_IMPLEMENTED; + off_t block = 0; + status_t status = fMetadataIcb->FindBlock(logicalBlock, block); + if (status != B_OK) + return status; + return fParentPartition.MapBlock(block, physicalBlock); } /*! Returns the initialization status of the object. diff --git a/src/add-ons/kernel/file_systems/udf/MetadataPartition.h b/src/add-ons/kernel/file_systems/udf/MetadataPartition.h index d172c14..0c97bf6 100644 --- a/src/add-ons/kernel/file_systems/udf/MetadataPartition.h +++ b/src/add-ons/kernel/file_systems/udf/MetadataPartition.h @@ -1,9 +1,8 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -// -// Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx -//--------------------------------------------------------------------- +/* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx + * This file may be used under the terms of the MIT License. + */ #ifndef _UDF_METADATA_PARTITION_H #define _UDF_METADATA_PARTITION_H @@ -12,8 +11,9 @@ #include <util/kernel_cpp.h> -#include "Partition.h" #include "UdfDebug.h" +#include "Volume.h" + /*! \brief Type 2 metadata partition @@ -24,10 +24,10 @@ */ class MetadataPartition : public Partition { public: - MetadataPartition(Partition &parentPartition, uint32 metadataFileLocation, - uint32 metadataMirrorFileLocation, uint32 metadataBitmapFileLocation, - uint32 allocationUnitSize, uint16 alignmentUnitSize, - bool metadataIsDuplicated); + MetadataPartition(Volume *volume, uint16 partition, Partition &parentPartition, + uint32 metadataFileLocation, uint32 metadataMirrorFileLocation, + uint32 metadataBitmapFileLocation, uint32 allocationUnitSize, + uint16 alignmentUnitSize, bool metadataIsDuplicated); virtual ~MetadataPartition(); virtual status_t MapBlock(uint32 logicalBlock, off_t &physicalBlock); @@ -37,11 +37,13 @@ public: uint16 AlignmentUnitSize() const { return fAlignmentUnitSize; } uint32 MetadataIsDuplicated() const { return fMetadataIsDuplicated; } private: + uint16 fPartition; Partition &fParentPartition; uint32 fAllocationUnitSize; uint16 fAlignmentUnitSize; bool fMetadataIsDuplicated; status_t fInitStatus; + Icb *fMetadataIcb; }; #endif // _UDF_METADATA_PARTITION_H diff --git a/src/add-ons/kernel/file_systems/udf/Recognition.cpp b/src/add-ons/kernel/file_systems/udf/Recognition.cpp index da9dc76..fbc8a27 100644 --- a/src/add-ons/kernel/file_systems/udf/Recognition.cpp +++ b/src/add-ons/kernel/file_systems/udf/Recognition.cpp @@ -1,3 +1,10 @@ +/* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx + * Distributed under the terms of the MIT License. + */ + + #include "Recognition.h" #include "UdfString.h" @@ -18,6 +25,7 @@ walk_volume_recognition_sequence(int device, off_t offset, uint32 blockSize, static status_t walk_anchor_volume_descriptor_sequences(int device, off_t offset, off_t length, uint32 blockSize, uint32 blockShift, + primary_volume_descriptor &primaryVolumeDescriptor, logical_volume_descriptor &logicalVolumeDescriptor, partition_descriptor partitionDescriptors[], uint8 &partitionDescriptorCount); @@ -25,6 +33,7 @@ walk_anchor_volume_descriptor_sequences(int device, off_t offset, off_t length, static status_t walk_volume_descriptor_sequence(extent_address descriptorSequence, int device, uint32 blockSize, uint32 blockShift, + primary_volume_descriptor &primaryVolumeDescriptor, logical_volume_descriptor &logicalVolumeDescriptor, partition_descriptor partitionDescriptors[], uint8 &partitionDescriptorCount); @@ -40,7 +49,8 @@ walk_integrity_sequence(int device, uint32 blockSize, uint32 blockShift, status_t udf_recognize(int device, off_t offset, off_t length, uint32 blockSize, - uint32 &blockShift, logical_volume_descriptor &logicalVolumeDescriptor, + uint32 &blockShift, primary_volume_descriptor &primaryVolumeDescriptor, + logical_volume_descriptor &logicalVolumeDescriptor, partition_descriptor partitionDescriptors[], uint8 &partitionDescriptorCount) { @@ -66,7 +76,8 @@ udf_recognize(int device, off_t offset, off_t length, uint32 blockSize, // Now hunt down a volume descriptor sequence from one of // the anchor volume pointers (if there are any). status = walk_anchor_volume_descriptor_sequences(device, offset, length, - blockSize, blockShift, logicalVolumeDescriptor, partitionDescriptors, + blockSize, blockShift, primaryVolumeDescriptor, + logicalVolumeDescriptor, partitionDescriptors, partitionDescriptorCount); if (status != B_OK) { TRACE_ERROR(("udf_recognize: cannot find volume descriptor. status = %ld\n", @@ -161,6 +172,7 @@ walk_volume_recognition_sequence(int device, off_t offset, uint32 blockSize, static status_t walk_anchor_volume_descriptor_sequences(int device, off_t offset, off_t length, uint32 blockSize, uint32 blockShift, + primary_volume_descriptor &primaryVolumeDescriptor, logical_volume_descriptor &logicalVolumeDescriptor, partition_descriptor partitionDescriptors[], uint8 &partitionDescriptorCount) @@ -200,13 +212,15 @@ walk_anchor_volume_descriptor_sequences(int device, off_t offset, off_t length, // Found an avds, so try the main sequence first, then // the reserve sequence if the main one fails. anchorErr = walk_volume_descriptor_sequence(anchor->main_vds(), - device, blockSize, blockShift, logicalVolumeDescriptor, - partitionDescriptors, partitionDescriptorCount); + device, blockSize, blockShift, primaryVolumeDescriptor, + logicalVolumeDescriptor, partitionDescriptors, + partitionDescriptorCount); if (anchorErr) anchorErr = walk_volume_descriptor_sequence(anchor->reserve_vds(), - device, blockSize, blockShift, logicalVolumeDescriptor, - partitionDescriptors, partitionDescriptorCount); + device, blockSize, blockShift, primaryVolumeDescriptor, + logicalVolumeDescriptor, partitionDescriptors, + partitionDescriptorCount); } if (!anchorErr) { PRINT(("block %Ld: found valid vds\n", avds_locations[i])); @@ -225,6 +239,7 @@ static status_t walk_volume_descriptor_sequence(extent_address descriptorSequence, int device, uint32 blockSize, uint32 blockShift, + primary_volume_descriptor &primaryVolumeDescriptor, logical_volume_descriptor &logicalVolumeDescriptor, partition_descriptor partitionDescriptors[], uint8 &partitionDescriptorCount) @@ -271,7 +286,7 @@ walk_volume_descriptor_sequence(extent_address descriptorSequence, { primary_volume_descriptor *primary = reinterpret_cast<primary_volume_descriptor*>(tag); PDUMP(primary); - (void)primary; // kill the warning + primaryVolumeDescriptor = *primary; break; } diff --git a/src/add-ons/kernel/file_systems/udf/Recognition.h b/src/add-ons/kernel/file_systems/udf/Recognition.h index 73bc009..0b50b7b 100644 --- a/src/add-ons/kernel/file_systems/udf/Recognition.h +++ b/src/add-ons/kernel/file_systems/udf/Recognition.h @@ -1,9 +1,8 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -// -// Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx -//--------------------------------------------------------------------- +/* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx + * Distributed under the terms of the MIT License. + */ #ifndef _UDF_RECOGNITION_H #define _UDF_RECOGNITION_H @@ -14,9 +13,10 @@ #include "UdfDebug.h" status_t udf_recognize(int device, off_t offset, off_t length, - uint32 blockSize, uint32 &blockShift, - logical_volume_descriptor &logicalVolumeDescriptor, - partition_descriptor partitionDescriptors[], - uint8 &partitionDescriptorCount); + uint32 blockSize, uint32 &blockShift, + primary_volume_descriptor &primaryVolumeDescriptor, + logical_volume_descriptor &logicalVolumeDescriptor, + partition_descriptor partitionDescriptors[], + uint8 &partitionDescriptorCount); #endif // _UDF_RECOGNITION_H diff --git a/src/add-ons/kernel/file_systems/udf/UdfStructures.cpp b/src/add-ons/kernel/file_systems/udf/UdfStructures.cpp index 66a90be..68e851d 100644 --- a/src/add-ons/kernel/file_systems/udf/UdfStructures.cpp +++ b/src/add-ons/kernel/file_systems/udf/UdfStructures.cpp @@ -1,9 +1,9 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -// -// Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx -//---------------------------------------------------------------------- +/* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx + * This file may be used under the terms of the MIT License. + */ + /*! \file UdfStructures.cpp @@ -38,20 +38,6 @@ const char* kVSDID_ECMA167_2 = "NSR02"; const char* kVSDID_ECMA167_3 = "NSR03"; const char* kVSDID_ECMA168 = "CDW02"; -// entity_ids -const entity_id kMetadataPartitionMapId(0, "*UDF Metadata Partition"); -const entity_id kSparablePartitionMapId(0, "*UDF Sparable Partition"); -const entity_id kVirtualPartitionMapId(0, "*UDF Virtual Partition"); -const entity_id kImplementationId(0, "*OpenBeOS UDF", implementation_id_suffix(OS_BEOS, BEOS_GENERIC)); -const entity_id kPartitionContentsId1xx(0, "+NSR02"); -const entity_id kPartitionContentsId2xx(0, "+NSR03"); -const entity_id kLogicalVolumeInfoId150(0, "*UDF LV Info", udf_id_suffix(0x0150, OS_BEOS, BEOS_GENERIC)); -const entity_id kLogicalVolumeInfoId201(0, "*UDF LV Info", udf_id_suffix(0x0201, OS_BEOS, BEOS_GENERIC)); -const entity_id kDomainId150(0, "*OSTA UDF Compliant", domain_id_suffix(0x0150, - DF_HARD_WRITE_PROTECT)); -const entity_id kDomainId201(0, "*OSTA UDF Compliant", domain_id_suffix(0x0201, - DF_HARD_WRITE_PROTECT)); - //! crc 010041 table, as generated by crc_table.cpp const uint16 kCrcTable[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, @@ -92,6 +78,40 @@ const uint32 kLogicalVolumeDescriptorBaseSize = sizeof(logical_volume_descriptor - (UDF_MAX_PARTITION_MAPS * UDF_MAX_PARTITION_MAP_SIZE); +// entity_ids +entity_id kMetadataPartitionMapId; +entity_id kSparablePartitionMapId; +entity_id kVirtualPartitionMapId; +entity_id kImplementationId; +entity_id kPartitionContentsId1xx; +entity_id kPartitionContentsId2xx; +entity_id kLogicalVolumeInfoId150; +entity_id kLogicalVolumeInfoId201; +entity_id kDomainId150; +entity_id kDomainId201; + + +//---------------------------------------------------------------------- +// Entities initialization +//---------------------------------------------------------------------- + +void +init_entities() +{ + kMetadataPartitionMapId = entity_id(0, "*UDF Metadata Partition"); + kSparablePartitionMapId = entity_id(0, "*UDF Sparable Partition"); + kVirtualPartitionMapId = entity_id(0, "*UDF Virtual Partition"); + kImplementationId = entity_id(0, "*OpenBeOS UDF", implementation_id_suffix(OS_BEOS, BEOS_GENERIC)); + kPartitionContentsId1xx = entity_id(0, "+NSR02"); + kPartitionContentsId2xx = entity_id(0, "+NSR03"); + kLogicalVolumeInfoId150 = entity_id(0, "*UDF LV Info", udf_id_suffix(0x0150, OS_BEOS, BEOS_GENERIC)); + kLogicalVolumeInfoId201 = entity_id(0, "*UDF LV Info", udf_id_suffix(0x0201, OS_BEOS, BEOS_GENERIC)); + kDomainId150 = entity_id(0, "*OSTA UDF Compliant", domain_id_suffix(0x0150, + DF_HARD_WRITE_PROTECT)); + kDomainId201 = entity_id(0, "*OSTA UDF Compliant", domain_id_suffix(0x0201, + DF_HARD_WRITE_PROTECT)); +} + //---------------------------------------------------------------------- // Helper functions @@ -527,7 +547,7 @@ descriptor_tag::init_check(uint32 block, bool calculateCrc) { DEBUG_INIT_ETC("descriptor_tag", ("location: %ld, calculateCrc: %s", block, bool_to_string(calculateCrc))); - PRINT(("location (paramater) == %ld\n", block)); + PRINT(("location (parameter) == %ld\n", block)); PRINT(("location (in structure) == %ld\n", location())); if (calculateCrc) { PRINT(("crc (calculated) == %d\n", diff --git a/src/add-ons/kernel/file_systems/udf/UdfStructures.h b/src/add-ons/kernel/file_systems/udf/UdfStructures.h index 56c4710..1f2634e 100644 --- a/src/add-ons/kernel/file_systems/udf/UdfStructures.h +++ b/src/add-ons/kernel/file_systems/udf/UdfStructures.h @@ -1,9 +1,8 @@ -//---------------------------------------------------------------------- -// This software is part of the OpenBeOS distribution and is covered -// by the OpenBeOS license. -// -// Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx -//--------------------------------------------------------------------- +/* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright (c) 2003 Tyler Dauwalder, tyler@xxxxxxxxxxxxx + * This file may be used under the terms of the MIT License. + */ #ifndef _UDF_DISK_STRUCTURES_H #define _UDF_DISK_STRUCTURES_H @@ -121,7 +120,8 @@ public: uint8 microsecond() const { return _microsecond; } // Set functions - void set_type_and_timezone(uint16 type_and_timezone) { _type_and_timezone = B_HOST_TO_LENDIAN_INT16(type_and_timezone); } + void set_type_and_timezone(uint16 type_and_timezone) { + _type_and_timezone = B_HOST_TO_LENDIAN_INT16(type_and_timezone); } void set_type(uint8 type) { type_and_timezone_accessor t; t.type_and_timezone = type_and_timezone(); @@ -141,7 +141,8 @@ public: void set_minute(uint8 minute) { _minute = minute; } void set_second(uint8 second) { _second = second; } void set_centisecond(uint8 centisecond) { _centisecond = centisecond; } - void set_hundred_microsecond(uint8 hundred_microsecond) { _hundred_microsecond = hundred_microsecond; } + void set_hundred_microsecond(uint8 hundred_microsecond) { + _hundred_microsecond = hundred_microsecond; } void set_microsecond(uint8 microsecond) { _microsecond = microsecond; } private: void _clear(); @@ -293,17 +294,18 @@ private: array<uint8, kIdentifierSuffixLength> _identifier_suffix; } __attribute__((packed)); -extern const entity_id kMetadataPartitionMapId; -extern const entity_id kSparablePartitionMapId; -extern const entity_id kVirtualPartitionMapId; -extern const entity_id kImplementationId; -extern const entity_id kPartitionContentsId1xx; -extern const entity_id kPartitionContentsId2xx; -extern const entity_id kUdfId; -extern const entity_id kLogicalVolumeInfoId150; -extern const entity_id kLogicalVolumeInfoId201; -extern const entity_id kDomainId150; -extern const entity_id kDomainId201; +extern entity_id kMetadataPartitionMapId; +extern entity_id kSparablePartitionMapId; +extern entity_id kVirtualPartitionMapId; +extern entity_id kImplementationId; +extern entity_id kPartitionContentsId1xx; +extern entity_id kPartitionContentsId2xx; +extern entity_id kUdfId; +extern entity_id kLogicalVolumeInfoId150; +extern entity_id kLogicalVolumeInfoId201; +extern entity_id kDomainId150; +extern entity_id kDomainId201; +extern void init_entities(void); //---------------------------------------------------------------------- // ECMA-167 Part 2 @@ -1307,6 +1309,49 @@ private: See also: UDF-2.50 2.2.10 */ struct metadata_partition_map { +public: + entity_id& partition_type_id() { return _partition_type_id; } + const entity_id& partition_type_id() const { return _partition_type_id; } + + uint16 volume_sequence_number() const { + return B_LENDIAN_TO_HOST_INT16(_volume_sequence_number); } + void set_volume_sequence_number(uint16 number) { + _volume_sequence_number = B_HOST_TO_LENDIAN_INT16(number); } + + uint16 partition_number() const { + return B_LENDIAN_TO_HOST_INT16(_partition_number); } + void set_partition_number(uint16 number) { + _partition_number = B_HOST_TO_LENDIAN_INT16(number); } + + uint32 metadata_file_location() const { + return B_LENDIAN_TO_HOST_INT32(_metadata_file_location); } + void set_metadata_file_location(uint32 location) { + _metadata_file_location = B_HOST_TO_LENDIAN_INT32(location); } + + uint32 metadata_mirror_file_location() const { + return B_LENDIAN_TO_HOST_INT32(_metadata_mirror_file_location); } + void set_metadata_mirror_file_location(uint32 location) { + _metadata_mirror_file_location = B_HOST_TO_LENDIAN_INT32(location); } + + uint32 metadata_bitmap_file_location() const { + return B_LENDIAN_TO_HOST_INT32(_metadata_bitmap_file_location); } + void set_metadata_bitmap_file_location(uint32 location) { + _metadata_bitmap_file_location = B_HOST_TO_LENDIAN_INT32(location); } + + uint32 allocation_unit_size() const { + return B_LENDIAN_TO_HOST_INT32(_allocation_unit_size); } + void set_allocation_unit_size(uint32 size) { + _allocation_unit_size = B_HOST_TO_LENDIAN_INT32(size); } + + uint32 alignment_unit_size() const { + return B_LENDIAN_TO_HOST_INT32(_alignment_unit_size); } + void set_alignment_unit_size(uint32 size) { + _alignment_unit_size = B_HOST_TO_LENDIAN_INT32(size); } + + uint8 flags() const { return _flags; } + void set_flags(uint8 flags) { _flags = flags; } + +private: uint8 type; uint8 length; uint8 reserved1[2]; @@ -1315,14 +1360,20 @@ struct metadata_partition_map { - identifier: "*UDF Metadata Partition" - identifier_suffix: per UDF-2.50 2.1.5 */ - entity_id partition_type_id; - uint16 volume_sequence_number; + entity_id _partition_type_id; + uint16 _volume_sequence_number; /*! corresponding type 1 or type 2 sparable partition map in same logical volume */ - uint16 partition_number; - uint8 reserved2[24]; + uint16 _partition_number; + uint32 _metadata_file_location; + uint32 _metadata_mirror_file_location; + uint32 _metadata_bitmap_file_location; + uint32 _allocation_unit_size; + uint16 _alignment_unit_size; + uint8 _flags; + uint8 reserved2[5]; } __attribute__((packed)); @@ -1470,7 +1521,7 @@ enum { /*! \brief Highest currently supported UDF read revision. */ -#define UDF_MAX_READ_REVISION 0x0201 +#define UDF_MAX_READ_REVISION 0x0250 //---------------------------------------------------------------------- // ECMA-167 Part 4 diff --git a/src/add-ons/kernel/file_systems/udf/Utils.cpp b/src/add-ons/kernel/file_systems/udf/Utils.cpp index 07c69d3..111e410 100644 --- a/src/add-ons/kernel/file_systems/udf/Utils.cpp +++ b/src/add-ons/kernel/file_systems/udf/Utils.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx * Distributed under the terms of the MIT License. */ @@ -79,8 +80,16 @@ get_block_shift(uint32 blockSize, uint32 &blockShift) } -time_t -make_time(timestamp ×tamp) +#define EPOCH_YEAR 1970 +#define MAX_YEAR 69 +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define SECSPERDAY (SECSPERMIN * MINSPERHOUR * HOURSPERDAY) +#define DAYSPERNYEAR 365 + +status_t +decode_time(timestamp ×tamp, struct timespec ×pec) { DEBUG_INIT_ETC(NULL, ("timestamp: (tnt: 0x%x, type: %d, timezone: %d = 0x%x, year: %d, " "month: %d, day: %d, hour: %d, minute: %d, second: %d)", timestamp.type_and_timezone(), @@ -88,50 +97,56 @@ make_time(timestamp ×tamp) timestamp.timezone(),timestamp.year(), timestamp.month(), timestamp.day(), timestamp.hour(), timestamp.minute(), timestamp.second())); - time_t result = 0; + if (timestamp.year() < EPOCH_YEAR || timestamp.year() >= EPOCH_YEAR + MAX_YEAR) + return B_BAD_VALUE; - if (timestamp.year() >= 1970) { - const int monthLengths[12] - = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - int year = timestamp.year(); - int month = timestamp.month(); - int day = timestamp.day(); - int hour = timestamp.hour(); - int minute = timestamp.minute(); - int second = timestamp.second(); - - // Range check the timezone offset, then round it down - // to the nearest hour, since no one I know treats timezones - // with a per-minute granularity, and none of the other OSes - // I've looked at appear to either. - int timezone_offset = timestamp.timezone(); - if (-1440 > timezone_offset || timezone_offset > 1440) - timezone_offset = 0; - timezone_offset -= timezone_offset % 60; - - int previousLeapYears = (year - 1968) / 4; - bool isLeapYear = (year - 1968) % 4 == 0; - if (isLeapYear) - --previousLeapYears; - - // Years to days - result = (year - 1970) * 365 + previousLeapYears; - // Months to days - for (int i = 0; i < month-1; i++) { - result += monthLengths[i]; - } - if (month > 2 && isLeapYear) - ++result; - // Days to hours - result = (result + day - 1) * 24; - // Hours to minutes - result = (result + hour) * 60 + timezone_offset; - // Minutes to seconds - result = (result + minute) * 60 + second; + time_t result = 0; + const int monthLengths[12] + = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + int year = timestamp.year(); + int month = timestamp.month(); + int day = timestamp.day(); + int hour = timestamp.hour(); + int minute = timestamp.minute(); + int second = timestamp.second(); + + // Range check the timezone offset, then round it down + // to the nearest hour, since no one I know treats timezones + // with a per-minute granularity, and none of the other OSes + // I've looked at appear to either. + int timezone_offset = 0; + if (timestamp.type() == 1) + timezone_offset = timestamp.timezone(); + if (-SECSPERDAY > timezone_offset || timezone_offset > SECSPERDAY) + timezone_offset = 0; + timezone_offset -= timezone_offset % 60; + + int previousLeapYears = (year - 1968) / 4; + bool isLeapYear = (year - 1968) % 4 == 0; + if (isLeapYear) + --previousLeapYears; + + // Years to days + result = (year - EPOCH_YEAR) * DAYSPERNYEAR + previousLeapYears; + // Months to days + for (int i = 0; i < month-1; i++) { + result += monthLengths[i]; } - - return result; + if (month > 2 && isLeapYear) + ++result; + // Days to hours + result = (result + day - 1) * HOURSPERDAY; + // Hours to minutes + result = (result + hour) * MINSPERHOUR + timezone_offset; + // Minutes to seconds + result = (result + minute) * SECSPERMIN + second; + + timespec.tv_sec = result; + timespec.tv_nsec = 1000 * (timestamp.microsecond() + + timestamp.hundred_microsecond() * 100 + + timestamp.centisecond() * 10000); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/udf/Utils.h b/src/add-ons/kernel/file_systems/udf/Utils.h index c6de522..5749849 100644 --- a/src/add-ons/kernel/file_systems/udf/Utils.h +++ b/src/add-ons/kernel/file_systems/udf/Utils.h @@ -16,7 +16,7 @@ const char *bool_to_string(bool value); uint16 calculate_crc(uint8 *data, uint16 length); status_t check_size_error(ssize_t bytesReturned, ssize_t bytesExpected); status_t get_block_shift(uint32 blockSize, uint32 &blockShift); -time_t make_time(timestamp ×tamp); +status_t decode_time(timestamp ×tamp, struct timespec ×pec); long_address to_long_address(ino_t id, uint32 length = 0); ino_t to_vnode_id(long_address address); diff --git a/src/add-ons/kernel/file_systems/udf/Volume.cpp b/src/add-ons/kernel/file_systems/udf/Volume.cpp index edca75a..4790bac 100644 --- a/src/add-ons/kernel/file_systems/udf/Volume.cpp +++ b/src/add-ons/kernel/file_systems/udf/Volume.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxx * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx * Distributed under the terms of the MIT License. @@ -8,6 +9,7 @@ #include "Icb.h" #include "MemoryChunk.h" +#include "MetadataPartition.h" #include "PhysicalPartition.h" #include "Recognition.h" @@ -62,6 +64,7 @@ Volume::Mount(const char *deviceName, off_t offset, off_t length, return device; } + DEBUG_INIT_ETC("Volume", ("deviceName: %s", deviceName)); status_t status = B_OK; // If the device is actually a normal file, try to disable the cache @@ -84,8 +87,8 @@ Volume::Mount(const char *deviceName, off_t offset, off_t length, // Run through the volume recognition and descriptor sequences to // see if we have a potentially valid UDF volume on our hands status = udf_recognize(device, offset, length, blockSize, blockShift, - logicalVolumeDescriptor, partitionDescriptors, - partitionDescriptorCount); + fPrimaryVolumeDescriptor, logicalVolumeDescriptor, + partitionDescriptors, partitionDescriptorCount); // Set up the block cache if (!status) { @@ -163,8 +166,43 @@ Volume::Mount(const char *deviceName, off_t offset, off_t length, TRACE(("map type: metadata\n")); metadata_partition_map* map = reinterpret_cast<metadata_partition_map*>(header); - metadataCount++; - (void)map; // kill the warning for now + + + // Find the corresponding partition descriptor + partition_descriptor *descriptor = NULL; + for (uint8 j = 0; j < partitionDescriptorCount; j++) { + if (map->partition_number() == + partitionDescriptors[j].partition_number()) { + descriptor = &partitionDescriptors[j]; + break; + } + } + Partition *parent = _GetPartition(map->partition_number()); + // Create and add the partition + if (descriptor != NULL && parent != NULL) { + MetadataPartition *partition + = new(nothrow) MetadataPartition(this, + map->partition_number(), *parent, + map->metadata_file_location(), + map->metadata_mirror_file_location(), + map->metadata_bitmap_file_location(), + map->allocation_unit_size(), + map->alignment_unit_size(), + map->flags() & 1); + status = partition ? partition->InitCheck() : B_NO_MEMORY; + if (!status) { + TRACE(("Volume::Mount: adding MetadataPartition()")); + status = _SetPartition(i, partition); + if (status == B_OK) + metadataCount++; + } else { + TRACE_ERROR(("Volume::Mount: metadata partition " + "creation failed! 0x%lx\n", status)); + } + } else { + TRACE_ERROR(("Volume::Mount: no matching partition descriptor found!\n")); + status = B_ERROR; + } } else { TRACE(("map type: unrecognized (`%.23s')\n", typeId.identifier())); @@ -180,9 +218,9 @@ Volume::Mount(const char *deviceName, off_t offset, off_t length, // Do some checking as to what sorts of partitions we've actually found. if (!status) { status = (physicalCount == 1 && virtualCount == 0 - && sparableCount == 0 && metadataCount == 0) + && sparableCount == 0) || (physicalCount == 2 && virtualCount == 0 - && sparableCount == 0 && metadataCount == 0) + && sparableCount == 0) ? B_OK : B_ERROR; if (status) { TRACE(("Invalid partition layout found:\n")); @@ -294,6 +332,8 @@ Volume::MapBlock(long_address address, off_t *mappedBlock) { TRACE(("Volume::MapBlock: partition = %d, block = %ld, mappedBlock = %p\n", address.partition(), address.block(), mappedBlock)); + DEBUG_INIT_ETC("Volume", ("partition = %d, block = %ld, mappedBlock = %p", + address.partition(), address.block(), mappedBlock)); status_t error = mappedBlock ? B_OK : B_BAD_VALUE; if (!error) { Partition *partition = _GetPartition(address.partition()); diff --git a/src/add-ons/kernel/file_systems/udf/Volume.h b/src/add-ons/kernel/file_systems/udf/Volume.h index a86e1c8..03487d3 100644 --- a/src/add-ons/kernel/file_systems/udf/Volume.h +++ b/src/add-ons/kernel/file_systems/udf/Volume.h @@ -1,4 +1,5 @@ /* + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxx * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx * Distributed under the terms of the MIT License. @@ -50,6 +51,8 @@ public: uint32 BlockShift() const { return fBlockShift; } bool Mounted() const { return fMounted; } Icb* RootIcb() { return fRootIcb; } + primary_volume_descriptor *PrimaryVolumeDescriptor() + { return &fPrimaryVolumeDescriptor; } private: void _Unset(); @@ -69,6 +72,7 @@ private: off_t fOffset; Partition *fPartitions[UDF_MAX_PARTITION_MAPS]; Icb *fRootIcb; // Destroyed by vfs via callback to put_node() + primary_volume_descriptor fPrimaryVolumeDescriptor; }; #endif // _UDF_VOLUME_H diff --git a/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp b/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp index 398bc6d..06a3a29 100644 --- a/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/udf/kernel_interface.cpp @@ -1,7 +1,8 @@ /* - * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx - * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxxx + * Copyright 2012, JÃrÃme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2010, Michael Lotz, mmlr@xxxxxxxxx + * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxxx + * Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxxx * Distributed under the terms of the MIT License. */ @@ -80,13 +81,14 @@ udf_identify_partition(int fd, partition_data *partition, void **_cookie) partition->offset, partition->size, partition->content_size, partition->block_size)); + primary_volume_descriptor primaryVolumeDescriptor; logical_volume_descriptor logicalVolumeDescriptor; partition_descriptor partitionDescriptors[kMaxPartitionDescriptors]; uint8 descriptorCount = kMaxPartitionDescriptors; uint32 blockShift; status_t error = udf_recognize(fd, partition->offset, partition->size, - partition->block_size, blockShift, logicalVolumeDescriptor, - partitionDescriptors, descriptorCount); + partition->block_size, blockShift, primaryVolumeDescriptor, + logicalVolumeDescriptor, partitionDescriptors, descriptorCount); if (error != B_OK) return -1; @@ -293,8 +295,12 @@ udf_read_stat(fs_volume *_volume, fs_vnode *node, struct stat *stat) // File times. For now, treat the modification time as creation // time as well, since true creation time is an optional extended // attribute, and supporting EAs is going to be a PITA. ;-) - stat->st_atime = icb->AccessTime(); - stat->st_mtime = stat->st_ctime = stat->st_crtime = icb->ModificationTime(); + icb->GetAccessTime(stat->st_atim); + icb->GetModificationTime(stat->st_mtim); + icb->GetModificationTime(stat->st_ctim); + icb->GetModificationTime(stat->st_crtim); + //icb->GetChangeTime(stat->st_ctim); + //icb->GetCreationTime(stat->st_crtim); TRACE(("udf_read_stat: mode = 0x%x, st_ino: %Ld\n", stat->st_mode, stat->st_ino)); @@ -343,6 +349,8 @@ udf_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, ((Volume *)volume->private_volume)->ID(), pos, *length)); Icb *icb = (Icb *)vnode->private_node; + DEBUG_INIT_ETC("udf_read", ("ID = %ld, pos = %lld, length = %lu", + ((Volume *)volume->private_volume)->ID(), pos, *length)); // if (!inode->HasUserAccessableStream()) { // *_length = 0; @@ -385,6 +393,8 @@ static status_t udf_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) { TRACE(("udf_open_dir: volume = %p, vnode = %p\n", volume, vnode)); + DEBUG_INIT_ETC("udf_open_dir", ("ID = %ld", + ((Volume *)volume->private_volume)->ID())); if (!volume || !vnode || !cookie) RETURN(B_BAD_VALUE); @@ -443,6 +453,8 @@ udf_read_dir(fs_volume *_volume, fs_vnode *vnode, void *cookie, Icb *dir = (Icb *)vnode->private_node; DirectoryIterator *iterator = (DirectoryIterator *)cookie; + DEBUG_INIT_ETC("udf_read_dir", ("ID = %ld", volume->ID())); + if (dir != iterator->Parent()) { TRACE_ERROR(("udf_read_dir: Icb does not match parent Icb of given " "DirectoryIterator! (iterator->Parent = %p)\n", iterator->Parent())); @@ -474,6 +486,8 @@ udf_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) { TRACE(("udf_rewind_dir: volume = %p, vnode = %p, cookie = %p\n", volume, vnode, cookie)); + DEBUG_INIT_ETC("udf_rewind_dir", ("ID = %ld", + ((Volume *)volume->private_volume)->ID())); if (!volume || !vnode || !cookie) RETURN(B_BAD_VALUE); @@ -604,6 +618,8 @@ udf_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: + init_entities(); + return B_OK; case B_MODULE_UNINIT: return B_OK; default: