xref: /haiku/src/kits/storage/disk_device/PartitioningInfo.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 
6 #include <string.h>
7 
8 #include <new>
9 
10 #include <PartitioningInfo.h>
11 
12 #include <syscalls.h>
13 #include <disk_device_manager/ddm_userland_interface.h>
14 
15 
16 using namespace std;
17 
18 
19 // constructor
20 BPartitioningInfo::BPartitioningInfo()
21 	: fPartitionID(-1),
22 	  fSpaces(NULL),
23 	  fCount(0),
24 	  fCapacity(0)
25 {
26 }
27 
28 
29 // destructor
30 BPartitioningInfo::~BPartitioningInfo()
31 {
32 	Unset();
33 }
34 
35 
36 // SetTo
37 status_t
38 BPartitioningInfo::SetTo(off_t offset, off_t size)
39 {
40 	fPartitionID = -1;
41 	delete[] fSpaces;
42 
43 	if (size > 0) {
44 		fSpaces = new(nothrow) partitionable_space_data[1];
45 		if (!fSpaces)
46 			return B_NO_MEMORY;
47 
48 		fCount = 1;
49 		fSpaces[0].offset = offset;
50 		fSpaces[0].size = size;
51 	} else {
52 		fSpaces = NULL;
53 		fCount = 0;
54 	}
55 
56 	fCapacity = fCount;
57 
58 	return B_OK;
59 }
60 
61 
62 // Unset
63 void
64 BPartitioningInfo::Unset()
65 {
66 	delete[] fSpaces;
67 	fPartitionID = -1;
68 	fSpaces = NULL;
69 	fCount = 0;
70 	fCapacity = 0;
71 }
72 
73 
74 // ExcludeOccupiedSpace
75 status_t
76 BPartitioningInfo::ExcludeOccupiedSpace(off_t offset, off_t size)
77 {
78 	if (size <= 0)
79 		return B_OK;
80 
81 	int32 leftIndex = -1;
82 	int32 rightIndex = -1;
83 	for (int32 i = 0; i < fCount; i++) {
84 		if (leftIndex == -1
85 			&& offset < fSpaces[i].offset + fSpaces[i].size) {
86 			leftIndex = i;
87 		}
88 
89 		if (fSpaces[i].offset < offset + size)
90 			rightIndex = i;
91 	}
92 
93 	// If there's no intersection with any free space, we're done.
94 	if (leftIndex == -1 || rightIndex == -1 || leftIndex > rightIndex)
95 		return B_OK;
96 
97 	partitionable_space_data& leftSpace = fSpaces[leftIndex];
98 	partitionable_space_data& rightSpace = fSpaces[rightIndex];
99 
100 	off_t rightSpaceEnd = rightSpace.offset + rightSpace.size;
101 
102 	// special case: split a single space in two
103 	if (leftIndex == rightIndex && leftSpace.offset < offset
104 		&& rightSpaceEnd > offset + size) {
105 		// add a space after this one
106 		status_t error = _InsertSpaces(leftIndex + 1, 1);
107 		if (error != B_OK)
108 			return error;
109 
110 		partitionable_space_data& space = fSpaces[leftIndex];
111 		partitionable_space_data& newSpace = fSpaces[leftIndex + 1];
112 
113 		space.size = offset - space.offset;
114 
115 		newSpace.offset = offset + size;
116 		newSpace.size = rightSpaceEnd - newSpace.offset;
117 
118 		return B_OK;
119 	}
120 
121 	// check whether the first affected space is eaten completely
122 	int32 deleteFirst = leftIndex;
123 	if (leftSpace.offset < offset) {
124 		leftSpace.size = offset - leftSpace.offset;
125 		deleteFirst++;
126 	}
127 
128 	// check whether the last affected space is eaten completely
129 	int32 deleteLast = rightIndex;
130 	if (rightSpaceEnd > offset + size) {
131 		rightSpace.offset = offset + size;
132 		rightSpace.size = rightSpaceEnd - rightSpace.offset;
133 		deleteLast--;
134 	}
135 
136 	// remove all spaces that are completely eaten
137 	if (deleteFirst <= deleteLast)
138 		_RemoveSpaces(deleteFirst, deleteLast - deleteFirst + 1);
139 
140 	return B_OK;
141 }
142 
143 
144 // PartitionID
145 partition_id
146 BPartitioningInfo::PartitionID() const
147 {
148 	return fPartitionID;
149 }
150 
151 
152 // GetPartitionableSpaceAt
153 status_t
154 BPartitioningInfo::GetPartitionableSpaceAt(int32 index, off_t *offset,
155 										   off_t *size) const
156 {
157 	if (!fSpaces || !offset || !size || index < 0 || index >= fCount)
158 		return B_BAD_VALUE;
159 	*offset = fSpaces[index].offset;
160 	*size = fSpaces[index].size;
161 	return B_OK;
162 }
163 
164 
165 // CountPartitionableSpaces
166 int32
167 BPartitioningInfo::CountPartitionableSpaces() const
168 {
169 	return fCount;
170 }
171 
172 
173 // _InsertSpaces
174 status_t
175 BPartitioningInfo::_InsertSpaces(int32 index, int32 count)
176 {
177 	if (index <= 0 || index > fCount || count <= 0)
178 		return B_BAD_VALUE;
179 
180 	// If the capacity is sufficient, we just need to copy the spaces to create
181 	// a gap.
182 	if (fCount + count <= fCapacity) {
183 		memmove(fSpaces + index + count, fSpaces + index, fCount - index);
184 		fCount += count;
185 		return B_OK;
186 	}
187 
188 	// alloc new array
189 	int32 capacity = (fCount + count) * 2;
190 		// add a bit room for further resizing
191 
192 	partitionable_space_data* spaces
193 		= new(nothrow) partitionable_space_data[capacity];
194 	if (!spaces)
195 		return B_NO_MEMORY;
196 
197 	// copy items
198 	memcpy(spaces, fSpaces, index);
199 	memcpy(spaces + index + count, fSpaces + index, fCount - index);
200 
201 	delete[] fSpaces;
202 	fSpaces = spaces;
203 	fCapacity = capacity;
204 	fCount += count;
205 
206 	return B_OK;
207 }
208 
209 
210 // _RemoveSpaces
211 void
212 BPartitioningInfo::_RemoveSpaces(int32 index, int32 count)
213 {
214 	if (index <= 0 || count <= 0 || index + count > fCount)
215 		return;
216 
217 	if (count < fCount) {
218 		int32 endIndex = index + count;
219 		memmove(fSpaces + index, fSpaces + endIndex, fCount - endIndex);
220 	}
221 
222 	fCount -= count;
223 }
224