]> arthur.barton.de Git - netatalk.git/commitdiff
try to make afpd directory access right works the way Macs expect
authordidg <didg>
Thu, 29 Aug 2002 18:57:26 +0000 (18:57 +0000)
committerdidg <didg>
Thu, 29 Aug 2002 18:57:26 +0000 (18:57 +0000)
etc/afpd/afs.c
etc/afpd/directory.c
etc/afpd/file.c
etc/afpd/filedir.c
etc/afpd/filedir.h
etc/afpd/fork.c
etc/afpd/unix.c
etc/afpd/unix.h
include/atalk/adouble.h
libatalk/adouble/ad_open.c

index 4c80d06993a1eabf1c618a516b0c4fa481110915..5727ccc35b8a0026664324289a3322bb01a8c582 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afs.c,v 1.10 2002-03-24 01:23:40 sibaz Exp $
+ * $Id: afs.c,v 1.11 2002-08-29 18:57:26 didg Exp $
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
@@ -123,10 +123,15 @@ int               ibuflen, *rbuflen;
  * VIOCGETAL.  If the directory is on AFS, use access() calls to
  * estimate permission, a la mdw.
  */
-afsmode( path, ma, dir )
+#ifdef accessmode
+    #undef accessmode
+#endif
+
+afsmode( path, ma, dir, st )
 char           *path;
 struct maccess *ma;
-struct dir             *dir;
+struct dir      *dir;
+struct stat     *st;
 {
     struct ViceIoctl   vi;
     char               buf[ 1024 ];
@@ -146,7 +151,7 @@ struct dir          *dir;
         return;
     }
 
-    accessmode( path, &ma, dir );
+    accessmode( path, &ma, dir, st );
 
     return;
 }
index 0ef58ce026856887e7c3a23ecd669289cfec2f2e..02fb04fe842f571092a31eb9fba433d89b4093d1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.37 2002-08-22 13:41:19 didg Exp $
+ * $Id: directory.c,v 1.38 2002-08-29 18:57:26 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -1109,15 +1109,8 @@ int getdirparams(const struct vol *vol,
             break;
 
         case DIRPBIT_ACCESS :
-            utommode( st, &ma );
-#ifndef SENDFILE_FLAVOR_LINUX /* ignore this section if it's linux */
-#ifdef HAVE_ACCESS
-            accessmode( upath, &ma, dir );
-#endif /* HAVE_ACCESS */
-#endif /* SENDFILE_FLAVOR_LINUX */
-#ifdef AFS     /* If only AFS defined, access() works only for AFS filesystems */ 
-            afsmode( upath, &ma, dir );
-#endif /* AFS */
+            accessmode( upath, &ma, dir , st);
+
             *data++ = ma.ma_user;
             *data++ = ma.ma_world;
             *data++ = ma.ma_group;
index 2d1871e349c47de7e2cfdf09556e7722ea8e43d6..7053464c1b568c0285945db449d7296d0a3d918d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.51 2002-08-28 15:08:16 didg Exp $
+ * $Id: file.c,v 1.52 2002-08-29 18:57:26 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -110,6 +110,7 @@ int getmetadata(struct vol *vol,
     u_int32_t          aint;
     u_int16_t          ashort;
     u_char              achar, fdType[4];
+    struct maccess     ma;
 
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin getmetadata:");
@@ -132,6 +133,17 @@ int getmetadata(struct vol *vol,
                 ashort = htons(ATTRBIT_INVISIBLE);
             } else
                 ashort = 0;
+#if 0
+            /* FIXME do we want a visual clue if the file is read only
+             */
+            accessmode( ".", &ma, dir , NULL);
+            if ((ma.ma_user & AR_UWRITE)) {
+               accessmode( upath, &ma, dir , st);
+               if (!(ma.ma_user & AR_UWRITE)) {
+                       attrbits |= ATTRBIT_NOWRITE;
+                }
+            }
+#endif
             if (attrbits)
                 ashort = htons(ntohs(ashort) | attrbits);
             memcpy(data, &ashort, sizeof( ashort ));
@@ -655,6 +667,13 @@ int setfilparams(struct vol *vol,
     set_uidgid ( vol );
 #endif /* FORCE_UIDGID */
 
+    if (check_access(upath, OPENACC_WR ) < 0) {
+#ifdef FORCE_UIDGID
+            restore_uidgid ( uidgid );
+#endif /* FORCE_UIDGID */
+        return AFPERR_ACCESS;
+    }
+
     if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
                  O_RDWR|O_CREAT, 0666, adp) < 0) {
         /* for some things, we don't need an adouble header */
@@ -821,9 +840,8 @@ setfilparam_done:
  * and the new mac name.
  * NOTE: if we have to copy a file instead of renaming it, locks
  *       will break. Anyway it's an error because then we have 2 files.
- * FIXME: locks on ressource fork will always break thanks to ad_close, done ?
  *
- * src         the full source absolute path 
+ * src         the source path 
  * dst         the dest filename in current dir
  * newname     the dest mac name
  * adp         adouble struct of src file, if open, or & zeroed one
@@ -860,7 +878,6 @@ struct adouble    *adp;
         case EROFS:
             return AFPERR_VLOCK;
         case EXDEV :                   /* Cross device move -- try copy */
-            /* if source is open bail out */
             if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
                 deletefile( dst, 0 );
                 return( rc );
@@ -994,7 +1011,7 @@ int                ibuflen, *rbuflen;
         return( AFPERR_NOOBJ );
     }
     if ( *path != '\0' ) {
-        return( AFPERR_BADTYPE );
+        return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
     }
 
     /* one of the handful of places that knows about the path type */
@@ -1004,6 +1021,12 @@ int              ibuflen, *rbuflen;
     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
         strncpy( newname, ibuf, plen );
         newname[ plen ] = '\0';
+        if (strlen(newname) != plen) {
+            /* there's \0 in newname, e.g. it's a pathname not
+             * only a filename. 
+            */
+            return( AFPERR_PARAM );
+        }
     }
 
     if ( (err = copyfile(p, mtoupath(vol, newname ), newname,
@@ -1072,11 +1095,14 @@ const int   noadouble;
     char               filebuf[8192];
     int                        sfd, dfd, len, err = AFP_OK;
     ssize_t             cc;
-
+    char                *dpath;
+    int                 admode;
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin copyfile:");
 #endif /* DEBUG */
 
+    dpath = ad_path( dst, ADFLAGS_HF );
+    admode = ad_mode( dst, 0666 );
     if (newname) {
         if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
             switch ( errno ) {
@@ -1088,8 +1114,7 @@ const int   noadouble;
                 return( AFPERR_PARAM );
             }
         } else {
-            if (( dfd = open( ad_path( dst, ADFLAGS_HF ), O_WRONLY|O_CREAT,
-                              ad_mode( ad_path( dst, ADFLAGS_HF ), 0666 ))) < 0 ) {
+            if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
                 close( sfd );
                 switch ( errno ) {
                 case ENOENT :
@@ -1139,7 +1164,7 @@ copyheader_done:
             close(sfd);
             close(dfd);
             if (err < 0) {
-                unlink(ad_path(dst, ADFLAGS_HF));
+                unlink(dpath);
                 return err;
             }
         }
@@ -1157,7 +1182,7 @@ copyheader_done:
         }
     }
 
-    if (( dfd = open( dst, O_WRONLY|O_CREAT, ad_mode( dst, 0666 ))) < 0 ) {
+    if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
         close( sfd );
         switch ( errno ) {
         case ENOENT :
@@ -1206,7 +1231,7 @@ copydata_done:
     close(sfd);
     close(dfd);
     if (err < 0) {
-        unlink(ad_path(dst, ADFLAGS_HF));
+        unlink(dpath);
         unlink(dst);
         return err;
     }
@@ -1247,6 +1272,7 @@ copydata_done:
    ie deletfile called by afp_delete
 
    when deletefile is called we don't have lock on it, file is closed (for us)
+   untrue if called by renamefile
 */
 int deletefile( file, checkAttrib )
 char           *file;
@@ -1527,11 +1553,11 @@ int             ibuflen, *rbuflen;
     ibuf += sizeof(id);
 
     if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
-        return AFPERR_BADID;
+        return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
     }
 
     if (( dir = dirlookup( vol, id )) == NULL ) {
-        return( AFPERR_PARAM );
+        return AFPERR_NOID; /* idem AFPERR_PARAM */
     }
 
     if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
index b4e616676553bdf2d50b259d59d101d3daeca2f6..7d690a9fdae4be2a08779ac409dab6e8070dc329 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: filedir.c,v 1.27 2002-05-13 04:59:36 jmarcus Exp $
+ * $Id: filedir.c,v 1.28 2002-08-29 18:57:26 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -232,6 +232,32 @@ int                ibuflen, *rbuflen;
     return( AFP_OK );
 }
 
+/*
+ * We can't use unix file's perm to support Apple's inherited protection modes.
+ * If we aren't the file's owner we can't change its perms when moving it and smb
+ * nfs,... don't even try.
+*/
+#define AFP_CHECK_ACCESS 
+
+int check_access(char *path, int mode)
+{
+#ifdef AFP_CHECK_ACCESS
+struct maccess ma;
+char *p;
+
+    p = ad_dir(path);
+    if (!p)
+       return -1;
+
+    accessmode(p, &ma, curdir, NULL);
+    if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
+        return -1;
+    if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
+        return -1;
+#endif
+    return 0;
+}
+
 int afp_setfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
 AFPObj      *obj;
 char   *ibuf, *rbuf;
@@ -409,6 +435,7 @@ int         isdir;
                                      vol_noadouble(vol), adp )) == AFP_OK) {
             /* if it's still open, rename the ofork as well. */
             rc = of_rename(vol, sdir, oldname, curdir, newname);
+
         }
     } else {
         rc = renamedir(p, upath, sdir, curdir, newname, vol_noadouble(vol));
@@ -494,6 +521,9 @@ int         ibuflen, *rbuflen;
     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
         strncpy( newname, ibuf, plen );
         newname[ plen ] = '\0';
+        if (strlen(newname) != plen) {
+            return( AFPERR_PARAM );
+        }
     }
     else {
         return AFP_OK; /* newname == oldname same dir */
@@ -682,6 +712,9 @@ int         ibuflen, *rbuflen;
     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
         strncpy( newname, ibuf, plen );
         newname[ plen ] = '\0';
+        if (strlen(newname) != plen) {
+            return( AFPERR_PARAM );
+        }
     }
     else {
         strcpy(newname, oldname);
@@ -696,7 +729,15 @@ int                ibuflen, *rbuflen;
                 return retvalue;
             }
         }
+        else
 #endif /* DROPKLUDGE */
+            if (!isdir) {
+                char *upath = mtoupath(vol, newname);
+                int  admode = ad_mode("", 0777);
+
+                setfilmode(upath, admode, NULL);
+                setfilmode(ad_path( upath, ADFLAGS_HF ), ad_hf_mode(admode), NULL);
+            }
         setvoltime(obj, vol );
     }
 
index f1ef1f6cb16d21a0f37a2711ca0ccef688df3f27..a64c8fd9f162cb9bcceb1d1e691d231106a20116 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: filedir.h,v 1.7 2002-05-13 04:59:36 jmarcus Exp $
+ * $Id: filedir.h,v 1.8 2002-08-29 18:57:26 didg Exp $
  */
 
 #ifndef AFPD_FILEDIR_H
@@ -16,6 +16,7 @@ extern char           *ctoupath __P((const struct vol *, struct dir *,
                                 char *));
 extern int             veto_file __P((const char *veto_str, const char *path));
 extern int             check_name __P((const struct vol *vol, char *name));
+extern int             check_access __P((char *name , int mode));
 
 /* FP functions */
 extern int     matchfile2dirperms __P((char *, struct vol *, int));
index 32ba481260d0c0283969ed68ecbaca5893661f09..4aaee8680e812dea5616c99d6a6e02d35c5fe8b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.33 2002-08-26 08:57:50 didg Exp $
+ * $Id: fork.c,v 1.34 2002-08-29 18:57:26 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -277,6 +277,10 @@ int                ibuflen, *rbuflen;
         adflags = ADFLAGS_HF;
     }
 
+    upath = mtoupath(vol, path);
+    if (check_access(upath, access ) < 0) {
+        return AFPERR_ACCESS;
+    }
     /* XXX: this probably isn't the best way to do this. the already
        open bits should really be set if the fork is opened by any
        program, not just this one. however, that's problematic to do
@@ -295,9 +299,9 @@ int         ibuflen, *rbuflen;
                            adsame)) == NULL ) {
         return( AFPERR_NFILE );
     }
+
     if (access & OPENACC_WR) {
         /* try opening in read-write mode */
-        upath = mtoupath(vol, path);
         ret = AFPERR_NOOBJ;
         if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
             switch ( errno ) {
@@ -345,7 +349,6 @@ int         ibuflen, *rbuflen;
         }
     } else {
         /* try opening in read-only mode */
-        upath = mtoupath(vol, path);
         ret = AFPERR_NOOBJ;
         if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
             switch ( errno ) {
index c5459c1612aa84c95ce9f586cb37d30424e58de3..7f948bc907a8492f53fc956fca1e2fd1dd999e9a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: unix.c,v 1.35 2002-06-06 10:14:26 didg Exp $
+ * $Id: unix.c,v 1.36 2002-08-29 18:57:26 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -20,6 +20,7 @@
 #include <netatalk/endian.h>
 #include <dirent.h>
 #include <limits.h>
+#include <atalk/adouble.h>
 #include <atalk/afp.h>
 
 /* STDC check */
@@ -121,10 +122,9 @@ void utommode( stat, ma )
 struct stat            *stat;
 struct maccess *ma;
 {
-    mode_t             mode;
+mode_t mode;
 
     mode = stat->st_mode;
-
     ma->ma_world = utombits( mode );
     mode = mode >> 3;
 
@@ -134,7 +134,7 @@ struct maccess      *ma;
     ma->ma_owner = utombits( mode );
 
     /* ma_user is a union of all permissions */
-
+    ma->ma_user = 0;
     if ( (uuid == stat->st_uid) || (uuid == 0)) {
         ma->ma_user = ma->ma_owner | AR_UOWN;
     }
@@ -165,15 +165,22 @@ struct maccess    *ma;
  * Note: the previous method, using access(), does not work correctly
  * over NFS.
  */
-void accessmode( path, ma, dir )
+void accessmode( path, ma, dir, st )
 char           *path;
 struct maccess *ma;
-struct dir             *dir;
+struct dir     *dir;
+struct stat     *st;
+
 {
-    struct stat sb;
-    ma->ma_user = ma->ma_owner = 0;
-    if ( stat( path, &sb ) == 0 )
-        utommode( &sb, ma );
+struct stat     sb;
+
+    ma->ma_user = ma->ma_owner = ma->ma_world = ma->ma_group = 0;
+    if (!st) {
+        if (stat(path, &sb) != 0)
+            return;
+        st = &sb;
+    }
+    utommode( st, ma );
     return;
 }
 
@@ -353,6 +360,27 @@ const mode_t       mode;
     return( 0 );
 }
 
+int setfilmode(name, mode, st)
+char * name;
+mode_t mode;
+struct stat *st;
+{
+struct stat sb;
+mode_t mask = S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP |S_IROTH | S_IWOTH;
+
+    if (!st) {
+        if (stat(name, &sb) != 0)
+            return;
+        st = &sb;
+    }
+   mode &= mask;       /* keep only rw-rw-rw in mode */
+   mode |= st->st_mode & ~mask; /* keep other bits from previous mode */
+   if ( chmod( name,  mode & ~default_options.umask ) < 0 && errno != EPERM ) {
+       return -1;
+   }
+   return 0;
+}
+
 int setdirmode( mode, noadouble, dropbox )
 const mode_t mode;
 const int noadouble;
@@ -363,7 +391,7 @@ const int dropbox;
     char               *m;
     struct dirent      *dirp;
     DIR                        *dir;
-
+    
     if (( dir = opendir( "." )) == NULL ) {
         LOG(log_error, logtype_afpd, "setdirmode: opendir .: %s", strerror(errno) );
         return( -1 );
@@ -380,15 +408,26 @@ const int dropbox;
         }
 
         if (S_ISREG(st.st_mode)) {
+           if (setfilmode(dirp->d_name, mode, &st) < 0) {
+                LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",
+                    dirp->d_name, strerror(errno) );
+                return -1;
+           }
+        }
+#if 0
             /* XXX: need to preserve special modes */
-            if (S_ISDIR(st.st_mode)) {
+        else if (S_ISDIR(st.st_mode)) {
                 if (stickydirmode(dirp->d_name, DIRBITS | mode, dropbox) < 0)
                     return (-1);
             } else if (stickydirmode(dirp->d_name, mode, dropbox) < 0)
                 return (-1);
         }
+#endif
     }
     closedir( dir );
+
+    /* change perm of .AppleDouble's files
+    */
     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
         if (noadouble)
             goto setdirmode_noadouble;
@@ -410,11 +449,11 @@ const int dropbox;
             LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", buf, strerror(errno) );
             continue;
         }
-
-        if (S_ISDIR(st.st_mode)) {
-            stickydirmode( buf, DIRBITS | mode, dropbox );
-        } else
-            stickydirmode( buf, mode, dropbox );
+        if (S_ISREG(st.st_mode)) {
+           if (setfilmode(dirp->d_name, ad_hf_mode(mode), &st) < 0) {
+               /* FIXME what do we do then? */
+           }
+        }
     } /* end for */
     closedir( dir );
 
index a846eb8931bd3134f24ed5f655f190775f97d5e4..3373aa658b29f347f217de42a83223f6c7313d03 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: unix.h,v 1.9 2001-12-03 05:03:38 jmarcus Exp $
+ * $Id: unix.h,v 1.10 2002-08-29 18:57:26 didg Exp $
  */
 
 #ifndef AFPD_UNIX_H
@@ -98,5 +98,12 @@ extern int setdeskmode  __P((const mode_t));
 extern int setdirmode   __P((const mode_t, const int, const int));
 extern int setdeskowner __P((const uid_t, const gid_t));
 extern int setdirowner  __P((const uid_t, const gid_t, const int));
+extern int setfilmode   __P((char *, mode_t , struct stat *));
+
+extern void accessmode  __P((char *, struct maccess *, struct dir *, struct stat *));
+
+#ifdef AFS     
+    #define accessmode afsmode
+#endif 
 
 #endif /* UNIX_H */
index cc5cd15d69a68bfb9acc3e2328d205b3557f49b0..93acdcb1924596a55d3cbf55356ab8604548402f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: adouble.h,v 1.8 2002-05-13 07:21:55 jmarcus Exp $
+ * $Id: adouble.h,v 1.9 2002-08-29 18:57:36 didg Exp $
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
@@ -39,6 +39,7 @@ extern int flock (int /*fd*/, int /*operation*/);
 #include <fcntl.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/mman.h>
 #include <netatalk/endian.h>
 
@@ -287,12 +288,28 @@ extern int ad_fcntl_tmplock __P((struct adouble *, const u_int32_t /*eid*/,
 #endif
 
 /* ad_open.c */
+extern char *ad_dir   __P((char *));
 extern char *ad_path  __P((char *, int));
 extern int ad_mode    __P((char *, int));
 extern int ad_mkdir   __P((char *, int));
 extern int ad_open    __P((char *, int, int, int, struct adouble *)); 
 extern int ad_refresh __P((struct adouble *));
 
+/* extend to RW if R for locking */ 
+static inline mode_t ad_hf_mode (mode_t mode)
+{
+#ifndef USE_FLOCK_LOCKS
+    /* fnctl lock need write access */
+    if ((mode & S_IRUSR))
+        mode |= S_IWUSR;
+    if ((mode & S_IRGRP))
+        mode |= S_IWGRP;
+    if ((mode & S_IROTH))
+        mode |= S_IWOTH;
+#endif
+    return mode;
+}
+
 /* ad_read.c/ad_write.c */
 extern ssize_t ad_read __P((struct adouble *, const u_int32_t, 
                            const off_t, char *, const size_t));
index 990e3a4d7cbde1ad64a7932d89623bff43db51aa..1fe07ca405420cb9e50675c14d77bafd68bdf182 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.18 2002-08-14 10:35:46 didg Exp $
+ * $Id: ad_open.c,v 1.19 2002-08-29 18:57:37 didg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -530,21 +530,15 @@ ad_path( path, adflags )
 
 #define DEFMASK 07700  /* be conservative */
 
-int
-ad_mode( path, mode )
+char 
+*ad_dir(path)
     char               *path;
-    int                        mode;
 {
     static char                modebuf[ MAXPATHLEN + 1];
-    struct stat                stbuf;
     char               *slash;
 
-    if ( mode == 0 ) {
-       return( mode );         /* save on syscalls */
-    }
-
     if ( strlen( path ) >= MAXPATHLEN ) {
-       return( mode & DEFMASK );  /* can't do it */
+       return NULL;  /* can't do it */
     }
 
     /*
@@ -559,8 +553,26 @@ ad_mode( path, mode )
        modebuf[0] = '.';       /* use current directory */
        modebuf[1] = '\0';
     }
+    return modebuf;
+}
+
+int
+ad_mode( path, mode )
+    char               *path;
+    int                        mode;
+{
+    struct stat                stbuf;
+    char                *p;
+    
+    if ( mode == 0 ) {
+       return( mode );         /* save on syscalls */
+    }
+    p = ad_dir(path);
+    if (!p) {
+       return( mode & DEFMASK );  /* can't do it */
+    }
 
-    if ( stat( modebuf, &stbuf ) != 0 ) {
+    if ( stat( p, &stbuf ) != 0 ) {
        return( mode & DEFMASK );       /* bail out... can't stat dir? */
     }
 
@@ -612,11 +624,11 @@ int ad_open( path, adflags, oflags, mode, ad )
     if (adflags & ADFLAGS_DF) { 
         if (ad_dfileno(ad) == -1) {
          hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
-         if (( ad->ad_df.adf_fd =
-               open( path, hoflags, ad_mode( path, mode ) )) < 0 ) {
+         admode = ad_mode( path, mode ); 
+         if (( ad->ad_df.adf_fd = open( path, hoflags, admode )) < 0 ) {
              if (errno == EACCES && !(oflags & O_RDWR)) {
                 hoflags = oflags;
-                ad->ad_df.adf_fd =open( path, hoflags, ad_mode( path, mode ) );
+                ad->ad_df.adf_fd =open( path, hoflags, admode );
              }
          }
          if ( ad->ad_df.adf_fd < 0)
@@ -639,15 +651,13 @@ int ad_open( path, adflags, oflags, mode, ad )
     if (adflags & ADFLAGS_HF) {
         if (ad_hfileno(ad) == -1) {
          ad_p = ad_path( path, adflags );
-         admode = ad_mode( ad_p, mode ); /* FIXME? */
+
          hoflags = oflags & ~O_CREAT;
          hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
-         if (( ad->ad_hf.adf_fd = open( ad_p, hoflags, admode )) < 0 ) {
-            if (errno == EACCES) {
-                if (!(oflags & O_RDWR)) {
-                 hoflags = oflags & ~O_CREAT;
-                  ad->ad_hf.adf_fd = open( ad_p, hoflags, admode );
-                }
+         if (( ad->ad_hf.adf_fd = open( ad_p, hoflags, 0 )) < 0 ) {
+            if (errno == EACCES && !(oflags & O_RDWR)) {
+                hoflags = oflags & ~O_CREAT;
+                ad->ad_hf.adf_fd = open( ad_p, hoflags, 0 );
             }    
           }
          if ( ad->ad_hf.adf_fd < 0 ) {
@@ -657,6 +667,7 @@ int ad_open( path, adflags, oflags, mode, ad )
               * here.
               * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
               */
+             admode = ad_hf_mode(ad_mode( ad_p, mode )); 
              errno = 0;
              if (( ad->ad_hf.adf_fd = open( ad_p, oflags,
                                             admode )) < 0 ) {