xref: /haiku/src/system/kernel/device_manager/devfs.cpp (revision 56187df6ebd9d1fb16bf954fce8df0999e9e3048)
1 /*
2  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 
10 #include <fs/devfs.h>
11 
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 
18 #include <Drivers.h>
19 #include <KernelExport.h>
20 #include <NodeMonitor.h>
21 
22 #include <arch/cpu.h>
23 #include <AutoDeleter.h>
24 #include <boot/kernel_args.h>
25 #include <boot_device.h>
26 #include <debug.h>
27 #include <elf.h>
28 #include <FindDirectory.h>
29 #include <fs/KPath.h>
30 #include <fs/node_monitor.h>
31 #include <kdevice_manager.h>
32 #include <lock.h>
33 #include <Notifications.h>
34 #include <util/AutoLock.h>
35 #include <util/khash.h>
36 #include <vfs.h>
37 #include <vm/vm.h>
38 
39 #include "BaseDevice.h"
40 #include "FileDevice.h"
41 #include "IORequest.h"
42 #include "legacy_drivers.h"
43 
44 
45 //#define TRACE_DEVFS
46 #ifdef TRACE_DEVFS
47 #	define TRACE(x) dprintf x
48 #else
49 #	define TRACE(x)
50 #endif
51 
52 
53 struct devfs_partition {
54 	struct devfs_vnode*	raw_device;
55 	partition_info		info;
56 };
57 
58 struct driver_entry;
59 
60 enum {
61 	kNotScanned = 0,
62 	kBootScan,
63 	kNormalScan,
64 };
65 
66 struct devfs_stream {
67 	mode_t				type;
68 	union {
69 		struct stream_dir {
70 			struct devfs_vnode*		dir_head;
71 			struct list				cookies;
72 			mutex					scan_lock;
73 			int32					scanned;
74 		} dir;
75 		struct stream_dev {
76 			BaseDevice*				device;
77 			struct devfs_partition*	partition;
78 		} dev;
79 		struct stream_symlink {
80 			const char*				path;
81 			size_t					length;
82 		} symlink;
83 	} u;
84 };
85 
86 struct devfs_vnode {
87 	struct devfs_vnode*	all_next;
88 	ino_t				id;
89 	char*				name;
90 	timespec			modification_time;
91 	timespec			creation_time;
92 	uid_t				uid;
93 	gid_t				gid;
94 	struct devfs_vnode*	parent;
95 	struct devfs_vnode*	dir_next;
96 	struct devfs_stream	stream;
97 };
98 
99 #define DEVFS_HASH_SIZE 16
100 
101 struct devfs {
102 	dev_t				id;
103 	fs_volume*			volume;
104 	recursive_lock		lock;
105  	int32				next_vnode_id;
106 	hash_table*			vnode_hash;
107 	struct devfs_vnode*	root_vnode;
108 };
109 
110 struct devfs_dir_cookie {
111 	struct list_link	link;
112 	struct devfs_vnode*	current;
113 	int32				state;	// iteration state
114 };
115 
116 struct devfs_cookie {
117 	void*				device_cookie;
118 };
119 
120 struct synchronous_io_cookie {
121 	BaseDevice*		device;
122 	void*			cookie;
123 };
124 
125 // directory iteration states
126 enum {
127 	ITERATION_STATE_DOT		= 0,
128 	ITERATION_STATE_DOT_DOT	= 1,
129 	ITERATION_STATE_OTHERS	= 2,
130 	ITERATION_STATE_BEGIN	= ITERATION_STATE_DOT,
131 };
132 
133 // extern and in a private namespace only to make forward declaration possible
134 namespace {
135 	extern fs_volume_ops kVolumeOps;
136 	extern fs_vnode_ops kVnodeOps;
137 }
138 
139 
140 static status_t get_node_for_path(struct devfs *fs, const char *path,
141 	struct devfs_vnode **_node);
142 static void get_device_name(struct devfs_vnode *vnode, char *buffer,
143 	size_t size);
144 static status_t unpublish_node(struct devfs *fs, devfs_vnode *node,
145 	mode_t type);
146 static status_t publish_device(struct devfs *fs, const char *path,
147 	BaseDevice* device);
148 
149 
150 /* the one and only allowed devfs instance */
151 static struct devfs* sDeviceFileSystem = NULL;
152 
153 
154 //	#pragma mark - devfs private
155 
156 
157 static timespec
158 current_timespec()
159 {
160 	bigtime_t time = real_time_clock_usecs();
161 
162 	timespec tv;
163 	tv.tv_sec = time / 1000000;
164 	tv.tv_nsec = (time % 1000000) * 1000;
165 	return tv;
166 }
167 
168 
169 static int32
170 scan_mode(void)
171 {
172 	// We may scan every device twice:
173 	//  - once before there is a boot device,
174 	//  - and once when there is one
175 
176 	return gBootDevice >= 0 ? kNormalScan : kBootScan;
177 }
178 
179 
180 static status_t
181 scan_for_drivers_if_needed(devfs_vnode* dir)
182 {
183 	ASSERT(S_ISDIR(dir->stream.type));
184 
185 	MutexLocker _(dir->stream.u.dir.scan_lock);
186 
187 	if (dir->stream.u.dir.scanned >= scan_mode())
188 		return B_OK;
189 
190 	KPath path;
191 	if (path.InitCheck() != B_OK)
192 		return B_NO_MEMORY;
193 
194 	get_device_name(dir, path.LockBuffer(), path.BufferSize());
195 	path.UnlockBuffer();
196 
197 	TRACE(("scan_for_drivers_if_needed: mode %ld: %s\n", scan_mode(),
198 		path.Path()));
199 
200 	// scan for drivers at this path
201 	static int32 updateCycle = 1;
202 	device_manager_probe(path.Path(), updateCycle++);
203 	legacy_driver_probe(path.Path());
204 
205 	dir->stream.u.dir.scanned = scan_mode();
206 	return B_OK;
207 }
208 
209 
210 static uint32
211 devfs_vnode_hash(void* _vnode, const void* _key, uint32 range)
212 {
213 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode;
214 	const ino_t* key = (const ino_t*)_key;
215 
216 	if (vnode != NULL)
217 		return vnode->id % range;
218 
219 	return (uint64)*key % range;
220 }
221 
222 
223 static int
224 devfs_vnode_compare(void* _vnode, const void* _key)
225 {
226 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode;
227 	const ino_t* key = (const ino_t*)_key;
228 
229 	if (vnode->id == *key)
230 		return 0;
231 
232 	return -1;
233 }
234 
235 
236 static void
237 init_directory_vnode(struct devfs_vnode* vnode, int permissions)
238 {
239 	vnode->stream.type = S_IFDIR | permissions;
240 		mutex_init(&vnode->stream.u.dir.scan_lock, "devfs scan");
241 	vnode->stream.u.dir.dir_head = NULL;
242 	list_init(&vnode->stream.u.dir.cookies);
243 }
244 
245 
246 static struct devfs_vnode*
247 devfs_create_vnode(struct devfs* fs, devfs_vnode* parent, const char* name)
248 {
249 	struct devfs_vnode* vnode;
250 
251 	vnode = (struct devfs_vnode*)malloc(sizeof(struct devfs_vnode));
252 	if (vnode == NULL)
253 		return NULL;
254 
255 	memset(vnode, 0, sizeof(struct devfs_vnode));
256 	vnode->id = fs->next_vnode_id++;
257 
258 	vnode->name = strdup(name);
259 	if (vnode->name == NULL) {
260 		free(vnode);
261 		return NULL;
262 	}
263 
264 	vnode->creation_time = vnode->modification_time = current_timespec();
265 	vnode->uid = geteuid();
266 	vnode->gid = parent ? parent->gid : getegid();
267 		// inherit group from parent if possible
268 
269 	return vnode;
270 }
271 
272 
273 static status_t
274 devfs_delete_vnode(struct devfs* fs, struct devfs_vnode* vnode,
275 	bool forceDelete)
276 {
277 	// cant delete it if it's in a directory or is a directory
278 	// and has children
279 	if (!forceDelete && ((S_ISDIR(vnode->stream.type)
280 				&& vnode->stream.u.dir.dir_head != NULL)
281 			|| vnode->dir_next != NULL))
282 		return B_NOT_ALLOWED;
283 
284 	// remove it from the global hash table
285 	hash_remove(fs->vnode_hash, vnode);
286 
287 	if (S_ISCHR(vnode->stream.type)) {
288 		if (vnode->stream.u.dev.partition == NULL) {
289 			// pass the call through to the underlying device
290 			vnode->stream.u.dev.device->Removed();
291 		} else {
292 			// for partitions, we have to release the raw device but must
293 			// not free the device info as it was inherited from the raw
294 			// device and is still in use there
295 			put_vnode(fs->volume, vnode->stream.u.dev.partition->raw_device->id);
296 		}
297 	} else if (S_ISDIR(vnode->stream.type)) {
298 		mutex_destroy(&vnode->stream.u.dir.scan_lock);
299 	}
300 
301 	free(vnode->name);
302 	free(vnode);
303 
304 	return B_OK;
305 }
306 
307 
308 /*! Makes sure none of the dircookies point to the vnode passed in */
309 static void
310 update_dir_cookies(struct devfs_vnode* dir, struct devfs_vnode* vnode)
311 {
312 	struct devfs_dir_cookie* cookie = NULL;
313 
314 	while ((cookie = (devfs_dir_cookie*)list_get_next_item(
315 			&dir->stream.u.dir.cookies, cookie)) != NULL) {
316 		if (cookie->current == vnode)
317 			cookie->current = vnode->dir_next;
318 	}
319 }
320 
321 
322 static struct devfs_vnode*
323 devfs_find_in_dir(struct devfs_vnode* dir, const char* path)
324 {
325 	struct devfs_vnode* vnode;
326 
327 	if (!S_ISDIR(dir->stream.type))
328 		return NULL;
329 
330 	if (!strcmp(path, "."))
331 		return dir;
332 	if (!strcmp(path, ".."))
333 		return dir->parent;
334 
335 	for (vnode = dir->stream.u.dir.dir_head; vnode; vnode = vnode->dir_next) {
336 		//TRACE(("devfs_find_in_dir: looking at entry '%s'\n", vnode->name));
337 		if (strcmp(vnode->name, path) == 0) {
338 			//TRACE(("devfs_find_in_dir: found it at %p\n", vnode));
339 			return vnode;
340 		}
341 	}
342 	return NULL;
343 }
344 
345 
346 static status_t
347 devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode,
348 	bool notify = true)
349 {
350 	if (!S_ISDIR(dir->stream.type))
351 		return B_BAD_VALUE;
352 
353 	// make sure the directory stays sorted alphabetically
354 
355 	devfs_vnode* node = dir->stream.u.dir.dir_head;
356 	devfs_vnode* last = NULL;
357 	while (node && strcmp(node->name, vnode->name) < 0) {
358 		last = node;
359 		node = node->dir_next;
360 	}
361 	if (last == NULL) {
362 		// the new vnode is the first entry in the list
363 		vnode->dir_next = dir->stream.u.dir.dir_head;
364 		dir->stream.u.dir.dir_head = vnode;
365 	} else {
366 		// insert after that node
367 		vnode->dir_next = last->dir_next;
368 		last->dir_next = vnode;
369 	}
370 
371 	vnode->parent = dir;
372 	dir->modification_time = current_timespec();
373 
374 	if (notify) {
375 		notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name,
376 			vnode->id);
377 		notify_stat_changed(sDeviceFileSystem->id, dir->id,
378 			B_STAT_MODIFICATION_TIME);
379 	}
380 	return B_OK;
381 }
382 
383 
384 static status_t
385 devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode,
386 	bool notify = true)
387 {
388 	struct devfs_vnode *vnode = dir->stream.u.dir.dir_head;
389 	struct devfs_vnode *lastNode = NULL;
390 
391 	for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) {
392 		if (vnode == removeNode) {
393 			// make sure no dircookies point to this vnode
394 			update_dir_cookies(dir, vnode);
395 
396 			if (lastNode)
397 				lastNode->dir_next = vnode->dir_next;
398 			else
399 				dir->stream.u.dir.dir_head = vnode->dir_next;
400 			vnode->dir_next = NULL;
401 			dir->modification_time = current_timespec();
402 
403 			if (notify) {
404 				notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name,
405 					vnode->id);
406 				notify_stat_changed(sDeviceFileSystem->id, dir->id,
407 					B_STAT_MODIFICATION_TIME);
408 			}
409 			return B_OK;
410 		}
411 	}
412 	return B_ENTRY_NOT_FOUND;
413 }
414 
415 
416 static status_t
417 add_partition(struct devfs* fs, struct devfs_vnode* device, const char* name,
418 	const partition_info& info)
419 {
420 	struct devfs_vnode* partitionNode;
421 	status_t status;
422 
423 	if (!S_ISCHR(device->stream.type))
424 		return B_BAD_VALUE;
425 
426 	// we don't support nested partitions
427 	if (device->stream.u.dev.partition != NULL)
428 		return B_BAD_VALUE;
429 
430 	// reduce checks to a minimum - things like negative offsets could be useful
431 	if (info.size < 0)
432 		return B_BAD_VALUE;
433 
434 	// create partition
435 	struct devfs_partition* partition = (struct devfs_partition*)malloc(
436 		sizeof(struct devfs_partition));
437 	if (partition == NULL)
438 		return B_NO_MEMORY;
439 
440 	memcpy(&partition->info, &info, sizeof(partition_info));
441 
442 	RecursiveLocker locker(fs->lock);
443 
444 	// you cannot change a partition once set
445 	if (devfs_find_in_dir(device->parent, name)) {
446 		status = B_BAD_VALUE;
447 		goto err1;
448 	}
449 
450 	// increase reference count of raw device -
451 	// the partition device really needs it
452 	status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device);
453 	if (status < B_OK)
454 		goto err1;
455 
456 	// now create the partition vnode
457 	partitionNode = devfs_create_vnode(fs, device->parent, name);
458 	if (partitionNode == NULL) {
459 		status = B_NO_MEMORY;
460 		goto err2;
461 	}
462 
463 	partitionNode->stream.type = device->stream.type;
464 	partitionNode->stream.u.dev.device = device->stream.u.dev.device;
465 	partitionNode->stream.u.dev.partition = partition;
466 
467 	hash_insert(fs->vnode_hash, partitionNode);
468 	devfs_insert_in_dir(device->parent, partitionNode);
469 
470 	TRACE(("add_partition(name = %s, offset = %Ld, size = %Ld)\n",
471 		name, info.offset, info.size));
472 	return B_OK;
473 
474 err2:
475 	put_vnode(fs->volume, device->id);
476 err1:
477 	free(partition);
478 	return status;
479 }
480 
481 
482 static inline void
483 translate_partition_access(devfs_partition* partition, off_t& offset,
484 	size_t& size)
485 {
486 	ASSERT(offset >= 0);
487 	ASSERT(offset < partition->info.size);
488 
489 	size = min_c(size, partition->info.size - offset);
490 	offset += partition->info.offset;
491 }
492 
493 
494 static inline void
495 translate_partition_access(devfs_partition* partition, io_request* request)
496 {
497 	off_t offset = request->Offset();
498 
499 	ASSERT(offset >= 0);
500 	ASSERT(offset + (off_t)request->Length() <= partition->info.size);
501 
502 	request->SetOffset(offset + partition->info.offset);
503 }
504 
505 
506 static status_t
507 get_node_for_path(struct devfs *fs, const char *path,
508 	struct devfs_vnode **_node)
509 {
510 	return vfs_get_fs_node_from_path(fs->volume, path, false, true,
511 		(void **)_node);
512 }
513 
514 
515 static status_t
516 unpublish_node(struct devfs *fs, devfs_vnode *node, mode_t type)
517 {
518 	if ((node->stream.type & S_IFMT) != type)
519 		return B_BAD_TYPE;
520 
521 	recursive_lock_lock(&fs->lock);
522 
523 	status_t status = devfs_remove_from_dir(node->parent, node);
524 	if (status < B_OK)
525 		goto out;
526 
527 	status = remove_vnode(fs->volume, node->id);
528 
529 out:
530 	recursive_lock_unlock(&fs->lock);
531 	return status;
532 }
533 
534 
535 static void
536 publish_node(devfs* fs, devfs_vnode* dirNode, struct devfs_vnode* node)
537 {
538 	hash_insert(fs->vnode_hash, node);
539 	devfs_insert_in_dir(dirNode, node);
540 }
541 
542 
543 static status_t
544 publish_directory(struct devfs *fs, const char *path)
545 {
546 	ASSERT_LOCKED_RECURSIVE(&fs->lock);
547 
548 	// copy the path over to a temp buffer so we can munge it
549 	KPath tempPath(path);
550 	if (tempPath.InitCheck() != B_OK)
551 		return B_NO_MEMORY;
552 
553 	TRACE(("devfs: publish directory \"%s\"\n", path));
554 	char *temp = tempPath.LockBuffer();
555 
556 	// create the path leading to the device
557 	// parse the path passed in, stripping out '/'
558 
559 	struct devfs_vnode *dir = fs->root_vnode;
560 	struct devfs_vnode *vnode = NULL;
561 	status_t status = B_OK;
562 	int32 i = 0, last = 0;
563 
564 	while (temp[last]) {
565 		if (temp[i] == '/') {
566 			temp[i] = '\0';
567 			i++;
568 		} else if (temp[i] != '\0') {
569 			i++;
570 			continue;
571 		}
572 
573 		//TRACE(("\tpath component '%s'\n", &temp[last]));
574 
575 		// we have a path component
576 		vnode = devfs_find_in_dir(dir, &temp[last]);
577 		if (vnode) {
578 			if (S_ISDIR(vnode->stream.type)) {
579 				last = i;
580 				dir = vnode;
581 				continue;
582 			}
583 
584 			// we hit something on our path that's not a directory
585 			status = B_FILE_EXISTS;
586 			goto out;
587 		} else {
588 			vnode = devfs_create_vnode(fs, dir, &temp[last]);
589 			if (!vnode) {
590 				status = B_NO_MEMORY;
591 				goto out;
592 			}
593 		}
594 
595 		// set up the new directory
596 		init_directory_vnode(vnode, 0755);
597 		publish_node(sDeviceFileSystem, dir, vnode);
598 
599 		last = i;
600 		dir = vnode;
601 	}
602 
603 out:
604 	return status;
605 }
606 
607 
608 static status_t
609 new_node(struct devfs *fs, const char *path, struct devfs_vnode **_node,
610 	struct devfs_vnode **_dir)
611 {
612 	ASSERT_LOCKED_RECURSIVE(&fs->lock);
613 
614 	// copy the path over to a temp buffer so we can munge it
615 	KPath tempPath(path);
616 	if (tempPath.InitCheck() != B_OK)
617 		return B_NO_MEMORY;
618 
619 	char *temp = tempPath.LockBuffer();
620 
621 	// create the path leading to the device
622 	// parse the path passed in, stripping out '/'
623 
624 	struct devfs_vnode *dir = fs->root_vnode;
625 	struct devfs_vnode *vnode = NULL;
626 	status_t status = B_OK;
627 	int32 i = 0, last = 0;
628 	bool atLeaf = false;
629 
630 	for (;;) {
631 		if (temp[i] == '\0') {
632 			atLeaf = true; // we'll be done after this one
633 		} else if (temp[i] == '/') {
634 			temp[i] = '\0';
635 			i++;
636 		} else {
637 			i++;
638 			continue;
639 		}
640 
641 		//TRACE(("\tpath component '%s'\n", &temp[last]));
642 
643 		// we have a path component
644 		vnode = devfs_find_in_dir(dir, &temp[last]);
645 		if (vnode) {
646 			if (!atLeaf) {
647 				// we are not at the leaf of the path, so as long as
648 				// this is a dir we're okay
649 				if (S_ISDIR(vnode->stream.type)) {
650 					last = i;
651 					dir = vnode;
652 					continue;
653 				}
654 			}
655 			// we are at the leaf and hit another node
656 			// or we aren't but hit a non-dir node.
657 			// we're screwed
658 			status = B_FILE_EXISTS;
659 			goto out;
660 		} else {
661 			vnode = devfs_create_vnode(fs, dir, &temp[last]);
662 			if (!vnode) {
663 				status = B_NO_MEMORY;
664 				goto out;
665 			}
666 		}
667 
668 		// set up the new vnode
669 		if (!atLeaf) {
670 			// this is a dir
671 			init_directory_vnode(vnode, 0755);
672 			publish_node(fs, dir, vnode);
673 		} else {
674 			// this is the last component
675 			// Note: We do not yet insert the node into the directory, as it
676 			// is not yet fully initialized. Instead we return the directory
677 			// vnode so that the calling function can insert it after all
678 			// initialization is done. This ensures that no create notification
679 			// is sent out for a vnode that is not yet fully valid.
680 			*_node = vnode;
681 			*_dir = dir;
682 			break;
683 		}
684 
685 		last = i;
686 		dir = vnode;
687 	}
688 
689 out:
690 	return status;
691 }
692 
693 
694 static status_t
695 publish_device(struct devfs* fs, const char* path, BaseDevice* device)
696 {
697 	TRACE(("publish_device(path = \"%s\", device = %p)\n", path, device));
698 
699 	if (sDeviceFileSystem == NULL) {
700 		panic("publish_device() called before devfs mounted\n");
701 		return B_ERROR;
702 	}
703 
704 	if (device == NULL || path == NULL || path[0] == '\0' || path[0] == '/')
705 		return B_BAD_VALUE;
706 
707 // TODO: this has to be done in the BaseDevice sub classes!
708 #if 0
709 	// are the provided device hooks okay?
710 	if (info->device_open == NULL || info->device_close == NULL
711 		|| info->device_free == NULL
712 		|| ((info->device_read == NULL || info->device_write == NULL)
713 			&& info->device_io == NULL))
714 		return B_BAD_VALUE;
715 #endif
716 
717 	struct devfs_vnode* node;
718 	struct devfs_vnode* dirNode;
719 	status_t status;
720 
721 	RecursiveLocker locker(&fs->lock);
722 
723 	status = new_node(fs, path, &node, &dirNode);
724 	if (status != B_OK)
725 		return status;
726 
727 	// all went fine, let's initialize the node
728 	node->stream.type = S_IFCHR | 0644;
729 	node->stream.u.dev.device = device;
730 	device->SetID(node->id);
731 
732 	// the node is now fully valid and we may insert it into the dir
733 	publish_node(fs, dirNode, node);
734 	return B_OK;
735 }
736 
737 
738 /*!	Construct complete device name (as used for device_open()).
739 	This is safe to use only when the device is in use (and therefore
740 	cannot be unpublished during the iteration).
741 */
742 static void
743 get_device_name(struct devfs_vnode* vnode, char* buffer, size_t size)
744 {
745 	RecursiveLocker _(sDeviceFileSystem->lock);
746 
747 	struct devfs_vnode* leaf = vnode;
748 	size_t offset = 0;
749 
750 	// count levels
751 
752 	for (; vnode->parent && vnode->parent != vnode; vnode = vnode->parent) {
753 		offset += strlen(vnode->name) + 1;
754 	}
755 
756 	// construct full path name
757 
758 	for (vnode = leaf; vnode->parent && vnode->parent != vnode;
759 			vnode = vnode->parent) {
760 		size_t length = strlen(vnode->name);
761 		size_t start = offset - length - 1;
762 
763 		if (size >= offset) {
764 			strcpy(buffer + start, vnode->name);
765 			if (vnode != leaf)
766 				buffer[offset - 1] = '/';
767 		}
768 
769 		offset = start;
770 	}
771 }
772 
773 
774 static status_t
775 device_read(void* _cookie, off_t offset, void* buffer, size_t* length)
776 {
777 	synchronous_io_cookie* cookie = (synchronous_io_cookie*)_cookie;
778 	return cookie->device->Read(cookie->cookie, offset, buffer, length);
779 }
780 
781 
782 static status_t
783 device_write(void* _cookie, off_t offset, void* buffer, size_t* length)
784 {
785 	synchronous_io_cookie* cookie = (synchronous_io_cookie*)_cookie;
786 	return cookie->device->Write(cookie->cookie, offset, buffer, length);
787 }
788 
789 
790 static int
791 dump_node(int argc, char **argv)
792 {
793 	if (argc != 2) {
794 		print_debugger_command_usage(argv[0]);
795 		return 0;
796 	}
797 
798 	struct devfs_vnode *vnode = (struct devfs_vnode *)parse_expression(argv[1]);
799 	if (vnode == NULL) {
800 		kprintf("invalid node address\n");
801 		return 0;
802 	}
803 
804 	kprintf("DEVFS NODE: %p\n", vnode);
805 	kprintf(" id:          %Ld\n", vnode->id);
806 	kprintf(" name:        \"%s\"\n", vnode->name);
807 	kprintf(" type:        %x\n", vnode->stream.type);
808 	kprintf(" parent:      %p\n", vnode->parent);
809 	kprintf(" dir next:    %p\n", vnode->dir_next);
810 
811 	if (S_ISDIR(vnode->stream.type)) {
812 		kprintf(" dir scanned: %ld\n", vnode->stream.u.dir.scanned);
813 		kprintf(" contents:\n");
814 
815 		devfs_vnode *children = vnode->stream.u.dir.dir_head;
816 		while (children != NULL) {
817 			kprintf("   %p, id %Ld\n", children, children->id);
818 			children = children->dir_next;
819 		}
820 	} else if (S_ISLNK(vnode->stream.type)) {
821 		kprintf(" symlink to:  %s\n", vnode->stream.u.symlink.path);
822 	} else {
823 		kprintf(" device:      %p\n", vnode->stream.u.dev.device);
824 		kprintf(" partition:   %p\n", vnode->stream.u.dev.partition);
825 		if (vnode->stream.u.dev.partition != NULL) {
826 			partition_info& info = vnode->stream.u.dev.partition->info;
827 			kprintf("  raw device node: %p\n",
828 				vnode->stream.u.dev.partition->raw_device);
829 			kprintf("  offset:          %Ld\n", info.offset);
830 			kprintf("  size:            %Ld\n", info.size);
831 			kprintf("  block size:      %ld\n", info.logical_block_size);
832 			kprintf("  session:         %ld\n", info.session);
833 			kprintf("  partition:       %ld\n", info.partition);
834 			kprintf("  device:          %s\n", info.device);
835 			set_debug_variable("_raw",
836 				(addr_t)vnode->stream.u.dev.partition->raw_device);
837 		}
838 	}
839 
840 	return 0;
841 }
842 
843 
844 static int
845 dump_cookie(int argc, char** argv)
846 {
847 	if (argc != 2) {
848 		print_debugger_command_usage(argv[0]);
849 		return 0;
850 	}
851 
852 	uint64 address;
853 	if (!evaluate_debug_expression(argv[1], &address, false))
854 		return 0;
855 
856 	struct devfs_cookie* cookie = (devfs_cookie*)(addr_t)address;
857 
858 	kprintf("DEVFS COOKIE: %p\n", cookie);
859 	kprintf(" device_cookie: %p\n", cookie->device_cookie);
860 
861 	return 0;
862 }
863 
864 
865 //	#pragma mark - file system interface
866 
867 
868 static status_t
869 devfs_mount(fs_volume *volume, const char *devfs, uint32 flags,
870 	const char *args, ino_t *root_vnid)
871 {
872 	struct devfs_vnode *vnode;
873 	struct devfs *fs;
874 	status_t err;
875 
876 	TRACE(("devfs_mount: entry\n"));
877 
878 	if (sDeviceFileSystem) {
879 		TRACE(("double mount of devfs attempted\n"));
880 		err = B_ERROR;
881 		goto err;
882 	}
883 
884 	fs = (struct devfs *)malloc(sizeof(struct devfs));
885 	if (fs == NULL) {
886 		err = B_NO_MEMORY;
887 		goto err;
888  	}
889 
890 	volume->private_volume = fs;
891 	volume->ops = &kVolumeOps;
892 	fs->volume = volume;
893 	fs->id = volume->id;
894 	fs->next_vnode_id = 0;
895 
896 	recursive_lock_init(&fs->lock, "devfs lock");
897 
898 	fs->vnode_hash = hash_init(DEVFS_HASH_SIZE, offsetof(devfs_vnode, all_next),
899 		//(addr_t)&vnode->all_next - (addr_t)vnode,
900 		&devfs_vnode_compare, &devfs_vnode_hash);
901 	if (fs->vnode_hash == NULL) {
902 		err = B_NO_MEMORY;
903 		goto err2;
904 	}
905 
906 	// create a vnode
907 	vnode = devfs_create_vnode(fs, NULL, "");
908 	if (vnode == NULL) {
909 		err = B_NO_MEMORY;
910 		goto err3;
911 	}
912 
913 	// set it up
914 	vnode->parent = vnode;
915 
916 	// create a dir stream for it to hold
917 	init_directory_vnode(vnode, 0755);
918 	fs->root_vnode = vnode;
919 
920 	hash_insert(fs->vnode_hash, vnode);
921 	publish_vnode(volume, vnode->id, vnode, &kVnodeOps, vnode->stream.type, 0);
922 
923 	*root_vnid = vnode->id;
924 	sDeviceFileSystem = fs;
925 	return B_OK;
926 
927 err3:
928 	hash_uninit(fs->vnode_hash);
929 err2:
930 	recursive_lock_destroy(&fs->lock);
931 	free(fs);
932 err:
933 	return err;
934 }
935 
936 
937 static status_t
938 devfs_unmount(fs_volume *_volume)
939 {
940 	struct devfs *fs = (struct devfs *)_volume->private_volume;
941 	struct devfs_vnode *vnode;
942 	struct hash_iterator i;
943 
944 	TRACE(("devfs_unmount: entry fs = %p\n", fs));
945 
946 	recursive_lock_lock(&fs->lock);
947 
948 	// release the reference to the root
949 	put_vnode(fs->volume, fs->root_vnode->id);
950 
951 	// delete all of the vnodes
952 	hash_open(fs->vnode_hash, &i);
953 	while ((vnode = (devfs_vnode *)hash_next(fs->vnode_hash, &i)) != NULL) {
954 		devfs_delete_vnode(fs, vnode, true);
955 	}
956 	hash_close(fs->vnode_hash, &i, false);
957 	hash_uninit(fs->vnode_hash);
958 
959 	recursive_lock_destroy(&fs->lock);
960 	free(fs);
961 
962 	return B_OK;
963 }
964 
965 
966 static status_t
967 devfs_sync(fs_volume *_volume)
968 {
969 	TRACE(("devfs_sync: entry\n"));
970 
971 	return B_OK;
972 }
973 
974 
975 static status_t
976 devfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id)
977 {
978 	struct devfs *fs = (struct devfs *)_volume->private_volume;
979 	struct devfs_vnode *dir = (struct devfs_vnode *)_dir->private_node;
980 	struct devfs_vnode *vnode;
981 	status_t status;
982 
983 	TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir, name));
984 
985 	if (!S_ISDIR(dir->stream.type))
986 		return B_NOT_A_DIRECTORY;
987 
988 	// Make sure the directory contents are up to date
989 	scan_for_drivers_if_needed(dir);
990 
991 	RecursiveLocker locker(&fs->lock);
992 
993 	// look it up
994 	vnode = devfs_find_in_dir(dir, name);
995 	if (vnode == NULL) {
996 		// We don't have to rescan here, because thanks to node monitoring
997 		// we already know it does not exist
998 		return B_ENTRY_NOT_FOUND;
999 	}
1000 
1001 	status = get_vnode(fs->volume, vnode->id, NULL);
1002 	if (status < B_OK)
1003 		return status;
1004 
1005 	*_id = vnode->id;
1006 
1007 	return B_OK;
1008 }
1009 
1010 
1011 static status_t
1012 devfs_get_vnode_name(fs_volume *_volume, fs_vnode *_vnode, char *buffer,
1013 	size_t bufferSize)
1014 {
1015 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1016 
1017 	TRACE(("devfs_get_vnode_name: vnode = %p\n", vnode));
1018 
1019 	strlcpy(buffer, vnode->name, bufferSize);
1020 	return B_OK;
1021 }
1022 
1023 
1024 static status_t
1025 devfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_vnode, int *_type,
1026 	uint32 *_flags, bool reenter)
1027 {
1028 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1029 
1030 	TRACE(("devfs_get_vnode: asking for vnode id = %Ld, vnode = %p, r %d\n", id, _vnode, reenter));
1031 
1032 	RecursiveLocker _(fs->lock);
1033 
1034 	struct devfs_vnode *vnode = (devfs_vnode *)hash_lookup(fs->vnode_hash, &id);
1035 	if (vnode == NULL)
1036 		return B_ENTRY_NOT_FOUND;
1037 
1038 	TRACE(("devfs_get_vnode: looked it up at %p\n", vnode));
1039 
1040 	_vnode->private_node = vnode;
1041 	_vnode->ops = &kVnodeOps;
1042 	*_type = vnode->stream.type;
1043 	*_flags = 0;
1044 	return B_OK;
1045 }
1046 
1047 
1048 static status_t
1049 devfs_put_vnode(fs_volume* _volume, fs_vnode* _vnode, bool reenter)
1050 {
1051 #ifdef TRACE_DEVFS
1052 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1053 
1054 	TRACE(("devfs_put_vnode: entry on vnode %p, id = %Ld, reenter %d\n",
1055 		vnode, vnode->id, reenter));
1056 #endif
1057 
1058 	return B_OK;
1059 }
1060 
1061 
1062 static status_t
1063 devfs_remove_vnode(fs_volume *_volume, fs_vnode *_v, bool reenter)
1064 {
1065 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1066 	struct devfs_vnode *vnode = (struct devfs_vnode *)_v->private_node;
1067 
1068 	TRACE(("devfs_removevnode: remove %p (%Ld), reenter %d\n", vnode, vnode->id, reenter));
1069 
1070 	RecursiveLocker locker(&fs->lock);
1071 
1072 	if (vnode->dir_next) {
1073 		// can't remove node if it's linked to the dir
1074 		panic("devfs_removevnode: vnode %p asked to be removed is present in dir\n", vnode);
1075 	}
1076 
1077 	devfs_delete_vnode(fs, vnode, false);
1078 
1079 	return B_OK;
1080 }
1081 
1082 
1083 static status_t
1084 devfs_create(fs_volume* _volume, fs_vnode* _dir, const char* name, int openMode,
1085 	int perms, void** _cookie, ino_t* _newVnodeID)
1086 {
1087 	struct devfs_vnode* dir = (struct devfs_vnode*)_dir->private_node;
1088 	struct devfs* fs = (struct devfs*)_volume->private_volume;
1089 	struct devfs_cookie* cookie;
1090 	struct devfs_vnode* vnode;
1091 	status_t status = B_OK;
1092 
1093 	TRACE(("devfs_create: dir %p, name \"%s\", openMode 0x%x, fs_cookie %p \n",
1094 		dir, name, openMode, _cookie));
1095 
1096 	RecursiveLocker locker(fs->lock);
1097 
1098 	// look it up
1099 	vnode = devfs_find_in_dir(dir, name);
1100 	if (vnode == NULL)
1101 		return EROFS;
1102 
1103 	if ((openMode & O_EXCL) != 0)
1104 		return B_FILE_EXISTS;
1105 
1106 	status = get_vnode(fs->volume, vnode->id, NULL);
1107 	if (status != B_OK)
1108 		return status;
1109 
1110 	locker.Unlock();
1111 
1112 	*_newVnodeID = vnode->id;
1113 
1114 	cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie));
1115 	if (cookie == NULL) {
1116 		status = B_NO_MEMORY;
1117 		goto err1;
1118 	}
1119 
1120 	if (S_ISCHR(vnode->stream.type)) {
1121 		BaseDevice* device = vnode->stream.u.dev.device;
1122 		status = device->InitDevice();
1123 		if (status != B_OK)
1124 			goto err2;
1125 
1126 		char path[B_FILE_NAME_LENGTH];
1127 		get_device_name(vnode, path, sizeof(path));
1128 
1129 		status = device->Open(path, openMode, &cookie->device_cookie);
1130 		if (status != B_OK) {
1131 			device->UninitDevice();
1132 			goto err2;
1133 		}
1134 	}
1135 
1136 	*_cookie = cookie;
1137 	return B_OK;
1138 
1139 err2:
1140 	free(cookie);
1141 err1:
1142 	put_vnode(fs->volume, vnode->id);
1143 	return status;
1144 }
1145 
1146 
1147 static status_t
1148 devfs_open(fs_volume* _volume, fs_vnode* _vnode, int openMode,
1149 	void** _cookie)
1150 {
1151 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1152 	struct devfs_cookie* cookie;
1153 	status_t status = B_OK;
1154 
1155 	cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie));
1156 	if (cookie == NULL)
1157 		return B_NO_MEMORY;
1158 
1159 	TRACE(("devfs_open: vnode %p, openMode 0x%x, cookie %p\n", vnode, openMode,
1160 		cookie));
1161 
1162 	cookie->device_cookie = NULL;
1163 
1164 	if (S_ISCHR(vnode->stream.type)) {
1165 		BaseDevice* device = vnode->stream.u.dev.device;
1166 		status = device->InitDevice();
1167 		if (status != B_OK)
1168 			return status;
1169 
1170 		char path[B_FILE_NAME_LENGTH];
1171 		get_device_name(vnode, path, sizeof(path));
1172 
1173 		status = device->Open(path, openMode, &cookie->device_cookie);
1174 		if (status != B_OK)
1175 			device->UninitDevice();
1176 	}
1177 
1178 	if (status != B_OK)
1179 		free(cookie);
1180 	else
1181 		*_cookie = cookie;
1182 
1183 	return status;
1184 }
1185 
1186 
1187 static status_t
1188 devfs_close(fs_volume *_volume, fs_vnode *_vnode, void *_cookie)
1189 {
1190 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1191 	struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
1192 
1193 	TRACE(("devfs_close: entry vnode %p, cookie %p\n", vnode, cookie));
1194 
1195 	if (S_ISCHR(vnode->stream.type)) {
1196 		// pass the call through to the underlying device
1197 		return vnode->stream.u.dev.device->Close(cookie->device_cookie);
1198 	}
1199 
1200 	return B_OK;
1201 }
1202 
1203 
1204 static status_t
1205 devfs_free_cookie(fs_volume *_volume, fs_vnode *_vnode, void *_cookie)
1206 {
1207 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1208 	struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
1209 
1210 	TRACE(("devfs_freecookie: entry vnode %p, cookie %p\n", vnode, cookie));
1211 
1212 	if (S_ISCHR(vnode->stream.type)) {
1213 		// pass the call through to the underlying device
1214 		vnode->stream.u.dev.device->Free(cookie->device_cookie);
1215 		vnode->stream.u.dev.device->UninitDevice();
1216 	}
1217 
1218 	free(cookie);
1219 	return B_OK;
1220 }
1221 
1222 
1223 static status_t
1224 devfs_fsync(fs_volume *_volume, fs_vnode *_v)
1225 {
1226 	return B_OK;
1227 }
1228 
1229 
1230 static status_t
1231 devfs_read_link(fs_volume *_volume, fs_vnode *_link, char *buffer,
1232 	size_t *_bufferSize)
1233 {
1234 	struct devfs_vnode *link = (struct devfs_vnode *)_link->private_node;
1235 
1236 	if (!S_ISLNK(link->stream.type))
1237 		return B_BAD_VALUE;
1238 
1239 	if (link->stream.u.symlink.length < *_bufferSize)
1240 		*_bufferSize = link->stream.u.symlink.length;
1241 
1242 	memcpy(buffer, link->stream.u.symlink.path, *_bufferSize);
1243 	return B_OK;
1244 }
1245 
1246 
1247 static status_t
1248 devfs_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos,
1249 	void* buffer, size_t* _length)
1250 {
1251 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1252 	struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie;
1253 
1254 	//TRACE(("devfs_read: vnode %p, cookie %p, pos %Ld, len %p\n",
1255 	//	vnode, cookie, pos, _length));
1256 
1257 	if (!S_ISCHR(vnode->stream.type))
1258 		return B_BAD_VALUE;
1259 
1260 	if (pos < 0)
1261 		return B_BAD_VALUE;
1262 
1263 	if (vnode->stream.u.dev.partition != NULL) {
1264 		if (pos >= vnode->stream.u.dev.partition->info.size)
1265 			return B_BAD_VALUE;
1266 
1267 		translate_partition_access(vnode->stream.u.dev.partition, pos, *_length);
1268 	}
1269 
1270 	if (*_length == 0)
1271 		return B_OK;
1272 
1273 	// pass the call through to the device
1274 	return vnode->stream.u.dev.device->Read(cookie->device_cookie, pos, buffer,
1275 		_length);
1276 }
1277 
1278 
1279 static status_t
1280 devfs_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos,
1281 	const void* buffer, size_t* _length)
1282 {
1283 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1284 	struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie;
1285 
1286 	//TRACE(("devfs_write: vnode %p, cookie %p, pos %Ld, len %p\n",
1287 	//	vnode, cookie, pos, _length));
1288 
1289 	if (!S_ISCHR(vnode->stream.type))
1290 		return B_BAD_VALUE;
1291 
1292 	if (pos < 0)
1293 		return B_BAD_VALUE;
1294 
1295 	if (vnode->stream.u.dev.partition != NULL) {
1296 		if (pos >= vnode->stream.u.dev.partition->info.size)
1297 			return B_BAD_VALUE;
1298 
1299 		translate_partition_access(vnode->stream.u.dev.partition, pos, *_length);
1300 	}
1301 
1302 	if (*_length == 0)
1303 		return B_OK;
1304 
1305 	return vnode->stream.u.dev.device->Write(cookie->device_cookie, pos, buffer,
1306 		_length);
1307 }
1308 
1309 
1310 static status_t
1311 devfs_create_dir(fs_volume *_volume, fs_vnode *_dir, const char *name,
1312 	int perms)
1313 {
1314 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1315 	struct devfs_vnode *dir = (struct devfs_vnode *)_dir->private_node;
1316 
1317 	struct devfs_vnode *vnode = devfs_find_in_dir(dir, name);
1318 	if (vnode != NULL) {
1319 		return EEXIST;
1320 	}
1321 
1322 	vnode = devfs_create_vnode(fs, dir, name);
1323 	if (vnode == NULL) {
1324 		return B_NO_MEMORY;
1325 	}
1326 
1327 	// set up the new directory
1328 	init_directory_vnode(vnode, perms);
1329 	publish_node(sDeviceFileSystem, dir, vnode);
1330 
1331 	return B_OK;
1332 }
1333 
1334 
1335 static status_t
1336 devfs_open_dir(fs_volume *_volume, fs_vnode *_vnode, void **_cookie)
1337 {
1338 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1339 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1340 	struct devfs_dir_cookie *cookie;
1341 
1342 	TRACE(("devfs_open_dir: vnode %p\n", vnode));
1343 
1344 	if (!S_ISDIR(vnode->stream.type))
1345 		return B_BAD_VALUE;
1346 
1347 	cookie = (devfs_dir_cookie *)malloc(sizeof(devfs_dir_cookie));
1348 	if (cookie == NULL)
1349 		return B_NO_MEMORY;
1350 
1351 	// make sure the directory has up-to-date contents
1352 	scan_for_drivers_if_needed(vnode);
1353 
1354 	RecursiveLocker locker(&fs->lock);
1355 
1356 	cookie->current = vnode->stream.u.dir.dir_head;
1357 	cookie->state = ITERATION_STATE_BEGIN;
1358 
1359 	list_add_item(&vnode->stream.u.dir.cookies, cookie);
1360 	*_cookie = cookie;
1361 
1362 	return B_OK;
1363 }
1364 
1365 
1366 static status_t
1367 devfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_vnode, void *_cookie)
1368 {
1369 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1370 	struct devfs_dir_cookie *cookie = (devfs_dir_cookie *)_cookie;
1371 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1372 
1373 	TRACE(("devfs_free_dir_cookie: entry vnode %p, cookie %p\n", vnode, cookie));
1374 
1375 	RecursiveLocker locker(&fs->lock);
1376 
1377 	list_remove_item(&vnode->stream.u.dir.cookies, cookie);
1378 	free(cookie);
1379 	return B_OK;
1380 }
1381 
1382 
1383 static status_t
1384 devfs_read_dir(fs_volume *_volume, fs_vnode *_vnode, void *_cookie,
1385 	struct dirent *dirent, size_t bufferSize, uint32 *_num)
1386 {
1387 	struct devfs_vnode *vnode = (devfs_vnode *)_vnode->private_node;
1388 	struct devfs_dir_cookie *cookie = (devfs_dir_cookie *)_cookie;
1389 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1390 	status_t status = B_OK;
1391 	struct devfs_vnode *childNode = NULL;
1392 	const char *name = NULL;
1393 	struct devfs_vnode *nextChildNode = NULL;
1394 	int32 nextState = cookie->state;
1395 
1396 	TRACE(("devfs_read_dir: vnode %p, cookie %p, buffer %p, size %ld\n",
1397 		_vnode, cookie, dirent, bufferSize));
1398 
1399 	if (!S_ISDIR(vnode->stream.type))
1400 		return B_BAD_VALUE;
1401 
1402 	RecursiveLocker locker(&fs->lock);
1403 
1404 	switch (cookie->state) {
1405 		case ITERATION_STATE_DOT:
1406 			childNode = vnode;
1407 			name = ".";
1408 			nextChildNode = vnode->stream.u.dir.dir_head;
1409 			nextState = cookie->state + 1;
1410 			break;
1411 		case ITERATION_STATE_DOT_DOT:
1412 			childNode = vnode->parent;
1413 			name = "..";
1414 			nextChildNode = vnode->stream.u.dir.dir_head;
1415 			nextState = cookie->state + 1;
1416 			break;
1417 		default:
1418 			childNode = cookie->current;
1419 			if (childNode) {
1420 				name = childNode->name;
1421 				nextChildNode = childNode->dir_next;
1422 			}
1423 			break;
1424 	}
1425 
1426 	if (!childNode) {
1427 		*_num = 0;
1428 		return B_OK;
1429 	}
1430 
1431 	dirent->d_dev = fs->id;
1432 	dirent->d_ino = childNode->id;
1433 	dirent->d_reclen = strlen(name) + sizeof(struct dirent);
1434 
1435 	if (dirent->d_reclen > bufferSize)
1436 		return ENOBUFS;
1437 
1438 	status = user_strlcpy(dirent->d_name, name,
1439 		bufferSize - sizeof(struct dirent));
1440 	if (status < B_OK)
1441 		return status;
1442 
1443 	cookie->current = nextChildNode;
1444 	cookie->state = nextState;
1445 	*_num = 1;
1446 
1447 	return B_OK;
1448 }
1449 
1450 
1451 static status_t
1452 devfs_rewind_dir(fs_volume *_volume, fs_vnode *_vnode, void *_cookie)
1453 {
1454 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1455 	struct devfs_dir_cookie *cookie = (devfs_dir_cookie *)_cookie;
1456 	struct devfs *fs = (struct devfs *)_volume->private_volume;
1457 
1458 	TRACE(("devfs_rewind_dir: vnode %p, cookie %p\n", vnode, cookie));
1459 
1460 	if (!S_ISDIR(vnode->stream.type))
1461 		return B_BAD_VALUE;
1462 
1463 	RecursiveLocker locker(&fs->lock);
1464 
1465 	cookie->current = vnode->stream.u.dir.dir_head;
1466 	cookie->state = ITERATION_STATE_BEGIN;
1467 
1468 	return B_OK;
1469 }
1470 
1471 
1472 /*!	Forwards the opcode to the device driver, but also handles some devfs
1473 	specific functionality, like partitions.
1474 */
1475 static status_t
1476 devfs_ioctl(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, uint32 op,
1477 	void *buffer, size_t length)
1478 {
1479 	struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node;
1480 	struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
1481 
1482 	TRACE(("devfs_ioctl: vnode %p, cookie %p, op %ld, buf %p, len %ld\n",
1483 		vnode, cookie, op, buffer, length));
1484 
1485 	// we are actually checking for a *device* here, we don't make the
1486 	// distinction between char and block devices
1487 	if (S_ISCHR(vnode->stream.type)) {
1488 		switch (op) {
1489 			case B_GET_GEOMETRY:
1490 			{
1491 				struct devfs_partition* partition
1492 					= vnode->stream.u.dev.partition;
1493 				if (partition == NULL)
1494 					break;
1495 
1496 				device_geometry geometry;
1497 				status_t status = vnode->stream.u.dev.device->Control(
1498 					cookie->device_cookie, op, &geometry, length);
1499 				if (status < B_OK)
1500 					return status;
1501 
1502 				// patch values to match partition size
1503 				geometry.sectors_per_track = 0;
1504 				if (geometry.bytes_per_sector == 0)
1505 					geometry.bytes_per_sector = 512;
1506 				geometry.sectors_per_track = partition->info.size
1507 					/ geometry.bytes_per_sector;
1508 				geometry.head_count = 1;
1509 				geometry.cylinder_count = 1;
1510 
1511 				return user_memcpy(buffer, &geometry, sizeof(device_geometry));
1512 			}
1513 
1514 			case B_GET_DRIVER_FOR_DEVICE:
1515 			{
1516 #if 0
1517 				const char* path;
1518 				if (!vnode->stream.u.dev.driver)
1519 					return B_ENTRY_NOT_FOUND;
1520 				path = vnode->stream.u.dev.driver->path;
1521 				if (path == NULL)
1522 					return B_ENTRY_NOT_FOUND;
1523 
1524 				return user_strlcpy((char *)buffer, path, B_FILE_NAME_LENGTH);
1525 #endif
1526 				return B_ERROR;
1527 			}
1528 
1529 			case B_GET_PARTITION_INFO:
1530 			{
1531 				struct devfs_partition* partition
1532 					= vnode->stream.u.dev.partition;
1533 				if (!S_ISCHR(vnode->stream.type)
1534 					|| partition == NULL
1535 					|| length != sizeof(partition_info))
1536 					return B_BAD_VALUE;
1537 
1538 				return user_memcpy(buffer, &partition->info,
1539 					sizeof(partition_info));
1540 			}
1541 
1542 			case B_SET_PARTITION:
1543 				return B_NOT_ALLOWED;
1544 
1545 			case B_GET_PATH_FOR_DEVICE:
1546 			{
1547 				char path[256];
1548 				/* TODO: we might want to actually find the mountpoint
1549 				 * of that instance of devfs...
1550 				 * but for now we assume it's mounted on /dev
1551 				 */
1552 				strcpy(path, "/dev/");
1553 				get_device_name(vnode, path + 5, sizeof(path) - 5);
1554 				if (length && (length <= strlen(path)))
1555 					return ERANGE;
1556 				return user_strlcpy((char *)buffer, path, sizeof(path));
1557 			}
1558 
1559 			// old unsupported R5 private stuff
1560 
1561 			case B_GET_NEXT_OPEN_DEVICE:
1562 				dprintf("devfs: unsupported legacy ioctl B_GET_NEXT_OPEN_DEVICE\n");
1563 				return B_NOT_SUPPORTED;
1564 			case B_ADD_FIXED_DRIVER:
1565 				dprintf("devfs: unsupported legacy ioctl B_ADD_FIXED_DRIVER\n");
1566 				return B_NOT_SUPPORTED;
1567 			case B_REMOVE_FIXED_DRIVER:
1568 				dprintf("devfs: unsupported legacy ioctl B_REMOVE_FIXED_DRIVER\n");
1569 				return B_NOT_SUPPORTED;
1570 
1571 		}
1572 
1573 		return vnode->stream.u.dev.device->Control(cookie->device_cookie,
1574 			op, buffer, length);
1575 	}
1576 
1577 	return B_BAD_VALUE;
1578 }
1579 
1580 
1581 static status_t
1582 devfs_set_flags(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
1583 	int flags)
1584 {
1585 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1586 	struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie;
1587 
1588 	// we need to pass the O_NONBLOCK flag to the underlying device
1589 
1590 	if (!S_ISCHR(vnode->stream.type))
1591 		return B_NOT_ALLOWED;
1592 
1593 	return vnode->stream.u.dev.device->Control(cookie->device_cookie,
1594 		flags & O_NONBLOCK ? B_SET_NONBLOCKING_IO : B_SET_BLOCKING_IO, NULL, 0);
1595 }
1596 
1597 
1598 static status_t
1599 devfs_select(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
1600 	uint8 event, selectsync* sync)
1601 {
1602 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1603 	struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie;
1604 
1605 	if (!S_ISCHR(vnode->stream.type))
1606 		return B_NOT_ALLOWED;
1607 
1608 	// If the device has no select() hook, notify select() now.
1609 	if (!vnode->stream.u.dev.device->HasSelect())
1610 		return notify_select_event((selectsync*)sync, event);
1611 
1612 	return vnode->stream.u.dev.device->Select(cookie->device_cookie, event,
1613 		(selectsync*)sync);
1614 }
1615 
1616 
1617 static status_t
1618 devfs_deselect(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
1619 	uint8 event, selectsync* sync)
1620 {
1621 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1622 	struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie;
1623 
1624 	if (!S_ISCHR(vnode->stream.type))
1625 		return B_NOT_ALLOWED;
1626 
1627 	// If the device has no select() hook, notify select() now.
1628 	if (!vnode->stream.u.dev.device->HasDeselect())
1629 		return B_OK;
1630 
1631 	return vnode->stream.u.dev.device->Deselect(cookie->device_cookie, event,
1632 		(selectsync*)sync);
1633 }
1634 
1635 
1636 static bool
1637 devfs_can_page(fs_volume *_volume, fs_vnode *_vnode, void *cookie)
1638 {
1639 #if 0
1640 	struct devfs_vnode *vnode = (devfs_vnode *)_vnode->private_node;
1641 
1642 	//TRACE(("devfs_canpage: vnode %p\n", vnode));
1643 
1644 	if (!S_ISCHR(vnode->stream.type)
1645 		|| vnode->stream.u.dev.device->Node() == NULL
1646 		|| cookie == NULL)
1647 		return false;
1648 
1649 	return vnode->stream.u.dev.device->HasRead()
1650 		|| vnode->stream.u.dev.device->HasIO();
1651 #endif
1652 	// TODO: Obsolete hook!
1653 	return false;
1654 }
1655 
1656 
1657 static status_t
1658 devfs_read_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie,
1659 	off_t pos, const iovec *vecs, size_t count, size_t *_numBytes)
1660 {
1661 	struct devfs_vnode *vnode = (devfs_vnode *)_vnode->private_node;
1662 	struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
1663 
1664 	//TRACE(("devfs_read_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes));
1665 
1666 	if (!S_ISCHR(vnode->stream.type)
1667 		|| (!vnode->stream.u.dev.device->HasRead()
1668 			&& !vnode->stream.u.dev.device->HasIO())
1669 		|| cookie == NULL)
1670 		return B_NOT_ALLOWED;
1671 
1672 	if (pos < 0)
1673 		return B_BAD_VALUE;
1674 
1675 	if (vnode->stream.u.dev.partition != NULL) {
1676 		if (pos >= vnode->stream.u.dev.partition->info.size)
1677 			return B_BAD_VALUE;
1678 
1679 		translate_partition_access(vnode->stream.u.dev.partition, pos,
1680 			*_numBytes);
1681 	}
1682 
1683 	if (vnode->stream.u.dev.device->HasIO()) {
1684 		// TODO: use io_requests for this!
1685 	}
1686 
1687 	// emulate read_pages() using read()
1688 
1689 	status_t error = B_OK;
1690 	size_t bytesTransferred = 0;
1691 
1692 	size_t remainingBytes = *_numBytes;
1693 	for (size_t i = 0; i < count && remainingBytes > 0; i++) {
1694 		size_t toRead = min_c(vecs[i].iov_len, remainingBytes);
1695 		size_t length = toRead;
1696 
1697 		error = vnode->stream.u.dev.device->Read(cookie->device_cookie, pos,
1698 			vecs[i].iov_base, &length);
1699 		if (error != B_OK)
1700 			break;
1701 
1702 		pos += length;
1703 		bytesTransferred += length;
1704 		remainingBytes -= length;
1705 
1706 		if (length < toRead)
1707 			break;
1708 	}
1709 
1710 	*_numBytes = bytesTransferred;
1711 
1712 	return bytesTransferred > 0 ? B_OK : error;
1713 }
1714 
1715 
1716 static status_t
1717 devfs_write_pages(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
1718 	off_t pos, const iovec* vecs, size_t count, size_t* _numBytes)
1719 {
1720 	struct devfs_vnode *vnode = (devfs_vnode *)_vnode->private_node;
1721 	struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
1722 
1723 	//TRACE(("devfs_write_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes));
1724 
1725 	if (!S_ISCHR(vnode->stream.type)
1726 		|| (!vnode->stream.u.dev.device->HasWrite()
1727 			&& !vnode->stream.u.dev.device->HasIO())
1728 		|| cookie == NULL)
1729 		return B_NOT_ALLOWED;
1730 
1731 	if (pos < 0)
1732 		return B_BAD_VALUE;
1733 
1734 	if (vnode->stream.u.dev.partition != NULL) {
1735 		if (pos >= vnode->stream.u.dev.partition->info.size)
1736 			return B_BAD_VALUE;
1737 
1738 		translate_partition_access(vnode->stream.u.dev.partition, pos,
1739 			*_numBytes);
1740 	}
1741 
1742 	if (vnode->stream.u.dev.device->HasIO()) {
1743 		// TODO: use io_requests for this!
1744 	}
1745 
1746 	// emulate write_pages() using write()
1747 
1748 	status_t error = B_OK;
1749 	size_t bytesTransferred = 0;
1750 
1751 	size_t remainingBytes = *_numBytes;
1752 	for (size_t i = 0; i < count && remainingBytes > 0; i++) {
1753 		size_t toWrite = min_c(vecs[i].iov_len, remainingBytes);
1754 		size_t length = toWrite;
1755 
1756 		error = vnode->stream.u.dev.device->Write(cookie->device_cookie, pos,
1757 			vecs[i].iov_base, &length);
1758 		if (error != B_OK)
1759 			break;
1760 
1761 		pos += length;
1762 		bytesTransferred += length;
1763 		remainingBytes -= length;
1764 
1765 		if (length < toWrite)
1766 			break;
1767 	}
1768 
1769 	*_numBytes = bytesTransferred;
1770 
1771 	return bytesTransferred > 0 ? B_OK : error;
1772 }
1773 
1774 
1775 static status_t
1776 devfs_io(fs_volume *volume, fs_vnode *_vnode, void *_cookie,
1777 	io_request *request)
1778 {
1779 	TRACE(("[%ld] devfs_io(request: %p)\n", find_thread(NULL), request));
1780 
1781 	devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node;
1782 	devfs_cookie* cookie = (devfs_cookie*)_cookie;
1783 
1784 	bool isWrite = request->IsWrite();
1785 
1786 	if (!S_ISCHR(vnode->stream.type)
1787 		|| (((isWrite && !vnode->stream.u.dev.device->HasWrite())
1788 				|| (!isWrite && !vnode->stream.u.dev.device->HasRead()))
1789 			&& !vnode->stream.u.dev.device->HasIO())
1790 		|| cookie == NULL) {
1791 		request->SetStatusAndNotify(B_NOT_ALLOWED);
1792 		return B_NOT_ALLOWED;
1793 	}
1794 
1795 	if (vnode->stream.u.dev.partition != NULL) {
1796 		if (request->Offset() + (off_t)request->Length()
1797 				> vnode->stream.u.dev.partition->info.size) {
1798 			request->SetStatusAndNotify(B_BAD_VALUE);
1799 			return B_BAD_VALUE;
1800 		}
1801 		translate_partition_access(vnode->stream.u.dev.partition, request);
1802 	}
1803 
1804 	if (vnode->stream.u.dev.device->HasIO())
1805 		return vnode->stream.u.dev.device->IO(cookie->device_cookie, request);
1806 
1807 	synchronous_io_cookie synchronousCookie = {
1808 		vnode->stream.u.dev.device,
1809 		cookie->device_cookie
1810 	};
1811 
1812 	return vfs_synchronous_io(request,
1813 		request->IsWrite() ? &device_write : &device_read, &synchronousCookie);
1814 }
1815 
1816 
1817 static status_t
1818 devfs_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* stat)
1819 {
1820 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1821 
1822 	TRACE(("devfs_read_stat: vnode %p (%Ld), stat %p\n", vnode, vnode->id,
1823 		stat));
1824 
1825 	stat->st_ino = vnode->id;
1826 	stat->st_size = 0;
1827 	stat->st_mode = vnode->stream.type;
1828 
1829 	stat->st_nlink = 1;
1830 	stat->st_blksize = 65536;
1831 	stat->st_blocks = 0;
1832 
1833 	stat->st_uid = vnode->uid;
1834 	stat->st_gid = vnode->gid;
1835 
1836 	stat->st_atim = current_timespec();
1837 	stat->st_mtim = stat->st_ctim = vnode->modification_time;
1838 	stat->st_crtim = vnode->creation_time;
1839 
1840 	// TODO: this only works for partitions right now - if we should decide
1841 	//	to keep this feature, we should have a better solution
1842 	if (S_ISCHR(vnode->stream.type)) {
1843 		//device_geometry geometry;
1844 
1845 		// if it's a real block device, then let's report a useful size
1846 		if (vnode->stream.u.dev.partition != NULL) {
1847 			stat->st_size = vnode->stream.u.dev.partition->info.size;
1848 #if 0
1849 		} else if (vnode->stream.u.dev.info->control(cookie->device_cookie,
1850 					B_GET_GEOMETRY, &geometry, sizeof(struct device_geometry)) >= B_OK) {
1851 			stat->st_size = 1LL * geometry.head_count * geometry.cylinder_count
1852 				* geometry.sectors_per_track * geometry.bytes_per_sector;
1853 #endif
1854 		}
1855 
1856 		// is this a real block device? then let's have it reported like that
1857 		if (stat->st_size != 0)
1858 			stat->st_mode = S_IFBLK | (vnode->stream.type & S_IUMSK);
1859 	} else if (S_ISLNK(vnode->stream.type)) {
1860 		stat->st_size = vnode->stream.u.symlink.length;
1861 	}
1862 
1863 	return B_OK;
1864 }
1865 
1866 
1867 static status_t
1868 devfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const struct stat* stat,
1869 	uint32 statMask)
1870 {
1871 	struct devfs* fs = (struct devfs*)_volume->private_volume;
1872 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1873 
1874 	TRACE(("devfs_write_stat: vnode %p (0x%Lx), stat %p\n", vnode, vnode->id,
1875 		stat));
1876 
1877 	// we cannot change the size of anything
1878 	if (statMask & B_STAT_SIZE)
1879 		return B_BAD_VALUE;
1880 
1881 	RecursiveLocker locker(&fs->lock);
1882 
1883 	if (statMask & B_STAT_MODE) {
1884 		vnode->stream.type = (vnode->stream.type & ~S_IUMSK)
1885 			| (stat->st_mode & S_IUMSK);
1886 	}
1887 
1888 	if (statMask & B_STAT_UID)
1889 		vnode->uid = stat->st_uid;
1890 	if (statMask & B_STAT_GID)
1891 		vnode->gid = stat->st_gid;
1892 
1893 	if (statMask & B_STAT_MODIFICATION_TIME)
1894 		vnode->modification_time = stat->st_mtim;
1895 	if (statMask & B_STAT_CREATION_TIME)
1896 		vnode->creation_time = stat->st_crtim;
1897 
1898 	notify_stat_changed(fs->id, vnode->id, statMask);
1899 	return B_OK;
1900 }
1901 
1902 
1903 static status_t
1904 devfs_std_ops(int32 op, ...)
1905 {
1906 	switch (op) {
1907 		case B_MODULE_INIT:
1908 			add_debugger_command_etc("devfs_node", &dump_node,
1909 				"Print info on a private devfs node",
1910 				"<address>\n"
1911 				"Prints information on a devfs node given by <address>.\n",
1912 				0);
1913 			add_debugger_command_etc("devfs_cookie", &dump_cookie,
1914 				"Print info on a private devfs cookie",
1915 				"<address>\n"
1916 				"Prints information on a devfs cookie given by <address>.\n",
1917 				0);
1918 
1919 			legacy_driver_init();
1920 			return B_OK;
1921 
1922 		case B_MODULE_UNINIT:
1923 			remove_debugger_command("devfs_node", &dump_node);
1924 			remove_debugger_command("devfs_cookie", &dump_cookie);
1925 			return B_OK;
1926 
1927 		default:
1928 			return B_ERROR;
1929 	}
1930 }
1931 
1932 namespace {
1933 
1934 fs_volume_ops kVolumeOps = {
1935 	&devfs_unmount,
1936 	NULL,
1937 	NULL,
1938 	&devfs_sync,
1939 	&devfs_get_vnode,
1940 
1941 	// the other operations are not supported (attributes, indices, queries)
1942 	NULL,
1943 };
1944 
1945 fs_vnode_ops kVnodeOps = {
1946 	&devfs_lookup,
1947 	&devfs_get_vnode_name,
1948 
1949 	&devfs_put_vnode,
1950 	&devfs_remove_vnode,
1951 
1952 	&devfs_can_page,
1953 	&devfs_read_pages,
1954 	&devfs_write_pages,
1955 
1956 	&devfs_io,
1957 	NULL,	// cancel_io()
1958 
1959 	NULL,	// get_file_map
1960 
1961 	/* common */
1962 	&devfs_ioctl,
1963 	&devfs_set_flags,
1964 	&devfs_select,
1965 	&devfs_deselect,
1966 	&devfs_fsync,
1967 
1968 	&devfs_read_link,
1969 	NULL,	// symlink
1970 	NULL,	// link
1971 	NULL,	// unlink
1972 	NULL,	// rename
1973 
1974 	NULL,	// access
1975 	&devfs_read_stat,
1976 	&devfs_write_stat,
1977 	NULL,
1978 
1979 	/* file */
1980 	&devfs_create,
1981 	&devfs_open,
1982 	&devfs_close,
1983 	&devfs_free_cookie,
1984 	&devfs_read,
1985 	&devfs_write,
1986 
1987 	/* directory */
1988 	&devfs_create_dir,
1989 	NULL,	// remove_dir
1990 	&devfs_open_dir,
1991 	&devfs_close,
1992 		// same as for files - it does nothing for directories, anyway
1993 	&devfs_free_dir_cookie,
1994 	&devfs_read_dir,
1995 	&devfs_rewind_dir,
1996 
1997 	// attributes operations are not supported
1998 	NULL,
1999 };
2000 
2001 }	// namespace
2002 
2003 file_system_module_info gDeviceFileSystem = {
2004 	{
2005 		"file_systems/devfs" B_CURRENT_FS_API_VERSION,
2006 		0,
2007 		devfs_std_ops,
2008 	},
2009 
2010 	"devfs",					// short_name
2011 	"Device File System",		// pretty_name
2012 	0,							// DDM flags
2013 
2014 	NULL,	// identify_partition()
2015 	NULL,	// scan_partition()
2016 	NULL,	// free_identify_partition_cookie()
2017 	NULL,	// free_partition_content_cookie()
2018 
2019 	&devfs_mount,
2020 };
2021 
2022 
2023 //	#pragma mark - kernel private API
2024 
2025 
2026 extern "C" status_t
2027 devfs_unpublish_file_device(const char *path)
2028 {
2029 	// get the device node
2030 	devfs_vnode* node;
2031 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
2032 	if (status != B_OK)
2033 		return status;
2034 
2035 	if (!S_ISCHR(node->stream.type)) {
2036 		put_vnode(sDeviceFileSystem->volume, node->id);
2037 		return B_BAD_VALUE;
2038 	}
2039 
2040 	// if it is indeed a file device, unpublish it
2041 	FileDevice* device = dynamic_cast<FileDevice*>(node->stream.u.dev.device);
2042 	if (device == NULL) {
2043 		put_vnode(sDeviceFileSystem->volume, node->id);
2044 		return B_BAD_VALUE;
2045 	}
2046 
2047 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2048 
2049 	put_vnode(sDeviceFileSystem->volume, node->id);
2050 	return status;
2051 }
2052 
2053 
2054 extern "C" status_t
2055 devfs_publish_file_device(const char *path, const char *filePath)
2056 {
2057 	// create a FileDevice for the file
2058 	FileDevice* device = new(std::nothrow) FileDevice;
2059 	if (device == NULL)
2060 		return B_NO_MEMORY;
2061 	ObjectDeleter<FileDevice> deviceDeleter(device);
2062 
2063 	status_t error = device->Init(filePath);
2064 	if (error != B_OK)
2065 		return error;
2066 
2067 	// publish the device
2068 	error = publish_device(sDeviceFileSystem, path, device);
2069 	if (error != B_OK)
2070 		return error;
2071 
2072 	deviceDeleter.Detach();
2073 	return B_OK;
2074 }
2075 
2076 
2077 extern "C" status_t
2078 devfs_unpublish_partition(const char* path)
2079 {
2080 	devfs_vnode *node;
2081 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
2082 	if (status != B_OK)
2083 		return status;
2084 
2085 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2086 	put_vnode(sDeviceFileSystem->volume, node->id);
2087 	return status;
2088 }
2089 
2090 
2091 extern "C" status_t
2092 devfs_publish_partition(const char* name, const partition_info* info)
2093 {
2094 	if (name == NULL || info == NULL)
2095 		return B_BAD_VALUE;
2096 	TRACE(("publish partition: %s (device \"%s\", offset %Ld, size %Ld)\n",
2097 		name, info->device, info->offset, info->size));
2098 
2099 	devfs_vnode* device;
2100 	status_t status = get_node_for_path(sDeviceFileSystem, info->device,
2101 		&device);
2102 	if (status != B_OK)
2103 		return status;
2104 
2105 	status = add_partition(sDeviceFileSystem, device, name, *info);
2106 
2107 	put_vnode(sDeviceFileSystem->volume, device->id);
2108 	return status;
2109 }
2110 
2111 
2112 extern "C" status_t
2113 devfs_rename_partition(const char *devicePath, const char* oldName,
2114 	const char *newName)
2115 {
2116 	status_t status;
2117 	devfs_vnode *device, *node;
2118 	if (oldName == NULL || newName == NULL)
2119 		return B_BAD_VALUE;
2120 
2121 	status = get_node_for_path(sDeviceFileSystem, devicePath, &device);
2122 	if (status != B_OK)
2123 		return status;
2124 
2125 	RecursiveLocker locker(sDeviceFileSystem->lock);
2126 	node = devfs_find_in_dir(device->parent, oldName);
2127 	if (node == NULL)
2128 		return B_ENTRY_NOT_FOUND;
2129 
2130 	// check if the new path already exists
2131 	if (devfs_find_in_dir(device->parent, newName))
2132 		return B_BAD_VALUE;
2133 
2134 	char *name = strdup(newName);
2135 	if (name == NULL)
2136 		return B_NO_MEMORY;
2137 
2138 	devfs_remove_from_dir(device->parent, node, false);
2139 
2140 	free(node->name);
2141 	node->name = name;
2142 
2143 	devfs_insert_in_dir(device->parent, node, false);
2144 
2145 	notify_entry_moved(sDeviceFileSystem->id, device->parent->id, oldName,
2146 		device->parent->id, newName, node->id);
2147 	notify_stat_changed(sDeviceFileSystem->id, device->parent->id,
2148 		B_STAT_MODIFICATION_TIME);
2149 
2150 	return B_OK;
2151 }
2152 
2153 
2154 extern "C" status_t
2155 devfs_publish_directory(const char* path)
2156 {
2157 	RecursiveLocker locker(&sDeviceFileSystem->lock);
2158 
2159 	return publish_directory(sDeviceFileSystem, path);
2160 }
2161 
2162 
2163 extern "C" status_t
2164 devfs_unpublish_device(const char* path, bool disconnect)
2165 {
2166 	devfs_vnode* node;
2167 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
2168 	if (status != B_OK)
2169 		return status;
2170 
2171 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2172 
2173 	if (status == B_OK && disconnect)
2174 		vfs_disconnect_vnode(sDeviceFileSystem->id, node->id);
2175 
2176 	put_vnode(sDeviceFileSystem->volume, node->id);
2177 	return status;
2178 }
2179 
2180 
2181 //	#pragma mark - device_manager private API
2182 
2183 
2184 status_t
2185 devfs_publish_device(const char* path, BaseDevice* device)
2186 {
2187 	return publish_device(sDeviceFileSystem, path, device);
2188 }
2189 
2190 
2191 status_t
2192 devfs_unpublish_device(BaseDevice* device, bool disconnect)
2193 {
2194 	devfs_vnode* node;
2195 	status_t status = get_vnode(sDeviceFileSystem->volume, device->ID(),
2196 		(void**)&node);
2197 	if (status != B_OK)
2198 		return status;
2199 
2200 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2201 
2202 	if (status == B_OK && disconnect)
2203 		vfs_disconnect_vnode(sDeviceFileSystem->id, node->id);
2204 
2205 	put_vnode(sDeviceFileSystem->volume, node->id);
2206 	return status;
2207 }
2208 
2209 
2210 //	#pragma mark - support API for legacy drivers
2211 
2212 
2213 extern "C" status_t
2214 devfs_rescan_driver(const char* driverName)
2215 {
2216 	TRACE(("devfs_rescan_driver: %s\n", driverName));
2217 
2218 	return legacy_driver_rescan(driverName);
2219 }
2220 
2221 
2222 extern "C" status_t
2223 devfs_publish_device(const char* path, device_hooks* hooks)
2224 {
2225 	return legacy_driver_publish(path, hooks);
2226 }
2227 
2228 
2229