]> arthur.barton.de Git - netatalk.git/blob - bin/megatron/megatron.c
Writing metadata xattr on directories with sticky bit set, FR#94
[netatalk.git] / bin / megatron / megatron.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif /* HAVE_CONFIG_H */
4
5 #include <sys/types.h>
6 #include <sys/param.h>
7 #include <sys/stat.h>
8 #include <sys/uio.h>
9 #include <fcntl.h>
10 #include <time.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <netatalk/endian.h>
15 #include "asingle.h"
16 #include "megatron.h"
17 #include "hqx.h"
18 #include "macbin.h"
19 #include "nad.h"
20
21 char            *forkname[] = { "data", "resource" };
22 static char     forkbuf[8192];
23 static char     *name[] = { "unhex",
24                             "unbin",
25                             "unsingle",
26                             "macbinary",
27                             "hqx2bin",
28                             "single2bin",
29                             "nadheader",
30                             "binheader",
31                             "megatron" };
32
33 static int from_open(int un, char *file, struct FHeader *fh, int flags)
34 {
35     switch ( un ) {
36         case MEGATRON :
37         case HEX2NAD :
38         case HEX2BIN :
39             return( hqx_open( file, O_RDONLY, fh, flags ));
40             break;
41         case BIN2NAD :
42         case BINHEADER:
43             return( bin_open( file, O_RDONLY, fh, flags ));
44             break;
45         case NAD2BIN :
46         case NADHEADER:
47             return( nad_open( file, O_RDONLY, fh, flags ));
48             break;
49         case SINGLE2NAD :
50         case SINGLE2BIN :
51             return( single_open( file, O_RDONLY, fh, flags ));
52         default :
53             return( -1 );
54             break;
55     }
56 }
57
58 static ssize_t from_read(int un, int fork, char *buf, size_t len)
59 {
60     switch ( un ) {
61         case MEGATRON :
62         case HEX2NAD :
63         case HEX2BIN :
64             return( hqx_read( fork, buf, len ));
65             break;
66         case BIN2NAD :
67             return( bin_read( fork, buf, len ));
68             break;
69         case NAD2BIN :
70             return( nad_read( fork, buf, len ));
71             break;
72         case SINGLE2NAD :
73         case SINGLE2BIN :
74             return( single_read( fork, buf, len ));
75         default :
76             return( -1 );
77             break;
78     }
79 }
80
81 static int from_close(int un)
82 {
83     switch ( un ) {
84         case MEGATRON :
85         case HEX2NAD :
86         case HEX2BIN :
87             return( hqx_close( KEEP ));
88             break;
89         case BIN2NAD :
90             return( bin_close( KEEP ));
91             break;
92         case NAD2BIN :
93             return( nad_close( KEEP ));
94             break;
95         case SINGLE2NAD :
96         case SINGLE2BIN :
97             return( single_close( KEEP ));
98         default :
99             return( -1 );
100             break;
101     }
102 }
103
104 static int to_open(int to, char *file, struct FHeader *fh, int flags)
105 {
106     switch ( to ) {
107         case MEGATRON :
108         case HEX2NAD :
109         case BIN2NAD :
110         case SINGLE2NAD :
111             return( nad_open( file, O_RDWR|O_CREAT|O_EXCL, fh, flags ));
112             break;
113         case NAD2BIN :
114         case HEX2BIN :
115         case SINGLE2BIN :
116             return( bin_open( file, O_RDWR|O_CREAT|O_EXCL, fh, flags ));
117             break;
118         default :
119             return( -1 );
120             break;
121     }
122 }
123
124 static ssize_t to_write(int to, int fork, size_t bufc)
125 {
126     switch ( to ) {
127         case MEGATRON :
128         case HEX2NAD :
129         case BIN2NAD :
130         case SINGLE2NAD :
131             return( nad_write( fork, forkbuf, bufc ));
132             break;
133         case NAD2BIN :
134         case HEX2BIN :
135         case SINGLE2BIN :
136             return( bin_write( fork, forkbuf, bufc ));
137             break;
138         default :
139             return( -1 );
140             break;
141     }
142 }
143
144 static int to_close(int to, int keepflag)
145 {
146     switch ( to ) {
147         case MEGATRON :
148         case HEX2NAD :
149         case BIN2NAD :
150         case SINGLE2NAD :
151             return( nad_close( keepflag ));
152             break;
153         case NAD2BIN :
154         case HEX2BIN :
155         case SINGLE2BIN :
156             return( bin_close( keepflag ));
157             break;
158         default :
159             return( -1 );
160             break;
161     }
162 }
163
164 static int megatron( char *path, int module, char *newname, int flags)
165 {
166     struct stat         st;
167     struct FHeader      fh;
168     ssize_t             bufc;
169     int                 fork;
170     size_t              forkred;
171
172 /*
173  * If the source file is not stdin, make sure it exists and
174  * that it is not a directory.
175  */
176
177     if ( strcmp( path, STDIN ) != 0 ) {
178         if ( stat( path, &st ) < 0 ) {
179             perror( path );
180             return( -1 );
181         }
182         if ( S_ISDIR( st.st_mode )) {
183             fprintf( stderr, "%s is a directory.\n", path );
184             return( 0 );
185         }
186     }
187
188 /*
189  * Open the source file and fill in the file header structure.
190  */
191
192     memset( &fh, 0, sizeof( fh ));
193     if ( from_open( module, path, &fh, flags ) < 0 ) {
194         return( -1 );
195     }
196
197     if ( flags & OPTION_HEADERONLY ) {
198         time_t t;
199         char buf[5] = "";
200         int i;
201
202         printf("name:               %s\n",fh.name);
203         printf("comment:            %s\n",fh.comment);
204         memcpy(&buf, &fh.finder_info.fdCreator, sizeof(u_int32_t));
205         printf("creator:            '%4s'\n", buf);
206         memcpy(&buf, &fh.finder_info.fdType, sizeof(u_int32_t));
207         printf("type:               '%4s'\n", buf);
208         for(i=0; i < NUMFORKS; ++i) 
209           printf("fork length[%d]:     %u\n", i, ntohl(fh.forklen[i]));
210         t = AD_DATE_TO_UNIX(fh.create_date);
211         printf("creation date:      %s", ctime(&t));
212         t = AD_DATE_TO_UNIX(fh.mod_date);
213         printf("modification date:  %s", ctime(&t));
214         t = AD_DATE_TO_UNIX(fh.backup_date);
215         printf("backup date:        %s", ctime(&t));
216         return( from_close( module ));
217     }
218     
219 /*
220  * Open the target file and write out the file header info.
221  * set the header to the new filename if it has been supplied.
222  */
223
224     if (*newname)
225         strcpy(fh.name, newname);
226
227     if ( to_open( module, path, &fh, flags ) < 0 ) {
228         (void)from_close( module );
229         return( -1 );
230     }
231
232 /*
233  * Read in and write out the data and resource forks.
234  */
235
236     for ( fork = 0; fork < NUMFORKS ; fork++ ) {
237         forkred = 0;
238         while(( bufc = from_read( module, fork, forkbuf, sizeof( forkbuf )))
239                 > 0 ) {
240             if ( to_write( module, fork, bufc ) != bufc ) {
241                 fprintf( stderr, "%s: Probable write error\n", path );
242                 to_close( module, TRASH );
243                 (void)from_close( module );
244                 return( -1 );
245             }
246             forkred += bufc;
247         }
248 #if DEBUG
249         fprintf( stderr, "megatron: forkred is \t\t%d\n", forkred );
250         fprintf( stderr, "megatron: fh.forklen[%d] is \t%d\n", fork, 
251                 ntohl( fh.forklen[ fork ] ));
252 #endif /* DEBUG */
253         if (( bufc < 0 ) || ( forkred != ntohl( fh.forklen[ fork ] ))) {
254             fprintf( stderr, "%s: Problem with input, dude\n", path );
255             to_close( module, TRASH );
256             (void)from_close( module );
257             return( -1 );
258         }
259     }
260
261 /*
262  * Close up the files, and get out of here.
263  */
264
265     if ( to_close( module, KEEP ) < 0 ) {
266         perror( "megatron:" );
267         (void)to_close( module, TRASH );
268     }
269     return( from_close( module ));
270 }
271
272 int main(int argc, char **argv)
273 {
274     int         rc, c;
275     int         rv = 0;
276     int         converts = sizeof(name) / sizeof(char *);
277     int         module = -1;
278     int         flags = 0;
279     char        *progname, newname[ADEDLEN_NAME + 1];
280
281     progname = strrchr( argv[ 0 ], '/' );
282     if (( progname == NULL ) || ( *progname == '\0' )) {
283         progname = argv[ 0 ];
284     } else progname++;
285
286 #if DEBUG
287     if ( CONVERTS != converts ) {
288         fprintf( stderr, "megatron: list of program links messed up\n" );
289         return( -1 );
290     }
291 #endif /* DEBUG */
292
293     for ( c = 0 ; (( c < converts ) && ( module < 0 )) ; ++c ) {
294         if ( strcmp( name[ c ], progname ) == 0 ) module = c;
295     }
296     if ( module == -1 ) module = ( converts - 1 );
297     if ((module == NADHEADER) || (module == BINHEADER))
298       flags |= OPTION_HEADERONLY;
299
300     if ( argc == 1 ) {
301         return( megatron( STDIN, module, newname, flags ));
302     }
303
304     *newname = '\0';
305     for ( c = 1 ; c < argc ; ++c ) {
306         if ( strcmp( argv [ c ], "--version" ) == 0 ) {
307             printf("%s (Netatalk %s megatron)\n", argv[0], VERSION);
308             return( -1 );
309         }
310         if ( strcmp( argv [ c ], "-v" ) == 0 ) {
311             printf("%s (Netatalk %s megatron)\n", argv[0], VERSION);
312             return( -1 );
313         }
314         if ( strcmp( argv [ c ], "--header" ) == 0 ) {
315             flags |= OPTION_HEADERONLY;
316             continue;
317         }
318         if ( strcmp( argv [ c ], "--filename" ) == 0 ) {
319           if(++c < argc) strncpy(newname,argv[c], ADEDLEN_NAME);
320           continue;
321         }
322         if (strcmp(argv[c], "--stdout") == 0) {
323           flags |= OPTION_STDOUT;
324           continue;
325         }
326         if (strcmp(argv[c], "--euc") == 0) {
327           flags |= OPTION_EUCJP;
328           continue;
329         }  
330         if (strcmp(argv[c], "--sjis") == 0) {
331           flags |= OPTION_SJIS;
332           continue;
333         }  
334         rc = megatron( argv[ c ], module, newname, flags);
335         if ( rc != 0 ) {
336             rv = rc;
337         }
338         *newname = '\0';
339     }
340     return( rv );
341 }