]> arthur.barton.de Git - netatalk.git/blob - bin/cnid/ad_ls.c
remove obsolete ATACC ifdef
[netatalk.git] / bin / cnid / ad_ls.c
1 /* 
2    $Id: ad_ls.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
36 #include <atalk/adouble.h>
37 #include <atalk/cnid.h>
38 #include <atalk/volinfo.h>
39 #include "ad.h"
40
41 #define ADv2_DIRNAME ".AppleDouble"
42
43 #define DIR_DOT_OR_DOTDOT(a) \
44         ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
45
46 /* ls options */
47 static int ls_a;
48 static int ls_l;
49 static int ls_R;
50 static int ls_d;
51 static int ls_u;
52
53 /* Used for pretty printing */
54 static int first = 1;
55 static int recursion;
56
57 static char           *netatalk_dirs[] = {
58     ADv2_DIRNAME,
59     ".AppleDB",
60     ".AppleDesktop",
61     NULL
62 };
63
64 static char *labels[] = {
65     "---",
66     "gry",
67     "gre",
68     "vio",
69     "blu",
70     "yel",
71     "red",
72     "ora"
73 };
74
75 /*
76   Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
77   Returns pointer to name or NULL.
78 */
79 static const char *check_netatalk_dirs(const char *name)
80 {
81     int c;
82
83     for (c=0; netatalk_dirs[c]; c++) {
84         if ((strcmp(name, netatalk_dirs[c])) == 0)
85             return netatalk_dirs[c];
86     }
87     return NULL;
88 }
89
90
91 static void usage_ls()
92 {
93     printf(
94         "Usage: ad ls [-dRl[u]] [file|dir, ...]\n\n"
95         "  -l Long Output [-u: unix info]:\n"
96         "     <unixinfo ...> <FinderFlags> <AFPAttributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>\n\n"
97         "     FinderFlags (valid for (f)ile and/or (d)irectory):\n"
98         "       d = On Desktop (f/d)\n"
99         "       e = Hidden extension (f/d)\n"
100         "       m = Shared (can run multiple times) (f)\n"
101         "       n = No INIT resources (f)\n"
102         "       i = Inited (f/d)\n"
103         "       c = Custom icon (f/d)\n"
104         "       t = Stationery (f)\n"
105         "       s = Name locked (f/d)\n"
106         "       b = Bundle (f/d)\n"
107         "       v = Invisible (f/d)\n"
108         "       a = Alias file (f/d)\n\n"
109         "     AFPAttributes:\n"
110         "       y = System (f/d)\n"
111         "       w = No write (f)\n"
112         "       p = Needs backup (f/d)\n"
113         "       r = No rename (f/d)\n"
114         "       l = No delete (f/d)\n"
115         "       o = No copy (f)\n\n"
116         "     Note: any letter appearing in uppercase means the flag is set\n"
117         "           but it's a directory for which the flag is not allowed.\n"
118         );
119 }
120
121 static void print_numlinks(const struct stat *statp)
122 {
123     printf("%5ld", (long)statp->st_nlink);
124 }
125
126 static void print_owner(const struct stat *statp)
127 {
128     struct passwd *pwd = getpwuid(statp->st_uid);
129
130     if (pwd == NULL)
131         printf(" %-8ld", (long)statp->st_uid);
132     else
133         printf(" %-8s", pwd->pw_name);
134 }
135
136 static void print_group(const struct stat *statp)
137 {
138     struct group *grp = getgrgid(statp->st_gid);
139
140     if (grp == NULL)
141         printf(" %-8ld", (long)statp->st_gid);
142     else
143         printf(" %-8s", grp->gr_name);
144 }
145
146 static void print_size(const struct stat *statp)
147 {
148     switch (statp->st_mode & S_IFMT) {
149     case S_IFCHR:
150     case S_IFBLK:
151         printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
152                (unsigned)(statp->st_rdev & 0xFF));
153         break;
154     default:
155         printf("%9lu", (unsigned long)statp->st_size);
156     }
157 }
158
159 static void print_date(const struct stat *statp)
160 {
161     time_t now;
162     double diff;
163     char buf[100], *fmt;
164
165     if (time(&now) == -1) {
166         printf(" ????????????");
167         return;
168     }
169     diff = difftime(now, statp->st_mtime);
170     if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
171         fmt = "%b %e  %Y";
172     else
173         fmt = "%b %e %H:%M";
174     strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
175     printf(" %s", buf);
176 }
177
178 static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
179 {
180     int adflags = 0;
181     struct adouble ad;
182     char *FinderInfo;
183     uint16_t FinderFlags;
184     uint16_t AFPattributes;
185     char type[5] = "----";
186     char creator[5] = "----";
187
188     if (S_ISDIR(st->st_mode))
189         adflags = ADFLAGS_DIR;
190
191     if (vol->volinfo.v_path == NULL)
192         return;
193
194     ad_init(&ad, vol->volinfo.v_adouble, vol->volinfo.v_ad_options);
195
196     if ( ad_metadata(path, adflags, &ad) < 0 )
197         return;
198
199     FinderInfo = ad_entry(&ad, ADEID_FINDERI);
200
201     memcpy(&FinderFlags, FinderInfo + 8, 2);
202     FinderFlags = ntohs(FinderFlags);
203
204     memcpy(type, FinderInfo, 4);
205     memcpy(creator, FinderInfo + 4, 4);
206
207     ad_getattr(&ad, &AFPattributes);
208     AFPattributes = ntohs(AFPattributes);
209
210     /*
211       Finder flags. Lowercase means valid, uppercase means invalid because
212       object is a dir and flag is only valid for files.
213     */
214     putchar(' ');
215     if (FinderFlags & FINDERINFO_ISONDESK)
216         putchar('d');
217     else
218         putchar('-');
219
220     if (FinderFlags & FINDERINFO_HIDEEXT)
221         putchar('e');
222     else
223         putchar('-');
224
225     if (FinderFlags & FINDERINFO_ISHARED) {
226         if (adflags & ADFLAGS_DIR)
227             putchar('M');
228         else
229             putchar('m');
230     } else
231         putchar('-');
232
233     if (FinderFlags & FINDERINFO_HASNOINITS) {
234         if (adflags & ADFLAGS_DIR)
235             putchar('N');
236         else
237             putchar('n');
238     } else
239         putchar('-');
240
241     if (FinderFlags & FINDERINFO_HASBEENINITED)
242         putchar('i');
243     else
244         putchar('-');
245
246     if (FinderFlags & FINDERINFO_HASCUSTOMICON)
247         putchar('c');
248     else
249         putchar('-');
250
251     if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
252         if (adflags & ADFLAGS_DIR)
253             putchar('T');
254         else
255             putchar('t');
256     } else
257         putchar('-');
258
259     if (FinderFlags & FINDERINFO_NAMELOCKED)
260         putchar('s');
261     else
262         putchar('-');
263
264     if (FinderFlags & FINDERINFO_HASBUNDLE)
265         putchar('b');
266     else
267         putchar('-');
268
269     if (FinderFlags & FINDERINFO_INVISIBLE)
270         putchar('v');
271     else
272         putchar('-');
273
274     if (FinderFlags & FINDERINFO_ISALIAS)
275         putchar('a');
276     else
277         putchar('-');
278
279     putchar(' ');
280
281     /* AFP attributes */
282     if (AFPattributes & ATTRBIT_SYSTEM)
283         putchar('y');
284     else
285         putchar('-');
286
287     if (AFPattributes & ATTRBIT_NOWRITE) {
288         if (adflags & ADFLAGS_DIR)
289             putchar('W');
290         else
291             putchar('w');
292     } else
293         putchar('-');
294
295     if (AFPattributes & ATTRBIT_BACKUP)
296         putchar('p');
297     else
298         putchar('-');
299
300     if (AFPattributes & ATTRBIT_NORENAME)
301         putchar('r');
302     else
303         putchar('-');
304
305     if (AFPattributes & ATTRBIT_NODELETE)
306         putchar('l');
307     else
308         putchar('-');
309
310     if (AFPattributes & ATTRBIT_NOCOPY) {
311         if (adflags & ADFLAGS_DIR)
312             putchar('O');
313         else
314             putchar('o');                
315     } else
316         putchar('-');
317
318     /* Color */
319     printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
320
321     /* Type & Creator */
322     int i;
323     for(i=0; i<4; i++) {
324         if (isalnum(type[i]))
325             putchar(type[i]);
326         else
327             putchar('-');
328     }
329     putchar(' '); 
330     for(i=0; i<4; i++) {
331         if (isalnum(creator[i]))
332             putchar(creator[i]);
333         else
334             putchar('-');
335     }
336     putchar(' '); 
337
338     /* CNID */
339     uint32_t cnid = ad_forcegetid(&ad);
340     if (cnid)
341         printf(" %10u ", ntohl(cnid));
342     else
343         printf(" !ADVOL_CACHE ");
344
345     ad_close_metadata(&ad);
346 }
347
348 #define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
349 #define MODE(b) ((st->st_mode & (b)) == (b))
350
351 static void print_mode(const struct stat *st)
352 {
353     if (TYPE(S_IFBLK))
354         putchar('b');
355     else if (TYPE(S_IFCHR))
356         putchar('c');
357     else if (TYPE(S_IFDIR))
358         putchar('d');
359     else if (TYPE(S_IFIFO))
360         putchar('p');
361     else if (TYPE(S_IFREG))
362         putchar('-');
363     else if (TYPE(S_IFLNK))
364         putchar('l');
365     else if (TYPE(S_IFSOCK))
366         putchar('s');
367     else
368         putchar('?');
369     putchar(MODE(S_IRUSR) ? 'r' : '-');
370     putchar(MODE(S_IWUSR) ? 'w' : '-');
371     if (MODE(S_ISUID)) {
372         if (MODE(S_IXUSR))
373             putchar('s');
374         else
375             putchar('S');
376     }
377     else if (MODE(S_IXUSR))
378         putchar('x');
379     else
380         putchar('-');
381     putchar(MODE(S_IRGRP) ? 'r' : '-');
382     putchar(MODE(S_IWGRP) ? 'w' : '-');
383     if (MODE(S_ISGID)) {
384         if (MODE(S_IXGRP))
385             putchar('s');
386         else
387             putchar('S');
388     }
389     else if (MODE(S_IXGRP))
390         putchar('x');
391     else
392         putchar('-');
393     putchar(MODE(S_IROTH) ? 'r' : '-');
394     putchar(MODE(S_IWOTH) ? 'w' : '-');
395     if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
396         if (MODE(S_IXOTH))
397             putchar('t');
398         else
399             putchar('T');
400     }
401     else if (MODE(S_IXOTH))
402         putchar('x');
403     else
404         putchar('-');
405 }
406 #undef TYPE
407 #undef MODE
408
409 int ad_print(char *path, const struct stat *st, afpvol_t *vol)
410 {
411     if ( ! ls_l) {
412         printf("%s  ", path);
413         if (ls_d)
414             printf("\n");
415         return 0;
416     }
417
418     /* Long output */
419     if (ls_u) {
420         print_mode(st);
421         print_numlinks(st);
422         print_owner(st);
423         print_group(st);
424         print_size(st);
425         print_date(st);
426     }
427     print_flags(path, vol, st);
428     printf("  %s\n", path);    
429
430
431     return 0;
432 }
433
434 int ad_ls_r(char *path, afpvol_t *vol)
435 {
436     int ret = 0, cwd, dirprinted = 0, dirempty;
437     const char *name;
438     char *tmp;
439     static char cwdpath[MAXPATHLEN+1];
440     DIR *dp;
441     struct dirent *ep;
442     static struct stat st;      /* Save some stack space */
443
444     if ( first)
445         cwdpath[0] = 0;
446     else
447         strcat(cwdpath, "/");
448
449     strcat(cwdpath, path);
450     first = 0;
451
452     if (lstat(path, &st) < 0) {
453         perror("Can't stat");
454         return -1;
455     }
456     /* If its a file or a dir with -d option call ad_print and return */
457     if (S_ISREG(st.st_mode) || ls_d)
458         return ad_print(path, &st, vol);
459
460     /* Its a dir: chdir to it remembering where we started */
461     if ((cwd = open(".", O_RDONLY)) == -1) {
462         perror("Cant open .");
463         return -1;
464     }
465     if (chdir(path) != 0) {
466         perror("Cant chdir");
467         close(cwd);
468         return -1;
469     }
470
471     if ((dp = opendir (".")) == NULL) {
472         perror("Couldn't opendir .");
473         return -1;
474     }
475
476     /* First run: print everything */
477     dirempty = 1;
478     while ((ep = readdir (dp))) {
479         /* Check if its "." or ".." */
480         if (DIR_DOT_OR_DOTDOT(ep->d_name))
481             continue;
482
483         /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
484         if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
485             continue;
486
487         if ((ep->d_name[0] == '.') && ! ls_a)
488             continue;
489
490         dirempty = 0;
491
492         if (recursion && ! dirprinted) {
493             printf("\n%s:\n", cwdpath);
494             dirprinted = 1;
495         }
496
497         if (lstat(ep->d_name, &st) < 0) {
498             perror("Can't stat");
499             return -1;
500         }
501
502         ret = ad_print(ep->d_name, &st, vol);
503         if (ret != 0)
504             goto exit;
505     }
506
507     if (! ls_l && ! dirempty)
508         printf("\n");
509
510     /* Second run: recurse to dirs */
511     if (ls_R) {
512         rewinddir(dp);
513         while ((ep = readdir (dp))) {
514             /* Check if its "." or ".." */
515             if (DIR_DOT_OR_DOTDOT(ep->d_name))
516                 continue;
517
518             /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
519             if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
520                 continue;
521
522             if (lstat(ep->d_name, &st) < 0) {
523                 perror("Can't stat");
524                 return -1;
525             }
526
527             /* Recursion */
528             if (S_ISDIR(st.st_mode)) {
529                 recursion = 1;
530                 ret = ad_ls_r(ep->d_name, vol);
531             }
532             if (ret != 0)
533                 goto exit;
534         }
535     }
536
537 exit:
538     closedir(dp);
539     fchdir(cwd);
540     close(cwd);
541
542     tmp = strrchr(cwdpath, '/');
543     if (tmp)
544         *tmp = 0;
545
546     return ret;
547 }
548
549 int ad_ls(int argc, char **argv)
550 {
551     int c, firstarg;
552     afpvol_t vol;
553     struct stat st;
554
555     while ((c = getopt(argc, argv, ":adlRu")) != -1) {
556         switch(c) {
557         case 'a':
558             ls_a = 1;
559             break;
560         case 'd':
561             ls_d = 1;
562             break;
563         case 'l':
564             ls_l = 1;
565             break;
566         case 'R':
567             ls_R = 1;
568             break;
569         case 'u':
570             ls_u = 1;
571             break;
572         case ':':
573         case '?':
574             usage_ls();
575             return -1;
576             break;
577         }
578
579     }
580
581     if ((argc - optind) == 0) {
582         newvol(".", &vol);
583         ad_ls_r(".", &vol);
584         freevol(&vol);
585     }
586     else {
587         firstarg = optind;
588
589         /* First run: only print files from argv paths */
590         int havefile = 0;
591         while(optind < argc) {
592             if (stat(argv[optind], &st) != 0)
593                 goto next;
594             if (S_ISDIR(st.st_mode))
595                 goto next;
596
597             havefile = 1;
598             first = 1;
599             recursion = 0;
600
601             newvol(argv[optind], &vol);
602             ad_ls_r(argv[optind], &vol);
603             freevol(&vol);
604         next:
605             optind++;
606         }
607         if (havefile && (! ls_l))
608             printf("\n");
609
610         /* Second run: print dirs */
611         optind = firstarg;
612         while(optind < argc) {
613             if (stat(argv[optind], &st) != 0)
614                 goto next2;
615             if ( ! S_ISDIR(st.st_mode))
616                 goto next2;
617             if ((optind > firstarg) || havefile)
618                 printf("\n%s:\n", argv[optind]);
619
620             first = 1;
621             recursion = 0;
622
623             newvol(argv[optind], &vol);
624             ad_ls_r(argv[optind], &vol);
625             freevol(&vol);
626
627         next2:
628             optind++;
629         }
630
631
632     }
633
634     return 0;
635 }