]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/file.c
Merge branch-2-1
[netatalk.git] / etc / afpd / file.c
index aa692842ed4a5c8d919080336292528d33dbcbd2..d3bf5600b36e1f68c91a15d3b1fadfe2eaa73f71 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.
  */
@@ -41,6 +39,7 @@ char *strchr (), *strrchr ();
 #include <atalk/unix.h>
 
 #include "directory.h"
+#include "dircache.h"
 #include "desktop.h"
 #include "volume.h"
 #include "fork.h"
@@ -201,19 +200,39 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t
                                  (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) 
+/*!
+ * @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;
     u_int32_t dbcnid = CNID_INVALID;
 
+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) {
@@ -222,23 +241,61 @@ u_int32_t get_id(struct vol *vol, struct adouble *adp,  const struct stat *st,
             case CNID_ERR_PARAM:
                 LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
                 afp_errno = AFPERR_PARAM;
-                return CNID_INVALID;
+                goto exit;
             case CNID_ERR_PATH:
                 afp_errno = AFPERR_PARAM;
-                return CNID_INVALID;
+                goto exit;
             default:
+                /* Close CNID backend if "dbd" and switch to temp in-memory "tdb" */
+                /* 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)) { /* (3) */
+                    cnid_close(vol->v_cdb);
+                    free(vol->v_cnidscheme);
+                    vol->v_cnidscheme = strdup("tdb");
+
+                    int flags = CNID_FLAG_MEMORY;
+                    if ((vol->v_flags & AFPVOL_NODEV)) {
+                        flags |= CNID_FLAG_NODEV;
+                    }
+                    LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
+                        vol->v_path);
+                    vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL);
+                    if (vol->v_cdb) {
+                        /* deactivate cnid caching/storing in AppleDouble files and set ro mode*/
+                        vol->v_flags &= ~AFPVOL_CACHE;
+                        vol->v_flags |= AFPVOL_RO;
+#ifdef SERVERTEXT
+                        /* kill ourself with SIGUSR2 aka msg pending */
+                        setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead."
+                                   "Check server messages for details. Switching to read-only mode.");
+                        kill(getpid(), SIGUSR2);
+#endif
+                        goto restart; /* not try again with the temp CNID db */
+                    } else {
+#ifdef SERVERTEXT
+                        setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB failed too!"
+                                   "Check server messages for details, can't recover from this state!");
+#endif
+                    }
+                }
                 afp_errno = AFPERR_MISC;
-                return CNID_INVALID;
+                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);
             }
         }
     }
+
+exit:
+    first = 0;
     return dbcnid;
 }
              
@@ -259,24 +316,50 @@ int getmetadata(struct vol *vol,
     struct stat         *st;
     struct maccess     ma;
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "begin getmetadata:");
-#endif /* DEBUG */
-
     upath = path->u_name;
     st = &path->st;
-
     data = buf;
 
     if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
          || (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
          || (bitmap & (1 << FILPBIT_FNUM))) {
-        if (!path->id)
-            id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
-        else 
+        if (!path->id) {
+            struct dir *cachedfile;
+            int len = strlen(upath);
+            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);
+
+                /* Add it to the cache */
+                LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u",
+                    ntohl(dir->d_did), upath, ntohl(id));
+
+                /* Get macname from unixname first */
+                if (path->m_name == NULL) {
+                    if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) {
+                        LOG(log_error, logtype_afpd, "getmetadata: utompath error");
+                        exit(EXITERR_SYS);
+                    }
+                }
+                
+                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) {
+                    LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
+                    exit(EXITERR_SYS);
+                }
+            }
+        } else {
             id = path->id;
+        }
+
         if (id == CNID_INVALID)
             return afp_errno;
+
         if (!path->m_name) {
             path->m_name = utompath(vol, upath, id, utf8_encoding());
         }
@@ -309,11 +392,15 @@ int getmetadata(struct vol *vol,
 #endif
             memcpy(data, &ashort, sizeof( ashort ));
             data += sizeof( ashort );
+            LOG(log_debug, logtype_afpd, "metadata('%s'): AFP Attributes: %04x",
+                path->u_name, ntohs(ashort));
             break;
 
         case FILPBIT_PDID :
             memcpy(data, &dir->d_did, sizeof( u_int32_t ));
             data += sizeof( u_int32_t );
+            LOG(log_debug, logtype_afpd, "metadata('%s'):     Parent DID: %u",
+                path->u_name, ntohl(dir->d_did));
             break;
 
         case FILPBIT_CDATE :
@@ -360,6 +447,8 @@ int getmetadata(struct vol *vol,
         case FILPBIT_FNUM :
             memcpy(data, &id, sizeof( id ));
             data += sizeof( id );
+            LOG(log_debug, logtype_afpd, "metadata('%s'):           CNID: %u",
+                path->u_name, ntohl(id));
             break;
 
         case FILPBIT_DFLEN :
@@ -524,10 +613,6 @@ int getfilparams(struct vol *vol,
     int                 opened = 0;
     int rc;    
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_default, "begin getfilparams:");
-#endif /* DEBUG */
-
     opened = PARAM_NEED_ADP(bitmap);
     adp = NULL;
 
@@ -558,9 +643,6 @@ int getfilparams(struct vol *vol,
     if ( adp ) {
         ad_close_metadata( adp);
     }
-#ifdef DEBUG
-    LOG(log_debug9, logtype_afpd, "end getfilparams:");
-#endif /* DEBUG */
 
     return( rc );
 }
@@ -1906,6 +1988,10 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
     }
 
     if (NULL == ( dir = dirlookup( vol, id )) ) {
+        if (afp_errno == AFPERR_NOOBJ) {
+            err = AFPERR_NOOBJ;
+            goto delete;
+        }
         return( AFPERR_PARAM );
     }
 
@@ -1929,6 +2015,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
     else if (S_ISDIR(st.st_mode)) /* directories are bad */
         return AFPERR_BADTYPE;
 
+delete:
     if (cnid_delete(vol->v_cdb, fileid)) {
         switch (errno) {
         case EROFS:
@@ -2149,12 +2236,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))
        ||
@@ -2248,5 +2334,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;
 }