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