]> arthur.barton.de Git - netatalk.git/blob - bin/ad/ad_ls.c
Rename cfrombstring to cfrombstr and msic
[netatalk.git] / bin / ad / ad_ls.c
1 /* 
2    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8  
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <time.h>
33
34 #include <atalk/adouble.h>
35 #include <atalk/cnid.h>
36 #include <atalk/volinfo.h>
37 #include "ad.h"
38
39 #define ADv2_DIRNAME ".AppleDouble"
40
41 #define DIR_DOT_OR_DOTDOT(a) \
42         ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
43
44 /* ls options */
45 static int ls_a;
46 static int ls_l;
47 static int ls_R;
48 static int ls_d;
49 static int ls_u;
50
51 /* Used for pretty printing */
52 static int first = 1;
53 static int recursion;
54
55 static char           *netatalk_dirs[] = {
56     ADv2_DIRNAME,
57     ".AppleDB",
58     ".AppleDesktop",
59     NULL
60 };
61
62 static char *labels[] = {
63     "---",
64     "gry",
65     "gre",
66     "vio",
67     "blu",
68     "yel",
69     "red",
70     "ora"
71 };
72
73 /*
74   Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
75   Returns pointer to name or NULL.
76 */
77 static const char *check_netatalk_dirs(const char *name)
78 {
79     int c;
80
81     for (c=0; netatalk_dirs[c]; c++) {
82         if ((strcmp(name, netatalk_dirs[c])) == 0)
83             return netatalk_dirs[c];
84     }
85     return NULL;
86 }
87
88
89 static void usage_ls(void)
90 {
91     printf(
92         "Usage: ad ls [-dRl[u]] [file|dir, ...]\n\n"
93         "  -l Long Output [-u: unix info]:\n"
94         "     <unixinfo ...> <FinderFlags> <AFPAttributes> <Color> <Type> <Creator> <CNID from AppleDouble> <name>\n\n"
95         "     FinderFlags (valid for (f)ile and/or (d)irectory):\n"
96         "       d = On Desktop (f/d)\n"
97         "       e = Hidden extension (f/d)\n"
98         "       m = Shared (can run multiple times) (f)\n"
99         "       n = No INIT resources (f)\n"
100         "       i = Inited (f/d)\n"
101         "       c = Custom icon (f/d)\n"
102         "       t = Stationery (f)\n"
103         "       s = Name locked (f/d)\n"
104         "       b = Bundle (f/d)\n"
105         "       v = Invisible (f/d)\n"
106         "       a = Alias file (f/d)\n\n"
107         "     AFPAttributes:\n"
108         "       y = System (f/d)\n"
109         "       w = No write (f)\n"
110         "       p = Needs backup (f/d)\n"
111         "       r = No rename (f/d)\n"
112         "       l = No delete (f/d)\n"
113         "       o = No copy (f)\n\n"
114         "     Note: any letter appearing in uppercase means the flag is set\n"
115         "           but it's a directory for which the flag is not allowed.\n"
116         );
117 }
118
119 static void print_numlinks(const struct stat *statp)
120 {
121     printf("%5ld", (long)statp->st_nlink);
122 }
123
124 static void print_owner(const struct stat *statp)
125 {
126     struct passwd *pwd = getpwuid(statp->st_uid);
127
128     if (pwd == NULL)
129         printf(" %-8ld", (long)statp->st_uid);
130     else
131         printf(" %-8s", pwd->pw_name);
132 }
133
134 static void print_group(const struct stat *statp)
135 {
136     struct group *grp = getgrgid(statp->st_gid);
137
138     if (grp == NULL)
139         printf(" %-8ld", (long)statp->st_gid);
140     else
141         printf(" %-8s", grp->gr_name);
142 }
143
144 static void print_size(const struct stat *statp)
145 {
146     switch (statp->st_mode & S_IFMT) {
147     case S_IFCHR:
148     case S_IFBLK:
149         printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
150                (unsigned)(statp->st_rdev & 0xFF));
151         break;
152     default:
153         printf("%9lu", (unsigned long)statp->st_size);
154     }
155 }
156
157 static void print_date(const struct stat *statp)
158 {
159     time_t now;
160     double diff;
161     char buf[100], *fmt;
162
163     if (time(&now) == -1) {
164         printf(" ????????????");
165         return;
166     }
167     diff = difftime(now, statp->st_mtime);
168     if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
169         fmt = "%b %e  %Y";
170     else
171         fmt = "%b %e %H:%M";
172     strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
173     printf(" %s", buf);
174 }
175
176 static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
177 {
178     int adflags = 0;
179     struct adouble ad;
180     char *FinderInfo;
181     uint16_t FinderFlags;
182     uint16_t AFPattributes;
183     char type[5] = "----";
184     char creator[5] = "----";
185     int i;
186     uint32_t cnid;
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     for(i=0; i<4; i++) {
323         if (isalnum(type[i]))
324             putchar(type[i]);
325         else
326             putchar('-');
327     }
328     putchar(' '); 
329     for(i=0; i<4; i++) {
330         if (isalnum(creator[i]))
331             putchar(creator[i]);
332         else
333             putchar('-');
334     }
335     putchar(' '); 
336
337     /* CNID */
338     cnid = ad_forcegetid(&ad);
339     if (cnid)
340         printf(" %10u ", ntohl(cnid));
341     else
342         printf(" !ADVOL_CACHE ");
343
344     ad_close_metadata(&ad);
345 }
346
347 #define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
348 #define MODE(b) ((st->st_mode & (b)) == (b))
349
350 static void print_mode(const struct stat *st)
351 {
352     if (TYPE(S_IFBLK))
353         putchar('b');
354     else if (TYPE(S_IFCHR))
355         putchar('c');
356     else if (TYPE(S_IFDIR))
357         putchar('d');
358     else if (TYPE(S_IFIFO))
359         putchar('p');
360     else if (TYPE(S_IFREG))
361         putchar('-');
362     else if (TYPE(S_IFLNK))
363         putchar('l');
364     else if (TYPE(S_IFSOCK))
365         putchar('s');
366     else
367         putchar('?');
368     putchar(MODE(S_IRUSR) ? 'r' : '-');
369     putchar(MODE(S_IWUSR) ? 'w' : '-');
370     if (MODE(S_ISUID)) {
371         if (MODE(S_IXUSR))
372             putchar('s');
373         else
374             putchar('S');
375     }
376     else if (MODE(S_IXUSR))
377         putchar('x');
378     else
379         putchar('-');
380     putchar(MODE(S_IRGRP) ? 'r' : '-');
381     putchar(MODE(S_IWGRP) ? 'w' : '-');
382     if (MODE(S_ISGID)) {
383         if (MODE(S_IXGRP))
384             putchar('s');
385         else
386             putchar('S');
387     }
388     else if (MODE(S_IXGRP))
389         putchar('x');
390     else
391         putchar('-');
392     putchar(MODE(S_IROTH) ? 'r' : '-');
393     putchar(MODE(S_IWOTH) ? 'w' : '-');
394     if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
395         if (MODE(S_IXOTH))
396             putchar('t');
397         else
398             putchar('T');
399     }
400     else if (MODE(S_IXOTH))
401         putchar('x');
402     else
403         putchar('-');
404 }
405 #undef TYPE
406 #undef MODE
407
408 static int ad_print(char *path, const struct stat *st, afpvol_t *vol)
409 {
410     if ( ! ls_l) {
411         printf("%s  ", path);
412         if (ls_d)
413             printf("\n");
414         return 0;
415     }
416
417     /* Long output */
418     if (ls_u) {
419         print_mode(st);
420         print_numlinks(st);
421         print_owner(st);
422         print_group(st);
423         print_size(st);
424         print_date(st);
425     }
426     print_flags(path, vol, st);
427     printf("  %s\n", path);    
428
429
430     return 0;
431 }
432
433 static int ad_ls_r(char *path, afpvol_t *vol)
434 {
435     int ret = 0, cwd, dirprinted = 0, dirempty;
436     const char *name;
437     char *tmp;
438     static char cwdpath[MAXPATHLEN+1];
439     DIR *dp;
440     struct dirent *ep;
441     static struct stat st;      /* Save some stack space */
442
443     if ( first)
444         cwdpath[0] = 0;
445     else
446         strcat(cwdpath, "/");
447
448     strcat(cwdpath, path);
449     first = 0;
450
451     if (lstat(path, &st) < 0) {
452         perror("Can't stat");
453         return -1;
454     }
455     /* If its a file or a dir with -d option call ad_print and return */
456     if (S_ISREG(st.st_mode) || ls_d)
457         return ad_print(path, &st, vol);
458
459     /* Its a dir: chdir to it remembering where we started */
460     if ((cwd = open(".", O_RDONLY)) == -1) {
461         perror("Cant open .");
462         return -1;
463     }
464     if (chdir(path) != 0) {
465         perror("Cant chdir");
466         close(cwd);
467         return -1;
468     }
469
470     if ((dp = opendir (".")) == NULL) {
471         perror("Couldn't opendir .");
472         return -1;
473     }
474
475     /* First run: print everything */
476     dirempty = 1;
477     while ((ep = readdir (dp))) {
478         /* Check if its "." or ".." */
479         if (DIR_DOT_OR_DOTDOT(ep->d_name))
480             continue;
481
482         /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
483         if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
484             continue;
485
486         if ((ep->d_name[0] == '.') && ! ls_a)
487             continue;
488
489         dirempty = 0;
490
491         if (recursion && ! dirprinted) {
492             printf("\n%s:\n", cwdpath);
493             dirprinted = 1;
494         }
495
496         if (lstat(ep->d_name, &st) < 0) {
497             perror("Can't stat");
498             return -1;
499         }
500
501         ret = ad_print(ep->d_name, &st, vol);
502         if (ret != 0)
503             goto exit;
504     }
505
506     if (! ls_l && ! dirempty)
507         printf("\n");
508
509     /* Second run: recurse to dirs */
510     if (ls_R) {
511         rewinddir(dp);
512         while ((ep = readdir (dp))) {
513             /* Check if its "." or ".." */
514             if (DIR_DOT_OR_DOTDOT(ep->d_name))
515                 continue;
516
517             /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
518             if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
519                 continue;
520
521             if ((ret = lstat(ep->d_name, &st)) < 0) {
522                 perror("Can't stat");
523                 goto exit;
524             }
525
526             /* Recursion */
527             if (S_ISDIR(st.st_mode)) {
528                 recursion = 1;
529                 ret = ad_ls_r(ep->d_name, vol);
530             }
531             if (ret != 0)
532                 goto exit;
533         }
534     }
535
536 exit:
537     closedir(dp);
538     fchdir(cwd);
539     close(cwd);
540
541     tmp = strrchr(cwdpath, '/');
542     if (tmp)
543         *tmp = 0;
544
545     return ret;
546 }
547
548 int ad_ls(int argc, char **argv)
549 {
550     int c, firstarg;
551     afpvol_t vol;
552     struct stat st;
553
554     while ((c = getopt(argc, argv, ":adlRu")) != -1) {
555         switch(c) {
556         case 'a':
557             ls_a = 1;
558             break;
559         case 'd':
560             ls_d = 1;
561             break;
562         case 'l':
563             ls_l = 1;
564             break;
565         case 'R':
566             ls_R = 1;
567             break;
568         case 'u':
569             ls_u = 1;
570             break;
571         case ':':
572         case '?':
573             usage_ls();
574             return -1;
575             break;
576         }
577
578     }
579
580     if ((argc - optind) == 0) {
581         newvol(".", &vol);
582         ad_ls_r(".", &vol);
583         freevol(&vol);
584     }
585     else {
586         int havefile = 0;
587
588         firstarg = optind;
589
590         /* First run: only print files from argv paths */
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 }