]> arthur.barton.de Git - netatalk.git/commitdiff
Use own ftw func in ad cp
authorFrank Lahm <franklahm@googlemail.com>
Tue, 5 Oct 2010 20:39:38 +0000 (22:39 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Tue, 5 Oct 2010 20:39:38 +0000 (22:39 +0200)
14 files changed:
bin/cnid/Makefile.am
bin/cnid/ad.c
bin/cnid/ad.h
bin/cnid/ad_cp.c
bin/cnid/ad_ls.c
bin/cnid/ad_util.c
include/atalk/Makefile.am
include/atalk/ftw.h [new file with mode: 0644]
include/atalk/queue.h
include/atalk/volinfo.h
libatalk/util/Makefile.am
libatalk/util/ftw.c [new file with mode: 0644]
libatalk/util/queue.c
libatalk/util/volinfo.c

index 3aa59e933c9dc53f240a87ca9bbf3a91a6b2523a..0de86aa96e8a66623177c3fd94996ce60ad378e8 100644 (file)
@@ -11,5 +11,9 @@ ad_SOURCES = ad.c ad_util.c \
        ad_ls.c \
        ad_cp.c
 
-ad_LDADD = $(top_builddir)/libatalk/libatalk.la
+ad_LDADD = \
+       $(top_builddir)/libatalk/cnid/libcnid.la \
+       $(top_builddir)/libatalk/libatalk.la \
+       @ACL_LIBS@
+
 endif
index 391a8465e180135027dc28af7a401f0bc8c32de1..e272f5b93499e94a01cfafc1f1e521b9ac8012c3 100644 (file)
@@ -41,7 +41,7 @@ static void usage_main(void)
 
 int main(int argc, char **argv)
 {
-    setuplog("default log_info /dev/tty");
+    setuplog("default log_note /dev/tty");
 
     if (argc < 2) {
         usage_main();
index 0f2c4ea3f96e0ae7b5b4e2481765290239a7ed2b..fe26bc515170dc7e74ba4e9b58305fe3433bc507 100644 (file)
@@ -20,8 +20,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <signal.h>
-#include <ftw.h>
 
+#include <atalk/ftw.h>
 #include <atalk/volinfo.h>
 
 #define STRCMP(a,b,c) (strcmp(a,c) b 0)
 #define DIR_DOT_OR_DOTDOT(a) \
         ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
 
-typedef struct {
-    struct volinfo volinfo;
-//    char *dirname;
-//    char *basename;
-//    int adflags;                /* file:0, dir:ADFLAGS_DIR */
-} afpvol_t;
-
 enum logtype {STD, DBG};
 
 #define SLOG(...)                             \
@@ -47,15 +40,26 @@ enum logtype {STD, DBG};
         exit(1);                                \
     } while (0)
 
+typedef struct {
+    struct volinfo volinfo;
+//    char *basename;
+} afpvol_t;
+
 extern int log_verbose;             /* Logging flag */
 extern void _log(enum logtype lt, char *fmt, ...);
 
-extern int newvol(const char *path, afpvol_t *vol);
-extern void freevol(afpvol_t *vol);
+extern struct volinfo svolinfo, dvolinfo;
+extern struct vol svolume, dvolume;
 
 extern int ad_ls(int argc, char **argv);
 extern int ad_cp(int argc, char **argv);
 
+/* ad_util.c */
+extern int newvol(const char *path, afpvol_t *vol);
+extern void freevol(afpvol_t *vol);
+extern cnid_t get_parent_cnid_for_path(const struct volinfo *vi, const struct vol *vol, const char *path);
+extern char *utompath(const struct volinfo *volinfo, char *upath);
+
 struct FTWELEM {
     const struct FTW  *ftw;
     const char        *ftw_path;
@@ -74,7 +78,7 @@ extern PATH_T to;
 extern int fflag, iflag, lflag, nflag, pflag, vflag;
 extern volatile sig_atomic_t info;
 
-extern int copy_file(const struct FTW *, const char *, const struct stat *, int);
+extern int ftw_copy_file(const struct FTW *, const char *, const struct stat *, int);
 extern int copy_link(const struct FTW *, const char *, const struct stat *, int);
 extern int setfile(const struct stat *, int);
 extern int preserve_dir_acls(const struct stat *, char *, char *);
index 10351467ecfaca571fdcbefea02bdb1cf1aa625e..91cb762bbc78851f53a607592e9dd7c3772a4ffb 100644 (file)
@@ -52,9 +52,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-// #include <err.h>
 #include <errno.h>
-#include <ftw.h>
 #include <limits.h>
 #include <signal.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
+#include <atalk/ftw.h>
+#include <atalk/adouble.h>
+#include <atalk/vfs.h>
 #include <atalk/util.h>
+#include <atalk/unix.h>
+#include <atalk/volume.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/queue.h>
 
 #include "ad.h"
 
@@ -77,10 +84,16 @@ PATH_T to = { to.p_path, emptystring, "" };
 
 int fflag, iflag, lflag, nflag, pflag, vflag;
 mode_t mask;
-static int Rflag, rflag;
+struct volinfo svolinfo, dvolinfo;
+struct vol svolume, dvolume;
+cnid_t did = 0; /* current dir CNID */
+
+static enum op type;
+static int Rflag;
 volatile sig_atomic_t sigint;
-static int type, badcp, rval;
-static int ftw_options = FTW_MOUNT | FTW_PHYS;
+static int badcp, rval;
+static int ftw_options = FTW_MOUNT | FTW_PHYS | FTW_ACTIONRETVAL;
+static q_t *cnidq;              /* CNID dir stack */
 
 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
 
@@ -94,7 +107,6 @@ static char           *netatalk_dirs[] = {
 static int copy(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf);
 static void siginfo(int _U_);
 
-
 /*
   Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
   Returns pointer to name or NULL.
@@ -114,34 +126,39 @@ static const char *check_netatalk_dirs(const char *name)
 static void usage_cp(void)
 {
     printf(
-        "Usage: ad cp [-R [-L | -P]] [-pvf] <source_file> <target_file>\n"
-        "Usage: ad cp [-R [-L | -P]] [-pvf] <source_file [source_file ...]> <target_directory>\n"
+        "Usage: ad cp [-R [-P]] [-pvf] <source_file> <target_file>\n"
+        "Usage: ad cp [-R [-P]] [-pvfx] <source_file [source_file ...]> <target_directory>\n"
         );
+    exit(EXIT_FAILURE);
+}
+
+static void upfunc(void)
+{
+    if (cnidq) {
+        cnid_t *cnid = dequeue(cnidq);
+        if (cnid) {
+            did = *cnid;
+            free(cnid);
+        }
+    }
 }
 
 int ad_cp(int argc, char *argv[])
 {
     struct stat to_stat, tmp_stat;
-    enum op type;
-    int Pflag, ch, r, have_trailing_slash;
+    int r, ch, have_trailing_slash;
     char *target;
 #if 0
     afpvol_t srcvol;
     afpvol_t dstvol;
 #endif
 
-    Pflag = 0;
-
-    while ((ch = getopt(argc, argv, "PRafilnprvx")) != -1)
+    while ((ch = getopt(argc, argv, "Rafilnpvx")) != -1)
         switch (ch) {
-        case 'P':
-            Pflag = 1;
-            break;
         case 'R':
             Rflag = 1;
             break;
         case 'a':
-            Pflag = 1;
             pflag = 1;
             Rflag = 1;
             break;
@@ -163,10 +180,6 @@ int ad_cp(int argc, char *argv[])
         case 'p':
             pflag = 1;
             break;
-        case 'r':
-            rflag = 1;
-            Pflag = 0;
-            break;
         case 'v':
             vflag = 1;
             break;
@@ -183,14 +196,10 @@ int ad_cp(int argc, char *argv[])
     if (argc < 2)
         usage_cp();
 
-    if (Rflag && rflag)
-        ERROR("the -R and -r options may not be specified together");
-
-    if (rflag)
-        Rflag = 1;
-
     (void)signal(SIGINT, siginfo);
 
+    cnid_init();
+
     /* Save the target base in "to". */
     target = argv[--argc];
     if ((strlcpy(to.p_path, target, PATH_MAX)) >= PATH_MAX)
@@ -206,7 +215,7 @@ int ad_cp(int argc, char *argv[])
         STRIP_TRAILING_SLASH(to);
     to.target_end = to.p_end;
 
-    /* Set end of argument list for fts(3). */
+    /* Set end of argument list */
     argv[argc] = NULL;
 
     /*
@@ -269,13 +278,77 @@ int ad_cp(int argc, char *argv[])
     mask = ~umask(0777);
     umask(~mask);
 
+#if 0
+    /* Inhereting perms in ad_mkdir etc requires this */
+    ad_setfuid(0);
+#endif
+
+    /* Load .volinfo file for destination*/
+    if (loadvolinfo(to.p_path, &dvolinfo) == 0) {
+        if (vol_load_charsets(&dvolinfo) == -1)
+            ERROR("Error loading charsets!");
+        /* Sanity checks to ensure we can touch this volume */
+        if (dvolinfo.v_vfs_ea != AFPVOL_EA_SYS)
+            ERROR("Unsupported Extended Attributes option: %u", dvolinfo.v_vfs_ea);
+
+        /* initialize sufficient struct vol and initialize CNID connection */
+        dvolume.v_adouble = AD_VERSION2;
+        dvolume.v_vfs_ea = AFPVOL_EA_SYS;
+        initvol_vfs(&dvolume);
+        int flags = 0;
+        if ((dvolinfo.v_flags & AFPVOL_NODEV))
+            flags |= CNID_FLAG_NODEV;
+
+        if ((dvolume.v_cdb = cnid_open(dvolinfo.v_path,
+                                       0000,
+                                       "dbd",
+                                       flags,
+                                       dvolinfo.v_dbd_host,
+                                       dvolinfo.v_dbd_port)) == NULL)
+            ERROR("Cant initialize CNID database connection for %s", dvolinfo.v_path);
+
+        /* setup a list for storing the CNID stack of dirs in destination path */
+        if ((cnidq = queue_init()) == NULL)
+            ERROR("Cant initialize CNID stack");
+    }
+
     for (int i = 0; argv[i] != NULL; i++) { 
-        if (nftw(argv[i], copy, 20, ftw_options) == -1) {
-            ERROR("nftw: %s", strerror(errno));
+        /* Load .volinfo file for source */
+        if (loadvolinfo(to.p_path, &svolinfo) == 0) {
+            if (vol_load_charsets(&svolinfo) == -1)
+                ERROR("Error loading charsets!");
+            /* Sanity checks to ensure we can touch this volume */
+            if (svolinfo.v_vfs_ea != AFPVOL_EA_SYS)
+                ERROR("Unsupported Extended Attributes option: %u", svolinfo.v_vfs_ea);
+
+            /* initialize sufficient struct vol and initialize CNID connection */
+            svolume.v_adouble = AD_VERSION2;
+            svolume.v_vfs_ea = AFPVOL_EA_SYS;
+            initvol_vfs(&svolume);
+            int flags = 0;
+            if ((svolinfo.v_flags & AFPVOL_NODEV))
+                flags |= CNID_FLAG_NODEV;
+
+            if ((svolume.v_cdb = cnid_open(svolinfo.v_path,
+                                           0000,
+                                           "dbd",
+                                           flags,
+                                           svolinfo.v_dbd_host,
+                                           svolinfo.v_dbd_port)) == NULL)
+                ERROR("Cant initialize CNID database connection for %s", svolinfo.v_path);
+        }
+
+        if (nftw(argv[i], copy, upfunc, 20, ftw_options) == -1) {
+            ERROR("%s: %s", argv[i], strerror(errno));
             exit(EXIT_FAILURE);
         }
+
+        if (svolume.v_cdb)
+            cnid_close(svolume.v_cdb);
+        svolume.v_cdb = NULL;
+
     }
-    return 0;
+    return rval;
 }
 
 static int copy(const char *path,
@@ -289,6 +362,16 @@ static int copy(const char *path,
     const char *p;
     char *target_mid;
 
+    const char *dir = strrchr(path, '/');
+    if (dir == NULL)
+        dir = path;
+    else
+        dir++;
+    if (check_netatalk_dirs(dir) != NULL) {
+        SLOG("Skipping Netatalk dir %s", path);
+        return FTW_SKIP_SIBLINGS;
+    }
+
     /*
      * If we are in case (2) above, we need to append the
      * source name to the target name.
@@ -320,7 +403,7 @@ static int copy(const char *path,
                 if (strcmp(&path[base], "..") == 0)
                     base += 1;
             } else
-                base = ftw->base;
+                base = strlen(path);
         }
 
         p = &path[base];
@@ -391,6 +474,30 @@ static int copy(const char *path,
             ERROR("%s", to.p_path);
         }
 
+        /* Create ad dir and copy ".Parent" */
+        if (svolinfo.v_path && svolinfo.v_adouble == AD_VERSION2 &&
+            dvolinfo.v_path && dvolinfo.v_adouble == AD_VERSION2) {
+            /* Create ".AppleDouble" dir */
+            mode_t omask = umask(0);
+            bstring addir = bfromcstr(to.p_path);
+            bcatcstr(addir, "/.AppleDouble");
+            mkdir(cfrombstring(addir), 02777);
+
+            /* copy ".Parent" file */
+            bcatcstr(addir, "/.Parent");
+            bstring sdir = bfromcstr(path);
+            bcatcstr(sdir, "/.AppleDouble/.Parent");
+            if (copy_file(-1, cfrombstring(sdir), cfrombstring(addir), 0666) != 0) {
+                SLOG("Error copying %s -> %s", cfrombstring(sdir), cfrombstring(addir));
+                badcp = rval = 1;
+                break;
+            }
+            umask(omask);
+
+            /* Get CNID of Parent and add new childir to CNID database */
+            did = get_parent_cnid_for_path(&dvolinfo, &dvolume, to.p_path);
+        }
+
         if (pflag) {
             if (setfile(statp, -1))
                 rval = 1;
@@ -412,7 +519,7 @@ static int copy(const char *path,
         SLOG("%s is a FIFO (not copied).", path);
         break;
     default:
-        if (copy_file(ftw, path, statp, dne))
+        if (ftw_copy_file(ftw, path, statp, dne))
             badcp = rval = 1;
         break;
     }
index cd6545e15c49c9412b179fb3ba3a725605c974ed..87834d8605706d61ed2847bb0bb45239cae4af2d 100644 (file)
@@ -1,6 +1,4 @@
 /* 
-   $Id: ad_ls.c,v 1.4 2009-10-14 01:38:28 didg Exp $
-
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
    
    This program is free software; you can redistribute it and/or modify
index 1c9ff645ed9bc3bff98f1013a9b7cbc1c089a35b..1814ae74eeb845b196d98a683cd2840ea8573fa6 100644 (file)
@@ -40,7 +40,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <ftw.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -87,17 +86,17 @@ void _log(enum logtype lt, char *fmt, ...)
 
 int newvol(const char *path, afpvol_t *vol)
 {
-//    char *pathdup;
-
+    //    char *pathdup;
+    
     memset(vol, 0, sizeof(afpvol_t));
 
-//    pathdup = strdup(path);
-//    vol->dirname = strdup(dirname(pathdup));
-//    free(pathdup);
-
-//    pathdup = strdup(path);
-//    vol->basename = strdup(basename(pathdup));
-//    free(pathdup);
+    //    pathdup = strdup(path);
+    //    vol->dirname = strdup(dirname(pathdup));
+    //    free(pathdup);
+    
+    //    pathdup = strdup(path);
+    //    vol->basename = strdup(basename(pathdup));
+    //    free(pathdup);
 
     loadvolinfo((char *)path, &vol->volinfo);
 
@@ -118,7 +117,73 @@ void freevol(afpvol_t *vol)
 #endif
 }
 
-int copy_file(const struct FTW *entp,
+/*
+  Taken form afpd/desktop.c
+*/
+char *utompath(const struct volinfo *volinfo, char *upath)
+{
+    static char  mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
+    char         *m, *u;
+    uint16_t     flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+    size_t       outlen;
+
+    if (!upath)
+        return NULL;
+
+    m = mpath;
+    u = upath;
+    outlen = strlen(upath);
+
+    if ((volinfo->v_casefold & AFPVOL_UTOMUPPER))
+        flags |= CONV_TOUPPER;
+    else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER))
+        flags |= CONV_TOLOWER;
+
+    if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
+        flags |= CONV__EILSEQ;
+    }
+
+    /* convert charsets */
+    if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset,
+                                                 CH_UTF8_MAC,
+                                                 volinfo->v_maccharset,
+                                                 u, outlen, mpath, MAXPATHLEN, &flags)) ) {
+        SLOG("Conversion from %s to %s for %s failed.",
+            volinfo->v_volcodepage, volinfo->v_maccodepage, u);
+        return NULL;
+    }
+
+    return(m);
+}
+
+/*!
+ * Resolves CNID of a given paths parent directory
+ *
+ * path might be:
+ * (a) relative:
+ *     "dir/subdir" with cwd: "/afp_volume/topdir"
+ * (b) absolute:
+ *     "/afp_volume/dir/subdir"
+ *
+ * 1) in case a) concatenate both paths
+ * 2) strip last element
+ * 3) strip volume root
+ * 4) start recursive CNID search with
+ *    a) DID:2, "topdir"
+ *    b) DID:2, "dir"
+ * 5) ...until we have the CNID for
+ *    a) "/afp_volume/topdir/dir"
+ *    b) "/afp_volume/dir" (no recursion required)
+ */
+cnid_t get_parent_cnid_for_path(const struct volinfo *vi,
+                                const struct vol *vol,
+                                const char *path)
+{
+
+    return 0;
+}
+
+int ftw_copy_file(const struct FTW *entp,
               const char *spath,
               const struct stat *sp,
               int dne)
index 6a9f0b1bbe6d75ab84fd5d72371c22769ec143a7..2bf09187b4c6cb996e3a729d0e9c776cabde0311 100644 (file)
@@ -2,10 +2,10 @@
 
 atalkincludedir = $(includedir)/atalk
 atalkinclude_HEADERS = \
-       adouble.h vfs.h aep.h afp.h asp.h atp.h boolean.h bstradd.h \
+       adouble.h vfs.h aep.h afp.h asp.h atp.h boolean.h \
        cnid.h compat.h ddp.h dsi.h ldapconfig.h list.h logger.h \
        nbp.h netddp.h pap.h paths.h queue.h rtmp.h server_child.h \
        server_ipc.h tdb.h uam.h unicode.h util.h uuid.h volinfo.h \
        zip.h ea.h acl.h unix.h directory.h hash.h volume.h
 
-noinst_HEADERS = cnid_dbd_private.h cnid_private.h bstrlib.h errchk.h
+noinst_HEADERS = cnid_dbd_private.h cnid_private.h bstradd.h bstrlib.h errchk.h ftw.h
diff --git a/include/atalk/ftw.h b/include/atalk/ftw.h
new file mode 100644 (file)
index 0000000..6845402
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (C) 1992,1996-1999,2003,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/*
+ *     X/Open Portability Guide 4.2: ftw.h
+ */
+
+#ifndef _ATALK_FTW_H
+#define        _ATALK_FTW_H    1
+
+#include <features.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+__BEGIN_DECLS
+
+/* Values for the FLAG argument to the user function passed to `ftw'
+   and 'nftw'.  */
+enum
+{
+  FTW_F,               /* Regular file.  */
+#define FTW_F   FTW_F
+  FTW_D,               /* Directory.  */
+#define FTW_D   FTW_D
+  FTW_DNR,             /* Unreadable directory.  */
+#define FTW_DNR         FTW_DNR
+  FTW_NS,              /* Unstatable file.  */
+#define FTW_NS  FTW_NS
+  FTW_SL,              /* Symbolic link.  */
+# define FTW_SL         FTW_SL
+
+/* These flags are only passed from the `nftw' function.  */
+  FTW_DP,              /* Directory, all subdirs have been visited. */
+# define FTW_DP         FTW_DP
+  FTW_SLN              /* Symbolic link naming non-existing file.  */
+# define FTW_SLN FTW_SLN
+};
+
+
+/* Flags for fourth argument of `nftw'.  */
+enum
+{
+  FTW_PHYS = 1,                /* Perform physical walk, ignore symlinks.  */
+# define FTW_PHYS      FTW_PHYS
+  FTW_MOUNT = 2,       /* Report only files on same file system as the
+                          argument.  */
+# define FTW_MOUNT     FTW_MOUNT
+  FTW_CHDIR = 4,       /* Change to current directory while processing it.  */
+# define FTW_CHDIR     FTW_CHDIR
+  FTW_DEPTH = 8,       /* Report files in directory before directory itself.*/
+# define FTW_DEPTH     FTW_DEPTH
+  FTW_ACTIONRETVAL = 16        /* Assume callback to return FTW_* values instead of
+                          zero to continue and non-zero to terminate.  */
+#  define FTW_ACTIONRETVAL FTW_ACTIONRETVAL
+};
+
+/* Return values from callback functions.  */
+enum
+{
+  FTW_CONTINUE = 0,    /* Continue with next sibling or for FTW_D with the
+                          first child.  */
+# define FTW_CONTINUE  FTW_CONTINUE
+  FTW_STOP = 1,                /* Return from `ftw' or `nftw' with FTW_STOP as return
+                          value.  */
+# define FTW_STOP      FTW_STOP
+  FTW_SKIP_SUBTREE = 2,        /* Only meaningful for FTW_D: Don't walk through the
+                          subtree, instead just continue with its next
+                          sibling. */
+# define FTW_SKIP_SUBTREE FTW_SKIP_SUBTREE
+  FTW_SKIP_SIBLINGS = 3,/* Continue with FTW_DP callback for current directory
+                           (if FTW_DEPTH) and then its siblings.  */
+# define FTW_SKIP_SIBLINGS FTW_SKIP_SIBLINGS
+};
+
+/* Structure used for fourth argument to callback function for `nftw'.  */
+struct FTW
+  {
+    int base;
+    int level;
+  };
+
+/* Convenient types for callback functions.  */
+typedef int (*nftw_func_t) (const char *filename,
+                            const struct stat *status,
+                            int flag,
+                            struct FTW *info);
+#define NFTW_FUNC_T nftw_func_t
+
+typedef void (*dir_notification_func_t) (void);
+
+extern int nftw(const char *dir,
+                nftw_func_t func,
+                dir_notification_func_t up,
+                int descriptors,
+                int flag);
+
+__END_DECLS
+
+#endif /* ATALK_FTW_H */
index 7ce49773122fab4d7c7908d84e1ac9909264ea3e..a3f433eb1546af6f8f52dd26dd64b80c4111d2a3 100644 (file)
@@ -35,6 +35,7 @@ extern q_t *queue_init(void);
 extern void queue_destroy(q_t *q, void (*callback)(void *));
 #define queue_free(q) queue_destroy((q), free)
 extern qnode_t *enqueue(q_t *q, void *data);
+extern qnode_t *prequeue(q_t *q, void *data);
 extern void *dequeue(q_t *q);
 
 #endif  /* ATALK_QUEUE_H */
index 410b6b2aa0ddb10c1b22dfc25b2f96d46ceb7573..2a95bef6fdf58beaa91ef96284a0b1c783e636dd 100644 (file)
@@ -33,7 +33,7 @@ struct volinfo {
     int                 v_vfs_ea;
     char                *(*ad_path)(const char *, int);
     char                *v_dbd_host;
-    int                 v_dbd_port;
+    char                *v_dbd_port;
 };
 
 extern int loadvolinfo(char *path, struct volinfo *vol);
index 52597e9c971ac64af20f01e89ee7d2879f6304e8..f36fbdc1ede20c8d8b9e4ac3857a7c1241300ee1 100644 (file)
@@ -10,6 +10,7 @@ libutil_la_SOURCES = \
        atalk_addr.c    \
        bprint.c        \
        fault.c         \
+       ftw.c           \
        getiface.c      \
        locking.c   \
        logger.c        \
diff --git a/libatalk/util/ftw.c b/libatalk/util/ftw.c
new file mode 100644 (file)
index 0000000..2d33a37
--- /dev/null
@@ -0,0 +1,803 @@
+/* File tree walker functions.
+   Copyright (C) 1996-2004, 2006-2008, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if __GNUC__
+# define alloca __builtin_alloca
+#else
+#  include <alloca.h>
+#endif
+
+#include <dirent.h>
+#define NAMLEN(dirent) strlen ((dirent)->d_name)
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#include <atalk/ftw.h>
+
+#define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+
+#define NDEBUG 1
+#include <assert.h>
+
+#ifndef _LIBC
+# undef __chdir
+# define __chdir chdir
+# undef __closedir
+# define __closedir closedir
+# undef __fchdir
+# define __fchdir fchdir
+# undef __getcwd
+# define __getcwd(P, N) xgetcwd ()
+# undef __mempcpy
+# define __mempcpy mempcpy
+# undef __opendir
+# define __opendir opendir
+# undef __readdir64
+# define __readdir64 readdir
+# undef __tdestroy
+# define __tdestroy tdestroy
+# undef __tfind
+# define __tfind tfind
+# undef __tsearch
+# define __tsearch tsearch
+# undef internal_function
+# define internal_function /* empty */
+# undef dirent64
+# define dirent64 dirent
+# undef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+/* Support for the LFS API version.  */
+#ifndef FTW_NAME
+# define FTW_NAME ftw
+# define NFTW_NAME nftw
+# define NFTW_OLD_NAME __old_nftw
+# define NFTW_NEW_NAME __new_nftw
+# define INO_T ino_t
+# define STAT stat
+# define LXSTAT(V,f,sb) lstat (f,sb)
+# define XSTAT(V,f,sb) stat (f,sb)
+# define FXSTATAT(V,d,f,sb,m) fstatat (d, f, sb, m)
+
+#endif
+
+/* We define PATH_MAX if the system does not provide a definition.
+   This does not artificially limit any operation.  PATH_MAX is simply
+   used as a guesstimate for the expected maximal path length.
+   Buffers will be enlarged if necessary.  */
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+struct dir_data
+{
+    DIR *stream;
+    int streamfd;
+    char *content;
+};
+
+struct known_object
+{
+    dev_t dev;
+    INO_T ino;
+};
+
+struct ftw_data
+{
+    /* Array with pointers to open directory streams.  */
+    struct dir_data **dirstreams;
+    size_t actdir;
+    size_t maxdir;
+
+    /* Buffer containing name of currently processed object.  */
+    char *dirbuf;
+    size_t dirbufsize;
+
+    /* Passed as fourth argument to `nftw' callback.  The `base' member
+       tracks the content of the `dirbuf'.  */
+    struct FTW ftw;
+
+    /* Flags passed to `nftw' function.  0 for `ftw'.  */
+    int flags;
+
+    /* Conversion array for flag values.  It is the identity mapping for
+       `nftw' calls, otherwise it maps the values to those known by
+       `ftw'.  */
+    const int *cvt_arr;
+
+    /* Callback function.  We always use the `nftw' form.  */
+    NFTW_FUNC_T func;
+
+    /* Device of starting point.  Needed for FTW_MOUNT.  */
+    dev_t dev;
+
+    /* Data structure for keeping fingerprints of already processed
+       object.  This is needed when not using FTW_PHYS.  */
+    void *known_objects;
+};
+
+
+/* Internally we use the FTW_* constants used for `nftw'.  When invoked
+   as `ftw', map each flag to the subset of values used by `ftw'.  */
+static const int nftw_arr[] =
+{
+    FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
+};
+
+static const int ftw_arr[] =
+{
+    FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
+};
+
+
+static dir_notification_func_t upfunc;
+
+/* Forward declarations of local functions.  */
+static int ftw_dir (struct ftw_data *data, struct STAT *st,
+                    struct dir_data *old_dir) internal_function;
+
+static char *mystpcpy(char *a, const char *b)
+{
+    strcpy(a, b);
+    return (a + strlen(a));
+}
+
+static char *xgetcwd(void)
+{
+    char *cwd;
+    char *ret;
+    unsigned path_max;
+
+    errno = 0;
+    path_max = (unsigned) PATH_MAX;
+    path_max += 2;        /* The getcwd docs say to do this. */
+
+    cwd = malloc (path_max);
+    errno = 0;
+    while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) {
+        path_max += 512;
+        cwd = realloc (cwd, path_max);
+        errno = 0;
+    }
+
+    if (ret == NULL) {
+        int save_errno = errno;
+        free (cwd);
+        errno = save_errno;
+        return NULL;
+    }
+    return cwd;
+}
+
+static int
+object_compare (const void *p1, const void *p2)
+{
+    /* We don't need a sophisticated and useful comparison.  We are only
+       interested in equality.  However, we must be careful not to
+       accidentally compare `holes' in the structure.  */
+    const struct known_object *kp1 = p1, *kp2 = p2;
+    int cmp1;
+    cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
+    if (cmp1 != 0)
+        return cmp1;
+    return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
+}
+
+
+static int
+add_object (struct ftw_data *data, struct STAT *st)
+{
+    struct known_object *newp = malloc (sizeof (struct known_object));
+    if (newp == NULL)
+        return -1;
+    newp->dev = st->st_dev;
+    newp->ino = st->st_ino;
+    return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1;
+}
+
+
+static inline int
+find_object (struct ftw_data *data, struct STAT *st)
+{
+    struct known_object obj;
+    obj.dev = st->st_dev;
+    obj.ino = st->st_ino;
+    return __tfind (&obj, &data->known_objects, object_compare) != NULL;
+}
+
+
+static inline int
+open_dir_stream (int *dfdp, struct ftw_data *data, struct dir_data *dirp)
+{
+    int result = 0;
+
+    if (data->dirstreams[data->actdir] != NULL)
+    {
+        /* Oh, oh.  We must close this stream.  Get all remaining
+           entries and store them as a list in the `content' member of
+           the `struct dir_data' variable.  */
+        size_t bufsize = 1024;
+        char *buf = malloc (bufsize);
+
+        if (buf == NULL)
+            result = -1;
+        else
+        {
+            DIR *st = data->dirstreams[data->actdir]->stream;
+            struct dirent64 *d;
+            size_t actsize = 0;
+
+            while ((d = __readdir64 (st)) != NULL)
+            {
+                size_t this_len = NAMLEN (d);
+                if (actsize + this_len + 2 >= bufsize)
+                {
+                    char *newp;
+                    bufsize += MAX (1024, 2 * this_len);
+                    newp = (char *) realloc (buf, bufsize);
+                    if (newp == NULL)
+                    {
+                        /* No more memory.  */
+                        int save_err = errno;
+                        free (buf);
+                        __set_errno (save_err);
+                        return -1;
+                    }
+                    buf = newp;
+                }
+
+                *((char *) __mempcpy (buf + actsize, d->d_name, this_len))
+                    = '\0';
+                actsize += this_len + 1;
+            }
+
+            /* Terminate the list with an additional NUL byte.  */
+            buf[actsize++] = '\0';
+
+            /* Shrink the buffer to what we actually need.  */
+            data->dirstreams[data->actdir]->content = realloc (buf, actsize);
+            if (data->dirstreams[data->actdir]->content == NULL)
+            {
+                int save_err = errno;
+                free (buf);
+                __set_errno (save_err);
+                result = -1;
+            }
+            else
+            {
+                __closedir (st);
+                data->dirstreams[data->actdir]->stream = NULL;
+                data->dirstreams[data->actdir]->streamfd = -1;
+                data->dirstreams[data->actdir] = NULL;
+            }
+        }
+    }
+
+    /* Open the new stream.  */
+    if (result == 0)
+    {
+        assert (data->dirstreams[data->actdir] == NULL);
+
+        if (dfdp != NULL && *dfdp != -1)
+        {
+            int fd = openat(*dfdp, data->dirbuf + data->ftw.base,
+                            O_RDONLY | O_DIRECTORY | O_NDELAY);
+            dirp->stream = NULL;
+            if (fd != -1 && (dirp->stream = fdopendir (fd)) == NULL)
+                close(fd);
+        }
+        else
+        {
+            const char *name;
+
+            if (data->flags & FTW_CHDIR)
+            {
+                name = data->dirbuf + data->ftw.base;
+                if (name[0] == '\0')
+                    name = ".";
+            }
+            else
+                name = data->dirbuf;
+
+            dirp->stream = __opendir (name);
+        }
+
+        if (dirp->stream == NULL)
+            result = -1;
+        else
+        {
+            dirp->streamfd = dirfd (dirp->stream);
+            dirp->content = NULL;
+            data->dirstreams[data->actdir] = dirp;
+
+            if (++data->actdir == data->maxdir)
+                data->actdir = 0;
+        }
+    }
+
+    return result;
+}
+
+
+static int
+process_entry (struct ftw_data *data, struct dir_data *dir, const char *name,
+               size_t namlen, int d_type)
+{
+    struct STAT st;
+    int result = 0;
+    int flag = 0;
+    size_t new_buflen;
+
+    if (name[0] == '.' && (name[1] == '\0'
+                           || (name[1] == '.' && name[2] == '\0')))
+        /* Don't process the "." and ".." entries.  */
+        return 0;
+
+    new_buflen = data->ftw.base + namlen + 2;
+    if (data->dirbufsize < new_buflen)
+    {
+        /* Enlarge the buffer.  */
+        char *newp;
+
+        data->dirbufsize = 2 * new_buflen;
+        newp = (char *) realloc (data->dirbuf, data->dirbufsize);
+        if (newp == NULL)
+            return -1;
+        data->dirbuf = newp;
+    }
+
+    *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0';
+
+    int statres;
+    if (dir->streamfd != -1)
+        statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
+                            (data->flags & FTW_PHYS) ? AT_SYMLINK_NOFOLLOW : 0);
+    else
+    {
+        if ((data->flags & FTW_CHDIR) == 0)
+            name = data->dirbuf;
+
+        statres = ((data->flags & FTW_PHYS)
+                   ? LXSTAT (_STAT_VER, name, &st)
+                   : XSTAT (_STAT_VER, name, &st));
+    }
+
+    if (statres < 0)
+    {
+        if (errno != EACCES && errno != ENOENT)
+            result = -1;
+        else if (data->flags & FTW_PHYS)
+            flag = FTW_NS;
+        else if (d_type == DT_LNK)
+            flag = FTW_SLN;
+        else
+        {
+            if (dir->streamfd != -1)
+                statres = FXSTATAT (_STAT_VER, dir->streamfd, name, &st,
+                                    AT_SYMLINK_NOFOLLOW);
+            else
+                statres = LXSTAT (_STAT_VER, name, &st);
+            if (statres == 0 && S_ISLNK (st.st_mode))
+                flag = FTW_SLN;
+            else
+                flag = FTW_NS;
+        }
+    }
+    else
+    {
+        if (S_ISDIR (st.st_mode))
+            flag = FTW_D;
+        else if (S_ISLNK (st.st_mode))
+            flag = FTW_SL;
+        else
+            flag = FTW_F;
+    }
+
+    if (result == 0
+        && (flag == FTW_NS
+            || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev))
+    {
+        if (flag == FTW_D)
+        {
+            if ((data->flags & FTW_PHYS)
+                || (!find_object (data, &st)
+                    /* Remember the object.  */
+                    && (result = add_object (data, &st)) == 0))
+                result = ftw_dir (data, &st, dir);
+        }
+        else
+            result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
+                                    &data->ftw);
+    }
+
+    if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
+        result = 0;
+
+    return result;
+}
+
+
+static int
+ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir)
+{
+    struct dir_data dir;
+    struct dirent64 *d;
+    int previous_base = data->ftw.base;
+    int result;
+    char *startp;
+
+    /* Open the stream for this directory.  This might require that
+       another stream has to be closed.  */
+    result = open_dir_stream (old_dir == NULL ? NULL : &old_dir->streamfd,
+                              data, &dir);
+    if (result != 0)
+    {
+        if (errno == EACCES)
+            /* We cannot read the directory.  Signal this with a special flag.  */
+            result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw);
+
+        return result;
+    }
+
+    /* First, report the directory (if not depth-first).  */
+    if (!(data->flags & FTW_DEPTH))
+    {
+        result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw);
+        if (result != 0)
+        {
+            int save_err;
+        fail:
+            save_err = errno;
+            __closedir (dir.stream);
+            dir.streamfd = -1;
+            __set_errno (save_err);
+
+            if (data->actdir-- == 0)
+                data->actdir = data->maxdir - 1;
+            data->dirstreams[data->actdir] = NULL;
+            return result;
+        }
+    }
+
+    /* If necessary, change to this directory.  */
+    if (data->flags & FTW_CHDIR)
+    {
+        if (__fchdir (dirfd (dir.stream)) < 0)
+        {
+            result = -1;
+            goto fail;
+        }
+    }
+
+    /* Next, update the `struct FTW' information.  */
+    ++data->ftw.level;
+    startp = data->dirbuf + strlen(data->dirbuf);
+    /* There always must be a directory name.  */
+    assert (startp != data->dirbuf);
+    if (startp[-1] != '/')
+        *startp++ = '/';
+    data->ftw.base = startp - data->dirbuf;
+
+    while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL)
+    {
+        result = process_entry (data, &dir, d->d_name, NAMLEN (d), d->d_type);
+        if (result != 0)
+            break;
+    }
+
+    if (dir.stream != NULL)
+    {
+        /* The stream is still open.  I.e., we did not need more
+           descriptors.  Simply close the stream now.  */
+        int save_err = errno;
+
+        assert (dir.content == NULL);
+
+        __closedir (dir.stream);
+        dir.streamfd = -1;
+        __set_errno (save_err);
+
+        if (data->actdir-- == 0)
+            data->actdir = data->maxdir - 1;
+        data->dirstreams[data->actdir] = NULL;
+    }
+    else
+    {
+        int save_err;
+        char *runp = dir.content;
+
+        while (result == 0 && *runp != '\0')
+        {
+            char *endp = strchr (runp, '\0');
+
+            // XXX Should store the d_type values as well?!
+            result = process_entry (data, &dir, runp, endp - runp, DT_UNKNOWN);
+
+            runp = endp + 1;
+        }
+
+        save_err = errno;
+        free (dir.content);
+        __set_errno (save_err);
+    }
+
+    if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
+        result = 0;
+
+    /* Prepare the return, revert the `struct FTW' information.  */
+    data->dirbuf[data->ftw.base - 1] = '\0';
+    --data->ftw.level;
+    if (upfunc)
+        (*upfunc)();
+    data->ftw.base = previous_base;
+
+    /* Finally, if we process depth-first report the directory.  */
+    if (result == 0 && (data->flags & FTW_DEPTH))
+        result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);
+
+    if (old_dir
+        && (data->flags & FTW_CHDIR)
+        && (result == 0
+            || ((data->flags & FTW_ACTIONRETVAL)
+                && (result != -1 && result != FTW_STOP))))
+    {
+        /* Change back to the parent directory.  */
+        int done = 0;
+        if (old_dir->stream != NULL)
+            if (__fchdir (dirfd (old_dir->stream)) == 0)
+                done = 1;
+
+        if (!done)
+        {
+            if (data->ftw.base == 1)
+            {
+                if (__chdir ("/") < 0)
+                    result = -1;
+            }
+            else
+                if (__chdir ("..") < 0)
+                    result = -1;
+        }
+    }
+
+    return result;
+}
+
+
+static int ftw_startup (const char *dir,
+                        int is_nftw,
+                        void *func,
+                        dir_notification_func_t up,
+                        int descriptors,
+                        int flags)
+{
+    struct ftw_data data;
+    struct STAT st;
+    int result = 0;
+    int save_err;
+    int cwdfd = -1;
+    char *cwd = NULL;
+    char *cp;
+
+    upfunc = up;
+
+    /* First make sure the parameters are reasonable.  */
+    if (dir[0] == '\0')
+    {
+        __set_errno (ENOENT);
+        return -1;
+    }
+
+    data.maxdir = descriptors < 1 ? 1 : descriptors;
+    data.actdir = 0;
+    data.dirstreams = (struct dir_data **) alloca (data.maxdir
+                                                   * sizeof (struct dir_data *));
+    memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
+
+    /* PATH_MAX is always defined when we get here.  */
+    data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
+    data.dirbuf = (char *) malloc (data.dirbufsize);
+    if (data.dirbuf == NULL)
+        return -1;
+    cp = mystpcpy (data.dirbuf, dir);
+    /* Strip trailing slashes.  */
+    while (cp > data.dirbuf + 1 && cp[-1] == '/')
+        --cp;
+    *cp = '\0';
+
+    data.ftw.level = 0;
+
+    /* Find basename.  */
+    while (cp > data.dirbuf && cp[-1] != '/')
+        --cp;
+    data.ftw.base = cp - data.dirbuf;
+
+    data.flags = flags;
+
+    /* This assignment might seem to be strange but it is what we want.
+       The trick is that the first three arguments to the `ftw' and
+       `nftw' callback functions are equal.  Therefore we can call in
+       every case the callback using the format of the `nftw' version
+       and get the correct result since the stack layout for a function
+       call in C allows this.  */
+    data.func = (NFTW_FUNC_T) func;
+
+    /* Since we internally use the complete set of FTW_* values we need
+       to reduce the value range before calling a `ftw' callback.  */
+    data.cvt_arr = is_nftw ? nftw_arr : ftw_arr;
+
+    /* No object known so far.  */
+    data.known_objects = NULL;
+
+    /* Now go to the directory containing the initial file/directory.  */
+    if (flags & FTW_CHDIR)
+    {
+        /* We have to be able to go back to the current working
+           directory.  The best way to do this is to use a file
+           descriptor.  */
+        cwdfd = open (".", O_RDONLY | O_DIRECTORY);
+        if (cwdfd == -1)
+        {
+            /* Try getting the directory name.  This can be needed if
+               the current directory is executable but not readable.  */
+            if (errno == EACCES)
+                /* GNU extension ahead.  */
+                cwd = __getcwd(NULL, 0);
+
+            if (cwd == NULL)
+                goto out_fail;
+        }
+        else if (data.maxdir > 1)
+            /* Account for the file descriptor we use here.  */
+            --data.maxdir;
+
+        if (data.ftw.base > 0)
+        {
+            /* Change to the directory the file is in.  In data.dirbuf
+               we have a writable copy of the file name.  Just NUL
+               terminate it for now and change the directory.  */
+            if (data.ftw.base == 1)
+                /* I.e., the file is in the root directory.  */
+                result = __chdir ("/");
+            else
+            {
+                char ch = data.dirbuf[data.ftw.base - 1];
+                data.dirbuf[data.ftw.base - 1] = '\0';
+                result = __chdir (data.dirbuf);
+                data.dirbuf[data.ftw.base - 1] = ch;
+            }
+        }
+    }
+
+    /* Get stat info for start directory.  */
+    if (result == 0)
+    {
+        const char *name;
+
+        if (data.flags & FTW_CHDIR)
+        {
+            name = data.dirbuf + data.ftw.base;
+            if (name[0] == '\0')
+                name = ".";
+        }
+        else
+            name = data.dirbuf;
+
+        if (((flags & FTW_PHYS)
+             ? LXSTAT (_STAT_VER, name, &st)
+             : XSTAT (_STAT_VER, name, &st)) < 0)
+        {
+            if (!(flags & FTW_PHYS)
+                && errno == ENOENT
+                && LXSTAT (_STAT_VER, name, &st) == 0
+                && S_ISLNK (st.st_mode))
+                result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN],
+                                       &data.ftw);
+            else
+                /* No need to call the callback since we cannot say anything
+                   about the object.  */
+                result = -1;
+        }
+        else
+        {
+            if (S_ISDIR (st.st_mode))
+            {
+                /* Remember the device of the initial directory in case
+                   FTW_MOUNT is given.  */
+                data.dev = st.st_dev;
+
+                /* We know this directory now.  */
+                if (!(flags & FTW_PHYS))
+                    result = add_object (&data, &st);
+
+                if (result == 0)
+                    result = ftw_dir (&data, &st, NULL);
+            }
+            else
+            {
+                int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F;
+
+                result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag],
+                                       &data.ftw);
+            }
+        }
+
+        if ((flags & FTW_ACTIONRETVAL)
+            && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS))
+            result = 0;
+    }
+
+    /* Return to the start directory (if necessary).  */
+    if (cwdfd != -1)
+    {
+        int save_err = errno;
+        __fchdir (cwdfd);
+        close(cwdfd);
+        __set_errno (save_err);
+    }
+    else if (cwd != NULL)
+    {
+        int save_err = errno;
+        __chdir (cwd);
+        free (cwd);
+        __set_errno (save_err);
+    }
+
+    /* Free all memory.  */
+out_fail:
+    save_err = errno;
+    __tdestroy (data.known_objects, free);
+    free (data.dirbuf);
+    __set_errno (save_err);
+
+    return result;
+}
+
+
+
+/* Entry points.  */
+int NFTW_NAME(const char *path,
+              NFTW_FUNC_T func,
+              dir_notification_func_t up,
+              int descriptors,
+              int flags)
+{
+    return ftw_startup (path, 1, func, up, descriptors, flags);
+}
+
index 2e7ff5ec0d0e87788274b98edfcc3ffa573f336e..114e6401aa2da7c199cc4c6e95fe1d7815ea43a3 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: queue.c,v 1.1.2.1 2010-02-01 10:56:08 franklahm Exp $
   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -51,6 +50,7 @@ q_t *queue_init(void)
     return queue;
 }
 
+/* Insert at tail */
 qnode_t *enqueue(q_t *q, void *data)
 {
     qnode_t *node;
@@ -67,6 +67,24 @@ qnode_t *enqueue(q_t *q, void *data)
     return node;
 }
 
+/* Insert at head */
+qnode_t *prequeue(q_t *q, void *data)
+{
+    qnode_t *node;
+
+    if ((node = alloc_init_node(data)) == NULL)
+        return NULL;
+
+    /* insert at head */
+    q->next->prev = node;
+    node->next = q->next;
+    node->prev = q;
+    q->next = node;
+
+    return node;
+}
+
+/* Take from head */
 void *dequeue(q_t *q)
 {
     qnode_t *node;
index ef438c5d278f5b103a968e8e41953c9cad4d5021..d4fdfab0bba147f27471bd8e75f8c3c6101f7cd5 100644 (file)
@@ -139,16 +139,32 @@ static char * make_path_absolute(char *path, size_t bufsize)
     char       abspath[MAXPATHLEN];
     char       *p;
 
-    if (stat(path, &st) != 0) {
-        return NULL;
-    }
+    strlcpy(abspath, path, sizeof(abspath));
 
-    strlcpy (abspath, path, sizeof(abspath));
+    /* we might be called from `ad cp ...` with non existing target */
+    if (stat(abspath, &st) != 0) {
+        if (errno != ENOENT)
+            return NULL;
 
-    if (!S_ISDIR(st.st_mode)) {
-        if (NULL == (p=strrchr(abspath, '/')) )
+        if (NULL == (p = strrchr(abspath, '/')) )
+            /* single component `ad cp SOURCEFILE TARGETFILE`, use "." instead */
             strcpy(abspath, ".");
         else
+            /* try without the last path element */
+            *p = '\0';
+
+        if (stat(abspath, &st) != 0) {
+            return NULL;
+        }
+    }
+
+    if (S_ISREG(st.st_mode)) {
+        /* single file copy SOURCE */
+        if (NULL == (p = strrchr(abspath, '/')) )
+            /* no path, use "." instead */
+            strcpy(abspath, ".");
+        else
+            /* try without the last path element */
             *p = '\0';
     }
 
@@ -272,7 +288,10 @@ static int parseline ( char *buf, struct volinfo *vol)
         }
         break;
       case CNIDDBDPORT:
-        vol->v_dbd_port = atoi(value);
+        if ((vol->v_dbd_port = strdup(value)) == NULL) {
+           fprintf (stderr, "strdup: %s", strerror(errno));
+            return -1;            
+        }
         break;
       case CNID_DBPATH:
         if ((vol->v_dbpath = strdup(value)) == NULL) {