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-2016, 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;
35 package body System.Mmap.OS_Interface is
40 (Addr : File_Size) return File_Size;
41 -- Align some offset/length to the lowest page boundary
45 Use_Mmap_If_Available : Boolean;
46 Write : Boolean) return System_File;
48 function From_UTF8 (Path : String) return Wide_String;
49 -- Convert from UTF-8 to Wide_String
55 function From_UTF8 (Path : String) return Wide_String is
56 function MultiByteToWideChar
57 (Codepage : Interfaces.C.unsigned;
58 Flags : Interfaces.C.unsigned;
62 Wc : Natural) return Integer;
63 pragma Import (C, MultiByteToWideChar);
65 Current_Codepage : Interfaces.C.unsigned;
66 pragma Import (C, Current_Codepage, "__gnat_current_codepage");
70 -- Compute length of the result
71 Len := MultiByteToWideChar
72 (Current_Codepage, 0, Path'Address, Path'Length, Null_Address, 0);
74 raise Constraint_Error;
79 Res : Wide_String (1 .. Len);
82 Len := MultiByteToWideChar
84 Path'Address, Path'Length,
87 raise Constraint_Error;
99 Use_Mmap_If_Available : Boolean;
100 Write : Boolean) return System_File
102 dwDesiredAccess, dwShareMode : DWORD;
105 W_Filename : constant Wide_String :=
106 From_UTF8 (Filename) & Wide_Character'Val (0);
107 File_Handle, Mapping_Handle : HANDLE;
109 SizeH : aliased DWORD;
113 dwDesiredAccess := GENERIC_READ + GENERIC_WRITE;
115 PageFlags := Win.PAGE_READWRITE;
117 dwDesiredAccess := GENERIC_READ;
118 dwShareMode := Win.FILE_SHARE_READ;
119 PageFlags := Win.PAGE_READONLY;
122 -- Actually open the file
124 File_Handle := CreateFile
125 (W_Filename'Address, dwDesiredAccess, dwShareMode,
126 null, OPEN_EXISTING, Win.FILE_ATTRIBUTE_NORMAL, 0);
128 if File_Handle = Win.INVALID_HANDLE_VALUE then
129 raise Ada.IO_Exceptions.Name_Error
130 with "Cannot open " & Filename;
135 Size := File_Size (Win.GetFileSize (File_Handle, SizeH'Access));
137 if Size = Win.INVALID_FILE_SIZE then
138 raise Ada.IO_Exceptions.Use_Error;
141 if SizeH /= 0 and then File_Size'Size > 32 then
142 Size := Size + (File_Size (SizeH) * 2 ** 32);
145 -- Then create a mapping object, if needed. On Win32, file memory
146 -- mapping is always available.
148 if Use_Mmap_If_Available then
150 Win.CreateFileMapping
151 (File_Handle, null, PageFlags,
152 0, DWORD (Size), Standard.System.Null_Address);
154 Mapping_Handle := Win.INVALID_HANDLE_VALUE;
158 (Handle => File_Handle,
159 Mapped => Use_Mmap_If_Available,
160 Mapping_Handle => Mapping_Handle,
171 Use_Mmap_If_Available : Boolean := True) return System_File is
173 return Open_Common (Filename, Use_Mmap_If_Available, False);
182 Use_Mmap_If_Available : Boolean := True) return System_File is
184 return Open_Common (Filename, Use_Mmap_If_Available, True);
191 procedure Close (File : in out System_File) is
193 pragma Unreferenced (Ignored);
195 Ignored := CloseHandle (File.Mapping_Handle);
196 Ignored := CloseHandle (File.Handle);
197 File.Handle := Win.INVALID_HANDLE_VALUE;
198 File.Mapping_Handle := Win.INVALID_HANDLE_VALUE;
205 function Read_From_Disk
207 Offset, Length : File_Size) return System.Strings.String_Access
209 Buffer : String_Access := new String (1 .. Integer (Length));
212 NbRead : aliased DWORD;
213 pragma Unreferenced (Pos);
215 Pos := Win.SetFilePointer
216 (File.Handle, LONG (Offset), null, Win.FILE_BEGIN);
219 (File.Handle, Buffer.all'Address,
220 DWORD (Length), NbRead'Unchecked_Access, null) = Win.FALSE
222 System.Strings.Free (Buffer);
223 raise Ada.IO_Exceptions.Device_Error;
232 procedure Write_To_Disk
234 Offset, Length : File_Size;
235 Buffer : System.Strings.String_Access)
238 NbWritten : aliased DWORD;
239 pragma Unreferenced (Pos);
241 pragma Assert (File.Write);
242 Pos := Win.SetFilePointer
243 (File.Handle, LONG (Offset), null, Win.FILE_BEGIN);
246 (File.Handle, Buffer.all'Address,
247 DWORD (Length), NbWritten'Unchecked_Access, null) = Win.FALSE
249 raise Ada.IO_Exceptions.Device_Error;
257 procedure Create_Mapping
259 Offset, Length : in out File_Size;
261 Mapping : out System_Mapping)
266 Flags := Win.FILE_MAP_WRITE;
268 Flags := Win.FILE_MAP_COPY;
270 Flags := Win.FILE_MAP_READ;
273 -- Adjust offset and mapping length to account for the required
274 -- alignment of offset on page boundary.
277 Queried_Offset : constant File_Size := Offset;
279 Offset := Align (Offset);
281 -- First extend the length to compensate the offset shift, then align
282 -- it on the upper page boundary, so that the whole queried area is
285 Length := Length + Queried_Offset - Offset;
286 Length := Align (Length + Get_Page_Size - 1);
288 -- But do not exceed the length of the file
289 if Offset + Length > File.Length then
290 Length := File.Length - Offset;
294 if Length > File_Size (Integer'Last) then
295 raise Ada.IO_Exceptions.Device_Error;
297 Mapping := Invalid_System_Mapping;
300 (File.Mapping_Handle, Flags,
301 0, DWORD (Offset), SIZE_T (Length));
302 Mapping.Length := Length;
306 ---------------------
307 -- Dispose_Mapping --
308 ---------------------
310 procedure Dispose_Mapping
311 (Mapping : in out System_Mapping)
314 pragma Unreferenced (Ignored);
316 Ignored := Win.UnmapViewOfFile (Mapping.Address);
317 Mapping := Invalid_System_Mapping;
324 function Get_Page_Size return File_Size is
325 SystemInfo : aliased SYSTEM_INFO;
327 GetSystemInfo (SystemInfo'Unchecked_Access);
328 return File_Size (SystemInfo.dwAllocationGranularity);
336 (Addr : File_Size) return File_Size is
338 return Addr - Addr mod Get_Page_Size;
341 end System.Mmap.OS_Interface;