aboutsummaryrefslogtreecommitdiff
path: root/libnetfs/dir-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnetfs/dir-lookup.c')
-rw-r--r--libnetfs/dir-lookup.c272
1 files changed, 143 insertions, 129 deletions
diff --git a/libnetfs/dir-lookup.c b/libnetfs/dir-lookup.c
index 9ca623f3..17d9e23e 100644
--- a/libnetfs/dir-lookup.c
+++ b/libnetfs/dir-lookup.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,10 +28,6 @@
#include "callbacks.h"
#include "misc.h"
-/* XXX - Temporary hack; this belongs in a header file, probably types.h. */
-#define major(x) ((int)(((unsigned) (x) >> 8) & 0xff))
-#define minor(x) ((int)((x) & 0xff))
-
error_t
netfs_S_dir_lookup (struct protid *diruser,
char *filename,
@@ -52,25 +48,24 @@ netfs_S_dir_lookup (struct protid *diruser,
char *nextname;
error_t error;
struct protid *newpi;
+ struct iouser *user;
if (!diruser)
return EOPNOTSUPP;
-
+
create = (flags & O_CREAT);
excl = (flags & O_EXCL);
-
+
/* Skip leading slashes */
while (*filename == '/')
filename++;
-
+
*retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
*do_retry = FS_RETRY_NORMAL;
*retry_name = '\0';
-
+
if (*filename == '\0')
{
- mustbedir = 1;
-
/* Set things up in the state expected by the code from gotit: on. */
dnp = 0;
np = diruser->po->np;
@@ -78,20 +73,19 @@ netfs_S_dir_lookup (struct protid *diruser,
netfs_nref (np);
goto gotit;
}
-
+
dnp = diruser->po->np;
mutex_lock (&dnp->lock);
- np = 0;
-
+
netfs_nref (dnp); /* acquire a reference for later netfs_nput */
-
+
do
{
assert (!lastcomp);
-
+
/* Find the name of the next pathname component */
nextname = index (filename, '/');
-
+
if (nextname)
{
*nextname++ = '\0';
@@ -108,55 +102,66 @@ netfs_S_dir_lookup (struct protid *diruser,
else
lastcomp = 0;
}
- else
+ else
lastcomp = 1;
-
+
np = 0;
-
+
retry_lookup:
-
- if (dnp == netfs_root_node
+
+ if ((dnp == netfs_root_node || dnp == diruser->po->shadow_root)
&& filename[0] == '.' && filename[1] == '.' && filename[2] == '\0')
- {
- /* Lookup of .. from root */
- if (diruser->po->dotdotport != MACH_PORT_NULL)
- {
- *do_retry = FS_RETRY_REAUTH;
- *retry_port = diruser->po->dotdotport;
- *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
- if (!lastcomp)
- strcpy (retry_name, nextname);
- error = 0;
- mutex_unlock (&dnp->lock);
- goto out;
- }
- else
- /* We are global root */
- {
- error = 0;
- np = dnp;
- netfs_nref (np);
- }
- }
+ if (dnp == diruser->po->shadow_root)
+ /* We're at the root of a shadow tree. */
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *retry_port = diruser->po->shadow_root_parent;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ if (! lastcomp)
+ strcpy (retry_name, nextname);
+ error = 0;
+ mutex_unlock (&dnp->lock);
+ goto out;
+ }
+ else if (diruser->po->root_parent != MACH_PORT_NULL)
+ /* We're at a real translator root; even if DIRUSER->po has a
+ shadow root, we can get here if its in a directory that was
+ renamed out from under it... */
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *retry_port = diruser->po->root_parent;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ if (!lastcomp)
+ strcpy (retry_name, nextname);
+ error = 0;
+ mutex_unlock (&dnp->lock);
+ goto out;
+ }
+ else
+ /* We are global root */
+ {
+ error = 0;
+ np = dnp;
+ netfs_nref (np);
+ }
else
/* Attempt a lookup on the next pathname component. */
- error = netfs_attempt_lookup (diruser->credential, dnp, filename, &np);
-
+ error = netfs_attempt_lookup (diruser->user, dnp, filename, &np);
+
/* At this point, DNP is unlocked */
/* Implement O_EXCL flag here */
if (lastcomp && create && excl && !error)
error = EEXIST;
-
+
/* Create the new node if necessary */
if (lastcomp && create && error == ENOENT)
{
mode &= ~(S_IFMT | S_ISPARE | S_ISVTX);
mode |= S_IFREG;
mutex_lock (&dnp->lock);
- error = netfs_attempt_create_file (diruser->credential, dnp,
+ error = netfs_attempt_create_file (diruser->user, dnp,
filename, mode, &np);
- newnode = 1;
/* If someone has already created the file (between our lookup
and this create) then we just got EEXIST. If we are
@@ -166,55 +171,57 @@ netfs_S_dir_lookup (struct protid *diruser,
mutex_lock (&dnp->lock);
goto retry_lookup;
}
+
+ newnode = 1;
}
/* All remaining errors get returned to the user */
if (error)
goto out;
-
- error = netfs_validate_stat (np, diruser->credential);
+
+ error = netfs_validate_stat (np, diruser->user);
if (error)
goto out;
if ((((flags & O_NOTRANS) == 0) || !lastcomp)
- && (np->istranslated
- || S_ISFIFO (np->nn_stat.st_mode)
- || S_ISCHR (np->nn_stat.st_mode)
- || S_ISBLK (np->nn_stat.st_mode)
+ && ((np->nn_translated & S_IPTRANS)
+ || S_ISFIFO (np->nn_translated)
+ || S_ISCHR (np->nn_translated)
+ || S_ISBLK (np->nn_translated)
|| fshelp_translated (&np->transbox)))
{
mach_port_t dirport;
- uid_t *uids, *gids;
- int nuids, ngids;
-
+
/* A callback function for short-circuited translators.
S_ISLNK and S_IFSOCK are handled elsewhere. */
error_t short_circuited_callback1 (void *cookie1, void *cookie2,
uid_t *uid, gid_t *gid,
- char **argz, int *argz_len)
+ char **argz, size_t *argz_len)
{
struct node *np = cookie1;
error_t err;
- err = netfs_validate_stat (np, diruser->credential);
+ err = netfs_validate_stat (np, diruser->user);
if (err)
return err;
- switch (np->nn_stat.st_mode & S_IFMT)
+ switch (np->nn_translated & S_IFMT)
{
case S_IFCHR:
case S_IFBLK:
- asprintf (argz, "%s%c%d%c%d",
- (S_ISCHR (np->nn_stat.st_mode)
- ? _HURD_CHRDEV : _HURD_BLKDEV),
- 0, major (np->nn_stat.st_rdev),
- 0, minor (np->nn_stat.st_rdev));
+ if (asprintf (argz, "%s%c%d%c%d",
+ (S_ISCHR (np->nn_translated)
+ ? _HURD_CHRDEV : _HURD_BLKDEV),
+ 0, major (np->nn_stat.st_rdev),
+ 0, minor (np->nn_stat.st_rdev)) < 0)
+ return ENOMEM;
*argz_len = strlen (*argz) + 1;
*argz_len += strlen (*argz + *argz_len) + 1;
*argz_len += strlen (*argz + *argz_len) + 1;
break;
case S_IFIFO:
- asprintf (argz, "%s", _HURD_FIFO);
+ if (asprintf (argz, "%s", _HURD_FIFO) < 0)
+ return ENOMEM;
*argz_len = strlen (*argz) + 1;
break;
default:
@@ -223,35 +230,44 @@ netfs_S_dir_lookup (struct protid *diruser,
*uid = np->nn_stat.st_uid;
*gid = np->nn_stat.st_gid;
-
+
return 0;
}
-
+
/* Create an unauthenticated port for DNP, and then
unlock it. */
- newpi =
- netfs_make_protid (netfs_make_peropen (dnp, 0,
- diruser->po->dotdotport),
- netfs_make_credential (0, 0, 0, 0));
- dirport = ports_get_right (newpi);
- mach_port_insert_right (mach_task_self (), dirport, dirport,
- MACH_MSG_TYPE_MAKE_SEND);
- ports_port_deref (newpi);
- if (np != dnp)
- mutex_unlock (&dnp->lock);
-
- netfs_interpret_credential (diruser->credential, &uids, &nuids,
- &gids, &ngids);
- error = fshelp_fetch_root (&np->transbox, &diruser->po->dotdotport,
- dirport, uids, nuids, gids, ngids,
- lastcomp ? flags : 0,
- (np->istranslated
- ? _netfs_translator_callback1
- : short_circuited_callback1),
- _netfs_translator_callback2,
- do_retry, retry_name, retry_port);
- free (uids);
- free (gids);
+ error = iohelp_create_empty_iouser (&user);
+ if (! error)
+ {
+ newpi = netfs_make_protid (netfs_make_peropen (dnp, 0,
+ diruser->po),
+ user);
+ if (! newpi)
+ {
+ error = errno;
+ iohelp_free_iouser (user);
+ }
+ }
+
+ if (! error)
+ {
+ dirport = ports_get_send_right (newpi);
+ ports_port_deref (newpi);
+
+ error = fshelp_fetch_root (&np->transbox, diruser->po,
+ dirport,
+ diruser->user,
+ lastcomp ? flags : 0,
+ ((np->nn_translated & S_IPTRANS)
+ ? _netfs_translator_callback1
+ : short_circuited_callback1),
+ _netfs_translator_callback2,
+ do_retry, retry_name, retry_port);
+ /* fetch_root copies DIRPORT for success, so we always should
+ deallocate our send right. */
+ mach_port_deallocate (mach_task_self (), dirport);
+ }
+
if (error != ENOENT)
{
netfs_nrele (dnp);
@@ -264,30 +280,20 @@ netfs_S_dir_lookup (struct protid *diruser,
}
return error;
}
-
+
/* ENOENT means there was a hiccup, and the translator vanished
- while NP was unlocked inside fshelp_fetch_root.
- Reacquire the locks and continue as normal. */
+ while NP was unlocked inside fshelp_fetch_root; continue as normal. */
error = 0;
- if (np != dnp)
- {
- if (!strcmp (filename, ".."))
- mutex_lock (&dnp->lock);
- else
- {
- mutex_unlock (&np->lock);
- mutex_lock (&dnp->lock);
- mutex_lock (&np->lock);
- }
- }
}
-
- if (S_ISLNK (np->nn_stat.st_mode)
- && !(lastcomp && (flags & (O_NOLINK|O_NOTRANS))))
+
+ if (S_ISLNK (np->nn_translated)
+ && (!lastcomp
+ || mustbedir /* "foo/" must see that foo points to a dir */
+ || !(flags & (O_NOLINK|O_NOTRANS))))
{
size_t nextnamelen, newnamelen, linklen;
char *linkbuf;
-
+
/* Handle symlink interpretation */
if (nsymlinks++ > netfs_maxsymlinks)
{
@@ -296,23 +302,23 @@ netfs_S_dir_lookup (struct protid *diruser,
}
linklen = np->nn_stat.st_size;
-
+
nextnamelen = nextname ? strlen (nextname) + 1 : 0;
newnamelen = nextnamelen + linklen + 1;
linkbuf = alloca (newnamelen);
-
- error = netfs_attempt_readlink (diruser->credential, np, linkbuf);
+
+ error = netfs_attempt_readlink (diruser->user, np, linkbuf);
if (error)
goto out;
-
+
if (nextname)
{
linkbuf[linklen] = '/';
- bcopy (nextname, linkbuf + linklen + 1,
+ memcpy (linkbuf + linklen + 1, nextname,
nextnamelen - 1);
}
linkbuf[nextnamelen + linklen] = '\0';
-
+
if (linkbuf[0] == '/')
{
/* Punt to the caller */
@@ -321,7 +327,7 @@ netfs_S_dir_lookup (struct protid *diruser,
strcpy (retry_name, linkbuf);
goto out;
}
-
+
filename = linkbuf;
if (lastcomp)
{
@@ -340,7 +346,7 @@ netfs_S_dir_lookup (struct protid *diruser,
/* Normal nodes here for next filename component */
filename = nextname;
netfs_nrele (dnp);
-
+
if (lastcomp)
dnp = 0;
else
@@ -357,26 +363,36 @@ netfs_S_dir_lookup (struct protid *diruser,
if (mustbedir)
{
- netfs_validate_stat (np, diruser->credential);
+ netfs_validate_stat (np, diruser->user);
if (!S_ISDIR (np->nn_stat.st_mode))
{
error = ENOTDIR;
goto out;
}
- }
- error = netfs_check_open_permissions (diruser->credential, np,
+ }
+ error = netfs_check_open_permissions (diruser->user, np,
flags, newnode);
if (error)
goto out;
-
+
flags &= ~OPENONLY_STATE_MODES;
-
- newpi = netfs_make_protid (netfs_make_peropen (np, flags,
- diruser->po->dotdotport),
- netfs_copy_credential (diruser->credential));
+
+ error = iohelp_dup_iouser (&user, diruser->user);
+ if (error)
+ goto out;
+
+ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
+ user);
+ if (! newpi)
+ {
+ iohelp_free_iouser (user);
+ error = errno;
+ goto out;
+ }
+
*retry_port = ports_get_right (newpi);
ports_port_deref (newpi);
-
+
out:
if (np)
netfs_nput (np);
@@ -384,5 +400,3 @@ netfs_S_dir_lookup (struct protid *diruser,
netfs_nrele (dnp);
return error;
}
-
-