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