]> arthur.barton.de Git - netatalk.git/blob - bin/cnid/ad_cp.c
e2f2472b8c25abab56b859c51cbdf8a6ba9a5a10
[netatalk.git] / bin / cnid / ad_cp.c
1 /* 
2    $Id: ad_cp.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
3
4    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10  
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif /* HAVE_CONFIG_H */
20
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <limits.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <dirent.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <time.h>
35 #include <libgen.h>
36
37 #include <atalk/adouble.h>
38 #include <atalk/cnid.h>
39 #include <atalk/volinfo.h>
40 #include <atalk/util.h>
41 #include "ad.h"
42
43 #define ADv2_DIRNAME ".AppleDouble"
44
45 /* options */
46 static int cp_R;
47 static int cp_L;
48 static int cp_P;
49 static int cp_n;
50 static int cp_p;
51 static int cp_v;
52
53 static char           *netatalk_dirs[] = {
54     ADv2_DIRNAME,
55     ".AppleDB",
56     ".AppleDesktop",
57     NULL
58 };
59
60 /*
61   Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
62   Returns pointer to name or NULL.
63 */
64 static const char *check_netatalk_dirs(const char *name)
65 {
66     int c;
67
68     for (c=0; netatalk_dirs[c]; c++) {
69         if ((strcmp(name, netatalk_dirs[c])) == 0)
70             return netatalk_dirs[c];
71     }
72     return NULL;
73 }
74
75
76 static void usage_cp()
77 {
78     printf(
79         "Usage: ad cp [-R [-L | -P]] [-pv] <source_file> <target_file>\n"
80         "Usage: ad cp [-R [-L | -P]] [-pv] <source_file [source_file ...]> <target_directory>\n"
81         );
82 }
83
84 static int ad_cp_copy(const afpvol_t *srcvol, const afpvol_t *dstvol,
85                       char *srcfile, char *dstfile, struct stat *st)
86 {
87     printf("copy: '%s' -> '%s'\n", srcfile, dstfile);
88     return 0;
89 }
90
91 static int ad_cp_r(const afpvol_t *srcvol, const afpvol_t *dstvol, char *srcdir, char *dstdir)
92 {
93     int ret = 0, cwd, dirprinted = 0, dirempty;
94     static char srcpath[MAXPATHLEN+1];
95     static char dstpath[MAXPATHLEN+1];
96     char *tmp;
97     DIR *dp;
98     struct dirent *ep;
99     static struct stat st;      /* Save some stack space */
100
101     strlcat(srcpath, srcdir, sizeof(srcpath));
102     strlcat(dstpath, dstdir, sizeof(dstpath));
103
104     if ((dp = opendir (srcdir)) == NULL) {
105         perror("Couldn't opendir .");
106         return -1;
107     }
108
109     /* First run: copy files */
110     while ((ep = readdir (dp))) {
111         /* Check if its "." or ".." */
112         if (DIR_DOT_OR_DOTDOT(ep->d_name))
113             continue;
114
115         /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
116         if ((check_netatalk_dirs(ep->d_name)) != NULL)
117             continue;
118
119         if (lstat(ep->d_name, &st) < 0) {
120             perror("Can't stat");
121             return -1;
122         }
123
124         /* Build paths, copy, strip name */
125         strlcat(srcpath, "/", sizeof(srcpath));
126         strlcat(dstpath, "/", sizeof(dstpath));
127         strlcat(srcpath, ep->d_name, sizeof(srcpath));
128         strlcat(dstpath, ep->d_name, sizeof(dstpath));
129
130         ret = ad_cp_copy(srcvol, dstvol, srcpath, dstpath, &st);
131
132         if ((tmp = strrchr(srcpath, '/')))
133             *tmp = 0;
134         if ((tmp = strrchr(dstpath, '/')))
135             *tmp = 0;
136
137         if (ret != 0)
138             goto exit;
139     }
140
141     /* Second run: recurse to dirs */
142     rewinddir(dp);
143     while ((ep = readdir (dp))) {
144         /* Check if its "." or ".." */
145         if (DIR_DOT_OR_DOTDOT(ep->d_name))
146             continue;
147         
148         /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
149         if (check_netatalk_dirs(ep->d_name) != NULL)
150             continue;
151         
152         if (lstat(ep->d_name, &st) < 0) {
153             perror("Can't stat");
154             return -1;
155         }
156         
157         /* Recursion */
158         if (S_ISDIR(st.st_mode)) {
159             strlcat(srcpath, "/", sizeof(srcpath));
160             strlcat(dstpath, "/", sizeof(dstpath));
161             ret = ad_cp_r(srcvol, dstvol, ep->d_name, ep->d_name);
162         }
163         if (ret != 0)
164             goto exit;
165     }
166
167 exit:
168     closedir(dp);
169     fchdir(cwd);
170     close(cwd);
171
172     if ((tmp = strrchr(srcpath, '/')))
173         *tmp = 0;
174     if ((tmp = strrchr(dstpath, '/')))
175         *tmp = 0;
176
177     return ret;
178 }
179
180 int ad_cp(int argc, char **argv)
181 {
182     int c, numpaths;
183     afpvol_t srcvvol;
184     struct stat sst;
185     struct stat dst;
186     afpvol_t srcvol;
187     afpvol_t dstvol;
188     char *srcfile = NULL;
189     char *srcdir = NULL;    
190     char *dstfile = NULL;
191     char *dstdir = NULL;
192     char path[MAXPATHLEN+1];
193     char *basenametmp;
194
195     while ((c = getopt(argc, argv, ":npvLPR")) != -1) {
196         switch(c) {
197         case 'n':
198             cp_n = 1;
199             break;
200         case 'p':
201             cp_p = 1;
202             break;
203         case 'v':
204             cp_v = 1;
205             break;
206         case 'L':
207             cp_L = 1;
208             break;
209         case 'P':
210             cp_P = 1;
211             break;
212         case 'R':
213             cp_R = 1;
214             break;
215         case ':':
216         case '?':
217             usage_cp();
218             return -1;
219             break;
220         }
221     }
222
223     /* How many pathnames do we have */
224     numpaths = argc - optind;
225     printf("Number of paths: %u\n", numpaths);
226     if (numpaths < 2) {
227         usage_cp();
228         exit(EXIT_FAILURE);
229     }
230
231     while ( argv[argc-1][(strlen(argv[argc-1]) - 1)] == '/')
232         argv[argc-1][(strlen(argv[argc-1]) - 1)] = 0;
233     printf("Destination is: %s\n", argv[argc-1]);
234
235     /* Create vol for destination */
236     newvol(argv[argc-1], &dstvol);
237
238     if (numpaths == 2) {
239         /* Case 1: 2 paths */
240         if (stat(argv[optind], &sst) != 0)
241             goto next;
242         if (S_ISREG(sst.st_mode)) {
243             /* Either file to file or file to dir copy */
244             newvol(argv[optind], &srcvol);
245             ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst);
246             freevol(&srcvol);
247             freevol(&dstvol);
248             
249         } else if (S_ISDIR(sst.st_mode)) {
250             /* dir to dir copy. Check if -R is requested */
251             if (!cp_R) {
252                 usage_cp();
253                 exit(EXIT_FAILURE);
254             }
255         }
256
257     } else {
258         /* Case 2: >2 paths */
259         while (optind < (argc-1)) {
260             printf("Source is: %s\n", argv[optind]);
261             newvol(argv[optind], &srcvol);
262             if (stat(argv[optind], &sst) != 0)
263                 goto next;
264             if (S_ISDIR(sst.st_mode)) {
265                 /* Source is a directory */
266                 if (!cp_R) {
267                     printf("Source %s is a directory\n", argv[optind]);
268                     goto next;
269                 }
270                 srcdir = argv[optind];
271                 dstdir = argv[argc-1];
272                 
273                 ad_cp_r(&srcvol, &dstvol, srcdir, dstdir);
274                 freevol(&srcvol);
275             } else {
276                 /* Source is a file */
277                 srcfile = argv[optind];
278                 if (numpaths != 2 && !dstdir) {
279                     usage_cp();
280                     exit(EXIT_FAILURE);
281                 }
282                 path[0] = 0;
283                 strlcat(path, dstdir, sizeof(path));
284                 basenametmp = strdup(srcfile);
285                 strlcat(path, basename(basenametmp), sizeof(path));
286                 free(basenametmp);
287                 printf("%s %s\n", srcfile, path);
288                 if (ad_cp_copy(&srcvol, &dstvol, srcfile, path, &sst) != 0) {
289                     freevol(&srcvol);
290                     freevol(&dstvol);
291                     exit(EXIT_FAILURE);
292                 }
293             } /* else */
294         next:
295             optind++;
296         } /* while */
297     } /* else (numpath>2) */
298
299     freevol(&dstvol);
300
301     return 0;
302
303 }