mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
UPD: [Cpio plugin] Added detecting archive by header, detecting other cpio types. Fixed reading binary archive type.
This commit is contained in:
parent
278b9880d8
commit
4ea6bef2b7
4 changed files with 236 additions and 118 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue