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