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