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