]> arthur.barton.de Git - netatalk.git/commitdiff
Configurable symlink behaviour
authorFrank Lahm <franklahm@googlemail.com>
Wed, 14 Nov 2012 15:02:41 +0000 (16:02 +0100)
committerRalph Boehme <sloowfranklin@gmail.com>
Thu, 27 Dec 2012 15:12:29 +0000 (16:12 +0100)
Add a new volumes option 'followsymlinks' which modifies Netatalk's
handling of symlinks. Without the option (default behaviour) symlinks
are not followed by afpd.
Setting the volume option causes afpd to follow any symlink on the
server. symlinks may then point outside of the AFP volume, currently
afpd doesn't do any checks for "wide symlinks".

In order to provide a somewhat consistent interface, add an API
of o* function wrappers for filesytem related functions.
These functions take an an additonal option arg (hence the o) which
tells the functions whether symlinks shall be followed or not.

27 files changed:
NEWS
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/adouble/ad_open.c
libatalk/util/unix.c
libatalk/vfs/ea.c
libatalk/vfs/unix.c
libatalk/vfs/vfs.c
man/man5/AppleVolumes.default.5.tmpl

diff --git a/NEWS b/NEWS
index 233d35c67a96eb46d1954280bdaa93d734cb6511..6c5aab2f3edfad4e7ac0e67255e32293ed2d4839 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,9 @@ 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
 ================
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 907e999cb59e700faa22293dacd990ab7495dfd5..f1f55ef96d7a3ed2cea6823d317f1abcb014d180 100644 (file)
@@ -193,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);
@@ -581,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:
@@ -774,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 8b6efd7e1bdac95dc73170d0ab6c0bdc4940b42c..8446a848b26baed169f915f280ef4f88e3b97b5d 100644 (file)
@@ -688,7 +688,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
@@ -761,7 +761,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
@@ -838,7 +838,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 50bafbe55b555e5aa0d12d89721a714b7d344879..50945539cffa78c09fc8e2d46e18a370c2611fea 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 cc7bf5b08f75bc1612ce0e418c867d97d9380a75..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);
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 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 e4cb21e8c12e95e828afb608430a73c8c034ebf8..0ff282a0864c2e57442f266c6110f43191bd6e9c 100644 (file)
@@ -168,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 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