xref: /haiku/src/kits/storage/Volume.cpp (revision e6eaad8615c4734498b9b800847d18bbe62782fa)
1 /*
2  * Copyright 2002-2009, Haiku Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Tyler Dauwalder
7  *		Ingo Weinhold
8  */
9 
10 
11 #include <errno.h>
12 #include <string.h>
13 
14 #include <Bitmap.h>
15 #include <Directory.h>
16 #include <fs_info.h>
17 #include <Node.h>
18 #include <Path.h>
19 #include <Volume.h>
20 
21 #include <storage_support.h>
22 #include <syscalls.h>
23 
24 #include <fs_interface.h>
25 
26 
27 // Creates an uninitialized BVolume object.
28 BVolume::BVolume()
29 	: fDevice((dev_t)-1),
30 	  fCStatus(B_NO_INIT)
31 {
32 }
33 
34 
35 // Creates a BVolume and initializes it to the volume specified by the
36 // supplied device ID.
37 BVolume::BVolume(dev_t device)
38 	: fDevice((dev_t)-1),
39 	  fCStatus(B_NO_INIT)
40 {
41 	SetTo(device);
42 }
43 
44 
45 // Creates a copy of the supplied BVolume object.
46 BVolume::BVolume(const BVolume &volume)
47 	: fDevice(volume.fDevice),
48 	  fCStatus(volume.fCStatus)
49 {
50 }
51 
52 
53 // Destroys the object and frees all associated resources.
54 BVolume::~BVolume()
55 {
56 }
57 
58 
59 // Returns the initialization status.
60 status_t
61 BVolume::InitCheck(void) const
62 {
63 	return fCStatus;
64 }
65 
66 
67 // Initializes the object to refer to the volume specified by the supplied
68 // device ID.
69 status_t
70 BVolume::SetTo(dev_t device)
71 {
72 	// uninitialize
73 	Unset();
74 	// check the parameter
75 	status_t error = (device >= 0 ? B_OK : B_BAD_VALUE);
76 	if (error == B_OK) {
77 		fs_info info;
78 		if (fs_stat_dev(device, &info) != 0)
79 			error = errno;
80 	}
81 	// set the new value
82 	if (error == B_OK)
83 		fDevice = device;
84 	// set the init status variable
85 	fCStatus = error;
86 	return fCStatus;
87 }
88 
89 
90 // Brings the BVolume object to an uninitialized state.
91 void
92 BVolume::Unset()
93 {
94 	fDevice = (dev_t)-1;
95 	fCStatus = B_NO_INIT;
96 }
97 
98 
99 // Returns the device ID of the volume the object refers to.
100 dev_t
101 BVolume::Device() const
102 {
103 	return fDevice;
104 }
105 
106 
107 // Writes the root directory of the volume referred to by this object into
108 // directory.
109 status_t
110 BVolume::GetRootDirectory(BDirectory *directory) const
111 {
112 	// check parameter and initialization
113 	status_t error = (directory && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
114 	// get FS stat
115 	fs_info info;
116 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
117 		error = errno;
118 	// init the directory
119 	if (error == B_OK) {
120 		node_ref ref;
121 		ref.device = info.dev;
122 		ref.node = info.root;
123 		error = directory->SetTo(&ref);
124 	}
125 	return error;
126 }
127 
128 
129 // Returns the total storage capacity of the volume.
130 off_t
131 BVolume::Capacity() const
132 {
133 	// check initialization
134 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
135 	// get FS stat
136 	fs_info info;
137 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
138 		error = errno;
139 	return (error == B_OK ? info.total_blocks * info.block_size : error);
140 }
141 
142 
143 // Returns the amount of unused space on the volume (in bytes).
144 off_t
145 BVolume::FreeBytes() const
146 {
147 	// check initialization
148 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
149 	// get FS stat
150 	fs_info info;
151 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
152 		error = errno;
153 	return (error == B_OK ? info.free_blocks * info.block_size : error);
154 }
155 
156 
157 // Returns the size of one block (in bytes).
158 off_t
159 BVolume::BlockSize() const
160 {
161 	// check initialization
162 	if (InitCheck() != B_OK)
163 		return B_NO_INIT;
164 
165 	// get FS stat
166 	fs_info info;
167 	if (fs_stat_dev(fDevice, &info) != 0)
168 		return errno;
169 
170 	return info.block_size;
171 }
172 
173 
174 // Copies the name of the volume into the provided buffer.
175 status_t
176 BVolume::GetName(char *name) const
177 {
178 	// check parameter and initialization
179 	status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
180 	// get FS stat
181 	fs_info info;
182 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
183 		error = errno;
184 	// copy the name
185 	if (error == B_OK)
186 		strncpy(name, info.volume_name, B_FILE_NAME_LENGTH);
187 	return error;
188 }
189 
190 
191 // Sets the name of the volume.
192 status_t
193 BVolume::SetName(const char *name)
194 {
195 	// check initialization
196 	if (!name || InitCheck() != B_OK)
197 		return B_BAD_VALUE;
198 	if (strlen(name) >= B_FILE_NAME_LENGTH)
199 		return B_NAME_TOO_LONG;
200 	// get the FS stat (including the old name) first
201 	fs_info oldInfo;
202 	if (fs_stat_dev(fDevice, &oldInfo) != 0)
203 		return errno;
204 	if (strcmp(name, oldInfo.volume_name) == 0)
205 		return B_OK;
206 	// set the volume name
207 	fs_info newInfo;
208 	strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name));
209 	status_t error = _kern_write_fs_info(fDevice, &newInfo,
210 		FS_WRITE_FSINFO_NAME);
211 	if (error != B_OK)
212 		return error;
213 
214 	// change the name of the mount point
215 
216 	// R5 implementation checks if an entry with the volume's old name
217 	// exists in the root directory and renames that entry, if it is indeed
218 	// the mount point of the volume (or a link referring to it). In all other
219 	// cases, nothing is done (even if the mount point is named like the
220 	// volume, but lives in a different directory).
221 	// We follow suit for the time being.
222 	// NOTE: If the volume name itself is actually "boot", then this code
223 	// tries to rename /boot, but that is prevented in the kernel.
224 
225 	BPath entryPath;
226 	BEntry entry;
227 	BEntry traversedEntry;
228 	node_ref entryNodeRef;
229 	if (BPrivate::Storage::check_entry_name(name) == B_OK
230 		&& BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK
231 		&& entryPath.SetTo("/", oldInfo.volume_name) == B_OK
232 		&& entry.SetTo(entryPath.Path(), false) == B_OK
233 		&& entry.Exists()
234 		&& traversedEntry.SetTo(entryPath.Path(), true) == B_OK
235 		&& traversedEntry.GetNodeRef(&entryNodeRef) == B_OK
236 		&& entryNodeRef.device == fDevice
237 		&& entryNodeRef.node == oldInfo.root) {
238 		entry.Rename(name, false);
239 	}
240 	return error;
241 }
242 
243 
244 // Writes the volume's icon into icon.
245 status_t
246 BVolume::GetIcon(BBitmap *icon, icon_size which) const
247 {
248 	// check initialization
249 	if (InitCheck() != B_OK)
250 		return B_NO_INIT;
251 
252 	// get FS stat for the device name
253 	fs_info info;
254 	if (fs_stat_dev(fDevice, &info) != 0)
255 		return errno;
256 
257 	// get the icon
258 	return get_device_icon(info.device_name, icon, which);
259 }
260 
261 
262 status_t
263 BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const
264 {
265 	// check initialization
266 	if (InitCheck() != B_OK)
267 		return B_NO_INIT;
268 
269 	// get FS stat for the device name
270 	fs_info info;
271 	if (fs_stat_dev(fDevice, &info) != 0)
272 		return errno;
273 
274 	// get the icon
275 	return get_device_icon(info.device_name, _data, _size, _type);
276 }
277 
278 
279 // Returns whether or not the volume is removable.
280 bool
281 BVolume::IsRemovable() const
282 {
283 	// check initialization
284 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
285 	// get FS stat
286 	fs_info info;
287 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
288 		error = errno;
289 	return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE));
290 }
291 
292 
293 // Returns whether or not the volume is read-only.
294 bool
295 BVolume::IsReadOnly(void) const
296 {
297 	// check initialization
298 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
299 	// get FS stat
300 	fs_info info;
301 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
302 		error = errno;
303 	return (error == B_OK && (info.flags & B_FS_IS_READONLY));
304 }
305 
306 
307 // Returns whether or not the volume is persistent.
308 bool
309 BVolume::IsPersistent(void) const
310 {
311 	// check initialization
312 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
313 	// get FS stat
314 	fs_info info;
315 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
316 		error = errno;
317 	return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT));
318 }
319 
320 
321 // Returns whether or not the volume is shared.
322 bool
323 BVolume::IsShared(void) const
324 {
325 	// check initialization
326 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
327 	// get FS stat
328 	fs_info info;
329 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
330 		error = errno;
331 	return (error == B_OK && (info.flags & B_FS_IS_SHARED));
332 }
333 
334 
335 // Returns whether or not the volume supports MIME-types.
336 bool
337 BVolume::KnowsMime(void) const
338 {
339 	// check initialization
340 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
341 	// get FS stat
342 	fs_info info;
343 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
344 		error = errno;
345 	return (error == B_OK && (info.flags & B_FS_HAS_MIME));
346 }
347 
348 
349 // Returns whether or not the volume supports attributes.
350 bool
351 BVolume::KnowsAttr(void) const
352 {
353 	// check initialization
354 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
355 	// get FS stat
356 	fs_info info;
357 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
358 		error = errno;
359 	return (error == B_OK && (info.flags & B_FS_HAS_ATTR));
360 }
361 
362 
363 // Returns whether or not the volume supports queries.
364 bool
365 BVolume::KnowsQuery(void) const
366 {
367 	// check initialization
368 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
369 	// get FS stat
370 	fs_info info;
371 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
372 		error = errno;
373 	return (error == B_OK && (info.flags & B_FS_HAS_QUERY));
374 }
375 
376 
377 // Returns whether or not the supplied BVolume object is a equal
378 // to this object.
379 bool
380 BVolume::operator==(const BVolume &volume) const
381 {
382 	return ((InitCheck() != B_OK && volume.InitCheck() != B_OK)
383 			|| fDevice == volume.fDevice);
384 }
385 
386 // Returns whether or not the supplied BVolume object is NOT equal
387 // to this object.
388 bool
389 BVolume::operator!=(const BVolume &volume) const
390 {
391 	return !(*this == volume);
392 }
393 
394 
395 // Assigns the supplied BVolume object to this volume.
396 BVolume&
397 BVolume::operator=(const BVolume &volume)
398 {
399 	if (&volume != this) {
400 		this->fDevice = volume.fDevice;
401 		this->fCStatus = volume.fCStatus;
402 	}
403 	return *this;
404 }
405 
406 
407 // FBC
408 void BVolume::_TurnUpTheVolume1() {}
409 void BVolume::_TurnUpTheVolume2() {}
410 void BVolume::_TurnUpTheVolume3() {}
411 void BVolume::_TurnUpTheVolume4() {}
412 void BVolume::_TurnUpTheVolume5() {}
413 void BVolume::_TurnUpTheVolume6() {}
414 void BVolume::_TurnUpTheVolume7() {}
415 void BVolume::_TurnUpTheVolume8() {}
416