xref: /haiku/src/kits/storage/disk_device/PartitioningInfo.cpp (revision 90ca02568835b140b0e59de496a7f1f1d3513f67)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include <new>
10 
11 #include <disk_device_manager.h>
12 #include <PartitioningInfo.h>
13 
14 #include <syscalls.h>
15 #include <ddm_userland_interface_defs.h>
16 
17 
18 using namespace std;
19 
20 
21 //#define TRACING 1
22 #if TRACING
23 #  define TRACE(x) printf x
24 #else
25 #  define TRACE(x)
26 #endif
27 
28 
29 // constructor
30 BPartitioningInfo::BPartitioningInfo()
31 	: fPartitionID(-1),
32 	  fSpaces(NULL),
33 	  fCount(0),
34 	  fCapacity(0)
35 {
36 }
37 
38 
39 // destructor
40 BPartitioningInfo::~BPartitioningInfo()
41 {
42 	Unset();
43 }
44 
45 
46 // SetTo
47 status_t
48 BPartitioningInfo::SetTo(off_t offset, off_t size)
49 {
50 	TRACE(("%p - BPartitioningInfo::SetTo(offset = %lld, size = %lld)\n", this, offset, size));
51 
52 	fPartitionID = -1;
53 	delete[] fSpaces;
54 
55 	if (size > 0) {
56 		fSpaces = new(nothrow) partitionable_space_data[1];
57 		if (!fSpaces)
58 			return B_NO_MEMORY;
59 
60 		fCount = 1;
61 		fSpaces[0].offset = offset;
62 		fSpaces[0].size = size;
63 	} else {
64 		fSpaces = NULL;
65 		fCount = 0;
66 	}
67 
68 	fCapacity = fCount;
69 
70 	return B_OK;
71 }
72 
73 
74 // Unset
75 void
76 BPartitioningInfo::Unset()
77 {
78 	delete[] fSpaces;
79 	fPartitionID = -1;
80 	fSpaces = NULL;
81 	fCount = 0;
82 	fCapacity = 0;
83 }
84 
85 
86 // ExcludeOccupiedSpace
87 status_t
88 BPartitioningInfo::ExcludeOccupiedSpace(off_t offset, off_t size)
89 {
90 	if (size <= 0)
91 		return B_OK;
92 
93 	TRACE(("%p - BPartitioningInfo::ExcludeOccupiedSpace(offset = %lld, "
94 		"size = %lld)\n", this, offset, size));
95 
96 	int32 leftIndex = -1;
97 	int32 rightIndex = -1;
98 	for (int32 i = 0; i < fCount; i++) {
99 		if (leftIndex == -1
100 			&& offset < fSpaces[i].offset + fSpaces[i].size) {
101 			leftIndex = i;
102 		}
103 
104 		if (fSpaces[i].offset < offset + size)
105 			rightIndex = i;
106 	}
107 
108 	TRACE(("  leftIndex = %ld, rightIndex = %ld\n", leftIndex, rightIndex));
109 
110 	// If there's no intersection with any free space, we're done.
111 	if (leftIndex == -1 || rightIndex == -1 || leftIndex > rightIndex)
112 		return B_OK;
113 
114 	partitionable_space_data& leftSpace = fSpaces[leftIndex];
115 	partitionable_space_data& rightSpace = fSpaces[rightIndex];
116 
117 	off_t rightSpaceEnd = rightSpace.offset + rightSpace.size;
118 
119 	// special case: split a single space in two
120 	if (leftIndex == rightIndex && leftSpace.offset < offset
121 		&& rightSpaceEnd > offset + size) {
122 
123 		TRACE(("  splitting space at %ld\n", leftIndex));
124 
125 		// add a space after this one
126 		status_t error = _InsertSpaces(leftIndex + 1, 1);
127 		if (error != B_OK)
128 			return error;
129 
130 		// IMPORTANT: after calling _InsertSpace(), one can not
131 		// use the partitionable_space_data references "leftSpace"
132 		// and "rightSpace" anymore (declared above)!
133 
134 		partitionable_space_data& space = fSpaces[leftIndex];
135 		partitionable_space_data& newSpace = fSpaces[leftIndex + 1];
136 
137 		space.size = offset - space.offset;
138 
139 		newSpace.offset = offset + size;
140 		newSpace.size = rightSpaceEnd - newSpace.offset;
141 
142 		#ifdef TRACING
143 			PrintToStream();
144 		#endif
145 		return B_OK;
146 	}
147 
148 	// check whether the first affected space is eaten completely
149 	int32 deleteFirst = leftIndex;
150 	if (leftSpace.offset < offset) {
151 		leftSpace.size = offset - leftSpace.offset;
152 
153 		TRACE(("  left space remains, new size is %lld\n", leftSpace.size));
154 
155 		deleteFirst++;
156 	}
157 
158 	// check whether the last affected space is eaten completely
159 	int32 deleteLast = rightIndex;
160 	if (rightSpaceEnd > offset + size) {
161 		rightSpace.offset = offset + size;
162 		rightSpace.size = rightSpaceEnd - rightSpace.offset;
163 
164 		TRACE(("  right space remains, new offset = %lld, size = %lld\n",
165 			rightSpace.offset, rightSpace.size));
166 
167 		deleteLast--;
168 	}
169 
170 	// remove all spaces that are completely eaten
171 	if (deleteFirst <= deleteLast)
172 		_RemoveSpaces(deleteFirst, deleteLast - deleteFirst + 1);
173 
174 	#ifdef TRACING
175 		PrintToStream();
176 	#endif
177 	return B_OK;
178 }
179 
180 
181 // PartitionID
182 partition_id
183 BPartitioningInfo::PartitionID() const
184 {
185 	return fPartitionID;
186 }
187 
188 
189 // GetPartitionableSpaceAt
190 status_t
191 BPartitioningInfo::GetPartitionableSpaceAt(int32 index, off_t *offset,
192 										   off_t *size) const
193 {
194 	if (!fSpaces)
195 		return B_NO_INIT;
196 	if (!offset || !size)
197 		return B_BAD_VALUE;
198 	if (index < 0 || index >= fCount)
199 		return B_BAD_INDEX;
200 	*offset = fSpaces[index].offset;
201 	*size = fSpaces[index].size;
202 	return B_OK;
203 }
204 
205 
206 // CountPartitionableSpaces
207 int32
208 BPartitioningInfo::CountPartitionableSpaces() const
209 {
210 	return fCount;
211 }
212 
213 
214 // PrintToStream
215 void
216 BPartitioningInfo::PrintToStream() const
217 {
218 	if (!fSpaces) {
219 		printf("BPartitioningInfo is not initialized\n");
220 		return;
221 	}
222 	printf("BPartitioningInfo has %ld spaces:\n", fCount);
223 	for (int32 i = 0; i < fCount; i++) {
224 		printf("  space at %ld: offset = %lld, size = %lld\n",
225 			i, fSpaces[i].offset, fSpaces[i].size);
226 	}
227 }
228 
229 
230 // #pragma mark -
231 
232 
233 // _InsertSpaces
234 status_t
235 BPartitioningInfo::_InsertSpaces(int32 index, int32 count)
236 {
237 	if (index <= 0 || index > fCount || count <= 0)
238 		return B_BAD_VALUE;
239 
240 	// If the capacity is sufficient, we just need to copy the spaces to create
241 	// a gap.
242 	if (fCount + count <= fCapacity) {
243 		memmove(fSpaces + index + count, fSpaces + index,
244 			(fCount - index) * sizeof(partitionable_space_data));
245 		fCount += count;
246 		return B_OK;
247 	}
248 
249 	// alloc new array
250 	int32 capacity = (fCount + count) * 2;
251 		// add a bit room for further resizing
252 
253 	partitionable_space_data* spaces
254 		= new(nothrow) partitionable_space_data[capacity];
255 	if (!spaces)
256 		return B_NO_MEMORY;
257 
258 	// copy items
259 	memcpy(spaces, fSpaces, index * sizeof(partitionable_space_data));
260 	memcpy(spaces + index + count, fSpaces + index,
261 		(fCount - index) * sizeof(partitionable_space_data));
262 
263 	delete[] fSpaces;
264 	fSpaces = spaces;
265 	fCapacity = capacity;
266 	fCount += count;
267 
268 	return B_OK;
269 }
270 
271 
272 // _RemoveSpaces
273 void
274 BPartitioningInfo::_RemoveSpaces(int32 index, int32 count)
275 {
276 	if (index < 0 || count <= 0 || index + count > fCount)
277 		return;
278 
279 	if (count < fCount) {
280 		int32 endIndex = index + count;
281 		memmove(fSpaces + index, fSpaces + endIndex,
282 			(fCount - endIndex) * sizeof(partitionable_space_data));
283 	}
284 
285 	fCount -= count;
286 }
287