patch-2.1.123 linux/fs/namei.c
Next file: linux/fs/nfs/dir.c
Previous file: linux/fs/msdos/namei.c
Back to the patch index
Back to the overall index
- Lines: 222
- Date:
Tue Sep 22 17:47:27 1998
- Orig file:
v2.1.122/linux/fs/namei.c
- Orig date:
Thu Sep 17 17:53:38 1998
diff -u --recursive --new-file v2.1.122/linux/fs/namei.c linux/fs/namei.c
@@ -280,7 +280,19 @@
return result;
}
-static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry)
+/*
+ * The bitmask for a lookup event:
+ * - follow links at the end
+ * - require a directory
+ * - ending slashes ok even for nonexistent files
+ * - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW (1)
+#define LOOKUP_DIRECTORY (2)
+#define LOOKUP_SLASHOK (4)
+#define LOOKUP_CONTINUE (8)
+
+static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
{
struct inode * inode = dentry->d_inode;
@@ -290,7 +302,7 @@
current->link_count++;
/* This eats the base */
- result = inode->i_op->follow_link(dentry, base);
+ result = inode->i_op->follow_link(dentry, base, follow);
current->link_count--;
dput(dentry);
return result;
@@ -320,9 +332,10 @@
* This is the basic name resolution function, turning a pathname
* into the final dentry.
*/
-struct dentry * lookup_dentry(const char * name, struct dentry * base, int follow_link)
+struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned int lookup_flags)
{
struct dentry * dentry;
+ struct inode *inode;
if (*name == '/') {
if (base)
@@ -338,22 +351,16 @@
if (!*name)
goto return_base;
+ inode = base->d_inode;
+ lookup_flags &= LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK;
+
/* At this point we know we have a real path component. */
for(;;) {
int err;
unsigned long hash;
struct qstr this;
- struct inode *inode;
- char c, follow;
-
- dentry = ERR_PTR(-ENOENT);
- inode = base->d_inode;
- if (!inode)
- break;
-
- dentry = ERR_PTR(-ENOTDIR);
- if (!inode->i_op || !inode->i_op->lookup)
- break;
+ unsigned int flags;
+ unsigned int c;
err = permission(inode, MAY_EXEC);
dentry = ERR_PTR(err);
@@ -361,23 +368,28 @@
break;
this.name = name;
- c = *name;
+ c = *(const unsigned char *)name;
hash = init_name_hash();
do {
+ name++;
hash = partial_name_hash(c, hash);
- c = *++name;
+ c = *(const unsigned char *)name;
} while (c && (c != '/'));
this.len = name - (const char *) this.name;
this.hash = end_name_hash(hash);
/* remove trailing slashes? */
- follow = follow_link;
+ flags = lookup_flags;
if (c) {
- follow |= c;
+ char tmp;
+
+ flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
do {
- c = *++name;
- } while (c == '/');
+ tmp = *++name;
+ } while (tmp == '/');
+ if (tmp)
+ flags |= LOOKUP_CONTINUE;
}
/*
@@ -407,15 +419,47 @@
/* Check mountpoints.. */
dentry = follow_mount(dentry);
- if (!follow)
+ if (!(flags & LOOKUP_FOLLOW))
break;
- base = do_follow_link(base, dentry);
- if (c && !IS_ERR(base))
- continue;
+ base = do_follow_link(base, dentry, flags);
+ if (IS_ERR(base))
+ goto return_base;
+ inode = base->d_inode;
+ if (flags & LOOKUP_DIRECTORY) {
+ if (!inode)
+ goto no_inode;
+ dentry = ERR_PTR(-ENOTDIR);
+ if (!inode->i_op || !inode->i_op->lookup)
+ break;
+ if (flags & LOOKUP_CONTINUE)
+ continue;
+ }
return_base:
return base;
+/*
+ * The case of a nonexisting file is special.
+ *
+ * In the middle of a pathname lookup (ie when
+ * LOOKUP_CONTINUE is set), it's an obvious
+ * error and returns ENOENT.
+ *
+ * At the end of a pathname lookup it's legal,
+ * and we return a negative dentry. However, we
+ * get here only if there were trailing slashes,
+ * which is legal only if we know it's supposed
+ * to be a directory (ie "mkdir"). Thus the
+ * LOOKUP_SLASHOK flag.
+ */
+no_inode:
+ dentry = ERR_PTR(-ENOENT);
+ if (flags & LOOKUP_CONTINUE)
+ break;
+ if (flags & LOOKUP_SLASHOK)
+ goto return_base;
+ dentry = ERR_PTR(-ENOTDIR);
+ break;
}
dput(base);
return dentry;
@@ -431,7 +475,7 @@
* namei exists in two versions: namei/lnamei. The only difference is
* that namei follows links, while lnamei does not.
*/
-struct dentry * __namei(const char *pathname, int follow_link)
+struct dentry * __namei(const char *pathname, unsigned int lookup_flags)
{
char *name;
struct dentry *dentry;
@@ -439,7 +483,7 @@
name = getname(pathname);
dentry = (struct dentry *) name;
if (!IS_ERR(name)) {
- dentry = lookup_dentry(name, NULL, follow_link);
+ dentry = lookup_dentry(name, NULL, lookup_flags);
putname(name);
if (!IS_ERR(dentry)) {
if (!dentry->d_inode) {
@@ -637,7 +681,7 @@
struct dentry *dentry, *retval;
mode &= ~current->fs->umask;
- dentry = lookup_dentry(filename, NULL, 1);
+ dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW);
if (IS_ERR(dentry))
return dentry;
@@ -721,7 +765,7 @@
struct dentry *dir;
struct dentry *dentry;
- dentry = lookup_dentry(pathname, NULL, 0);
+ dentry = lookup_dentry(pathname, NULL, LOOKUP_SLASHOK);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto exit;
@@ -1128,7 +1172,16 @@
if (IS_ERR(old_dentry))
goto exit;
- new_dentry = lookup_dentry(newname, NULL, 0);
+ error = -ENOENT;
+ if (!old_dentry->d_inode)
+ goto exit;
+
+ {
+ unsigned int flags = 0;
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
+ flags = LOOKUP_SLASHOK;
+ new_dentry = lookup_dentry(newname, NULL, flags);
+ }
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
@@ -1138,10 +1191,6 @@
old_dir = get_parent(old_dentry);
double_lock(new_dir, old_dir);
-
- error = -ENOENT;
- if (!old_dentry->d_inode)
- goto exit_lock;
error = permission(old_dir->d_inode,MAY_WRITE | MAY_EXEC);
if (error)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov