2 $Id: ad_ls.c,v 1.1 2009-09-01 14:28:07 franklahm Exp $
4 Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
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.
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.
19 #endif /* HAVE_CONFIG_H */
22 #include <sys/types.h>
36 #include <atalk/adouble.h>
37 #include <atalk/cnid.h>
38 #include <atalk/volinfo.h>
41 #define ADv2_DIRNAME ".AppleDouble"
43 #define DIR_DOT_OR_DOTDOT(a) \
44 ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
53 /* Used for pretty printing */
57 static char *netatalk_dirs[] = {
64 static char *labels[] = {
76 Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
77 Returns pointer to name or NULL.
79 static const char *check_netatalk_dirs(const char *name)
83 for (c=0; netatalk_dirs[c]; c++) {
84 if ((strcmp(name, netatalk_dirs[c])) == 0)
85 return netatalk_dirs[c];
91 static void usage_ls()
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"
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"
121 static void print_numlinks(const struct stat *statp)
123 printf("%5ld", (long)statp->st_nlink);
126 static void print_owner(const struct stat *statp)
128 struct passwd *pwd = getpwuid(statp->st_uid);
131 printf(" %-8ld", (long)statp->st_uid);
133 printf(" %-8s", pwd->pw_name);
136 static void print_group(const struct stat *statp)
138 struct group *grp = getgrgid(statp->st_gid);
141 printf(" %-8ld", (long)statp->st_gid);
143 printf(" %-8s", grp->gr_name);
146 static void print_size(const struct stat *statp)
148 switch (statp->st_mode & S_IFMT) {
151 printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),
152 (unsigned)(statp->st_rdev & 0xFF));
155 printf("%9lu", (unsigned long)statp->st_size);
159 static void print_date(const struct stat *statp)
165 if (time(&now) == -1) {
166 printf(" ????????????");
169 diff = difftime(now, statp->st_mtime);
170 if (diff < 0 || diff > 60 * 60 * 24 * 182.5)
174 strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));
178 static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
183 uint16_t FinderFlags;
184 uint16_t AFPattributes;
185 char type[5] = "----";
186 char creator[5] = "----";
188 if (S_ISDIR(st->st_mode))
189 adflags = ADFLAGS_DIR;
191 if (vol->volinfo.v_path == NULL)
194 ad_init(&ad, vol->volinfo.v_adouble, vol->volinfo.v_ad_options);
196 if ( ad_metadata(path, adflags, &ad) < 0 )
199 FinderInfo = ad_entry(&ad, ADEID_FINDERI);
201 memcpy(&FinderFlags, FinderInfo + 8, 2);
202 FinderFlags = ntohs(FinderFlags);
204 memcpy(type, FinderInfo, 4);
205 memcpy(creator, FinderInfo + 4, 4);
207 ad_getattr(&ad, &AFPattributes);
208 AFPattributes = ntohs(AFPattributes);
211 Finder flags. Lowercase means valid, uppercase means invalid because
212 object is a dir and flag is only valid for files.
215 if (FinderFlags & FINDERINFO_ISONDESK)
220 if (FinderFlags & FINDERINFO_HIDEEXT)
225 if (FinderFlags & FINDERINFO_ISHARED) {
226 if (adflags & ADFLAGS_DIR)
233 if (FinderFlags & FINDERINFO_HASNOINITS) {
234 if (adflags & ADFLAGS_DIR)
241 if (FinderFlags & FINDERINFO_HASBEENINITED)
246 if (FinderFlags & FINDERINFO_HASCUSTOMICON)
251 if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
252 if (adflags & ADFLAGS_DIR)
259 if (FinderFlags & FINDERINFO_NAMELOCKED)
264 if (FinderFlags & FINDERINFO_HASBUNDLE)
269 if (FinderFlags & FINDERINFO_INVISIBLE)
274 if (FinderFlags & FINDERINFO_ISALIAS)
282 if (AFPattributes & ATTRBIT_SYSTEM)
287 if (AFPattributes & ATTRBIT_NOWRITE) {
288 if (adflags & ADFLAGS_DIR)
295 if (AFPattributes & ATTRBIT_BACKUP)
300 if (AFPattributes & ATTRBIT_NORENAME)
305 if (AFPattributes & ATTRBIT_NODELETE)
310 if (AFPattributes & ATTRBIT_NOCOPY) {
311 if (adflags & ADFLAGS_DIR)
319 printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
324 if (isalnum(type[i]))
331 if (isalnum(creator[i]))
339 uint32_t cnid = ad_forcegetid(&ad);
341 printf(" %10u ", ntohl(cnid));
343 printf(" !ADVOL_CACHE ");
345 ad_close_metadata(&ad);
348 #define TYPE(b) ((st->st_mode & (S_IFMT)) == (b))
349 #define MODE(b) ((st->st_mode & (b)) == (b))
351 static void print_mode(const struct stat *st)
355 else if (TYPE(S_IFCHR))
357 else if (TYPE(S_IFDIR))
359 else if (TYPE(S_IFIFO))
361 else if (TYPE(S_IFREG))
363 else if (TYPE(S_IFLNK))
365 else if (TYPE(S_IFSOCK))
369 putchar(MODE(S_IRUSR) ? 'r' : '-');
370 putchar(MODE(S_IWUSR) ? 'w' : '-');
377 else if (MODE(S_IXUSR))
381 putchar(MODE(S_IRGRP) ? 'r' : '-');
382 putchar(MODE(S_IWGRP) ? 'w' : '-');
389 else if (MODE(S_IXGRP))
393 putchar(MODE(S_IROTH) ? 'r' : '-');
394 putchar(MODE(S_IWOTH) ? 'w' : '-');
395 if (MODE(S_IFDIR) && MODE(S_ISVTX)) {
401 else if (MODE(S_IXOTH))
409 int ad_print(char *path, const struct stat *st, afpvol_t *vol)
427 print_flags(path, vol, st);
428 printf(" %s\n", path);
434 int ad_ls_r(char *path, afpvol_t *vol)
436 int ret = 0, cwd, dirprinted = 0, dirempty;
439 static char cwdpath[MAXPATHLEN+1];
442 static struct stat st; /* Save some stack space */
447 strcat(cwdpath, "/");
449 strcat(cwdpath, path);
452 if (lstat(path, &st) < 0) {
453 perror("Can't stat");
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);
460 /* Its a dir: chdir to it remembering where we started */
461 if ((cwd = open(".", O_RDONLY)) == -1) {
462 perror("Cant open .");
465 if (chdir(path) != 0) {
466 perror("Cant chdir");
471 if ((dp = opendir (".")) == NULL) {
472 perror("Couldn't opendir .");
476 /* First run: print everything */
478 while ((ep = readdir (dp))) {
479 /* Check if its "." or ".." */
480 if (DIR_DOT_OR_DOTDOT(ep->d_name))
483 /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
484 if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
487 if ((ep->d_name[0] == '.') && ! ls_a)
492 if (recursion && ! dirprinted) {
493 printf("\n%s:\n", cwdpath);
497 if (lstat(ep->d_name, &st) < 0) {
498 perror("Can't stat");
502 ret = ad_print(ep->d_name, &st, vol);
507 if (! ls_l && ! dirempty)
510 /* Second run: recurse to dirs */
513 while ((ep = readdir (dp))) {
514 /* Check if its "." or ".." */
515 if (DIR_DOT_OR_DOTDOT(ep->d_name))
518 /* Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop" */
519 if ((name = check_netatalk_dirs(ep->d_name)) != NULL)
522 if (lstat(ep->d_name, &st) < 0) {
523 perror("Can't stat");
528 if (S_ISDIR(st.st_mode)) {
530 ret = ad_ls_r(ep->d_name, vol);
542 tmp = strrchr(cwdpath, '/');
549 int ad_ls(int argc, char **argv)
555 while ((c = getopt(argc, argv, ":adlRu")) != -1) {
581 if ((argc - optind) == 0) {
589 /* First run: only print files from argv paths */
591 while(optind < argc) {
592 if (stat(argv[optind], &st) != 0)
594 if (S_ISDIR(st.st_mode))
601 newvol(argv[optind], &vol);
602 ad_ls_r(argv[optind], &vol);
607 if (havefile && (! ls_l))
610 /* Second run: print dirs */
612 while(optind < argc) {
613 if (stat(argv[optind], &st) != 0)
615 if ( ! S_ISDIR(st.st_mode))
617 if ((optind > firstarg) || havefile)
618 printf("\n%s:\n", argv[optind]);
623 newvol(argv[optind], &vol);
624 ad_ls_r(argv[optind], &vol);