xref: /haiku/src/kits/storage/Node.cpp (revision 5e96d7d537fbec23bad4ae9b4c8e7b02e769f0c6)
1 /*
2  * Copyright 2002-2011, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Tyler Dauwalder
7  *		Ingo Weinhold, bonefish@users.sf.net
8  */
9 
10 
11 #include <Node.h>
12 
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <new>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include <compat/sys/stat.h>
20 
21 #include <Directory.h>
22 #include <Entry.h>
23 #include <fs_attr.h>
24 #include <String.h>
25 #include <TypeConstants.h>
26 
27 #include <syscalls.h>
28 
29 #include "storage_support.h"
30 
31 
32 //	#pragma mark - node_ref
33 
34 
35 node_ref::node_ref()
36 		: device((dev_t)-1),
37 		  node((ino_t)-1)
38 {
39 }
40 
41 
42 node_ref::node_ref(dev_t device, ino_t node)
43 	:
44 	device(device),
45 	node(node)
46 {
47 }
48 
49 
50 node_ref::node_ref(const node_ref &ref)
51 		: device((dev_t)-1),
52 		  node((ino_t)-1)
53 {
54 	*this = ref;
55 }
56 
57 // ==
58 bool
59 node_ref::operator==(const node_ref &ref) const
60 {
61 	return (device == ref.device && node == ref.node);
62 }
63 
64 // !=
65 bool
66 node_ref::operator!=(const node_ref &ref) const
67 {
68 	return !(*this == ref);
69 }
70 
71 
72 bool
73 node_ref::operator<(const node_ref& other) const
74 {
75 	if (this->device != other.device)
76 		return this->device < other.device;
77 	return this->node < other.node;
78 }
79 
80 
81 // =
82 node_ref&
83 node_ref::operator=(const node_ref &ref)
84 {
85 	device = ref.device;
86 	node = ref.node;
87 	return *this;
88 }
89 
90 
91 //	#pragma mark - BNode
92 
93 
94 BNode::BNode()
95 	 : fFd(-1),
96 	   fAttrFd(-1),
97 	   fCStatus(B_NO_INIT)
98 {
99 }
100 
101 
102 BNode::BNode(const entry_ref *ref)
103 	 : fFd(-1),
104 	   fAttrFd(-1),
105 	   fCStatus(B_NO_INIT)
106 {
107 	SetTo(ref);
108 }
109 
110 
111 BNode::BNode(const BEntry *entry)
112 	 : fFd(-1),
113 	   fAttrFd(-1),
114 	   fCStatus(B_NO_INIT)
115 {
116 	SetTo(entry);
117 }
118 
119 
120 BNode::BNode(const char *path)
121 	 : fFd(-1),
122 	   fAttrFd(-1),
123 	   fCStatus(B_NO_INIT)
124 {
125 	SetTo(path);
126 }
127 
128 
129 BNode::BNode(const BDirectory *dir, const char *path)
130 	 : fFd(-1),
131 	   fAttrFd(-1),
132 	   fCStatus(B_NO_INIT)
133 {
134 	SetTo(dir, path);
135 }
136 
137 
138 BNode::BNode(const BNode &node)
139 	 : fFd(-1),
140 	   fAttrFd(-1),
141 	   fCStatus(B_NO_INIT)
142 {
143 	*this = node;
144 }
145 
146 
147 BNode::~BNode()
148 {
149 	Unset();
150 }
151 
152 
153 status_t
154 BNode::InitCheck() const
155 {
156 	return fCStatus;
157 }
158 
159 
160 status_t
161 BNode::SetTo(const entry_ref *ref)
162 {
163 	return _SetTo(ref, false);
164 }
165 
166 
167 status_t
168 BNode::SetTo(const BEntry *entry)
169 {
170 	if (!entry) {
171 		Unset();
172 		return (fCStatus = B_BAD_VALUE);
173 	}
174 	return _SetTo(entry->fDirFd, entry->fName, false);
175 }
176 
177 
178 status_t
179 BNode::SetTo(const char *path)
180 {
181 	return _SetTo(-1, path, false);
182 }
183 
184 
185 status_t
186 BNode::SetTo(const BDirectory *dir, const char *path)
187 {
188 	if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) {
189 		Unset();
190 		return (fCStatus = B_BAD_VALUE);
191 	}
192 	return _SetTo(dir->fDirFd, path, false);
193 }
194 
195 
196 void
197 BNode::Unset()
198 {
199 	close_fd();
200 	fCStatus = B_NO_INIT;
201 }
202 
203 
204 status_t
205 BNode::Lock()
206 {
207 	if (fCStatus != B_OK)
208 		return fCStatus;
209 	return _kern_lock_node(fFd);
210 }
211 
212 
213 status_t
214 BNode::Unlock()
215 {
216 	if (fCStatus != B_OK)
217 		return fCStatus;
218 	return _kern_unlock_node(fFd);
219 }
220 
221 
222 status_t
223 BNode::Sync()
224 {
225 	return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_fsync(fFd);
226 }
227 
228 
229 ssize_t
230 BNode::WriteAttr(const char *attr, type_code type, off_t offset,
231 				 const void *buffer, size_t len)
232 {
233 	if (fCStatus != B_OK)
234 		return B_FILE_ERROR;
235 	if (!attr || !buffer)
236 		return B_BAD_VALUE;
237 
238 	ssize_t result = fs_write_attr(fFd, attr, type, offset, buffer, len);
239 	return result < 0 ? errno : result;
240 }
241 
242 
243 ssize_t
244 BNode::ReadAttr(const char *attr, type_code type, off_t offset,
245 				void *buffer, size_t len) const
246 {
247 	if (fCStatus != B_OK)
248 		return B_FILE_ERROR;
249 	if (!attr || !buffer)
250 		return B_BAD_VALUE;
251 
252 	ssize_t result = fs_read_attr(fFd, attr, type, offset, buffer, len );
253 	return result == -1 ? errno : result;
254 }
255 
256 
257 status_t
258 BNode::RemoveAttr(const char *name)
259 {
260 	return fCStatus != B_OK ? B_FILE_ERROR : _kern_remove_attr(fFd, name);
261 }
262 
263 
264 status_t
265 BNode::RenameAttr(const char *oldname, const char *newname)
266 {
267 	if (fCStatus != B_OK)
268 		return B_FILE_ERROR;
269 
270 	return _kern_rename_attr(fFd, oldname, fFd, newname);
271 }
272 
273 
274 status_t
275 BNode::GetAttrInfo(const char *name, struct attr_info *info) const
276 {
277 	if (fCStatus != B_OK)
278 		return B_FILE_ERROR;
279 	if (!name || !info)
280 		return B_BAD_VALUE;
281 
282 	return fs_stat_attr(fFd, name, info) < 0 ? errno : B_OK ;
283 }
284 
285 
286 status_t
287 BNode::GetNextAttrName(char *buffer)
288 {
289 	// We're allowed to assume buffer is at least
290 	// B_ATTR_NAME_LENGTH chars long, but NULLs
291 	// are not acceptable.
292 	if (buffer == NULL)
293 		return B_BAD_VALUE;	// /new R5 crashed when passed NULL
294 	if (InitAttrDir() != B_OK)
295 		return B_FILE_ERROR;
296 
297 	BPrivate::Storage::LongDirEntry entry;
298 	ssize_t result = _kern_read_dir(fAttrFd, &entry, sizeof(entry), 1);
299 	if (result < 0)
300 		return result;
301 	if (result == 0)
302 		return B_ENTRY_NOT_FOUND;
303 	strlcpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH);
304 	return B_OK;
305 }
306 
307 
308 status_t
309 BNode::RewindAttrs()
310 {
311 	if (InitAttrDir() != B_OK)
312 		return B_FILE_ERROR;
313 
314 	return _kern_rewind_dir(fAttrFd);
315 }
316 
317 
318 status_t
319 BNode::WriteAttrString(const char *name, const BString *data)
320 {
321 	status_t error = (!name || !data)  ? B_BAD_VALUE : B_OK;
322 	if (error == B_OK) {
323 		int32 len = data->Length() + 1;
324 		ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(),
325 										len);
326 		if (sizeWritten != len)
327 			error = sizeWritten;
328 	}
329 	return error;
330 }
331 
332 
333 status_t
334 BNode::ReadAttrString(const char *name, BString *result) const
335 {
336 	if (!name || !result)
337 		return B_BAD_VALUE;
338 
339 	attr_info info;
340 	status_t error;
341 
342 	error = GetAttrInfo(name, &info);
343 	if (error != B_OK)
344 		return error;
345 
346 	// Lock the string's buffer so we can meddle with it
347 	char *data = result->LockBuffer(info.size + 1);
348 	if (!data)
349 		return B_NO_MEMORY;
350 
351 	// Read the attribute
352 	ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size);
353 	// Check for failure
354 	if (bytes < 0) {
355 		error = bytes;
356 		bytes = 0;	// In this instance, we simply clear the string
357 	} else
358 		error = B_OK;
359 
360 	// Null terminate the new string just to be sure (since it *is*
361 	// possible to read and write non-NULL-terminated strings)
362 	data[bytes] = 0;
363 	result->UnlockBuffer();
364 	return error;
365 }
366 
367 
368 BNode&
369 BNode::operator=(const BNode &node)
370 {
371 	// No need to do any assignment if already equal
372 	if (*this == node)
373 		return *this;
374 
375 	// Close down out current state
376 	Unset();
377 	// We have to manually dup the node, because R5::BNode::Dup()
378 	// is not declared to be const (which IMO is retarded).
379 	fFd = _kern_dup(node.fFd);
380 	fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ;
381 	return *this;
382 }
383 
384 
385 bool
386 BNode::operator==(const BNode &node) const
387 {
388 	if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT)
389 		return true;
390 	if (fCStatus == B_OK && node.InitCheck() == B_OK) {
391 		// compare the node_refs
392 		node_ref ref1, ref2;
393 		if (GetNodeRef(&ref1) != B_OK)
394 			return false;
395 		if (node.GetNodeRef(&ref2) != B_OK)
396 			return false;
397 		return (ref1 == ref2);
398 	}
399 	return false;
400 }
401 
402 
403 bool
404 BNode::operator!=(const BNode &node) const
405 {
406 	return !(*this == node);
407 }
408 
409 
410 int
411 BNode::Dup()
412 {
413 	int fd = _kern_dup(fFd);
414 	return (fd >= 0 ? fd : -1);	// comply with R5 return value
415 }
416 
417 
418 /*! (currently unused) */
419 void BNode::_RudeNode1() { }
420 void BNode::_RudeNode2() { }
421 void BNode::_RudeNode3() { }
422 void BNode::_RudeNode4() { }
423 void BNode::_RudeNode5() { }
424 void BNode::_RudeNode6() { }
425 
426 
427 status_t
428 BNode::set_fd(int fd)
429 {
430 	if (fFd != -1)
431 		close_fd();
432 	fFd = fd;
433 	return B_OK;
434 }
435 
436 
437 void
438 BNode::close_fd()
439 {
440 	if (fAttrFd >= 0) {
441 		_kern_close(fAttrFd);
442 		fAttrFd = -1;
443 	}
444 	if (fFd >= 0) {
445 		_kern_close(fFd);
446 		fFd = -1;
447 	}
448 }
449 
450 
451 void
452 BNode::set_status(status_t newStatus)
453 {
454 	fCStatus = newStatus;
455 }
456 
457 
458 status_t
459 BNode::_SetTo(int fd, const char *path, bool traverse)
460 {
461 	Unset();
462 	status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE);
463 	if (error == B_OK) {
464 		int traverseFlag = (traverse ? 0 : O_NOTRAVERSE);
465 		fFd = _kern_open(fd, path, O_RDWR | O_CLOEXEC | traverseFlag, 0);
466 		if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) {
467 			// opening read-write failed, re-try read-only
468 			fFd = _kern_open(fd, path, O_RDONLY | O_CLOEXEC | traverseFlag, 0);
469 		}
470 		if (fFd < 0)
471 			error = fFd;
472 	}
473 	return fCStatus = error;
474 }
475 
476 
477 status_t
478 BNode::_SetTo(const entry_ref *ref, bool traverse)
479 {
480 	Unset();
481 	status_t error = (ref ? B_OK : B_BAD_VALUE);
482 	if (error == B_OK) {
483 		int traverseFlag = (traverse ? 0 : O_NOTRAVERSE);
484 		fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
485 			O_RDWR | O_CLOEXEC | traverseFlag, 0);
486 		if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) {
487 			// opening read-write failed, re-try read-only
488 			fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
489 				O_RDONLY | O_CLOEXEC | traverseFlag, 0);
490 		}
491 		if (fFd < 0)
492 			error = fFd;
493 	}
494 	return fCStatus = error;
495 }
496 
497 
498 status_t
499 BNode::set_stat(struct stat &st, uint32 what)
500 {
501 	if (fCStatus != B_OK)
502 		return B_FILE_ERROR;
503 
504 	return _kern_write_stat(fFd, NULL, false, &st, sizeof(struct stat),
505 		what);
506 }
507 
508 
509 status_t
510 BNode::InitAttrDir()
511 {
512 	if (fCStatus == B_OK && fAttrFd < 0) {
513 		fAttrFd = _kern_open_attr_dir(fFd, NULL, false);
514 		if (fAttrFd < 0)
515 			return fAttrFd;
516 
517 		// set close on exec flag
518 		fcntl(fAttrFd, F_SETFD, FD_CLOEXEC);
519 	}
520 	return fCStatus;
521 }
522 
523 
524 status_t
525 BNode::_GetStat(struct stat *st) const
526 {
527 	return fCStatus != B_OK
528 		? fCStatus
529 		: _kern_read_stat(fFd, NULL, false, st, sizeof(struct stat));
530 }
531 
532 
533 status_t
534 BNode::_GetStat(struct stat_beos *st) const
535 {
536 	struct stat newStat;
537 	status_t error = _GetStat(&newStat);
538 	if (error != B_OK)
539 		return error;
540 
541 	convert_to_stat_beos(&newStat, st);
542 	return B_OK;
543 }
544 
545 
546 // #pragma mark - symbol versions
547 
548 
549 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
550 #	if __GNUC__ == 2	// gcc 2
551 
552 	B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP4stat",
553 		"GetStat__C5BNodeP4stat@@LIBBE_TEST");
554 
555 #	else	// gcc 4
556 
557 	B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP4stat",
558 		"_ZNK5BNode7GetStatEP4stat@@LIBBE_TEST");
559 
560 #	endif	// gcc 4
561 #else	// !HAIKU_TARGET_PLATFORM_LIBBE_TEST
562 #	if __GNUC__ == 2	// gcc 2
563 
564 	// BeOS compatible GetStat()
565 	B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP9stat_beos",
566 		"GetStat__C5BNodeP4stat@LIBBE_BASE");
567 
568 	// Haiku GetStat()
569 	B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP4stat",
570 		"GetStat__C5BNodeP4stat@@LIBBE_1_ALPHA1");
571 
572 #	else	// gcc 4
573 
574 	// BeOS compatible GetStat()
575 	B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP9stat_beos",
576 		"_ZNK5BNode7GetStatEP4stat@LIBBE_BASE");
577 
578 	// Haiku GetStat()
579 	B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP4stat",
580 		"_ZNK5BNode7GetStatEP4stat@@LIBBE_1_ALPHA1");
581 
582 #	endif	// gcc 4
583 #endif	// !HAIKU_TARGET_PLATFORM_LIBBE_TEST
584