UPD: [Cpio plugin] Added detecting archive by header, detecting other cpio types. Fixed reading binary archive type.

This commit is contained in:
cobines 2010-04-29 15:42:19 +00:00
commit 4ea6bef2b7
4 changed files with 236 additions and 118 deletions

View file

@ -21,8 +21,6 @@ uses
cpio_def in 'cpio_def.pas',
cpio_archive in 'cpio_archive.pas';
{$E wcx}
exports
CloseArchive name 'CloseArchive',
GetPackerCaps name 'GetPackerCaps',
@ -30,7 +28,8 @@ exports
ProcessFile name 'ProcessFile',
ReadHeader name 'ReadHeader',
SetChangeVolProc name 'SetChangeVolProc',
SetProcessDataProc name 'SetProcessDataProc';
SetProcessDataProc name 'SetProcessDataProc',
CanYouHandleThisFile;
begin
end.

View file

@ -58,6 +58,7 @@ function ReadHeader(hArcData : TArcHandle; var HeaderData : THeaderData) : Inte
function ProcessFile(hArcData : TArcHandle; Operation : Integer; DestPath : PChar; DestName : PChar) : Integer; stdcall;
procedure SetProcessDataProc(hArcData : TArcHandle; ProcessDataProc : TProcessDataProc); stdcall;
procedure SetChangeVolProc(hArcData : TArcHandle; ChangeVolProc : TChangeVolProc); stdcall;
function CanYouHandleThisFile(FileName: PAnsiChar): Boolean; stdcall;
implementation
@ -156,7 +157,7 @@ begin
Result := E_SUCCESS;
end;
function ReadHeader;
function ReadHeader(hArcData : TArcHandle; var HeaderData : THeaderData): Integer;
var
i_rec : Integer;
arec : PArchiveRec;
@ -175,14 +176,14 @@ begin
Break
end
else begin
if header.records[08] <> 0 then begin
if header.filesize <> 0 then begin
with HeaderData do begin
copy_str2buf(TStrBuf(ArcName), arec^.fname);
copy_str2buf(TStrBuf(FileName), header.filename);
PackSize := header.records[08];
UnpSize := header.records[08];
FileAttr := $20;
FileTime := UnixTimeToDosTime(header.records[07], True);
PackSize := header.filesize;
UnpSize := header.filesize;
FileAttr := header.mode;
FileTime := UnixTimeToDosTime(header.mtime, True);
end;{with}
Result := 0;
Break;
@ -222,7 +223,7 @@ begin
case Operation of
PK_TEST : begin
faborted:=false;
fsize := head.records[08];
fsize := head.filesize;
buf_size := 65536;
GetMem(buf, buf_size);
fgReadError := False;
@ -250,7 +251,7 @@ begin
else if fgReadError then Result := E_EREAD
else begin
Result := 0;
if arec^.last_header.oldhdrtype then begin
if arec^.last_header.IsOldHeader then begin
if not AlignFilePointer(arec^.handle_file, 2) then Result := E_EREAD;
end else
if not AlignFilePointer(arec^.handle_file, 4) then Result := E_EREAD;
@ -258,10 +259,10 @@ begin
FreeMem(buf, 65536);
end;{PK_TEST}
PK_SKIP : begin
Seek(arec^.handle_file, FilePos(arec^.handle_file) + LongInt(head.records[08]));
Seek(arec^.handle_file, FilePos(arec^.handle_file) + LongInt(head.filesize));
if IOResult = 0 then begin
Result := 0;
if arec^.last_header.oldhdrtype then begin
if arec^.last_header.IsOldHeader then begin
if not AlignFilePointer(arec^.handle_file, 2) then Result := E_EREAD;
end else
if not AlignFilePointer(arec^.handle_file, 4) then Result := E_EREAD;
@ -275,7 +276,7 @@ begin
Rewrite(cpio_file, 1);
if IOResult <> 0 then Result := E_ECREATE
else begin
fsize := head.records[08];
fsize := head.filesize;
buf_size := 65536;
GetMem(buf, buf_size);
fgReadError := False;
@ -315,12 +316,12 @@ begin
else if fgReadError then Result := E_EREAD
else begin
Result := 0;
if arec^.last_header.oldhdrtype then begin
if arec^.last_header.IsOldHeader then begin
if not AlignFilePointer(arec^.handle_file, 2) then Result := E_EREAD;
end else
if not AlignFilePointer(arec^.handle_file, 4) then Result := E_EREAD;
end;
FileSetDate(tfilerec(cpio_file).handle,UnixTimeToDosTime(head.records[07], True));
FileSetDate(tfilerec(cpio_file).handle,UnixTimeToDosTime(head.mtime, True));
CloseFile(cpio_file);
if result<>0 then
Erase(cpio_file);
@ -358,6 +359,15 @@ begin
end;
end;
function CanYouHandleThisFile(FileName: PAnsiChar): Boolean; stdcall;
begin
try
Result:= IsCPIOArchive(StrPas(FileName));
except
Result := False;
end;
end;
initialization
aList := TList.Create;
finalization

View file

@ -13,40 +13,25 @@ unit cpio_def;
interface
{$ifdef ver90}
type longword=longint;
{$endif}
{$ifdef ver100}
type longword=longint;
{$endif}
type
CPIO_Header = record
records : array [1..14] of LongWord;
filename : String;
origname : String;
oldhdrtype:boolean;
(* records array contains fields :
{01}c_magic : LongWord; //"070701" for "new" portable format "070702" for CRC format
{02}c_ino : LongWord;
{03}c_mode : LongWord;
{04}c_uid : LongWord;
{05}c_gid : LongWord;
{06}c_nlink : LongWord;
{07}c_mtime : LongWord;
{08}c_filesize : LongWord; //must be 0 for FIFOs and directories
{09}c_maj : LongWord;
{10}c_min : LongWord;
{11}c_rmaj : LongWord; //only valid for chr and blk special files
{12}c_rmin : LongWord; //only valid for chr and blk special files
{13}c_namesize : LongWord; //count includes terminating NUL in pathname
{14}c_chksum : LongWord; //0 for "new" portable format; for CRC format the sum of all the bytes in the file
*)
magic,
dev_major,
dev_minor,
inode,
mode,
uid,
gid,
nlink,
mtime,
filesize,
namesize: Longword;
filename : UTF8String;
origname : UTF8String;
IsOldHeader: Boolean;
end;{CPIO_Header}
(* Old CPIO header structure:*)
type tOldHdr=packed record
TOldBinaryHeader=packed record
c_magic,
c_dev,
c_ino,
@ -59,8 +44,39 @@ type tOldHdr=packed record
c_namesize:word;
c_filesize1,c_filesize2:word;
(* char c_name[c_namesize rounded to word];*)
end;
end;
TOldCharHeader=packed record
c_magic : array[0..5] of AnsiChar; {070707}
c_dev : array[0..5] of AnsiChar;
c_ino : array[0..5] of AnsiChar;
c_mode : array[0..5] of AnsiChar;
c_uid : array[0..5] of AnsiChar;
c_gid : array[0..5] of AnsiChar;
c_nlink : array[0..5] of AnsiChar;
c_rdev : array[0..5] of AnsiChar;
c_mtime : array[0..10] of AnsiChar;
c_namesize: array[0..5] of AnsiChar;
c_filesize: array[0..10] of AnsiChar;
end;
TNewCharHeader=packed record
c_magic : array[0..5] of AnsiChar; {070701} {070702 - CRC format}
c_ino : array[0..7] of AnsiChar;
c_mode : array[0..7] of AnsiChar;
c_uid : array[0..7] of AnsiChar;
c_gid : array[0..7] of AnsiChar;
c_nlink : array[0..7] of AnsiChar;
c_mtime : array[0..7] of AnsiChar;
c_filesize : array[0..7] of AnsiChar; //must be 0 for FIFOs and directories
c_devmajor : array[0..7] of AnsiChar;
c_devminor : array[0..7] of AnsiChar;
c_rdevmajor: array[0..7] of AnsiChar; //only valid for chr and blk special files
c_rdevminor: array[0..7] of AnsiChar; //only valid for chr and blk special files
c_namesize : array[0..7] of AnsiChar; //count includes terminating NUL in pathname
c_check : array[0..7] of AnsiChar; //0 for "new" portable format; for CRC format the sum of all the bytes in the file
end;
implementation
end.
end.

View file

@ -22,12 +22,13 @@ unit cpio_io;
interface
uses
cpio_def;
cpio_def, Classes;
type
TStrBuf = array[1..260] of Char;
function CPIO_ReadHeader(var f : file; var header : CPIO_Header) : Boolean;
function IsCPIOArchive(FileName: UTF8String): Boolean;
function AlignFilePointer(var f : file; align : Integer) : Boolean;
procedure copy_str2buf(var buf : TStrBuf; s : AnsiString);
@ -111,89 +112,181 @@ begin
end;
end;
function swapbytes(w:word):word;
function OctalToDec(Octal: String): Longword;
var
i: Integer;
begin
result:=256*lo(w)+hi(w);
Result := 0;
for i := 1 to Length(Octal) do
begin
Result := Result shl 3;
case Octal[i] of
'0'..'7':
Result := Result + Longword(Ord(Octal[i]) - Ord('0'));
end;
end;
end;
function CPIO_ReadHeader;
function HexToDec(Hex: String): Longword;
var
tmp_buf : array [0..259] of Char;
oldhdr : toldhdr absolute tmp_buf;
code, i : Integer;
loadlen,ofs: Integer;
value : LongWord;
i: Integer;
begin
Result := 0;
for i := 1 to Length(Hex) do
begin
Result := Result shl 4;
case Hex[i] of
'0'..'9':
Result := Result + LongWord(Ord(Hex[i]) - Ord('0'));
'A'..'F':
Result := Result + LongWord(Ord(Hex[i]) - Ord('A')) + 10;
'a'..'f':
Result := Result + LongWord(Ord(Hex[i]) - Ord('a')) + 10;
end;
end;
end;
function CPIO_ReadHeader(var f : file; var header : CPIO_Header): Boolean;
var
Buffer : array [0..259] of AnsiChar;
OldHdr : TOldBinaryHeader absolute Buffer;
OdcHdr : TOldCharHeader absolute Buffer;
NewHdr : TNewCharHeader absolute Buffer;
ofs : Integer;
begin
Result := False;
{First, check the type of header (old or new)}
tmp_buf[0]:='$';
BlockRead(f, tmp_buf[1], 6);
{First, check the type of header}
BlockRead(f, Buffer[0], 6);
if IOResult <> 0 then Exit;
header.oldhdrtype:=false;
if (tmp_buf[1]=#$71) and (tmp_buf[2]=#$C7) then begin {Old format!}
header.oldhdrtype:=true;
move(tmp_buf[1],tmp_buf[0],6);
BlockRead(f, tmp_buf[6], sizeof(tOldHdr)-6);
header.IsOldHeader := False;
// Old binary format.
if PWord(@Buffer[0])^ = $71C7 then
begin
header.IsOldHeader := True;
BlockRead(f, Buffer[6], SizeOf(TOldBinaryHeader) - 6);
if IOResult <> 0 then Exit;
with header,oldhdr do begin
records[1]:=swapbytes(c_magic);
records[2]:=swapbytes(c_ino);
records[3]:=swapbytes(c_mode);
records[4]:=swapbytes(c_uid);
records[5]:=swapbytes(c_gid);
records[6]:=swapbytes(c_nlink);
records[7]:=65536*swapbytes(c_mtime1)+swapbytes(c_mtime2);
records[8]:=65536*swapbytes(c_filesize1)+swapbytes(c_filesize2);
records[9]:=0;
records[10]:=0;
records[11]:=0;
records[12]:=0;
records[13]:=swapbytes(c_namesize);
records[14]:=0;
with header, OldHdr do
begin
magic := c_magic;
dev_major := c_dev;
dev_minor := 0;
inode := c_ino;
mode := c_mode;
uid := c_uid;
gid := c_gid;
nlink := c_nlink;
mtime := 65536 * c_mtime1 + c_mtime2;
filesize := 65536 * c_filesize1 + c_filesize2;
namesize := c_namesize;
end;
end else if strlcomp(tmp_buf,'$0707',5)=0 then begin
tmp_buf[7]:=#0;
Val(tmp_buf, value, code);
header.records[1] := value;
for i := 2 to 14 do begin
loadlen := 8;
tmp_buf[0]:='$';
BlockRead(f, tmp_buf[1], loadlen);
if IOResult <> 0 then Exit;
tmp_buf[loadlen+1]:=#0;
Val(tmp_buf, value, code);
header.records[i] := value;
end;
end else
exit;
end
if header.records[13]<0 then exit; {Error!}
{Read name}
ofs:=0;
if header.records[13]>259 then begin
ofs:=header.records[13]-259;
header.records[13]:=259;
// Old Ascii format.
else if strlcomp(Buffer, '070707', 6) = 0 then
begin
BlockRead(f, Buffer[6], SizeOf(TOldCharHeader) - 6);
if IOResult <> 0 then Exit;
with header, OdcHdr do
begin
magic := OctalToDec(c_magic);
dev_major := OctalToDec(c_dev);
dev_minor := 0;
inode := OctalToDec(c_ino);
mode := OctalToDec(c_mode);
uid := OctalToDec(c_uid);
gid := OctalToDec(c_gid);
nlink := OctalToDec(c_nlink);
mtime := OctalToDec(c_mtime);
filesize := OctalToDec(c_filesize);
namesize := OctalToDec(c_namesize);
end;
end
// New Ascii format.
else if (strlcomp(Buffer, '070701', 6) = 0) or
(strlcomp(Buffer, '070702', 6) = 0) then
begin
BlockRead(f, Buffer[6], SizeOf(TNewCharHeader) - 6);
if IOResult <> 0 then Exit;
with header, NewHdr do
begin
magic := HexToDec(c_magic);
dev_major := HexToDec(c_devmajor);
dev_minor := HexToDec(c_devminor);
inode := HexToDec(c_ino);
mode := HexToDec(c_mode);
uid := HexToDec(c_uid);
gid := HexToDec(c_gid);
nlink := HexToDec(c_nlink);
mtime := HexToDec(c_mtime);
filesize := HexToDec(c_filesize);
namesize := HexToDec(c_namesize);
end;
end
else
Exit;
with header do
begin
if namesize = 0 then exit; {Error!}
{Read name}
ofs:=0;
if namesize > 259 then
begin
ofs := namesize - 259;
namesize := 259;
end;
FillChar(Buffer, SizeOf(Buffer), #0);
BlockRead(f, Buffer, namesize);
if IOResult <> 0 then Exit;
SetString(filename, Buffer, namesize);
if ofs <> 0 then
Seek(f, FilePos(f) + ofs);
origname := filename;
DoDirSeparators(filename);
if IsOldHeader then begin
if not AlignFilePointer(f, 2) then Exit;
end else
if not AlignFilePointer(f, 4) then Exit;
//Correct file name started with "./" or "/"
filename := correct_filename(filename);
end;
fillchar(tmp_buf,sizeof(tmp_buf),#0);
BlockRead(f, tmp_buf, header.records[13]);
if IOResult <> 0 then Exit;
tmp_buf[header.records[13]]:=#0;
header.filename:=strpas(tmp_buf);
if ofs<>0 then
Seek(f,filepos(f)+ofs);
header.origname := header.filename;
DoDirSeparators(header.filename);
if header.oldhdrtype then begin
if not AlignFilePointer(f, 2) then Exit;
end else
if not AlignFilePointer(f, 4) then Exit;
//Correct file name started with "./" or "/"
header.filename := correct_filename(header.filename);
Result := True;
end;
function IsCPIOArchive(FileName: UTF8String): Boolean;
type
TAsciiHeader = array[0..5] of AnsiChar;
const
sOld: TAsciiHeader = ('0', '7', '0', '7', '0', '7');
sNew: TAsciiHeader = ('0', '7', '0', '7', '0', '1');
sCrc: TAsciiHeader = ('0', '7', '0', '7', '0', '2');
var
Buf: TAsciiHeader;
Stream: TFileStream;
begin
Result := False;
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
try
if (Stream.Size >= 6) and (Stream.Read(Buf[0], 6) = 6) then
begin
Result := // Binary format
(PWord(@Buf[0])^ = $71C7) or
// Ascii formats
CompareMem(@Buf[0], @sOld[0], 6) or
CompareMem(@Buf[0], @sNew[0], 6) or
CompareMem(@Buf[0], @sCrc[0], 6);
end;
finally
Stream.Free;
end;
end;
function correct_filename(oldname : AnsiString) : AnsiString;
begin
Result := oldname;