-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfileutils.pas
109 lines (95 loc) · 2.8 KB
/
fileutils.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{$MODE OBJFPC} { -*- delphi -*- }
{$INCLUDE settings.inc}
unit fileutils;
interface
uses
baseunix;
type
TFileData = record
Start: Pointer;
Length: size_t; // QWord, not Int64
procedure Destroy();
end;
function ReadFile(const FileName: AnsiString): TFileData; // This is efficient
function ReadTextFile(const FileName: AnsiString): UTF8String; // This is not
procedure WriteTextFile(const FileName: AnsiString; const Data: UTF8String);
function IsEmptyDirectory(const Path: AnsiString): Boolean;
implementation
uses
exceptions, sysutils;
function ReadFile(const FileName: AnsiString): TFileData;
var
FileDescriptor: CInt;
StatInfo: Stat;
MapResult: Pointer;
begin
FileDescriptor := fpOpen(FileName, O_RDONLY);
if (FileDescriptor < 0) then
raise EKernelError.Create(fpGetErrNo);
if (fpFStat(FileDescriptor, StatInfo) <> 0) then // $DFA- for StatInfo
raise EKernelError.Create(fpGetErrNo);
MapResult := fpMMap(nil, StatInfo.st_size+1, PROT_READ, MAP_PRIVATE, FileDescriptor, 0); // $R-
{$PUSH}
{$WARNINGS OFF} {$HINTS OFF}
if (PtrInt(MapResult) = -1) then
raise EKernelError.Create(fpGetErrNo);
{$POP}
fpClose(FileDescriptor);
Result.Length := StatInfo.st_size; // $R-
Result.Start := Pointer(MapResult);
end;
procedure TFileData.Destroy();
begin
if (fpMUnMap(Self.Start, Self.Length) <> 0) Then
raise EKernelError.Create(fpGetErrNo);
end;
function ReadTextFile(const FileName: AnsiString): UTF8String;
var
Source: TFileData;
begin
Source := ReadFile(FileName);
if (Source.Length > High(Integer)) then
raise Exception.Create('text file too big');
SetLength(Result, Source.Length); // {BOGUS Hint: Function result variable of a managed type does not seem to be initialized}
Move(Source.Start^, Result[1], Source.Length); // $R-
Source.Destroy();
end;
procedure WriteTextFile(const FileName: AnsiString; const Data: UTF8String);
var
F: Text;
begin
Assign(F, FileName);
Rewrite(F);
Writeln(F, Data);
Close(F);
end;
function IsEmptyDirectory(const Path: AnsiString): Boolean;
var
FileRecord: TSearchRec;
GotOneDot, GotTwoDots, GotOther: Boolean;
begin
if (DirectoryExists(Path)) then
begin
GotOneDot := False;
GotTwoDots := False;
GotOther := False;
if (FindFirst(Path + '/*', faDirectory, FileRecord) = 0) then
repeat
if (FileRecord.Name = '.') then
GotOneDot := True
else
if (FileRecord.Name = '..') then
GotTwoDots := True
else
begin
GotOther := True;
break;
end;
until (FindNext(FileRecord) <> 0);
Result := GotOneDot and GotTwoDots and not GotOther;
FindClose(FileRecord);
end
else
Result := False;
end;
end.