1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- S Y S T E M . M M A P . O S _ I N T E R F A C E --
9 -- Copyright (C) 2007-2024, AdaCore --
11 -- This library is free software; you can redistribute it and/or modify it --
12 -- under terms of the GNU General Public License as published by the Free --
13 -- Software Foundation; either version 3, or (at your option) any later --
14 -- version. This library is distributed in the hope that it will be useful, --
15 -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
16 -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada
.IO_Exceptions
;
33 with System
.Strings
; use System
.Strings
;
36 pragma Unreferenced
(System
.OS_Lib
);
37 -- Only used to generate same runtime dependencies and same binder file on
38 -- GNU/Linux and Windows.
40 package body System
.Mmap
.OS_Interface
is
45 (Addr
: File_Size
) return File_Size
;
46 -- Align some offset/length to the lowest page boundary
50 Use_Mmap_If_Available
: Boolean;
51 Write
: Boolean) return System_File
;
53 function From_UTF8
(Path
: String) return Wide_String;
54 -- Convert from UTF-8 to Wide_String
60 function From_UTF8
(Path
: String) return Wide_String is
61 function MultiByteToWideChar
62 (Codepage
: Interfaces
.C
.unsigned
;
63 Flags
: Interfaces
.C
.unsigned
;
67 Wc
: Natural) return Integer;
68 pragma Import
(Stdcall
, MultiByteToWideChar
, "MultiByteToWideChar");
70 Current_Codepage
: Interfaces
.C
.unsigned
;
71 pragma Import
(C
, Current_Codepage
, "__gnat_current_codepage");
75 -- Compute length of the result
76 Len
:= MultiByteToWideChar
77 (Current_Codepage
, 0, Path
'Address, Path
'Length, Null_Address
, 0);
79 raise Constraint_Error
;
84 Res
: Wide_String (1 .. Len
);
87 Len
:= MultiByteToWideChar
89 Path
'Address, Path
'Length,
92 raise Constraint_Error
;
104 Use_Mmap_If_Available
: Boolean;
105 Write
: Boolean) return System_File
107 dwDesiredAccess
, dwShareMode
: DWORD
;
110 W_Filename
: constant Wide_String :=
111 From_UTF8
(Filename
) & Wide_Character'Val (0);
112 File_Handle
, Mapping_Handle
: HANDLE
;
114 SizeH
: aliased DWORD
;
118 dwDesiredAccess
:= GENERIC_READ
+ GENERIC_WRITE
;
120 PageFlags
:= Win
.PAGE_READWRITE
;
122 dwDesiredAccess
:= GENERIC_READ
;
123 dwShareMode
:= Win
.FILE_SHARE_READ
;
124 PageFlags
:= Win
.PAGE_READONLY
;
127 -- Actually open the file
129 File_Handle
:= CreateFile
130 (W_Filename
'Address, dwDesiredAccess
, dwShareMode
,
131 null, OPEN_EXISTING
, Win
.FILE_ATTRIBUTE_NORMAL
, 0);
133 if File_Handle
= Win
.INVALID_HANDLE_VALUE
then
134 return Invalid_System_File
;
139 Size
:= File_Size
(Win
.GetFileSize
(File_Handle
, SizeH
'Access));
141 if Size
= Win
.INVALID_FILE_SIZE
then
142 return Invalid_System_File
;
145 if SizeH
/= 0 and then File_Size
'Size > 32 then
146 Size
:= Size
+ (File_Size
(SizeH
) * 2 ** 32);
149 -- Then create a mapping object, if needed. On Win32, file memory
150 -- mapping is always available.
152 if Use_Mmap_If_Available
then
154 Win
.CreateFileMapping
155 (File_Handle
, null, PageFlags
,
156 0, DWORD
(Size
), Standard
.System
.Null_Address
);
158 Mapping_Handle
:= Win
.INVALID_HANDLE_VALUE
;
162 (Handle
=> File_Handle
,
163 Mapped
=> Use_Mmap_If_Available
,
164 Mapping_Handle
=> Mapping_Handle
,
175 Use_Mmap_If_Available
: Boolean := True) return System_File
is
177 return Open_Common
(Filename
, Use_Mmap_If_Available
, False);
186 Use_Mmap_If_Available
: Boolean := True) return System_File
is
188 return Open_Common
(Filename
, Use_Mmap_If_Available
, True);
195 procedure Close
(File
: in out System_File
) is
197 pragma Unreferenced
(Ignored
);
199 Ignored
:= CloseHandle
(File
.Mapping_Handle
);
200 Ignored
:= CloseHandle
(File
.Handle
);
201 File
.Handle
:= Win
.INVALID_HANDLE_VALUE
;
202 File
.Mapping_Handle
:= Win
.INVALID_HANDLE_VALUE
;
209 function Read_From_Disk
211 Offset
, Length
: File_Size
) return System
.Strings
.String_Access
213 Buffer
: String_Access
:= new String (1 .. Integer (Length
));
216 NbRead
: aliased DWORD
;
217 pragma Unreferenced
(Pos
);
219 Pos
:= Win
.SetFilePointer
220 (File
.Handle
, LONG
(Offset
), null, Win
.FILE_BEGIN
);
223 (File
.Handle
, Buffer
.all'Address,
224 DWORD
(Length
), NbRead
'Unchecked_Access, null) = Win
.FALSE
226 System
.Strings
.Free
(Buffer
);
227 raise Ada
.IO_Exceptions
.Device_Error
;
236 procedure Write_To_Disk
238 Offset
, Length
: File_Size
;
239 Buffer
: System
.Strings
.String_Access
)
242 NbWritten
: aliased DWORD
;
243 pragma Unreferenced
(Pos
);
245 pragma Assert
(File
.Write
);
246 Pos
:= Win
.SetFilePointer
247 (File
.Handle
, LONG
(Offset
), null, Win
.FILE_BEGIN
);
250 (File
.Handle
, Buffer
.all'Address,
251 DWORD
(Length
), NbWritten
'Unchecked_Access, null) = Win
.FALSE
253 raise Ada
.IO_Exceptions
.Device_Error
;
261 procedure Create_Mapping
263 Offset
, Length
: in out File_Size
;
265 Mapping
: out System_Mapping
)
270 Flags
:= Win
.FILE_MAP_WRITE
;
272 Flags
:= Win
.FILE_MAP_COPY
;
274 Flags
:= Win
.FILE_MAP_READ
;
277 -- Adjust offset and mapping length to account for the required
278 -- alignment of offset on page boundary.
281 Queried_Offset
: constant File_Size
:= Offset
;
283 Offset
:= Align
(Offset
);
285 -- First extend the length to compensate the offset shift, then align
286 -- it on the upper page boundary, so that the whole queried area is
289 Length
:= Length
+ Queried_Offset
- Offset
;
290 Length
:= Align
(Length
+ Get_Page_Size
- 1);
292 -- But do not exceed the length of the file
293 if Offset
+ Length
> File
.Length
then
294 Length
:= File
.Length
- Offset
;
298 if Length
> File_Size
(Integer'Last) then
299 raise Ada
.IO_Exceptions
.Device_Error
;
301 Mapping
:= Invalid_System_Mapping
;
304 (File
.Mapping_Handle
, Flags
,
305 0, DWORD
(Offset
), SIZE_T
(Length
));
306 Mapping
.Length
:= Length
;
310 ---------------------
311 -- Dispose_Mapping --
312 ---------------------
314 procedure Dispose_Mapping
315 (Mapping
: in out System_Mapping
)
318 pragma Unreferenced
(Ignored
);
320 Ignored
:= Win
.UnmapViewOfFile
(Mapping
.Address
);
321 Mapping
:= Invalid_System_Mapping
;
328 function Get_Page_Size
return File_Size
is
329 SystemInfo
: aliased SYSTEM_INFO
;
331 GetSystemInfo
(SystemInfo
'Unchecked_Access);
332 return File_Size
(SystemInfo
.dwAllocationGranularity
);
340 (Addr
: File_Size
) return File_Size
is
342 return Addr
- Addr
mod Get_Page_Size
;
345 end System
.Mmap
.OS_Interface
;