2 * Copyright 2012, Jérôme Duval, korli@users.berlios.de.
3 * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com
4 * Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net.
5 * Distributed under the terms of the MIT License.
11 #include "MemoryChunk.h"
12 #include "MetadataPartition.h"
13 #include "PhysicalPartition.h"
14 #include "Recognition.h"
16 extern fs_volume_ops gUDFVolumeOps
;
17 extern fs_vnode_ops gUDFVnodeOps
;
19 /*! \brief Creates an unmounted volume with the given id. */
20 Volume::Volume(fs_volume
*fsVolume
)
32 for (int i
= 0; i
< UDF_MAX_PARTITION_MAPS
; i
++)
33 fPartitions
[i
] = NULL
;
43 /*! \brief Attempts to mount the given device.
45 \param lenght The length of the device in number of blocks
48 Volume::Mount(const char *deviceName
, off_t offset
, off_t length
,
49 uint32 blockSize
, uint32 flags
)
51 TRACE(("Volume::Mount: deviceName = `%s', offset = %" B_PRIdOFF
", length "
52 "= %" B_PRIdOFF
", blockSize: %" B_PRIu32
", flags: %" B_PRIu32
"\n",
53 deviceName
, offset
, length
, blockSize
, flags
));
57 // Already mounted, thank you for asking
60 // Open the device read only
61 int device
= open(deviceName
, O_RDONLY
);
63 TRACE_ERROR(("Volume::Mount: failed to open device = %s\n", deviceName
));
67 DEBUG_INIT_ETC("Volume", ("deviceName: %s", deviceName
));
68 status_t status
= B_OK
;
70 // If the device is actually a normal file, try to disable the cache
71 // for the file in the parent filesystem
74 error
= fstat(device
, &stat
) < 0 ? B_ERROR
: B_OK
;
76 if (stat
.st_mode
& S_IFREG
&& ioctl(device
, IOCTL_FILE_UNCACHED_IO
, NULL
) < 0) {
77 DIE(("Unable to disable cache of underlying file system.\n"));
82 logical_volume_descriptor logicalVolumeDescriptor
;
83 partition_descriptor partitionDescriptors
[kMaxPartitionDescriptors
];
84 uint8 partitionDescriptorCount
;
87 // Run through the volume recognition and descriptor sequences to
88 // see if we have a potentially valid UDF volume on our hands
89 status
= udf_recognize(device
, offset
, length
, blockSize
, blockShift
,
90 fPrimaryVolumeDescriptor
, logicalVolumeDescriptor
,
91 partitionDescriptors
, partitionDescriptorCount
);
93 // Set up the block cache
95 TRACE(("Volume::Mount: partition recognized\n"));
96 fBlockCache
= block_cache_create(device
, length
, blockSize
, IsReadOnly());
98 TRACE_ERROR(("Volume::Mount: failed to recognize partition\n"));
102 int physicalCount
= 0;
103 int virtualCount
= 0;
104 int sparableCount
= 0;
105 int metadataCount
= 0;
107 // Set up the partitions
108 // Set up physical and sparable partitions first
110 for (uint8 i
= 0; i
< logicalVolumeDescriptor
.partition_map_count()
113 uint8
*maps
= logicalVolumeDescriptor
.partition_maps();
114 partition_map_header
*header
= (partition_map_header
*)(maps
+ offset
);
115 TRACE(("Volume::Mount: partition map %d (type %d):\n", i
,
117 if (header
->type() == 1) {
118 TRACE(("Volume::Mount: map type -> physical\n"));
119 physical_partition_map
* map
= (physical_partition_map
*)header
;
120 // Find the corresponding partition descriptor
121 partition_descriptor
*descriptor
= NULL
;
122 for (uint8 j
= 0; j
< partitionDescriptorCount
; j
++) {
123 if (map
->partition_number() ==
124 partitionDescriptors
[j
].partition_number()) {
125 descriptor
= &partitionDescriptors
[j
];
129 // Create and add the partition
131 PhysicalPartition
*partition
132 = new(nothrow
) PhysicalPartition(map
->partition_number(),
133 descriptor
->start(), descriptor
->length());
134 status
= partition
? B_OK
: B_NO_MEMORY
;
136 TRACE(("Volume::Mount: adding PhysicalPartition(number: %d, "
137 "start: %" B_PRIu32
", length: %" B_PRIu32
")\n",
138 map
->partition_number(), descriptor
->start(),
139 descriptor
->length()));
140 status
= _SetPartition(i
, partition
);
145 TRACE_ERROR(("Volume::Mount: no matching partition descriptor found!\n"));
148 } else if (header
->type() == 2) {
149 // Figure out what kind of type 2 partition map we have based
150 // on the type identifier
151 const entity_id
&typeId
= header
->partition_type_id();
153 DUMP(kSparablePartitionMapId
);
154 if (typeId
.matches(kVirtualPartitionMapId
)) {
155 TRACE(("map type: virtual\n"));
156 virtual_partition_map
* map
=
157 reinterpret_cast<virtual_partition_map
*>(header
);
159 (void)map
; // kill the warning for now
160 } else if (typeId
.matches(kSparablePartitionMapId
)) {
161 TRACE(("map type: sparable\n"));
162 sparable_partition_map
* map
=
163 reinterpret_cast<sparable_partition_map
*>(header
);
165 (void)map
; // kill the warning for now
166 } else if (typeId
.matches(kMetadataPartitionMapId
)) {
167 TRACE(("map type: metadata\n"));
168 metadata_partition_map
* map
=
169 reinterpret_cast<metadata_partition_map
*>(header
);
172 // Find the corresponding partition descriptor
173 partition_descriptor
*descriptor
= NULL
;
174 for (uint8 j
= 0; j
< partitionDescriptorCount
; j
++) {
175 if (map
->partition_number() ==
176 partitionDescriptors
[j
].partition_number()) {
177 descriptor
= &partitionDescriptors
[j
];
181 Partition
*parent
= _GetPartition(map
->partition_number());
182 // Create and add the partition
183 if (descriptor
!= NULL
&& parent
!= NULL
) {
184 MetadataPartition
*partition
185 = new(nothrow
) MetadataPartition(this,
186 map
->partition_number(), *parent
,
187 map
->metadata_file_location(),
188 map
->metadata_mirror_file_location(),
189 map
->metadata_bitmap_file_location(),
190 map
->allocation_unit_size(),
191 map
->alignment_unit_size(),
193 status
= partition
? partition
->InitCheck() : B_NO_MEMORY
;
195 TRACE(("Volume::Mount: adding MetadataPartition()"));
196 status
= _SetPartition(i
, partition
);
200 TRACE_ERROR(("Volume::Mount: metadata partition "
201 "creation failed! 0x%" B_PRIx32
"\n", status
));
204 TRACE_ERROR(("Volume::Mount: no matching partition descriptor found!\n"));
208 TRACE(("map type: unrecognized (`%.23s')\n",
209 typeId
.identifier()));
213 TRACE(("Invalid partition type %d found!\n", header
->type()));
216 offset
+= header
->length();
219 // Do some checking as to what sorts of partitions we've actually found.
221 status
= (physicalCount
== 1 && virtualCount
== 0
222 && sparableCount
== 0)
223 || (physicalCount
== 2 && virtualCount
== 0
224 && sparableCount
== 0)
227 TRACE(("Invalid partition layout found:\n"));
228 TRACE((" physical partitions: %d\n", physicalCount
));
229 TRACE((" virtual partitions: %d\n", virtualCount
));
230 TRACE((" sparable partitions: %d\n", sparableCount
));
231 TRACE((" metadata partitions: %d\n", metadataCount
));
235 // We're now going to start creating Icb's, which will expect
236 // certain parts of the volume to be initialized properly. Thus,
237 // we initialize those parts here.
242 fBlockSize
= blockSize
;
243 fBlockShift
= blockShift
;
245 TRACE(("Volume::Mount: device = %d, offset = %" B_PRIdOFF
", length = %"
246 B_PRIdOFF
", blockSize = %" B_PRIu32
", blockShift = %" B_PRIu32
"\n",
247 device
, offset
, length
, blockSize
, blockShift
));
248 // At this point we've found a valid set of volume descriptors and
249 // our partitions are all set up. We now need to investigate the file
250 // set descriptor pointed to by the logical volume descriptor.
252 TRACE(("Volume::Mount: Partition has been set up\n"));
253 MemoryChunk
chunk(logicalVolumeDescriptor
.file_set_address().length());
255 status
= chunk
.InitCheck();
259 // Read in the file set descriptor
260 status
= MapBlock(logicalVolumeDescriptor
.file_set_address(),
263 address
<<= blockShift
;
266 = read_pos(device
, address
, chunk
.Data(), blockSize
);
267 if (bytesRead
!= ssize_t(blockSize
)) {
269 TRACE_ERROR(("read_pos(pos:%" B_PRIdOFF
", len:%" B_PRIu32
270 ") failed with: 0x%lx\n", address
, blockSize
,
274 // See if it's valid, and if so, create the root icb
276 file_set_descriptor
*fileSet
=
277 reinterpret_cast<file_set_descriptor
*>(chunk
.Data());
279 status
= fileSet
->tag().id() == TAGID_FILE_SET_DESCRIPTOR
282 status
= fileSet
->tag().init_check(
283 logicalVolumeDescriptor
.file_set_address().block());
286 fRootIcb
= new(nothrow
) Icb(this, fileSet
->root_directory_icb());
287 if (fRootIcb
== NULL
|| fRootIcb
->InitCheck() != B_OK
)
291 TRACE(("Volume::Mount: Root Node id = %" B_PRIdINO
"\n",
294 status
= publish_vnode(fFSVolume
, fRootIcb
->Id(), fRootIcb
,
295 &gUDFVnodeOps
, fRootIcb
->Mode(), 0);
296 if (status
!= B_OK
) {
297 TRACE_ERROR(("Error creating vnode for root icb! "
298 "status = 0x%" B_PRIx32
", `%s'\n", status
,
300 // Clean up the icb we created, since _Unset()
301 // won't do this for us.
305 TRACE(("Volume::Mount: Root vnode published. Id = %"
306 B_PRIdINO
"\n", fRootIcb
->Id()));
312 // If we've made it this far, we're good to go; set the volume
313 // name and then flag that we're mounted. On the other hand, if
314 // an error occurred, we need to clean things up.
316 fName
.SetTo(logicalVolumeDescriptor
.logical_volume_identifier());
327 Volume::Name() const {
331 /*! \brief Maps the given logical block to a physical block.
334 Volume::MapBlock(long_address address
, off_t
*mappedBlock
)
336 TRACE(("Volume::MapBlock: partition = %d, block = %" B_PRIu32
337 ", mappedBlock = %p\n", address
.partition(), address
.block(),
339 DEBUG_INIT_ETC("Volume", ("partition = %d, block = %" B_PRIu32
340 ", mappedBlock = %p", address
.partition(), address
.block(),
342 status_t error
= mappedBlock
? B_OK
: B_BAD_VALUE
;
344 Partition
*partition
= _GetPartition(address
.partition());
345 error
= partition
? B_OK
: B_BAD_ADDRESS
;
347 error
= partition
->MapBlock(address
.block(), *mappedBlock
);
352 /*! \brief Unsets the volume and deletes any partitions.
354 Does *not* delete the root icb object.
359 DEBUG_INIT("Volume");
360 // delete our partitions
361 for (int i
= 0; i
< UDF_MAX_PARTITION_MAPS
; i
++)
362 _SetPartition(i
, NULL
);
365 block_cache_delete(fBlockCache
, true);
378 /*! \brief Sets the partition associated with the given number after
379 deleting any previously associated partition.
381 \param number The partition number (should be the same as the index
382 into the lvd's partition map array).
383 \param partition The new partition (may be NULL).
386 Volume::_SetPartition(uint number
, Partition
*partition
)
388 status_t error
= number
< UDF_MAX_PARTITION_MAPS
389 ? B_OK
: B_BAD_VALUE
;
391 delete fPartitions
[number
];
392 fPartitions
[number
] = partition
;
397 /*! \brief Returns the partition associated with the given number, or
398 NULL if no such partition exists or the number is invalid.
401 Volume::_GetPartition(uint number
)
403 return (number
< UDF_MAX_PARTITION_MAPS
)
404 ? fPartitions
[number
] : NULL
;