1//----------------------------------------------------------------------
2//  This software is part of the OpenBeOS distribution and is covered
3//  by the OpenBeOS license.
4//
5//  Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6//----------------------------------------------------------------------
7
8/*! \file PartitionAllocator.h
9
10	Udf physical partition allocator (implementation).
11*/
12
13#include "PhysicalPartitionAllocator.h"
14
15Udf::extent_address PhysicalPartitionAllocator::dummyExtent;
16
17PhysicalPartitionAllocator::PhysicalPartitionAllocator(uint16 number,
18                                                       uint32 offset,
19                                                       Allocator &allocator)
20	: fNumber(number)
21	, fOffset(offset)
22	, fAllocator(allocator)
23{
24
25}
26
27/*! \brief Allocates the next available block.
28
29	\param block Output parameter into which the number of the
30	             allocated block (in the partition) is stored.
31	\param physicalBlock Output parameter into which the number of the
32	                     allocated block (on the physical volume) is
33	                     stored.
34
35	\return
36	- B_OK: Success.
37	- error code: Failure, no blocks available.
38*/
39status_t
40PhysicalPartitionAllocator::GetNextBlock(uint32 &block, uint32 &physicalBlock)
41{
42	status_t error = fAllocator.GetNextBlock(physicalBlock, fOffset);
43	if (!error)
44		block = physicalBlock-fOffset;
45	return error;
46}
47
48/*! \brief Allocates the next available extent of given length.
49
50	\param length The desired length (in bytes) of the extent.
51	\param contiguous If false, signals that an extent of shorter length will
52	                  be accepted. This allows for small chunks of
53	                  unallocated space to be consumed, provided a
54	                  contiguous chunk is not needed.
55	\param extent Output parameter into which the extent as allocated
56	              in the partition is stored. Note that the length
57	              field of the extent may be shorter than the length
58	              parameter passed to this function is \a contiguous is
59	              false.
60	\param physicalExtent Output parameter into which the extent as allocated
61	                      on the physical volume is stored. Note that the length
62	                      field of the extent may be shorter than the length
63	                      parameter passed to this function is \a contiguous is
64	                      false.
65
66	\return
67	- B_OK: Success.
68	- error code: Failure.
69*/
70status_t
71PhysicalPartitionAllocator::GetNextExtent(uint32 length,
72	                                      bool contiguous,
73                                          Udf::long_address &extent,
74                                          Udf::extent_address &physicalExtent)
75{
76	status_t error = fAllocator.GetNextExtent(length, contiguous, physicalExtent, fOffset);
77	if (!error) {
78		extent.set_partition(PartitionNumber());
79		extent.set_block(physicalExtent.location()-fOffset);
80		extent.set_length(physicalExtent.length());
81	}
82	return error;
83}
84
85/*! \brief Allocates enough extents to add up to length bytes and stores said
86           extents in the given address lists.
87
88	\param length The desired length (in bytes) to be allocated.
89	\param extents Output parameter into which the extents as allocated
90	               in the partition are stored.
91	\param physicalExtent Output parameter into which the extents as allocated
92	                      on the physical volume are stored.
93
94	\return
95	- B_OK: Success.
96	- error code: Failure.
97*/
98status_t
99PhysicalPartitionAllocator::GetNextExtents(off_t length, std::list<Udf::long_address> &extents,
100	                                       std::list<Udf::extent_address> &physicalExtents)
101{
102	DEBUG_INIT_ETC("PhysicalPartitionAllocator", ("length: %lld", length));
103	extents.empty();
104	physicalExtents.empty();
105
106	// Allocate extents until we're done or we hit an error
107	status_t error = B_OK;
108	while (error == B_OK) {
109		Udf::long_address extent;
110		Udf::extent_address physicalExtent;
111		uint32 chunkLength = length <= ULONG_MAX ? uint32(length) : ULONG_MAX;
112		error = GetNextExtent(chunkLength, false, extent, physicalExtent);
113		if (!error) {
114			extents.push_back(extent);
115			physicalExtents.push_back(physicalExtent);
116			if (physicalExtent.length() > chunkLength) {
117				// This should never happen, but just to be safe
118				PRINT(("ERROR: allocated extent length longer than requested "
119				       " extent length (allocated: %ld, requested: %ld)\n",
120				       physicalExtent.length(), chunkLength));
121				error = B_ERROR;
122			} else {
123				// ToDo: Might want to add some checks for 0 length allocations here
124				length -= physicalExtent.length();
125				if (length == 0) {
126					// All done
127					break;
128				}
129			}
130		}
131	}
132	RETURN(error);
133}
134
135/*! \brief Returns the length of the partition in blocks.
136*/
137uint32
138PhysicalPartitionAllocator::Length() const
139{
140	uint32 length = fAllocator.Length();
141	return fOffset >= length ? 0 : length-fOffset;
142}
143