[w32file] Push win32 specific error to win32 specific implementation (#5665)
[mono.git] / mono / metadata / w32file-win32.c
1 /**
2  * \file
3  * Windows File IO internal calls.
4  *
5  * Copyright 2016 Microsoft
6  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7  */
8 #include <config.h>
9 #include <glib.h>
10
11 #include <winsock2.h>
12 #include <windows.h>
13 #include "mono/metadata/w32file-win32-internals.h"
14
15 void
16 mono_w32file_init (void)
17 {
18 }
19
20 void
21 mono_w32file_cleanup (void)
22 {
23 }
24
25 gunichar2
26 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
27 {
28         return (gunichar2) ':'; /* colon */
29 }
30
31 gunichar2
32 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
33 {
34         return (gunichar2) '\\';        /* backslash */
35 }
36
37 gunichar2
38 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
39 {
40         return (gunichar2) '/'; /* forward slash */
41 }
42
43 gunichar2
44 ves_icall_System_IO_MonoIO_get_PathSeparator ()
45 {
46         return (gunichar2) ';'; /* semicolon */
47 }
48
49 void ves_icall_System_IO_MonoIO_DumpHandles (void)
50 {
51         return;
52 }
53
54 gpointer
55 mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs)
56 {
57         gpointer res;
58         MONO_ENTER_GC_SAFE;
59         res = CreateFile (name, fileaccess, sharemode, NULL, createmode, attrs, NULL);
60         MONO_EXIT_GC_SAFE;
61         return res;
62 }
63
64 gboolean
65 mono_w32file_close (gpointer handle)
66 {
67         gboolean res;
68         MONO_ENTER_GC_SAFE;
69         res = CloseHandle (handle);
70         MONO_EXIT_GC_SAFE;
71         return res;
72 }
73
74 gboolean
75 mono_w32file_delete (const gunichar2 *name)
76 {
77         gboolean res;
78         MONO_ENTER_GC_SAFE;
79         res = DeleteFile (name);
80         MONO_EXIT_GC_SAFE;
81         return res;
82 }
83
84 gboolean
85 mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
86 {
87         gboolean res;
88         MONO_ENTER_GC_SAFE;
89         res = ReadFile (handle, buffer, numbytes, bytesread, NULL);
90         MONO_EXIT_GC_SAFE;
91         return res;
92 }
93
94 gboolean
95 mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
96 {
97         gboolean res;
98         MONO_ENTER_GC_SAFE;
99         res = WriteFile (handle, buffer, numbytes, byteswritten, NULL);
100         MONO_EXIT_GC_SAFE;
101         return res;
102 }
103
104 gboolean
105 mono_w32file_flush (gpointer handle)
106 {
107         gboolean res;
108         MONO_ENTER_GC_SAFE;
109         res = FlushFileBuffers (handle);
110         MONO_EXIT_GC_SAFE;
111         return res;
112 }
113
114 gboolean
115 mono_w32file_truncate (gpointer handle)
116 {
117         gboolean res;
118         MONO_ENTER_GC_SAFE;
119         res = SetEndOfFile (handle);
120         MONO_EXIT_GC_SAFE;
121         return res;
122 }
123
124 guint32
125 mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method)
126 {
127         guint32 res;
128         MONO_ENTER_GC_SAFE;
129         res = SetFilePointer (handle, movedistance, highmovedistance, method);
130         MONO_EXIT_GC_SAFE;
131         return res;
132 }
133
134 gint
135 mono_w32file_get_type (gpointer handle)
136 {
137         gint res;
138         MONO_ENTER_GC_SAFE;
139         res = GetFileType (handle);
140         MONO_EXIT_GC_SAFE;
141         return res;
142 }
143
144 gboolean
145 mono_w32file_get_times (gpointer handle, FILETIME *create_time, FILETIME *access_time, FILETIME *write_time)
146 {
147         gboolean res;
148         MONO_ENTER_GC_SAFE;
149         res = GetFileTime (handle, create_time, access_time, write_time);
150         MONO_EXIT_GC_SAFE;
151         return res;
152 }
153
154 gboolean
155 mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time)
156 {
157         gboolean res;
158         MONO_ENTER_GC_SAFE;
159         res = SetFileTime (handle, create_time, access_time, write_time);
160         MONO_EXIT_GC_SAFE;
161         return res;
162 }
163
164 gboolean
165 mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time)
166 {
167         gboolean res;
168         MONO_ENTER_GC_SAFE;
169         res = FileTimeToSystemTime (file_time, system_time);
170         MONO_EXIT_GC_SAFE;
171         return res;
172 }
173
174 gpointer
175 mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
176 {
177         gpointer res;
178         MONO_ENTER_GC_SAFE;
179         res = FindFirstFile (pattern, find_data);
180         MONO_EXIT_GC_SAFE;
181         return res;
182 }
183
184 gboolean
185 mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data)
186 {
187         gboolean res;
188         MONO_ENTER_GC_SAFE;
189         res = FindNextFile (handle, find_data);
190         MONO_EXIT_GC_SAFE;
191         return res;
192 }
193
194 gboolean
195 mono_w32file_find_close (gpointer handle)
196 {
197         gboolean res;
198         MONO_ENTER_GC_SAFE;
199         res = FindClose (handle);
200         MONO_EXIT_GC_SAFE;
201         return res;
202 }
203
204 gboolean
205 mono_w32file_create_directory (const gunichar2 *name)
206 {
207         gboolean res;
208         MONO_ENTER_GC_SAFE;
209         res = CreateDirectory (name, NULL);
210         MONO_EXIT_GC_SAFE;
211         return res;
212 }
213
214 gboolean
215 mono_w32file_remove_directory (const gunichar2 *name)
216 {
217         gboolean res;
218         MONO_ENTER_GC_SAFE;
219         res = RemoveDirectory (name);
220         MONO_EXIT_GC_SAFE;
221         return res;
222 }
223
224 /*
225  * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas
226  * FindFirstFile always succeeds.
227  */
228 guint32
229 mono_w32file_get_attributes (const gunichar2 *name)
230 {
231         guint32 res;
232         guint32 error;
233         HANDLE find_handle;
234         WIN32_FIND_DATA find_data;
235
236         MONO_ENTER_GC_SAFE;
237         res = GetFileAttributes (name);
238         MONO_EXIT_GC_SAFE;
239
240         if (res != INVALID_FILE_ATTRIBUTES)
241                 return res;
242
243         error = GetLastError ();
244         if (error != ERROR_SHARING_VIOLATION)
245                 return INVALID_FILE_ATTRIBUTES;
246
247         MONO_ENTER_GC_SAFE;
248         find_handle = FindFirstFile (name, &find_data);
249         MONO_EXIT_GC_SAFE;
250
251         if (find_handle == INVALID_HANDLE_VALUE)
252                 return INVALID_FILE_ATTRIBUTES;
253
254         MONO_ENTER_GC_SAFE;
255         FindClose (find_handle);
256         MONO_EXIT_GC_SAFE;
257
258         return find_data.dwFileAttributes;
259 }
260
261 static gint64
262 convert_filetime (const FILETIME *filetime)
263 {
264         return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime);
265 }
266
267 gboolean
268 mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
269 {
270         gboolean res;
271         guint32 error;
272         HANDLE find_handle;
273         WIN32_FIND_DATA find_data;
274         WIN32_FILE_ATTRIBUTE_DATA file_attribute_data;
275
276         MONO_ENTER_GC_SAFE;
277         res = GetFileAttributesEx (name, GetFileExInfoStandard, &file_attribute_data);
278         MONO_EXIT_GC_SAFE;
279         if (res) {
280                 stat->attributes = file_attribute_data.dwFileAttributes;
281                 stat->creation_time = convert_filetime (&file_attribute_data.ftCreationTime);
282                 stat->last_access_time = convert_filetime (&file_attribute_data.ftLastAccessTime);
283                 stat->last_write_time = convert_filetime (&file_attribute_data.ftLastWriteTime);
284                 stat->length = ((gint64)file_attribute_data.nFileSizeHigh << 32) | file_attribute_data.nFileSizeLow;
285                 return TRUE;
286         }
287
288         error = GetLastError ();
289         if (error != ERROR_SHARING_VIOLATION)
290                 return FALSE;
291
292         MONO_ENTER_GC_SAFE;
293         find_handle = FindFirstFile (name, &find_data);
294         MONO_EXIT_GC_SAFE;
295
296         if (find_handle == INVALID_HANDLE_VALUE)
297                 return FALSE;
298
299         MONO_ENTER_GC_SAFE;
300         FindClose (find_handle);
301         MONO_EXIT_GC_SAFE;
302
303         stat->attributes = find_data.dwFileAttributes;
304         stat->creation_time = convert_filetime (&find_data.ftCreationTime);
305         stat->last_access_time = convert_filetime (&find_data.ftLastAccessTime);
306         stat->last_write_time = convert_filetime (&find_data.ftLastWriteTime);
307         stat->length = ((gint64)find_data.nFileSizeHigh << 32) | find_data.nFileSizeLow;
308         return TRUE;
309 }
310
311 gboolean
312 mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
313 {
314         gboolean res;
315         MONO_ENTER_GC_SAFE;
316         res = SetFileAttributes (name, attrs);
317         MONO_EXIT_GC_SAFE;
318         return res;
319 }
320
321 guint32
322 mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
323 {
324         guint32 res;
325         MONO_ENTER_GC_SAFE;
326         res = GetCurrentDirectory (length, buffer);
327         MONO_EXIT_GC_SAFE;
328         return res;
329 }
330
331 gboolean
332 mono_w32file_set_cwd (const gunichar2 *path)
333 {
334         gboolean res;
335         MONO_ENTER_GC_SAFE;
336         res = SetCurrentDirectory (path);
337         MONO_EXIT_GC_SAFE;
338         return res;
339 }
340
341 gboolean
342 mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
343 {
344         gboolean res;
345         SECURITY_ATTRIBUTES attr;
346         attr.nLength = sizeof(SECURITY_ATTRIBUTES);
347         attr.bInheritHandle = TRUE;
348         attr.lpSecurityDescriptor = NULL;
349         MONO_ENTER_GC_SAFE;
350         res = CreatePipe (readpipe, writepipe, &attr, size);
351         MONO_EXIT_GC_SAFE;
352         return res;
353 }
354
355 gboolean
356 mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes)
357 {
358         gboolean result;
359         ULARGE_INTEGER wapi_free_bytes_avail;
360         ULARGE_INTEGER wapi_total_number_of_bytes;
361         ULARGE_INTEGER wapi_total_number_of_free_bytes;
362
363         MONO_ENTER_GC_SAFE;
364         result = GetDiskFreeSpaceEx (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes);
365         MONO_EXIT_GC_SAFE;
366         if (result) {
367                 if (free_bytes_avail)
368                         *free_bytes_avail = wapi_free_bytes_avail.QuadPart;
369                 if (total_number_of_bytes)
370                         *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart;
371                 if (total_number_of_free_bytes)
372                         *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart;
373         }
374
375         return result;
376 }
377
378 gboolean
379 mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize)
380 {
381         gboolean res;
382         MONO_ENTER_GC_SAFE;
383         res = GetVolumeInformation (path, volumename, volumesize, outserial, maxcomp, fsflags, fsbuffer, fsbuffersize);
384         MONO_EXIT_GC_SAFE;
385         return res;
386 }
387
388 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
389
390 gboolean
391 mono_w32file_move (gunichar2 *path, gunichar2 *dest, gint32 *error)
392 {
393         gboolean result;
394
395         MONO_ENTER_GC_SAFE;
396
397         result = MoveFile (path, dest);
398         if (!result)
399                 *error = GetLastError ();
400
401         MONO_EXIT_GC_SAFE;
402
403         return result;
404 }
405
406 gboolean
407 mono_w32file_replace (gunichar2 *destinationFileName, gunichar2 *sourceFileName, gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
408 {
409         gboolean result;
410
411         MONO_ENTER_GC_SAFE;
412
413         result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
414         if (!result)
415                 *error = GetLastError ();
416
417         MONO_EXIT_GC_SAFE;
418
419         return result;
420 }
421
422 gboolean
423 mono_w32file_copy (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32 *error)
424 {
425         gboolean result;
426
427         MONO_ENTER_GC_SAFE;
428
429         result = CopyFile (path, dest, !overwrite);
430         if (!result)
431                 *error = GetLastError ();
432
433         MONO_EXIT_GC_SAFE;
434
435         return result;
436 }
437
438 gboolean
439 mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error)
440 {
441         gboolean result;
442
443         MONO_ENTER_GC_SAFE;
444
445         result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
446         if (!result)
447                 *error = GetLastError ();
448
449         MONO_EXIT_GC_SAFE;
450
451         return result;
452 }
453
454 gboolean
455 mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error)
456 {
457         gboolean result;
458
459         MONO_ENTER_GC_SAFE;
460
461         result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
462         if (!result)
463                 *error = GetLastError ();
464
465         MONO_EXIT_GC_SAFE;
466
467         return result;
468 }
469
470 HANDLE
471 mono_w32file_get_console_input (void)
472 {
473         HANDLE res;
474         MONO_ENTER_GC_SAFE;
475         res = GetStdHandle (STD_INPUT_HANDLE);
476         MONO_EXIT_GC_SAFE;
477         return res;
478 }
479
480 HANDLE
481 mono_w32file_get_console_output (void)
482 {
483         HANDLE res;
484         MONO_ENTER_GC_SAFE;
485         res = GetStdHandle (STD_OUTPUT_HANDLE);
486         MONO_EXIT_GC_SAFE;
487         return res;
488 }
489
490 HANDLE
491 mono_w32file_get_console_error (void)
492 {
493         HANDLE res;
494         MONO_ENTER_GC_SAFE;
495         res = GetStdHandle (STD_ERROR_HANDLE);
496         MONO_EXIT_GC_SAFE;
497         return res;
498 }
499
500 gint64
501 mono_w32file_get_file_size (gpointer handle, gint32 *error)
502 {
503         gint64 length;
504         guint32 length_hi;
505
506         MONO_ENTER_GC_SAFE;
507
508         length = GetFileSize (handle, &length_hi);
509         if(length==INVALID_FILE_SIZE) {
510                 *error=GetLastError ();
511         }
512
513         MONO_EXIT_GC_SAFE;
514
515         return length | ((gint64)length_hi << 32);
516 }
517
518 guint32
519 mono_w32file_get_drive_type (const gunichar2 *root_path_name)
520 {
521         guint32 res;
522         MONO_ENTER_GC_SAFE;
523         res = GetDriveType (root_path_name);
524         MONO_EXIT_GC_SAFE;
525         return res;
526 }
527
528 gint32
529 mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
530 {
531         gint32 res;
532         MONO_ENTER_GC_SAFE;
533         res = GetLogicalDriveStrings (len, buf);
534         MONO_EXIT_GC_SAFE;
535         return res;
536 }
537
538 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */