* terms of the GNU Lesser General Public License
* (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
*
- * Cplant(TM) Copyright 1998-2003 Sandia Corporation.
+ * Cplant(TM) Copyright 1998-2006 Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the US Government.
* Export of this program may require a license from the United States
* lee@sandia.gov
*/
-#if defined(AUTOMOUNT_FILE_NAME) && defined(__linux__)
-#define _BSD_SOURCE
-#endif
-
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
struct qstr *name,
struct pnode **pnop,
struct intent *intnt,
- const char *path)
+ const char *path,
+ int check_permissions)
{
- struct pnode *pno;
int err;
+ struct pnode *pno;
if (!parent->p_base->pb_ino)
return -ENOTDIR;
/*
+ * Sometimes we don't want to check permissions. At initialization
+ * time, for instance.
+ */
+ if (check_permissions) {
+ err = _sysio_permitted(parent, X_OK);
+ if (err)
+ return err;
+ }
+
+ /*
* Short-circuit `.' and `..'; We don't cache those.
*/
pno = NULL;
* ND_NOFOLLOW symbolic links are not followed
* ND_NEGOK if terminal/leaf does not exist, return
* path node (alias) anyway.
+ * ND_NOPERMCHECK do not check permissions
*/
int
_sysio_path_walk(struct pnode *parent, struct nameidata *nd)
parent = nd->nd_root;
}
+#ifdef DEFER_INIT_CWD
+ if (!parent) {
+ const char *icwd;
+
+ if (!_sysio_init_cwd && !nd->nd_root)
+ abort();
+
+ /*
+ * Finally have to set the current working directory. We can
+ * not tolerate errors here or else risk leaving the process
+ * in a very unexpected location. We abort then unless all goes
+ * well.
+ */
+ icwd = _sysio_init_cwd;
+ _sysio_init_cwd = NULL;
+ parent = nd->nd_root;
+ if (!parent)
+ abort();
+ (void )_sysio_namei(nd->nd_root, icwd, 0, NULL, &parent);
+ if (_sysio_p_chdir(parent) != 0)
+ abort();
+ }
+#endif
+
/*
* (Re)Validate the parent.
*/
*/
for (;;) {
ino = nd->nd_pno->p_base->pb_ino;
- if (S_ISLNK(ino->i_mode) &&
+ if (S_ISLNK(ino->i_stbuf.st_mode) &&
(next.len || !(nd->nd_flags & ND_NOFOLLOW))) {
char *lpath;
ssize_t cc;
lpath[cc] = '\0'; /* NUL term */
/*
* Handle symbolic links with recursion. Yuck!
+ * Pass the NULL intent for recursive symlink
+ * except the last component.
*/
ND_INIT(&nameidata,
- (nd->nd_flags | ND_NEGOK),
+ nd->nd_flags,
lpath,
nd->nd_root,
- nd->nd_intent);
+ !next.len ? nd->nd_intent : NULL);
nameidata.nd_slicnt = nd->nd_slicnt + 1;
err =
_sysio_path_walk(nd->nd_pno->p_parent, &nameidata);
}
#ifdef AUTOMOUNT_FILE_NAME
else if (ino &&
- S_ISDIR(ino->i_mode) &&
+ S_ISDIR(ino->i_stbuf.st_mode) &&
(nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO) &&
nd->nd_amcnt < MAX_MOUNT_DEPTH &&
- ino->i_mode & S_ISUID) {
+ ino->i_stbuf.st_mode & S_ISUID) {
struct pnode *pno;
/*
&_sysio_mount_file_name,
&pno,
NULL,
- NULL);
+ NULL,
+ 1);
if (pno)
P_RELE(pno);
if (!err && _sysio_automount(pno) == 0) {
/*
* Parent must be a directory.
*/
- if (ino && !S_ISDIR(ino->i_mode)) {
+ if (ino && !S_ISDIR(ino->i_stbuf.st_mode)) {
err = -ENOTDIR;
break;
}
(path || !next.len)
? nd->nd_intent
: NULL,
- (path && next.len) ? path : NULL);
+ (path && next.len) ? path : NULL,
+ !(nd->nd_flags & ND_NOPERMCHECK));
if (err) {
if (err == -ENOENT &&
!next.len &&
* Make sure the last processed component was a directory. The
* trailing slashes are illegal behind anything else.
*/
- if (!(err || S_ISDIR(nd->nd_pno->p_base->pb_ino->i_mode)))
+ if (!(err ||
+ S_ISDIR(nd->nd_pno->p_base->pb_ino->i_stbuf.st_mode)))
err = -ENOTDIR;
}