]> arthur.barton.de Git - netatalk.git/blob - bin/cnid/ad_ls.c
call readt with ONE_DELAY = 5 s
[netatalk.git] / bin / cnid / ad_ls.c
1 /* 
2    $Id: ad_ls.c,v 1.4 2009-10-14 01:38:28 didg 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(void)
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     int i;
188     uint32_t cnid;
189
190     if (S_ISDIR(st->st_mode))
191         adflags = ADFLAGS_DIR;
192
193     if (vol->volinfo.v_path == NULL)
194         return;
195
196     ad_init(&ad, vol->volinfo.v_adouble, vol->volinfo.v_ad_options);
197
198     if ( ad_metadata(path, adflags, &ad) < 0 )
199         return;
200
201     FinderInfo = ad_entry(&ad, ADEID_FINDERI);
202
203     memcpy(&FinderFlags, FinderInfo + 8, 2);
204     FinderFlags = ntohs(FinderFlags);
205
206     memcpy(type, FinderInfo, 4);
207     memcpy(creator, FinderInfo + 4, 4);
208
209     ad_getattr(&ad, &AFPattributes);
210     AFPattributes = ntohs(AFPattributes);
211
212     /*
213       Finder flags. Lowercase means valid, uppercase means invalid because
214       object is a dir and flag is only valid for files.
215     */
216     putchar(' ');
217     if (FinderFlags & FINDERINFO_ISONDESK)
218         putchar('d');
219     else
220         putchar('-');
221
222     if (FinderFlags & FINDERINFO_HIDEEXT)
223         putchar('e');
224     else
225         putchar('-');
226
227     if (FinderFlags & FINDERINFO_ISHARED) {
228         if (adflags & ADFLAGS_DIR)
229             putchar('M');
230         else
231             putchar('m');
232     } else
233         putchar('-');
234
235     if (FinderFlags & FINDERINFO_HASNOINITS) {
236         if (adflags & ADFLAGS_DIR)
237             putchar('N');
238         else
239             putchar('n');
240     } else
241         putchar('-');
242
243     if (FinderFlags & FINDERINFO_HASBEENINITED)
244         putchar('i');
245     else
246         putchar('-');
247
248     if (FinderFlags & FINDERINFO_HASCUSTOMICON)
249         putchar('c');
250     else
251         putchar('-');
252
253     if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
254         if (adflags & ADFLAGS_DIR)
255             putchar('T');
256         else
257             putchar('t');
258     } else
259         putchar('-');
260
261     if (FinderFlags & FINDERINFO_NAMELOCKED)
262         putchar('s');
263     else
264         putchar('-');
265
266     if (FinderFlags & FINDERINFO_HASBUNDLE)
267         putchar('b');
268     else
269         putchar('-');
270
271     if (FinderFlags & FINDERINFO_INVISIBLE)
272         putchar('v');
273     else
274         putchar('-');
275
276     if (FinderFlags & FINDERINFO_ISALIAS)
277         putchar('a');
278     else
279         putchar('-');
280
281     putchar(' ');
282
283     /* AFP attributes */
284     if (AFPattributes & ATTRBIT_SYSTEM)
285         putchar('y');
286     else
287         putchar('-');
288
289     if (AFPattributes & ATTRBIT_NOWRITE) {
290         if (adflags & ADFLAGS_DIR)
291             putchar('W');
292         else
293             putchar('w');
294     } else
295         putchar('-');
296
297     if (AFPattributes & ATTRBIT_BACKUP)
298         putchar('p');
299     else
300         putchar('-');
301
302     if (AFPattributes & ATTRBIT_NORENAME)
303         putchar('r');
304     else
305         putchar('-');
306
307     if (AFPattributes & ATTRBIT_NODELETE)
308         putchar('l');
309     else
310         putchar('-');
311
312     if (AFPattributes & ATTRBIT_NOCOPY) {
313         if (adflags & ADFLAGS_DIR)
314             putchar('O');
315         else
316             putchar('o');                
317     } else
318         putchar('-');
319
320     /* Color */
321     printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
322
323     /* Type & Creator */
324     for(i=0; i<4; i++) {
325         if (isalnum(type[i]))
326             putchar(type[i]);
327         else
328             putchar('-');
329     }
330     putchar(' '); 
331     for(i=0; i<4; i++) {
332         if (isalnum(creator[i]))
333             putchar(creator[i]);
334         else
335             putchar('-');
336     }
337     putchar(' '); 
338
339     /* CNID */
340     cnid = ad_forcegetid(&ad);
341     if (cnid)
342         printf(" %10u ", ntohl(cnid));
343     else
344         printf(" !ADVOL_CACHE ");
345
346     ad_close_metadata(&ad);
347 }
348
349 #define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
350 #define MODE(b) ((st->st_mode & (b)) == (b))
351
352 static void print_mode(const struct stat *st)
353 {
354     if (TYPE(S_IFBLK))
355         putchar('b');
356     else if (TYPE(S_IFCHR))
357         putchar('c');
358     else if (TYPE(S_IFDIR))
359         putchar('d');
360     else if (TYPE(S_IFIFO))
361         putchar('p');
362     else if (TYPE(S_IFREG))
363         putchar('-');
364     else if (TYPE(S_IFLNK))
365         putchar('l');
366     else if (TYPE(S_IFSOCK))
367         putchar('s');
368     else
369         putchar('?');
370     putchar(MODE(S_IRUSR) ? 'r' : '-');
371     putchar(MODE(S_IWUSR) ? 'w' : '-');
372     if (MODE(S_ISUID)) {
373         if (MODE(S_IXUSR))
374             putchar('s');
375         else
376             putchar('S');
377     }
378     else if (MODE(S_IXUSR))
379         putchar('x');
380     else
381         putchar('-');
382     putchar(MODE(S_IRGRP) ? 'r' : '-');
383     putchar(MODE(S_IWGRP) ? 'w' : '-');
384     if (MODE(S_ISGID)) {
385         if (MODE(S_IXGRP))
386             putchar('s');
387         else
388             putchar('S');
389     }
390     else if (MODE(S_IXGRP))
391         putchar('x');
392     else
393         putchar('-');
394     putchar(MODE(S_IROTH) ? 'r' : '-');
395     putchar(MODE(S_IWOTH) ? 'w' : '-');
396     if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
397         if (MODE(S_IXOTH))
398             putchar('t');
399         else
400             putchar('T');
401     }
402     else if (MODE(S_IXOTH))
403         putchar('x');
404     else
405         putchar('-');
406 }
407 #undef TYPE
408 #undef MODE
409
410 static int ad_print(char *path, const struct stat *st, afpvol_t *vol)
411 {
412     if ( ! ls_l) {
413         printf("%s  ", path);
414         if (ls_d)
415             printf("\n");
416         return 0;
417     }
418
419     /* Long output */
420     if (ls_u) {
421         print_mode(st);
422         print_numlinks(st);
423         print_owner(st);
424         print_group(st);
425         print_size(st);
426         print_date(st);
427     }
428     print_flags(path, vol, st);
429     printf("  %s\n", path);    
430
431
432     return 0;
433 }
434
435 static int ad_ls_r(char *path, afpvol_t *vol)
436 {
437     int ret = 0, cwd, dirprinted = 0, dirempty;
438     const char *name;
439     char *tmp;
440     static char cwdpath[MAXPATHLEN+1];
441     DIR *dp;
442     struct dirent *ep;
443     static struct stat st;      /* Save some stack space */
444
445     if ( first)
446         cwdpath[0] = 0;
447     else
448         strcat(cwdpath, "/");
449
450     strcat(cwdpath, path);
451     first = 0;
452
453     if (lstat(path, &st) < 0) {
454         perror("Can't stat");
455         return -1;
456     }
457     /* If its a file or a dir with -d option call ad_print and return */
458     if (S_ISREG(st.st_mode) || ls_d)
459         return ad_print(path, &st, vol);
460
461     /* Its a dir: chdir to it remembering where we started */
462     if ((cwd = open(".", O_RDONLY)) == -1) {
463         perror("Cant open .");
464         return -1;
465     }
466     if (chdir(path) != 0) {
467         perror("Cant chdir");
468         close(cwd);
469         return -1;
470     }
471
472     if ((dp = opendir (".")) == NULL) {
473         perror("Couldn't opendir .");
474         return -1;
475     }
476
477     /* First run: print everything */
478     dirempty = 1;
479     while ((ep = readdir (dp))) {
480         /* Check if its "." or ".." */
481         if (DIR_DOT_OR_DOTDOT(ep->d_name))
482             continue;
483
484         /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
485         if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
486             continue;
487
488         if ((ep->d_name[0] == '.') && ! ls_a)
489             continue;
490
491         dirempty = 0;
492
493         if (recursion && ! dirprinted) {
494             printf("\n%s:\n", cwdpath);
495             dirprinted = 1;
496         }
497
498         if (lstat(ep->d_name, &st) < 0) {
499             perror("Can't stat");
500             return -1;
501         }
502
503         ret = ad_print(ep->d_name, &st, vol);
504         if (ret != 0)
505             goto exit;
506     }
507
508     if (! ls_l && ! dirempty)
509         printf("\n");
510
511     /* Second run: recurse to dirs */
512     if (ls_R) {
513         rewinddir(dp);
514         while ((ep = readdir (dp))) {
515             /* Check if its "." or ".." */
516             if (DIR_DOT_OR_DOTDOT(ep->d_name))
517                 continue;
518
519             /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
520             if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
521                 continue;
522
523             if ((ret = lstat(ep->d_name, &st)) < 0) {
524                 perror("Can't stat");
525                 goto exit;
526             }
527
528             /* Recursion */
529             if (S_ISDIR(st.st_mode)) {
530                 recursion = 1;
531                 ret = ad_ls_r(ep->d_name, vol);
532             }
533             if (ret != 0)
534                 goto exit;
535         }
536     }
537
538 exit:
539     closedir(dp);
540     fchdir(cwd);
541     close(cwd);
542
543     tmp = strrchr(cwdpath, '/');
544     if (tmp)
545         *tmp = 0;
546
547     return ret;
548 }
549
550 int ad_ls(int argc, char **argv)
551 {
552     int c, firstarg;
553     afpvol_t vol;
554     struct stat st;
555
556     while ((c = getopt(argc, argv, ":adlRu")) != -1) {
557         switch(c) {
558         case 'a':
559             ls_a = 1;
560             break;
561         case 'd':
562             ls_d = 1;
563             break;
564         case 'l':
565             ls_l = 1;
566             break;
567         case 'R':
568             ls_R = 1;
569             break;
570         case 'u':
571             ls_u = 1;
572             break;
573         case ':':
574         case '?':
575             usage_ls();
576             return -1;
577             break;
578         }
579
580     }
581
582     if ((argc - optind) == 0) {
583         newvol(".", &vol);
584         ad_ls_r(".", &vol);
585         freevol(&vol);
586     }
587     else {
588         int havefile = 0;
589
590         firstarg = optind;
591
592         /* First run: only print files from argv paths */
593         while(optind < argc) {
594             if (stat(argv[optind], &st) != 0)
595                 goto next;
596             if (S_ISDIR(st.st_mode))
597                 goto next;
598
599             havefile = 1;
600             first = 1;
601             recursion = 0;
602
603             newvol(argv[optind], &vol);
604             ad_ls_r(argv[optind], &vol);
605             freevol(&vol);
606         next:
607             optind++;
608         }
609         if (havefile && (! ls_l))
610             printf("\n");
611
612         /* Second run: print dirs */
613         optind = firstarg;
614         while(optind < argc) {
615             if (stat(argv[optind], &st) != 0)
616                 goto next2;
617             if ( ! S_ISDIR(st.st_mode))
618                 goto next2;
619             if ((optind > firstarg) || havefile)
620                 printf("\n%s:\n", argv[optind]);
621
622             first = 1;
623             recursion = 0;
624
625             newvol(argv[optind], &vol);
626             ad_ls_r(argv[optind], &vol);
627             freevol(&vol);
628
629         next2:
630             optind++;
631         }
632
633
634     }
635
636     return 0;
637 }