]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/file.c
Merge master
[netatalk.git] / etc / afpd / file.c
index 51a33e8c30ba0bd2e823b856e9f331bd484053d4..0459656f1ed51572135398ef97adfd818470e5fa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: file.c,v 1.141 2010/03/12 15:16:49 franklahm Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
 #include <stdio.h>
 #include <stdlib.h>
 
-/* STDC check */
-#if STDC_HEADERS
 #include <string.h>
-#else /* STDC_HEADERS */
-#ifndef HAVE_STRCHR
-#define strchr index
-#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))
-#endif /* ! HAVE_MEMCPY */
-#endif /* STDC_HEADERS */
-
 #include <utime.h>
 #include <errno.h>
 #include <sys/param.h>
@@ -41,6 +24,7 @@ char *strchr (), *strrchr ();
 #include <atalk/unix.h>
 
 #include "directory.h"
+#include "dircache.h"
 #include "desktop.h"
 #include "volume.h"
 #include "fork.h"
@@ -166,8 +150,8 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t
     else {
         u_int16_t temp;
 
-        if (aint > 255)  /* FIXME safeguard, anyway if no ascii char it's game over*/
-           aint = 255;
+        if (aint > UTF8FILELEN_EARLY)  /* FIXME safeguard, anyway if no ascii char it's game over*/
+           aint = UTF8FILELEN_EARLY;
 
         utf8 = vol->v_kTextEncoding;
         memcpy(data, &utf8, sizeof(utf8));
@@ -201,9 +185,27 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t
                                  (1 << FILPBIT_FNUM) |\
                                  (1 << FILPBIT_UNIXPR)))
 
-/* -------------------------- */
-uint32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
-                const cnid_t did, char *upath, const int len) 
+/*!
+ * @brief Get CNID for did/upath args both from database and adouble file
+ *
+ * 1. Get the objects CNID as stored in its adouble file
+ * 2. Get the objects CNID from the database
+ * 3. If there's a problem with a "dbd" database, fallback to "tdb" in memory
+ * 4. In case 2 and 3 differ, store 3 in the adouble file
+ *
+ * @param vol    (rw) volume
+ * @param adp    (rw) adouble struct of object upath, might be NULL
+ * @param st     (r) stat of upath, must NOT be NULL
+ * @param did    (r) parent CNID of upath
+ * @param upath  (r) name of object
+ * @param len    (r) strlen of upath
+ */
+uint32_t get_id(struct vol *vol,
+                struct adouble *adp, 
+                const struct stat *st,
+                const cnid_t did,
+                const char *upath,
+                const int len) 
 {
     static int first = 1;       /* mark if this func is called the first time */
     u_int32_t adcnid;
@@ -213,9 +215,9 @@ restart:
     if (vol->v_cdb != NULL) {
         /* 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);
+        adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */
 
-           dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid);
+           dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */
            /* Throw errors if cnid_add fails. */
            if (dbcnid == CNID_INVALID) {
             switch (errno) {
@@ -233,7 +235,7 @@ restart:
                 /* we have to do it here for "dbd" because it uses "lazy opening" */
                 /* In order to not end in a loop somehow with goto restart below  */
                 /*  */
-                if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) {
+                if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */
                     cnid_close(vol->v_cdb);
                     free(vol->v_cnidscheme);
                     vol->v_cnidscheme = strdup("tdb");
@@ -267,9 +269,10 @@ restart:
                 goto exit;
             }
         }
-        else if (adp && (adcnid != dbcnid)) {
+        else if (adp && (adcnid != dbcnid)) { /* 4 */
             /* 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));
+            LOG(log_debug, logtype_afpd, "get_id(%s/%s): calling ad_setid(old: %u, new: %u)",
+                getcwdpath(), upath, htonl(adcnid), htonl(dbcnid));
             if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) {
                 ad_flush(adp);
             }
@@ -298,6 +301,8 @@ int getmetadata(struct vol *vol,
     struct stat         *st;
     struct maccess     ma;
 
+    LOG(log_debug, logtype_afpd, "getmetadata(\"%s\")", path->u_name);
+
     upath = path->u_name;
     st = &path->st;
     data = buf;
@@ -308,7 +313,7 @@ int getmetadata(struct vol *vol,
         if (!path->id) {
             struct dir *cachedfile;
             int len = strlen(upath);
-            if (cachedfile = dircache_search_by_name(vol, dir, upath, len))
+            if ((cachedfile = dircache_search_by_name(vol, dir, upath, len, st->st_ctime)) != NULL)
                 id = cachedfile->d_did;
             else {
                 id = get_id(vol, adp, st, dir->d_did, upath, len);
@@ -325,11 +330,12 @@ int getmetadata(struct vol *vol,
                     }
                 }
                 
-                if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL)) == NULL) {
+                if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL, st->st_ctime)) == NULL) {
                     LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
                     exit(EXITERR_SYS);
                 }
-                if ((dircache_add(cachedfile)) != 0) {
+
+                if ((dircache_add(vol, cachedfile)) != 0) {
                     LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
                     exit(EXITERR_SYS);
                 }
@@ -594,17 +600,19 @@ int getfilparams(struct vol *vol,
     int                 opened = 0;
     int rc;    
 
+    LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name);
+
     opened = PARAM_NEED_ADP(bitmap);
     adp = NULL;
 
     if (opened) {
         char *upath;
-        int  flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
+        int  flags = (bitmap & (1 << FILPBIT_ATTR)) ? ADFLAGS_CHECK_OF : 0;
 
         adp = of_ad(vol, path, &ad);
         upath = path->u_name;
 
-        if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) {
+        if ( ad_metadata( upath, flags, adp) < 0 ) {
             switch (errno) {
             case EACCES:
                 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
@@ -621,9 +629,7 @@ int getfilparams(struct vol *vol,
         }
     }
     rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
-    if ( adp ) {
-        ad_close_metadata( adp);
-    }
+    ad_close_metadata( adp);
 
     return( rc );
 }
@@ -631,7 +637,7 @@ int getfilparams(struct vol *vol,
 /* ----------------------------- */
 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct adouble     ad, *adp;
+    struct adouble     ad;
     struct vol         *vol;
     struct dir         *dir;
     struct ofork        *of = NULL;
@@ -647,9 +653,8 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     memcpy(&vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
 
-    if (NULL == ( vol = getvolbyvid( vid )) ) {
+    if (NULL == ( vol = getvolbyvid( vid )) )
         return( AFPERR_PARAM );
-    }
 
     if (vol->v_flags & AFPVOL_RO)
         return AFPERR_VLOCK;
@@ -657,44 +662,35 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     memcpy(&did, ibuf, sizeof( did));
     ibuf += sizeof( did );
 
-    if (NULL == ( dir = dirlookup( vol, did )) ) {
+    if (NULL == ( dir = dirlookup( vol, did )) )
         return afp_errno;
-    }
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) )
         return get_afp_errno(AFPERR_PARAM);
-    }
 
-    if ( *s_path->m_name == '\0' ) {
+    if ( *s_path->m_name == '\0' )
         return( AFPERR_BADTYPE );
-    }
 
     upath = s_path->u_name;
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     
     /* if upath is deleted we already in trouble anyway */
     if ((of = of_findname(s_path))) {
-        adp = of->of_ad;
-    } else {
-        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-        adp = &ad;
-    }
-    if ( creatf) {
-        /* on a hard create, fail if file exists and is open */
-        if (of)
+        if (creatf)
             return AFPERR_BUSY;
+        else
+            return AFPERR_EXIST;
+    }
+
+    if ( creatf)
         openf = O_RDWR|O_CREAT|O_TRUNC;
-    } else {
+    else
        /* on a soft create, if the file is open then ad_open won't fail
-          because open syscall is not called
-       */
-       if (of) {
-               return AFPERR_EXIST;
-       }
+          because open syscall is not called */
         openf = O_RDWR|O_CREAT|O_EXCL;
-    }
 
-    if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
-                  openf, 0666, adp) < 0 ) {
+    if ( ad_open(&ad, upath, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF,
+                 openf, 0666, openf, 0666) < 0 ) {
         switch ( errno ) {
         case EROFS:
             return AFPERR_VLOCK;
@@ -711,34 +707,39 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
             return( AFPERR_PARAM );
         }
     }
-    if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
+    if ( ad_meta_fileno( &ad ) == -1 ) { /* Hard META / HF */
          /* on noadouble volumes, just creating the data fork is ok */
          if (vol_noadouble(vol)) {
-             ad_close( adp, ADFLAGS_DF );
+             ad_close( &ad, ADFLAGS_DF );
              goto createfile_done;
          }
          /* FIXME with hard create on an existing file, we already
           * corrupted the data file.
           */
          netatalk_unlink( upath );
-         ad_close( adp, ADFLAGS_DF );
+         ad_close( &ad, ADFLAGS_DF );
          return AFPERR_ACCESS;
     }
 
     path = s_path->m_name;
-    ad_setname(adp, path);
-    ad_flush( adp);
-    ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
+    ad_setname(&ad, path);
+
+    struct stat st;
+    if (lstat(upath, &st) != 0) {
+        LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): stat: %s",
+            upath, strerror(errno));
+        ad_close( adp, ADFLAGS_DF|ADFLAGS_HF);
+        return AFPERR_MISC;
+    }
+
+    (void)get_id(vol, adp, &st, dir->d_did, upath, strlen(upath));
+
+    ad_flush(&ad);
+    ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
 
 createfile_done:
     curdir->offcnt++;
 
-#ifdef DROPKLUDGE
-    if (vol->v_flags & AFPVOL_DROPBOX) {
-        retvalue = matchfile2dirperms(upath, vol, did);
-    }
-#endif /* DROPKLUDGE */
-
     setvoltime(obj, vol );
 
     return (retvalue);
@@ -953,7 +954,7 @@ int setfilparams(struct vol *vol,
 
     /* second try with adouble open 
     */
-    if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
+    if ( ad_open(adp, upath, ADFLAGS_HF, O_RDWR | O_CREAT, 0666) < 0) {
         LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
         /*
          * For some things, we don't need an adouble header:
@@ -966,7 +967,7 @@ int setfilparams(struct vol *vol,
         }
         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) ) {
+    } else if ((ad_get_MD_flags( adp ) & O_CREAT) ) {
         ad_setname(adp, path->m_name);
     }
     
@@ -1047,7 +1048,6 @@ setfilparam_done:
     if (isad) {
         ad_flush( adp);
         ad_close_metadata( adp);
-
     }
 
     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
@@ -1078,6 +1078,9 @@ int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *n
 {
     int                rc;
 
+    LOG(log_debug, logtype_afpd,
+        "renamefile: src[%d, \"%s\"] -> dst[\"%s\"]", sdir_fd, src, dst);
+
     if ( unix_rename( sdir_fd, src, -1, dst ) < 0 ) {
         switch ( errno ) {
         case ENOENT :
@@ -1130,9 +1133,8 @@ int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *n
         }
     }
 
-    /* don't care if we can't open the newly renamed ressource fork
-     */
-    if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
+    /* don't care if we can't open the newly renamed ressource fork */
+    if (ad_open(adp, dst, ADFLAGS_HF, O_RDWR) == 0) {
         ad_setname(adp, newname);
         ad_flush( adp );
         ad_close( adp, ADFLAGS_HF );
@@ -1260,11 +1262,11 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
 
     adp = of_ad(s_vol, s_path, &ad);
 
-    if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+    if (ad_open(adp, s_path->u_name, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, O_RDONLY) < 0) {
         return AFPERR_DENYCONF;
     }
-    denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
-                  getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
+    denyreadset = (ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
+                  ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
 
     if (denyreadset) {
         retvalue = AFPERR_DENYCONF;
@@ -1280,9 +1282,6 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
         goto copy_exit;
     }
 
-#ifdef FORCE_UIDGID
-    /* FIXME svid != dvid && dvid's user can't read svid */
-#endif
     if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
         retvalue = AFPERR_PARAM;
         goto copy_exit;
@@ -1327,12 +1326,6 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
     }
     curdir->offcnt++;
 
-#ifdef DROPKLUDGE
-    if (vol->v_flags & AFPVOL_DROPBOX) {
-        retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
-    }
-#endif /* DROPKLUDGE */
-
     setvoltime(obj, d_vol );
 
 copy_exit:
@@ -1471,7 +1464,7 @@ int copyfile(const struct vol *s_vol,
         adflags |= ADFLAGS_HF;
     }
 
-    if (ad_openat(sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+    if (ad_openat(adp, sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, O_RDONLY) < 0) {
         ret_err = errno;
         goto done;
     }
@@ -1489,7 +1482,7 @@ int copyfile(const struct vol *s_vol,
     }
 
     ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
-    if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
+    if (ad_open(&add, dst, adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, O_RDWR|O_CREAT|O_EXCL, st.st_mode) < 0) {
         ret_err = errno;
         ad_close( adp, adflags );
         if (EEXIST != ret_err) {
@@ -1604,7 +1597,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
          * moreover sometimes deletefile is called with a no existent file and 
          * ad_open would create a 0 byte resource fork
         */
-        if ( ad_metadataat(dirfd, file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
+        if ( ad_metadataat(dirfd, file, ADFLAGS_CHECK_OF, &ad) == 0 ) {
             if ((err = check_attrib(&ad))) {
                ad_close_metadata(&ad);
                return err;
@@ -1615,7 +1608,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
  
     /* try to open both forks at once */
     adflags = ADFLAGS_DF;
-    if ( ad_openat(dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) {
+    if ( ad_openat(&ad, dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, O_RDONLY) < 0 ) {
         switch (errno) {
         case ENOENT:
             err = AFPERR_NOOBJ;
@@ -1758,32 +1751,12 @@ 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 ( lstat(de->d_name, &path.st) < 0 )
         return 0;
     
     /* update or add to cnid */
     aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
 
-#if AD_VERSION > AD_VERSION1
-    if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
-        struct adouble  ad, *adp;
-
-        path.st_errno = 0;
-        path.st_valid = 1;
-        path.u_name = de->d_name;
-            
-        adp = of_ad(vol, &path, &ad);
-            
-        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);
-        }
-        ad_close_metadata(adp);
-    }
-#endif /* AD_VERSION > AD_VERSION1 */
-
     return 0;
 }
 
@@ -2045,7 +2018,7 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct
         adp = (*of)->of_ad;
     }
     else {
-        ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
+        ret = ad_open(adp, path->u_name, ADFLAGS_HF, O_RDONLY);
         /* META and HF */
         if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
             /* from AFP spec.
@@ -2217,12 +2190,11 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     /* id's need switching. src -> dest and dest -> src. 
      * we need to re-stat() if it was a cross device copy.
     */
-    if (sid) {
-       cnid_delete(vol->v_cdb, sid);
-    }
-    if (did) {
-       cnid_delete(vol->v_cdb, did);
-    }
+    if (sid)
+        cnid_delete(vol->v_cdb, sid);
+    if (did)
+        cnid_delete(vol->v_cdb, did);
+
     if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || 
                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
@@ -2316,5 +2288,11 @@ err_exchangefile:
        ad_close(addp, ADFLAGS_HF);
     }
 
+    struct dir *cached;
+    if ((cached = dircache_search_by_did(vol, sid)) != NULL)
+        (void)dir_remove(vol, cached);
+    if ((cached = dircache_search_by_did(vol, did)) != NULL)
+        (void)dir_remove(vol, cached);
+
     return err;
 }