]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/file.c
always test file open modes.
[netatalk.git] / etc / afpd / file.c
index 55d77df54c180fd9009c580f55d25c72eec21513..26015e3d2d44f473c31387e00f2cb3384507c6a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.92.2.2.2.5 2003-10-17 00:48:56 bfernhomberg Exp $
+ * $Id: file.c,v 1.92.2.2.2.15 2004-02-29 22:18:24 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -11,9 +11,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
 
 /* STDC check */
 #if STDC_HEADERS
@@ -24,6 +21,7 @@
 #define strrchr index
 #endif /* HAVE_STRCHR */
 char *strchr (), *strrchr ();
+
 #ifndef HAVE_MEMCPY
 #define memcpy(d,s,n) bcopy ((s), (d), (n))
 #define memmove(d,s,n) bcopy ((s), (d), (n))
@@ -31,21 +29,14 @@ char *strchr (), *strrchr ();
 #endif /* STDC_HEADERS */
 
 #include <utime.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
 #include <dirent.h>
-#include <sys/mman.h>
 #include <errno.h>
 
 #include <atalk/logger.h>
-#include <sys/types.h>
-#include <sys/time.h>
 #include <sys/param.h>
-#include <sys/stat.h>
 
-#include <netatalk/endian.h>
 #include <atalk/adouble.h>
+
 #include <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/cnid.h>
@@ -101,7 +92,7 @@ void *get_finderinfo(const char *mpath, struct adouble *adp, void *data)
                && (em = getextmap( mpath ))
     ) {
         memcpy(data, em->em_type, sizeof( em->em_type ));
-        memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
+        memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator));
     }
     return data;
 }
@@ -142,7 +133,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 = htonl(vol->v_mac->kTextEncoding);         /* htonl(utf8) */
+        utf8 = vol->v_mac?htonl(vol->v_mac->kTextEncoding):0;         /* htonl(utf8) */
         memcpy(data, &utf8, sizeof(utf8));
         data += sizeof(utf8);
         
@@ -181,6 +172,7 @@ u_int32_t aint = 0;
 #if AD_VERSION > AD_VERSION1
 dev_t  dev;
 ino_t  ino;
+cnid_t a_did;
 char   stamp[ADEDLEN_PRIVSYN];
     /* look in AD v2 header 
      * note inode and device are opaques and not in network order
@@ -191,10 +183,17 @@ char   stamp[ADEDLEN_PRIVSYN];
             memcpy(&ino, ad_entry(adp, ADEID_PRIVINO), sizeof(ino_t));
             if (sizeof(stamp) == ad_getentrylen(adp,ADEID_PRIVSYN)) {
                 memcpy(stamp, ad_entry(adp, ADEID_PRIVSYN), sizeof(stamp));
-
-                if (dev == st->st_dev && ino == st->st_ino && !memcmp(vol->v_stamp, stamp, sizeof(stamp))) {
-                    memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
-                    return aint;
+                if (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_DID)) {
+                    memcpy(&a_did, ad_entry(adp, ADEID_DID), sizeof(cnid_t));
+
+                    if (   ((vol->v_flags & AFPVOL_NODEV) || dev == st->st_dev)
+                           && ino == st->st_ino && a_did == did &&
+                           !memcmp(vol->v_stamp, stamp, sizeof(stamp)) &&
+                          (sizeof(cnid_t) == ad_getentrylen(adp, ADEID_PRIVID)) ) 
+                    { 
+                        memcpy(&aint, ad_entry(adp, ADEID_PRIVID), sizeof(aint));
+                        return aint;
+                    } 
                 }
             }
         }
@@ -224,7 +223,7 @@ char   stamp[ADEDLEN_PRIVSYN];
             /* update the ressource fork
              * for a folder adp is always null
              */
-            ad_setid(adp, st, aint, vol->v_stamp);
+            ad_setid(adp,(vol->v_flags & AFPVOL_NODEV)?0:st->st_dev, st->st_ino, aint, did, vol->v_stamp);
             ad_flush(adp, ADFLAGS_HF);
         }
 #endif    
@@ -538,8 +537,12 @@ int getfilparams(struct vol *vol,
            */
            if ((bitmap & (1 << FILPBIT_ATTR))) {
                 if (!(attrbits & ATTRBIT_ROPEN)) {
+                    attribs | = ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) ? ATTRBIT_ROPEN : 0;
+                    attribs | = ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) ? ATTRBIT_ROPEN : 0;
                 }
                 if (!(attrbits & ATTRBIT_DOPEN)) {
+                    attribs | = ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) ? ATTRBIT_DOPEN : 0;
+                    attribs | = ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) ? ATTRBIT_DOPEN : 0;
                 }
            }
        }
@@ -862,6 +865,19 @@ int setfilparams(struct vol *vol,
             buf += 32;
             break;
 
+        case FILPBIT_UNIXPR :
+           /* Skip the UIG/GID, no way to set them from OSX clients */
+            buf += sizeof( aint );
+            buf += sizeof( aint );
+
+            change_mdate = 1;
+            change_parent_mdate = 1;
+            memcpy( &aint, buf, sizeof( aint ));
+            buf += sizeof( aint );
+            aint = ntohl (aint);
+
+            setfilemode(path, aint);
+            break;
             /* Client needs to set the ProDOS file info for this file.
                Use a defined string for TEXT to support crlf
                translations and convert all else into pXYY per Inside
@@ -887,19 +903,6 @@ int setfilparams(struct vol *vol,
                 break;
             }
             /* fallthrough */
-        case FILPBIT_UNIXPR :
-           /* Skip the UIG/GID, no way to set them from OSX clients */
-            buf += sizeof( aint );
-            buf += sizeof( aint );
-
-            change_mdate = 1;
-            change_parent_mdate = 1;
-            memcpy( &aint, buf, sizeof( aint ));
-            buf += sizeof( aint );
-            aint = ntohl (aint);
-
-            setfilemode(path, aint);
-            break;
         default :
             err = AFPERR_BITMAP;
             goto setfilparam_done;
@@ -1322,6 +1325,7 @@ const int   noadouble;
     struct adouble     ads, add;
     int                        len, err = AFP_OK;
     int                 adflags;
+    struct stat         st;
     
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "begin copyfile:");
@@ -1367,6 +1371,29 @@ const int   noadouble;
        err = copy_fd(ad_dfileno(&add), ad_dfileno(&ads));
     }
 
+    /* Now, reopen destination file */
+    err = AFP_OK;
+    if (ad_close( &add, adflags ) <0) {
+       deletefile(NULL, dst, 0);
+        return AFPERR_PARAM;  /* FIXME */
+    } else {
+       ad_init(&add, 0);
+       if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
+           ad_close( &ads, adflags );
+           deletefile(NULL, dst, 0);
+           switch ( err ) {
+           case ENOENT :
+               return( AFPERR_NOOBJ );
+           case EACCES :
+               return( AFPERR_ACCESS );
+           case EROFS:
+               return AFPERR_VLOCK;
+           default :
+               return( AFPERR_PARAM );
+           }
+       }
+    }
+
     if (newname) {
         len = strlen( newname );
         ad_setentrylen( &add, ADEID_NAME, len );
@@ -1390,6 +1417,14 @@ const int   noadouble;
         }
     }
 
+    /* set dest modification date to src date */
+    if (!stat(src, &st)) {
+        struct utimbuf ut;
+
+       ut.actime = ut.modtime = st.st_mtime;
+       utime(dst, &ut);
+    }
+
 #ifdef DEBUG
     LOG(log_info, logtype_afpd, "end copyfile:");
 #endif /* DEBUG */
@@ -1578,6 +1613,55 @@ int              ibuflen, *rbuflen;
     return afp_errno;
 }
 
+static int
+reenumerate_id(const struct vol *vol, char *name, cnid_t did)
+{
+    DIR             *dp;
+    struct dirent   *de;
+    int             ret;
+    struct stat     st;
+    cnid_t         aint;
+    struct adouble  ad;
+       
+
+    if (vol->v_cdb == NULL) {
+       return -1;
+    }
+    if (NULL == ( dp = opendir( name)) ) {
+        return -1;
+    }
+    ret = 0;
+    for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
+        if (NULL == check_dirent(vol, de->d_name))
+            continue;
+
+        if ( stat(de->d_name, &st)<0 )
+            continue;
+       
+       /* update or add to cnid */
+        aint = cnid_add(vol->v_cdb, &st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
+
+#if AD_VERSION > AD_VERSION1
+        if (aint != CNID_INVALID && !S_ISDIR(st.st_mode)) {
+            ad_init(&ad, 0);  /* OK */
+            if ( ad_open( de->d_name, ADFLAGS_HF, O_RDWR, 0, &ad ) < 0 ) {
+                continue;
+            }
+            else {
+                ad_setid(&ad,(vol->v_flags & AFPVOL_NODEV)?0:st.st_dev, st.st_ino, aint, did, vol->v_stamp);
+                ad_flush(&ad, ADFLAGS_HF);
+                ad_close(&ad, ADFLAGS_HF);
+           }
+        }
+#endif /* AD_VERSION > AD_VERSION1 */
+
+        ret++;
+    }
+    closedir(dp);
+    return ret;
+}
+
+    
 /* ------------------------------
    resolve a file id */
 int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
@@ -1589,7 +1673,7 @@ int               ibuflen, *rbuflen;
     struct dir         *dir;
     char               *upath;
     struct path         path;
-    int                 err, buflen;
+    int                 err, buflen, retry=0;
     cnid_t             id, cnid;
     u_int16_t          vid, bitmap;
 
@@ -1618,6 +1702,7 @@ int               ibuflen, *rbuflen;
     ibuf += sizeof(id);
     cnid = id;
 
+retry:
     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) {
         return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
     }
@@ -1626,7 +1711,7 @@ int               ibuflen, *rbuflen;
         return AFPERR_NOID; /* idem AFPERR_PARAM */
     }
     path.u_name = upath;
-    if (movecwd(vol, dir) < 0 || of_stat(&path) < 0) {
+    if (movecwd(vol, dir) < 0) {
         switch (errno) {
         case EACCES:
         case EPERM:
@@ -1637,6 +1722,26 @@ int              ibuflen, *rbuflen;
             return AFPERR_PARAM;
         }
     }
+
+    if ( of_stat(&path) < 0 ) {
+       if ( errno == ENOENT && !retry) {
+           /* cnid db is out of sync, reenumerate the directory and updated ids */
+           reenumerate_id(vol, ".", id);
+           id = cnid;
+           retry = 1;
+           goto retry;
+        }
+        switch (errno) {
+        case EACCES:
+        case EPERM:
+            return AFPERR_ACCESS;
+        case ENOENT:
+            return AFPERR_NOID;
+        default:
+            return AFPERR_PARAM;
+        }
+    }
+
     /* directories are bad */
     if (S_ISDIR(path.st.st_mode))
         return AFPERR_BADTYPE;