xref: /haiku/src/kits/storage/NodeInfo.cpp (revision e39da397f5ff79f2db9f9a3ddf1852b6710578af)
1 /*
2  * Copyright 2002-2006, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, bonefish@users.sf.net
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 
11 #include <NodeInfo.h>
12 
13 #include <new>
14 #include <string.h>
15 
16 #include <MimeTypes.h>
17 #include <Bitmap.h>
18 #include <Entry.h>
19 #include <Node.h>
20 #include <Path.h>
21 #include <Rect.h>
22 
23 #include <fs_attr.h>
24 #include <fs_info.h>
25 
26 using namespace std;
27 
28 // attribute names
29 #define NI_BEOS "BEOS"
30 static const char *kNITypeAttribute			= NI_BEOS ":TYPE";
31 static const char *kNIPreferredAppAttribute	= NI_BEOS ":PREF_APP";
32 static const char *kNIAppHintAttribute		= NI_BEOS ":PPATH";
33 static const char *kNIMiniIconAttribute		= NI_BEOS ":M:STD_ICON";
34 static const char *kNILargeIconAttribute	= NI_BEOS ":L:STD_ICON";
35 
36 
37 /*!	\brief Creates an uninitialized BNodeInfo object.
38 
39 	After created a BNodeInfo with this, you should call SetTo().
40 
41 	\see SetTo(BNode *node)
42 */
43 BNodeInfo::BNodeInfo()
44 	:
45 	fNode(NULL),
46 	fCStatus(B_NO_INIT)
47 {
48 }
49 
50 // constructor
51 /*!	\brief Creates a BNodeInfo object and initializes it to the supplied node.
52 
53 	\param node The node to gather information on. Can be any flavor.
54 
55 	\see SetTo(BNode *node)
56 */
57 BNodeInfo::BNodeInfo(BNode *node)
58 	:
59 	fNode(NULL),
60 	fCStatus(B_NO_INIT)
61 {
62 	fCStatus = SetTo(node);
63 }
64 
65 // destructor
66 /*!	\brief Frees all resources associated with this object.
67 
68 	The BNode object passed to the constructor or to SetTo() is not deleted.
69 */
70 BNodeInfo::~BNodeInfo()
71 {
72 }
73 
74 // SetTo
75 /*!	\brief Initializes the BNodeInfo to the supplied node.
76 
77 	The BNodeInfo object does not copy the supplied object, but uses it
78 	directly. You must not delete the object you supply while the BNodeInfo
79 	does exist. The BNodeInfo does not take over ownership of the BNode and
80 	it doesn't delete it on destruction.
81 
82 	\param node The node to play with
83 
84 	\return
85 	- \c B_OK: Everything went fine.
86 	- \c B_BAD_VALUE: The node was bad.
87 */
88 status_t
89 BNodeInfo::SetTo(BNode *node)
90 {
91 	fNode = NULL;
92 	// check parameter
93 	fCStatus = (node && node->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
94 	if (fCStatus == B_OK)
95 		fNode = node;
96 	return fCStatus;
97 }
98 
99 // InitCheck
100 /*!	\brief returns whether the object has been properly initialized.
101 
102 	\return
103 	- \c B_OK: Everything went fine.
104 	- \c B_NO_INIT: The node is not properly initialized.
105 */
106 status_t
107 BNodeInfo::InitCheck() const
108 {
109 	return fCStatus;
110 }
111 
112 // GetType
113 /*!	\brief Gets the node's MIME type.
114 
115 	Writes the contents of the "BEOS:TYPE" attribute into the supplied buffer
116 	\a type.
117 
118 	\param type A pointer to a pre-allocated character buffer of size
119 		   \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the
120 		   node shall be written.
121 	\return
122 	- \c B_OK: Everything went fine.
123 	- \c B_NO_INIT: The object is not properly initialized.
124 	- \c B_BAD_VALUE: \c NULL \a type or the type string stored in the
125 	  attribute is longer than \c B_MIME_TYPE_LENGTH.
126 	- \c B_BAD_TYPE: The attribute the type string is stored in has the wrong
127 	   type.
128 	- \c B_ENTRY_NOT_FOUND: No type is set on the node.
129 	- other error codes
130 */
131 status_t
132 BNodeInfo::GetType(char *type) const
133 {
134 	// check parameter and initialization
135 	status_t error = (type ? B_OK : B_BAD_VALUE);
136 	if (error == B_OK && InitCheck() != B_OK)
137 		error = B_NO_INIT;
138 	// get the attribute info and check type and length of the attr contents
139 	attr_info attrInfo;
140 	if (error == B_OK)
141 		error = fNode->GetAttrInfo(kNITypeAttribute, &attrInfo);
142 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
143 		error = B_BAD_TYPE;
144 	if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
145 		error = B_BAD_DATA;
146 
147 	// read the data
148 	if (error == B_OK) {
149 		ssize_t read = fNode->ReadAttr(kNITypeAttribute, attrInfo.type, 0,
150 									   type, attrInfo.size);
151 		if (read < 0)
152 			error = read;
153 		else if (read != attrInfo.size)
154 			error = B_ERROR;
155 
156 		if (error == B_OK) {
157 			// attribute strings doesn't have to be null terminated
158 			type[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
159 		}
160 	}
161 	return error;
162 }
163 
164 // SetType
165 /*!	\brief Sets the node's MIME type.
166 
167 	The supplied string is written into the node's "BEOS:TYPE" attribute.
168 
169 	If \a type is \c NULL, the respective attribute is removed.
170 
171 	\param type The MIME type to be assigned to the node. Must not be longer
172 		   than \c B_MIME_TYPE_LENGTH (including the terminating null).
173 		   May be \c NULL.
174 	\return
175 	- \c B_OK: Everything went fine.
176 	- \c B_NO_INIT: The object is not properly initialized.
177 	- \c B_BAD_VALUE: \a type is longer than \c B_MIME_TYPE_LENGTH.
178 	- other error codes
179 */
180 status_t
181 BNodeInfo::SetType(const char *type)
182 {
183 	// check parameter and initialization
184 	status_t error = B_OK;
185 	if (error == B_OK && type && strlen(type) >= B_MIME_TYPE_LENGTH)
186 		error = B_BAD_VALUE;
187 	if (error == B_OK && InitCheck() != B_OK)
188 		error = B_NO_INIT;
189 
190 	// write/remove the attribute
191 	if (error == B_OK) {
192 		if (type) {
193 			size_t toWrite = strlen(type) + 1;
194 			ssize_t written = fNode->WriteAttr(kNITypeAttribute,
195 											   B_MIME_STRING_TYPE, 0, type,
196 											   toWrite);
197 			if (written < 0)
198 				error = written;
199 			else if (written != (ssize_t)toWrite)
200 				error = B_ERROR;
201 		} else
202 			error = fNode->RemoveAttr(kNITypeAttribute);
203 	}
204 	return error;
205 }
206 
207 // GetIcon
208 /*!	\brief Gets the node's icon.
209 
210 	The icon stored in the node's "BEOS:L:STD_ICON" (large) or
211 	"BEOS:M:STD_ICON" (mini) attribute is retrieved.
212 
213 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
214 		   to store the requested icon (16x16 for the mini and 32x32 for the
215 		   large icon).
216 	\param k Specifies the size of the icon to be retrieved: \c B_MINI_ICON
217 		   for the mini and \c B_LARGE_ICON for the large icon.
218 	\return
219 	- \c B_OK: Everything went fine.
220 	- \c B_NO_INIT: The object is not properly initialized.
221 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a k or bitmap
222 		 dimensions (\a icon) and icon size (\a k) do not match.
223 	- other error codes
224 */
225 status_t
226 BNodeInfo::GetIcon(BBitmap *icon, icon_size k) const
227 {
228 	status_t error = B_OK;
229 	// set some icon size related variables
230 	const char *attribute = NULL;
231 	BRect bounds;
232 	uint32 attrType = 0;
233 	size_t attrSize = 0;
234 	switch (k) {
235 		case B_MINI_ICON:
236 			attribute = kNIMiniIconAttribute;
237 			bounds.Set(0, 0, 15, 15);
238 			attrType = B_MINI_ICON_TYPE;
239 			attrSize = 16 * 16;
240 			break;
241 		case B_LARGE_ICON:
242 			attribute = kNILargeIconAttribute;
243 			bounds.Set(0, 0, 31, 31);
244 			attrType = B_LARGE_ICON_TYPE;
245 			attrSize = 32 * 32;
246 			break;
247 		default:
248 			error = B_BAD_VALUE;
249 			break;
250 	}
251 
252 	// check parameter and initialization
253 	if (error == B_OK
254 		&& (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
255 		error = B_BAD_VALUE;
256 	}
257 	if (error == B_OK && InitCheck() != B_OK)
258 		error = B_NO_INIT;
259 
260 	// get the attribute info and check type and size of the attr contents
261 	attr_info attrInfo;
262 	if (error == B_OK)
263 		error = fNode->GetAttrInfo(attribute, &attrInfo);
264 	if (error == B_OK && attrInfo.type != attrType)
265 		error = B_BAD_TYPE;
266 	if (error == B_OK && attrInfo.size != attrSize)
267 		error = B_BAD_DATA;
268 
269 	// read the attribute
270 	if (error == B_OK) {
271 		bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
272 		char *buffer = NULL;
273 		ssize_t read;
274 		if (otherColorSpace) {
275 			// other color space than stored in attribute
276 			buffer = new(nothrow) char[attrSize];
277 			if (!buffer)
278 				error = B_NO_MEMORY;
279 			if (error == B_OK) {
280 				read = fNode->ReadAttr(attribute, attrType, 0, buffer,
281 									   attrSize);
282 			}
283 		} else {
284 			read = fNode->ReadAttr(attribute, attrType, 0, icon->Bits(),
285 								   attrSize);
286 		}
287 		if (error == B_OK) {
288 			if (read < 0)
289 				error = read;
290 			else if (read != attrInfo.size)
291 				error = B_ERROR;
292 		}
293 		if (otherColorSpace) {
294 			// other color space than stored in attribute
295 			if (error == B_OK) {
296 				error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW,
297 										 0, B_CMAP8);
298 			}
299 			delete[] buffer;
300 		}
301 	}
302 	return error;
303 }
304 
305 // SetIcon
306 /*!	\brief Sets the node's icon.
307 
308 	The icon is stored in the node's "BEOS:L:STD_ICON" (large) or
309 	"BEOS:M:STD_ICON" (mini) attribute.
310 
311 	If \a icon is \c NULL, the respective attribute is removed.
312 
313 	\param icon A pointer to the BBitmap containing the icon to be set.
314 		   May be \c NULL.
315 	\param k Specifies the size of the icon to be set: \c B_MINI_ICON
316 		   for the mini and \c B_LARGE_ICON for the large icon.
317 	\return
318 	- \c B_OK: Everything went fine.
319 	- \c B_NO_INIT: The object is not properly initialized.
320 	- \c B_BAD_VALUE: Unknown icon size \a k or bitmap dimensions (\a icon)
321 		 and icon size (\a k) do not match.
322 	- other error codes
323 */
324 status_t
325 BNodeInfo::SetIcon(const BBitmap *icon, icon_size k)
326 {
327 	status_t error = B_OK;
328 	// set some icon size related variables
329 	const char *attribute = NULL;
330 	BRect bounds;
331 	uint32 attrType = 0;
332 	size_t attrSize = 0;
333 	switch (k) {
334 		case B_MINI_ICON:
335 			attribute = kNIMiniIconAttribute;
336 			bounds.Set(0, 0, 15, 15);
337 			attrType = B_MINI_ICON_TYPE;
338 			attrSize = 16 * 16;
339 			break;
340 		case B_LARGE_ICON:
341 			attribute = kNILargeIconAttribute;
342 			bounds.Set(0, 0, 31, 31);
343 			attrType = B_LARGE_ICON_TYPE;
344 			attrSize = 32 * 32;
345 			break;
346 		default:
347 			error = B_BAD_VALUE;
348 			break;
349 	}
350 
351 	// check parameter and initialization
352 	if (error == B_OK && icon
353 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
354 		error = B_BAD_VALUE;
355 	}
356 	if (error == B_OK && InitCheck() != B_OK)
357 		error = B_NO_INIT;
358 
359 	// write/remove the attribute
360 	if (error == B_OK) {
361 		if (icon) {
362 			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
363 			ssize_t written = 0;
364 			if (otherColorSpace) {
365 				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
366 				error = bitmap.InitCheck();
367 				if (error == B_OK)
368 					error = bitmap.ImportBits(icon);
369 				if (error == B_OK) {
370 					written = fNode->WriteAttr(attribute, attrType, 0,
371 											   bitmap.Bits(), attrSize);
372 				}
373 			} else {
374 				written = fNode->WriteAttr(attribute, attrType, 0,
375 										   icon->Bits(), attrSize);
376 			}
377 			if (error == B_OK) {
378 				if (written < 0)
379 					error = written;
380 				else if (written != (ssize_t)attrSize)
381 					error = B_ERROR;
382 			}
383 		} else	// no icon given => remove
384 			error = fNode->RemoveAttr(attribute);
385 	}
386 	return error;
387 }
388 
389 // GetPreferredApp
390 /*!	\brief Gets the node's preferred application.
391 
392 	Writes the contents of the "BEOS:PREF_APP" attribute into the supplied
393 	buffer \a signature. The preferred application is identifief by its
394 	signature.
395 
396 	\param signature A pointer to a pre-allocated character buffer of size
397 		   \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the
398 		   preferred application shall be written.
399 	\param verb Specifies the type of access the preferred application is
400 		   requested for. Currently only \c B_OPEN is meaningful.
401 	\return
402 	- \c B_OK: Everything went fine.
403 	- \c B_NO_INIT: The object is not properly initialized.
404 	- \c B_BAD_VALUE: \c NULL \a signature or bad app_verb \a verb.
405 	- other error codes
406 */
407 status_t
408 BNodeInfo::GetPreferredApp(char *signature, app_verb verb) const
409 {
410 	// check parameter and initialization
411 	status_t error = (signature && verb == B_OPEN ? B_OK : B_BAD_VALUE);
412 	if (error == B_OK && InitCheck() != B_OK)
413 		error = B_NO_INIT;
414 
415 	// get the attribute info and check type and length of the attr contents
416 	attr_info attrInfo;
417 	if (error == B_OK)
418 		error = fNode->GetAttrInfo(kNIPreferredAppAttribute, &attrInfo);
419 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
420 		error = B_BAD_TYPE;
421 	if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
422 		error = B_BAD_DATA;
423 
424 	// read the data
425 	if (error == B_OK) {
426 		ssize_t read = fNode->ReadAttr(kNIPreferredAppAttribute, attrInfo.type,
427 									   0, signature, attrInfo.size);
428 		if (read < 0)
429 			error = read;
430 		else if (read != attrInfo.size)
431 			error = B_ERROR;
432 
433 		if (error == B_OK) {
434 			// attribute strings doesn't have to be null terminated
435 			signature[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
436 		}
437 	}
438 	return error;
439 }
440 
441 // SetPreferredApp
442 /*!	\brief Sets the node's preferred application.
443 
444 	The supplied string is written into the node's "BEOS:PREF_APP" attribute.
445 
446 	If \a signature is \c NULL, the respective attribute is removed.
447 
448 	\param signature The signature of the preferred application to be set.
449 		   Must not be longer than \c B_MIME_TYPE_LENGTH (including the
450 		   terminating null). May be \c NULL.
451 	\param verb Specifies the type of access the preferred application shall
452 		   be set for. Currently only \c B_OPEN is meaningful.
453 	\return
454 	- \c B_OK: Everything went fine.
455 	- \c B_NO_INIT: The object is not properly initialized.
456 	- \c B_BAD_VALUE: \c NULL \a signature, \a signature is longer than
457 	  \c B_MIME_TYPE_LENGTH or bad app_verb \a verb.
458 	- other error codes
459 */
460 status_t
461 BNodeInfo::SetPreferredApp(const char *signature, app_verb verb)
462 {
463 	// check parameters and initialization
464 	status_t error = (verb == B_OPEN ? B_OK : B_BAD_VALUE);
465 	if (error == B_OK && signature && strlen(signature) >= B_MIME_TYPE_LENGTH)
466 		error = B_BAD_VALUE;
467 	if (error == B_OK && InitCheck() != B_OK)
468 		error = B_NO_INIT;
469 
470 	// write/remove the attribute
471 	if (error == B_OK) {
472 		if (signature) {
473 			size_t toWrite = strlen(signature) + 1;
474 			ssize_t written = fNode->WriteAttr(kNIPreferredAppAttribute,
475 											   B_MIME_STRING_TYPE, 0,
476 											   signature, toWrite);
477 			if (written < 0)
478 				error = written;
479 			else if (written != (ssize_t)toWrite)
480 				error = B_ERROR;
481 		} else
482 			error = fNode->RemoveAttr(kNIPreferredAppAttribute);
483 	}
484 	return error;
485 }
486 
487 // GetAppHint
488 /*!	\brief Returns a hint in form of and entry_ref to the application that
489 		   shall be used to open this node.
490 
491 	The path contained in the node's "BEOS:PPATH" attribute is converted into
492 	an entry_ref and returned in \a ref.
493 
494 	\param ref A pointer to a pre-allocated entry_ref into which the requested
495 		   app hint shall be written.
496 	\return
497 	- \c B_OK: Everything went fine.
498 	- \c B_NO_INIT: The object is not properly initialized.
499 	- \c B_BAD_VALUE: \c NULL \a ref.
500 	- other error codes
501 */
502 status_t
503 BNodeInfo::GetAppHint(entry_ref *ref) const
504 {
505 	// check parameter and initialization
506 	status_t error = (ref ? B_OK : B_BAD_VALUE);
507 	if (error == B_OK && InitCheck() != B_OK)
508 		error = B_NO_INIT;
509 
510 	// get the attribute info and check type and length of the attr contents
511 	attr_info attrInfo;
512 	if (error == B_OK)
513 		error = fNode->GetAttrInfo(kNIAppHintAttribute, &attrInfo);
514 	// NOTE: The attribute type should be B_STRING_TYPE, but R5 uses
515 	// B_MIME_STRING_TYPE.
516 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
517 		error = B_BAD_TYPE;
518 	if (error == B_OK && attrInfo.size > B_PATH_NAME_LENGTH)
519 		error = B_BAD_DATA;
520 
521 	// read the data
522 	if (error == B_OK) {
523 		char path[B_PATH_NAME_LENGTH];
524 		ssize_t read = fNode->ReadAttr(kNIAppHintAttribute, attrInfo.type, 0,
525 									   path, attrInfo.size);
526 		if (read < 0)
527 			error = read;
528 		else if (read != attrInfo.size)
529 			error = B_ERROR;
530 		// get the entry_ref for the path
531 		if (error == B_OK) {
532 			// attribute strings doesn't have to be null terminated
533 			path[min_c(attrInfo.size, B_PATH_NAME_LENGTH - 1)] = '\0';
534 			error = get_ref_for_path(path, ref);
535 		}
536 	}
537 	return error;
538 }
539 
540 // SetAppHint
541 /*!	\brief Sets the node's app hint.
542 
543 	The supplied entry_ref is converted into a path and stored in the node's
544 	"BEOS:PPATH" attribute.
545 
546 	If \a ref is \c NULL, the respective attribute is removed.
547 
548 	\param ref A pointer to an entry_ref referring to the application.
549 		   May be \c NULL.
550 	\return
551 	- \c B_OK: Everything went fine.
552 	- \c B_NO_INIT: The object is not properly initialized.
553 	- \c B_BAD_VALUE: \c NULL \a ref.
554 	- other error codes
555 */
556 status_t
557 BNodeInfo::SetAppHint(const entry_ref *ref)
558 {
559 	// check parameter and initialization
560 	status_t error = B_OK;
561 	if (error == B_OK && InitCheck() != B_OK)
562 		error = B_NO_INIT;
563 
564 	// write/remove the attribute
565 	if (error == B_OK) {
566 		if (ref) {
567 			BPath path;
568 			error = path.SetTo(ref);
569 			if (error == B_OK) {
570 				size_t toWrite = strlen(path.Path()) + 1;
571 				ssize_t written = fNode->WriteAttr(kNIAppHintAttribute,
572 												   B_MIME_STRING_TYPE, 0,
573 												   path.Path(), toWrite);
574 				if (written < 0)
575 					error = written;
576 				else if (written != (ssize_t)toWrite)
577 					error = B_ERROR;
578 			}
579 		} else
580 			error = fNode->RemoveAttr(kNIAppHintAttribute);
581 	}
582 	return error;
583 }
584 
585 // GetTrackerIcon
586 /*!	\brief Gets the icon which tracker displays.
587 
588 	This method tries real hard to find an icon for the node:
589 	- If the node has no type, return the icon for B_FILE_MIME_TYPE if it's a
590 	  regular file, for B_DIRECTORY_MIME_TYPE if it's a directory, etc. from
591 	  the MIME database. Even, if the node has an own icon!
592 	- Ask GetIcon().
593 	- Get the preferred application and ask the MIME database, if that
594 	  application has a special icon for the node's file type.
595 	- Ask the MIME database whether there is an icon for the node's file type.
596 	- Ask the MIME database for the preferred application for the node's
597 	  file type and whether this application has a special icon for the type.
598 	- Return the icon for whatever type of node (file/dir/etc.) from the MIME database.
599 	This list is processed in the given order and the icon the first
600 	successful attempt provides is returned. In case none of them yields an
601 	icon, this method fails. This is very unlikely though.
602 
603 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
604 		   to store the requested icon (16x16 for the mini and 32x32 for the
605 		   large icon).
606 	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
607 		   for the mini and \c B_LARGE_ICON for the large icon.
608 	\return
609 	- \c B_OK: Everything went fine.
610 	- \c B_NO_INIT: The object is not properly initialized.
611 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a iconSize or bitmap
612 		 dimensions (\a icon) and icon size (\a iconSize) do not match.
613 	- other error codes
614 */
615 status_t
616 BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size iconSize) const
617 {
618 	// set some icon size related variables
619 	status_t error = B_OK;
620 	BRect bounds;
621 	switch (iconSize) {
622 		case B_MINI_ICON:
623 			bounds.Set(0, 0, 15, 15);
624 			break;
625 		case B_LARGE_ICON:
626 			bounds.Set(0, 0, 31, 31);
627 			break;
628 		default:
629 			error = B_BAD_VALUE;
630 			break;
631 	}
632 
633 	// check parameters and initialization
634 	if (error == B_OK
635 		&& (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
636 		error = B_BAD_VALUE;
637 	}
638 	if (error == B_OK && InitCheck() != B_OK)
639 		error = B_NO_INIT;
640 
641 	bool success = false;
642 
643 	// get node MIME type, and, if that fails, the generic icon
644 	char mimeString[B_MIME_TYPE_LENGTH];
645 	if (error == B_OK) {
646 		if (GetType(mimeString) != B_OK) {
647 			struct stat stat;
648 			error = fNode->GetStat(&stat);
649 			if (error == B_OK) {
650 				// no type available -- get the icon for the appropriate type (file/dir/etc.)
651 				BMimeType type;
652 				if (S_ISREG(stat.st_mode)) {
653 					// is it an application (executable) or just a regular file?
654 					if ((stat.st_mode & S_IXUSR) != 0)
655 						type.SetTo(B_APP_MIME_TYPE);
656 					else
657 						type.SetTo(B_FILE_MIME_TYPE);
658 				} else if (S_ISDIR(stat.st_mode)) {
659 					// it's either a volume or just a standard directory
660 					fs_info info;
661 					if (fs_stat_dev(stat.st_dev, &info) == 0 && stat.st_ino == info.root)
662 						type.SetTo(B_VOLUME_MIME_TYPE);
663 					else
664 						type.SetTo(B_DIRECTORY_MIME_TYPE);
665 				} else if (S_ISLNK(stat.st_mode))
666 					type.SetTo(B_SYMLINK_MIME_TYPE);
667 
668 				error = type.GetIcon(icon, iconSize);
669 				success = (error == B_OK);
670 			}
671 		}
672 	}
673 
674 	// Ask GetIcon().
675 	if (error == B_OK && !success)
676 		success = (GetIcon(icon, iconSize) == B_OK);
677 
678 	// Get the preferred application and ask the MIME database, if that
679 	// application has a special icon for the node's file type.
680 	if (error == B_OK && !success) {
681 		char signature[B_MIME_TYPE_LENGTH];
682 		if (GetPreferredApp(signature) == B_OK) {
683 			BMimeType type(signature);
684 			success = (type.GetIconForType(mimeString, icon, iconSize) == B_OK);
685 		}
686 	}
687 
688 	// Ask the MIME database whether there is an icon for the node's file type.
689 	BMimeType nodeType;
690 	if (error == B_OK && !success) {
691 		nodeType.SetTo(mimeString);
692 		success = (nodeType.GetIcon(icon, iconSize) == B_OK);
693 	}
694 
695 	// Ask the MIME database for the preferred application for the node's
696 	// file type and whether this application has a special icon for the type.
697 	if (error == B_OK && !success) {
698 		char signature[B_MIME_TYPE_LENGTH];
699 		if (nodeType.GetPreferredApp(signature) == B_OK) {
700 			BMimeType type(signature);
701 			success = (type.GetIconForType(mimeString, icon, iconSize) == B_OK);
702 		}
703 	}
704 
705 	// Return the icon for "application/octet-stream" from the MIME database.
706 	if (error == B_OK && !success) {
707 		// get the "application/octet-stream" icon
708 		BMimeType type(B_FILE_MIME_TYPE);
709 		error = type.GetIcon(icon, iconSize);
710 		success = (error == B_OK);
711 	}
712 	return error;
713 }
714 
715 // GetTrackerIcon
716 /*!	\brief Gets the icon which tracker displays for the node referred to by
717 		   the supplied entry_ref.
718 
719 	This methods works similar to the non-static version. The first argument
720 	\a ref identifies the node in question.
721 
722 	\param ref An entry_ref referring to the node for which the icon shall be
723 		   retrieved.
724 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
725 		   to store the requested icon (16x16 for the mini and 32x32 for the
726 		   large icon).
727 	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
728 		   for the mini and \c B_LARGE_ICON for the large icon.
729 	\return
730 	- \c B_OK: Everything went fine.
731 	- \c B_NO_INIT: The object is not properly initialized.
732 	- \c B_BAD_VALUE: \c NULL ref or \a icon, unsupported icon size \a iconSize or
733 		 bitmap dimensions (\a icon) and icon size (\a iconSize) do not match.
734 	- other error codes
735 */
736 status_t
737 BNodeInfo::GetTrackerIcon(const entry_ref *ref, BBitmap *icon, icon_size iconSize)
738 {
739 	// check ref param
740 	status_t error = (ref ? B_OK : B_BAD_VALUE);
741 
742 	// init a BNode
743 	BNode node;
744 	if (error == B_OK)
745 		error = node.SetTo(ref);
746 
747 	// init a BNodeInfo
748 	BNodeInfo nodeInfo;
749 	if (error == B_OK)
750 		error = nodeInfo.SetTo(&node);
751 
752 	// let the non-static GetTrackerIcon() do the dirty work
753 	if (error == B_OK)
754 		error = nodeInfo.GetTrackerIcon(icon, iconSize);
755 	return error;
756 }
757 
758 // TODO: just here for providing binary compatibility
759 // (for example "Guido" needs this)
760 extern "C"
761 status_t
762 GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(
763 	BNodeInfo *nodeInfo, entry_ref* ref,
764 	BBitmap* bitmap, icon_size iconSize)
765 {
766 	// NOTE: nodeInfo is ignored - maybe that's wrong!
767 	return BNodeInfo::GetTrackerIcon(ref, bitmap, iconSize);
768 }
769 
770 void
771 BNodeInfo::_ReservedNodeInfo1()
772 {
773 }
774 
775 void
776 BNodeInfo::_ReservedNodeInfo2()
777 {
778 }
779 
780 void
781 BNodeInfo::_ReservedNodeInfo3()
782 {
783 }
784 
785 // =
786 /*!	\brief Privatized assignment operator to prevent usage.
787 */
788 BNodeInfo &
789 BNodeInfo::operator=(const BNodeInfo &nodeInfo)
790 {
791 	return *this;
792 }
793 
794 // copy constructor
795 /*!	\brief Privatized copy constructor to prevent usage.
796 */
797 BNodeInfo::BNodeInfo(const BNodeInfo &)
798 {
799 }
800 
801 
802 //	#pragma mark -
803 
804 namespace BPrivate {
805 
806 /*!
807 	Private function used by Tracker. Should be moved into the Tracker sources.
808 */
809 extern bool
810 CheckNodeIconHintPrivate(const BNode *node, bool checkMiniIconOnly)
811 {
812 	attr_info info;
813 	if (node->GetAttrInfo(kNIMiniIconAttribute, &info) != B_OK && checkMiniIconOnly)
814 		return false;
815 
816 	if (node->GetAttrInfo(kNILargeIconAttribute, &info) != B_OK)
817 		return false;
818 
819 	return true;
820 }
821 
822 }	// namespace BPrivate
823