]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/directory.c
Convert afp_moveandrename and all called funcs to XXXat semantics if available
[netatalk.git] / etc / afpd / directory.c
index fe1b8f4d9218bb2bf14400ad00db9b4658f25c6b..6480ca7f65c83158d770194d2a5f7a3bdea973bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.127 2010-01-10 10:58:24 franklahm Exp $
+ * $Id: directory.c,v 1.140 2010-03-12 15:16:49 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -98,7 +98,7 @@ extern void addir_inherit_acl(const struct vol *vol);
  */
 
 struct dir  *curdir;
-int             afp_errno;
+int         afp_errno;
 
 #define SENTINEL (&sentinel)
 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
@@ -787,7 +787,7 @@ static int netatalk_mkdir(const char *name)
 }
 
 /* ------------------- */
-static int deletedir(char *dir)
+static int deletedir(int dirfd, char *dir)
 {
     char path[MAXPATHLEN + 1];
     DIR *dp;
@@ -801,7 +801,7 @@ static int deletedir(char *dir)
         return AFPERR_PARAM;
 
     /* already gone */
-    if ((dp = opendir(dir)) == NULL)
+    if ((dp = opendirat(dirfd, dir)) == NULL)
         return AFP_OK;
 
     strcpy(path, dir);
@@ -818,13 +818,13 @@ static int deletedir(char *dir)
             break;
         }
         strcpy(path + len, de->d_name);
-        if (stat(path, &st)) {
+        if (lstatat(dirfd, path, &st)) {
             continue;
         }
         if (S_ISDIR(st.st_mode)) {
-            err = deletedir(path);
+            err = deletedir(dirfd, path);
         } else {
-            err = netatalk_unlink(path);
+            err = netatalk_unlinkat(dirfd, path);
         }
     }
     closedir(dp);
@@ -832,13 +832,13 @@ static int deletedir(char *dir)
     /* okay. the directory is empty. delete it. note: we already got rid
        of .AppleDouble.  */
     if (err == AFP_OK) {
-        err = netatalk_rmdir(dir);
+        err = netatalk_rmdir(dirfd, dir);
     }
     return err;
 }
 
 /* do a recursive copy. */
-static int copydir(const struct vol *vol, char *src, char *dst)
+static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
 {
     char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
     DIR *dp;
@@ -852,7 +852,7 @@ static int copydir(const struct vol *vol, char *src, char *dst)
     /* doesn't exist or the path is too long. */
     if (((slen = strlen(src)) > sizeof(spath) - 2) ||
         ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
-        ((dp = opendir(src)) == NULL))
+        ((dp = opendirat(dirfd, src)) == NULL))
         return AFPERR_PARAM;
 
     /* try to create the destination directory */
@@ -884,7 +884,7 @@ static int copydir(const struct vol *vol, char *src, char *dst)
         }
         strcpy(spath + slen, de->d_name);
 
-        if (stat(spath, &st) == 0) {
+        if (lstatat(dirfd, spath, &st) == 0) {
             if (strlen(de->d_name) > drem) {
                 err = AFPERR_PARAM;
                 break;
@@ -892,9 +892,9 @@ static int copydir(const struct vol *vol, char *src, char *dst)
             strcpy(dpath + dlen, de->d_name);
 
             if (S_ISDIR(st.st_mode)) {
-                if (AFP_OK != (err = copydir(vol, spath, dpath)))
+                if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
                     goto copydir_done;
-            } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) {
+            } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
                 goto copydir_done;
 
             } else {
@@ -906,7 +906,7 @@ static int copydir(const struct vol *vol, char *src, char *dst)
     }
 
     /* keep the same time stamp. */
-    if (stat(src, &st) == 0) {
+    if (lstatat(dirfd, src, &st) == 0) {
         ut.actime = ut.modtime = st.st_mtime;
         utime(dst, &ut);
     }
@@ -986,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;
     }
@@ -1111,6 +1122,7 @@ struct dir *dirnew(const char *m_name, const char *u_name)
     return dir;
 }
 
+#if 0
 /* ------------------ */
 static hash_val_t hash_fun_dir(const void *key)
 {
@@ -1136,6 +1148,7 @@ static hash_val_t hash_fun_dir(const void *key)
     }
     return acc;
 }
+#endif
 
 #undef get16bits
 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)    \
@@ -1531,6 +1544,7 @@ int movecwd(struct vol *vol, struct dir *dir)
     struct dir  *d;
     char    *p, *u;
     int     n;
+    int     ret;
 
     if ( dir == curdir ) {
         return( 0 );
@@ -1541,8 +1555,7 @@ int movecwd(struct vol *vol, struct dir *dir)
     }
 
     p = path + sizeof(path) - 1;
-    *p-- = '\0';
-    *p = '.';
+    *p = '\0';
     for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
         u = d->d_u_name;
         if (!u) {
@@ -1569,7 +1582,19 @@ int movecwd(struct vol *vol, struct dir *dir)
         p -= n;
         memcpy( p, vol->v_path, n );
     }
-    if ( chdir( p ) < 0 ) {
+    if ( (ret = lchdir(p )) != 0 ) {
+        LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
+
+        if (ret == 1) {
+            /* p is a symlink or getcwd failed */
+            afp_errno = AFPERR_BADTYPE;
+            vol->v_curdir = curdir = vol->v_dir;
+            if (chdir(vol->v_path ) < 0) {
+                LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
+                /* XXX what do we do here? */
+            }
+            return -1;
+        }
         switch (errno) {
         case EACCES:
         case EPERM:
@@ -1688,6 +1713,17 @@ int getdirparams(const struct vol *vol,
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
         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);
+            }
         }
     }
 
@@ -2003,7 +2039,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;
@@ -2159,14 +2195,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;
@@ -2498,9 +2534,12 @@ createdir_done:
  * dst       new unix filename (not a pathname)
  * newname   new mac name
  * newparent curdir
- *
+ * dirfd     -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
  */
-int renamedir(const struct vol *vol, char *src, char *dst,
+int renamedir(const struct vol *vol,
+              int dirfd,
+              char *src,
+              char *dst,
               struct dir *dir,
               struct dir *newparent,
               char *newname)
@@ -2511,7 +2550,7 @@ int renamedir(const struct vol *vol, char *src, char *dst,
     int         len, err;
 
     /* existence check moved to afp_moveandrename */
-    if ( unix_rename( src, dst ) < 0 ) {
+    if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOOBJ );
@@ -2525,11 +2564,11 @@ int renamedir(const struct vol *vol, char *src, char *dst,
         case EXDEV:
             /* this needs to copy and delete. bleah. that means we have
              * to deal with entire directory hierarchies. */
-            if ((err = copydir(vol, src, dst)) < 0) {
-                deletedir(dst);
+            if ((err = copydir(vol, dirfd, src, dst)) < 0) {
+                deletedir(-1, dst);
                 return err;
             }
-            if ((err = deletedir(src)) < 0)
+            if ((err = deletedir(dirfd, src)) < 0)
                 return err;
             break;
         default :
@@ -2537,7 +2576,7 @@ int renamedir(const struct vol *vol, char *src, char *dst,
         }
     }
 
-    vol->vfs->vfs_renamedir(vol, src, dst);
+    vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
 
     len = strlen( newname );
     /* rename() succeeded so we need to update our tree even if we can't open
@@ -2621,7 +2660,7 @@ int deletecurdir(struct vol *vol)
     if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
 
         ad_getattr(&ad, &ashort);
-        ad_close( &ad, ADFLAGS_HF );
+        ad_close_metadata(&ad);
         if ((ashort & htons(ATTRBIT_NODELETE))) {
             return  AFPERR_OLOCK;
         }
@@ -2656,11 +2695,11 @@ int deletecurdir(struct vol *vol)
         goto delete_done;
     }
 
-    if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
+    err = netatalk_rmdir_all_errors(-1, 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) {