]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/directory.c
use the right test for file/dir invisible attribute bit modification and parent direc...
[netatalk.git] / etc / afpd / directory.c
index 3bc836c73a2cfdd82114494fd11f1e2d5652acb3..11c6de7ea47142af52964e5d7e6778d0d5a5402e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.122 2010-01-05 12:06:33 franklahm Exp $
+ * $Id: directory.c,v 1.131 2010-01-26 20:39:52 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -62,16 +62,59 @@ char *strchr (), *strrchr ();
 extern void addir_inherit_acl(const struct vol *vol);
 #endif
 
+/* 
+ * Directory caches
+ * ================
+ *
+ * There are currently two cache structures where afpd caches directory information
+ * a) a DID/dirname cache in a hashtable 
+ * b) a (red-black) tree with CNIDs as key
+ *
+ * a) is for searching by DID/dirname
+ * b) is for searching by CNID
+ *
+ * Through additional parent, child, previous and next pointers, b) is also used to
+ * represent the on-disk layout of the filesystem. parent and child point to parent
+ * and child directory respectively, linking 2 or more subdirectories in one
+ * directory with previous and next pointers.
+ *
+ * Usage examples, highlighting the main functions:
+ * 
+ * a) is eg used in enumerate():
+ * if IS_DIR
+ *     dir = dirsearch_byname() // search in cache
+ *     if (dir == NULL)         // not found
+ *         dir = adddir()       // add to cache
+ *      getdirparams()
+ *
+ * b) is eg used in afp_getfildirparams()
+ * dirlookup()             // wrapper for cache and db search
+ *   => dir = dirsearch()  // search in cache
+ *      if (dir)           // found
+ *          return
+ *      else               // not found,
+ *          cnid_resolve() // resolve with CNID database
+ *      cname()            // add to cache
+ */
+
 struct dir  *curdir;
 int             afp_errno;
 
 #define SENTINEL (&sentinel)
-static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
-                               NULL, NULL, NULL, NULL, NULL, 0, 0,
-                               0, 0, NULL, NULL, 0, NULL};
-static struct dir rootpar  = { SENTINEL, SENTINEL, NULL, 0,
-                               NULL, NULL, NULL, NULL, NULL, 0, 0,
-                               0, 0, NULL, NULL, 0, NULL};
+static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
+                               DIRTREE_COLOR_BLACK,      /* color */
+                               NULL, NULL,               /* parent, child */
+                               NULL, NULL,               /* previous, next */
+                               NULL, 0, 0,               /* oforks, did, flags */
+                               0, 0,                     /* ctime, offcnt */
+                               NULL, NULL, NULL};        /* mname, uname, ucs2-name */
+static struct dir rootpar  = { SENTINEL, SENTINEL, NULL,
+                               0,
+                               NULL, NULL,
+                               NULL, NULL,
+                               NULL, 0, 0,
+                               0, 0,
+                               NULL, NULL, NULL};
 
 /* (from IM: Toolbox Essentials)
  * dirFinderInfo (DInfo) fields:
@@ -157,7 +200,6 @@ dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
 
         key.d_parent = cdir;
         key.d_u_name = name;
-        key.d_u_name_len = strlen(name);
         hn = hash_lookup(vol->v_hash, &key);
         if (hn) {
             dir = hnode_get(hn);
@@ -944,13 +986,24 @@ adddir(struct vol *vol, struct dir *dir, struct path *path)
     char        *upath;
     struct stat *st;
     int         deleted;
+    struct adouble  ad;
+    struct adouble *adp = NULL;
     cnid_t      id;
 
     upath = path->u_name;
     st    = &path->st;
     upathlen = strlen(upath);
 
-    id = get_id(vol, NULL, st, dir->d_did, upath, upathlen);
+    /* get_id needs adp for reading CNID from adouble file */
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+    if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
+        adp = &ad;
+
+    id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
+
+    if (adp)
+        ad_close_metadata(adp);
+
     if (id == 0) {
         return NULL;
     }
@@ -1063,7 +1116,6 @@ struct dir *dirnew(const char *m_name, const char *u_name)
         return NULL;
     }
 
-    dir->d_u_name_len = strlen(dir->d_u_name);
     dir->d_m_name_ucs2 = NULL;
     dir->d_left = dir->d_right = SENTINEL;
     dir->d_next = dir->d_prev = dir;
@@ -1111,7 +1163,7 @@ static hash_val_t hash_fun2_dir(const void *key)
 {
     const struct dir *k = key;
     const char *data = k->d_u_name;
-    int len = k->d_u_name_len;
+    int len = strlen(k->d_u_name);
     hash_val_t hash = k->d_parent->d_did, tmp;
 
     int rem = len & 3;
@@ -1645,8 +1697,19 @@ int getdirparams(const struct vol *vol,
                    (1 << DIRPBIT_FINFO)))) {
 
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-        if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) ) {
+        if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
             isad = 1;
+            if (ad.ad_md->adf_flags & O_CREAT) {
+                /* We just created it */
+                ad_setname(&ad, s_path->m_name);
+                ad_setid( &ad,
+                          s_path->st.st_dev,
+                          s_path->st.st_ino,
+                          dir->d_did,
+                          dir->d_parent->d_did,
+                          vol->v_stamp);
+                ad_flush( &ad);
+            }
         }
     }
 
@@ -1962,7 +2025,7 @@ int setdirparams(struct vol *vol,
     int         bit, isad = 1;
     int                 cdate, bdate;
     int                 owner, group;
-    u_int16_t       ashort, bshort;
+    u_int16_t       ashort, bshort, oshort;
     int                 err = AFP_OK;
     int                 change_mdate = 0;
     int                 change_parent_mdate = 0;
@@ -2118,14 +2181,14 @@ int setdirparams(struct vol *vol,
         case DIRPBIT_ATTR :
             if (isad) {
                 ad_getattr(&ad, &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(&ad, bshort);
             }
             break;
@@ -2430,7 +2493,7 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
     }
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-    if (ad_open_metadata( ".", vol_noadouble(vol)|ADFLAGS_DIR, O_CREAT, &ad ) < 0)  {
+    if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0)  {
         if (vol_noadouble(vol))
             goto createdir_done;
         return( AFPERR_ACCESS );
@@ -2615,11 +2678,11 @@ int deletecurdir(struct vol *vol)
         goto delete_done;
     }
 
-    if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
+    err = netatalk_rmdir_all_errors(fdir->d_u_name);
+    if ( err ==  AFP_OK || err == AFPERR_NOOBJ) {
         dirchildremove(curdir, fdir);
         cnid_delete(vol->v_cdb, fdir->d_did);
         dir_remove( vol, fdir );
-        err = AFP_OK;
     }
 delete_done:
     if (dp) {