diff options
author | jh <jh@FreeBSD.org> | 2010-08-12 15:29:07 +0000 |
---|---|---|
committer | jh <jh@FreeBSD.org> | 2010-08-12 15:29:07 +0000 |
commit | 2e34ad384bd3205d66ee6ab608cb257848c7e808 (patch) | |
tree | 6b06256a02fb0fa029aa1464f21f7d57c5d67644 /sys/fs/devfs/devfs_devs.c | |
parent | 16e60f2ae7dae83cc366e00660498e8588bdc5b1 (diff) | |
download | FreeBSD-src-2e34ad384bd3205d66ee6ab608cb257848c7e808.zip FreeBSD-src-2e34ad384bd3205d66ee6ab608cb257848c7e808.tar.gz |
Allow user created symbolic links to cover device files and directories
if the device file appears during or after the link creation.
User created symbolic links are now inserted at the head of the
directory entry list after the "." and ".." entries. A new directory
entry flag DE_COVERED indicates that an entry is covered by a symbolic
link.
PR: kern/114057
Reviewed by: kib
Idea from: kib
Discussed on: freebsd-current (mostly silence)
Diffstat (limited to 'sys/fs/devfs/devfs_devs.c')
-rw-r--r-- | sys/fs/devfs/devfs_devs.c | 33 |
1 files changed, 28 insertions, 5 deletions
diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index b14a41f..a11544f 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -158,13 +158,15 @@ devfs_free(struct cdev *cdev) } struct devfs_dirent * -devfs_find(struct devfs_dirent *dd, const char *name, int namelen) +devfs_find(struct devfs_dirent *dd, const char *name, int namelen, int type) { struct devfs_dirent *de; TAILQ_FOREACH(de, &dd->de_dlist, de_list) { if (namelen != de->de_dirent->d_namlen) continue; + if (type != 0 && type != de->de_dirent->d_type) + continue; if (bcmp(name, de->de_dirent->d_name, namelen) != 0) continue; break; @@ -235,14 +237,19 @@ devfs_vmkdir(struct devfs_mount *dmp, char *name, int namelen, struct devfs_dire else dd->de_inode = alloc_unr(devfs_inos); - /* Create the "." entry in the new directory */ + /* + * "." and ".." are always the two first entries in the + * de_dlist list. + * + * Create the "." entry in the new directory. + */ de = devfs_newdirent(".", 1); de->de_dirent->d_type = DT_DIR; de->de_flags |= DE_DOT; TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); de->de_dir = dd; - /* Create the ".." entry in the new directory */ + /* Create the ".." entry in the new directory. */ de = devfs_newdirent("..", 2); de->de_dirent->d_type = DT_DIR; de->de_flags |= DE_DOTDOT; @@ -382,7 +389,7 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup) struct devfs_dirent *de; struct devfs_dirent *dd; struct cdev *pdev; - int j; + int de_flags, j; char *q, *s; sx_assert(&dm->dm_lock, SX_XLOCKED); @@ -454,12 +461,27 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup) continue; if (*q != '/') break; - de = devfs_find(dd, s, q - s); + de = devfs_find(dd, s, q - s, 0); if (de == NULL) de = devfs_vmkdir(dm, s, q - s, dd, 0); + else if (de->de_dirent->d_type == DT_LNK) { + de = devfs_find(dd, s, q - s, DT_DIR); + if (de == NULL) + de = devfs_vmkdir(dm, s, q - s, dd, 0); + de->de_flags |= DE_COVERED; + } s = q + 1; dd = de; + KASSERT(dd->de_dirent->d_type == DT_DIR && + (dd->de_flags & (DE_DOT | DE_DOTDOT)) == 0, + ("%s: invalid directory (si_name=%s)", + __func__, cdp->cdp_c.si_name)); + } + de_flags = 0; + de = devfs_find(dd, s, q - s, DT_LNK); + if (de != NULL) + de_flags |= DE_COVERED; de = devfs_newdirent(s, q - s); if (cdp->cdp_c.si_flags & SI_ALIAS) { @@ -477,6 +499,7 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup) de->de_mode = cdp->cdp_c.si_mode; de->de_dirent->d_type = DT_CHR; } + de->de_flags |= de_flags; de->de_inode = cdp->cdp_inode; de->de_cdp = cdp; #ifdef MAC |