]> arthur.barton.de Git - netatalk.git/blob - contrib/shell_utils/apple_dump.in
apple_dump: small fix
[netatalk.git] / contrib / shell_utils / apple_dump.in
1 #!@PERL@
2 #
3 # AppleSingle/AppleDouble dump
4 #
5 # (c) 2009-2012 by HAT <hat@fa2.so-net.ne.jp>
6 #
7 #  This program is free software; you can redistribute it and/or modify
8 #  it under the terms of the GNU General Public License as published by
9 #  the Free Software Foundation; either version 2 of the License, or
10 #  (at your option) any later version.
11 #
12 #  This program is distributed in the hope that it will be useful,
13 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #  GNU General Public License for more details.
16 #
17
18 #
19 # References:
20 #
21 # Applesingle and AppleDouble format internals (version 1)
22 # http://users.phg-online.de/tk/netatalk/doc/Apple/v1/
23 #
24 # AppleSingle/AppleDouble Formats for Foreign Files Developer's Note (version2)
25 # http://users.phg-online.de/tk/netatalk/doc/Apple/v2/AppleSingle_AppleDouble.pdf
26 #
27 # Inside Macintosh: Macintosh Toolbox Essentials /
28 # Chapter 7 - Finder Interface / Finder Interface Reference
29 # http://developer.apple.com/legacy/mac/library/documentation/mac/toolbox/Toolbox-463.html
30 #
31 # Finder Interface Reference
32 # http://developer.apple.com/legacy/mac/library/documentation/Carbon/Reference/Finder_Interface/Reference/reference.html
33 #
34 # Technical Note TN1150  HFS Plus Volume Format
35 # http://developer.apple.com/mac/library/technotes/tn/tn1150.html#FinderInfo
36 #
37 # CarbonHeaders source
38 # http://www.opensource.apple.com/source/CarbonHeaders/CarbonHeaders-8A428/Finder.h
39 # http://www.opensource.apple.com/source/CarbonHeaders/CarbonHeaders-9A581/Finder.h
40 #
41 # Xcode 3.2.1
42 # /usr/bin/SetFile
43 # /usr/bin/GetFileInfo
44 #
45 # Mac OS X 10.6.2 kernel source
46 # http://www.opensource.apple.com/source/xnu/xnu-1486.2.11/bsd/vfs/vfs_xattr.c
47 #
48
49 use File::Basename;
50 use File::Spec;
51 use File::Temp qw /tempfile/;
52 use bigint; # require perl >= 5.8
53
54 # check command for extended attributes -----------------------------------
55
56 if (     0 == system("which getfattr > /dev/null 2>&1")) {
57     $eacommand = 1;
58 } elsif (0 == system("which xattr > /dev/null 2>&1")) {
59     $eacommand = 2;
60 } elsif (0 == system("which runat > /dev/null 2>&1")) {
61     $eacommand = 3;
62 } elsif (0 == system("which getextattr > /dev/null 2>&1")) {
63     $eacommand = 4;
64 } else {
65     $eacommand = 0;
66 }
67
68 #printf ( "eacommand = %d\n", $eacommand );   # debug
69
70 # parse command line -----------------------------------------------
71
72 $stdinputmode = 0;
73 $eaoption = 0;
74 $finderinfo = 0;              #  0: unknown   1: file   2: directory
75 while ($arg = shift @ARGV)
76 {
77     if  ($arg =~ /^(-h|-help|--help)$/ ) {
78         printf ("usage: %s [-a] [FILE|DIR]\n"         ,basename($0));
79         printf (" or:   %s -e FILE|DIR\n"             ,basename($0));
80         printf (" or:   %s -f [FILE]\n"               ,basename($0));
81         printf (" or:   %s -d [FILE]\n"               ,basename($0));
82         printf (" or:   %s -h|-help|--help\n"         ,basename($0));
83         printf (" or:   %s -v|-version|--version\n"   ,basename($0));
84         printf ("Dump AppleSingle/AppleDouble format data.\n");
85         printf ("With no FILE|DIR, or when FILE|DIR is -, read standard input.\n");
86         printf ("\n");
87         printf ("  -a (default)     Dump a AppleSingle/AppleDouble data for FILE or DIR\n");
88         printf ("                   automatically.\n");
89         printf ("                   If FILE is not AppleSingle/AppleDouble format,\n");
90         printf ("                   look for extended attribute, .AppleDouble/FILE and ._FILE.\n");
91         printf ("                   If DIR, look for extended attribute,\n");
92         printf ("                   DIR/.AppleDouble/.Parent and ._DIR.\n");
93         printf ("  -e               Dump extended attribute of FILE or DIR\n");
94         printf ("  -f               Dump FILE. Assume FinderInfo to be FileInfo.\n");
95         printf ("  -d               Dump FILE. Assume FinderInfo to be DirInfo.\n");
96         printf ("  -h,-help,--help  Display this help and exit\n");
97         printf ("  -v,-version,--version  Show version and exit\n");
98         printf ("\n");
99         printf ("There is no way to detect whether FinderInfo is FileInfo or DirInfo.\n");
100         printf ("By default, %s examins whether file or directory,\n"   ,basename($0));
101         printf ("a parent directory is .AppleDouble, filename is ._*, filename is .Parent,\n");
102         printf ("and so on.\n");
103         printf ("If setting option -e, -f or -d, %s assume FinderInfo and doesn't look for\n");
104         printf ("another file.\n");
105         exit 1;
106     } elsif ($arg =~ /^(-v|-version|--version)$/ ) {
107         printf ("%s \(Netatalk @NETATALK_VERSION@\)\n", basename($0));
108         exit 1;
109     } elsif ($arg eq "-a") {
110         $finderinfo = 0;
111     } elsif ($arg eq "-e") {
112         if ($eacommand == 0) {
113             printf (STDERR "%s: unsupported option -e\n", basename($0));
114             printf (STDERR "because neither getfattr, xattr, runat nor getextattr is found.\n");
115             exit 1;
116         }
117         $eaoption = 1;
118     } elsif ($arg eq "-f") {
119         $finderinfo = 1;
120     } elsif ($arg eq "-d") {
121         $finderinfo = 2;
122     } elsif ($arg eq "-") {
123         $stdinputmode = 1;
124     } elsif ($arg =~ /^-/) {
125         printf (STDERR "%s: invalid option %s\n", basename($0), $arg);
126         printf (STDERR "Try \`%s\ -h' for more information.\n", basename($0));
127         exit 1;
128     } else {
129         $afile = $arg;
130     }
131 }
132
133 if (!($afile)) {
134     $stdinputmode = 1;
135 } elsif (!( -e $afile)) {
136     printf (STDERR "\"%s\" is not found.\n", $afile);
137     exit 1;
138 }
139
140 # detect FinderInfo, and search AppleSingle/AppleDouble file --------------
141
142 $abspath = File::Spec->rel2abs($afile);
143 ($basename, $path, $ext) = fileparse($abspath);
144
145 if ( $stdinputmode == 1) {
146     ($eatempfh, $openfile) = tempfile(UNLINK => 1);
147     system("cat - > $openfile");
148     close($eatempfh);
149     $openmessage = "Dumping Standard Input...\n";
150 } elsif ( $eaoption == 1 ) {
151     if ( -f $afile ) {
152         $finderinfo = 1;
153     } elsif ( -d $afile ) {
154         $finderinfo = 2;
155     } else {
156         printf (STDERR "unknown error: %s\n", $afile);
157         exit 1;
158     }
159     if ( 0 == checkea($afile) ) {
160         printf (STDERR "\"%s\"'s extended attribute is not found\n",  $afile);
161         exit 1;
162     }
163     $openfile = eaopenfile($afile);
164     $openmessage = "Dumping \"$afile\"'s extended attribute...\n";
165 } elsif ( $finderinfo != 0 ) {
166     $openfile = $afile;
167     $openmessage = "Dumping \"$openfile\"...\n";
168 } elsif ( -f $afile ) {
169     if ( $basename eq ".Parent") {
170         $finderinfo = 2;
171     } elsif ( $path =~ /\/.AppleDouble\/$/ ) {
172         $finderinfo = 1;
173     } elsif ( $basename =~ /^._/ ) {
174         if ( -f $path.substr($basename, 2) ) {
175             $finderinfo = 1;
176         } elsif ( -d $path.substr($basename, 2) ) {
177             $finderinfo = 2;
178         }
179     }
180     if (!open(INFILE, "<$afile")) {
181         printf (STDERR "cannot open %s\n",  $afile);
182         exit 1;
183     }
184     read(INFILE,$buf,4);
185     $val = unpack("N", $buf );
186     close(INFILE);
187     if ($val == 0x00051600 || $val == 0x00051607) {
188         $openfile = $afile;
189         $openmessage = "Dumping \"$openfile\"...\n";
190     } else {
191         printf ("\"%s\" is not AppleSingle/AppleDouble format.\n", $afile);
192         $finderinfo = 1;
193         $adcount = 0;
194         $netatalkfile = $path.".AppleDouble/".$basename;
195         $osxfile = $path."._".$basename;
196
197         if ( 1 == checkea($afile) ) {
198             printf ("\"%s\"\'s extended attribute is found.\n", $afile);
199             $adcount++;
200             $openfile = eaopenfile($afile);
201             $openmessage = "Dumping \"$afile\"'s extended attribute...\n";
202         }
203         if ( -e $netatalkfile ) {
204             printf ("\"%s\" is found.\n", $netatalkfile);
205             $adcount++;
206             $openfile = $netatalkfile;
207             $openmessage = "Dumping \"$openfile\"...\n";
208         }
209         if ( -e $osxfile ) {
210             printf ("\"%s\" is found.\n", $osxfile);
211             $adcount++;
212             $openfile = $osxfile;
213             $openmessage = "Dumping \"$openfile\"...\n";
214         }
215         if ( $adcount == 0 ) {
216             printf ("AppleSingle/AppleDouble data is not found.\n");
217             exit 1;
218         }
219         if ( $adcount != 1 ) {
220             printf ("Specify any one.\n");
221             exit 1;
222         }
223     }
224 } elsif ( -d $afile) {
225     printf ("\"%s\" is a directory.\n", $afile);
226     $finderinfo = 2;
227     $adcount = 0;
228     $netatalkfile = $path.$basename."/.AppleDouble/.Parent";
229     $osxfile = $path."._".$basename;
230
231     if ( 1 == checkea($afile) ) {
232         printf ("\"%s\"\'s extended attribute is found.\n", $afile);
233         $adcount++;
234         $openfile = eaopenfile($afile);
235         $openmessage = "Dumping \"$afile\"'s extended attribute...\n";
236     }
237     if ( -e $netatalkfile ) {
238         printf ("\"%s\" is found.\n", $netatalkfile);
239         $adcount++;
240         $openfile= $netatalkfile;
241         $openmessage = "Dumping \"$openfile\"...\n";
242     }
243     if ( -e $osxfile ) {
244         printf ("\"%s\" is found.\n", $osxfile);
245         $adcount++;
246         $openfile = $osxfile;
247         $openmessage = "Dumping \"$openfile\"...\n";
248     }
249     if ( $adcount == 0 ) {
250         printf ("AppleSingle/AppleDouble data is not found.\n");
251         exit 1;
252     }
253     if ( $adcount != 1 ) {
254         printf ("Specify any one.\n");
255         exit 1;
256     }
257 } else {
258     printf (STDERR "unknown error: %s\n", $afile);
259     exit 1;
260 }
261
262 if (!open(INFILE, "<$openfile")) {
263     printf (STDERR "cannot open %s\n",  $openfile);
264     exit 1;
265 }
266
267 printf ($openmessage);
268
269 #Dump --------------------------------------------------------
270
271 # Magic Number -----------------------------------------------
272
273 print "-------------------------------------------------------------------------------\n";
274
275 read(INFILE,$buf,4);
276 $val = unpack("N", $buf );
277 printf("MagicNumber: %08X", $val);
278 if    ( $val == 0x00051600 ) {
279     printf("                                        : AppleSingle");
280 }
281 elsif ( $val == 0x00051607 ) {
282     printf("                                        : AppleDouble");
283 }
284 else                         {
285     printf("                                        : Unknown"    );
286 }
287 print "\n";
288
289 # Version Number ---------------------------------------------
290
291 read(INFILE,$buf,4);
292 $version = unpack("N", $buf );
293 printf("Version    : %08X", $version);
294 if ( $version == 0x00010000 ) {
295     printf("                                        : Version 1");
296 } elsif ( $version == 0x00020000 ) {
297     printf("                                        : Version 2");
298 } else {
299     printf("                                        : Unknown"  );
300 }
301 print "\n";
302
303 # v1:Home file system / v2:Filler ----------------------------
304
305 read(INFILE,$buf,16);
306 if ( $version == 0x00010000 ) {
307     print "HomeFileSys:";
308 } else {
309     print "Filler     :";
310 }
311 hexdump($buf, 16, 16, " ");
312
313 # Number of entities -----------------------------------------
314
315 read(INFILE,$buf,2);
316 $entnum = unpack("n", $buf );
317 printf("Num. of ent: %04X    ", $entnum);
318 printf("                                        : %d", $entnum);
319 print "\n";
320
321 # data -------------------------------------------------------
322
323 for ( $num = 0 ; $num < $entnum ; $num++) {
324
325     seek(INFILE, ($num * 12 + 26), 0);
326
327 #    Entry ---------------------------------------------------
328
329     read(INFILE,$buf,4);
330     $entid = unpack("N", $buf );
331     print "\n-------------------------------------------------------------------------------\n";
332     printf("Entry ID   : %08X", $entid);
333     if    ( $entid ==  1 )         { printf(" : Data Fork"); }
334     elsif ( $entid ==  2 )         { printf(" : Resource Fork"); }
335     elsif ( $entid ==  3 )         { printf(" : Real Name"); }
336     elsif ( $entid ==  4 )         { printf(" : Comment"); }
337     elsif ( $entid ==  5 )         { printf(" : Icon, B&W"); }
338     elsif ( $entid ==  6 )         { printf(" : Icon Color"); }
339     elsif ( $entid ==  7 )         { printf(" : File Info"); }
340     elsif ( $entid ==  8 )         { printf(" : File Dates Info"); }
341     elsif ( $entid ==  9 )         { printf(" : Finder Info"); }
342     elsif ( $entid == 10 )         { printf(" : Macintosh File Info"); }
343     elsif ( $entid == 11 )         { printf(" : ProDOS File Info"); }
344     elsif ( $entid == 12 )         { printf(" : MS-DOS File Info"); }
345     elsif ( $entid == 13 )         { printf(" : Short Name"); }
346     elsif ( $entid == 14 )         { printf(" : AFP File Info"); }
347     elsif ( $entid == 15 )         { printf(" : Directory ID"); }
348     elsif ( $entid == 0x8053567E ) { printf(" : CNID (Netatalk Extended)"); }
349     elsif ( $entid == 0x8053594E ) { printf(" : DB stamp (Netatalk Extended)"); }
350     elsif ( $entid == 0x80444556 ) { printf(" : dev (Netatalk Extended)"); }
351     elsif ( $entid == 0x80494E4F ) { printf(" : inode (Netatalk Extended)"); }
352     else                           { printf(" : Unknown"); }
353     print "\n";
354
355 #    Offset -------------------------------------------------
356
357     read(INFILE,$buf,4);
358     $ofst = unpack("N", $buf );
359     printf("Offset     : %08X", $ofst);
360     printf(" : %d ", $ofst);
361
362 #    Length -------------------------------------------------
363
364     read(INFILE,$buf,4);
365     $len = unpack("N", $buf );
366     printf("\nLength     : %08X", $len);
367     printf(" : %d", $len);
368     $quo = $len >> 4;
369     $rem = $len & 0xF;
370     print "\n";
371
372 #     Dump for each Entry ID --------------------------------
373
374 #    if ( $entid ==  1 ) { ; } # Data Fork
375 #    if ( $entid ==  2 ) { ; } # Resource Fork
376 #    if ( $entid ==  3 ) { ; } # Real Name
377 #    if ( $entid ==  4 ) { ; } # Comment
378 #    if ( $entid ==  5 ) { ; } # Icon, B&W
379 #    if ( $entid ==  6 ) { ; } # Icon Color
380 #    if ( $entid ==  7 ) { ; } # File Info
381     if ( $entid ==  8 ) { filedatesdump($ofst,$len); }
382     elsif ( $entid ==  9 ) { finderinfodump($ofst,$len); }
383 #    if ( $entid == 10 ) { ; } # Macintosh File Info
384 #    if ( $entid == 11 ) { ; } # ProDOS File Info
385 #    if ( $entid == 12 ) { ; } # MS-DOS File Info
386 #    if ( $entid == 13 ) { ; } # Short Name
387 #    if ( $entid == 14 ) { ; } # AFP File Info 
388     elsif ( $entid == 15 ) { print "\n"; bedump($ofst,$len); } # Directory ID
389     elsif ( $entid == 0x8053567E  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # CNID (Netatalk Extended)
390     elsif ( $entid == 0x8053594E  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # DB stamp (Netatalk Extended)
391     elsif ( $entid == 0x80444556  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # dev (Netatalk Extended)
392     elsif ( $entid == 0x80494E4F  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # inode (Netatalk Extended)
393
394 #    RAW Dump ---------------------------------------------------
395
396     if ( ($quo > 0) || ($rem > 0)) {
397         print "\n";
398         print "-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)\n";
399     }
400
401     seek(INFILE, $ofst, 0);
402     rawdump($quo, $rem);
403
404 }
405
406 close(INFILE);
407 exit 0;
408
409 #sub -----------------------------------------------------------
410
411 sub filedatesdump {
412     my ($ofst, $len) = @_;
413     my ($datedata);
414     my ($i);
415     my ($datestr);
416
417     @datetype =('create    ', 'modify    ', 'backup    ', 'access    ');
418
419     seek(INFILE, $ofst, 0);
420
421     print "\n";
422     printf ("-DATE------:          : (GMT)                    : (Local)\n");
423
424     for ( $i = 0 ; $i < 4 ; $i++) {
425         read(INFILE,$buf,4);
426         $datedata = unpack("N", $buf );
427         if ($datedata < 0x80000000) {
428             $datestr = gmtime( $datedata + 946684800)
429                 ." : "
430                 .localtime( $datedata + 946684800);
431         } elsif ($datedata == 0x80000000) {
432             $datestr = "Unknown or Initial";
433         } else {
434             $datestr = gmtime( $datedata - 3348282496)
435                 ." : "
436                 .localtime( $datedata - 3348282496);
437         }
438         printf ("%s : %08X : %s\n",$datetype[$i], $datedata, $datestr);
439     }
440 }
441
442 sub finderinfodump {
443     my ($ofst, $len) = @_;
444
445     seek(INFILE, $ofst, 0);
446
447     if ($finderinfo == 0) {
448         print "\n";
449         print "-NOTE------: cannot detect whether FInfo or DInfo. assume FInfo.\n";
450     }
451
452     if ($finderinfo == 0 || $finderinfo == 1) {
453         filefinderinfodump();
454     } elsif ($finderinfo == 2) {
455         dirfinderinfodump();
456     } else {
457         print STDERR "unknown FinderInfo type\n"
458     }
459
460     if ($len > 32) { eadump(); }
461 }
462
463 sub filefinderinfodump {
464
465     print "\n";
466     print "-FInfo-----:\n";
467
468     read(INFILE,$buf,4);
469     print "Type       : ";
470     hexdump($buf, 4, 4, "");
471
472     read(INFILE,$buf,4);
473     print "Creator    : ";
474     hexdump($buf, 4, 4, "");
475
476     flagsdump();
477
478     read(INFILE,$buf,2);
479     $val = unpack("n", $buf );
480     printf("Location v : %04X", $val);
481     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
482
483     read(INFILE,$buf,2);
484     $val = unpack("n", $buf );
485     printf("Location h : %04X", $val);
486     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
487
488     read(INFILE,$buf,2);
489     print "Fldr       : ";
490     hexdump($buf, 2, 4, "");
491
492     print "\n";
493     print "-FXInfo----:\n";
494
495     read(INFILE,$buf,2);
496     $val = unpack("n", $buf );
497     printf("Rsvd|IconID: %04X", $val);
498     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
499
500     read(INFILE,$buf,2);
501     print "Rsvd       : ";
502     hexdump($buf, 2, 4, "");
503     read(INFILE,$buf,2);
504     print "Rsvd       : ";
505     hexdump($buf, 2, 4, "");
506     read(INFILE,$buf,2);
507     print "Rsvd       : ";
508     hexdump($buf, 2, 4, "");
509
510     xflagsdump();
511
512     read(INFILE,$buf,2);
513     $val = unpack("n", $buf );
514     printf("Rsvd|commnt: %04X", $val);
515     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
516
517     read(INFILE,$buf,4);
518     $val = unpack("N", $buf );
519     printf("PutAway    : %08X", $val);
520     printf(" : %d\n", $val>0x7FFFFFFF?$val-0x100000000:$val); # Why SInt32?
521
522 }
523
524 sub dirfinderinfodump {
525
526     print "\n";
527     print "-DInfo-----:\n";
528
529     read(INFILE,$buf,2);
530     $val = unpack("n", $buf );
531     printf("Rect top   : %04X", $val);
532     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
533
534     read(INFILE,$buf,2);
535     $val = unpack("n", $buf );
536     printf("Rect left  : %04X", $val);
537     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
538
539     read(INFILE,$buf,2);
540     $val = unpack("n", $buf );
541     printf("Rect bottom: %04X", $val);
542     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
543
544     read(INFILE,$buf,2);
545     $val = unpack("n", $buf );
546     printf("Rect right : %04X", $val);
547     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
548
549     flagsdump();
550
551     read(INFILE,$buf,2);
552     $val = unpack("n", $buf );
553     printf("Location v : %04X", $val);
554     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
555
556     read(INFILE,$buf,2);
557     $val = unpack("n", $buf );
558     printf("Location h : %04X", $val);
559     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
560
561     read(INFILE,$buf,2);
562     print "View       : ";
563     hexdump($buf, 2, 4, "");
564
565     print "\n";
566     print "-DXInfo----:\n";
567
568     read(INFILE,$buf,2);
569     $val = unpack("n", $buf );
570     printf("Scroll v   : %04X", $val);
571     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
572
573     read(INFILE,$buf,2);
574     $val = unpack("n", $buf );
575     printf("Scroll h   : %04X", $val);
576     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
577
578     read(INFILE,$buf,4);
579     $val = unpack("N", $buf );
580     printf("Rsvd|OpnChn: %08X", $val);
581     printf(" : %d\n", $val>0x7FFFFFFF?$val-0x100000000:$val); # Why SInt32?
582
583     xflagsdump();
584
585     read(INFILE,$buf,2);
586     print "Comment    : ";
587     hexdump($buf, 2, 4, "");
588
589     read(INFILE,$buf,4);
590     $val = unpack("N", $buf );
591     printf("PutAway    : %08X", $val);
592     printf(" : %d\n", $val>0x7FFFFFFF?$val-0x100000000:$val); # Why SInt32?
593
594 }
595 sub flagsdump {
596
597     @colortype =('none', 'gray', 'green', 'purple', 'blue', 'yellow', 'red', 'orange');
598
599     read(INFILE,$buf,2);
600     $flags = unpack("n", $buf );
601     printf ("isAlias    : %d\n", ($flags >> 15) & 1);
602     printf ("Invisible  : %d\n", ($flags >> 14) & 1);
603     printf ("hasBundle  : %d\n", ($flags >> 13) & 1);
604     printf ("nameLocked : %d\n", ($flags >> 12) & 1);
605     printf ("Stationery : %d\n", ($flags >> 11) & 1);
606     printf ("CustomIcon : %d\n", ($flags >> 10) & 1);
607     printf ("Reserved   : %d\n", ($flags >>  9) & 1);
608     printf ("Inited     : %d\n", ($flags >>  8) & 1);
609     printf ("NoINITS    : %d\n", ($flags >>  7) & 1);
610     printf ("Shared     : %d\n", ($flags >>  6) & 1);
611     printf ("SwitchLaunc: %d\n", ($flags >>  5) & 1);
612     printf ("Hidden Ext : %d\n", ($flags >>  4) & 1);
613     printf ("color      : %d%d%d      : %s\n", ($flags >>  3) & 1,
614             ($flags >>  2) & 1,
615             ($flags >>  1) & 1,
616             @colortype[($flags & 0xE)>>1]);
617     printf ("isOnDesk   : %d\n", ($flags >>  0) & 1);
618
619 }
620
621 sub xflagsdump {
622
623     read(INFILE,$buf,2);
624     $flags = unpack("n", $buf );
625
626     if (($flags >> 15) == 1) {
627         print "Script     : ";
628         hexdump($buf, 1, 4, "");
629     } else {
630         printf ("AreInvalid : %d\n", ($flags >> 15) & 1);
631         printf ("unknown bit: %d\n", ($flags >> 14) & 1);
632         printf ("unknown bit: %d\n", ($flags >> 13) & 1);
633         printf ("unknown bit: %d\n", ($flags >> 12) & 1);
634         printf ("unknown bit: %d\n", ($flags >> 11) & 1);
635         printf ("unknown bit: %d\n", ($flags >> 10) & 1);
636         printf ("unknown bit: %d\n", ($flags >>  9) & 1);
637     }
638
639     printf ("CustomBadge: %d\n", ($flags >>  8) & 1);
640     printf ("ObjctIsBusy: %d\n", ($flags >>  7) & 1);
641     printf ("unknown bit: %d\n", ($flags >>  6) & 1);
642     printf ("unknown bit: %d\n", ($flags >>  5) & 1);
643     printf ("unknown bit: %d\n", ($flags >>  4) & 1);
644     printf ("unknown bit: %d\n", ($flags >>  3) & 1);
645     printf ("RoutingInfo: %d\n", ($flags >>  2) & 1);
646     printf ("unknown bit: %d\n", ($flags >>  1) & 1);
647     printf ("unknown bit: %d\n", ($flags >>  0) & 1);
648
649 }
650
651 sub eadump {
652
653     print "\n";
654     print "-EA--------:\n";
655
656     read(INFILE,$buf,2);
657     print "pad        : ";
658     hexdump($buf, 2, 4, "");
659
660     read(INFILE,$buf,4);
661     print "magic      : ";
662     hexdump($buf, 4, 4, "");
663
664     read(INFILE,$buf,4);
665     $ea_debug_tag = unpack("N", $buf );
666     printf("debug_tag  : %08X", $ea_debug_tag);
667     printf(" : %d\n", $ea_debug_tag);
668
669     read(INFILE,$buf,4);
670     $ea_total_size = unpack("N", $buf );
671     printf("total_size : %08X", $ea_total_size);
672     printf(" : %d\n", $ea_total_size);
673
674     read(INFILE,$buf,4);
675     $ea_data_start = unpack("N", $buf );
676     printf("data_start : %08X", $ea_data_start);
677     printf(" : %d\n", $ea_data_start);
678
679     read(INFILE,$buf,4);
680     $ea_data_length = unpack("N", $buf );
681     printf("data_length: %08X", $ea_data_length);
682     printf(" : %d\n", $ea_data_length);
683
684     read(INFILE,$buf,4);
685     print "reserved[0]: ";
686     hexdump($buf, 4, 4, "");
687
688     read(INFILE,$buf,4);
689     print "reserved[1]: ";
690     hexdump($buf, 4, 4, "");
691
692     read(INFILE,$buf,4);
693     print "reserved[2]: ";
694     hexdump($buf, 4, 4, "");
695
696     read(INFILE,$buf,2);
697     print "flags      : ";
698     hexdump($buf, 2, 4, "");
699
700     read(INFILE,$buf,2);
701     $ea_num_attrs = unpack("n", $buf );
702     printf("num_attrs  : %04X", $ea_num_attrs);
703     printf("     : %d\n", $ea_num_attrs);
704
705     $pos = tell(INFILE);
706
707     for ($i = 0 ; $i < $ea_num_attrs ; $i++) {
708
709         $pos = (($pos & 0x3) == 0) ? ($pos) : ((($pos >> 2) + 1) << 2);
710         seek(INFILE, $pos, 0);
711
712         print "-EA ENTRY--:\n";
713
714         read(INFILE,$buf,4);
715         $ea_offset = unpack("N", $buf );
716         printf("offset     : %08X", $ea_offset);
717         printf(" : %d\n", $ea_offset);
718
719         read(INFILE,$buf,4);
720         $ea_length = unpack("N", $buf );
721         printf("length     : %08X", $ea_length);
722         printf(" : %d\n", $ea_length);
723
724         read(INFILE,$buf,2);
725         print "flags      : ";
726         hexdump($buf, 2, 4, "");
727
728         read(INFILE,$buf,1);
729         $ea_namelen = unpack("C", $buf );
730         printf("namelen    : %02X", $ea_namelen);
731         printf("       : %d\n", $ea_namelen);
732
733         $ea_namequo = $ea_namelen >> 4;
734         $ea_namerem = $ea_namelen & 0xF;
735         print "-EA NAME---:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)\n";
736         rawdump($ea_namequo, $ea_namerem);
737
738         $pos = tell(INFILE);
739
740         seek(INFILE, $ea_offset, 0);
741         $ea_quo = $ea_length >> 4;
742         $ea_rem = $ea_length & 0xF;
743         print "-EA VALUE--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)\n";
744         rawdump($ea_quo, $ea_rem);
745     }
746 }
747
748 sub bedump  {
749     my ($ofst, $len) = @_;
750     my ($i);
751     my ($value);
752
753     seek(INFILE, $ofst, 0);
754
755     printf("%2dbit-BE   : ", $len * 8 );
756
757     $value = 0;
758     for ( $i=0 ; $i < $len ; $i++ ) {
759         read(INFILE,$buf,1);
760         $bytedata[$i] = unpack("C", $buf );
761           $value += $bytedata[$i] << (($len - $i -1) * 8) ;
762     }
763
764     for ( $i=0 ; $i < $len ; $i++ ) {
765         printf("%02X", $bytedata[$i]);
766     }
767
768     printf(" : %s", $value);
769     print "\n";
770 }
771
772 sub ledump  {
773     my ($ofst, $len) = @_;
774     my ($i);
775     my ($value);
776
777     seek(INFILE, $ofst, 0);
778
779     printf("%2dbit-LE   : ", $len * 8 );
780
781     $value = 0;
782     for ( $i=0 ; $i < $len ; $i++ ) {
783         read(INFILE,$buf,1);
784         $bytedata[$len - $i - 1] = unpack("C", $buf );
785           $value += $bytedata[$len - $i -1] << ($i * 8) ;
786     }
787
788     for ( $i=0 ; $i < $len ; $i++ ) {
789         printf("%02X", $bytedata[$i]);
790     }
791
792     printf(" : %s", $value);
793     print "\n";
794 }
795
796 sub rawdump {
797     my ($quo, $rem) = @_;
798     my ($addrs, $line, $buf);
799
800     $addrs = 0;
801     for ( $line = 0 ; $line < $quo ; $line++) {
802         read(INFILE, $buf, 16);
803         printf ( "%08X   :", $addrs);
804         hexdump($buf, 16, 16, " ");
805         $addrs = $addrs + 0x10;
806     }
807     if ( $rem != 0 ) {
808         read(INFILE, $buf, $rem);
809         printf ( "%08X   :", $addrs);
810         hexdump($buf, $rem, 16, " ");
811     }
812 }
813
814 sub hexdump {
815     my ($buf, $len, $col, $delimit) = @_;
816     my ($i);
817
818     $hexstr = "";
819     $ascstr = "";
820
821     for ( $i=0 ; $i < $len ; $i++ ) {
822         $val = substr($buf, $i, 1);
823         $ascval = ord($val);
824         $hexstr .= sprintf("%s%02X", $delimit, $ascval);
825
826         if (($ascval < 32) || (  $ascval > 126 )) {
827             $val = ".";
828         }
829         $ascstr .= $val;
830     }
831     for ( ; $i < $col ; $i++) {
832         $hexstr .= "  ".$delimit;
833         $ascstr .= " ";
834     }
835
836     printf("%s : %s", $hexstr,$ascstr);
837
838     print "\n";
839 }
840
841 sub checkea {
842     my ($file) = @_;
843
844     $file =~ s/\\/\\\\/g;
845     $file =~ s/\"/\\\"/g;
846     $file =~ s/\$/\\\$/g;
847     $file =~ s/\`/\\\`/g;
848     if ( $eacommand == 1 ) {
849         open(EALIST, "getfattr \"$file\" |");
850         while(<EALIST>) {
851             if ( $_ eq "user.org.netatalk.Metadata\n" ) {
852                 close (EALIST);
853                 return 1;
854             }
855         }
856         close (EALIST);
857         return 0;
858     } elsif ( $eacommand == 2 ) {
859         open(EALIST, "attr -q -l \"$file\" |");
860         while(<EALIST>) {
861             if ( $_ eq "org.netatalk.Metadata\n" ) {
862                 close (EALIST);
863                 return 1;
864             }
865         }
866         close (EALIST);
867         return 0;
868     } elsif ( $eacommand == 3 ) {
869         open(EALIST, "runat \"$file\" ls -1 |");
870         while(<EALIST>) {
871             if ( $_ eq "org.netatalk.Metadata\n" ) {
872                 close (EALIST);
873                 return 1;
874             }
875         }
876         close (EALIST);
877         return 0;
878     } elsif ( $eacommand == 4 ) {
879         open(EALIST, "lsextattr -q user \"$file\" |");
880         while(<EALIST>) {
881             $_ = "\t".$_;
882             if ( $_ =~ /\torg\.netatalk\.Metadata[\n\t]/ ) {
883                 close (EALIST);
884                 return 1;
885             }
886         }
887         close (EALIST);
888         return 0;
889     } else {
890         return 0;
891     }
892 }
893
894 sub eaopenfile {
895     my ($file) = @_;
896
897     $file =~ s/\\/\\\\/g;
898     $file =~ s/\"/\\\"/g;
899     $file =~ s/\$/\\\$/g;
900     $file =~ s/\`/\\\`/g;
901     ($eatempfh, $eatempfile) = tempfile(UNLINK => 1);
902
903     if ( $eacommand == 1 ) {
904         system("getfattr --only-values -n user.org.netatalk.Metadata \"$file\" > $eatempfile");
905     } elsif ( $eacommand == 2 ) {
906         system("attr -q -g org.netatalk.Metadata \"$file\" > $eatempfile");
907     } elsif ( $eacommand == 3 ) {
908         system("runat \"$file\" cat org.netatalk.Metadata > $eatempfile");
909     } elsif ( $eacommand == 4 ) {
910         system("getextattr -q user org.netatalk.Metadata \"$file\" > $eatempfile");
911     } else {
912         return "";
913     }
914
915     close($eatempfh);
916     return $eatempfile;
917 }
918
919 #EOF