]> arthur.barton.de Git - netatalk.git/commitdiff
Merge branch 'product-2-2' of git://github.com/franklahm/Netatalk into alex-master
authorAlexander Barton <alex@barton.de>
Thu, 3 Jan 2013 13:56:35 +0000 (14:56 +0100)
committerAlexander Barton <alex@barton.de>
Thu, 3 Jan 2013 13:56:35 +0000 (14:56 +0100)
* 'product-2-2' of git://github.com/franklahm/Netatalk:
  Configurable symlink behaviour
  Trying to create an EA that already existed returned the wrong AFP error code
  Add become_root() capability to nfsv4_chmod()
  Fix an error where catalog search gave incomplete results
  2.2.5dev
  Add missing source afp_asp.c
  Version 2.2.4

31 files changed:
NEWS
VERSION
etc/afpd/acls.c
etc/afpd/afp_asp.c
etc/afpd/catsearch.c
etc/afpd/desktop.c
etc/afpd/directory.c
etc/afpd/enumerate.c
etc/afpd/file.c
etc/afpd/filedir.c
etc/afpd/fork.c
etc/afpd/fork.h
etc/afpd/ofork.c
etc/afpd/quota.c
etc/afpd/unix.c
etc/afpd/volume.c
include/atalk/acl.h
include/atalk/adouble.h
include/atalk/unix.h
include/atalk/util.h
include/atalk/volume.h
libatalk/acl/Makefile.am
libatalk/acl/unix.c
libatalk/adouble/ad_open.c
libatalk/util/unix.c
libatalk/vfs/ea.c
libatalk/vfs/sys_ea.c
libatalk/vfs/unix.c
libatalk/vfs/vfs.c
man/man5/AppleVolumes.default.5.tmpl
test/afpd/Makefile.am

diff --git a/NEWS b/NEWS
index 9375ba0c8efe82e5c70c46f234a52625ca26fdb0..6c5aab2f3edfad4e7ac0e67255e32293ed2d4839 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+Changes in 2.2.5
+================
+
+* FIX: Fix errors searching volumes
+* NEW: Configurable symlink handling with a new volume option
+       'followsymlinks'. Setting the option causes afpd to follow
+       symlinks on the server side.
+
 Changes in 2.2.4
 ================
 
diff --git a/VERSION b/VERSION
index c3ff749c71ea9ec9f2e89bca8ecc796a7b96780b..8c99ff7bf43d6711f291c8946b1c4ba49bf64e57 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2.4dev
\ No newline at end of file
+2.2.5dev
\ No newline at end of file
index 82d61eb5444d88512ae58aa9ef6ed9c6496f4247..7290b31bf24a31882e5dae3e558263987acd1398 100644 (file)
@@ -1372,7 +1372,7 @@ static int check_acl_access(const struct vol *vol,
     }
 #endif
 
-    EC_ZERO_LOG_ERR(lstat(path, &st), AFPERR_PARAM);
+    EC_ZERO_LOG_ERR(ostat(path, &st, vol_syml_opt(vol)), AFPERR_PARAM);
 
     is_dir = !strcmp(path, ".");
 
index 3e208f74a102d1db449b49b317908f508e8a75ec..e255227538a43f56d2a71ce2ea3873d7241b57a2 100644 (file)
@@ -81,7 +81,7 @@ static void afp_authprint_remove(AFPObj *obj)
 
     memset( addr_filename_buff, 0, 256 );
 
-    if(lstat(addr_filename, &cap_st) == 0) {
+    if (stat(addr_filename, &cap_st) == 0) {
        if( S_ISREG(cap_st.st_mode) ) {
            int len;
            int capfd = open( addr_filename, O_RDONLY );
index 89a6d5733aed67b6c13de4d41f8b3f357928d0c2..f1f55ef96d7a3ed2cea6823d317f1abcb014d180 100644 (file)
@@ -29,6 +29,9 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -108,12 +111,8 @@ struct scrit {
  *
  */
 struct dsitem {
-//     struct dir *dir; /* Structure describing this directory */
-//  cnid_t did;      /* CNID of this directory           */
-       int pidx;        /* Parent's dsitem structure index. */
-       int checked;     /* Have we checked this directory ? */
-       int path_len;
-       char *path;      /* absolute UNIX path to this directory */
+    cnid_t ds_did;         /* CNID of this directory           */
+    int    ds_checked;     /* Have we checked this directory ? */
 };
  
 
@@ -130,7 +129,6 @@ static void clearstack(void)
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
-               free(dstack[dsidx].path);
        }
 }
 
@@ -155,23 +153,8 @@ static int addstack(char *uname, struct dir *dir, int pidx)
 
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
-//     ds->did = dir->d_did;
-       ds->pidx = pidx;
-       ds->checked = 0;
-       if (pidx >= 0) {
-           l = dstack[pidx].path_len;
-           u = strlen(uname) +1;
-           if (!(ds->path = malloc(l + u + 1) ))
-                       return -1;
-               memcpy(ds->path, dstack[pidx].path, l);
-               ds->path[l] = '/';
-               memcpy(&ds->path[l+1], uname, u);
-               ds->path_len = l +u;
-       }
-       else {
-           ds->path = strdup(uname);
-               ds->path_len = strlen(uname);
-       }
+       ds->ds_did = dir->d_did;
+       ds->ds_checked = 0;
        return 0;
 }
 
@@ -186,9 +169,9 @@ static int reducestack(void)
        }
 
        while (dsidx > 0) {
-               if (dstack[dsidx-1].checked) {
+               if (dstack[dsidx-1].ds_checked) {
                        dsidx--;
-                       free(dstack[dsidx].path);
+//                     free(dstack[dsidx].path);
                } else
                        return dsidx - 1;
        } 
@@ -210,7 +193,7 @@ static struct adouble *adl_lkup(struct vol *vol, struct path *path, struct adoub
            
        isdir  = S_ISDIR(path->st.st_mode);
 
-       if (!isdir && (of = of_findname(path))) {
+       if (!isdir && (of = of_findname(vol, path))) {
                adp = of->of_ad;
        } else {
                ad_init(&ad, vol->v_adouble, vol->v_ad_options);
@@ -519,7 +502,8 @@ static int catsearch(struct vol *vol,
     int num_rounds = NUM_ROUNDS;
     int cwd = -1;
     int error;
-        
+    int unlen;
+
        if (*pos != 0 && *pos != cur_pos) {
                result = AFPERR_CATCHNG;
                goto catsearch_end;
@@ -553,20 +537,24 @@ static int catsearch(struct vol *vol,
     start_time = time(NULL);
 
        while ((cidx = reducestack()) != -1) {
-        LOG(log_debug, logtype_afpd, "catsearch: dir: \"%s\"", dstack[cidx].path);
+        if ((currentdir = dirlookup(vol, dstack[cidx].ds_did)) == NULL) {
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
+        LOG(log_debug, logtype_afpd, "catsearch: current struct dir: \"%s\"", cfrombstr(currentdir->d_fullpath));
 
-               error = lchdir(dstack[cidx].path);
+               error = movecwd(vol, currentdir);
 
                if (!error && dirpos == NULL)
                        dirpos = opendir(".");
 
                if (dirpos == NULL)
-                       dirpos = opendir(dstack[cidx].path);
+                       dirpos = opendir(bdata(currentdir->d_fullpath));
 
                if (error || dirpos == NULL) {
                        switch (errno) {
                        case EACCES:
-                               dstack[cidx].checked = 1;
+                               dstack[cidx].ds_checked = 1;
                                continue;
                        case EMFILE:
                        case ENFILE:
@@ -581,11 +569,6 @@ static int catsearch(struct vol *vol,
                        goto catsearch_end;
                }
 
-        if ((currentdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
-            result = AFPERR_MISC;
-            goto catsearch_end;
-        }
-        LOG(log_debug, logtype_afpd, "catsearch: current struct dir: \"%s\"", cfrombstr(currentdir->d_fullpath));
                
                while ((entry = readdir(dirpos)) != NULL) {
                        (*pos)++;
@@ -598,7 +581,7 @@ static int catsearch(struct vol *vol,
 
                        memset(&path, 0, sizeof(path));
                        path.u_name = entry->d_name;
-                       if (of_stat(&path) != 0) {
+                       if (of_stat(vol, &path) != 0) {
                                switch (errno) {
                                case EACCES:
                                case ELOOP:
@@ -613,12 +596,13 @@ static int catsearch(struct vol *vol,
                                        goto catsearch_end;
                                } 
                        }
-                       if (S_ISDIR(path.st.st_mode)) {
+            switch (S_IFMT & path.st.st_mode) {
+            case S_IFDIR:
                                /* here we can short cut 
                                   ie if in the same loop the parent dir wasn't in the cache
                                   ALL dirsearch_byname will fail.
                                */
-                int unlen = strlen(path.u_name);
+                unlen = strlen(path.u_name);
                 path.d_dir = dircache_search_by_name(vol,
                                                      currentdir,
                                                      path.u_name,
@@ -639,8 +623,12 @@ static int catsearch(struct vol *vol,
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
                                } 
-            } else {
+                break;
+            case S_IFREG:
                path.d_dir = currentdir;
+                break;
+            default:
+                continue;
             }
 
                        ccr = crit_check(vol, &path);
@@ -672,7 +660,7 @@ static int catsearch(struct vol *vol,
                } /* while ((entry=readdir(dirpos)) != NULL) */
                closedir(dirpos);
                dirpos = NULL;
-               dstack[cidx].checked = 1;
+               dstack[cidx].ds_checked = 1;
        } /* while (current_idx = reducestack()) != -1) */
 
        /* We have finished traversing our tree. Return EOF here. */
@@ -786,7 +774,7 @@ static int catsearch_db(struct vol *vol,
         path.u_name = name;
         path.m_name = utompath(vol, name, cnid, utf8_encoding());
 
-        if (of_stat(&path) != 0) {
+        if (of_stat(vol, &path) != 0) {
             switch (errno) {
             case EACCES:
             case ELOOP:
index 7a513b6a3cd760d9469364a6524546954c02c7e7..da39e9b124e4df74be91592d3c0a81a35221e5f1 100644 (file)
@@ -721,7 +721,7 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
     }
     
     isadir = path_isadir(path);
-    if (isadir || !(of = of_findname(path))) {
+    if (isadir || !(of = of_findname(vol, path))) {
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
@@ -794,7 +794,7 @@ static int ad_getcomment(struct vol *vol, struct path *path, char *rbuf, size_t
 
     upath = path->u_name;
     isadir = path_isadir(path);
-    if (isadir || !(of = of_findname(path))) {
+    if (isadir || !(of = of_findname(vol, path))) {
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
@@ -871,7 +871,7 @@ static int ad_rmvcomment(struct vol *vol, struct path *path)
     }
 
     isadir = path_isadir(path);
-    if (isadir || !(of = of_findname(path))) {
+    if (isadir || !(of = of_findname(vol, path))) {
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         adp = &ad;
     } else
index a6b194b176626222cd925cdbcc376dc884cc8b86..84b5093d12c355543d0e4dfac64ff73f49c87027 100644 (file)
@@ -132,7 +132,7 @@ static int netatalk_mkdir(const struct vol *vol, const char *name)
 }
 
 /* ------------------- */
-static int deletedir(int dirfd, char *dir)
+static int deletedir(const struct vol *vol, int dirfd, char *dir)
 {
     char path[MAXPATHLEN + 1];
     DIR *dp;
@@ -163,11 +163,11 @@ static int deletedir(int dirfd, char *dir)
             break;
         }
         strcpy(path + len, de->d_name);
-        if (lstatat(dirfd, path, &st)) {
+        if (ostatat(dirfd, path, &st, vol_syml_opt(vol))) {
             continue;
         }
         if (S_ISDIR(st.st_mode)) {
-            err = deletedir(dirfd, path);
+            err = deletedir(vol, dirfd, path);
         } else {
             err = netatalk_unlinkat(dirfd, path);
         }
@@ -229,7 +229,7 @@ static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
         }
         strcpy(spath + slen, de->d_name);
 
-        if (lstatat(dirfd, spath, &st) == 0) {
+        if (ostatat(dirfd, spath, &st, vol_syml_opt(vol)) == 0) {
             if (strlen(de->d_name) > drem) {
                 err = AFPERR_PARAM;
                 break;
@@ -251,7 +251,7 @@ static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
     }
 
     /* keep the same time stamp. */
-    if (lstatat(dirfd, src, &st) == 0) {
+    if (ostatat(dirfd, src, &st, vol_syml_opt(vol)) == 0) {
         ut.actime = ut.modtime = st.st_mtime;
         utime(dst, &ut);
     }
@@ -641,7 +641,7 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did)
     LOG(log_debug, logtype_afpd, "dirlookup(did: %u): stating \"%s\"",
         ntohl(did), cfrombstr(fullpath));
 
-    if (lstat(cfrombstr(fullpath), &st) != 0) { /* 5a */
+    if (ostat(cfrombstr(fullpath), &st, vol_syml_opt(vol)) != 0) { /* 5a */
         switch (errno) {
         case ENOENT:
             afp_errno = AFPERR_NOOBJ;
@@ -729,7 +729,7 @@ int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
     if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
         path->u_name = cname;
         path->d_dir = NULL;
-        if (of_stat( path ) == 0 ) {
+        if (of_stat(vol, path ) == 0 ) {
             return 0;
         }
         /* something changed, we cannot stat ... */
@@ -760,7 +760,7 @@ int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
             strlcpy(cname, de->d_name, sizeof(cname));
             path->u_name = cname;
             path->d_dir = NULL;
-            if (of_stat( path ) == 0 ) {
+            if (of_stat(vol, path ) == 0 ) {
                 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
                 strlcpy(lname, tmp, sizeof(lname));
                 did = dir->d_did;
@@ -1259,7 +1259,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath)
              *   and thus call continue which should terminate the while loop because
              *   len = 0. Ok?
              */
-            if (of_stat(&ret) != 0) { /* 9 */
+            if (of_stat(vol, &ret) != 0) { /* 9 */
                 /*
                  * ret.u_name doesn't exist, might be afp_createfile|dir
                  * that means it should have been the last part
@@ -1377,7 +1377,7 @@ int movecwd(const struct vol *vol, struct dir *dir)
     LOG(log_debug, logtype_afpd, "movecwd(to: did: %u, \"%s\")",
         ntohl(dir->d_did), cfrombstr(dir->d_fullpath));
 
-    if ((ret = lchdir(cfrombstr(dir->d_fullpath))) != 0 ) {
+    if ((ret = ochdir(cfrombstr(dir->d_fullpath), vol_syml_opt(vol))) != 0 ) {
         LOG(log_debug, logtype_afpd, "movecwd(\"%s\"): %s",
             cfrombstr(dir->d_fullpath), strerror(errno));
         if (ret == 1) {
@@ -2267,7 +2267,7 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
         return err;
     }
 
-    if (of_stat(s_path) < 0) {
+    if (of_stat(vol, s_path) < 0) {
         return AFPERR_MISC;
     }
 
@@ -2335,10 +2335,10 @@ int renamedir(const struct vol *vol,
             /* this needs to copy and delete. bleah. that means we have
              * to deal with entire directory hierarchies. */
             if ((err = copydir(vol, dirfd, src, dst)) < 0) {
-                deletedir(-1, dst);
+                deletedir(vol, -1, dst);
                 return err;
             }
-            if ((err = deletedir(dirfd, src)) < 0)
+            if ((err = deletedir(vol, dirfd, src)) < 0)
                 return err;
             break;
         default :
@@ -2717,7 +2717,7 @@ int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen  _U_, char *rbuf, si
         return path_error(path, AFPERR_NOOBJ);
     }
 
-    if ( !path->st_valid && of_stat(path ) < 0 ) {
+    if ( !path->st_valid && of_stat(vol, path) < 0 ) {
         return( AFPERR_NOOBJ );
     }
     if ( path->st_errno ) {
index fe5a66d993746610ce45747d347abc1e409036e4..2a3893354838f51cded7ff6e7628ef058cd74784 100644 (file)
@@ -283,7 +283,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
     if ( sindex == 1 || curdir->d_did != sd.sd_did || vid != sd.sd_vid ) {
         sd.sd_last = sd.sd_buf;
         /* if dir was in the cache we don't have the inode */
-        if (( !o_path->st_valid && lstat( ".", &o_path->st ) < 0 ) ||
+        if (( !o_path->st_valid && ostat(".", &o_path->st, vol_syml_opt(vol)) < 0 ) ||
             (ret = for_each_dirent(vol, ".", enumerate_loop, (void *)&sd)) < 0) 
         {
             LOG(log_error, logtype_afpd, "enumerate: loop error: %s (%d)", strerror(errno), errno);
@@ -347,7 +347,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
         }
         memset(&s_path, 0, sizeof(s_path));
         s_path.u_name = sd.sd_last;
-        if (of_stat( &s_path) < 0 ) {
+        if (of_stat(vol, &s_path) < 0 ) {
             /*
              * Somebody else plays with the dir, well it can be us with 
             * "Empty Trash..."
index 93c91c049634d8ef786afdfecd8e99880a255185..9f1ff318b1b8729928ae06f3fa0f32f7305f38ed 100644 (file)
@@ -115,7 +115,7 @@ void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *a
         }
     }
 
-    if (islink){
+    if (islink && !vol_syml_opt(vol)) {
         u_int16_t linkflag;
         memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2);
         linkflag |= htons(FINDERINFO_ISALIAS);
@@ -701,7 +701,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     upath = s_path->u_name;
     
     /* if upath is deleted we already in trouble anyway */
-    if ((of = of_findname(s_path))) {
+    if ((of = of_findname(vol, s_path))) {
         adp = of->of_ad;
     } else {
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
@@ -871,6 +871,9 @@ int setfilparams(struct vol *vol,
     u_int16_t           bitmap = f_bitmap;
     u_int32_t           cdate,bdate;
     u_char              finder_buf[32];
+    int fp;
+    ssize_t len;
+    char symbuf[MAXPATHLEN+1];
 
 #ifdef DEBUG
     LOG(log_debug9, logtype_afpd, "begin setfilparams:");
@@ -912,29 +915,32 @@ int setfilparams(struct vol *vol,
             break;
         case FILPBIT_FINFO :
             change_mdate = 1;
-            memcpy(finder_buf, buf, 32 );
-            if (memcmp(buf,"slnkrhap",8)==0 && !S_ISLNK(path->st.st_mode)){
-            // SLFINFO
-                int fp;
-                ssize_t len;
-                int erc=1;
-                char buf[PATH_MAX+1];
-                if ((fp=open(path->u_name,O_RDONLY))>=0){
-                    if ((len=read(fp,buf,PATH_MAX+1))){
-                        if (unlink(path->u_name)==0){
-                            buf[len]=0;
-                            erc = symlink(buf, path->u_name);
-                            if (!erc)
-                                of_stat(path);
-                        }
-                    }
-                    close(fp);
+            if (memcmp(buf,"slnkrhap",8) == 0
+                && !(S_ISLNK(path->st.st_mode))
+                && !(vol->v_flags & AFPVOL_FOLLOWSYM)) {
+                /* request to turn this into a symlink */
+                if ((fp = open(path->u_name, O_RDONLY)) == -1) {
+                    err = AFPERR_MISC;
+                    goto setfilparam_done;
                 }
-                if (erc!=0){
-                    err=AFPERR_BITMAP;
+                len = read(fp, symbuf, MAXPATHLEN);
+                close(fp);
+                if (!(len > 0)) {
+                    err = AFPERR_MISC;
                     goto setfilparam_done;
                 }
+                if (unlink(path->u_name) != 0) {
+                    err = AFPERR_MISC;
+                    goto setfilparam_done;
+                }
+                symbuf[len] = 0;
+                if (symlink(symbuf, path->u_name) != 0) {
+                    err = AFPERR_MISC;
+                    goto setfilparam_done;
+                }
+                of_stat(vol, path);
             }
+            memcpy(finder_buf, buf, 32 );
             buf += 32;
             break;
         case FILPBIT_UNIXPR :
@@ -1807,7 +1813,7 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
     cnid_t        did  = param->did;
     cnid_t       aint;
     
-    if ( lstat(de->d_name, &path.st)<0 )
+    if (ostat(de->d_name, &path.st, vol_syml_opt(vol)) < 0)
         return 0;
     
     /* update or add to cnid */
@@ -1852,7 +1858,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir)
     }
     
     /* FIXME use of_statdir ? */
-    if (lstat(name, &st)) {
+    if (ostat(name, &st, vol_syml_opt(vol))) {
        return -1;
     }
 
@@ -1931,7 +1937,7 @@ retry:
 
     memset(&path, 0, sizeof(path));
     path.u_name = upath;
-    if ( of_stat(&path) < 0 ) {
+    if (of_stat(vol, &path) < 0 ) {
 #ifdef ESTALE
         /* with nfs and our working directory is deleted */
        if (errno == ESTALE) {
@@ -2026,7 +2032,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
     }
 
     err = AFP_OK;
-    if ((movecwd(vol, dir) < 0) || (lstat(upath, &st) < 0)) {
+    if ((movecwd(vol, dir) < 0) || (ostat(upath, &st, vol_syml_opt(vol)) < 0)) {
         switch (errno) {
         case EACCES:
         case EPERM:
@@ -2062,7 +2068,7 @@ delete:
 }
 
 /* ------------------------------ */
-static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp)
+static struct adouble *find_adouble(const struct vol *vol, struct path *path, struct ofork **of, struct adouble *adp)
 {
     int             ret;
 
@@ -2089,7 +2095,7 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct
         return NULL;
     }
     
-    if ((*of = of_findname(path))) {
+    if ((*of = of_findname(vol, path))) {
         /* reuse struct adouble so it won't break locks */
         adp = (*of)->of_ad;
     }
@@ -2180,7 +2186,7 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     }
     
     ad_init(&ads, vol->v_adouble, vol->v_ad_options);
-    if (!(adsp = find_adouble( path, &s_of, &ads))) {
+    if (!(adsp = find_adouble(vol, path, &s_of, &ads))) {
         return afp_errno;
     }
 
@@ -2213,7 +2219,7 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     }
 
     ad_init(&add, vol->v_adouble, vol->v_ad_options);
-    if (!(addp = find_adouble( path, &d_of, &add))) {
+    if (!(addp = find_adouble(vol, path, &d_of, &add))) {
         err = afp_errno;
         goto err_exchangefile;
     }
@@ -2271,10 +2277,10 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     if (did)
         cnid_delete(vol->v_cdb, did);
 
-    if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || 
+    if ((did && ( (crossdev && ostat(upath, &srcst, vol_syml_opt(vol)) < 0) || 
                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
-       (sid && ( (crossdev && lstat(p, &destst) < 0) ||
+        (sid && ( (crossdev && ostat(p, &destst, vol_syml_opt(vol)) < 0) ||
                 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
     ) {
         switch (errno) {
index 6fe3c855b2d32d007432a9623ffa2cb2f0b6f8f8..c6bcc34e19181b50f61c9dee6adc91072f79e7f1 100644 (file)
@@ -94,28 +94,33 @@ int matchfile2dirperms(
         if ( uid != sb.st_uid )
         {
             seteuid(0);
-            if (lchown(upath, sb.st_uid, sb.st_gid) < 0)
+            if (ochown(upath, sb.st_uid, sb.st_gid, vol_syml_opt(vol)) < 0)
             {
                 LOG(log_error, logtype_afpd,
                     "matchfile2dirperms(%s): Error changing owner/gid: %s",
                     upath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
-            else if ((!S_ISLNK(st->st_mode)) && (chmod_acl(upath,(st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0))
-            {
+            else if (ochmod(upath,
+                            (st.st_mode & ~default_options.umask) | S_IRGRP | S_IROTH,
+                            &sb,
+                            vol_syml_opt(vol) | O_NETATALK_ACL) < 0) {                         
                 LOG(log_error, logtype_afpd,
                     "matchfile2dirperms(%s): Error adding file read permissions: %s",
                     upath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
-            else if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
+            else if (ochown(adpath, sb.st_uid, sb.st_gid, vol_syml_opt(vol)) < 0)
             {
                 LOG(log_error, logtype_afpd,
                     "matchfile2dirperms(%s): Error changing AppleDouble owner/gid: %s",
                     adpath, strerror(errno));
                 ret = AFPERR_ACCESS;
             }
-            else if (chmod_acl(adpath, (st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0)
+            else if (ochmod(adpath,
+                            (st.st_mode & ~default_options.umask) | S_IRGRP| S_IROTH,
+                            &st,
+                            vol_syml_opt(vol) | O_NETATALK_ACL) < 0)
             {
                 LOG(log_error, logtype_afpd,
                     "matchfile2dirperms(%s):  Error adding AD file read permissions: %s",
@@ -449,7 +454,7 @@ static int moveandrename(const struct vol *vol,
     if ( !isdir ) {
         path.st_valid = 1;
         path.st_errno = errno;
-        if (of_findname(&path)) {
+        if (of_findname(vol, &path)) {
             rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
         } else {
             rc = renamefile(vol, sdir_fd, oldunixname, upath, newname, adp );
@@ -614,7 +619,7 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
                 fce_register_delete_dir(cfrombstr(dname));
             bdestroy(dname);
         }
-    } else if (of_findname(s_path)) {
+    } else if (of_findname(vol, s_path)) {
         rc = AFPERR_BUSY;
     } else {
         /* it's a file st_valid should always be true
@@ -796,8 +801,8 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
             if (!isdir && !vol_unix_priv(vol)) {
                 int  admode = ad_mode("", 0777) | vol->v_fperm;
 
-                setfilmode(upath, admode, NULL, vol->v_umask);
-                vol->vfs->vfs_setfilmode(vol, upath, admode, NULL);
+                setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL);
+                vol->vfs->vfs_setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL);
             }
         setvoltime(obj, vol );
     }
index 33aaf66d1c025b1be90da8170b05376a2f988d81..634f7ad8f7499239d421342b955c047fe5d64090 100644 (file)
@@ -331,7 +331,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
        ad_open so that we can keep file locks together.
        FIXME: add the fork we are opening? 
     */
-    if ((opened = of_findname(s_path))) {
+    if ((opened = of_findname(vol, s_path))) {
         adsame = opened->of_ad;
     }
 
index 0ad46a9779ff519afcac78183db69c9c8e24e33a..bd70920a35f22aa191017c696be2397ec9f82778 100644 (file)
@@ -60,14 +60,14 @@ extern struct ofork *of_alloc    (struct vol *, struct dir *,
                                                       struct stat *);
 extern void         of_dealloc   (struct ofork *);
 extern struct ofork *of_find     (const u_int16_t);
-extern struct ofork *of_findname (struct path *);
+extern struct ofork *of_findname (const struct vol *vol, struct path *);
 extern int          of_rename    (const struct vol *,
                                           struct ofork *,
                                           struct dir *, const char *,
                                           struct dir *, const char *);
 extern int          of_flush     (const struct vol *);
 extern void         of_pforkdesc (FILE *);
-extern int          of_stat      (struct path *);
+extern int          of_stat      (const struct vol *vol, struct path *);
 extern int          of_statdir   (struct vol *vol, struct path *);
 extern int          of_closefork (struct ofork *ofork);
 extern void         of_closevol  (const struct vol *vol);
index 2d2600895cb5cc37a730a84a5bb1bdb1b9c6380e..47a1260990d0696e9069fbf730c0d7494ab00f3d 100644 (file)
@@ -248,14 +248,14 @@ struct ofork *of_find(const u_int16_t ofrefnum )
 }
 
 /* -------------------------- */
-int of_stat(struct path *path)
+int of_stat(const struct vol *vol, struct path *path)
 {
     int ret;
 
     path->st_errno = 0;
     path->st_valid = 1;
 
-    if ((ret = lstat(path->u_name, &path->st)) < 0) {
+    if ((ret = ostat(path->u_name, &path->st, vol_syml_opt(vol))) < 0) {
         LOG(log_debug, logtype_afpd, "of_stat('%s/%s': %s)",
             cfrombstr(curdir->d_fullpath), path->u_name, strerror(errno));
        path->st_errno = errno;
@@ -294,7 +294,7 @@ int of_statdir(struct vol *vol, struct path *path)
 
     if (*path->m_name) {
         /* not curdir */
-        return of_stat (path);
+        return of_stat(vol, path);
     }
     path->st_errno = 0;
     path->st_valid = 1;
@@ -306,7 +306,7 @@ int of_statdir(struct vol *vol, struct path *path)
 
     LOG(log_debug, logtype_afpd, "of_statdir: stating: '%s'", pathname);
 
-    if (!(ret = lstat(pathname, &path->st)))
+    if (!(ret = ostat(pathname, &path->st, vol_syml_opt(vol))))
         return 0;
 
     path->st_errno = errno;
@@ -317,7 +317,7 @@ int of_statdir(struct vol *vol, struct path *path)
            return -1;
        path->st_errno = 0;
 
-       if ((ret = lstat(cfrombstr(path->d_dir->d_u_name), &path->st)) < 0) 
+       if ((ret = ostat(cfrombstr(path->d_dir->d_u_name), &path->st, vol_syml_opt(vol))) < 0) 
            path->st_errno = errno;
     }
 
@@ -325,13 +325,13 @@ int of_statdir(struct vol *vol, struct path *path)
 }
 
 /* -------------------------- */
-struct ofork *of_findname(struct path *path)
+struct ofork *of_findname(const struct vol *vol, struct path *path)
 {
     struct ofork *of;
     struct file_key key;
 
     if (!path->st_valid) {
-        of_stat(path);
+        of_stat(vol, path);
     }
 
     if (path->st_errno)
@@ -455,7 +455,7 @@ struct adouble *of_ad(const struct vol *vol, struct path *path, struct adouble *
     struct ofork        *of;
     struct adouble      *adp;
 
-    if ((of = of_findname(path))) {
+    if ((of = of_findname(vol, path))) {
         adp = of->of_ad;
     } else {
         ad_init(ad, vol->v_adouble, vol->v_ad_options);
index 577ddab795961a2fd35be68614ba9745ba20011f..53938442b09242a1576010dfb891be5bc0b95680 100644 (file)
@@ -42,6 +42,7 @@ char *strchr (), *strrchr ();
 #include <atalk/logger.h>
 #include <atalk/afp.h>
 #include <atalk/compat.h>
+#include <atalk/util.h>
 
 #include "auth.h"
 #include "volume.h"
@@ -387,7 +388,7 @@ mountp( char *file, int *nfs)
     dev_t                      devno;
     static struct mnttab       mnt;
 
-    if ( lstat( file, &sb ) < 0 ) {
+    if (stat(file, &sb) < 0) {
         return( NULL );
     }
     devno = sb.st_dev;
@@ -398,14 +399,14 @@ mountp( char *file, int *nfs)
 
     while ( getmntent( mtab, &mnt ) == 0 ) {
         /* local fs */
-        if ( (lstat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) {
+        if ( (stat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) {
             fclose( mtab );
             return mnt.mnt_mountp;
         }
 
         /* check for nfs. we probably should use
          * strcmp(mnt.mnt_fstype, MNTTYPE_NFS), but that's not as fast. */
-        if ((lstat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) &&
+        if ((stat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) &&
                 strchr(mnt.mnt_special, ':')) {
             *nfs = 1;
             fclose( mtab );
@@ -475,7 +476,7 @@ special(char *file, int *nfs)
     struct mntent      *mnt;
     int                found=0;
 
-    if ( lstat( file, &sb ) < 0 ) {
+    if (stat(file, &sb) < 0 ) {
         return( NULL );
     }
     devno = sb.st_dev;
@@ -486,14 +487,14 @@ special(char *file, int *nfs)
 
     while (( mnt = getmntent( mtab )) != NULL ) {
         /* check for local fs */
-        if ( (lstat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) {
+        if ( (stat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) {
            found = 1;
            break;
         }
 
         /* check for an nfs mount entry. the alternative is to use
         * strcmp(mnt->mnt_type, MNTTYPE_NFS) instead of the strchr. */
-        if ((lstat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) &&
+        if ((stat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) &&
                 strchr(mnt->mnt_fsname, ':')) {
             *nfs = 1;
            found = 1;
index cc10d97ba02dbf39e58118eed7b6a4bba75503ec..d068c0b3c2711caa45d579df36180a53fc12802a 100644 (file)
@@ -175,7 +175,7 @@ void accessmode(const struct vol *vol, char *path, struct maccess *ma, struct di
 
     ma->ma_user = ma->ma_owner = ma->ma_world = ma->ma_group = 0;
     if (!st) {
-        if (lstat(path, &sb) != 0)
+        if (ostat(path, &sb, vol_syml_opt(vol)) != 0)
             return;
         st = &sb;
     }
@@ -234,6 +234,7 @@ mode_t mtoumode(struct maccess *ma)
 
 #define EXEC_MODE (S_IXGRP | S_IXUSR | S_IXOTH)
 
+/* Using chmod_acl() instead of ochmod is ok here */
 int setdeskmode(const mode_t mode)
 {
     char               wd[ MAXPATHLEN + 1];
@@ -277,7 +278,7 @@ int setdeskmode(const mode_t mode)
             *m = '\0';
             strcat( modbuf, subp->d_name );
             /* XXX: need to preserve special modes */
-            if (lstat(modbuf, &st) < 0) {
+            if (stat(modbuf, &st) < 0) {
                 LOG(log_error, logtype_afpd, "setdeskmode: stat %s: %s",fullpathname(modbuf), strerror(errno) );
                 continue;
             }
@@ -313,7 +314,7 @@ int setdeskmode(const mode_t mode)
 int setfilunixmode (const struct vol *vol, struct path* path, mode_t mode)
 {
     if (!path->st_valid) {
-        of_stat(path);
+        of_stat(vol, path);
     }
 
     if (path->st_errno) {
@@ -322,7 +323,7 @@ int setfilunixmode (const struct vol *vol, struct path* path, mode_t mode)
         
     mode |= vol->v_fperm;
 
-    if (setfilmode( path->u_name, mode, &path->st, vol->v_umask) < 0)
+    if (setfilmode(vol, path->u_name, mode, &path->st) < 0)
         return -1;
     /* we need to set write perm if read set for resource fork */
     return vol->vfs->vfs_setfilmode(vol, path->u_name, mode, &path->st);
@@ -384,7 +385,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode)
         if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
             continue;
         }
-        if ( lstat( dirp->d_name, &st ) < 0 ) {
+        if (ostat(dirp->d_name, &st, vol_syml_opt(vol)) < 0 ) {
             LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s",dirp->d_name, strerror(errno) );
             continue;
         }
@@ -392,7 +393,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode)
         if (!S_ISDIR(st.st_mode)) {
            int setmode = (osx && *dirp->d_name == '.')?hf_mode:mode;
 
-           if (setfilmode(dirp->d_name, setmode, &st, vol->v_umask) < 0) {
+           if (setfilmode(vol, dirp->d_name, setmode, &st) < 0) {
                closedir( dir );
                 LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",dirp->d_name, strerror(errno) );
                 return -1;
@@ -479,14 +480,14 @@ int setfilowner(const struct vol *vol, const uid_t uid, const gid_t gid, struct
 {
 
     if (!path->st_valid) {
-        of_stat(path);
+        of_stat(vol, path);
     }
 
     if (path->st_errno) {
         return -1;
     }
 
-    if ( lchown( path->u_name, uid, gid ) < 0 && errno != EPERM ) {
+    if (ochown( path->u_name, uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) {
         LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s",
             uid, gid, path->u_name, strerror(errno) );
        return -1;
@@ -520,13 +521,13 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const
         if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
             continue;
         }
-        if ( lstat( dirp->d_name, &st ) < 0 ) {
+        if (ostat(dirp->d_name, &st, vol_syml_opt(vol)) < 0 ) {
             LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s",
                 fullpathname(dirp->d_name), strerror(errno) );
             continue;
         }
         if (( st.st_mode & S_IFMT ) == S_IFREG ) {
-            if ( lchown( dirp->d_name, uid, gid ) < 0 && errno != EPERM ) {
+            if (ochown(dirp->d_name, uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) {
                 LOG(log_debug, logtype_afpd, "setdirowner: chown %s: %s",
                     fullpathname(dirp->d_name), strerror(errno) );
                 /* return ( -1 ); Sometimes this is okay */
@@ -539,10 +540,10 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const
         return -1;
     }
     
-    if ( lstat( ".", &st ) < 0 ) {
+    if (ostat(".", &st, vol_syml_opt(vol)) < 0 ) {
         return( -1 );
     }
-    if ( gid && gid != st.st_gid && lchown( ".", uid, gid ) < 0 && errno != EPERM ) {
+    if ( gid && gid != st.st_gid && ochown(".", uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) {
         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
             uid, gid, fullpathname("."), strerror(errno) );
     }
@@ -566,7 +567,7 @@ static int recursive_chown(const char *path, uid_t uid, gid_t gid) {
        return -1;
     }
 
-    if (lstat(path, &sbuf) < 0) {
+    if (stat(path, &sbuf) < 0) {
        LOG(log_error, logtype_afpd, "cannot chown() file [%s] (uid = %d): %s", path, uid, strerror(errno));
        return -1;
     }
index 11f154b0375717b139bdac9462cd23a7cb37b060..8079966310bf68a37cad2285e278545eab23652d 100644 (file)
@@ -513,6 +513,8 @@ static void volset(struct vol_option *options, struct vol_option *save,
                 options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS;
             else if (strcasecmp(p, "noacls") == 0)
                 options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS;
+            else if (strcasecmp(p, "followsymlinks") == 0)
+                options[VOLOPT_FLAGS].i_value |= AFPVOL_FOLLOWSYM;
             p = strtok(NULL, ",");
         }
 
@@ -778,6 +780,8 @@ static int creatvol(AFPObj *obj, struct passwd *pwd,
             volume->v_ad_options |= ADVOL_INVDOTS;
         if ((volume->v_flags & AFPVOL_NOADOUBLE))
             volume->v_ad_options |= ADVOL_NOADOUBLE;
+        if ((volume->v_flags & AFPVOL_FOLLOWSYM))
+            volume->v_ad_options |= ADVOL_FOLLO_SYML;
 
         if (options[VOLOPT_PASSWORD].c_value)
             volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value);
index 95aa0753401bb3385013192c3ea620a1fdd327b1..810be707bfec96b9ee2a8366cd1e25b8a83ad28e 100644 (file)
@@ -21,6 +21,8 @@
 
 #ifdef HAVE_ACLS
 
+#define O_NETATALK_ACL (O_NOFOLLOW << 1)
+
 #ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
 
@@ -51,6 +53,7 @@ extern int remove_acl_vfs(const char *name);
 
 #else /* HAVE_ACLS=no */
 
+#define O_NETATALK_ACL
 #define chmod_acl chmod
 
 #endif /* HAVE_ACLS */
index 78a35b02909ecd932bbf86d00cb5d908402e9426..4990022d7e079d5e52dfae04c1f50da0d9883d3b 100644 (file)
@@ -293,6 +293,8 @@ struct adouble_fops {
 #define ADVOL_UNIXPRIV   (1 << 2) /* adouble unix priv */
 #define ADVOL_INVDOTS    (1 << 3) /* dot files (.DS_Store) are invisible) */
 #define ADVOL_NOADOUBLE  (1 << 4)
+#define ADVOL_FOLLO_SYML (1 << 5)
+
 
 /* lock flags */
 #define ADLOCK_CLR      (0)
@@ -417,6 +419,8 @@ struct adouble_fops {
 #define ad_get_HF_flags(ad) ((ad)->ad_resource_fork.adf_flags)
 #define ad_get_MD_flags(ad) ((ad)->ad_md->adf_flags)
 
+#define ad_get_syml_opt(ad) (((ad)->ad_options & ADVOL_FOLLO_SYML) ? 0 : O_NOFOLLOW)
+
 /* ad_flush.c */
 extern int ad_rebuild_adouble_header (struct adouble *);
 extern int ad_rebuild_sfm_header (struct adouble *);
index f6d191ca6000d21f1613cad1a3fd6afb47083786..f8ab69275057f4b4c40f7a87c944e7b72211dbdd 100644 (file)
 extern int netatalk_unlink(const char *name);
 extern int netatalk_unlinkat(int dirfd, const char *name);
 extern int statat(int dirfd, const char *path, struct stat *st);
-extern int lstatat(int dirfd, const char *path, struct stat *st);
 extern DIR *opendirat(int dirfd, const char *path);
 
 /* rmdir ENOENT not an error */
 extern int netatalk_rmdir(int dirfd, const char *name);
 extern int netatalk_rmdir_all_errors(int dirfd, const char *name);
 
-extern int setfilmode(const char *, mode_t, struct stat *, mode_t);
+extern int setfilmode(const struct vol *vol, const char *name, mode_t mode, struct stat *st);
 extern int dir_rx_set(mode_t mode);
 extern int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask);
 extern int unix_rename(int sfd, const char *oldpath, int dfd, const char *newpath);
 extern int copy_file(int sfd, const char *src, const char *dst, mode_t mode);
+extern void become_root(void);
+extern void unbecome_root(void);
+
 #endif  /* ATALK_UNIX_H */
index 3a6dd24498bb85e7e66c84800f4edb633ca26aeb..9ce71584a8d0ed46b9041e85054a2848d871d1a8 100644 (file)
@@ -17,6 +17,9 @@
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <poll.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+
 #include <netatalk/at.h>
 
 #include <atalk/unicode.h>
@@ -187,10 +190,15 @@ extern int recv_fd(int fd, int nonblocking);
 extern const char *getcwdpath(void);
 extern const char *fullpathname(const char *);
 extern char *stripped_slashes_basename(char *p);
-extern int lchdir(const char *dir);
 extern void randombytes(void *buf, int n);
 extern int daemonize(int nochdir, int noclose);
 
+extern int ochdir(const char *dir, int options);
+extern int ostat(const char *path, struct stat *buf, int options);
+extern int ostatat(int dirfd, const char *path, struct stat *st, int options);
+extern int ochown(const char *path, uid_t owner, gid_t group, int options);
+extern int ochmod(const char *path, mode_t mode, const struct stat *st, int options);
+
 /******************************************************************
  * cnid.c
  *****************************************************************/
index af2b411c625ca6b07f8203798d5ccbcd12d36c10..60bae6ff5cb0dde0831c075eaec37886400af5a9 100644 (file)
@@ -139,6 +139,7 @@ struct vol {
 #define AFPVOL_ACLS      (1 << 24)   /* Volume supports ACLS */
 #define AFPVOL_SEARCHDB  (1 << 25)   /* Use fast CNID db search instead of filesystem */
 #define AFPVOL_NONETIDS  (1 << 26)   /* signal the client it shall do privelege mapping */
+#define AFPVOL_FOLLOWSYM (1 << 27)   /* follow symlinks on the server, default is not to */
 
 /* Extended Attributes vfs indirection  */
 #define AFPVOL_EA_NONE           0   /* No EAs */
@@ -202,6 +203,6 @@ int wincheck(const struct vol *vol, const char *path);
 #define vol_nodev(vol) (((vol)->v_flags & AFPVOL_NODEV) ? 1 : 0)
 #define vol_unix_priv(vol) (afp_version >= 30 && ((vol)->v_flags & AFPVOL_UNIX_PRIV))
 #define vol_inv_dots(vol) (((vol)->v_flags & AFPVOL_INV_DOTS) ? 1 : 0)
-
+#define vol_syml_opt(vol) (((vol)->v_flags & AFPVOL_FOLLOWSYM) ? 0 : O_NOFOLLOW)
 
 #endif
index e7f9753aca68a1400cd41dd409dc5744e8478463..524b73e6652b97ca4cee503a83724d31e1f9c453 100644 (file)
@@ -5,6 +5,7 @@ noinst_HEADERS = aclldap.h cache.h
 noinst_LTLIBRARIES = libacl.la
 libacl_la_SOURCES = cache.c unix.c uuid.c
 libacl_la_LDFLAGS =
+libacl_la_LIBADD  = @ACL_LIBS@
 
 if HAVE_LDAP
 libacl_la_SOURCES += ldap.c ldap_config.c
index 9bad9c94ea277ec4d1a7be192ab539aa6c71977d..8defd7d86174aa9e990fd295819feb6956a4be22 100644 (file)
@@ -33,6 +33,7 @@
 #include <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/acl.h>
+#include <atalk/unix.h>
 
 #ifdef HAVE_SOLARIS_ACLS
 
@@ -47,7 +48,7 @@ int get_nfsv4_acl(const char *name, ace_t **retAces)
     *retAces = NULL;
     /* Only call acl() for regular files and directories, otherwise just return 0 */
     if (lstat(name, &st) != 0) {
-        LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): %s", getcwdpath(), name, strerror(errno));
+        LOG(log_debug, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): %s", getcwdpath(), name, strerror(errno));
         return -1;
     }
 
@@ -234,8 +235,16 @@ int nfsv4_chmod(char *name, mode_t mode)
     if (chmod(name, mode) != 0) /* (3) */
         goto exit;
 
-    if ((nnaces = get_nfsv4_acl(name, &nacl)) == -1) /* (4) */
-        goto exit;
+    if ((nnaces = get_nfsv4_acl(name, &nacl)) == -1) {/* (4) */
+        if (errno != EACCES)
+            goto exit;
+        become_root();
+        nnaces = get_nfsv4_acl(name, &nacl);
+        unbecome_root();
+        if (nnaces == -1)
+            goto exit;
+    }
+
     if ((nnaces = strip_nontrivial_aces(&nacl, nnaces)) == -1) /* (5) */
         goto exit;
 
@@ -243,8 +252,17 @@ int nfsv4_chmod(char *name, mode_t mode)
         goto exit;
 
     if ((ret = acl(name, ACE_SETACL, noaces + nnaces, cacl)) != 0) {
-        LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno));
-        goto exit;
+        if (errno != EACCES) {
+            LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno));
+            goto exit;
+        }
+        become_root();
+        ret = acl(name, ACE_SETACL, noaces + nnaces, cacl);
+        unbecome_root();
+        if (ret != 0) {
+            LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno));
+            goto exit;
+        }
     }
 
 exit:
@@ -252,7 +270,7 @@ exit:
     if (nacl) free(nacl);
     if (cacl) free(cacl);
 
-    LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o): result: %u",
+    LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o): result: %d",
         getcwdpath(), name, mode, ret);
 
     return ret;
index 7adb4abda262c7261a8197463d36f9369a2a7426..b2b291b659a2e1d3e7666fa53d5ef5123d490f60 100644 (file)
@@ -1013,8 +1013,8 @@ int ad_stat(const char *path, struct stat *stbuf)
     if (!p) {
         return -1;
     }
-//FIXME!
-    return lstat( p, stbuf );
+
+    return stat(p, stbuf);
 }
 
 /* ----------------
@@ -1036,7 +1036,7 @@ static int ad_chown(const char *path, struct stat *stbuf)
     if (default_uid != (uid_t)-1) {
         /* we are root (admin) */
         id = (default_uid)?default_uid:stbuf->st_uid;
-        ret = lchown( path, id, stbuf->st_gid );
+        ret = chown(path, id, stbuf->st_gid);
     }
 #endif
     return ret;
@@ -1284,12 +1284,12 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
                 }
             }
                 
-            ad->ad_data_fork.adf_fd =open( path, hoflags | O_NOFOLLOW, admode );
+            ad->ad_data_fork.adf_fd = open(path, hoflags | ad_get_syml_opt(ad), admode);
             
             if (ad->ad_data_fork.adf_fd == -1) {
                 if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
                     hoflags = oflags;
-                    ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
+                    ad->ad_data_fork.adf_fd = open( path, hoflags | ad_get_syml_opt(ad), admode );
                 }
                 if (ad->ad_data_fork.adf_fd == -1 && errno == OPEN_NOFOLLOW_ERRNO) {
                     int lsz;
@@ -1366,11 +1366,11 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
     if (!(adflags & ADFLAGS_RDONLY)) {
         hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
     }
-    ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+    ad->ad_md->adf_fd = open(ad_p, hoflags | ad_get_syml_opt(ad), 0);
     if (ad->ad_md->adf_fd < 0 ) {
         if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
             hoflags = oflags & ~(O_CREAT | O_EXCL);
-            ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+            ad->ad_md->adf_fd = open(ad_p, hoflags | ad_get_syml_opt(ad), 0);
         }
     }
 
@@ -1391,7 +1391,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
             }
             admode = ad_hf_mode(admode);
             if ((errno == ENOENT) && (ad->ad_flags != AD_VERSION2_OSX)) {
-                if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
+                if (ad->ad_ops->ad_mkrf(ad_p) < 0) {
                     return ad_error(ad, adflags);
                 }
                 admode = mode;
@@ -1673,7 +1673,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
         memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
     }
 
-    if (lstat(path, &st) < 0) {
+    if (ostat(path, &st, ad_get_syml_opt(ad)) < 0) {
         return -1;
     }
 
index 0e466307bcd30d6ad13ec3af0c8444be0b26bd45..0ff282a0864c2e57442f266c6110f43191bd6e9c 100644 (file)
@@ -94,6 +94,22 @@ int daemonize(int nochdir, int noclose)
     return 0;
 }
 
+static uid_t saved_uid = -1;
+
+void become_root(void)
+{
+    saved_uid = geteuid();
+    if (seteuid(0) != 0)
+        AFP_PANIC("Can't seteuid(0)");
+}
+
+void unbecome_root(void)
+{
+    if (saved_uid == -1 || seteuid(saved_uid) < 0)
+        AFP_PANIC("Can't seteuid back");
+    saved_uid = -1;
+}
+
 /*!
  * @brief get cwd in static buffer
  *
@@ -152,20 +168,103 @@ char *stripped_slashes_basename(char *p)
     return (strrchr(p, '/') ? strrchr(p, '/') + 1 : p);
 }
 
+/*********************************************************************************
+ * chdir(), chmod(), chown(), stat() wrappers taking an additional option.
+ * Currently the only used options are O_NOFOLLOW, used to switch between symlink
+ * behaviour, and O_NETATALK_ACL for ochmod() indicating chmod_acl() shall be
+ * called which does special ACL handling depending on the filesytem
+ *********************************************************************************/
+
+int ostat(const char *path, struct stat *buf, int options)
+{
+    if (options & O_NOFOLLOW)
+        return lstat(path, buf);
+    else
+        return stat(path, buf);
+}
+
+int ochown(const char *path, uid_t owner, gid_t group, int options)
+{
+    if (options & O_NOFOLLOW)
+        return lchown(path, owner, group);
+    else
+        return chown(path, owner, group);
+}
+
+/*!
+ * chmod() wrapper for symlink and ACL handling
+ *
+ * @param path       (r) path
+ * @param mode       (r) requested mode
+ * @param sb         (r) stat() of path or NULL
+ * @param option     (r) O_NOFOLLOW | O_NETATALK_ACL
+ *
+ * Options description:
+ * O_NOFOLLOW: don't chmod() symlinks, do nothing, return 0
+ * O_NETATALK_ACL: call chmod_acl() instead of chmod()
+ */
+int ochmod(const char *path, mode_t mode, const struct stat *st, int options)
+{
+    struct stat sb;
+
+    if (!st) {
+        if (lstat(path, &sb) != 0)
+            return -1;
+        st = &sb;
+    }
+
+    if (options & O_NOFOLLOW)
+        if (S_ISLNK(st->st_mode))
+            return 0;
+
+    if (options & O_NETATALK_ACL) {
+        return chmod_acl(path, mode);
+    } else {
+        return chmod(path, mode);
+    }
+}
+
+/* 
+ * @brief ostat/fsstatat multiplexer
+ *
+ * ostatat mulitplexes ostat and fstatat. If we dont HAVE_ATFUNCS, dirfd is ignored.
+ *
+ * @param dirfd   (r) Only used if HAVE_ATFUNCS, ignored else, -1 gives AT_FDCWD
+ * @param path    (r) pathname
+ * @param st      (rw) pointer to struct stat
+ */
+int ostatat(int dirfd, const char *path, struct stat *st, int options)
+{
+#ifdef HAVE_ATFUNCS
+    if (dirfd == -1)
+        dirfd = AT_FDCWD;
+    return fstatat(dirfd, path, st, (options & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
+#else
+    return ostat(path, st, options);
+#endif            
+
+    /* DEADC0DE */
+    return -1;
+}
+
 /*!
  * @brief symlink safe chdir replacement
  *
- * Only chdirs to dir if it doesn't contain symlinks.
+ * Only chdirs to dir if it doesn't contain symlinks or if symlink checking
+ * is disabled
  *
  * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror
  */
-int lchdir(const char *dir)
+int ochdir(const char *dir, int options)
 {
     char buf[MAXPATHLEN+1];
     char cwd[MAXPATHLEN+1];
     char *test;
     int  i;
 
+    if (!(options & O_NOFOLLOW))
+        return chdir(dir);
+
     /*
      dir is a canonical path (without "../" "./" "//" )
      but may end with a / 
index abe266fef978574b0140ef01773b1b6be3927df7..25b758c2f856390266b30d7b26da78e209a78886 100644 (file)
@@ -894,7 +894,7 @@ int ea_close(struct ea * restrict ea)
             if (ea->ea_count == 0) {
                 /* Check if EA header exists and remove it */
                 eaname = ea_path(ea, NULL, 0);
-                if ((lstatat(ea->dirfd, eaname, &st)) == 0) {
+                if ((statat(ea->dirfd, eaname, &st)) == 0) {
                     if ((netatalk_unlinkat(ea->dirfd, eaname)) != 0) {
                         LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s",
                             eaname, strerror(errno));
@@ -1571,7 +1571,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN)
         }
     }
 
-    if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) {
+    if ((ochown(ea_path(&ea, NULL, 0), uid, gid, vol_syml_opt(vol))) != 0) {
         switch (errno) {
         case EPERM:
         case EACCES:
@@ -1588,7 +1588,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN)
             ret = AFPERR_MISC;
             goto exit;
         }
-        if ((lchown(eaname, uid, gid)) != 0) {
+        if ((ochown(eaname, uid, gid, vol_syml_opt(vol))) != 0) {
             switch (errno) {
             case EPERM:
             case EACCES:
@@ -1632,7 +1632,7 @@ int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
     }
 
     /* Set mode on EA header file */
-    if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+    if ((setfilmode(vol, ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL)) != 0) {
         LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
         switch (errno) {
         case EPERM:
@@ -1651,7 +1651,7 @@ int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
             ret = AFPERR_MISC;
             goto exit;
         }
-        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+        if ((setfilmode(vol, eaname, ea_mode(mode), NULL)) != 0) {
             LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", eaname, strerror(errno));
             switch (errno) {
             case EPERM:
@@ -1708,7 +1708,7 @@ int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
     }
 
     /* Set mode on EA header */
-    if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+    if ((setfilmode(vol, ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL)) != 0) {
         LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
         switch (errno) {
         case EPERM:
@@ -1738,7 +1738,7 @@ int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
             ret = AFPERR_MISC;
             goto exit;
         }
-        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+        if ((setfilmode(vol, eaname, ea_mode(mode), NULL)) != 0) {
             LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", eaname, strerror(errno));
             switch (errno) {
             case EPERM:
index 3db20b239cc69f4b2a39695d85ced1653dbf6daf..6269f0a46d63145a972d0bfb29e0e576b83dd68a 100644 (file)
@@ -723,14 +723,7 @@ static int solaris_unlinkat(int attrdirfd, const char *name)
 
 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
 {
-       int filedes = attropen(path, attrpath, oflag, mode);
-       if (filedes == -1) {
-        if (errno != ENOENT)
-            LOG(log_error, logtype_default, "attropen(\"%s\", ea:'%s'): %s",
-                path, attrpath, strerror(errno));
-        errno = ENOATTR;
-       }
-       return filedes;
+       return attropen(path, attrpath, oflag, mode);
 }
 
 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
index ffb524b825d88e7b2444a8e5cf742eaf4d5834d6..ce6b70a35ae0c47d22755a44acc4d0de9fec3850 100644 (file)
@@ -27,6 +27,7 @@
    a dropbox is a folder where w is set but not r eg:
    rwx-wx-wx or rwx-wx--
    rwx----wx (is not asked by a Mac with OS >= 8.0 ?)
+   using chmod_acl() instead of ochmod is ok here
 */
 int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask)
 {
@@ -76,7 +77,7 @@ int dir_rx_set(mode_t mode)
 }
 
 /* --------------------- */
-int setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
+int setfilmode(const struct vol *vol, const char *name, mode_t mode, struct stat *st)
 {
     struct stat sb;
     mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO;  /* rwx for owner group and other, by default */
@@ -87,12 +88,9 @@ int setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
         st = &sb;
     }
 
-    if (S_ISLNK(st->st_mode))
-        return 0; /* we don't want to change link permissions */
-    
     mode |= st->st_mode & ~mask; /* keep other bits from previous mode */
 
-    if ( chmod_acl( name,  mode & ~v_umask ) < 0 && errno != EPERM ) {
+    if (ochmod(name, mode & ~vol->v_umask, st, vol_syml_opt(vol) | O_NETATALK_ACL) < 0 && errno != EPERM ) {
         return -1;
     }
     return 0;
@@ -330,29 +328,6 @@ int statat(int dirfd, const char *path, struct stat *st)
     return -1;
 }
 
-/* 
- * @brief lstat/fsstatat multiplexer
- *
- * lstatat mulitplexes lstat and fstatat. If we dont HAVE_ATFUNCS, dirfd is ignored.
- *
- * @param dirfd   (r) Only used if HAVE_ATFUNCS, ignored else, -1 gives AT_FDCWD
- * @param path    (r) pathname
- * @param st      (rw) pointer to struct stat
- */
-int lstatat(int dirfd, const char *path, struct stat *st)
-{
-#ifdef HAVE_ATFUNCS
-    if (dirfd == -1)
-        dirfd = AT_FDCWD;
-    return (fstatat(dirfd, path, st, AT_SYMLINK_NOFOLLOW));
-#else
-    return (lstat(path, st));
-#endif            
-
-    /* DEADC0DE */
-    return -1;
-}
-
 /* 
  * @brief opendir wrapper for *at semantics support
  *
index 0999b878a8c37c800660e3ffb6945893e78623fe..66e5d3765e9d0b17345896024248f38638951afc 100644 (file)
@@ -48,11 +48,11 @@ struct perm {
     gid_t gid;
 };
 
-typedef int (*rf_loop)(struct dirent *, char *, void *, int , mode_t );
+typedef int (*rf_loop)(const struct vol *, struct dirent *, char *, void *, int);
 
 /* ----------------------------- */
 static int 
-for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int flag, mode_t v_umask)
+for_each_adouble(const char *from, const char *name, rf_loop fn, const struct vol *vol, void *data, int flag)
 {
     char            buf[ MAXPATHLEN + 1];
     char            *m;
@@ -78,7 +78,7 @@ for_each_adouble(const char *from, const char *name, rf_loop fn, void *data, int
         }
         
         strlcat(buf, de->d_name, sizeof(buf));
-        if (fn && (ret = fn(de, buf, data, flag, v_umask))) {
+        if (fn && (ret = fn(vol, de, buf, data, flag))) {
            closedir(dp);
            return ret;
         }
@@ -131,7 +131,7 @@ static int RF_renamedir_adouble(VFS_FUNC_ARGS_RENAMEDIR)
 }
 
 /* ----------------- */
-static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask)
+static int deletecurdir_adouble_loop(const struct vol *vol, struct dirent *de, char *name, void *data _U_, int flag _U_)
 {
     struct stat st;
     int         err;
@@ -154,20 +154,20 @@ static int RF_deletecurdir_adouble(VFS_FUNC_ARGS_DELETECURDIR)
 
     /* delete stray .AppleDouble files. this happens to get .Parent files
        as well. */
-    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1, vol->v_umask))) 
+    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, vol, NULL, 1))) 
         return err;
     return netatalk_rmdir(-1, ".AppleDouble" );
 }
 
 /* ----------------- */
-static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
+static int adouble_setfilmode(const struct vol *vol, const char *name, mode_t mode, struct stat *st)
 {
-    return setfilmode(name, ad_hf_mode(mode), st, v_umask);
+    return setfilmode(vol, name, ad_hf_mode(mode), st);
 }
 
 static int RF_setfilmode_adouble(VFS_FUNC_ARGS_SETFILEMODE)
 {
-    return adouble_setfilmode(vol->ad_path(name, ADFLAGS_HF ), mode, st, vol->v_umask);
+    return adouble_setfilmode(vol, vol->ad_path(name, ADFLAGS_HF ), mode, st);
 }
 
 /* ----------------- */
@@ -181,7 +181,7 @@ static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
             return -1;
     }
 
-    if (adouble_setfilmode(vol->ad_path(name, ADFLAGS_DIR ), mode, st, vol->v_umask) < 0) 
+    if (adouble_setfilmode(vol, vol->ad_path(name, ADFLAGS_DIR ), mode, st) < 0) 
         return -1;
 
     if (!dir_rx_set(mode)) {
@@ -192,18 +192,18 @@ static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 }
 
 /* ----------------- */
-static int setdirmode_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask)
+static int setdirmode_adouble_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag)
 {
     mode_t hf_mode = *(mode_t *)data;
     struct stat st;
 
-    if ( stat( name, &st ) < 0 ) {
+    if (ostat(name, &st, vol_syml_opt(vol)) < 0 ) {
         if (flag)
             return 0;
         LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s", name, strerror(errno) );
     }
     else if (!S_ISDIR(st.st_mode)) {
-        if (setfilmode(name, hf_mode , &st, v_umask) < 0) {
+        if (setfilmode(vol, name, hf_mode, &st) < 0) {
                /* FIXME what do we do then? */
         }
     }
@@ -222,7 +222,7 @@ static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
             return -1;
     }
 
-    if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, &hf_mode, vol_noadouble(vol), vol->v_umask))
+    if (for_each_adouble("setdirmode", adouble_p, setdirmode_adouble_loop, vol, &hf_mode, vol_noadouble(vol)))
         return -1;
 
     if (!dir_rx_set(mode)) {
@@ -233,7 +233,7 @@ static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
 }
 
 /* ----------------- */
-static int setdirowner_adouble_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
+static int setdirowner_adouble_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag _U_)
 {
     struct perm   *owner  = data;
 
@@ -257,7 +257,7 @@ static int RF_setdirowner_adouble(VFS_FUNC_ARGS_SETDIROWNER)
 
     adouble_p = ad_dir(vol->ad_path(name, ADFLAGS_DIR ));
 
-    if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble, vol->v_umask)) 
+    if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, vol, &owner, noadouble))
         return -1;
 
     /*
@@ -297,7 +297,7 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
         if (errno == ENOENT) {
                struct adouble    ad;
 
-            if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
+            if (ostatat(dirfd, adsrc, &st, vol_syml_opt(vol))) /* source has no ressource fork, */
                 return 0;
 
             /* We are here  because :
@@ -496,7 +496,7 @@ EC_CLEANUP:
 /*********************************************************************************
  * sfm adouble format
  *********************************************************************************/
-static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
+static int ads_chown_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag _U_)
 {
     struct perm   *owner  = data;
     
@@ -526,11 +526,11 @@ static int RF_chown_ads(VFS_FUNC_ARGS_CHOWN)
     if (chown( ad_p, uid, gid ) < 0) {
        return -1;
     }
-    return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1, vol->v_umask);
+    return for_each_adouble("chown_ads", ad_p, ads_chown_loop, vol, &owner, 1);
 }
 
 /* --------------------------------- */
-static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
+static int deletecurdir_ads1_loop(const struct vol *vol _U_, struct dirent *de _U_, char *name, void *data _U_, int flag _U_)
 {
     return netatalk_unlink(name);
 }
@@ -539,19 +539,19 @@ static int ads_delete_rf(char *name)
 {
     int err;
 
-    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) 
+    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, NULL, 1)))
         return err;
     /* FIXME 
      * it's a problem for a nfs mounted folder, there's .nfsxxx around
      * for linux the following line solve it.
      * but it could fail if rm .nfsxxx  create a new .nfsyyy :(
     */
-    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) 
+    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, NULL, 1))) 
         return err;
     return netatalk_rmdir(-1, name);
 }
 
-static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
+static int deletecurdir_ads_loop(const struct vol *vol, struct dirent *de, char *name, void *data _U_, int flag _U_)
 {
     struct stat st;
     
@@ -569,7 +569,7 @@ static int RF_deletecurdir_ads(VFS_FUNC_ARGS_DELETECURDIR)
     int err;
 
     /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
-    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1, 0))) 
+    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, vol, NULL, 1))) 
         return err;
 
     return netatalk_rmdir(-1, ".AppleDouble" );
@@ -581,14 +581,14 @@ struct set_mode {
     struct stat *st;
 };
 
-static int ads_setfilmode_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask)
+static int ads_setfilmode_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag _U_)
 {
     struct set_mode *param = data;
 
-    return setfilmode(name, param->mode, param->st, v_umask);
+    return setfilmode(vol, name, param->mode, NULL);
 }
 
-static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
+static int ads_setfilmode(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
 {
     mode_t file_mode = ad_hf_mode(mode);
     mode_t dir_mode = file_mode;
@@ -604,16 +604,16 @@ static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_
        /* change folder */
        dir_mode |= DIRBITS;
     if (dir_rx_set(dir_mode)) {
-        if (chmod_acl( name,  dir_mode ) < 0)
+        if (ochmod(name, dir_mode, st, vol_syml_opt(vol) | O_NETATALK_ACL) < 0)
             return -1;
     }
     param.st = st;
     param.mode = file_mode;
-    if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, &param, 0, v_umask) < 0)
+    if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, vol, &param, 0) < 0)
         return -1;
 
     if (!dir_rx_set(dir_mode)) {
-        if (chmod_acl( name,  dir_mode ) < 0)
+        if (ochmod(name, dir_mode, st, vol_syml_opt(vol) | O_NETATALK_ACL) < 0)
             return -1;
     }
 
@@ -622,7 +622,7 @@ static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_
 
 static int RF_setfilmode_ads(VFS_FUNC_ARGS_SETFILEMODE)
 {
-    return ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_HF )), mode, st, vol->v_umask);
+    return ads_setfilmode(vol, ad_dir(vol->ad_path(name, ADFLAGS_HF )), mode, st);
 }
 
 /* ------------------- */
@@ -645,7 +645,7 @@ static int RF_setdirunixmode_ads(VFS_FUNC_ARGS_SETDIRUNIXMODE)
             return -1;
     }
 
-    if (ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_DIR)), mode, st, vol->v_umask) < 0)
+    if (ads_setfilmode(vol, ad_dir(vol->ad_path(name, ADFLAGS_DIR)), mode, st) < 0)
         return -1;
 
     if (!dir_rx_set(mode)) {
@@ -663,25 +663,25 @@ struct dir_mode {
     int    dropbox;
 };
 
-static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask)
+static int setdirmode_ads_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag)
 {
 
     struct dir_mode *param = data;
     int    ret = 0; /* 0 ignore error, -1 */
 
     if (dir_rx_set(param->mode)) {
-        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) {
+        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, vol->v_umask) < 0) {
             if (flag) {
                 return 0;
             }
             return ret;
         }
     }
-    if (ads_setfilmode(name, param->mode, NULL, v_umask) < 0)
+    if (ads_setfilmode(vol, name, param->mode, NULL) < 0)
         return ret;
 
     if (!dir_rx_set(param->mode)) {
-        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) {
+        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, vol->v_umask) < 0) {
             if (flag) {
                 return 0;
             }
@@ -708,7 +708,7 @@ static int RF_setdirmode_ads(VFS_FUNC_ARGS_SETDIRMODE)
             return -1;
     }
 
-    if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, &param, vol_noadouble(vol), vol->v_umask))
+    if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, vol, &param, vol_noadouble(vol)))
         return -1;
 
     if (!dir_rx_set(mode)) {
@@ -719,7 +719,7 @@ static int RF_setdirmode_ads(VFS_FUNC_ARGS_SETDIRMODE)
 }
 
 /* ------------------- */
-static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
+static int setdirowner_ads1_loop(const struct vol *vol _U_, struct dirent *de _U_, char *name, void *data, int flag _U_)
 {
     struct perm   *owner  = data;
 
@@ -731,11 +731,11 @@ static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data,
     return 0;
 }
 
-static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask _U_)
+static int setdirowner_ads_loop(const struct vol *vol, struct dirent *de _U_, char *name, void *data, int flag)
 {
     struct perm   *owner  = data;
 
-    if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag, 0) < 0)
+    if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, vol, data, flag) < 0)
         return -1;
 
     if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
@@ -758,7 +758,7 @@ static int RF_setdirowner_ads(VFS_FUNC_ARGS_SETDIROWNER)
 
     strlcpy(adouble_p, ad_dir(vol->ad_path(name, ADFLAGS_DIR )), sizeof(adouble_p));
 
-    if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble, 0)) 
+    if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, vol, &owner, noadouble)) 
         return -1;
 
     /*
@@ -822,7 +822,7 @@ static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE)
         if (errno == ENOENT) {
                struct adouble    ad;
 
-            if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
+            if (ostatat(dirfd, adsrc, &st, vol_syml_opt(vol))) /* source has no ressource fork, */
                 return 0;
             
             /* We are here  because :
@@ -881,7 +881,7 @@ static int RF_deletecurdir_osx(VFS_FUNC_ARGS_DELETECURDIR)
 /* ---------------- */
 static int RF_setdirunixmode_osx(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
-    return adouble_setfilmode(vol->ad_path(name, ADFLAGS_DIR ), mode, st, vol->v_umask);
+    return adouble_setfilmode(vol, vol->ad_path(name, ADFLAGS_DIR), mode, st);
 }
 
 /* ---------------- */
@@ -908,7 +908,7 @@ static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
         struct stat st;
 
         err = errno;
-        if (errno == ENOENT && lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
+        if (errno == ENOENT && ostatat(dirfd, adsrc, &st, vol_syml_opt(vol))) /* source has no ressource fork, */
             return 0;
         errno = err;
         return -1;
index 6aabe036499e4fcdd05b3643acd7743de635f69d..d2926f7313c630447f4d2b585e260791b19004fa 100644 (file)
@@ -1,13 +1,22 @@
 '\" t
 .\"     Title: AppleVolumes.default
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: 13 Oct 2011
-.\"    Manual: Netatalk 2.2
-.\"    Source: Netatalk 2.2
+.\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
+.\"      Date: 27 Dez 2012
+.\"    Manual: Netatalk 3.0
+.\"    Source: Netatalk 3.0
 .\"  Language: English
 .\"
-.TH "APPLEVOLUMES\&.DEFAU" "5" "13 Oct 2011" "Netatalk 2.2" "Netatalk 2.2"
+.TH "APPLEVOLUMES\&.DEFAU" "5" "27 Dez 2012" "Netatalk 3.0" "Netatalk 3.0"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -58,7 +67,7 @@ path
 The path name must be a fully qualified path name, or a path name using either the ~ shell shorthand or any of the substitution variables, which are listed below\&.
 .PP
 The volume name is the name that appears in the Chooser ot the "connect to server" dialog on Macintoshes to represent the appropriate share\&. If volumename is unspecified, the last component of pathname is used\&. No two volumes may have the same name\&. If there are spaces in the name, it should be in quotes (i\&.e\&. "File Share")\&. The volume name cannot contain the
-\':\'
+\*(Aq:\*(Aq
 character\&. The volume name is mangled if it is very long\&. Mac codepage volume name is limited to 27 characters\&. UTF8\-MAC volume name is limited to \-volnamelen parameter in afpd\&.conf
 .if n \{\
 .sp
@@ -79,7 +88,7 @@ line\&. Though newline escaping is supported\&.
 .sp .5v
 .RE
 .PP
-The leading\-dot lines specify file name extension mappings\&. The extension \'\&.\' sets the default creator and type for otherwise untyped Unix files\&.
+The leading\-dot lines specify file name extension mappings\&. The extension \*(Aq\&.\*(Aq sets the default creator and type for otherwise untyped Unix files\&.
 .if n \{\
 .sp
 .\}
@@ -131,7 +140,7 @@ Specify the format of the metadata files, which are used for saving Mac resource
 .br
 \fBadouble:osx\fR
 \fBcannot\fR
-be treated normally any longer\&. Its only aim was to temporarely share eg\&. FAT32 formatted FireWire harddrives written on a Macintosh with afpd\&. Apple\'s metadata scheme lacks several essential features, so using it on the server\'s side will break both CNIDs and MacOS 9 compatibility\&. AppleDouble file of Mac OS X 10\&.6 is incompatible to V1 and V2\&.
+be treated normally any longer\&. Its only aim was to temporarely share eg\&. FAT32 formatted FireWire harddrives written on a Macintosh with afpd\&. Apple\*(Aqs metadata scheme lacks several essential features, so using it on the server\*(Aqs side will break both CNIDs and MacOS 9 compatibility\&. AppleDouble file of Mac OS X 10\&.6 is incompatible to V1 and V2\&.
 .sp .5v
 .RE
 .RE
@@ -284,15 +293,20 @@ a non\-zero return code from root_preexec closes the volume immediately, prevent
 .PP
 upriv
 .RS 4
-use AFP3 unix privileges\&. This should be set for OS X clients\&. Starting with Netatalk 2\&.1 it\'s part of the default config :DEFAULT: line\&. See also:
+use AFP3 unix privileges\&. This should be set for OS X clients\&. Starting with Netatalk 2\&.1 it\*(Aqs part of the default config :DEFAULT: line\&. See also:
 \fBperm|fperm|dperm\fR\&.
 .RE
 .PP
 usedots
 .RS 4
-Don\'t do :hex translation for dot files\&. note: when this option gets set, certain file names become illegal\&. These are \&.Parent and anything that starts with \&.Apple\&. See also
+Don\*(Aqt do :hex translation for dot files\&. note: when this option gets set, certain file names become illegal\&. These are \&.Parent and anything that starts with \&.Apple\&. See also
 \fBinvisibledots\fR\&.
 .RE
+.PP
+followsymlinks
+.RS 4
+Follow symlinks on the server\&.
+.RE
 .RE
 .PP
 password:\fI[password]\fR
@@ -362,7 +376,7 @@ Allows certain users and groups to have read/write access to a share\&. This fol
 .PP
 veto:\fI[vetoed names]\fR
 .RS 4
-hide files and directories,where the path matches one of the \'/\' delimited vetoed names\&. The veto string must always be terminated with a \'/\', eg\&. "veto1/", "veto1/veto2/"\&.
+hide files and directories,where the path matches one of the \*(Aq/\*(Aq delimited vetoed names\&. The veto string must always be terminated with a \*(Aq/\*(Aq, eg\&. "veto1/", "veto1/veto2/"\&.
 .RE
 .PP
 volcharset:\fI[charset]\fR
@@ -392,7 +406,7 @@ if you specify an unknown variable, it will not get converted\&.
 .sp -1
 .IP "  2." 4.2
 .\}
-if you specify a known variable, but that variable doesn\'t have a value, it will get ignored\&.
+if you specify a known variable, but that variable doesn\*(Aqt have a value, it will get ignored\&.
 .RE
 .PP
 The variables which can be used for substitutions are:
@@ -404,7 +418,7 @@ basename
 .PP
 $c
 .RS 4
-client\'s ip or appletalk address
+client\*(Aqs ip or appletalk address
 .RE
 .PP
 $d
@@ -429,7 +443,7 @@ hostname
 .PP
 $i
 .RS 4
-client\'s ip, without port
+client\*(Aqs ip, without port
 .RE
 .PP
 $s
@@ -473,13 +487,13 @@ prints dollar sign ($)
 We define "groupdirs" for each primary group and use a personalized server name for homedir shares\&.
 .SH "CNID BACKENDS"
 .PP
-The AFP protocol mostly refers to files and directories by ID and not by name\&. Netatalk needs a way to store these ID\'s in a persistent way, to achieve this several different CNID backends are available\&. The CNID Databases are by default located in the
+The AFP protocol mostly refers to files and directories by ID and not by name\&. Netatalk needs a way to store these ID\*(Aqs in a persistent way, to achieve this several different CNID backends are available\&. The CNID Databases are by default located in the
 \&.AppleDB
 folder in the volume root\&.
 .PP
 cdb
 .RS 4
-"Concurrent database", backend is based on Sleepycat\'s Berkely DB\&. With this backend several
+"Concurrent database", backend is based on Sleepycat\*(Aqs Berkely DB\&. With this backend several
 \fBafpd\fR
 deamons access the CNID database directly\&. Berkeley DB locking is used to synchronize access, if more than one
 \fBafpd\fR
@@ -500,7 +514,7 @@ processes communicate with the daemon for database reads and updates\&. If built
 .PP
 last
 .RS 4
-This backend is an exception, in terms of ID persistency\&. ID\'s are only valid for the current session\&. This is basically what
+This backend is an exception, in terms of ID persistency\&. ID\*(Aqs are only valid for the current session\&. This is basically what
 \fBafpd\fR
 did in the 1\&.5 (and 1\&.6) versions\&. This backend is still available, as it is useful for e\&.g\&. sharing cdroms\&.
 .sp
@@ -513,20 +527,20 @@ now relies heavily on a persistent ID database\&. Aliases will likely not work a
 .PP
 Even though
 \fB\&./configure \-\-help\fR
-might show that there are other CNID backends available, be warned those are likely broken or mainly used for testing\&. Don\'t use them unless you know what you\'re doing, they may be removed without further notice from future versions\&.
+might show that there are other CNID backends available, be warned those are likely broken or mainly used for testing\&. Don\*(Aqt use them unless you know what you\*(Aqre doing, they may be removed without further notice from future versions\&.
 .SH "CHARSET OPTIONS"
 .PP
 With OS X Apple introduced the AFP3 protocol\&. One of the most important changes was that AFP3 uses unicode names encoded as UTF\-8 decomposed\&. Previous AFP/OS versions used codepages, like MacRoman, MacCentralEurope, etc\&.
 .PP
 \fBafpd\fR
 needs a way to preserve extended macintosh characters, or characters illegal in unix filenames, when saving files on a unix filesystem\&. Earlier versions used the the so called CAP encoding\&. An extended character (>0x7F) would be converted to a :xx sequence, e\&.g\&. the Apple Logo (MacRoman: 0XF0) was saved as
-:f0\&. Some special characters will be converted as to :xx notation as well\&. \'/\' will be encoded to
+:f0\&. Some special characters will be converted as to :xx notation as well\&. \*(Aq/\*(Aq will be encoded to
 :2f, if
 \fBusedots\fR
-is not specified, a leading dot \'\&.\' will be encoded as
+is not specified, a leading dot \*(Aq\&.\*(Aq will be encoded as
 :2e\&.
 .PP
-This version now uses UTF\-8 as the default encoding for names\&. Special characters, like \'/\' and a leading \'\&.\' will still be CAP style encoded \&.
+This version now uses UTF\-8 as the default encoding for names\&. Special characters, like \*(Aq/\*(Aq and a leading \*(Aq\&.\*(Aq will still be CAP style encoded \&.
 .PP
 The
 \fB\-volcharset\fR
@@ -539,14 +553,14 @@ provided charset\&. If a character cannot be converted from the mac codepage to
 will convert the UTF\-8
 character to
 \fB\-maccharset\fR
-first\&. If this conversion fails, you\'ll receive a \-50 error on the mac\&.
+first\&. If this conversion fails, you\*(Aqll receive a \-50 error on the mac\&.
 .PP
 \fINote\fR: Whenever you can, please stick with the default UTF\-8 volume format\&.
 .SH "COMPATIBILITY WITH EARLIER VERSIONS"
 .PP
 To use a volume created with an earlier
 \fBafpd\fR
-version, you\'ll have to specify the following options:
+version, you\*(Aqll have to specify the following options:
 .PP
 \fBExample.\ \&use a 1.x style volume\fR
 .sp
@@ -580,7 +594,7 @@ You should consider converting old style volumes to the new UTF\-8/AD2 format\&.
 \fINote\fR: Using above example options will allow you to downgrade to 1\&.x netatalk again\&.
 .PP
 \fINote\fR: Some 1\&.x NLS files used non standard mappings, e\&.g\&.
-maccode\&.iso8859\-1\&.adapted\&. Three 1\&.x CAP double\-byte maccharsets are incompatible to netatalk 2\&.x; "MAC_CHINESE_TRAD", "MAC_JAPANESE" and "MAC_KOREAN"\&. These are not supported anymore\&. You\'ll have to copy the contents of those volumes files to a Mac and then back to the netatalk server, preferably to an UTF\-8 volume\&.
+maccode\&.iso8859\-1\&.adapted\&. Three 1\&.x CAP double\-byte maccharsets are incompatible to netatalk 2\&.x; "MAC_CHINESE_TRAD", "MAC_JAPANESE" and "MAC_KOREAN"\&. These are not supported anymore\&. You\*(Aqll have to copy the contents of those volumes files to a Mac and then back to the netatalk server, preferably to an UTF\-8 volume\&.
 .SH "ADVANCED OPTIONS"
 .PP
 The following options should only be used after serious consideration\&. Be sure you fully understood the, sometimes complex, consequences, before using them\&.
@@ -660,7 +674,7 @@ to not create \&.AppleDouble directories unless macintosh metadata needs to be w
 \fBafpd\fR
 to not automatically create \&.AppleDouble subdirs containing AD header files in every directory it enters (which will it do by default)\&.
 .sp
-In case, you save or change files from mac clients, AD metadata files have to be written even in case you set this option\&. So you can\'t avoid the creation of \&.AppleDouble directories and its contents when you give macs write access to a share and they make use of it\&.
+In case, you save or change files from mac clients, AD metadata files have to be written even in case you set this option\&. So you can\*(Aqt avoid the creation of \&.AppleDouble directories and its contents when you give macs write access to a share and they make use of it\&.
 .sp
 Try to avoid
 \fBnoadouble\fR
@@ -671,7 +685,7 @@ nocnidcache
 .RS 4
 If set
 \fBafpd\fR
-doesn\'t store the ID information in AppleDouble V2 header files\&. As these IDs are used for caching and as a database backup, this option normally shouldn\'t be set\&.
+doesn\*(Aqt store the ID information in AppleDouble V2 header files\&. As these IDs are used for caching and as a database backup, this option normally shouldn\*(Aqt be set\&.
 .RE
 .PP
 nodev
@@ -681,18 +695,18 @@ always use 0 for device number, helps when the device number is not constant acr
 .PP
 nofileid
 .RS 4
-don\'t advertise createfileid, resolveid, deleteid calls\&.
+don\*(Aqt advertise createfileid, resolveid, deleteid calls\&.
 .RE
 .PP
 nohex
 .RS 4
 Disables :hex translations for anything except dot files\&. This option makes the
-\'/\' character illegal\&.
+\*(Aq/\*(Aq character illegal\&.
 .RE
 .PP
 nostat
 .RS 4
-don\'t stat volume path when enumerating volumes list, useful for automounting or volumes created by a preexec script\&.
+don\*(Aqt stat volume path when enumerating volumes list, useful for automounting or volumes created by a preexec script\&.
 .RE
 .PP
 prodos
index ca379e0eec0fcd6c79f29c8d7164ed3f97ccc6ef..fec7a0e57a70d7684a3405c3b9a70cb5b5defcdf 100644 (file)
@@ -10,6 +10,7 @@ EXTRA_DIST = test.sh
 CLEANFILES = test.default test.conf
 
 test_SOURCES =  test.c subtests.c afpfunc_helpers.c \
+                               $(top_builddir)/etc/afpd/afp_asp.c \
                                $(top_builddir)/etc/afpd/afp_avahi.c \
                                $(top_builddir)/etc/afpd/afp_config.c \
                                $(top_builddir)/etc/afpd/afp_dsi.c \