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