~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to bin/megatron/asingle.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: asingle.c,v 1.8.4.1 2003/08/09 14:30:21 srittau Exp $
 
3
 */
 
4
 
 
5
#ifdef HAVE_CONFIG_H
 
6
#include "config.h"
 
7
#endif /* HAVE_CONFIG_H */
 
8
 
 
9
#include <sys/types.h>
 
10
#include <sys/uio.h>
 
11
#include <sys/time.h>
 
12
#include <sys/param.h>
 
13
#ifdef HAVE_FCNTL_H
 
14
#include <fcntl.h>
 
15
#endif /* HAVE_FCNTL_H */
 
16
#include <time.h>
 
17
#include <string.h>
 
18
#include <ctype.h>
 
19
#include <stdio.h>
 
20
#ifdef HAVE_UNISTD_H
 
21
#include <unistd.h>
 
22
#endif /* HAVE_UNISTD_H */
 
23
#include <atalk/adouble.h>
 
24
#include <netatalk/endian.h>
 
25
#include "asingle.h"
 
26
#include "megatron.h"
 
27
 
 
28
/*      String used to indicate standard input instead of a disk
 
29
        file.  Should be a string not normally used for a file
 
30
 */
 
31
#ifndef STDIN
 
32
#       define  STDIN   "-"
 
33
#endif
 
34
 
 
35
/*      Yes and no
 
36
 */
 
37
#define NOWAY           0
 
38
#define SURETHANG       1
 
39
 
 
40
/*      This structure holds an entry description, consisting of three
 
41
        four byte entities.  The first is the Entry ID, the second is
 
42
        the File Offset and the third is the Length.
 
43
 */
 
44
 
 
45
 
 
46
/*      Both input and output routines use this struct and the
 
47
        following globals; therefore this module can only be used
 
48
        for one of the two functions at a time.
 
49
 */
 
50
struct single_file_data {
 
51
    int                 filed;
 
52
    char                path[ MAXPATHLEN + 1];
 
53
    struct ad_entry     entry[ ADEID_MAX ];
 
54
}               single;
 
55
 
 
56
extern char     *forkname[];
 
57
u_char          header_buf[ AD_HEADER_LEN ];
 
58
 
 
59
/* 
 
60
 * single_open must be called first.  pass it a filename that is supposed
 
61
 * to contain a AppleSingle file.  an single struct will be allocated and
 
62
 * somewhat initialized; single_filed is set.
 
63
 */
 
64
 
 
65
int single_open( singlefile, flags, fh, options )
 
66
    char                *singlefile;
 
67
    int                 flags, options;
 
68
    struct FHeader      *fh;
 
69
{
 
70
    int                 rc;
 
71
 
 
72
    if ( flags == O_RDONLY ) {
 
73
        if ( strcmp( singlefile, STDIN ) == 0 ) {
 
74
            single.filed = fileno( stdin );
 
75
        } else if (( single.filed = open( singlefile, flags )) < 0 ) {
 
76
            perror( singlefile );
 
77
            return( -1 );
 
78
        }
 
79
        strncpy( single.path, singlefile, MAXPATHLEN );
 
80
#if DEBUG
 
81
        fprintf( stderr, "opened %s for read\n", single.path );
 
82
#endif /* DEBUG */
 
83
        if ((( rc = single_header_test()) > 0 ) && 
 
84
                ( single_header_read( fh, rc ) == 0 )) {
 
85
            return( 0 );
 
86
        }
 
87
        single_close( KEEP );
 
88
        return( -1 );
 
89
    }
 
90
    return( 0 );
 
91
}
 
92
 
 
93
/* 
 
94
 * single_close must be called before a second file can be opened using
 
95
 * single_open.  Upon successful completion, a value of 0 is returned.  
 
96
 * Otherwise, a value of -1 is returned.
 
97
 */
 
98
 
 
99
int single_close( keepflag )
 
100
    int                 keepflag;
 
101
{
 
102
    if ( keepflag == KEEP ) {
 
103
        return( close( single.filed ));
 
104
    } else if ( keepflag == TRASH ) {
 
105
        if (( strcmp( single.path, STDIN ) != 0 ) && 
 
106
                ( unlink( single.path ) < 0 )) {
 
107
            perror ( single.path );
 
108
        }
 
109
        return( 0 );
 
110
    } else return( -1 );
 
111
}
 
112
 
 
113
/* 
 
114
 * single_header_read is called by single_open, and before any information
 
115
 * can read from the fh substruct.  it must be called before any of the
 
116
 * bytes of the other two forks can be read, as well.
 
117
 */
 
118
 
 
119
int single_header_read( fh, version )
 
120
    struct FHeader      *fh;
 
121
    int                 version;
 
122
{
 
123
/*
 
124
 * entry_buf is used for reading in entry descriptors, and for reading in
 
125
 *      the actual entries of FILEINFO, FINDERINFO, and DATES.
 
126
 */
 
127
    u_char              entry_buf[ 16 ];
 
128
    u_int32_t           entry_id;
 
129
    u_int32_t           time_seconds;
 
130
    u_short             mask = 0xfcee;
 
131
    u_short             num_entries;
 
132
    int                 n;
 
133
    int                 readlen;
 
134
    int                 date_entry = 0;
 
135
    off_t               pos;
 
136
 
 
137
/*
 
138
 * Go through and initialize the array of entry_info structs.  Read in the
 
139
 * number of entries, and then read in the info for each entry and save it
 
140
 * in the array.
 
141
 */
 
142
 
 
143
    for ( n = 0 ; n < ADEID_MAX; n++ ) {
 
144
        single.entry[ n ].ade_off = 0;
 
145
        single.entry[ n ].ade_len = 0;
 
146
    }
 
147
    memcpy( &num_entries, header_buf + 24, sizeof( num_entries ));
 
148
    num_entries = ntohs( num_entries );
 
149
#if DEBUG >= 2
 
150
    fprintf( stderr, "The number of entries is %d\n", num_entries );
 
151
#endif /* DEBUG */
 
152
    for ( ; num_entries > 0 ; num_entries-- ) {
 
153
        if ( read( single.filed, (char *)entry_buf, AD_ENTRY_LEN )
 
154
                != AD_ENTRY_LEN ) {
 
155
            perror( "Premature end of file :" );
 
156
            return( -1 );
 
157
        }
 
158
        memcpy(&entry_id,  entry_buf, sizeof( entry_id ));
 
159
        entry_id = ntohl( entry_id );
 
160
        memcpy(&single.entry[ entry_id ].ade_off,
 
161
               entry_buf + 4,
 
162
               sizeof( single.entry[ entry_id ].ade_off ));
 
163
        single.entry[ entry_id ].ade_off =
 
164
                ntohl( single.entry[ entry_id ].ade_off );
 
165
        memcpy(&single.entry[ entry_id ].ade_len,
 
166
               entry_buf + 8,
 
167
               sizeof( single.entry[ entry_id ].ade_len ));
 
168
        single.entry[ entry_id ].ade_len =
 
169
                ntohl( single.entry[ entry_id ].ade_len );
 
170
#if DEBUG >= 2
 
171
        fprintf( stderr, "entry_id\t%d\n", entry_id );
 
172
        fprintf( stderr, "\toffset\t\t%d\n", single.entry[ entry_id ].ade_off );
 
173
        fprintf( stderr, "\tlength\t\t%d\n", single.entry[ entry_id ].ade_len );
 
174
#endif /* DEBUG */
 
175
    }
 
176
 
 
177
/*
 
178
 * Now that the entries have been identified, check to make sure
 
179
 * it is a Macintosh file if dealing with version two format file.
 
180
 */
 
181
 
 
182
    if ( version == 1 ) {
 
183
        if ( single.entry[ ADEID_FILEI ].ade_len > 0 )
 
184
            date_entry = ADEID_FILEI;
 
185
    } else if ( version == 2 ) {
 
186
        if ( single.entry[ ADEID_FILEDATESI ].ade_len > 0 )
 
187
            date_entry = ADEID_FILEDATESI;
 
188
    }
 
189
#if DEBUG
 
190
    fprintf( stderr, "date_entry = %d\n", date_entry );
 
191
#endif /* DEBUG */
 
192
 
 
193
/*
 
194
 * Go through and copy all the information you can get from 
 
195
 * the informational entries into the fh struct.  The ENTRYID_DATA
 
196
 * must be the last one done, because it leaves the file pointer in
 
197
 * the right place for the first read of the data fork.
 
198
 */
 
199
 
 
200
    if ( single.entry[ ADEID_NAME ].ade_off == 0 ) {
 
201
        fprintf( stderr, "%s has no name for the mac file.\n", single.path );
 
202
        return( -1 );
 
203
    } else {
 
204
        pos = lseek( single.filed, single.entry[ ADEID_NAME ].ade_off,
 
205
                SEEK_SET );
 
206
        readlen = single.entry[ ADEID_NAME ].ade_len > ADEDLEN_NAME ? 
 
207
              ADEDLEN_NAME : single.entry[ ADEID_NAME ].ade_len;
 
208
        if ( read( single.filed, (char *)fh->name, readlen ) != readlen ) {
 
209
            perror( "Premature end of file :" );
 
210
            return( -1 );
 
211
        }
 
212
    }
 
213
    if (( single.entry[ ADEID_FINDERI ].ade_len < 16 ) ||
 
214
            ( single.entry[ ADEID_FINDERI ].ade_off <= AD_HEADER_LEN )) {
 
215
        fprintf( stderr, "%s has bogus FinderInfo.\n", single.path );
 
216
        return( -1 );
 
217
    } else {
 
218
        pos = lseek( single.filed,
 
219
                single.entry[ ADEID_FINDERI ].ade_off, SEEK_SET );
 
220
        if ( read( single.filed, (char *)entry_buf, sizeof( entry_buf )) !=
 
221
                sizeof( entry_buf )) {
 
222
            perror( "Premature end of file :" );
 
223
            return( -1 );
 
224
        }
 
225
        memcpy( &fh->finder_info.fdType, entry_buf + FINDERIOFF_TYPE,   
 
226
                sizeof( fh->finder_info.fdType ));
 
227
        memcpy( &fh->finder_info.fdCreator, entry_buf + FINDERIOFF_CREATOR,
 
228
                sizeof( fh->finder_info.fdCreator ));
 
229
        memcpy( &fh->finder_info.fdFlags, entry_buf +  FINDERIOFF_FLAGS,
 
230
                sizeof( fh->finder_info.fdFlags ));
 
231
        fh->finder_info.fdFlags = fh->finder_info.fdFlags & mask;
 
232
        memcpy( &fh->finder_info.fdLocation, entry_buf + FINDERIOFF_LOC,
 
233
                sizeof( fh->finder_info.fdLocation ));
 
234
        memcpy(&fh->finder_info.fdFldr, entry_buf + FINDERIOFF_FLDR,
 
235
                sizeof( fh->finder_info.fdFldr ));
 
236
        fh->finder_xinfo.fdScript = *(entry_buf + FINDERIOFF_SCRIPT);
 
237
        fh->finder_xinfo.fdXFlags = *(entry_buf + FINDERIOFF_XFLAGS);
 
238
 
 
239
#if DEBUG
 
240
        {
 
241
            char                type[5];
 
242
            char                creator[5];
 
243
 
 
244
            strncpy( type, &fh->finder_info.fdType, 4 );
 
245
            strncpy( creator, &fh->finder_info.fdCreator, 4 );
 
246
            type[4] = creator[4] = '\0';
 
247
            fprintf( stderr, "type is %s, creator is %s\n", type, creator );
 
248
        }
 
249
#endif /* DEBUG */
 
250
    }
 
251
    if (( single.entry[ ADEID_COMMENT ].ade_len == 0 ) || 
 
252
            ( single.entry[ ADEID_COMMENT ].ade_off <= AD_HEADER_LEN )) {
 
253
        fh->comment[0] = '\0';
 
254
    } else {
 
255
        pos = lseek( single.filed, single.entry[ ADEID_COMMENT ].ade_off,
 
256
                SEEK_SET );
 
257
        readlen = single.entry[ ADEID_COMMENT ].ade_len > ADEDLEN_COMMENT
 
258
                ? ADEDLEN_COMMENT : single.entry[ ADEID_COMMENT ].ade_len;
 
259
        if ( read( single.filed, (char *)fh->comment, readlen ) != readlen ) {
 
260
            perror( "Premature end of file :" );
 
261
            return( -1 );
 
262
        }
 
263
    }
 
264
/*
 
265
 * If date_entry is 7, we have an AppleSingle version one, do the 
 
266
 * appropriate stuff.  If it is 8, we have an AppleSingle version two,
 
267
 * do the right thing.  If date_entry is neither, just use the current date.
 
268
 * Unless I can't get the current date, in which case use time zero.
 
269
 */
 
270
    if (( date_entry < 7 ) || ( date_entry > 8 )) {
 
271
        if (( time_seconds = time( NULL )) == -1 ) {
 
272
            time_seconds = AD_DATE_START;
 
273
        } else {
 
274
            time_seconds = AD_DATE_FROM_UNIX(time_seconds);
 
275
        }
 
276
        memcpy(&fh->create_date, &time_seconds, sizeof( fh->create_date ));
 
277
        memcpy(&fh->mod_date, &time_seconds, sizeof( fh->mod_date ));
 
278
        fh->backup_date = AD_DATE_START;
 
279
    } else if ( single.entry[ date_entry ].ade_len != 16 ) {
 
280
        fprintf( stderr, "%s has bogus FileInfo or File Dates Info.\n", 
 
281
                single.path );
 
282
        return( -1 );
 
283
    } else if ( date_entry == ADEID_FILEI ) {
 
284
        pos = lseek( single.filed,
 
285
                single.entry[ date_entry ].ade_off, SEEK_SET );
 
286
        if ( read( single.filed, (char *)entry_buf, sizeof( entry_buf )) !=
 
287
                sizeof( entry_buf )) {
 
288
            perror( "Premature end of file :" );
 
289
            return( -1 );
 
290
        }
 
291
        memcpy( &fh->create_date, entry_buf + FILEIOFF_CREATE,
 
292
                sizeof( fh->create_date ));
 
293
        memcpy( &fh->mod_date, entry_buf + FILEIOFF_MODIFY,
 
294
                sizeof( fh->mod_date ));
 
295
        memcpy( &fh->backup_date, entry_buf + FILEIOFF_BACKUP,
 
296
                sizeof(fh->backup_date));
 
297
    } else if ( date_entry == ADEID_FILEDATESI ) {
 
298
        pos = lseek( single.filed,
 
299
                single.entry[ date_entry ].ade_off, SEEK_SET );
 
300
        if ( read( single.filed, (char *)entry_buf, sizeof( entry_buf )) !=
 
301
                sizeof( entry_buf )) {
 
302
            perror( "Premature end of file :" );
 
303
            return( -1 );
 
304
        }
 
305
        memcpy( &fh->create_date, entry_buf + FILEIOFF_CREATE,
 
306
                sizeof( fh->create_date ));
 
307
        memcpy( &fh->mod_date, entry_buf + FILEIOFF_MODIFY,
 
308
                sizeof( fh->mod_date ));
 
309
        memcpy( &fh->backup_date, entry_buf + FILEIOFF_BACKUP,
 
310
                sizeof(fh->backup_date));
 
311
    }
 
312
    if ( single.entry[ ADEID_RFORK ].ade_off == 0 ) {
 
313
        fh->forklen[ ADEID_RFORK ] = 0;
 
314
    } else {
 
315
        fh->forklen[ ADEID_RFORK ] =
 
316
                htonl( single.entry[ ADEID_RFORK ].ade_len );
 
317
    }
 
318
    if ( single.entry[ ADEID_DFORK ].ade_off == 0 ) {
 
319
        fh->forklen[ DATA ] = 0;
 
320
    } else {
 
321
        fh->forklen[ DATA ] = htonl( single.entry[ ADEID_DFORK ].ade_len );
 
322
        pos = lseek( single.filed, single.entry[ ADEID_DFORK ].ade_off, SEEK_SET );
 
323
    }
 
324
 
 
325
    return( 0 );
 
326
}
 
327
 
 
328
/*
 
329
 * single_header_test is called from single_open.  It checks certain
 
330
 * values of the file and determines if the file is an AppleSingle version
 
331
 * one file something else, and returns a one, or negative one to indicate
 
332
 * file type.
 
333
 *
 
334
 * The Magic Number of the file, the first four bytes, must be hex
 
335
 * 0x00051600.  Bytes 4 through 7 are the version number and must be hex
 
336
 * 0x00010000.  Bytes 8 through 23 identify the home file system, and we
 
337
 * are only interested in files from Macs.  Therefore these bytes must
 
338
 * contain hex 0x4d6163696e746f736820202020202020 which is ASCII
 
339
 * "Macintosh       " (that is seven blanks of padding).
 
340
 */
 
341
#define MACINTOSH       "Macintosh       "
 
342
u_char          sixteennulls[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 
343
                                    0, 0, 0, 0, 0, 0, 0, 0 };
 
344
 
 
345
int single_header_test(void)
 
346
{
 
347
    int                 cc;
 
348
    u_int32_t           templong;
 
349
 
 
350
    cc = read( single.filed, (char *)header_buf, sizeof( header_buf ));
 
351
    if ( cc < sizeof( header_buf )) {
 
352
        perror( "Premature end of file :" );
 
353
        return( -1 );
 
354
    }
 
355
 
 
356
    memcpy( &templong, header_buf, sizeof( templong ));
 
357
    if ( ntohl( templong ) != AD_APPLESINGLE_MAGIC ) {
 
358
        fprintf( stderr, "%s is not an AppleSingle file.\n", single.path );
 
359
        return( -1 );
 
360
    }
 
361
 
 
362
    memcpy(&templong,  header_buf +  4, sizeof( templong ));
 
363
    templong = ntohl( templong );
 
364
    if ( templong == AD_VERSION1 ) {
 
365
        cc = 1;
 
366
        if ( memcmp( MACINTOSH, header_buf + 8, sizeof( MACINTOSH ) - 1 ) 
 
367
                != 0 ) {
 
368
            fprintf( stderr, "%s is not a Macintosh AppleSingle file.\n", 
 
369
                    single.path );
 
370
            return( -1 );
 
371
        }
 
372
    } else if ( templong == AD_VERSION2 ) {
 
373
        cc = 2;
 
374
        if ( memcmp( sixteennulls, header_buf + 8, sizeof( sixteennulls ))
 
375
                != 0 ) {
 
376
            fprintf( stderr, 
 
377
                    "Warning:  %s may be a corrupt AppleSingle file.\n",
 
378
                    single.path );
 
379
            return( -1 );
 
380
        }
 
381
    } else {
 
382
        fprintf( stderr, "%s is a version of AppleSingle I don't understand!\n",
 
383
                single.path );
 
384
        return( -1 );
 
385
    }
 
386
 
 
387
    return( cc );
 
388
}
 
389
 
 
390
/*
 
391
 * single_read is called until it returns zero for each fork.  When
 
392
 * it returns zero for the first fork, it seeks to the proper place
 
393
 * to read in the next, if there is one.  single_read must be called
 
394
 * enough times to return zero for each fork and no more.
 
395
 *
 
396
 */
 
397
 
 
398
int single_read( fork, buffer, length )
 
399
    int                 fork;
 
400
    char                *buffer;
 
401
    int                 length;
 
402
{
 
403
    u_int32_t           entry_id;
 
404
    char                *buf_ptr;
 
405
    int                 readlen;
 
406
    int                 cc = 1;
 
407
    off_t               pos;
 
408
 
 
409
    switch ( fork ) {
 
410
        case DATA :
 
411
            entry_id = ADEID_DFORK;
 
412
            break;
 
413
        case RESOURCE :
 
414
            entry_id = ADEID_RFORK;
 
415
            break;
 
416
        default :
 
417
            return( -1 );
 
418
            break;
 
419
    }
 
420
 
 
421
    if ( single.entry[ entry_id ].ade_len < 0 ) {
 
422
        fprintf( stderr, "single_read: Trying to read past end of fork!\n" );
 
423
        return( single.entry[ entry_id ].ade_len );
 
424
    }
 
425
    if ( single.entry[ entry_id ].ade_len == 0 ) {
 
426
        if ( fork == DATA ) {
 
427
            pos = lseek( single.filed,
 
428
                single.entry[ ADEID_RFORK ].ade_off, SEEK_SET );
 
429
        }
 
430
        return( 0 );
 
431
    }
 
432
 
 
433
    if ( single.entry[ entry_id ].ade_len < length ) {
 
434
        readlen = single.entry[ entry_id ].ade_len;
 
435
    } else {
 
436
        readlen = length;
 
437
    }
 
438
 
 
439
    buf_ptr = buffer;
 
440
    while (( readlen > 0 ) && ( cc > 0 )) {
 
441
        if (( cc = read( single.filed, buf_ptr, readlen )) > 0 ) {
 
442
            readlen -= cc;
 
443
            buf_ptr += cc;
 
444
        }
 
445
    }
 
446
    if ( cc >= 0 ) {
 
447
        cc = buf_ptr - buffer;
 
448
        single.entry[ entry_id ].ade_len -= cc;
 
449
    }
 
450
 
 
451
    return( cc );
 
452
}