Linux: ndevfs - a "nano" devfs

Submitted by Kedar Sovani
on June 25, 2005 - 12:54pm

In order to mitigate the concerns raised by few about the removal of devfs [story] from the mainline kernel, GregKH announced ndevfs - a "nano" devfs. ndevfs is a simple ramfs based filesystem. It creates/deletes nodes in the /dev directory dynamically in the format seen in devfs. The patch has been satisfactory for most of the users. Greg adds:

"I'm not going to be submitting this. But what it is, is a nice proof-of-concept for people who 'just can't live without a in-kernel devfs' to show that it can be done in less than 300 lines of code, and only 6 hooks (2 functions in 3 different places) in the main kernel tree. That is managable outside of the main kernel for years, with almost little to no effort."


From: Greg KH
To: linux-kernel 
Subject: [ANNOUNCE] ndevfs - a "nano" devfs
Date: Fri, 06/24/2005 - 14:03 
Now I just know I'm going to regret this somehow... Anyway, here's yet-another-ramfs-based filesystem, ndevfs. It's a very tiny: $ size fs/ndevfs/inode.o text data bss dec hex filename 1571 200 8 1779 6f3 fs/ndevfs/inode.o replacement for devfs for those embedded users who just can't live without the damm thing. It doesn't allow subdirectories, and only uses LSB compliant names. But it works, and should be enough for people to use, if they just can't wean themselves off of the idea of an in-kernel fs to provide device nodes. Now, with this, is there still anyone out there who just can't live without devfs in their kernel? Damm, the depths I've sunk to these days, I'm such a people pleaser... Comments? Questions? Criticisms? I need sleep. greg k-h --------------- ndevfs - a "nano" devfs For embedded people to use since they seem to hate userspace. Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 3 fs/Kconfig | 3 fs/Makefile | 1 fs/ndevfs/Makefile | 4 fs/ndevfs/inode.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/partitions/check.c | 6 + include/linux/ndevfs.h | 13 ++ 7 files changed, 279 insertions(+) --- gregkh-2.6.orig/fs/Kconfig 2005-06-24 01:05:59.000000000 -0700 +++ gregkh-2.6/fs/Kconfig 2005-06-24 01:06:02.000000000 -0700 @@ -1700,6 +1700,9 @@ config RXRPC tristate +config NDEV_FS + bool "Nano Device File System" + endmenu menu "Partition Types" --- gregkh-2.6.orig/fs/Makefile 2005-06-24 01:05:59.000000000 -0700 +++ gregkh-2.6/fs/Makefile 2005-06-24 01:06:02.000000000 -0700 @@ -95,3 +95,4 @@ obj-$(CONFIG_HOSTFS) += hostfs/ obj-$(CONFIG_HPPFS) += hppfs/ obj-$(CONFIG_DEBUG_FS) += debugfs/ +obj-$(CONFIG_NDEV_FS) += ndevfs/ --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gregkh-2.6/include/linux/ndevfs.h 2005-06-24 01:06:02.000000000 -0700 @@ -0,0 +1,13 @@ +#ifndef _NDEVFS_H_ +#define _NDEVFS_H_ + +#if defined(CONFIG_NDEV_FS) +extern void ndevfs_create(const char *name, dev_t dev, int is_char); +extern void ndevfs_remove(const char *name); +#else +static inline void ndevfs_create(const char *name, dev_t dev, int is_char) {} +static inline void ndevfs_remove(const char *name) {} +#endif + +#endif + --- gregkh-2.6.orig/drivers/base/class.c 2005-06-24 01:05:59.000000000 -0700 +++ gregkh-2.6/drivers/base/class.c 2005-06-24 01:06:02.000000000 -0700 @@ -17,6 +17,7 @@ #include <linux/string.h> #include <linux/kdev_t.h> #include <linux/err.h> +#include <linux/ndevfs.h> #include "base.h" #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) @@ -492,6 +493,7 @@ attr->store = NULL; class_device_create_file(class_dev, attr); class_dev->devt_attr = attr; + ndevfs_create(class_dev->class_id, class_dev->devt, 1); } class_device_add_attrs(class_dev); @@ -595,6 +597,7 @@ class_device_remove_file(class_dev, class_dev->devt_attr); kfree(class_dev->devt_attr); class_dev->devt_attr = NULL; + ndevfs_remove(class_dev->class_id); } class_device_remove_attrs(class_dev); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gregkh-2.6/fs/ndevfs/Makefile 2005-06-24 01:06:02.000000000 -0700 @@ -0,0 +1,4 @@ +ndevfs-objs := inode.o + +obj-$(CONFIG_NDEV_FS) += ndevfs.o + --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gregkh-2.6/fs/ndevfs/inode.c 2005-06-24 01:06:02.000000000 -0700 @@ -0,0 +1,249 @@ +/* + * inode.c - part of ndevfs, a tiny little device file system + * + * Copyright (C) 2004,2005 Greg Kroah-Hartman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * Written for all of the people out there who just hate userspace solutions. + * + */ + +/* uncomment to get debug messages */ +#define DEBUG + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/pagemap.h> +#include <linux/init.h> +#include <linux/namei.h> +#include <linux/device.h> +#include <linux/ndevfs.h> + +#define MAGIC 0x64756d62 + +struct entry { + struct list_head node; + struct dentry *dentry; + char name[BUS_ID_SIZE]; +}; +static LIST_HEAD(entries); + +static struct vfsmount *mount; +static int mount_count; + +static struct file_operations stupid_file_ops = { + .read = generic_file_read, + .write = generic_file_write, + .mmap = generic_file_mmap, + .fsync = simple_sync_file, + .llseek = generic_file_llseek, +}; + +static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &stupid_file_ops; + break; + case S_IFDIR: + inode->i_op = &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inode->i_nlink++; + break; + } + } + return inode; +} + +/* SMP-safe */ +static int mknod(struct inode *dir, struct dentry *dentry, + int mode, dev_t dev) +{ + struct inode *inode = get_inode(dir->i_sb, mode, dev); + int error = -EPERM; + + if (dentry->d_inode) + return -EEXIST; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} + +static inline int positive(struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +static int fill_super(struct super_block *sb, void *data, int silent) +{ + static struct tree_descr files[] = {{""}}; + + return simple_fill_super(sb, MAGIC, files); +} + +static struct super_block *get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + return get_sb_single(fs_type, flags, data, fill_super); +} + +static void remove(struct dentry *dentry) +{ + struct dentry *parent; + + if (!dentry) + return; + + parent = dentry->d_parent; + if (!parent || !parent->d_inode) + return; + + down(&parent->d_inode->i_sem); + if (positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + simple_rmdir(parent->d_inode, dentry); + else + simple_unlink(parent->d_inode, dentry); + dput(dentry); + } + } + up(&parent->d_inode->i_sem); + simple_release_fs(&mount, &mount_count); +} + +/** + * ndevfs_create - create a device node in ndevfs + * + * @name: the name to create + * @dev: the dev_t of the node + * @is_char: if the node is a char device or not + */ +void ndevfs_create(const char *name, dev_t dev, int is_char) +{ + struct dentry *parent; + struct dentry *dentry; + struct entry *entry; + int err; + int mode = S_IRUSR | S_IWUSR; + + pr_debug("ndevfs: creating file '%s' with major %d and minor %d\n", + name, MAJOR(dev), MINOR(dev)); + + if (is_char) + mode |= S_IFCHR; + else + mode |= S_IFBLK; + + err = simple_pin_fs("ndevfs", &mount, &mount_count); + if (err) + return; + + /* everything is at the root fs, no directories allowed */ + if (mount && mount->mnt_sb) { + parent = mount->mnt_sb->s_root; + } else { + pr_debug("%s: no parent?\n", __FUNCTION__); + goto error; + } + + down(&parent->d_inode->i_sem); + dentry = lookup_one_len(name, parent, strlen(name)); + if (!IS_ERR(dentry)) + err = mknod(parent->d_inode, dentry, mode, dev); + else + err = PTR_ERR(dentry); + up(&parent->d_inode->i_sem); + + if (err) + goto error; + + entry = kmalloc(sizeof(struct entry), GFP_KERNEL); + if (!entry) { + remove(dentry); + err = -ENOMEM; + goto error; + } + entry->dentry = dentry; + strcpy(&entry->name[0], name); + list_add(&entry->node, &entries); + return; + +error: + pr_debug("%s failed with error %d\n", __FUNCTION__, err); + simple_release_fs(&mount, &mount_count); +} +EXPORT_SYMBOL_GPL(ndevfs_create); + +/** + * ndevfs_remove - removes the node from the fs + * + * @name: the name to remove. + */ +void ndevfs_remove(const char *name) +{ + struct entry *entry; + struct dentry *dentry = NULL; + + pr_debug("ndevfs: removing file '%s'\n", name); + + list_for_each_entry(entry, &entries, node) { + if (strcmp(name, &entry->name[0]) == 0) { + dentry = entry->dentry; + break; + } + } + if (!dentry) { + pr_debug("%s: can't find %s\n", __FUNCTION__, name); + return; + } + remove (dentry); +} +EXPORT_SYMBOL_GPL(ndevfs_remove); + +static struct file_system_type fs_type = { + .owner = THIS_MODULE, + .name = "ndevfs", + .get_sb = get_sb, + .kill_sb = kill_litter_super, +}; + +static int __init ndevfs_init(void) +{ + return register_filesystem(&fs_type); +} + +static void __exit ndevfs_exit(void) +{ + simple_release_fs(&mount, &mount_count); + unregister_filesystem(&fs_type); +} + +core_initcall(ndevfs_init); +module_exit(ndevfs_exit); +MODULE_LICENSE("GPL"); + --- gregkh-2.6.orig/fs/partitions/check.c 2005-06-24 01:05:59.000000000 -0700 +++ gregkh-2.6/fs/partitions/check.c 2005-06-24 01:06:02.000000000 -0700 @@ -18,6 +18,7 @@ #include #include #include +#include #include "check.h" @@ -273,6 +274,7 @@ p->start_sect = 0; p->nr_sects = 0; p->reads = p->writes = p->read_sectors = p->write_sectors = 0; + ndevfs_remove(kobject_name(&p->kobj)); kobject_unregister(&p->kobj); } @@ -296,6 +298,7 @@ p->kobj.parent = &disk->kobj; p->kobj.ktype = &ktype_part; kobject_register(&p->kobj); + ndevfs_create(kobject_name(&p->kobj), MKDEV(disk->major, p->partno), 0); disk->part[part-1] = p; } @@ -323,6 +326,8 @@ if ((err = kobject_add(&disk->kobj))) return; disk_sysfs_symlinks(disk); + ndevfs_create(kobject_name(&disk->kobj), + MKDEV(disk->major, disk->first_minor), 0); kobject_hotplug(&disk->kobj, KOBJ_ADD); /* No minors to use for partitions */ @@ -420,6 +425,7 @@ sysfs_remove_link(&disk->driverfs_dev->kobj, "block"); put_device(disk->driverfs_dev); } + ndevfs_remove(kobject_name(&disk->kobj)); kobject_hotplug(&disk->kobj, KOBJ_REMOVE); kobject_del(&disk->kobj); }

Related Links:

Good start...

AssBuilder (not verified)
on
June 25, 2005 - 6:27pm

There's got to be a middle ground between devfs and udev and this might be it. If done correctly, then both parties should be happy. Good to see K-H trying to meet his critics in the middle.

Say, did he ever list out all those reasons why udev was better than devfs? Maybe he can incorporate those features into this ndevfs.

Yes, I have, see the udev pac

Greg K-H (not verified)
on
June 25, 2005 - 8:49pm

Yes, I have, see the udev package for the list of the differences
(it's in the doc/ directory).

Also see the udev FAQ for more details:
http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev-FAQ

What's keeping you...

AssHammer (not verified)
on
July 1, 2005 - 11:23am

What's keeping you from using ndevfs in place of devfs in the kernel? If devfs is going to be ripped out anyway, why not submit ndevfs as its replacement (provide the appropriate caveats in the menuconfig, of course).

Looks like you did good with ndevfs. Put it in there and let it shine!

Agreed. Sometimes one gets th

peschmae (not verified)
on
June 26, 2005 - 12:15am

Agreed. Sometimes one gets the impressions some kernel hackers only shout and don't listen (see reiser4-discussions) but it seems not all of them (at least once in a while) ;-)

blabla

Anonym (not verified)
on
June 27, 2005 - 1:25am

indeed hans reiser has a strange view of reality.

concerning ndevfs it's absolutely not needed: use your own static /dev inside of initramfs. if you need you can later start udev.

That's not always so.

Anonymous/00001 (not verified)
on
June 27, 2005 - 1:54am

You forget the case of automatic hardware detection.
The point of devfs is that kernel knows hardware configuration. Userspace sees only /dev/ and has to guess. DevFS solves that problem: if there is hardware - you have nodes. No hardware - no nodes. Easy.

Kernel already has everything, I repeat *everything*, userspace needs to know. So why does one need duplicate all that stuff? What's more - with specifically tailored userspace deamon. That's just redundancy.

If you have noticed the only culprit was naming (well, and maintanance). And the people who use devfs said to not care about naming as long as it worked. I honestly never seen anyone who cares about dev nodes naming. And most of such cases can be solved either by (1) userspace application reconfiguration or (2) sym-link. Most of portable applications has to deal with multiple naming conventions anyway - you would not expect *BSD be LSB compatible :-)

LSB is relevant to... - well let us be honest - to no-one.
For example RedHat was ignoring it for quite some time. And everyone was Okay. And it just happened that Fedora was made to be LSB compliant, so after takeover, RedHat anounced LSB support. Neat. Most of commercial software anyway is tailored specifically for RedHat _and_ SUSE/LSB - since SUSE supported LSB from earlier days. And RedHat was obviosly conformant and compatible... well with earlier RedHats. And RedHat as usually never ever ships point releases of libraries. Compared to that problem, application developers have to solve, device node naming is not problem at all. And SUSE started doing the same. Personal experience.

Kernel already has everything

tbf (not verified)
on
June 27, 2005 - 6:47am

Kernel already has everything, I repeat *everything*, userspace needs to know. So why does one need duplicate all that stuff? What's more - with specifically tailored userspace deamon. That's just redundancy.

Well, and it exposes all that information via sysfs.
So as far as I understand sysfs the following should be enough for populating /dev, if you don't have hotplugging hardware:

find /sys/block /sys/class -name dev -printf '%h\n' | 

while read d
do 
    n=${d//*\//}
    i=$(<$d/dev)
    mknod $n ${d:5:1} ${i/:/ }
done

Wondering now, why udevd is that "large" and slow...

And still unhappy with the fact, that udev forces me to load bloat like the entire SCSI subsystem on startup, just cause I want to use my scanner from time to time. In good old devfs days I could build the entire SCSI monster and let devfs load it, once some program was looking for a SCSI subsystem.

Wondering now, why udevd is t

THe_ZiPMaN
on
June 27, 2005 - 7:34am

Wondering now, why udevd is that "large" and slow...

Maybe because it does more things than just create dev nodes; for example it allows consistent naming for hotpluggable devices despite the order you activate them.

And still unhappy with the fact, that udev forces me to load bloat like the entire SCSI subsystem on startup, just cause I want to use my scanner from time to time. In good old devfs days I could build the entire SCSI monster and let devfs load it, once some program was looking for a SCSI subsystem.

Simply blacklist your controllers' scsi drivers in hotplug. Then prepare a simple script that modprobes the driver and starts sane.

Devfs is simply horrible and hard to manage and its naming convention always creates troubles (for example with grub). I'd prefer to handle hand made nodes.

--
There are only 10 types of people in this world:
those who understand binary, and those wh

Eh??

Ratta
on
June 27, 2005 - 9:20am

Blacklist the driver and write a script that runs modprobe would be the solution?
And udev would be superior to devfs if i have to do a such hack?
Without forgetting that i have to be root to run modprobe, while i can confingure devfs to automatically run modprobe when any userspace program needs it.

I agree that devfs naming convention is problematic and should be solved, BTW.

The problem with that is that

Anonymous2 (not verified)
on
June 27, 2005 - 6:18pm

The problem with that is that modprobe can take arbitrarily long to find a driver to load, which blocks the program forever. Repeated modprobing is exceptionally slow on slow computers. Also, if there are two drivers that provide the same device, which one is modprobe going to choose? There is no way for devfs to provide it with the information of which one you 'meant'.

> Without forgetting that i h

J. (not verified)
on
June 28, 2005 - 9:06am

> Without forgetting that i have to be root to run modprobe

Your /etc/rc.local or Sysvinit runs scripts as root by default. Its easy to incorporate a script into one of those.

> while i can confingure devfs to automatically run modprobe when any userspace program needs it.

Udev does this as well.

> I agree that devfs naming convention is problematic and should be solved, BTW.

Go hack the code then. Which, from what i've heard, is spaghetti mess. The original developer vanished from earth somehow. The code has been unchanged for years. So when those people who comaplain would have actually touched the code or hacked a viable alternative we'd be futher. Luckily, Greg KH made a working version as alternative for these people. What a service, indeed.

Or you could just live with the 'problem'.

Morons and Parrots Unite...

Post-Coital Symphony (not verified)
on
June 28, 2005 - 12:27pm

All everyone seems to do is parrot.

"Go hack the code then. Which, from what i've heard, is spaghetti mess."

Riiiiiiight.... Like you'd know. I'm sure "what I heard" is a good basis for making a decision to change a big kernel subsystem. It's also a great rationale for blindly throwing support behind it.

I'm not saying you are wrong. Maybe devfs is a POS and needs to go. But maybe it should be ripped out and rewritten a la the IDE subsystem instead.

Here's the code:

http://lxr.linux.no/source/fs/devfs/

Hey K-H: why not keep devfs, whether re-written, or in the new form you propose. The kernel will always have a default policy at boot time, but devices should be able to be renamed/aliased on the fly via a daemon interfaced with an ioctl. Best of both worlds, potentially...

Uh, in what way does udev do

Anonymous2 (not verified)
on
June 29, 2005 - 9:51am

Uh, in what way does udev do this? Udev, as a userspace program, can't possibly intercept filesystem I/O operations in /dev unless there is a kernel callback specifically for such a purpose.

Easy

AstralStorm (not verified)
on
June 30, 2005 - 2:57am

It uses hotplug and there are special hooks for hotplug to know that a device is in use. (See option "Kernel event interface")
It can do many things with it: from creating nodes through running a given command.
Hal also uses this interface.

Hmm... Just a random thought:

tbf (not verified)
on
July 1, 2005 - 7:42am

Hmm... Just a random thought: Maybe overlaying udev by fuse might do the trick. In that case I really would have to admit, devfs being obsolete.

Not necessary. When kernel sp

AnonymousC (not verified)
on
July 1, 2005 - 5:10pm

Not necessary. When kernel spots an access to a device node it will try to load the driver for it. It doesn't depend on whether you are using udev or devfs. The mechanism has been in place for a long time.

The problem here is accessing

Dave (not verified)
on
July 3, 2005 - 3:46pm

The problem here is accessing nodes that don't currently exist as files. By benefit of being its own filesystem, devfs could tell when someone tried to access a nonexistent node, and instead of returning a file-doesn't-exist error, it could figure out what needed to be loaded and load that.

Since Udev is filesystem-agnostic, it can't intercept these accesses to nonexistent device node files, making it either necessary to manually create the nodes or preload the driver beforehand.

The only circumstance where I've personally had trouble with this, though, was with the Loopback block device driver. My distribution's kernel compiles it as a module, and unfortunately, udev isn't able to autoload it, so I had to manually modprobe it at bootup.

Distro?

Gentoober (not verified)
on
July 4, 2005 - 3:12pm

# /etc/modules.autoload.d/kernel-2.6: kernel modules to load when system boots.
# $Header: /var/cvsroot/gentoo-src/rc-scripts/etc/modules.autoload.d/kernel-2.6,v 1.1 2003/07/16 18:13:45 azarah Exp $
#
# Note that this file is for 2.6 kernels.
#
# Add the names of modules that you'd like to load when the system
# starts into this file, one per line. Comments begin with # and
# are ignored. Read man modules.autoload for additional details.

# For example:
# 3c59x

THat's actually what I meant

Dave (not verified)
on
July 4, 2005 - 3:21pm

THat's actually what I meant by manually loading the driver. Under DevFS, you wouldn't need to tell the kernel to load the module at boot-time.

"Manually"

Gentoober (not verified)
on
July 5, 2005 - 6:40am

Would involve doing a modprobe at the command line, IMO.
Having a configuration script in /etc that lets you specify modules and arguments is more of a feature than a bug.
The challenge is to make it less of an easter-egg hunt for the user to map the hardare to the modules.
Getting your Treo600 synched involves magically knowing to enable USB Serial Converters and the Handspring module at kernel compile-time, and then getting "visor" into /etc/modules.autoload/kernel-2.6, which I would attack as "less than obvious for the FNG".

The problem here is accessing

Dave (not verified)
on
July 3, 2005 - 3:54pm

The problem here is accessing nodes that don't currently exist as files. By benefit of being its own filesystem, devfs could tell when someone tried to access a nonexistent node, and instead of returning a file-doesn't-exist error, it could figure out what needed to be loaded and load that.

Since Udev is filesystem-agnostic, it can't intercept these accesses to nonexistent device node files, making it either necessary to manually create the nodes or preload the driver beforehand.

The only circumstance where I've personally had trouble with this, though, was with the Loopback block device driver. My distribution's kernel compiles it as a module, and unfortunately, udev isn't able to autoload it, so I had to manually modprobe it at bootup.

Uhh... A bit of information i

Anonymous (not verified)
on
November 4, 2005 - 5:29pm

Uhh... A bit of information is missing here:

How does Joe User enable nDevFS, and use it instead of uDev?

He updates and applies the pa

Ano Nymous
on
November 5, 2005 - 4:40am

Joe updates and applies the patch, enables the config option, and mounts the thing. And just don't run udev (which is in user space). How to disable Udv may be distro specific.

Ndevfs is mainly made to show embedded people that they don't really need devfs, but instead can use something much smaller and simpler which is also easy to keep up to date with the current kernel as a custom patch.

Ahh... Thank you very, very,

Anonymous (not verified)
on
November 5, 2005 - 12:02pm

Ahh... Thank you very, very, very much.

Uh, wait a minute... Should h

Anonymous (not verified)
on
November 5, 2005 - 12:08pm

Uh, wait a minute... Should have asked before: do I need devfsd, the DevFS daemon?

Does not work.

Anonymous (not verified)
on
November 5, 2005 - 12:53pm

It seems my bootloader needs an extra option to mount nDevFS. You know, sort of like how you have to specify "devfs=nomount" to use uDev prior to kernel 2.6.13? I think I need something like "ndevfs=mount" in order to use it...

Assumin you aret he same anon

Ano Nymous
on
November 6, 2005 - 4:46am

Assumin you aret he same anonymous as the post before; no you don't need the devfs daemon. Ndefvs has nothing to do with devfs.

You need to mount ndevfs yourself, somewhere at the beginning of the init pocess, if you really want to use it, which I think the average Joe should't want (and most non-Joes either).

Why not? It doesn't work well

Anonymous (not verified)
on
November 6, 2005 - 8:28am

Why not? It doesn't work well, or something?

No, and it isn't tested very

Ano Nymous
on
November 6, 2005 - 11:53am

Not really, and it isn't tested very well. Its main deficiency at the moment is that it doesn't support directories.

It is more a reference implementation to show what can be done and used by people who want this, it was never meant to be serious.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.