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