1 /*
2  * win32_replacements.c - Replacements for various functions not available on
3  * Windows, such as fsync().
4  */
5 
6 /*
7  * Copyright (C) 2013-2016 Eric Biggers
8  *
9  * This file is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU Lesser General Public License as published by the Free
11  * Software Foundation; either version 3 of the License, or (at your option) any
12  * later version.
13  *
14  * This file is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this file; if not, see http://www.gnu.org/licenses/.
21  */
22 
23 #ifdef __WIN32__
24 
25 #ifdef HAVE_CONFIG_H
26 #  include "config.h"
27 #endif
28 
29 #include <errno.h>
30 #include <pthread.h>
31 #include <io.h>	/* for _get_osfhandle()  */
32 #include <fcntl.h>
33 
34 #include "wimlib/win32_common.h"
35 
36 #include "wimlib/assert.h"
37 #include "wimlib/glob.h"
38 #include "wimlib/error.h"
39 #include "wimlib/timestamp.h"
40 #include "wimlib/util.h"
41 
42 static int
win32_error_to_errno(DWORD err_code)43 win32_error_to_errno(DWORD err_code)
44 {
45 	/* This mapping is that used in Cygwin.
46 	 * Some of these choices are arbitrary. */
47 	switch (err_code) {
48 	case ERROR_ACCESS_DENIED:
49 		return EACCES;
50 	case ERROR_ACTIVE_CONNECTIONS:
51 		return EAGAIN;
52 	case ERROR_ALREADY_EXISTS:
53 		return EEXIST;
54 	case ERROR_BAD_DEVICE:
55 		return ENODEV;
56 	case ERROR_BAD_EXE_FORMAT:
57 		return ENOEXEC;
58 	case ERROR_BAD_NETPATH:
59 		return ENOENT;
60 	case ERROR_BAD_NET_NAME:
61 		return ENOENT;
62 	case ERROR_BAD_NET_RESP:
63 		return ENOSYS;
64 	case ERROR_BAD_PATHNAME:
65 		return ENOENT;
66 	case ERROR_BAD_PIPE:
67 		return EINVAL;
68 	case ERROR_BAD_UNIT:
69 		return ENODEV;
70 	case ERROR_BAD_USERNAME:
71 		return EINVAL;
72 	case ERROR_BEGINNING_OF_MEDIA:
73 		return EIO;
74 	case ERROR_BROKEN_PIPE:
75 		return EPIPE;
76 	case ERROR_BUSY:
77 		return EBUSY;
78 	case ERROR_BUS_RESET:
79 		return EIO;
80 	case ERROR_CALL_NOT_IMPLEMENTED:
81 		return ENOSYS;
82 	case ERROR_CANNOT_MAKE:
83 		return EPERM;
84 	case ERROR_CHILD_NOT_COMPLETE:
85 		return EBUSY;
86 	case ERROR_COMMITMENT_LIMIT:
87 		return EAGAIN;
88 	case ERROR_CRC:
89 		return EIO;
90 	case ERROR_DEVICE_DOOR_OPEN:
91 		return EIO;
92 	case ERROR_DEVICE_IN_USE:
93 		return EAGAIN;
94 	case ERROR_DEVICE_REQUIRES_CLEANING:
95 		return EIO;
96 	case ERROR_DIRECTORY:
97 		return ENOTDIR;
98 	case ERROR_DIR_NOT_EMPTY:
99 		return ENOTEMPTY;
100 	case ERROR_DISK_CORRUPT:
101 		return EIO;
102 	case ERROR_DISK_FULL:
103 		return ENOSPC;
104 #ifdef ENOTUNIQ
105 	case ERROR_DUP_NAME:
106 		return ENOTUNIQ;
107 #endif
108 	case ERROR_EAS_DIDNT_FIT:
109 		return ENOSPC;
110 #ifdef ENOTSUP
111 	case ERROR_EAS_NOT_SUPPORTED:
112 		return ENOTSUP;
113 #endif
114 	case ERROR_EA_LIST_INCONSISTENT:
115 		return EINVAL;
116 	case ERROR_EA_TABLE_FULL:
117 		return ENOSPC;
118 	case ERROR_END_OF_MEDIA:
119 		return ENOSPC;
120 	case ERROR_EOM_OVERFLOW:
121 		return EIO;
122 	case ERROR_EXE_MACHINE_TYPE_MISMATCH:
123 		return ENOEXEC;
124 	case ERROR_EXE_MARKED_INVALID:
125 		return ENOEXEC;
126 	case ERROR_FILEMARK_DETECTED:
127 		return EIO;
128 	case ERROR_FILENAME_EXCED_RANGE:
129 		return ENAMETOOLONG;
130 	case ERROR_FILE_CORRUPT:
131 		return EEXIST;
132 	case ERROR_FILE_EXISTS:
133 		return EEXIST;
134 	case ERROR_FILE_INVALID:
135 		return ENXIO;
136 	case ERROR_FILE_NOT_FOUND:
137 		return ENOENT;
138 	case ERROR_HANDLE_DISK_FULL:
139 		return ENOSPC;
140 #ifdef ENODATA
141 	case ERROR_HANDLE_EOF:
142 		return ENODATA;
143 #endif
144 	case ERROR_INVALID_ADDRESS:
145 		return EINVAL;
146 	case ERROR_INVALID_AT_INTERRUPT_TIME:
147 		return EINTR;
148 	case ERROR_INVALID_BLOCK_LENGTH:
149 		return EIO;
150 	case ERROR_INVALID_DATA:
151 		return EINVAL;
152 	case ERROR_INVALID_DRIVE:
153 		return ENODEV;
154 	case ERROR_INVALID_EA_NAME:
155 		return EINVAL;
156 	case ERROR_INVALID_EXE_SIGNATURE:
157 		return ENOEXEC;
158 #ifdef EBADRQC
159 	case ERROR_INVALID_FUNCTION:
160 		return EBADRQC;
161 #endif
162 	case ERROR_INVALID_HANDLE:
163 		return EBADF;
164 	case ERROR_INVALID_NAME:
165 		return ENOENT;
166 	case ERROR_INVALID_PARAMETER:
167 		return EINVAL;
168 	case ERROR_INVALID_SIGNAL_NUMBER:
169 		return EINVAL;
170 	case ERROR_IOPL_NOT_ENABLED:
171 		return ENOEXEC;
172 	case ERROR_IO_DEVICE:
173 		return EIO;
174 	case ERROR_IO_INCOMPLETE:
175 		return EAGAIN;
176 	case ERROR_IO_PENDING:
177 		return EAGAIN;
178 	case ERROR_LOCK_VIOLATION:
179 		return EBUSY;
180 	case ERROR_MAX_THRDS_REACHED:
181 		return EAGAIN;
182 	case ERROR_META_EXPANSION_TOO_LONG:
183 		return EINVAL;
184 	case ERROR_MOD_NOT_FOUND:
185 		return ENOENT;
186 #ifdef EMSGSIZE
187 	case ERROR_MORE_DATA:
188 		return EMSGSIZE;
189 #endif
190 	case ERROR_NEGATIVE_SEEK:
191 		return EINVAL;
192 	case ERROR_NETNAME_DELETED:
193 		return ENOENT;
194 	case ERROR_NOACCESS:
195 		return EFAULT;
196 	case ERROR_NONE_MAPPED:
197 		return EINVAL;
198 	case ERROR_NONPAGED_SYSTEM_RESOURCES:
199 		return EAGAIN;
200 #ifdef ENOLINK
201 	case ERROR_NOT_CONNECTED:
202 		return ENOLINK;
203 #endif
204 	case ERROR_NOT_ENOUGH_MEMORY:
205 		return ENOMEM;
206 	case ERROR_NOT_OWNER:
207 		return EPERM;
208 #ifdef ENOMEDIUM
209 	case ERROR_NOT_READY:
210 		return ENOMEDIUM;
211 #endif
212 	case ERROR_NOT_SAME_DEVICE:
213 		return EXDEV;
214 	case ERROR_NOT_SUPPORTED:
215 		return ENOSYS;
216 	case ERROR_NO_DATA:
217 		return EPIPE;
218 	case ERROR_NO_DATA_DETECTED:
219 		return EIO;
220 #ifdef ENOMEDIUM
221 	case ERROR_NO_MEDIA_IN_DRIVE:
222 		return ENOMEDIUM;
223 #endif
224 #ifdef ENMFILE
225 	case ERROR_NO_MORE_FILES:
226 		return ENMFILE;
227 #endif
228 #ifdef ENMFILE
229 	case ERROR_NO_MORE_ITEMS:
230 		return ENMFILE;
231 #endif
232 	case ERROR_NO_MORE_SEARCH_HANDLES:
233 		return ENFILE;
234 	case ERROR_NO_PROC_SLOTS:
235 		return EAGAIN;
236 	case ERROR_NO_SIGNAL_SENT:
237 		return EIO;
238 	case ERROR_NO_SYSTEM_RESOURCES:
239 		return EFBIG;
240 	case ERROR_NO_TOKEN:
241 		return EINVAL;
242 	case ERROR_OPEN_FAILED:
243 		return EIO;
244 	case ERROR_OPEN_FILES:
245 		return EAGAIN;
246 	case ERROR_OUTOFMEMORY:
247 		return ENOMEM;
248 	case ERROR_PAGED_SYSTEM_RESOURCES:
249 		return EAGAIN;
250 	case ERROR_PAGEFILE_QUOTA:
251 		return EAGAIN;
252 	case ERROR_PATH_NOT_FOUND:
253 		return ENOENT;
254 	case ERROR_PIPE_BUSY:
255 		return EBUSY;
256 	case ERROR_PIPE_CONNECTED:
257 		return EBUSY;
258 #ifdef ECOMM
259 	case ERROR_PIPE_LISTENING:
260 		return ECOMM;
261 	case ERROR_PIPE_NOT_CONNECTED:
262 		return ECOMM;
263 #endif
264 	case ERROR_POSSIBLE_DEADLOCK:
265 		return EDEADLOCK;
266 	case ERROR_PRIVILEGE_NOT_HELD:
267 		return EPERM;
268 	case ERROR_PROCESS_ABORTED:
269 		return EFAULT;
270 	case ERROR_PROC_NOT_FOUND:
271 		return ESRCH;
272 #ifdef ENONET
273 	case ERROR_REM_NOT_LIST:
274 		return ENONET;
275 #endif
276 	case ERROR_SECTOR_NOT_FOUND:
277 		return EINVAL;
278 	case ERROR_SEEK:
279 		return EINVAL;
280 	case ERROR_SETMARK_DETECTED:
281 		return EIO;
282 	case ERROR_SHARING_BUFFER_EXCEEDED:
283 		return ENOLCK;
284 	case ERROR_SHARING_VIOLATION:
285 		return EBUSY;
286 	case ERROR_SIGNAL_PENDING:
287 		return EBUSY;
288 	case ERROR_SIGNAL_REFUSED:
289 		return EIO;
290 #ifdef ELIBBAD
291 	case ERROR_SXS_CANT_GEN_ACTCTX:
292 		return ELIBBAD;
293 #endif
294 	case ERROR_THREAD_1_INACTIVE:
295 		return EINVAL;
296 	case ERROR_TOO_MANY_LINKS:
297 		return EMLINK;
298 	case ERROR_TOO_MANY_OPEN_FILES:
299 		return EMFILE;
300 	case ERROR_WAIT_NO_CHILDREN:
301 		return ECHILD;
302 	case ERROR_WORKING_SET_QUOTA:
303 		return EAGAIN;
304 	case ERROR_WRITE_PROTECT:
305 		return EROFS;
306 	default:
307 		return -1;
308 	}
309 }
310 
311 static void
set_errno_from_win32_error(DWORD err)312 set_errno_from_win32_error(DWORD err)
313 {
314 	errno = win32_error_to_errno(err);
315 }
316 
317 static void
set_errno_from_GetLastError(void)318 set_errno_from_GetLastError(void)
319 {
320 	set_errno_from_win32_error(GetLastError());
321 }
322 
323 /* Replacement for POSIX fsync() */
324 int
fsync(int fd)325 fsync(int fd)
326 {
327 	HANDLE h;
328 
329 	h = (HANDLE)_get_osfhandle(fd);
330 	if (h == INVALID_HANDLE_VALUE)
331 		goto err;
332 	if (!FlushFileBuffers(h))
333 		goto err_set_errno;
334 	return 0;
335 err_set_errno:
336 	set_errno_from_GetLastError();
337 err:
338 	return -1;
339 }
340 
341 /* Use the Win32 API to get the number of processors.  */
342 unsigned
get_available_cpus(void)343 get_available_cpus(void)
344 {
345 	SYSTEM_INFO sysinfo;
346 	GetSystemInfo(&sysinfo);
347 	return sysinfo.dwNumberOfProcessors;
348 }
349 
350 /* Use the Win32 API to get the amount of available memory.  */
351 u64
get_available_memory(void)352 get_available_memory(void)
353 {
354 	MEMORYSTATUSEX status = {
355 		.dwLength = sizeof(status),
356 	};
357 	GlobalMemoryStatusEx(&status);
358 	return (u64)min(status.ullTotalPhys, status.ullTotalVirtual) * 85 / 100;
359 }
360 
361 /* Replacement for POSIX-2008 realpath().  Warning: partial functionality only
362  * (resolved_path must be NULL).   Also I highly doubt that GetFullPathName
363  * really does the right thing under all circumstances. */
364 wchar_t *
realpath(const wchar_t * path,wchar_t * resolved_path)365 realpath(const wchar_t *path, wchar_t *resolved_path)
366 {
367 	DWORD ret;
368 	DWORD err;
369 	wimlib_assert(resolved_path == NULL);
370 
371 	ret = GetFullPathNameW(path, 0, NULL, NULL);
372 	if (!ret) {
373 		err = GetLastError();
374 		goto fail_win32;
375 	}
376 
377 	resolved_path = MALLOC(ret * sizeof(wchar_t));
378 	if (!resolved_path)
379 		goto out;
380 	ret = GetFullPathNameW(path, ret, resolved_path, NULL);
381 	if (!ret) {
382 		err = GetLastError();
383 		FREE(resolved_path);
384 		resolved_path = NULL;
385 		goto fail_win32;
386 	}
387 	goto out;
388 fail_win32:
389 	set_errno_from_win32_error(err);
390 out:
391 	return resolved_path;
392 }
393 
394 /* A quick hack to get reasonable rename() semantics on Windows, in particular
395  * deleting the destination file instead of failing with ERROR_FILE_EXISTS and
396  * working around any processes that may have the destination file open.
397  *
398  * Note: This is intended to be called when overwriting a regular file with an
399  * updated copy and is *not* a fully POSIX compliant rename().  For that you may
400  * wish to take a look at Cygwin's implementation, but be prepared...
401  *
402  * Return 0 on success, -1 on regular error, or 1 if the destination file was
403  * deleted but the source could not be renamed and therefore should not be
404  * deleted.
405  */
406 int
win32_rename_replacement(const wchar_t * srcpath,const wchar_t * dstpath)407 win32_rename_replacement(const wchar_t *srcpath, const wchar_t *dstpath)
408 {
409 	wchar_t *tmpname;
410 
411 	/* Normally, MoveFileExW() with the MOVEFILE_REPLACE_EXISTING flag does
412 	 * what we want.  */
413 
414 	if (MoveFileExW(srcpath, dstpath, MOVEFILE_REPLACE_EXISTING))
415 		return 0;
416 
417 	/* MoveFileExW() failed.  One way this can happen is if any process has
418 	 * the destination file open, in which case ERROR_ACCESS_DENIED is
419 	 * produced.  This can commonly happen if there is a backup or antivirus
420 	 * program monitoring or scanning the files.  This behavior is very
421 	 * different from the behavior of POSIX rename(), which simply unlinks
422 	 * the destination file and allows other processes to keep it open!  */
423 
424 	if (GetLastError() != ERROR_ACCESS_DENIED)
425 		goto err_set_errno;
426 
427 	/* We can work around the above-mentioned problem by renaming the
428 	 * destination file to yet another temporary file, then "deleting" it,
429 	 * which on Windows will in fact not actually delete it immediately but
430 	 * rather mark it for deletion when the last handle to it is closed.  */
431 	{
432 		static const wchar_t orig_suffix[5] = L".orig";
433 		const size_t num_rand_chars = 9;
434 		wchar_t *p;
435 
436 		size_t dstlen = wcslen(dstpath);
437 
438 		tmpname = alloca(sizeof(wchar_t) *
439 				 (dstlen + ARRAY_LEN(orig_suffix) + num_rand_chars + 1));
440 		p = tmpname;
441 		p = wmempcpy(p, dstpath, dstlen);
442 		p = wmempcpy(p, orig_suffix, ARRAY_LEN(orig_suffix));
443 		get_random_alnum_chars(p, num_rand_chars);
444 		p += num_rand_chars;
445 		*p = L'\0';
446 	}
447 
448 	if (!MoveFile(dstpath, tmpname))
449 		goto err_set_errno;
450 
451 	if (!DeleteFile(tmpname)) {
452 		set_errno_from_GetLastError();
453 		WARNING_WITH_ERRNO("Failed to delete original file "
454 				   "(moved to \"%ls\")", tmpname);
455 	}
456 
457 	if (!MoveFile(srcpath, dstpath)) {
458 		set_errno_from_GetLastError();
459 		WARNING_WITH_ERRNO("Atomic semantics not respected in "
460 				   "failed rename() (new file is at \"%ls\")",
461 				   srcpath);
462 		return 1;
463 	}
464 
465 	return 0;
466 
467 err_set_errno:
468 	set_errno_from_GetLastError();
469 	return -1;
470 }
471 
472 /* This really could be replaced with _wcserror_s, but this doesn't seem to
473  * actually be available in MSVCRT.DLL on Windows XP (perhaps it's statically
474  * linked in by Visual Studio...?). */
475 int
win32_strerror_r_replacement(int errnum,wchar_t * buf,size_t buflen)476 win32_strerror_r_replacement(int errnum, wchar_t *buf, size_t buflen)
477 {
478 	static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
479 
480 	pthread_mutex_lock(&strerror_lock);
481 	mbstowcs(buf, strerror(errnum), buflen);
482 	buf[buflen - 1] = '\0';
483 	pthread_mutex_unlock(&strerror_lock);
484 	return 0;
485 }
486 
487 #define MAX_IO_AMOUNT 1048576
488 
489 static int
do_pread_or_pwrite(int fd,void * buf,size_t count,off_t offset,bool is_pwrite)490 do_pread_or_pwrite(int fd, void *buf, size_t count, off_t offset,
491 		   bool is_pwrite)
492 {
493 	HANDLE h;
494 	LARGE_INTEGER orig_offset;
495 	DWORD result = 0xFFFFFFFF;
496 	LARGE_INTEGER relative_offset;
497 	OVERLAPPED overlapped;
498 	BOOL bret;
499 	DWORD err = 0;
500 
501 	h = (HANDLE)_get_osfhandle(fd);
502 	if (h == INVALID_HANDLE_VALUE)
503 		goto error;
504 
505 	if (GetFileType(h) == FILE_TYPE_PIPE) {
506 		errno = ESPIPE;
507 		goto error;
508 	}
509 
510 	/* Get original position */
511 	relative_offset.QuadPart = 0;
512 	if (!SetFilePointerEx(h, relative_offset, &orig_offset, FILE_CURRENT)) {
513 		err = GetLastError();
514 		win32_error(err, L"Failed to get original file position");
515 		goto error;
516 	}
517 
518 	memset(&overlapped, 0, sizeof(overlapped));
519 	overlapped.Offset = offset;
520 	overlapped.OffsetHigh = offset >> 32;
521 
522 	/* Do the read or write at the specified offset */
523 	count = min(count, MAX_IO_AMOUNT);
524 	SetLastError(0);
525 	if (is_pwrite)
526 		bret = WriteFile(h, buf, count, &result, &overlapped);
527 	else
528 		bret = ReadFile(h, buf, count, &result, &overlapped);
529 	if (!bret) {
530 		err = GetLastError();
531 		win32_error(err, L"Failed to %s %zu bytes at offset %"PRIu64,
532 			    (is_pwrite ? "write" : "read"), count, offset);
533 		goto error;
534 	}
535 
536 	wimlib_assert(result <= count);
537 
538 	/* Restore the original position */
539 	if (!SetFilePointerEx(h, orig_offset, NULL, FILE_BEGIN)) {
540 		err = GetLastError();
541 		win32_error(err, L"Failed to restore file position to %"PRIu64,
542 			    offset);
543 		goto error;
544 	}
545 
546 	return result;
547 
548 error:
549 	if (err)
550 		set_errno_from_win32_error(err);
551 	return -1;
552 }
553 
554 /* Dumb Windows implementation of pread().  It temporarily changes the file
555  * offset, so it is not safe to use with readers/writers on the same file
556  * descriptor.  */
557 ssize_t
win32_pread(int fd,void * buf,size_t count,off_t offset)558 win32_pread(int fd, void *buf, size_t count, off_t offset)
559 {
560 	return do_pread_or_pwrite(fd, buf, count, offset, false);
561 }
562 
563 /* Dumb Windows implementation of pwrite().  It temporarily changes the file
564  * offset, so it is not safe to use with readers/writers on the same file
565  * descriptor. */
566 ssize_t
win32_pwrite(int fd,const void * buf,size_t count,off_t offset)567 win32_pwrite(int fd, const void *buf, size_t count, off_t offset)
568 {
569 	return do_pread_or_pwrite(fd, (void*)buf, count, offset, true);
570 }
571 
572 /* Replacement for read() which doesn't hide the Win32 error code */
573 ssize_t
win32_read(int fd,void * buf,size_t count)574 win32_read(int fd, void *buf, size_t count)
575 {
576 	HANDLE h = (HANDLE)_get_osfhandle(fd);
577 	DWORD result = 0xFFFFFFFF;
578 
579 	if (h == INVALID_HANDLE_VALUE)
580 		return -1;
581 
582 	count = min(count, MAX_IO_AMOUNT);
583 	SetLastError(0);
584 	if (!ReadFile(h, buf, count, &result, NULL)) {
585 		DWORD err = GetLastError();
586 		win32_error(err,
587 			    L"Error reading %zu bytes from fd %d", count, fd);
588 		set_errno_from_win32_error(err);
589 		return -1;
590 	}
591 
592 	wimlib_assert(result <= count);
593 	return result;
594 }
595 
596 /* Replacement for write() which doesn't hide the Win32 error code */
597 ssize_t
win32_write(int fd,const void * buf,size_t count)598 win32_write(int fd, const void *buf, size_t count)
599 {
600 	HANDLE h = (HANDLE)_get_osfhandle(fd);
601 	DWORD result = 0xFFFFFFFF;
602 
603 	if (h == INVALID_HANDLE_VALUE)
604 		return -1;
605 
606 	count = min(count, MAX_IO_AMOUNT);
607 	SetLastError(0);
608 	if (!WriteFile(h, buf, count, &result, NULL)) {
609 		DWORD err = GetLastError();
610 		win32_error(err,
611 			    L"Error writing %zu bytes to fd %d", count, fd);
612 		set_errno_from_win32_error(err);
613 		return -1;
614 	}
615 
616 	wimlib_assert(result <= count);
617 	return result;
618 }
619 
620 /* Replacement for glob() in Windows native builds that operates on wide
621  * characters.  */
622 int
win32_wglob(const wchar_t * pattern,int flags,int (* errfunc)(const wchar_t * epath,int eerrno),glob_t * pglob)623 win32_wglob(const wchar_t *pattern, int flags,
624 	    int (*errfunc)(const wchar_t *epath, int eerrno),
625 	    glob_t *pglob)
626 {
627 	WIN32_FIND_DATAW dat;
628 	DWORD err;
629 	HANDLE hFind;
630 	int ret;
631 	size_t nspaces;
632 	int errno_save;
633 
634 	const wchar_t *backslash, *end_slash;
635 	size_t prefix_len;
636 
637 	backslash = wcsrchr(pattern, L'\\');
638 	end_slash = wcsrchr(pattern, L'/');
639 
640 	if (backslash > end_slash)
641 		end_slash = backslash;
642 
643 	if (end_slash)
644 		prefix_len = end_slash - pattern + 1;
645 	else
646 		prefix_len = 0;
647 
648 	/* This function does not support all functionality of the POSIX glob(),
649 	 * so make sure the parameters are consistent with supported
650 	 * functionality. */
651 	wimlib_assert(errfunc == NULL);
652 	wimlib_assert((flags & GLOB_ERR) == GLOB_ERR);
653 	wimlib_assert((flags & ~(GLOB_NOSORT | GLOB_ERR)) == 0);
654 
655 	hFind = FindFirstFileW(pattern, &dat);
656 	if (hFind == INVALID_HANDLE_VALUE) {
657 		err = GetLastError();
658 		if (err == ERROR_FILE_NOT_FOUND) {
659 			errno = 0;
660 			return GLOB_NOMATCH;
661 		} else {
662 			set_errno_from_win32_error(err);
663 			return GLOB_ABORTED;
664 		}
665 	}
666 	pglob->gl_pathc = 0;
667 	pglob->gl_pathv = NULL;
668 	nspaces = 0;
669 	do {
670 		wchar_t *path;
671 		if (pglob->gl_pathc == nspaces) {
672 			size_t new_nspaces;
673 			wchar_t **pathv;
674 
675 			new_nspaces = nspaces * 2 + 1;
676 			pathv = REALLOC(pglob->gl_pathv,
677 					new_nspaces * sizeof(pglob->gl_pathv[0]));
678 			if (!pathv)
679 				goto oom;
680 			pglob->gl_pathv = pathv;
681 			nspaces = new_nspaces;
682 		}
683 		size_t filename_len = wcslen(dat.cFileName);
684 		size_t len_needed = prefix_len + filename_len;
685 
686 		path = MALLOC((len_needed + 1) * sizeof(wchar_t));
687 		if (!path)
688 			goto oom;
689 
690 		wmemcpy(path, pattern, prefix_len);
691 		wmemcpy(path + prefix_len, dat.cFileName, filename_len + 1);
692 		pglob->gl_pathv[pglob->gl_pathc++] = path;
693 	} while (FindNextFileW(hFind, &dat));
694 	err = GetLastError();
695 	CloseHandle(hFind);
696 	if (err != ERROR_NO_MORE_FILES) {
697 		set_errno_from_win32_error(err);
698 		ret = GLOB_ABORTED;
699 		goto fail_globfree;
700 	}
701 	return 0;
702 
703 oom:
704 	CloseHandle(hFind);
705 	errno = ENOMEM;
706 	ret = GLOB_NOSPACE;
707 fail_globfree:
708 	errno_save = errno;
709 	globfree(pglob);
710 	errno = errno_save;
711 	return ret;
712 }
713 
714 void
globfree(glob_t * pglob)715 globfree(glob_t *pglob)
716 {
717 	size_t i;
718 	for (i = 0; i < pglob->gl_pathc; i++)
719 		FREE(pglob->gl_pathv[i]);
720 	FREE(pglob->gl_pathv);
721 }
722 
723 /* Replacement for fopen(path, "a") that doesn't prevent other processes from
724  * reading the file  */
725 FILE *
win32_open_logfile(const wchar_t * path)726 win32_open_logfile(const wchar_t *path)
727 {
728 	HANDLE h;
729 	int fd;
730 	FILE *fp;
731 
732 	h = CreateFile(path, FILE_APPEND_DATA, FILE_SHARE_VALID_FLAGS,
733 		       NULL, OPEN_ALWAYS, 0, NULL);
734 	if (h == INVALID_HANDLE_VALUE)
735 		return NULL;
736 
737 	fd = _open_osfhandle((intptr_t)h, O_APPEND);
738 	if (fd < 0) {
739 		CloseHandle(h);
740 		return NULL;
741 	}
742 
743 	fp = fdopen(fd, "a");
744 	if (!fp) {
745 		close(fd);
746 		return NULL;
747 	}
748 
749 	return fp;
750 }
751 
752 #define RtlGenRandom SystemFunction036
753 BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
754 
755 /*
756  * Generate @n cryptographically secure random bytes (thread-safe)
757  *
758  * This is the Windows version.  It uses RtlGenRandom() (actually called
759  * SystemFunction036) from advapi32.dll.
760  */
761 void
get_random_bytes(void * p,size_t n)762 get_random_bytes(void *p, size_t n)
763 {
764 	while (n != 0) {
765 		u32 count = min(n, UINT32_MAX);
766 
767 		if (!RtlGenRandom(p, count)) {
768 			win32_error(GetLastError(),
769 				    L"RtlGenRandom() failed (count=%u)", count);
770 			wimlib_assert(0);
771 			count = 0;
772 		}
773 		p += count;
774 		n -= count;
775 	}
776 }
777 
778 /* Retrieve the current time as a WIM timestamp.  */
779 u64
now_as_wim_timestamp(void)780 now_as_wim_timestamp(void)
781 {
782 	FILETIME ft;
783 
784 	GetSystemTimeAsFileTime(&ft);
785 
786 	return ((u64)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
787 }
788 
789 #endif /* __WIN32__ */
790