Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.3 KiB

  1. package CabComp;
  2. use strict;
  3. use Carp;
  4. use File::Temp;
  5. use File::Path; # File::Temp has a problem cleaning up recursive
  6. # directories (passes "bad" values to rmtree)
  7. use Win32::OLE qw(in);
  8. use BinComp;
  9. sub new {
  10. my $class = shift;
  11. my $instance = {
  12. DIFF => '',
  13. ERR => ''
  14. };
  15. return bless $instance;
  16. }
  17. sub GetLastError {
  18. my $self = shift;
  19. if (!ref $self) {croak "Invalid object reference"}
  20. return $self->{ERR};
  21. }
  22. sub GetLastDiff {
  23. my $self = shift;
  24. if (!ref $self) {croak "Invalid object reference"}
  25. return $self->{DIFF};
  26. }
  27. sub GetCabFileInfo {
  28. my $self = shift;
  29. my $cab_file = shift;
  30. if (!ref $self) {confess "Invalid object referenc"}
  31. if ( ! -e $cab_file ) {
  32. $self->{ERR} = "Invalid file: $cab_file";
  33. return;
  34. }
  35. my @files = `cabarc.exe l $cab_file`;
  36. if ( $! ) {
  37. $self->{ERR} = "Error calling cabarc.exe: $!";
  38. return;
  39. }
  40. elsif ( $? ) {
  41. $self->{ERR} = "Error returned from cabarc: ".($?>>8);
  42. return;
  43. }
  44. return grep {/\S+\s+\d+\s\d+\/\d+\/\d+\s\d+:\d+:\d+\s+\S+/} @files;
  45. }
  46. #
  47. # 0 - different
  48. # 1 - same
  49. # undefined - error
  50. #
  51. sub compare {
  52. my $self = shift;
  53. my $base = shift;
  54. my $upd = shift;
  55. if (!ref $self) {croak "Invalid object reference"}
  56. if (!$base||!$upd) {croak "Invalid function call -- missing required parameters"}
  57. my %cab_files;
  58. $self->{ERR} = '';
  59. my @base_files = $self->GetCabFileInfo( $base );
  60. return if $self->{ERR};
  61. my @upd_files = $self->GetCabFileInfo( $upd );
  62. return if $self->{ERR};
  63. foreach ( @base_files ) {
  64. my @info = split;
  65. $cab_files{lc$info[0]} = $info[2];
  66. }
  67. foreach ( @upd_files ) {
  68. my @info = split;
  69. my $prev_size = $cab_files{lc$info[0]};
  70. if ( !defined $prev_size ) {
  71. $self->{DIFF} = "File $info[0] does not appear in both cabs";
  72. return 0;
  73. }
  74. elsif ( $info[2] != $prev_size ) {
  75. $self->{DIFF} = "File $info[0] is different in size between the cabs ($prev_size vs $info[2])";
  76. return 0;
  77. }
  78. else {
  79. delete $cab_files{lc$info[0]};
  80. }
  81. }
  82. my @excess_files = sort keys %cab_files;
  83. if ( @excess_files ) {
  84. $self->{DIFF} = "File $excess_files[0] does not appear in both cabs";
  85. return 0;
  86. }
  87. my $scratch_dir = File::Temp::tempdir( DIR => $ENV{TEMP}, CLEANUP => 1 );
  88. if ( !$scratch_dir ) {
  89. $self->{ERR} = "Unable to create temporary directory: $!";
  90. return;
  91. }
  92. # Now we have to actually compare the files one at a time
  93. my $verbose = `cabarc.exe -o -p x $base $scratch_dir\\a\\`;
  94. if ($!) {
  95. $self->{ERR} = "Unable to execute cabarc: $!";
  96. File::Path::rmtree( "$scratch_dir\\a" ) if -d "$scratch_dir\\a";
  97. return;
  98. }
  99. if ($?) {
  100. $self->{ERR} = $verbose;
  101. return;
  102. }
  103. $verbose = `cabarc.exe -o -p x $upd $scratch_dir\\b\\`;
  104. if ($!) {
  105. $self->{ERR} = "Unable to execute cabarc: $!";
  106. File::Path::rmtree( "$scratch_dir\\a" ) if -d "$scratch_dir\\a";
  107. File::Path::rmtree( "$scratch_dir\\b" ) if -d "$scratch_dir\\b";
  108. return;
  109. }
  110. if ($?) {
  111. $self->{ERR} = $verbose;
  112. File::Path::rmtree( "$scratch_dir\\a" ) if -d "$scratch_dir\\a";
  113. File::Path::rmtree( "$scratch_dir\\b" ) if -d "$scratch_dir\\b";
  114. return;
  115. }
  116. my $bin_comp = new BinComp;
  117. foreach ( @upd_files ) {
  118. my @info = split;
  119. my $diff = $bin_comp->compare( "$scratch_dir\\a\\$info[0]", "$scratch_dir\\b\\$info[0]" );
  120. if ( !defined $diff ) {
  121. $self->{ERR} = $bin_comp->GetLastError();
  122. File::Path::rmtree( "$scratch_dir\\a" ) if -d "$scratch_dir\\a";
  123. File::Path::rmtree( "$scratch_dir\\b" ) if -d "$scratch_dir\\b";
  124. return;
  125. }
  126. elsif( !$diff ) {
  127. $self->{DIFF} = $bin_comp->GetLastDiff();
  128. File::Path::rmtree( "$scratch_dir\\a" ) if -d "$scratch_dir\\a";
  129. File::Path::rmtree( "$scratch_dir\\b" ) if -d "$scratch_dir\\b";
  130. return 0;
  131. }
  132. }
  133. File::Path::rmtree( "$scratch_dir\\a" ) if -d "$scratch_dir\\a";
  134. File::Path::rmtree( "$scratch_dir\\b" ) if -d "$scratch_dir\\b";
  135. return 1;
  136. }
  137. 1;