PERL-Shortcuts
- !/usr/bin/perl
- PLANS
- =====
- Renaming, global-naming, merging etc
- Repairing (broken links and re-locating)
- Could update the copy-contacts script to follow shortcuts properly
- Later add to the PERL-NW allowing either cmd or bg
- Add generic nodal layer (atts-array and name with migration/"casting" rules)
- Add spreadsheet parsing
- ======================================================================================================================= #
sub createShortcut; sub readShortcut; sub quadNullString; sub intToDWord; sub intToWord; sub scanTree; sub searchTree; sub dumpShortcut;
- ======================================================================================================================= #
- Create a shortcut file
sub createShortcut { ($shortcut, $target, $description) = shift;
- PHP: if (!ereg("^([A-Za-z]):[\\](.+)$",$target,$m)) return;
return unless $target =~ /^([a-z]):[\\](.+)$/i; $drive = $1; $target = $2;
- Create shortcut data structure
$lnk = "\x4c\x00\x00\x00"; # L $lnk .= "\x01\x14\x02\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46"; # GUID $lnk .= "\x07\x00\x00\x00"; # Flags (bits: 0=itemlist 1=file/folder 2=description 3=relative path) $lnk .= "\x10\x00\x00\x00"; # File attributes $lnk .= "\x00\x00\x00\x00\x00\x00\x00\x00"; # Time 1 $lnk .= "\x00\x00\x00\x00\x00\x00\x00\x00"; # Time 2 $lnk .= "\x00\x00\x00\x00\x00\x00\x00\x00"; # Time 3 $lnk .= "\x00\x00\x00\x00"; # File length $lnk .= "\x00\x00\x00\x00"; # Icon number $lnk .= "\x01\x00\x00\x00"; # normal window $lnk .= "\x00\x00\x00\x00"; # Hotkey $lnk .= "\x00\x00\x00\x00"; # reserved $lnk .= "\x00\x00\x00\x00"; # reserved
- Item id list (just copy dump for now)
$lnk .= intToWord(0x3e + length $target);
$lnk .= "\x14\x00"; # First item (?) $lnk .= "\x1f\x0f\xe0\x4f"; $lnk .= "\xd0\x20\xea\x3a"; $lnk .= "\x69\x10\xa2\xd8"; $lnk .= "\x08\x00\x2b\x30"; $lnk .= "\x30\x9d";
$lnk .= "\x19\x00"; $lnk .= "\x23$drive\x3a\x5c"; #Drive $lnk .= "\x00\x00\xb0\x0c"; $lnk .= "\xc1\x00\x00\x00"; $lnk .= "\x00\x00\x50\x42"; $lnk .= "\x42\x00\x00\x00"; $lnk .= "\x00\x71\x65";
$lnk .= intToWord(0xf + length $target); $lnk .= "\x31\x00\x00\x00"; $lnk .= "\x00\x00\x56\x31"; $lnk .= "\xf2\x2c\x10\x00"; $lnk .= "$target\x00"; #Path
$lnk .= "\x00\x00";
$lnk .= "\x30\x00\x00\x00"; # Offset to description
- File location info (offsets are from start of this struct)
$lnk .= "\x2c\x00\x00\x00"; # Total length $lnk .= "\x1c\x00\x00\x00"; # this blocks length (always &1c) $lnk .= "\x01\x00\x00\x00"; # Flags (local volume only) $lnk .= "\x1c\x00\x00\x00"; # Offset to local volume table $lnk .= "\x00\x00\x00\x00"; $lnk .= "\x00\x00\x00\x00"; # Offset to network volume table $lnk .= "\x00\x00\x00\x00";
- Local volume table
$lnk .= "\x18\x00\x00\x00"; # Length of table $lnk .= "\x03\x00\x00\x00"; # fixed disk $lnk .= "\x00\x00\x00\x00"; # Volume serial $lnk .= "\x00\x00\x00\x00"; # Offset to volume label
- Description String
$lnk .= intToWord(length $description); # Length of string $lnk .= $description;
- Extra
$lnk .= "\x00\x00\x00\x00"; # End
- Write shortcut to file
open FH, '>', $shortcut; print FH $lnk; close FH; }
- Extract target informaton from a shortcut
sub readShortcut { $shortcut = shift; global $ROOT;
# Read in shortcut binary file $bin=implode(,file("$ROOT$shortcut")); $target=;
# Count blocks in item_id_list $ptr=0x4e; $len=1; while ($len>0) { $len=ord(substr($bin,$ptr,1))+256*ord(substr($bin,$ptr+1,1)); $ptr+=$len; } $ptr+=2;
$descrip=; $flags=ord(substr($bin,0x14,1)); if ($flags&4) { $doffset=ord(substr($bin,$ptr,1))+256*ord(substr($bin,$ptr+1,1)); $dptr=$ptr+$doffset; $dlen=ord(substr($bin,$dptr,1))+256*ord(substr($bin,$dptr+1,1)); $descrip=substr($bin,$dptr+2,$dlen); # test if fatware's mangled it and return with target hacked from description - fuckin fatware! if (substr($descrip,0,2)=="[\x00") { $descrip=substr($bin,$dptr+3,$dlen*2-4); $target=$ROOT.str_replace("\x00","",$descrip); }
- else if (substr($descrip,0,1)=="[") {
- # one of ours
- $target=$root.substr($descrip,1,strlen($descrip)-2);
- print "Ours - $target\n";
- }
$ptr+=4; }
if ($target==) { # It's not one of ours - just extract all strings and pick best
- preg_match_all("/[ ^!@$^&\\[\\]()\\-_\\\\\\/+=~,.{}0-9a-zA-Z]{4,}\\x00/",$bin,$m);
- foreach ($m[0] as $n) {
- $n=str_replace("\x00","",$n);
- if (ereg(":",$n)) {if (ereg("^.:",$n)) $target.=$n;}
- else if (ereg("\\\\",$n)&&!ereg("\\\\\\\\",$n)) $target.=$n;
- }
}
# Validate extracted info if ($target==) { print "\nCouldn't extract target from $shortcut\n";
- foreach ($m[0] as $n) print "$n\n";
}
- else if (!file_exists($target)) {
- #print "\nBroken link found:\n$shortcut\n-->$target\n";
- # Attempt to repair broken link
- if (ereg("(\\\\[^\\\\]+\\\\[^\\\\]+)$",$target,$m)) {
- if (file_exists($ROOT.$m[1])) {
- $target=str_replace("/","\\",$target);
- print "Repairing:$target\n";
- print $target;
- createShortcut("$ROOT$shortcut",$target,'['.$m[1].']');
- }
- }
- }
return $target; }
- UTILITY FUNCTIONS
sub quadNullString { $s = shift; $l = 1 + length $s; if (($nulls = ($l%4)) > 0) {$nulls = 4-$nulls} #return $s.str_repeat("\x00", $nulls+1); }
sub intToDWord { $i = shift; return chr($i&0xff).chr(($i&0xff00)>>8).chr(($i&0xff0000)>>16).chr(($i&0xff000000)>>24); }
sub intToWord { $i = shift; return chr($i&0xff).chr(($i&0xff00)>>8); }
- Recursively scan dir structure and apply house-keeping rules
sub scanTree { $dir = shift; global $ROOT;
- if ($handle = opendir("$ROOT$dir")) {
- while (false !== ($name = readdir($handle))) {
- unless ($name =~ /^[.]/) {
- scanTree("$dir/$name") if is_dir("$dir/$name");
- echo "$dir/$name\n";
- readShortcut("$dir/$name") if (ereg('.lnk$',$name));
- }
- }
- }
closedir($handle); }
- Recursively search structure for a file
sub searchTree { ($dir, $target) = shift; global $ROOT; $target = uc $target;
- if ($handle = opendir("$ROOT$dir")) {
- while (false !== ($name = readdir($handle))) {
- if ($target eq uc $name)) {
- closedir($handle);
- return "$dir$name";
- }
- else if ($name!='.'&&$name!='..'&&is_dir("$ROOT$dir$name"))
- if ($name=searchTree("$dir$name/",$target)) {
- closedir($handle);
- return $name;
- }
- }
- }
#closedir($handle); return false; }
- SHORTCUT DEBUGGING FUNCTIONS
- Debugging - dump shortcut files
sub dump { $hex = shift; $dump = ; $o = 0; for ($i = 0; $i < length $hex;) {
$d=dechex($i);if (length $d == 1) {$dump .= "000$d : "} else {$dump .= "00$d : "}
$d1=dechex(ord(substr($hex,$i++,1))); if (strlen($d1)==1) $dump.="0$d1"; else $dump.="$d1"; $d2=dechex(ord(substr($hex,$i++,1))); if (strlen($d2)==1) $dump.="0$d2"; else $dump.="$d2"; $d3=dechex(ord(substr($hex,$i++,1))); if (strlen($d3)==1) $dump.="0$d3"; else $dump.="$d3"; $d4=dechex(ord(substr($hex,$i++,1))); if (strlen($d4)==1) $dump.="0$d4"; else $dump.="$d4";
$dump.=' : '; $d1=hexdec($d1); $d2=hexdec($d2); $d3=hexdec($d3); $d4=hexdec($d4); if ($d1<32||$d1>126) {$dump .= '.'} else {$dump .= chr($d1)} if ($d2<32||$d2>126) {$dump .= '.'} else {$dump .= chr($d2)} if ($d3<32||$d3>126) {$dump .= '.'} else {$dump .= chr($d3)} if ($d4<32||$d4>126) {$dump .= '.'} else {$dump .= chr($d4)}
# Output comments with shortcut dump if ($i==4) {$dump .= " L\n"} elsif ($i==8) {$dump .= " GUID"} elsif ($i==20) {$dump .= "\n"} elsif ($i==24) {$dump .= " Flags\n"} elsif ($i==28) {$dump .= " File Attributes\n"} elsif ($i==32) {$dump .= " Time Stamps"} elsif ($i==52) {$dump .= "\n"} elsif ($i==56) {$dump .= " File Length\n"} elsif ($i==60) {$dump .= " Icon Number\n"} elsif ($i==64) {$dump .= " Window State\n"} elsif ($i==68) {$dump .= " Hotkey\n"} elsif ($i==72) {$dump .= " Reserved"} elsif ($i==0x50) {$dump .= " (Skipping Item ID List)\n\nFile Location Block:"; #$o+=$d1-2; $i+=$o; # skip item id list } elsif ($i==0x54+$o) {$dump .= " ???\n"} elsif ($i==0x58+$o) {$dump .= " Length of this structure\n"} elsif ($i==0x5c+$o) {$dump .= " Flags\n"} elsif ($i==0x60+$o) {$dump .= " Offset to LVtab\n"} elsif ($i==0x64+$o) {$dump .= " Offset to local Path\n"}
$dump .= " \n\n";
} return $dump; }