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
mono_w32file_init(void)16 mono_w32file_init (void)
17 {
18 }
19 
20 void
mono_w32file_cleanup(void)21 mono_w32file_cleanup (void)
22 {
23 }
24 
25 gunichar2
ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar()26 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
27 {
28 	return (gunichar2) ':';	/* colon */
29 }
30 
31 gunichar2
ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar()32 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
33 {
34 	return (gunichar2) '\\';	/* backslash */
35 }
36 
37 gunichar2
ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar()38 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
39 {
40 	return (gunichar2) '/';	/* forward slash */
41 }
42 
43 gunichar2
ves_icall_System_IO_MonoIO_get_PathSeparator()44 ves_icall_System_IO_MonoIO_get_PathSeparator ()
45 {
46 	return (gunichar2) ';';	/* semicolon */
47 }
48 
ves_icall_System_IO_MonoIO_DumpHandles(void)49 void ves_icall_System_IO_MonoIO_DumpHandles (void)
50 {
51 	return;
52 }
53 
54 gpointer
mono_w32file_create(const gunichar2 * name,guint32 fileaccess,guint32 sharemode,guint32 createmode,guint32 attrs)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
mono_w32file_close(gpointer handle)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
mono_w32file_delete(const gunichar2 * name)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
mono_w32file_read(gpointer handle,gpointer buffer,guint32 numbytes,guint32 * bytesread)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
mono_w32file_write(gpointer handle,gconstpointer buffer,guint32 numbytes,guint32 * byteswritten)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
mono_w32file_flush(gpointer handle)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
mono_w32file_truncate(gpointer handle)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
mono_w32file_seek(gpointer handle,gint32 movedistance,gint32 * highmovedistance,guint32 method)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
mono_w32file_get_type(gpointer handle)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
mono_w32file_get_times(gpointer handle,FILETIME * create_time,FILETIME * access_time,FILETIME * write_time)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
mono_w32file_set_times(gpointer handle,const FILETIME * create_time,const FILETIME * access_time,const FILETIME * write_time)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
mono_w32file_filetime_to_systemtime(const FILETIME * file_time,SYSTEMTIME * system_time)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
mono_w32file_find_first(const gunichar2 * pattern,WIN32_FIND_DATA * find_data)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
mono_w32file_find_next(gpointer handle,WIN32_FIND_DATA * find_data)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
mono_w32file_find_close(gpointer handle)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
mono_w32file_create_directory(const gunichar2 * name)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
mono_w32file_remove_directory(const gunichar2 * name)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
mono_w32file_get_attributes(const gunichar2 * name)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
convert_filetime(const FILETIME * filetime)262 convert_filetime (const FILETIME *filetime)
263 {
264 	return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime);
265 }
266 
267 gboolean
mono_w32file_get_attributes_ex(const gunichar2 * name,MonoIOStat * stat)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
mono_w32file_set_attributes(const gunichar2 * name,guint32 attrs)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
mono_w32file_get_cwd(guint32 length,gunichar2 * buffer)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
mono_w32file_set_cwd(const gunichar2 * path)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
mono_w32file_create_pipe(gpointer * readpipe,gpointer * writepipe,guint32 size)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
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)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
mono_w32file_get_volume_information(const gunichar2 * path,gunichar2 * volumename,gint volumesize,gint * outserial,gint * maxcomp,gint * fsflags,gunichar2 * fsbuffer,gint fsbuffersize)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
mono_w32file_move(const gunichar2 * path,const gunichar2 * dest,gint32 * error)391 mono_w32file_move (const gunichar2 *path, const 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
mono_w32file_replace(const gunichar2 * destinationFileName,const gunichar2 * sourceFileName,const gunichar2 * destinationBackupFileName,guint32 flags,gint32 * error)407 mono_w32file_replace (const gunichar2 *destinationFileName, const gunichar2 *sourceFileName, const 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
mono_w32file_copy(const gunichar2 * path,const gunichar2 * dest,gboolean overwrite,gint32 * error)423 mono_w32file_copy (const gunichar2 *path, const 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
mono_w32file_lock(gpointer handle,gint64 position,gint64 length,gint32 * error)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
mono_w32file_unlock(gpointer handle,gint64 position,gint64 length,gint32 * error)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
mono_w32file_get_console_input(void)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
mono_w32file_get_console_output(void)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
mono_w32file_get_console_error(void)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
mono_w32file_get_file_size(gpointer handle,gint32 * error)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
mono_w32file_get_drive_type(const gunichar2 * root_path_name)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
mono_w32file_get_logical_drive(guint32 len,gunichar2 * buf)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) */
539