cpio_windows.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2009 Michihiro NAKAJIMA
  5. * All rights reserved.
  6. */
  7. #if defined(_WIN32) && !defined(__CYGWIN__)
  8. #include "cpio_platform.h"
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include <fcntl.h>
  12. #include <io.h>
  13. #include <stddef.h>
  14. #ifdef HAVE_SYS_UTIME_H
  15. #include <sys/utime.h>
  16. #endif
  17. #include <sys/stat.h>
  18. #include <process.h>
  19. #include <stdlib.h>
  20. #include <wchar.h>
  21. #include <windows.h>
  22. #include <sddl.h>
  23. #include "cpio.h"
  24. #include "err.h"
  25. #define EPOC_TIME (116444736000000000ULL)
  26. static void cpio_dosmaperr(unsigned long);
  27. /*
  28. * Prepend "\\?\" to the path name and convert it to unicode to permit
  29. * an extended-length path for a maximum total path length of 32767
  30. * characters.
  31. * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
  32. */
  33. static wchar_t *
  34. permissive_name(const char *name)
  35. {
  36. wchar_t *wn, *wnp;
  37. wchar_t *ws, *wsp;
  38. DWORD l, len, slen, alloclen;
  39. int unc;
  40. len = (DWORD)strlen(name);
  41. wn = malloc((len + 1) * sizeof(wchar_t));
  42. if (wn == NULL)
  43. return (NULL);
  44. l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
  45. if (l == 0) {
  46. free(wn);
  47. return (NULL);
  48. }
  49. wn[l] = L'\0';
  50. /* Get a full path names */
  51. l = GetFullPathNameW(wn, 0, NULL, NULL);
  52. if (l == 0) {
  53. free(wn);
  54. return (NULL);
  55. }
  56. wnp = malloc(l * sizeof(wchar_t));
  57. if (wnp == NULL) {
  58. free(wn);
  59. return (NULL);
  60. }
  61. len = GetFullPathNameW(wn, l, wnp, NULL);
  62. free(wn);
  63. wn = wnp;
  64. if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
  65. wnp[2] == L'?' && wnp[3] == L'\\')
  66. /* We have already permissive names. */
  67. return (wn);
  68. if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
  69. wnp[2] == L'.' && wnp[3] == L'\\') {
  70. /* Device names */
  71. if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
  72. (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
  73. wnp[5] == L':' && wnp[6] == L'\\')
  74. wnp[2] = L'?';/* Not device names. */
  75. return (wn);
  76. }
  77. unc = 0;
  78. if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
  79. wchar_t *p = &wnp[2];
  80. /* Skip server-name letters. */
  81. while (*p != L'\\' && *p != L'\0')
  82. ++p;
  83. if (*p == L'\\') {
  84. wchar_t *rp = ++p;
  85. /* Skip share-name letters. */
  86. while (*p != L'\\' && *p != L'\0')
  87. ++p;
  88. if (*p == L'\\' && p != rp) {
  89. /* Now, match patterns such as
  90. * "\\server-name\share-name\" */
  91. wnp += 2;
  92. len -= 2;
  93. unc = 1;
  94. }
  95. }
  96. }
  97. alloclen = slen = 4 + (unc * 4) + len + 1;
  98. ws = wsp = malloc(slen * sizeof(wchar_t));
  99. if (ws == NULL) {
  100. free(wn);
  101. return (NULL);
  102. }
  103. /* prepend "\\?\" */
  104. wcsncpy(wsp, L"\\\\?\\", 4);
  105. wsp += 4;
  106. slen -= 4;
  107. if (unc) {
  108. /* append "UNC\" ---> "\\?\UNC\" */
  109. wcsncpy(wsp, L"UNC\\", 4);
  110. wsp += 4;
  111. slen -= 4;
  112. }
  113. wcsncpy(wsp, wnp, slen);
  114. free(wn);
  115. ws[alloclen - 1] = L'\0';
  116. return (ws);
  117. }
  118. static HANDLE
  119. cpio_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
  120. LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
  121. DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
  122. {
  123. wchar_t *wpath;
  124. HANDLE handle;
  125. # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
  126. CREATEFILE2_EXTENDED_PARAMETERS createExParams;
  127. #endif
  128. #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
  129. handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
  130. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
  131. hTemplateFile);
  132. if (handle != INVALID_HANDLE_VALUE)
  133. return (handle);
  134. if (GetLastError() != ERROR_PATH_NOT_FOUND)
  135. return (handle);
  136. #endif
  137. wpath = permissive_name(path);
  138. if (wpath == NULL)
  139. return INVALID_HANDLE_VALUE;
  140. # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
  141. ZeroMemory(&createExParams, sizeof(createExParams));
  142. createExParams.dwSize = sizeof(createExParams);
  143. createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF;
  144. createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000;
  145. createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F0000;
  146. createExParams.lpSecurityAttributes = lpSecurityAttributes;
  147. createExParams.hTemplateFile = hTemplateFile;
  148. handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode,
  149. dwCreationDisposition, &createExParams);
  150. #else
  151. handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
  152. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
  153. hTemplateFile);
  154. #endif
  155. free(wpath);
  156. return (handle);
  157. }
  158. #define WINTIME(sec, usec) (((sec * 10000000LL) + EPOC_TIME) + (usec * 10))
  159. static int
  160. __hutimes(HANDLE handle, const struct __timeval *times)
  161. {
  162. ULARGE_INTEGER wintm;
  163. FILETIME fatime, fmtime;
  164. wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec);
  165. fatime.dwLowDateTime = wintm.LowPart;
  166. fatime.dwHighDateTime = wintm.HighPart;
  167. wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec);
  168. fmtime.dwLowDateTime = wintm.LowPart;
  169. fmtime.dwHighDateTime = wintm.HighPart;
  170. if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) {
  171. errno = EINVAL;
  172. return (-1);
  173. }
  174. return (0);
  175. }
  176. int
  177. futimes(int fd, const struct __timeval *times)
  178. {
  179. return (__hutimes((HANDLE)_get_osfhandle(fd), times));
  180. }
  181. int
  182. utimes(const char *name, const struct __timeval *times)
  183. {
  184. int ret;
  185. HANDLE handle;
  186. handle = cpio_CreateFile(name, GENERIC_READ | GENERIC_WRITE,
  187. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  188. FILE_FLAG_BACKUP_SEMANTICS, NULL);
  189. if (handle == INVALID_HANDLE_VALUE) {
  190. cpio_dosmaperr(GetLastError());
  191. return (-1);
  192. }
  193. ret = __hutimes(handle, times);
  194. CloseHandle(handle);
  195. return (ret);
  196. }
  197. /*
  198. * The following function was modified from PostgreSQL sources and is
  199. * subject to the copyright below.
  200. */
  201. /*-------------------------------------------------------------------------
  202. *
  203. * win32error.c
  204. * Map win32 error codes to errno values
  205. *
  206. * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  207. *
  208. * IDENTIFICATION
  209. * $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
  210. *
  211. *-------------------------------------------------------------------------
  212. */
  213. /*
  214. PostgreSQL Database Management System
  215. (formerly known as Postgres, then as Postgres95)
  216. Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  217. Portions Copyright (c) 1994, The Regents of the University of California
  218. Permission to use, copy, modify, and distribute this software and its
  219. documentation for any purpose, without fee, and without a written agreement
  220. is hereby granted, provided that the above copyright notice and this
  221. paragraph and the following two paragraphs appear in all copies.
  222. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  223. DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
  224. LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
  225. DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
  226. POSSIBILITY OF SUCH DAMAGE.
  227. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  228. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  229. AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  230. ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
  231. PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  232. */
  233. static const struct {
  234. DWORD winerr;
  235. int doserr;
  236. } doserrors[] =
  237. {
  238. { ERROR_INVALID_FUNCTION, EINVAL },
  239. { ERROR_FILE_NOT_FOUND, ENOENT },
  240. { ERROR_PATH_NOT_FOUND, ENOENT },
  241. { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
  242. { ERROR_ACCESS_DENIED, EACCES },
  243. { ERROR_INVALID_HANDLE, EBADF },
  244. { ERROR_ARENA_TRASHED, ENOMEM },
  245. { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
  246. { ERROR_INVALID_BLOCK, ENOMEM },
  247. { ERROR_BAD_ENVIRONMENT, E2BIG },
  248. { ERROR_BAD_FORMAT, ENOEXEC },
  249. { ERROR_INVALID_ACCESS, EINVAL },
  250. { ERROR_INVALID_DATA, EINVAL },
  251. { ERROR_INVALID_DRIVE, ENOENT },
  252. { ERROR_CURRENT_DIRECTORY, EACCES },
  253. { ERROR_NOT_SAME_DEVICE, EXDEV },
  254. { ERROR_NO_MORE_FILES, ENOENT },
  255. { ERROR_LOCK_VIOLATION, EACCES },
  256. { ERROR_SHARING_VIOLATION, EACCES },
  257. { ERROR_BAD_NETPATH, ENOENT },
  258. { ERROR_NETWORK_ACCESS_DENIED, EACCES },
  259. { ERROR_BAD_NET_NAME, ENOENT },
  260. { ERROR_FILE_EXISTS, EEXIST },
  261. { ERROR_CANNOT_MAKE, EACCES },
  262. { ERROR_FAIL_I24, EACCES },
  263. { ERROR_INVALID_PARAMETER, EINVAL },
  264. { ERROR_NO_PROC_SLOTS, EAGAIN },
  265. { ERROR_DRIVE_LOCKED, EACCES },
  266. { ERROR_BROKEN_PIPE, EPIPE },
  267. { ERROR_DISK_FULL, ENOSPC },
  268. { ERROR_INVALID_TARGET_HANDLE, EBADF },
  269. { ERROR_INVALID_HANDLE, EINVAL },
  270. { ERROR_WAIT_NO_CHILDREN, ECHILD },
  271. { ERROR_CHILD_NOT_COMPLETE, ECHILD },
  272. { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
  273. { ERROR_NEGATIVE_SEEK, EINVAL },
  274. { ERROR_SEEK_ON_DEVICE, EACCES },
  275. { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
  276. { ERROR_NOT_LOCKED, EACCES },
  277. { ERROR_BAD_PATHNAME, ENOENT },
  278. { ERROR_MAX_THRDS_REACHED, EAGAIN },
  279. { ERROR_LOCK_FAILED, EACCES },
  280. { ERROR_ALREADY_EXISTS, EEXIST },
  281. { ERROR_FILENAME_EXCED_RANGE, ENOENT },
  282. { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
  283. { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }
  284. };
  285. static void
  286. cpio_dosmaperr(unsigned long e)
  287. {
  288. int i;
  289. if (e == 0) {
  290. errno = 0;
  291. return;
  292. }
  293. for (i = 0; i < (int)sizeof(doserrors); i++) {
  294. if (doserrors[i].winerr == e) {
  295. errno = doserrors[i].doserr;
  296. return;
  297. }
  298. }
  299. /* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
  300. errno = EINVAL;
  301. return;
  302. }
  303. #endif