167 lines
4.2 KiB
ObjectPascal
167 lines
4.2 KiB
ObjectPascal
(* Copyright 2025 Sebastian Lederer. See the file LICENSE.md for details *)
|
|
program recover;
|
|
const PageMargin = 4;
|
|
var filename:string;
|
|
volid:integer;
|
|
|
|
(* we use some stuff internal to stdlib.pas *)
|
|
procedure getdirslot(volumeid:integer;slotNo:integer;var result:DirectorySlot;var error:integer);
|
|
external;
|
|
procedure openfile(volid:integer; slotno:integer; var dirslot:DirectorySlot; var aFile:File; mode:filemode);
|
|
external;
|
|
|
|
function openvolume:integer;
|
|
var volid:integer;
|
|
begin
|
|
openvolume := -1;
|
|
|
|
volid := findvolume(DefaultVolume);
|
|
if volid < 1 then
|
|
writeln('Volume ', DefaultVolume, ' not found.')
|
|
else
|
|
openvolume := volid;
|
|
end;
|
|
|
|
procedure waitForKey;
|
|
var c:char;
|
|
begin
|
|
writeln;
|
|
writeln('-- press any key to continue --');
|
|
c := conin;
|
|
end;
|
|
|
|
procedure copyfile(volid:integer;slotno:integer;oldname,newname:string);
|
|
var srcfile,destfile:file;
|
|
dirslot:DirectorySlot;
|
|
error:integer;
|
|
ch:char;
|
|
count:integer;
|
|
begin
|
|
(* to open the deleted source file, we emulate parts
|
|
of the open procedure from stdlib *)
|
|
getdirslot(volid, slotno, dirslot, error);
|
|
if not (SlotDeleted in dirslot.flags) or (dirslot.name <> oldname) then
|
|
writeln('Invalid slot ', slotno)
|
|
else
|
|
begin
|
|
openfile(volid, slotno, dirslot, srcfile, ModeReadOnly);
|
|
if error <> 0 then
|
|
writeln('Error opening file from slot ', slotno,
|
|
': ', ErrorStr(error))
|
|
else
|
|
begin
|
|
open(destfile, newname, ModeCreate);
|
|
if IOResult(destfile) = IOFileExists then
|
|
begin
|
|
write('File ', newname, ' already exists, overwrite? [y/n] ');
|
|
readln(ch);
|
|
if ch in ['Y', 'y'] then
|
|
open(destfile, newname, ModeOverwrite);
|
|
end;
|
|
if IOResult(destfile) <> 0 then
|
|
writeln('Error opening ', newname, ': ',
|
|
ErrorStr(IOResult(destfile)))
|
|
else
|
|
begin
|
|
(* taken from shell.pas copyFile *)
|
|
write('Recovering from slot ', slotno, ' to ', newname, '...');
|
|
count := 0;
|
|
while not eof(srcfile) do
|
|
begin
|
|
read(srcfile,ch);
|
|
write(destfile,ch);
|
|
count := count + 1;
|
|
if (count and 8191) = 0 then write('.');
|
|
end;
|
|
writeln;
|
|
close(destfile);
|
|
end;
|
|
close(srcfile);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure recoverfile(volid:integer;wantedname:string);
|
|
var dirs:DirectorySlot;
|
|
i:integer;
|
|
lastSlot:integer;
|
|
error:integer;
|
|
screenW,screenH:integer;
|
|
count:integer;
|
|
datestr:string;
|
|
ftime:DateTime;
|
|
wantedslot:integer;
|
|
newname:string;
|
|
foundsomething:boolean;
|
|
begin
|
|
writeln('Files available for recovery:');
|
|
foundsomething := false;
|
|
newname := '';
|
|
|
|
GetTermSize(screenW, screenH);
|
|
count := PageMargin;
|
|
|
|
lastSlot := volumeTable[volid].part.dirSize - 1;
|
|
openvolumeid(volid);
|
|
|
|
for i := 0 to lastSlot do
|
|
begin
|
|
getdirslot(volid, i, dirs, error);
|
|
with dirs do
|
|
begin
|
|
if (SlotFirst in flags) or (SlotDeleted in flags) then
|
|
if name = wantedname then
|
|
begin
|
|
ftime := GetDateTime(dirs.modTime);
|
|
datestr := DateStr(ftime) + ' ' + TimeStr(ftime, true);
|
|
write('slot ', i:4, name:34, sizeBytes:8, datestr:21, ' ');
|
|
if SlotFirst in flags then write('Cur');
|
|
if SlotExtent in flags then write('Extent');
|
|
if SlotReserved in flags then write('Resvd');
|
|
if SlotDeleted in flags then write('Del');
|
|
if SlotFree in flags then write('Free');
|
|
if SlotEndScan in flags then write('End');
|
|
writeln;
|
|
foundsomething := true;
|
|
count := count + 1;
|
|
if count >= screenH then
|
|
begin
|
|
count := PageMargin;
|
|
waitForKey;
|
|
end;
|
|
if SlotEndScan in flags then break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if foundsomething then
|
|
begin
|
|
write('Slot no to recover> ');
|
|
readln(wantedslot);
|
|
if (wantedslot < 1) or (wantedslot >= volumeTable[volid].part.dirSize) then
|
|
writeln('Invalid slot number.')
|
|
else
|
|
begin
|
|
write('New filename> ');
|
|
readln(newname);
|
|
end;
|
|
|
|
if length(newname) > 0 then
|
|
copyfile(volid, wantedslot, wantedname, newname);
|
|
end;
|
|
|
|
closevolumeid(volid);
|
|
end;
|
|
|
|
begin
|
|
if ParamCount > 0 then
|
|
filename := ParamStr(1)
|
|
else
|
|
begin
|
|
write('Filename to recover> ');
|
|
readln(filename);
|
|
end;
|
|
volid := openvolume;
|
|
if volid > 0 then
|
|
recoverfile(volid, filename);
|
|
end.
|