2 Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
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.
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.
17 #endif /* HAVE_CONFIG_H */
20 #include <sys/types.h>
34 #include <atalk/adouble.h>
35 #include <atalk/cnid.h>
38 #define ADv2_DIRNAME ".AppleDouble"
40 #define DIR_DOT_OR_DOTDOT(a) \
41 ((strcmp(a, ".") == 0) || (strcmp(a, "..") == 0))
43 static volatile sig_atomic_t alarmed;
52 /* Used for pretty printing */
56 static char *netatalk_dirs[] = {
63 static char *labels[] = {
76 catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
79 static void sig_handler(int signo)
85 static void set_signal(void)
89 sv.sa_handler = sig_handler;
90 sv.sa_flags = SA_RESTART;
91 sigemptyset(&sv.sa_mask);
92 if (sigaction(SIGTERM, &sv, NULL) < 0)
93 ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
95 if (sigaction(SIGINT, &sv, NULL) < 0)
96 ERROR("error in sigaction(SIGINT): %s", strerror(errno));
98 memset(&sv, 0, sizeof(struct sigaction));
99 sv.sa_handler = SIG_IGN;
100 sigemptyset(&sv.sa_mask);
102 if (sigaction(SIGABRT, &sv, NULL) < 0)
103 ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
105 if (sigaction(SIGHUP, &sv, NULL) < 0)
106 ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
108 if (sigaction(SIGQUIT, &sv, NULL) < 0)
109 ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
113 Check for netatalk special folders e.g. ".AppleDB" or ".AppleDesktop"
114 Returns pointer to name or NULL.
116 static const char *check_netatalk_dirs(const char *name)
120 for (c=0; netatalk_dirs[c]; c++) {
121 if ((strcmp(name, netatalk_dirs[c])) == 0)
122 return netatalk_dirs[c];
128 static void usage_set(void)
131 "Usage: ad set file|dir [-t TYPE] [-c CREATOR] [-l label] [-f flags]\n\n"
132 " FinderFlags (valid for (f)ile and/or (d)irectory):\n"
133 " d = On Desktop (f/d)\n"
134 " e = Hidden extension (f/d)\n"
135 " m = Shared (can run multiple times) (f)\n"
136 " n = No INIT resources (f)\n"
137 " i = Inited (f/d)\n"
138 " c = Custom icon (f/d)\n"
139 " t = Stationery (f)\n"
140 " s = Name locked (f/d)\n"
141 " b = Bundle (f/d)\n"
142 " v = Invisible (f/d)\n"
143 " a = Alias file (f/d)\n\n"
145 " y = System (f/d)\n"
146 " w = No write (f)\n"
147 " p = Needs backup (f/d)\n"
148 " r = No rename (f/d)\n"
149 " l = No delete (f/d)\n"
150 " o = No copy (f)\n\n"
151 " Note: any letter appearing in uppercase means the flag is set\n"
152 " but it's a directory for which the flag is not allowed.\n"
156 static void print_flags(char *path, afpvol_t *vol, const struct stat *st)
161 uint16_t FinderFlags;
162 uint16_t AFPattributes;
163 char type[5] = "----";
164 char creator[5] = "----";
168 if (S_ISDIR(st->st_mode))
169 adflags = ADFLAGS_DIR;
171 if (vol->vol->v_path == NULL)
174 ad_init(&ad, vol->vol);
176 if ( ad_metadata(path, adflags, &ad) < 0 )
179 FinderInfo = ad_entry(&ad, ADEID_FINDERI);
181 memcpy(&FinderFlags, FinderInfo + 8, 2);
182 FinderFlags = ntohs(FinderFlags);
184 memcpy(type, FinderInfo, 4);
185 memcpy(creator, FinderInfo + 4, 4);
187 ad_getattr(&ad, &AFPattributes);
188 AFPattributes = ntohs(AFPattributes);
191 Finder flags. Lowercase means valid, uppercase means invalid because
192 object is a dir and flag is only valid for files.
195 if (FinderFlags & FINDERINFO_ISONDESK)
200 if (FinderFlags & FINDERINFO_HIDEEXT)
205 if (FinderFlags & FINDERINFO_ISHARED) {
206 if (adflags & ADFLAGS_DIR)
213 if (FinderFlags & FINDERINFO_HASNOINITS) {
214 if (adflags & ADFLAGS_DIR)
221 if (FinderFlags & FINDERINFO_HASBEENINITED)
226 if (FinderFlags & FINDERINFO_HASCUSTOMICON)
231 if (FinderFlags & FINDERINFO_ISSTATIONNERY) {
232 if (adflags & ADFLAGS_DIR)
239 if (FinderFlags & FINDERINFO_NAMELOCKED)
244 if (FinderFlags & FINDERINFO_HASBUNDLE)
249 if (FinderFlags & FINDERINFO_INVISIBLE)
254 if (FinderFlags & FINDERINFO_ISALIAS)
262 if (AFPattributes & ATTRBIT_SYSTEM)
267 if (AFPattributes & ATTRBIT_NOWRITE) {
268 if (adflags & ADFLAGS_DIR)
275 if (AFPattributes & ATTRBIT_BACKUP)
280 if (AFPattributes & ATTRBIT_NORENAME)
285 if (AFPattributes & ATTRBIT_NODELETE)
290 if (AFPattributes & ATTRBIT_NOCOPY) {
291 if (adflags & ADFLAGS_DIR)
299 printf(" %s ", labels[(FinderFlags & FINDERINFO_COLOR) >> 1]);
303 if (isalnum(type[i]))
310 if (isalnum(creator[i]))
318 cnid = ad_forcegetid(&ad);
320 printf(" %10u ", ntohl(cnid));
322 printf(" !ADVOL_CACHE ");
324 ad_close(&ad, ADFLAGS_HF);
327 int ad_ls(int argc, char **argv, AFPObj *obj)
333 while ((c = getopt(argc, argv, ":adlRu")) != -1) {
362 if ((argc - optind) == 0) {
363 openvol(obj, ".", &vol);
372 /* First run: only print files from argv paths */
373 while(optind < argc) {
374 if (stat(argv[optind], &st) != 0)
376 if (S_ISDIR(st.st_mode))
383 openvol(obj, argv[optind], &vol);
384 ad_ls_r(argv[optind], &vol);
389 if (havefile && (! ls_l))
392 /* Second run: print dirs */
394 while(optind < argc) {
395 if (stat(argv[optind], &st) != 0)
397 if ( ! S_ISDIR(st.st_mode))
399 if ((optind > firstarg) || havefile)
400 printf("\n%s:\n", argv[optind]);
405 openvol(obj, argv[optind], &vol);
406 ad_ls_r(argv[optind], &vol);