]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/file.c
Merge symlink branch
[netatalk.git] / etc / afpd / file.c
index 96970807805b98ff327650f1ca6ea218d4611f43..915219f595d11d7ea53876adc269a26a8b484b0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.96 2005-04-28 20:49:41 bfernhomberg Exp $
+ * $Id: file.c,v 1.134 2010-02-10 14:05:37 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -28,18 +28,18 @@ char *strchr (), *strrchr ();
 #endif /* ! HAVE_MEMCPY */
 #endif /* STDC_HEADERS */
 
-#include <atalk/adouble.h>
 #include <utime.h>
-#include <dirent.h>
 #include <errno.h>
-
-#include <atalk/logger.h>
 #include <sys/param.h>
 
-
+#include <atalk/adouble.h>
+#include <atalk/vfs.h>
+#include <atalk/logger.h>
 #include <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/cnid.h>
+#include <atalk/unix.h>
+
 #include "directory.h"
 #include "desktop.h"
 #include "volume.h"
@@ -89,7 +89,7 @@ static int default_type(void *finder)
 }
 
 /* FIXME path : unix or mac name ? (for now it's unix name ) */
-void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
+void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data, int islink)
 {
     struct extmap      *em;
     void                *ad_finder = NULL;
@@ -107,13 +107,24 @@ void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
     else {
         memcpy(data, ufinderi, ADEDLEN_FINDERI);
         chk_ext = 1;
-        if (*upath == '.') { /* make it invisible */
+        if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
             u_int16_t ashort;
             
             ashort = htons(FINDERINFO_INVISIBLE);
-            memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
+            memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
         }
     }
+
+    if (islink){
+        u_int16_t linkflag;
+        memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2);
+        linkflag |= htons(FINDERINFO_ISALIAS);
+        memcpy((char *)data + FINDERINFO_FRFLAGOFF, &linkflag, 2);
+        memcpy((char *)data + FINDERINFO_FRTYPEOFF,"slnk",4); 
+        memcpy((char *)data + FINDERINFO_FRCREATOFF,"rhap",4); 
+        chk_ext = 0;
+    }
+
     /** Only enter if no appledouble information and no finder information found. */
     if (chk_ext && (em = getextmap( upath ))) {
         memcpy(data, em->em_type, sizeof( em->em_type ));
@@ -158,7 +169,7 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t
         if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
            aint = 255;
 
-        utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0;         /* htonl(utf8) */
+        utf8 = vol->v_kTextEncoding;
         memcpy(data, &utf8, sizeof(utf8));
         data += sizeof(utf8);
         
@@ -187,25 +198,24 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t
                                  (1 << FILPBIT_RFLEN) |\
                                  (1 << FILPBIT_EXTRFLEN) |\
                                  (1 << FILPBIT_PDINFO) |\
+                                 (1 << FILPBIT_FNUM) |\
                                  (1 << FILPBIT_UNIXPR)))
 
 /* -------------------------- */
 u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
-             const cnid_t did, char *upath, const int len) 
+                 const cnid_t did, char *upath, const int len) 
 {
-u_int32_t aint = 0;
-
-#if AD_VERSION > AD_VERSION1
-
-    if ((aint = ad_getid(adp, st->st_dev, st->st_ino, did, vol->v_stamp))) {
-       return aint;
-    }
-#endif
+    u_int32_t adcnid;
+    u_int32_t dbcnid = CNID_INVALID;
 
     if (vol->v_cdb != NULL) {
-           aint = cnid_add(vol->v_cdb, st, did, upath, len, aint);
+        /* prime aint with what we think is the cnid, set did to zero for
+           catching moved files */
+        adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp);
+
+           dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid);
            /* Throw errors if cnid_add fails. */
-           if (aint == CNID_INVALID) {
+           if (dbcnid == CNID_INVALID) {
             switch (errno) {
             case CNID_ERR_CLOSE: /* the db is closed */
                 break;
@@ -221,25 +231,22 @@ u_int32_t aint = 0;
                 return CNID_INVALID;
             }
         }
-#if AD_VERSION > AD_VERSION1
-        else if (adp ) {
-            /* update the ressource fork
-             * for a folder adp is always null
-             */
-            if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
-                ad_flush(adp, ADFLAGS_HF);
+        else if (adp && (adcnid != dbcnid)) {
+            /* Update the ressource fork. For a folder adp is always null */
+            LOG(log_debug, logtype_afpd, "get_id: calling ad_setid. adcnid: %u, dbcnid: %u", htonl(adcnid), htonl(dbcnid));
+            if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) {
+                ad_flush(adp);
             }
         }
-#endif    
     }
-    return aint;
+    return dbcnid;
 }
              
 /* -------------------------- */
 int getmetadata(struct vol *vol,
                  u_int16_t bitmap,
                  struct path *path, struct dir *dir, 
-                 char *buf, int *buflen, struct adouble *adp, int attrbits )
+                 char *buf, size_t *buflen, struct adouble *adp)
 {
     char               *data, *l_nameoff = NULL, *upath;
     char                *utf_nameoff = NULL;
@@ -253,7 +260,7 @@ int getmetadata(struct vol *vol,
     struct maccess     ma;
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin getmetadata:");
+    LOG(log_debug9, logtype_afpd, "begin getmetadata:");
 #endif /* DEBUG */
 
     upath = path->u_name;
@@ -268,7 +275,7 @@ int getmetadata(struct vol *vol,
             id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
         else 
             id = path->id;
-        if (id == 0)
+        if (id == CNID_INVALID)
             return afp_errno;
         if (!path->m_name) {
             path->m_name = utompath(vol, upath, id, utf8_encoding());
@@ -284,7 +291,7 @@ int getmetadata(struct vol *vol,
         case FILPBIT_ATTR :
             if ( adp ) {
                 ad_getattr(adp, &ashort);
-            } else if (*upath == '.') {
+            } else if (vol_inv_dots(vol) && *upath == '.') {
                 ashort = htons(ATTRBIT_INVISIBLE);
             } else
                 ashort = 0;
@@ -296,12 +303,10 @@ int getmetadata(struct vol *vol,
             if ((ma.ma_user & AR_UWRITE)) {
                accessmode( upath, &ma, dir , st);
                if (!(ma.ma_user & AR_UWRITE)) {
-                       attrbits |= ATTRBIT_NOWRITE;
+                       ashort |= htons(ATTRBIT_NOWRITE);
                 }
             }
 #endif
-            if (attrbits)
-                ashort = htons(ntohs(ashort) | attrbits);
             memcpy(data, &ashort, sizeof( ashort ));
             data += sizeof( ashort );
             break;
@@ -338,7 +343,7 @@ int getmetadata(struct vol *vol,
             break;
 
         case FILPBIT_FINFO :
-           get_finderinfo(upath, adp, (char *)data);
+               get_finderinfo(vol, upath, adp, (char *)data,S_ISLNK(st->st_mode));
             data += ADEDLEN_FINDERI;
             break;
 
@@ -513,33 +518,27 @@ int getmetadata(struct vol *vol,
 int getfilparams(struct vol *vol,
                  u_int16_t bitmap,
                  struct path *path, struct dir *dir, 
-                 char *buf, int *buflen )
+                 char *buf, size_t *buflen )
 {
     struct adouble     ad, *adp;
-    struct ofork        *of;
-    char                   *upath;
-    u_int16_t          attrbits = 0;
     int                 opened = 0;
     int rc;    
 
 #ifdef DEBUG
-    LOG(log_info, logtype_default, "begin getfilparams:");
+    LOG(log_debug9, logtype_default, "begin getfilparams:");
 #endif /* DEBUG */
 
     opened = PARAM_NEED_ADP(bitmap);
     adp = NULL;
+
     if (opened) {
+        char *upath;
+        int  flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
+
+        adp = of_ad(vol, path, &ad);
         upath = path->u_name;
-        if ((of = of_findname(path))) {
-            adp = of->of_ad;
-           attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
-           attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
-        } else {
-            ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-            adp = &ad;
-        }
 
-        if ( ad_metadata( upath, 0, adp) < 0 ) {
+        if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) {
             switch (errno) {
             case EACCES:
                 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
@@ -554,41 +553,20 @@ int getfilparams(struct vol *vol,
                 break;
             }
         }
-        if (adp) {
-           /* FIXME 
-              we need to check if the file is open by another process.
-              it's slow so we only do it if we have to:
-              - bitmap is requested.
-              - we don't already have the answer!
-           */
-           if ((bitmap & (1 << FILPBIT_ATTR))) {
-                if (!(attrbits & ATTRBIT_ROPEN)) {
-                    attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
-                    attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
-                }
-                if (!(attrbits & ATTRBIT_DOPEN)) {
-                    attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
-                    attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
-                }
-           }
-       }
     }
-    rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
+    rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
     if ( adp ) {
-        ad_close( adp, ADFLAGS_HF );
+        ad_close_metadata( adp);
     }
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end getfilparams:");
+    LOG(log_debug9, logtype_afpd, "end getfilparams:");
 #endif /* DEBUG */
 
     return( rc );
 }
 
 /* ----------------------------- */
-int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj;
-char   *ibuf, *rbuf _U_;
-int    ibuflen _U_, *rbuflen;
+int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct adouble     ad, *adp;
     struct vol         *vol;
@@ -597,13 +575,8 @@ int        ibuflen _U_, *rbuflen;
     char               *path, *upath;
     int                        creatf, did, openf, retvalue = AFP_OK;
     u_int16_t          vid;
-    int                 ret;
     struct path                *s_path;
     
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_createfile:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
     ibuf++;
     creatf = (unsigned char) *ibuf++;
@@ -634,8 +607,6 @@ int ibuflen _U_, *rbuflen;
     }
 
     upath = s_path->u_name;
-    if (0 != (ret = check_name(vol, upath))) 
-       return  ret;
     
     /* if upath is deleted we already in trouble anyway */
     if ((of = of_findname(s_path))) {
@@ -659,7 +630,7 @@ int ibuflen _U_, *rbuflen;
         openf = O_RDWR|O_CREAT|O_EXCL;
     }
 
-    if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
+    if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
                   openf, 0666, adp) < 0 ) {
         switch ( errno ) {
         case EROFS:
@@ -670,11 +641,14 @@ int       ibuflen _U_, *rbuflen;
             return( AFPERR_EXIST );
         case EACCES :
             return( AFPERR_ACCESS );
+        case EDQUOT:
+        case ENOSPC :
+            return( AFPERR_DFULL );
         default :
             return( AFPERR_PARAM );
         }
     }
-    if ( ad_hfileno( adp ) == -1 ) {
+    if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
          /* on noadouble volumes, just creating the data fork is ok */
          if (vol_noadouble(vol)) {
              ad_close( adp, ADFLAGS_DF );
@@ -690,7 +664,7 @@ int ibuflen _U_, *rbuflen;
 
     path = s_path->m_name;
     ad_setname(adp, path);
-    ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
+    ad_flush( adp);
     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
 
 createfile_done:
@@ -704,17 +678,10 @@ createfile_done:
 
     setvoltime(obj, vol );
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end afp_createfile");
-#endif /* DEBUG */
-
     return (retvalue);
 }
 
-int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj;
-char   *ibuf, *rbuf _U_;
-int    ibuflen _U_, *rbuflen;
+int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct vol *vol;
     struct dir *dir;
@@ -722,10 +689,6 @@ int        ibuflen _U_, *rbuflen;
     int                did, rc;
     u_int16_t  vid, bitmap;
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
     ibuf += 2;
 
@@ -768,10 +731,6 @@ int        ibuflen _U_, *rbuflen;
         setvoltime(obj, vol );
     }
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end afp_setfilparams:");
-#endif /* DEBUG */
-
     return( rc );
 }
 
@@ -789,7 +748,7 @@ int setfilparams(struct vol *vol,
     int                        bit, isad = 1, err = AFP_OK;
     char                *upath;
     u_char              achar, *fdType, xyy[4]; /* uninitialized, OK 310105 */
-    u_int16_t          ashort, bshort;
+    u_int16_t          ashort, bshort, oshort;
     u_int32_t          aint;
     u_int32_t          upriv;
     u_int16_t           upriv_bit = 0;
@@ -807,12 +766,11 @@ int setfilparams(struct vol *vol,
     u_char              finder_buf[32];
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin setfilparams:");
+    LOG(log_debug9, logtype_afpd, "begin setfilparams:");
 #endif /* DEBUG */
 
-    upath = path->u_name;
     adp = of_ad(vol, path, &ad);
-    
+    upath = path->u_name;
 
     if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) {
         return AFPERR_ACCESS;
@@ -848,6 +806,27 @@ int setfilparams(struct vol *vol,
         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);  
+                            lstat(path->u_name,&(path->st));
+                        }
+                    }
+                    close(fp);
+                }
+                if (erc!=0){
+                    err=AFPERR_BITMAP;
+                    goto setfilparam_done;
+                }
+            }
             buf += 32;
             break;
         case FILPBIT_UNIXPR :
@@ -910,12 +889,18 @@ int setfilparams(struct vol *vol,
 
     /* second try with adouble open 
     */
-    if ( ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
-                 O_RDWR|O_CREAT, 0666, adp) < 0) {
-        /* for some things, we don't need an adouble header */
-        if (f_bitmap & ~(1<<FILPBIT_MDATE)) {
+    if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
+        LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
+        /*
+         * For some things, we don't need an adouble header:
+         * - change of modification date
+         * - UNIX privs (Bug-ID #2863424)
+         */
+        if ( (f_bitmap & ~(1<<FILPBIT_MDATE | 1<<FILPBIT_UNIXPR))) {
+            LOG(log_debug, logtype_afpd, "setfilparams: need adouble access");
             return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
         }
+        LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
         isad = 0;
     } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
         ad_setname(adp, path->m_name);
@@ -932,14 +917,14 @@ int setfilparams(struct vol *vol,
         switch(  bit ) {
         case FILPBIT_ATTR :
             ad_getattr(adp, &bshort);
-            if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
-                (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
-                change_parent_mdate = 1;
+            oshort = bshort;
             if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
             } else {
                 bshort &= ~ashort;
             }
+            if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
+                change_parent_mdate = 1;
             ad_setattr(adp, bshort);
             break;
         case FILPBIT_CDATE :
@@ -996,8 +981,8 @@ setfilparam_done:
     }
 
     if (isad) {
-        ad_flush( adp, ADFLAGS_HF );
-        ad_close( adp, ADFLAGS_HF );
+        ad_flush( adp);
+        ad_close_metadata( adp);
 
     }
 
@@ -1008,7 +993,7 @@ setfilparam_done:
     }
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end setfilparams:");
+    LOG(log_debug9, logtype_afpd, "end setfilparams:");
 #endif /* DEBUG */
     return err;
 }
@@ -1023,15 +1008,12 @@ setfilparam_done:
  * adp         adouble struct of src file, if open, or & zeroed one
  *
  */
-int renamefile(vol, src, dst, newname, adp )
-const struct vol *vol;
-char   *src, *dst, *newname;
-struct adouble    *adp;
+int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struct adouble *adp)
 {
     int                rc;
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin renamefile:");
+    LOG(log_debug9, logtype_afpd, "begin renamefile:");
 #endif /* DEBUG */
 
     if ( unix_rename( src, dst ) < 0 ) {
@@ -1048,7 +1030,7 @@ struct adouble    *adp;
             * get two files, it's fixable for our process (eg reopen the new file, get the
             * locks, and so on. But it doesn't solve the case with a second process
             */
-           if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
+           if (adp->ad_open_forks) {
                /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
                return AFPERR_OLOCK; /* little lie */
            }
@@ -1062,7 +1044,7 @@ struct adouble    *adp;
         }
     }
 
-    if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
+    if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
         int err;
         
         err = errno;        
@@ -1090,11 +1072,11 @@ struct adouble    *adp;
      */
     if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
         ad_setname(adp, newname);
-        ad_flush( adp, ADFLAGS_HF );
+        ad_flush( adp );
         ad_close( adp, ADFLAGS_HF );
     }
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end renamefile:");
+    LOG(log_debug9, logtype_afpd, "end renamefile:");
 #endif /* DEBUG */
 
     return( AFP_OK );
@@ -1171,10 +1153,7 @@ u_int32_t   hint;
 
 /* -----------------------------------
 */
-int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj;
-char   *ibuf, *rbuf _U_;
-int    ibuflen _U_, *rbuflen;
+int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct vol *s_vol, *d_vol;
     struct dir *dir;
@@ -1187,10 +1166,6 @@ int      ibuflen _U_, *rbuflen;
     struct adouble ad, *adp;
     int denyreadset;
     
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_copyfile:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1288,21 +1263,17 @@ int     ibuflen _U_, *rbuflen;
 
     setvoltime(obj, d_vol );
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end afp_copyfile:");
-#endif /* DEBUG */
-
     return( retvalue );
 }
 
 /* ----------------------- */
-static __inline__ int copy_all(const int dfd, const void *buf,
+static int copy_all(const int dfd, const void *buf,
                                size_t buflen)
 {
     ssize_t cc;
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin copy_all:");
+    LOG(log_debug9, logtype_afpd, "begin copy_all:");
 #endif /* DEBUG */
 
     while (buflen > 0) {
@@ -1318,19 +1289,37 @@ static __inline__ int copy_all(const int dfd, const void *buf,
     }
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end copy_all:");
+    LOG(log_debug9, logtype_afpd, "end copy_all:");
 #endif /* DEBUG */
 
     return 0;
 }
 
-/* -------------------------- */
-static int copy_fd(int dfd, int sfd)
+/* -------------------------- 
+ * copy only the fork data stream
+*/
+static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
 {
     ssize_t cc;
     int     err = 0;
     char    filebuf[8192];
+    int     sfd, dfd;
     
+    if (eid == ADEID_DFORK) {
+        sfd = ad_data_fileno(ads);
+        dfd = ad_data_fileno(add);
+    }
+    else {
+        sfd = ad_reso_fileno(ads);
+        dfd = ad_reso_fileno(add);
+    }        
+
+    if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
+       return -1;
+
+    if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
+       return -1;
+       
 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
     /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
     off_t   offset = 0;
@@ -1376,23 +1365,22 @@ static int copy_fd(int dfd, int sfd)
 }
 
 /* ----------------------------------
- * if newname is NULL (from directory.c) we don't want to copy ressource fork.
+ * if newname is NULL (from directory.c) we don't want to copy the resource fork.
  * because we are doing it elsewhere.
+ * currently if newname is NULL then adp is NULL. 
  */
-int copyfile(s_vol, d_vol, src, dst, newname, adp )
-const struct vol *s_vol, *d_vol;
-char   *src, *dst, *newname;
-struct adouble *adp;
+int copyfile(const struct vol *s_vol, const struct vol*d_vol, 
+    char *src, char *dst, char *newname, struct adouble *adp)
 {
     struct adouble     ads, add;
     int                        err = 0;
     int                 ret_err = 0;
     int                 adflags;
-    int                 noadouble = vol_noadouble(d_vol);
+    int                 stat_result;
     struct stat         st;
     
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin copyfile:");
+    LOG(log_debug9, logtype_afpd, "begin copyfile:");
 #endif /* DEBUG */
 
     if (adp == NULL) {
@@ -1410,12 +1398,19 @@ struct adouble *adp;
         goto done;
     }
 
-    if (ad_hfileno(adp) == -1) {
+    if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
         /* no resource fork, don't create one for dst file */
         adflags &= ~ADFLAGS_HF;
     }
 
-    if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
+    stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
+
+    if (stat_result < 0) {           
+      /* unlikely but if fstat fails, the default file mode will be 0666. */
+      st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    }
+
+    if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
         ret_err = errno;
         ad_close( adp, adflags );
         if (EEXIST != ret_err) {
@@ -1424,45 +1419,40 @@ struct adouble *adp;
         }
         return AFPERR_EXIST;
     }
-    if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
+    
+    /*
+     * XXX if the source and the dest don't use the same resource type it's broken
+     */
+    if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
         /* copy the data fork */
-       err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
+        if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) {
+            err = d_vol->vfs->vfs_copyfile(d_vol, src, dst);
+        }
     }
 
-    /* Now, reopen destination file */
     if (err < 0) {
        ret_err = errno;
     }
-    ad_close( adp, adflags );
 
-    if (ad_close( &add, adflags ) <0) {
-        deletefile(d_vol, dst, 0);
-        ret_err = errno;
-        goto done;
-    } 
-    else {
-       ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
-       if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
-           ret_err = errno;
-       }
-    }
-
-    if (!ret_err && newname) {
+    if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
+        /* set the new name in the resource fork */
+        ad_copy_header(&add, adp);
         ad_setname(&add, newname);
+        ad_flush( &add );
     }
+    ad_close( adp, adflags );
 
-    ad_flush( &add, adflags );
     if (ad_close( &add, adflags ) <0) {
        ret_err = errno;
-    }
+    } 
+
     if (ret_err) {
         deletefile(d_vol, dst, 0);
     }
-    else if (!stat(src, &st)) {
+    else if (stat_result == 0) {
         /* set dest modification date to src date */
         struct utimbuf ut;
 
-        /* ADS here ? */
        ut.actime = ut.modtime = st.st_mtime;
        utime(dst, &ut);
        /* FIXME netatalk doesn't use resource fork file date
@@ -1471,7 +1461,7 @@ struct adouble *adp;
     }
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end copyfile:");
+    LOG(log_debug9, logtype_afpd, "end copyfile:");
 #endif /* DEBUG */
 
 done:
@@ -1503,23 +1493,53 @@ done:
    ad_open always try to open file RDWR first and ad_lock takes care of
    WRITE lock on read only file.
 */
-int deletefile( vol, file, checkAttrib )
-const struct vol      *vol;
-char           *file;
-int         checkAttrib;
+
+static int check_attrib(struct adouble *adp)
+{
+u_int16_t   bshort = 0;
+
+       ad_getattr(adp, &bshort);
+    /*
+     * Does kFPDeleteInhibitBit (bit 8) set?
+     */
+       if ((bshort & htons(ATTRBIT_NODELETE))) {
+               return AFPERR_OLOCK;
+       }
+    if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
+       return AFPERR_BUSY;
+       }
+       return 0;
+}
+
+int deletefile(const struct vol *vol, char *file, int checkAttrib)
 {
     struct adouble     ad;
     struct adouble      *adp = &ad;
     int                        adflags, err = AFP_OK;
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin deletefile:");
+    LOG(log_debug9, logtype_afpd, "begin deletefile:");
 #endif /* DEBUG */
 
     /* try to open both forks at once */
     adflags = ADFLAGS_DF|ADFLAGS_HF;
-    ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
+    if (checkAttrib) {
+        /* was EACCESS error try to get only metadata */
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+        /* we never want to create a resource fork here, we are going to delete it 
+         * moreover sometimes deletefile is called with a no existent file and 
+         * ad_open would create a 0 byte resource fork
+        */
+        if ( ad_metadata( file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
+            ad_close( &ad, adflags );
+            if ((err = check_attrib(&ad))) {
+               return err;
+            }
+        }
+    }
     while(1) {
+       ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
             switch (errno) {
             case ENOENT:
@@ -1531,7 +1551,7 @@ int         checkAttrib;
                 continue;
 
             case EACCES:
-                adp = NULL; /* maybe it's a file we no rw mode for us */
+                adp = NULL; /* maybe it's a file with no write mode for us */
                 break;      /* was return AFPERR_ACCESS;*/
             case EROFS:
                 return AFPERR_VLOCK;
@@ -1541,33 +1561,7 @@ int         checkAttrib;
         }
         break; /* from the while */
     }
-    /*
-     * Does kFPDeleteInhibitBit (bit 8) set?
-     */
-    if (checkAttrib) {
-        u_int16_t   bshort;
-        
-        if (adp && (adflags & ADFLAGS_HF)) {
 
-            ad_getattr(&ad, &bshort);
-            if ((bshort & htons(ATTRBIT_NODELETE))) {
-                ad_close( &ad, adflags );
-                return(AFPERR_OLOCK);
-            }
-        }
-        else if (!adp) {
-            /* was EACCESS error try to get only metadata */
-            ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
-            if ( ad_metadata( file , 0, &ad) == 0 ) {
-                ad_getattr(&ad, &bshort);
-                ad_close( &ad, ADFLAGS_HF );
-                if ((bshort & htons(ATTRBIT_NODELETE))) {
-                    return  AFPERR_OLOCK;
-                }
-            }
-        }
-    }
-    
     if (adp && (adflags & ADFLAGS_HF) ) {
         /* FIXME we have a pb here because we want to know if a file is open 
          * there's a 'priority inversion' if you can't open the ressource fork RW
@@ -1587,7 +1581,7 @@ int         checkAttrib;
     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
         err = AFPERR_BUSY;
     }
-    else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
+    else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
         cnid_t id;
         if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
         {
@@ -1598,7 +1592,7 @@ int         checkAttrib;
         ad_close( &ad, adflags );  /* ad_close removes locks if any */
 
 #ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end deletefile:");
+    LOG(log_debug9, logtype_afpd, "end deletefile:");
 #endif /* DEBUG */
 
     return err;
@@ -1606,10 +1600,7 @@ int         checkAttrib;
 
 /* ------------------------------------ */
 /* return a file id */
-int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj _U_;
-char   *ibuf, *rbuf;
-int    ibuflen _U_, *rbuflen;
+int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
     struct stat         *st;
     struct vol         *vol;
@@ -1620,10 +1611,6 @@ int      ibuflen _U_, *rbuflen;
     u_short            vid;
     struct path         *s_path;
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_createid:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
 
     ibuf += 2;
@@ -1682,9 +1669,6 @@ int       ibuflen _U_, *rbuflen;
         return AFP_OK;
     }
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "ending afp_createid...:");
-#endif /* DEBUG */
     return afp_errno;
 }
 
@@ -1702,9 +1686,7 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
     cnid_t        did  = param->did;
     cnid_t       aint;
     
-    memset(&path, 0, sizeof(path));
-
-    if ( stat(de->d_name, &path.st)<0 )
+    if ( lstat(de->d_name, &path.st)<0 )
         return 0;
     
     /* update or add to cnid */
@@ -1720,13 +1702,13 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
             
         adp = of_ad(vol, &path, &ad);
             
-        if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, adp ) < 0 ) {
+        if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
             return 0;
         }
         if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
-            ad_flush(adp, ADFLAGS_HF);
+            ad_flush(adp);
         }
-        ad_close(adp, ADFLAGS_HF);
+        ad_close_metadata(adp);
     }
 #endif /* AD_VERSION > AD_VERSION1 */
 
@@ -1749,7 +1731,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir)
     }
     
     /* FIXME use of_statdir ? */
-    if (stat(name, &st)) {
+    if (lstat(name, &st)) {
        return -1;
     }
 
@@ -1770,26 +1752,20 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir)
 
 /* ------------------------------
    resolve a file id */
-int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj _U_;
-char   *ibuf, *rbuf;
-int    ibuflen _U_, *rbuflen;
+int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
     struct vol         *vol;
     struct dir         *dir;
     char               *upath;
     struct path         path;
-    int                 err, buflen, retry=0;
+    int                 err, retry=0;
+    size_t             buflen;
     cnid_t             id, cnid;
     u_int16_t          vid, bitmap;
 
     static char buffer[12 + MAXPATHLEN + 1];
     int len = 12 + MAXPATHLEN + 1;
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_resolveid:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1813,7 +1789,6 @@ int       ibuflen _U_, *rbuflen;
         return AFPERR_NOID;
     }
 retry:
-    memset(&path, 0, sizeof(path));
     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
     }
@@ -1821,7 +1796,6 @@ retry:
     if (NULL == ( dir = dirlookup( vol, id )) ) {
         return AFPERR_NOID; /* idem AFPERR_PARAM */
     }
-    path.u_name = upath;
     if (movecwd(vol, dir) < 0) {
         switch (errno) {
         case EACCES:
@@ -1834,6 +1808,8 @@ retry:
         }
     }
 
+    memset(&path, 0, sizeof(path));
+    path.u_name = upath;
     if ( of_stat(&path) < 0 ) {
 #ifdef ESTALE
         /* with nfs and our working directory is deleted */
@@ -1860,8 +1836,10 @@ retry:
     }
 
     /* directories are bad */
-    if (S_ISDIR(path.st.st_mode))
-        return AFPERR_BADTYPE;
+    if (S_ISDIR(path.st.st_mode)) {
+        /* OS9 and OSX don't return the same error code  */
+        return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE;
+    }
 
     memcpy(&bitmap, ibuf, sizeof(bitmap));
     bitmap = ntohs( bitmap );
@@ -1876,18 +1854,11 @@ retry:
     *rbuflen = buflen + sizeof(bitmap);
     memcpy(rbuf, ibuf, sizeof(bitmap));
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end afp_resolveid:");
-#endif /* DEBUG */
-
     return AFP_OK;
 }
 
 /* ------------------------------ */
-int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj _U_;
-char   *ibuf, *rbuf _U_;
-int    ibuflen _U_, *rbuflen;
+int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct stat         st;
     struct vol         *vol;
@@ -1900,10 +1871,6 @@ int      ibuflen _U_, *rbuflen;
     static char buffer[12 + MAXPATHLEN + 1];
     int len = 12 + MAXPATHLEN + 1;
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_deleteid:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1934,7 +1901,7 @@ int       ibuflen _U_, *rbuflen;
     }
 
     err = AFP_OK;
-    if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
+    if ((movecwd(vol, dir) < 0) || (lstat(upath, &st) < 0)) {
         switch (errno) {
         case EACCES:
         case EPERM:
@@ -1965,10 +1932,6 @@ int      ibuflen _U_, *rbuflen;
         }
     }
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "end afp_deleteid:");
-#endif /* DEBUG */
-
     return err;
 }
 
@@ -2006,7 +1969,8 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct
     }
     else {
         ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
-        if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
+        /* META and HF */
+        if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
             /* from AFP spec.
              * The user must have the Read & Write privilege for both files in order to use this command.
              */
@@ -2020,10 +1984,7 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct
 
 #define APPLETEMP ".AppleTempXXXXXX"
 
-int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
-AFPObj  *obj;
-char   *ibuf, *rbuf _U_ ;
-int    ibuflen _U_, *rbuflen;
+int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct stat         srcst, destst;
     struct vol         *vol;
@@ -2047,10 +2008,6 @@ int      ibuflen _U_, *rbuflen;
     uid_t              uid;
     gid_t              gid;
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
-#endif /* DEBUG */
-
     *rbuflen = 0;
     ibuf += 2;
 
@@ -2189,10 +2146,10 @@ int     ibuflen _U_, *rbuflen;
     if (did) {
        cnid_delete(vol->v_cdb, did);
     }
-    if ((did && ( (crossdev && stat( upath, &srcst) < 0) || 
+    if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || 
                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
-       (sid && ( (crossdev && stat(p, &destst) < 0) ||
+       (sid && ( (crossdev && lstat(p, &destst) < 0) ||
                 cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0))
     ) {
         switch (errno) {
@@ -2209,12 +2166,12 @@ int     ibuflen _U_, *rbuflen;
     /* here we need to reopen if crossdev */
     if (sid && ad_setid(addp, destst.st_dev, destst.st_ino,  sid, sdir->d_did, vol->v_stamp)) 
     {
-       ad_flush( addp, ADFLAGS_HF );
+       ad_flush( addp );
     }
         
     if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino,  did, curdir->d_did, vol->v_stamp)) 
     {
-       ad_flush( adsp, ADFLAGS_HF );
+       ad_flush( adsp );
     }
 
     /* change perms, src gets dest perm and vice versa */
@@ -2254,10 +2211,6 @@ int      ibuflen _U_, *rbuflen;
         exit(EXITERR_SYS);
     }
 
-#ifdef DEBUG
-    LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
-#endif /* DEBUG */
-
     err = AFP_OK;
     goto err_exchangefile;
 
@@ -2279,10 +2232,10 @@ err_src_to_tmp:
     of_rename(vol, s_of, curdir, temp, sdir, spath);
 
 err_exchangefile:
-    if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
+    if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
        ad_close(adsp, ADFLAGS_HF);
     }
-    if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
+    if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
        ad_close(addp, ADFLAGS_HF);
     }