]> arthur.barton.de Git - netatalk.git/blobdiff - bin/cnid/ad_cp.c
New utility: ad
[netatalk.git] / bin / cnid / ad_cp.c
diff --git a/bin/cnid/ad_cp.c b/bin/cnid/ad_cp.c
new file mode 100644 (file)
index 0000000..e2f2472
--- /dev/null
@@ -0,0 +1,303 @@
+/* 
+   $Id: ad_cp.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
+
+   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program 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 General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <libgen.h>
+
+#include <atalk/adouble.h>
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include <atalk/util.h>
+#include "ad.h"
+
+#define ADv2_DIRNAME ".AppleDouble"
+
+/* options */
+static int cp_R;
+static int cp_L;
+static int cp_P;
+static int cp_n;
+static int cp_p;
+static int cp_v;
+
+static char           *netatalk_dirs[] = {
+    ADv2_DIRNAME,
+    ".AppleDB",
+    ".AppleDesktop",
+    NULL
+};
+
+/*
+  Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
+  Returns pointer to name or NULL.
+*/
+static const char *check_netatalk_dirs(const char *name)
+{
+    int c;
+
+    for (c=0; netatalk_dirs[c]; c++) {
+        if ((strcmp(name, netatalk_dirs[c])) == 0)
+            return netatalk_dirs[c];
+    }
+    return NULL;
+}
+
+
+static void usage_cp()
+{
+    printf(
+        "Usage: ad cp [-R [-L | -P]] [-pv] <source_file> <target_file>\n"
+        "Usage: ad cp [-R [-L | -P]] [-pv] <source_file [source_file ...]> <target_directory>\n"
+        );
+}
+
+static int ad_cp_copy(const afpvol_t *srcvol, const afpvol_t *dstvol,
+                      char *srcfile, char *dstfile, struct stat *st)
+{
+    printf("copy: '%s' -> '%s'\n", srcfile, dstfile);
+    return 0;
+}
+
+static int ad_cp_r(const afpvol_t *srcvol, const afpvol_t *dstvol, char *srcdir, char *dstdir)
+{
+    int ret = 0, cwd, dirprinted = 0, dirempty;
+    static char srcpath[MAXPATHLEN+1];
+    static char dstpath[MAXPATHLEN+1];
+    char *tmp;
+    DIR *dp;
+    struct dirent *ep;
+    static struct stat st;      /* Save some stack space */
+
+    strlcat(srcpath, srcdir, sizeof(srcpath));
+    strlcat(dstpath, dstdir, sizeof(dstpath));
+
+    if ((dp = opendir (srcdir)) == NULL) {
+        perror("Couldn't opendir .");
+        return -1;
+    }
+
+    /* First run: copy files */
+    while ((ep = readdir (dp))) {
+        /* Check if its "." or ".." */
+        if (DIR_DOT_OR_DOTDOT(ep->d_name))
+            continue;
+
+        /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+        if ((check_netatalk_dirs(ep->d_name)) != NULL)
+            continue;
+
+        if (lstat(ep->d_name, &st) < 0) {
+            perror("Can't stat");
+            return -1;
+        }
+
+        /* Build paths, copy, strip name */
+        strlcat(srcpath, "/", sizeof(srcpath));
+        strlcat(dstpath, "/", sizeof(dstpath));
+        strlcat(srcpath, ep->d_name, sizeof(srcpath));
+        strlcat(dstpath, ep->d_name, sizeof(dstpath));
+
+        ret = ad_cp_copy(srcvol, dstvol, srcpath, dstpath, &st);
+
+        if ((tmp = strrchr(srcpath, '/')))
+            *tmp = 0;
+        if ((tmp = strrchr(dstpath, '/')))
+            *tmp = 0;
+
+        if (ret != 0)
+            goto exit;
+    }
+
+    /* Second run: recurse to dirs */
+    rewinddir(dp);
+    while ((ep = readdir (dp))) {
+        /* Check if its "." or ".." */
+        if (DIR_DOT_OR_DOTDOT(ep->d_name))
+            continue;
+        
+        /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
+        if (check_netatalk_dirs(ep->d_name) != NULL)
+            continue;
+        
+        if (lstat(ep->d_name, &st) < 0) {
+            perror("Can't stat");
+            return -1;
+        }
+        
+        /* Recursion */
+        if (S_ISDIR(st.st_mode)) {
+            strlcat(srcpath, "/", sizeof(srcpath));
+            strlcat(dstpath, "/", sizeof(dstpath));
+            ret = ad_cp_r(srcvol, dstvol, ep->d_name, ep->d_name);
+        }
+        if (ret != 0)
+            goto exit;
+    }
+
+exit:
+    closedir(dp);
+    fchdir(cwd);
+    close(cwd);
+
+    if ((tmp = strrchr(srcpath, '/')))
+        *tmp = 0;
+    if ((tmp = strrchr(dstpath, '/')))
+        *tmp = 0;
+
+    return ret;
+}
+
+int ad_cp(int argc, char **argv)
+{
+    int c, numpaths;
+    afpvol_t srcvvol;
+    struct stat sst;
+    struct stat dst;
+    afpvol_t srcvol;
+    afpvol_t dstvol;
+    char *srcfile = NULL;
+    char *srcdir = NULL;    
+    char *dstfile = NULL;
+    char *dstdir = NULL;
+    char path[MAXPATHLEN+1];
+    char *basenametmp;
+
+    while ((c = getopt(argc, argv, ":npvLPR")) != -1) {
+        switch(c) {
+        case 'n':
+            cp_n = 1;
+            break;
+        case 'p':
+            cp_p = 1;
+            break;
+        case 'v':
+            cp_v = 1;
+            break;
+        case 'L':
+            cp_L = 1;
+            break;
+        case 'P':
+            cp_P = 1;
+            break;
+        case 'R':
+            cp_R = 1;
+            break;
+        case ':':
+        case '?':
+            usage_cp();
+            return -1;
+            break;
+        }
+    }
+
+    /* How many pathnames do we have */
+    numpaths = argc - optind;
+    printf("Number of paths: %u\n", numpaths);
+    if (numpaths < 2) {
+        usage_cp();
+        exit(EXIT_FAILURE);
+    }
+
+    while ( argv[argc-1][(strlen(argv[argc-1]) - 1)] == '/')
+        argv[argc-1][(strlen(argv[argc-1]) - 1)] = 0;
+    printf("Destination is: %s\n", argv[argc-1]);
+
+    /* Create vol for destination */
+    newvol(argv[argc-1], &dstvol);
+
+    if (numpaths == 2) {
+        /* Case 1: 2 paths */
+        if (stat(argv[optind], &sst) != 0)
+            goto next;
+        if (S_ISREG(sst.st_mode)) {
+            /* Either file to file or file to dir copy */
+            newvol(argv[optind], &srcvol);
+            ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst);
+            freevol(&srcvol);
+            freevol(&dstvol);
+            
+        } else if (S_ISDIR(sst.st_mode)) {
+            /* dir to dir copy. Check if -R is requested */
+            if (!cp_R) {
+                usage_cp();
+                exit(EXIT_FAILURE);
+            }
+        }
+
+    } else {
+        /* Case 2: >2 paths */
+        while (optind < (argc-1)) {
+            printf("Source is: %s\n", argv[optind]);
+            newvol(argv[optind], &srcvol);
+            if (stat(argv[optind], &sst) != 0)
+                goto next;
+            if (S_ISDIR(sst.st_mode)) {
+                /* Source is a directory */
+                if (!cp_R) {
+                    printf("Source %s is a directory\n", argv[optind]);
+                    goto next;
+                }
+                srcdir = argv[optind];
+                dstdir = argv[argc-1];
+                
+                ad_cp_r(&srcvol, &dstvol, srcdir, dstdir);
+                freevol(&srcvol);
+            } else {
+                /* Source is a file */
+                srcfile = argv[optind];
+                if (numpaths != 2 && !dstdir) {
+                    usage_cp();
+                    exit(EXIT_FAILURE);
+                }
+                path[0] = 0;
+                strlcat(path, dstdir, sizeof(path));
+                basenametmp = strdup(srcfile);
+                strlcat(path, basename(basenametmp), sizeof(path));
+                free(basenametmp);
+                printf("%s %s\n", srcfile, path);
+                if (ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst) != 0) {
+                    freevol(&srcvol);
+                    freevol(&dstvol);
+                    exit(EXIT_FAILURE);
+                }
+            } /* else */
+        next:
+            optind++;
+        } /* while */
+    } /* else (numpath>2) */
+
+    freevol(&dstvol);
+
+    return 0;
+
+}