]> arthur.barton.de Git - netatalk.git/blob - bin/afile/achfile.c
massive commenting/autoconf changes
[netatalk.git] / bin / afile / achfile.c
1 /*
2  * $Id: achfile.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
3  *
4     afile - determine the MacOS creator/type of files
5
6     Copyright (C) 2001 Sebastian Rittau.
7     All rights reserved.
8
9     This file may be distributed and/or modfied under the terms of the
10     following license:
11
12     Redistribution and use in source and binary forms, with or without
13     modification, are permitted provided that the following conditions
14     are met:
15     1. Redistributions of source code must retain the above copyright
16        notice, this list of conditions and the following disclaimer.
17     2. Redistributions in binary form must reproduce the above copyright
18        notice, this list of conditions and the following disclaimer in the
19        documentation and/or other materials provided with the distribution.
20     3. Neither the name of the author nor the names of its contributors
21        may be used to endorse or promote products derived from this software
22        without specific prior written permission.
23
24     THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27     ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30     OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34     SUCH DAMAGE.
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif /* HAVE_CONFIG_H */
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <errno.h>
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif /* HAVE_FCNTL_H */
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif /* HAVE_UNISTD_H */
53
54 #include <atalk/adouble.h>
55
56 #include "common.h"
57
58 /* Please change this whenever you change this file. */
59 #define ACHFILE_VERSION "1.0.0"
60
61 /* Global Variables */
62 const char *type    = NULL;
63 const char *creator = NULL;
64
65
66 /* Print usage information. */
67 void usage(char *prog)
68 {
69   fprintf(stderr, "Usage: %s [-t TYPE] [-c CREATOR] FILE ...\n", prog);
70 }
71
72 /* Print extensive help. */
73 void help(char *prog)
74 {
75   usage(prog);
76   fprintf(stderr,
77           "\n"
78           "Change the MacOS creator/type of FILEs.\n"
79           "\n"
80           "  -t, --type=TYPE        choose type\n"
81           "  -c, --creator=CREATOR  choose creator\n"
82           "  -h, --help             show this help and exit\n"
83           "  -v, --version          show version information and exit\n");
84 }
85
86 /* Print the version. */
87 void version()
88 {
89   fprintf(stderr, "achfile " ACHFILE_VERSION " (netatalk " VERSION ")\n");
90 }
91
92 /* Argument Handling
93  * known options: -t, -c, -h, -v
94  * known long options: --help, --version
95  */
96 #define OPTSTRING "t:c:hv-:"
97 const char *get_long_arg(int argc, char *argv[], const char *arg, const char *oa) {
98   switch (*oa) {
99   case '=':
100     return &oa[1];
101   case '\0':
102     if (optind == argc) {
103       fprintf(stderr, "%s: option \'%s\' requires an argument\n", argv[0], arg);
104       return NULL;
105     }
106     return argv[optind++];
107   default:
108     fprintf(stderr, "%s: unrecognized option \'%s\'\n", argv[0], arg);
109     usage(argv[0]);
110     return NULL;
111   }
112 }
113
114 int parse_args(int argc, char *argv[])
115 {
116   int c;
117   const char *longarg;
118
119   /* iterate through the command line */
120   while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
121     switch (c) {
122     case 'h':
123       help(argv[0]);
124       exit(0);
125     case 'v':
126       version();
127       exit(0);
128     case 't':
129       type = optarg;
130       break;
131     case 'c':
132       creator = optarg;
133       break;
134     case '-':
135       if (strcmp(optarg, "help") == 0) {
136         help(argv[0]);
137         exit(0);
138       }
139       if (strcmp(optarg, "version") == 0) {
140         version();
141         exit(0);
142       }
143       if (strncmp(optarg, "type", 4) == 0) {
144         longarg = get_long_arg(argc, argv, "type", &optarg[4]);
145         if (!longarg)
146           return -1;
147         type = longarg;
148       } else if (strncmp(optarg, "creator", 7) == 0) {
149         longarg = get_long_arg(argc, argv, "creator", &optarg[7]);
150         if (!longarg)
151           return -1;
152         creator = longarg;
153       }
154       break;
155     default:
156       usage(argv[0]);
157       return -1;
158     }
159   }
160
161   /* At least one file argument is required. */
162   if (argc == optind) {
163     usage(argv[0]);
164     return -1;
165   }
166
167   /* Either type or creator is required. */
168   if (!type && !creator) {
169     fprintf(stderr, "achfile: either type or creator must be specified\n");
170     return -1;
171   }
172
173   /* Type and creator must be exactly four characters long. */
174   if ((type && strlen(type) != 4) || (creator && strlen(creator) != 4)) {
175     fprintf(stderr, "achfile: type and creator must be four character IDs\n");
176     return -1;
177   }
178
179   return 0;
180 }
181
182
183 /* Change the owner/creator of each file specified on the command line. */
184 int handle_file(const char *filename)
185 {
186   int fd;
187   struct stat statbuf;
188   char *adname;
189   ssize_t sz;
190   char buf[AD_DATASZ];
191   struct adouble *ad = (struct adouble *) &buf;
192
193   if (stat(filename, &statbuf) == -1) {
194     fprintf(stderr, "achfile:%s: %s\n", filename, strerror(errno));
195     return -1;
196   }
197
198   adname = dataname_to_adname(filename);
199   fd = open(adname, O_RDWR, 0);
200   if (fd == -1) {
201     if (errno == ENOENT)
202       fprintf(stderr, "achfile:%s: no resource fork\n", filename);
203     else
204       fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
205     free(adname);
206     return -1;
207   }
208   sz = read(fd, buf, AD_DATASZ);
209   if (sz == -1) {
210     fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
211     free(adname);
212     close(fd);
213     return -1;
214   } else if (sz < AD_DATASZ) {
215     fprintf(stderr, "achfile:%s: corrupt resource fork\n", filename);
216     free(adname);
217     close(fd);
218     return -1;
219   }
220   if (ad->ad_magic != AD_MAGIC) {
221     fprintf(stderr, "achfile:%s: corrupt resource fork\n", filename);
222     free(adname);
223     close(fd);
224     return -1;
225   }
226
227   /* Change Type */
228   if (type) {
229     buf[ADEDOFF_FINDERI + 0] = type[0];
230     buf[ADEDOFF_FINDERI + 1] = type[1];
231     buf[ADEDOFF_FINDERI + 2] = type[2];
232     buf[ADEDOFF_FINDERI + 3] = type[3];
233  }
234
235   /* Change Creator */
236   if (creator) {
237     buf[ADEDOFF_FINDERI + 4] = creator[0];
238     buf[ADEDOFF_FINDERI + 5] = creator[1];
239     buf[ADEDOFF_FINDERI + 6] = creator[2];
240     buf[ADEDOFF_FINDERI + 7] = creator[3];
241  }
242
243   /* Write file back to disk. */
244   if (lseek(fd, 0, SEEK_SET) == -1) {
245     fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
246     free(adname);
247     close(fd);
248     return -1;
249   }
250   if (write(fd, &buf, AD_DATASZ) < AD_DATASZ) {
251     fprintf(stderr, "achfile:%s: %s\n", adname, strerror(errno));
252     free(adname);
253     close(fd);
254     return -1;
255   }
256
257   /* Clean Up */
258   free(adname);
259   close(fd);
260
261   return 0;
262 }
263
264
265 int main(int argc, char *argv[])
266 {
267   /* argument handling */
268   if (parse_args(argc, argv) == -1)
269     return 1;
270
271   while (optind < argc)
272     handle_file(argv[optind++]);
273
274   return 0;
275 }