archive_windows.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  1. /*-
  2. * Copyright (c) 2009 Michihiro NAKAJIMA
  3. * Copyright (c) 2003-2007 Kees Zeelenberg
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. * $FreeBSD$
  27. */
  28. /*
  29. * A set of compatibility glue for building libarchive on Windows platforms.
  30. *
  31. * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg
  32. * for the GnuWin32 project, trimmed significantly by Tim Kientzle.
  33. *
  34. * Much of the original file was unnecessary for libarchive, because
  35. * many of the features it emulated were not strictly necessary for
  36. * libarchive. I hope for this to shrink further as libarchive
  37. * internals are gradually reworked to sit more naturally on both
  38. * POSIX and Windows. Any ideas for this are greatly appreciated.
  39. *
  40. * The biggest remaining issue is the dev/ino emulation; libarchive
  41. * has a couple of public APIs that rely on dev/ino uniquely
  42. * identifying a file. This doesn't match well with Windows. I'm
  43. * considering alternative APIs.
  44. */
  45. #if defined(_WIN32) && !defined(__CYGWIN__)
  46. #define _WIN32_WINNT 0x0500
  47. #define WINVER 0x0500
  48. #include "archive_platform.h"
  49. #include <errno.h>
  50. #include <stddef.h>
  51. #include <sys/utime.h>
  52. #include <sys/stat.h>
  53. #include <process.h>
  54. #include <stdlib.h>
  55. #include <wchar.h>
  56. #include <windows.h>
  57. #define EPOC_TIME (116444736000000000ULL)
  58. struct ustat {
  59. int64_t st_atime;
  60. uint32_t st_atime_nsec;
  61. int64_t st_ctime;
  62. uint32_t st_ctime_nsec;
  63. int64_t st_mtime;
  64. uint32_t st_mtime_nsec;
  65. gid_t st_gid;
  66. /* 64bits ino */
  67. int64_t st_ino;
  68. mode_t st_mode;
  69. uint32_t st_nlink;
  70. uint64_t st_size;
  71. uid_t st_uid;
  72. dev_t st_dev;
  73. dev_t st_rdev;
  74. };
  75. /* Transform 64-bits ino into 32-bits by hashing.
  76. * You do not forget that really unique number size is 64-bits.
  77. */
  78. #define INOSIZE (8*sizeof(ino_t)) /* 32 */
  79. static __inline ino_t
  80. getino(struct ustat *ub)
  81. {
  82. ULARGE_INTEGER ino64;
  83. ino64.QuadPart = ub->st_ino;
  84. /* I don't know this hashing is correct way */
  85. return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE));
  86. }
  87. /*
  88. * Prepend "\\?\" to the path name and convert it to unicode to permit
  89. * an extended-length path for a maximum total path length of 32767
  90. * characters.
  91. * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
  92. */
  93. static wchar_t *
  94. permissive_name(const char *name)
  95. {
  96. wchar_t *wn, *wnp;
  97. wchar_t *ws, *wsp;
  98. size_t l, len, slen;
  99. int unc;
  100. len = strlen(name);
  101. wn = malloc((len + 1) * sizeof(wchar_t));
  102. if (wn == NULL)
  103. return (NULL);
  104. l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
  105. if (l == 0) {
  106. free(wn);
  107. return (NULL);
  108. }
  109. wn[l] = L'\0';
  110. /* Get a full path names */
  111. l = GetFullPathNameW(wn, 0, NULL, NULL);
  112. if (l == 0) {
  113. free(wn);
  114. return (NULL);
  115. }
  116. wnp = malloc(l * sizeof(wchar_t));
  117. if (wnp == NULL) {
  118. free(wn);
  119. return (NULL);
  120. }
  121. len = GetFullPathNameW(wn, l, wnp, NULL);
  122. free(wn);
  123. wn = wnp;
  124. if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
  125. wnp[2] == L'?' && wnp[3] == L'\\')
  126. /* We have already permissive names. */
  127. return (wn);
  128. if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
  129. wnp[2] == L'.' && wnp[3] == L'\\') {
  130. /* Device names */
  131. if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
  132. (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
  133. wnp[5] == L':' && wnp[6] == L'\\')
  134. wnp[2] = L'?';/* Not device names. */
  135. return (wn);
  136. }
  137. unc = 0;
  138. if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
  139. wchar_t *p = &wnp[2];
  140. /* Skip server-name letters. */
  141. while (*p != L'\\' && *p != L'\0')
  142. ++p;
  143. if (*p == L'\\') {
  144. wchar_t *rp = ++p;
  145. /* Skip share-name letters. */
  146. while (*p != L'\\' && *p != L'\0')
  147. ++p;
  148. if (*p == L'\\' && p != rp) {
  149. /* Now, match patterns such as
  150. * "\\server-name\share-name\" */
  151. wnp += 2;
  152. len -= 2;
  153. unc = 1;
  154. }
  155. }
  156. }
  157. slen = 4 + (unc * 4) + len + 1;
  158. ws = wsp = malloc(slen * sizeof(wchar_t));
  159. if (ws == NULL) {
  160. free(wn);
  161. return (NULL);
  162. }
  163. /* prepend "\\?\" */
  164. wcsncpy(wsp, L"\\\\?\\", 4);
  165. wsp += 4;
  166. slen -= 4;
  167. if (unc) {
  168. /* append "UNC\" ---> "\\?\UNC\" */
  169. wcsncpy(wsp, L"UNC\\", 4);
  170. wsp += 4;
  171. slen -= 4;
  172. }
  173. wcsncpy_s(wsp, slen, wnp, _TRUNCATE);
  174. free(wn);
  175. return (ws);
  176. }
  177. static HANDLE
  178. la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
  179. LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
  180. DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
  181. {
  182. wchar_t *wpath;
  183. HANDLE handle;
  184. handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
  185. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
  186. hTemplateFile);
  187. if (handle != INVALID_HANDLE_VALUE)
  188. return (handle);
  189. if (GetLastError() != ERROR_PATH_NOT_FOUND)
  190. return (handle);
  191. wpath = permissive_name(path);
  192. if (wpath == NULL)
  193. return (handle);
  194. handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
  195. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
  196. hTemplateFile);
  197. free(wpath);
  198. return (handle);
  199. }
  200. static size_t
  201. wequallen(const wchar_t *s1, const wchar_t *s2)
  202. {
  203. size_t i = 0;
  204. while (*s1 != L'\0' && *s2 != L'\0' && *s1 == *s2) {
  205. ++s1; ++s2; ++i;
  206. }
  207. return (i);
  208. }
  209. /* Check that path1 and path2 can be hard-linked by each other.
  210. * Both arguments must be made by permissive_name function.
  211. */
  212. static int
  213. canHardLinkW(const wchar_t *path1, const wchar_t *path2)
  214. {
  215. wchar_t root[MAX_PATH];
  216. wchar_t fs[32];
  217. const wchar_t *s;
  218. int r;
  219. r = wequallen(path1, path2);
  220. /* Is volume-name the same? */
  221. if (r < 7)
  222. return (0);
  223. if (wcsncmp(path1, L"\\\\?\\UNC\\", 8) == 0) {
  224. int len;
  225. s = path1 + 8;
  226. if (*s == L'\\')
  227. return (0);
  228. /* 012345678
  229. * Name : "\\?\UNC\Server\Share\"
  230. * ^ search
  231. */
  232. s = wcschr(++s, L'\\');
  233. if (s == NULL)
  234. return (0);
  235. if (*++s == L'\\')
  236. return (0);
  237. /* 012345678
  238. * Name : "\\?\UNC\Server\Share\"
  239. * ^ search
  240. */
  241. s = wcschr(++s, L'\\');
  242. if (s == NULL)
  243. return (0);
  244. s++;
  245. /* 012345678
  246. * Name : "\\?\UNC\Server\Share\xxxx"
  247. * ^--- len ----^
  248. */
  249. len = (int)(s - path1 - 8);
  250. /* Is volume-name the same? */
  251. if (r < len + 8)
  252. return (0);
  253. /* Is volume-name too long? */
  254. if (sizeof(root) -3 < len)
  255. return (0);
  256. root[0] = root[1] = L'\\';
  257. wcsncpy(root + 2, path1 + 8, len);
  258. /* root : "\\Server\Share\" */
  259. root[2 + len] = L'\0';
  260. } else if (wcsncmp(path1, L"\\\\?\\", 4) == 0) {
  261. s = path1 + 4;
  262. if ((!iswalpha(*s)) || s[1] != L':' || s[2] != L'\\')
  263. return (0);
  264. wcsncpy(root, path1 + 4, 3);
  265. root[3] = L'\0';
  266. } else
  267. return (0);
  268. if (!GetVolumeInformationW(root, NULL, 0, NULL, NULL, NULL, fs, sizeof(fs)))
  269. return (0);
  270. if (wcscmp(fs, L"NTFS") == 0)
  271. return (1);
  272. else
  273. return (0);
  274. }
  275. /* Make a link to src called dst. */
  276. static int
  277. __link(const char *src, const char *dst, int sym)
  278. {
  279. wchar_t *wsrc, *wdst;
  280. int res, retval;
  281. DWORD attr;
  282. if (src == NULL || dst == NULL) {
  283. set_errno (EINVAL);
  284. return -1;
  285. }
  286. wsrc = permissive_name(src);
  287. wdst = permissive_name(dst);
  288. if (wsrc == NULL || wdst == NULL) {
  289. if (wsrc != NULL)
  290. free(wsrc);
  291. if (wdst != NULL)
  292. free(wdst);
  293. set_errno (EINVAL);
  294. return -1;
  295. }
  296. if ((attr = GetFileAttributesW(wsrc)) != -1) {
  297. if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  298. errno = EPERM;
  299. retval = -1;
  300. goto exit;
  301. }
  302. if (!sym && canHardLinkW(wsrc, wdst))
  303. res = CreateHardLinkW(wdst, wsrc, NULL);
  304. else
  305. res = CopyFileW(wsrc, wdst, FALSE);
  306. } else {
  307. /* wsrc does not exist; try src prepend it with the dirname of wdst */
  308. wchar_t *wnewsrc, *slash;
  309. int i, n, slen, wlen;
  310. if (strlen(src) >= 3 && isalpha((unsigned char)src[0]) &&
  311. src[1] == ':' && src[2] == '\\') {
  312. /* Original src name is already full-path */
  313. retval = -1;
  314. goto exit;
  315. }
  316. if (src[0] == '\\') {
  317. /* Original src name is almost full-path
  318. * (maybe src name is without drive) */
  319. retval = -1;
  320. goto exit;
  321. }
  322. wnewsrc = malloc ((wcslen(wsrc) + wcslen(wdst) + 1) * sizeof(wchar_t));
  323. if (wnewsrc == NULL) {
  324. errno = ENOMEM;
  325. retval = -1;
  326. goto exit;
  327. }
  328. /* Copying a dirname of wdst */
  329. wcscpy(wnewsrc, wdst);
  330. slash = wcsrchr(wnewsrc, L'\\');
  331. if (slash != NULL)
  332. *++slash = L'\0';
  333. else
  334. wcscat(wnewsrc, L"\\");
  335. /* Converting multi-byte src to wide-char src */
  336. wlen = wcslen(wsrc);
  337. slen = strlen(src);
  338. n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, slen);
  339. if (n == 0) {
  340. free (wnewsrc);
  341. retval = -1;
  342. goto exit;
  343. }
  344. for (i = 0; i < n; i++)
  345. if (wsrc[i] == L'/')
  346. wsrc[i] = L'\\';
  347. wcsncat(wnewsrc, wsrc, n);
  348. /* Check again */
  349. attr = GetFileAttributesW(wnewsrc);
  350. if (attr == -1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  351. if (attr == -1)
  352. _dosmaperr(GetLastError());
  353. else
  354. errno = EPERM;
  355. free (wnewsrc);
  356. retval = -1;
  357. goto exit;
  358. }
  359. if (!sym && canHardLinkW(wnewsrc, wdst))
  360. res = CreateHardLinkW(wdst, wnewsrc, NULL);
  361. else
  362. res = CopyFileW(wnewsrc, wdst, FALSE);
  363. free (wnewsrc);
  364. }
  365. if (res == 0) {
  366. _dosmaperr(GetLastError());
  367. retval = -1;
  368. } else
  369. retval = 0;
  370. exit:
  371. free(wsrc);
  372. free(wdst);
  373. return (retval);
  374. }
  375. /* Make a hard link to src called dst. */
  376. int
  377. link(const char *src, const char *dst)
  378. {
  379. return __link (src, dst, 0);
  380. }
  381. /* Make a symbolic link to FROM called TO. */
  382. int symlink (from, to)
  383. const char *from;
  384. const char *to;
  385. {
  386. return __link (from, to, 1);
  387. }
  388. int
  389. ftruncate(int fd, off_t length)
  390. {
  391. LARGE_INTEGER distance;
  392. HANDLE handle;
  393. if (fd < 0) {
  394. errno = EBADF;
  395. return (-1);
  396. }
  397. handle = (HANDLE)_get_osfhandle(fd);
  398. if (GetFileType(handle) != FILE_TYPE_DISK) {
  399. errno = EBADF;
  400. return (-1);
  401. }
  402. distance.QuadPart = length;
  403. if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN)) {
  404. _dosmaperr(GetLastError());
  405. return (-1);
  406. }
  407. if (!SetEndOfFile(handle)) {
  408. _dosmaperr(GetLastError());
  409. return (-1);
  410. }
  411. return (0);
  412. }
  413. #define WINTIME(sec, usec) ((Int32x32To64(sec, 10000000) + EPOC_TIME) + (usec * 10))
  414. static int
  415. __hutimes(HANDLE handle, const struct __timeval *times)
  416. {
  417. ULARGE_INTEGER wintm;
  418. FILETIME fatime, fmtime;
  419. wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec);
  420. fatime.dwLowDateTime = wintm.LowPart;
  421. fatime.dwHighDateTime = wintm.HighPart;
  422. wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec);
  423. fmtime.dwLowDateTime = wintm.LowPart;
  424. fmtime.dwHighDateTime = wintm.HighPart;
  425. if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) {
  426. errno = EINVAL;
  427. return (-1);
  428. }
  429. return (0);
  430. }
  431. int
  432. futimes(int fd, const struct __timeval *times)
  433. {
  434. return (__hutimes((HANDLE)_get_osfhandle(fd), times));
  435. }
  436. int
  437. utimes(const char *name, const struct __timeval *times)
  438. {
  439. int ret;
  440. HANDLE handle;
  441. handle = la_CreateFile(name, GENERIC_READ | GENERIC_WRITE,
  442. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  443. FILE_FLAG_BACKUP_SEMANTICS, NULL);
  444. if (handle == INVALID_HANDLE_VALUE) {
  445. _dosmaperr(GetLastError());
  446. return (-1);
  447. }
  448. ret = __hutimes(handle, times);
  449. CloseHandle(handle);
  450. return (ret);
  451. }
  452. int
  453. la_chdir(const char *path)
  454. {
  455. wchar_t *ws;
  456. int r;
  457. r = SetCurrentDirectoryA(path);
  458. if (r == 0) {
  459. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  460. _dosmaperr(GetLastError());
  461. return (-1);
  462. }
  463. } else
  464. return (0);
  465. ws = permissive_name(path);
  466. if (ws == NULL) {
  467. errno = EINVAL;
  468. return (-1);
  469. }
  470. r = SetCurrentDirectoryW(ws);
  471. free(ws);
  472. if (r == 0) {
  473. _dosmaperr(GetLastError());
  474. return (-1);
  475. }
  476. return (0);
  477. }
  478. int
  479. la_chmod(const char *path, mode_t mode)
  480. {
  481. wchar_t *ws;
  482. int r;
  483. r = _chmod(path, mode);
  484. if (r >= 0 || errno != ENOENT)
  485. return (r);
  486. ws = permissive_name(path);
  487. if (ws == NULL) {
  488. errno = EINVAL;
  489. return (-1);
  490. }
  491. r = _wchmod(ws, mode);
  492. free(ws);
  493. return (r);
  494. }
  495. /*
  496. * This fcntl is limited implemention.
  497. */
  498. int
  499. la_fcntl(int fd, int cmd, int val)
  500. {
  501. HANDLE handle;
  502. handle = (HANDLE)_get_osfhandle(fd);
  503. if (GetFileType(handle) == FILE_TYPE_PIPE) {
  504. if (cmd == F_SETFL && val == 0) {
  505. DWORD mode = PIPE_WAIT;
  506. if (SetNamedPipeHandleState(
  507. handle, &mode, NULL, NULL) != 0)
  508. return (0);
  509. }
  510. }
  511. errno = EINVAL;
  512. return (-1);
  513. }
  514. __int64
  515. la_lseek(int fd, __int64 offset, int whence)
  516. {
  517. LARGE_INTEGER distance;
  518. LARGE_INTEGER newpointer;
  519. HANDLE handle;
  520. if (fd < 0) {
  521. errno = EBADF;
  522. return (-1);
  523. }
  524. handle = (HANDLE)_get_osfhandle(fd);
  525. if (GetFileType(handle) != FILE_TYPE_DISK) {
  526. errno = EBADF;
  527. return (-1);
  528. }
  529. distance.QuadPart = offset;
  530. if (!SetFilePointerEx(handle, distance, &newpointer, whence)) {
  531. DWORD lasterr;
  532. lasterr = GetLastError();
  533. if (lasterr == ERROR_BROKEN_PIPE)
  534. return (0);
  535. if (lasterr == ERROR_ACCESS_DENIED)
  536. errno = EBADF;
  537. else
  538. _dosmaperr(lasterr);
  539. return (-1);
  540. }
  541. return (newpointer.QuadPart);
  542. }
  543. int
  544. la_mkdir(const char *path, mode_t mode)
  545. {
  546. wchar_t *ws;
  547. int r;
  548. (void)mode;/* UNUSED */
  549. r = CreateDirectoryA(path, NULL);
  550. if (r == 0) {
  551. DWORD lasterr = GetLastError();
  552. if (lasterr != ERROR_FILENAME_EXCED_RANGE &&
  553. lasterr != ERROR_PATH_NOT_FOUND) {
  554. _dosmaperr(GetLastError());
  555. return (-1);
  556. }
  557. } else
  558. return (0);
  559. ws = permissive_name(path);
  560. if (ws == NULL) {
  561. errno = EINVAL;
  562. return (-1);
  563. }
  564. r = CreateDirectoryW(ws, NULL);
  565. free(ws);
  566. if (r == 0) {
  567. _dosmaperr(GetLastError());
  568. return (-1);
  569. }
  570. return (0);
  571. }
  572. /* Windows' mbstowcs is differrent error handling from other unix mbstowcs.
  573. * That one is using MultiByteToWideChar function with MB_PRECOMPOSED and
  574. * MB_ERR_INVALID_CHARS flags.
  575. * This implements for only to pass libarchive_test.
  576. */
  577. size_t
  578. la_mbstowcs(wchar_t *wcstr, const char *mbstr, size_t nwchars)
  579. {
  580. return (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
  581. mbstr, (int)strlen(mbstr), wcstr,
  582. (int)nwchars));
  583. }
  584. int
  585. la_open(const char *path, int flags, ...)
  586. {
  587. va_list ap;
  588. wchar_t *ws;
  589. int r, pmode;
  590. DWORD attr;
  591. va_start(ap, flags);
  592. pmode = va_arg(ap, int);
  593. va_end(ap);
  594. ws = NULL;
  595. if ((flags & ~O_BINARY) == O_RDONLY) {
  596. /*
  597. * When we open a directory, _open function returns
  598. * "Permission denied" error.
  599. */
  600. attr = GetFileAttributesA(path);
  601. if (attr == -1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
  602. ws = permissive_name(path);
  603. if (ws == NULL) {
  604. errno = EINVAL;
  605. return (-1);
  606. }
  607. attr = GetFileAttributesW(ws);
  608. }
  609. if (attr == -1) {
  610. _dosmaperr(GetLastError());
  611. free(ws);
  612. return (-1);
  613. }
  614. if (attr & FILE_ATTRIBUTE_DIRECTORY) {
  615. HANDLE handle;
  616. if (ws != NULL)
  617. handle = CreateFileW(ws, 0, 0, NULL,
  618. OPEN_EXISTING,
  619. FILE_FLAG_BACKUP_SEMANTICS |
  620. FILE_ATTRIBUTE_READONLY,
  621. NULL);
  622. else
  623. handle = CreateFileA(path, 0, 0, NULL,
  624. OPEN_EXISTING,
  625. FILE_FLAG_BACKUP_SEMANTICS |
  626. FILE_ATTRIBUTE_READONLY,
  627. NULL);
  628. free(ws);
  629. if (handle == INVALID_HANDLE_VALUE) {
  630. _dosmaperr(GetLastError());
  631. return (-1);
  632. }
  633. r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
  634. return (r);
  635. }
  636. }
  637. if (ws == NULL) {
  638. r = _open(path, flags, pmode);
  639. if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
  640. /* simular other POSIX system action to pass a test */
  641. attr = GetFileAttributesA(path);
  642. if (attr == -1)
  643. _dosmaperr(GetLastError());
  644. else if (attr & FILE_ATTRIBUTE_DIRECTORY)
  645. errno = EISDIR;
  646. else
  647. errno = EACCES;
  648. return (-1);
  649. }
  650. if (r >= 0 || errno != ENOENT)
  651. return (r);
  652. ws = permissive_name(path);
  653. if (ws == NULL) {
  654. errno = EINVAL;
  655. return (-1);
  656. }
  657. }
  658. r = _wopen(ws, flags, pmode);
  659. if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
  660. /* simular other POSIX system action to pass a test */
  661. attr = GetFileAttributesW(ws);
  662. if (attr == -1)
  663. _dosmaperr(GetLastError());
  664. else if (attr & FILE_ATTRIBUTE_DIRECTORY)
  665. errno = EISDIR;
  666. else
  667. errno = EACCES;
  668. }
  669. free(ws);
  670. return (r);
  671. }
  672. ssize_t
  673. la_read(int fd, void *buf, size_t nbytes)
  674. {
  675. HANDLE handle;
  676. DWORD bytes_read, lasterr;
  677. int r;
  678. #ifdef _WIN64
  679. if (nbytes > UINT32_MAX)
  680. nbytes = UINT32_MAX;
  681. #endif
  682. if (fd < 0) {
  683. errno = EBADF;
  684. return (-1);
  685. }
  686. handle = (HANDLE)_get_osfhandle(fd);
  687. if (GetFileType(handle) == FILE_TYPE_PIPE) {
  688. DWORD sta;
  689. if (GetNamedPipeHandleState(
  690. handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 &&
  691. (sta & PIPE_NOWAIT) == 0) {
  692. DWORD avail = -1;
  693. int cnt = 3;
  694. while (PeekNamedPipe(
  695. handle, NULL, 0, NULL, &avail, NULL) != 0 &&
  696. avail == 0 && --cnt)
  697. Sleep(100);
  698. if (avail == 0)
  699. return (0);
  700. }
  701. }
  702. r = ReadFile(handle, buf, (uint32_t)nbytes,
  703. &bytes_read, NULL);
  704. if (r == 0) {
  705. lasterr = GetLastError();
  706. if (lasterr == ERROR_NO_DATA) {
  707. errno = EAGAIN;
  708. return (-1);
  709. }
  710. if (lasterr == ERROR_BROKEN_PIPE)
  711. return (0);
  712. if (lasterr == ERROR_ACCESS_DENIED)
  713. errno = EBADF;
  714. else
  715. _dosmaperr(lasterr);
  716. return (-1);
  717. }
  718. return ((ssize_t)bytes_read);
  719. }
  720. /* Remove directory */
  721. int
  722. la_rmdir(const char *path)
  723. {
  724. wchar_t *ws;
  725. int r;
  726. r = _rmdir(path);
  727. if (r >= 0 || errno != ENOENT)
  728. return (r);
  729. ws = permissive_name(path);
  730. if (ws == NULL) {
  731. errno = EINVAL;
  732. return (-1);
  733. }
  734. r = _wrmdir(ws);
  735. free(ws);
  736. return (r);
  737. }
  738. /* Convert Windows FILETIME to UTC */
  739. __inline static void
  740. fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
  741. {
  742. ULARGE_INTEGER utc;
  743. utc.HighPart = filetime->dwHighDateTime;
  744. utc.LowPart = filetime->dwLowDateTime;
  745. if (utc.QuadPart >= EPOC_TIME) {
  746. utc.QuadPart -= EPOC_TIME;
  747. *time = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */
  748. *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
  749. } else {
  750. *time = 0;
  751. *ns = 0;
  752. }
  753. }
  754. /* Stat by handle
  755. * Windows' stat() does not accept path which is added "\\?\" especially "?"
  756. * character.
  757. * It means we cannot access a long name path(which is longer than MAX_PATH).
  758. * So I've implemented simular Windows' stat() to access the long name path.
  759. * And I've added some feature.
  760. * 1. set st_ino by nFileIndexHigh and nFileIndexLow of
  761. * BY_HANDLE_FILE_INFORMATION.
  762. * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.
  763. * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.
  764. */
  765. static int
  766. __hstat(HANDLE handle, struct ustat *st)
  767. {
  768. BY_HANDLE_FILE_INFORMATION info;
  769. ULARGE_INTEGER ino64;
  770. DWORD ftype;
  771. mode_t mode;
  772. time_t time;
  773. long ns;
  774. switch (ftype = GetFileType(handle)) {
  775. case FILE_TYPE_UNKNOWN:
  776. errno = EBADF;
  777. return (-1);
  778. case FILE_TYPE_CHAR:
  779. case FILE_TYPE_PIPE:
  780. if (ftype == FILE_TYPE_CHAR) {
  781. st->st_mode = S_IFCHR;
  782. st->st_size = 0;
  783. } else {
  784. DWORD avail;
  785. st->st_mode = S_IFIFO;
  786. if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))
  787. st->st_size = avail;
  788. else
  789. st->st_size = 0;
  790. }
  791. st->st_atime = 0;
  792. st->st_atime_nsec = 0;
  793. st->st_mtime = 0;
  794. st->st_mtime_nsec = 0;
  795. st->st_ctime = 0;
  796. st->st_ctime_nsec = 0;
  797. st->st_ino = 0;
  798. st->st_nlink = 1;
  799. st->st_uid = 0;
  800. st->st_gid = 0;
  801. st->st_rdev = 0;
  802. st->st_dev = 0;
  803. return (0);
  804. case FILE_TYPE_DISK:
  805. break;
  806. default:
  807. /* This ftype is undocumented type. */
  808. _dosmaperr(GetLastError());
  809. return (-1);
  810. }
  811. ZeroMemory(&info, sizeof(info));
  812. if (!GetFileInformationByHandle (handle, &info)) {
  813. _dosmaperr(GetLastError());
  814. return (-1);
  815. }
  816. mode = S_IRUSR | S_IRGRP | S_IROTH;
  817. if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
  818. mode |= S_IWUSR | S_IWGRP | S_IWOTH;
  819. if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  820. mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
  821. else
  822. mode |= S_IFREG;
  823. st->st_mode = mode;
  824. fileTimeToUTC(&info.ftLastAccessTime, &time, &ns);
  825. st->st_atime = time;
  826. st->st_atime_nsec = ns;
  827. fileTimeToUTC(&info.ftLastWriteTime, &time, &ns);
  828. st->st_mtime = time;
  829. st->st_mtime_nsec = ns;
  830. fileTimeToUTC(&info.ftCreationTime, &time, &ns);
  831. st->st_ctime = time;
  832. st->st_ctime_nsec = ns;
  833. st->st_size =
  834. ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
  835. + (int64_t)(info.nFileSizeLow);
  836. #ifdef SIMULATE_WIN_STAT
  837. st->st_ino = 0;
  838. st->st_nlink = 1;
  839. st->st_dev = 0;
  840. #else
  841. /* Getting FileIndex as i-node. We have to remove a sequence which
  842. * is high-16-bits of nFileIndexHigh. */
  843. ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;
  844. ino64.LowPart = info.nFileIndexLow;
  845. st->st_ino = ino64.QuadPart;
  846. st->st_nlink = info.nNumberOfLinks;
  847. if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  848. ++st->st_nlink;/* Add parent directory. */
  849. st->st_dev = info.dwVolumeSerialNumber;
  850. #endif
  851. st->st_uid = 0;
  852. st->st_gid = 0;
  853. st->st_rdev = 0;
  854. return (0);
  855. }
  856. static void
  857. copy_stat(struct stat *st, struct ustat *us)
  858. {
  859. st->st_atime = us->st_atime;
  860. st->st_ctime = us->st_ctime;
  861. st->st_mtime = us->st_mtime;
  862. st->st_gid = us->st_gid;
  863. st->st_ino = getino(us);
  864. st->st_mode = us->st_mode;
  865. st->st_nlink = us->st_nlink;
  866. st->st_size = us->st_size;
  867. st->st_uid = us->st_uid;
  868. st->st_dev = us->st_dev;
  869. st->st_rdev = us->st_rdev;
  870. }
  871. int
  872. la_fstat(int fd, struct stat *st)
  873. {
  874. struct ustat u;
  875. int ret;
  876. if (fd < 0) {
  877. errno = EBADF;
  878. return (-1);
  879. }
  880. ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
  881. if (ret >= 0) {
  882. copy_stat(st, &u);
  883. if (u.st_mode & (S_IFCHR | S_IFIFO)) {
  884. st->st_dev = fd;
  885. st->st_rdev = fd;
  886. }
  887. }
  888. return (ret);
  889. }
  890. int
  891. la_stat(const char *path, struct stat *st)
  892. {
  893. HANDLE handle;
  894. struct ustat u;
  895. int ret;
  896. handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
  897. FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
  898. NULL);
  899. if (handle == INVALID_HANDLE_VALUE) {
  900. _dosmaperr(GetLastError());
  901. return (-1);
  902. }
  903. ret = __hstat(handle, &u);
  904. CloseHandle(handle);
  905. if (ret >= 0) {
  906. char *p;
  907. copy_stat(st, &u);
  908. p = strrchr(path, '.');
  909. if (p != NULL && strlen(p) == 4) {
  910. char exttype[4];
  911. ++ p;
  912. exttype[0] = toupper(*p++);
  913. exttype[1] = toupper(*p++);
  914. exttype[2] = toupper(*p++);
  915. exttype[3] = '\0';
  916. if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
  917. !strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
  918. st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
  919. }
  920. }
  921. return (ret);
  922. }
  923. int
  924. la_unlink(const char *path)
  925. {
  926. wchar_t *ws;
  927. int r;
  928. r = _unlink(path);
  929. if (r >= 0 || errno != ENOENT)
  930. return (r);
  931. ws = permissive_name(path);
  932. if (ws == NULL) {
  933. errno = EINVAL;
  934. return (-1);
  935. }
  936. r = _wunlink(ws);
  937. free(ws);
  938. return (r);
  939. }
  940. /*
  941. * This waitpid is limited implemention.
  942. */
  943. pid_t
  944. la_waitpid(pid_t wpid, int *status, int option)
  945. {
  946. HANDLE child;
  947. DWORD cs, ret;
  948. (void)option;/* UNUSED */
  949. child = OpenProcess(PROCESS_ALL_ACCESS, FALSE, wpid);
  950. if (child == NULL) {
  951. _dosmaperr(GetLastError());
  952. return (-1);
  953. }
  954. ret = WaitForSingleObject(child, INFINITE);
  955. if (ret == WAIT_FAILED) {
  956. CloseHandle(child);
  957. _dosmaperr(GetLastError());
  958. return (-1);
  959. }
  960. if (GetExitCodeProcess(child, &cs) == 0) {
  961. CloseHandle(child);
  962. _dosmaperr(GetLastError());
  963. return (-1);
  964. }
  965. if (cs == STILL_ACTIVE)
  966. *status = 0x100;
  967. else
  968. *status = (int)(cs & 0xff);
  969. CloseHandle(child);
  970. return (wpid);
  971. }
  972. ssize_t
  973. la_write(int fd, const void *buf, size_t nbytes)
  974. {
  975. uint32_t bytes_written;
  976. #ifdef _WIN64
  977. if (nbytes > UINT32_MAX)
  978. nbytes = UINT32_MAX;
  979. #endif
  980. if (fd < 0) {
  981. errno = EBADF;
  982. return (-1);
  983. }
  984. if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,
  985. &bytes_written, NULL)) {
  986. DWORD lasterr;
  987. lasterr = GetLastError();
  988. if (lasterr == ERROR_ACCESS_DENIED)
  989. errno = EBADF;
  990. else
  991. _dosmaperr(lasterr);
  992. return (-1);
  993. }
  994. return (bytes_written);
  995. }
  996. #if !defined(HAVE_OPENSSL_MD5_H) && !defined(HAVE_OPENSSL_SHA_H)
  997. /*
  998. * Message digest functions.
  999. */
  1000. static void
  1001. Digest_Init(Digest_CTX *ctx, ALG_ID algId)
  1002. {
  1003. ctx->valid = 0;
  1004. if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
  1005. PROV_RSA_FULL, 0)) {
  1006. if (GetLastError() != NTE_BAD_KEYSET)
  1007. return;
  1008. if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
  1009. PROV_RSA_FULL, CRYPT_NEWKEYSET))
  1010. return;
  1011. }
  1012. if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
  1013. CryptReleaseContext(ctx->cryptProv, 0);
  1014. return;
  1015. }
  1016. ctx->valid = 1;
  1017. }
  1018. static void
  1019. Digest_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
  1020. {
  1021. if (!ctx->valid)
  1022. return;
  1023. CryptHashData(ctx->hash, buf, (DWORD)len, 0);
  1024. }
  1025. static void
  1026. Digest_Final(unsigned char *buf, int bufsize, Digest_CTX *ctx)
  1027. {
  1028. DWORD siglen = bufsize;
  1029. if (!ctx->valid)
  1030. return;
  1031. CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
  1032. CryptDestroyHash(ctx->hash);
  1033. CryptReleaseContext(ctx->cryptProv, 0);
  1034. ctx->valid = 0;
  1035. }
  1036. #define DIGEST_INIT(name, algid) \
  1037. void name ## _Init(Digest_CTX *ctx)\
  1038. {\
  1039. Digest_Init(ctx, algid);\
  1040. }
  1041. #define DIGEST_UPDATE(name) \
  1042. void name ## _Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)\
  1043. {\
  1044. Digest_Update(ctx, buf, len);\
  1045. }
  1046. #define DIGEST_FINAL(name, size) \
  1047. void name ## _Final(unsigned char buf[size], Digest_CTX *ctx)\
  1048. {\
  1049. Digest_Final(buf, size, ctx);\
  1050. }
  1051. DIGEST_INIT(MD5, CALG_MD5)
  1052. DIGEST_UPDATE(MD5)
  1053. DIGEST_FINAL(MD5, MD5_DIGEST_LENGTH)
  1054. DIGEST_INIT(SHA1, CALG_SHA1)
  1055. DIGEST_UPDATE(SHA1)
  1056. DIGEST_FINAL(SHA1, SHA1_DIGEST_LENGTH)
  1057. /*
  1058. * SHA256 nor SHA384 nor SHA512 are not supported on Windows XP and Windows 2000.
  1059. */
  1060. #ifdef CALG_SHA256
  1061. DIGEST_INIT(SHA256, CALG_SHA256)
  1062. DIGEST_UPDATE(SHA256)
  1063. DIGEST_FINAL(SHA256, SHA256_DIGEST_LENGTH)
  1064. #endif
  1065. #ifdef CALG_SHA384
  1066. DIGEST_INIT(SHA384, CALG_SHA384)
  1067. DIGEST_UPDATE(SHA384)
  1068. DIGEST_FINAL(SHA384, SHA384_DIGEST_LENGTH)
  1069. #endif
  1070. #ifdef CALG_SHA512
  1071. DIGEST_INIT(SHA512, CALG_SHA512)
  1072. DIGEST_UPDATE(SHA512)
  1073. DIGEST_FINAL(SHA512, SHA384_DIGEST_LENGTH)
  1074. #endif
  1075. #endif /* !HAVE_OPENSSL_MD5_H && !HAVE_OPENSSL_SHA_H */
  1076. #endif /* _WIN32 && !__CYGWIN__ */