From: Michihiro NAKAJIMA Date: Tue, 25 Jan 2011 22:36:17 +0000 (-0500) Subject: Properly restore birthtime on Windows; use W32API directly in X-Git-Tag: v3.0.0a~714 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab4968f13fa5014525b178fafda3c266dc579807;p=thirdparty%2Flibarchive.git Properly restore birthtime on Windows; use W32API directly in archive_write_disk.c and remove __la_futimes()/__la_utimes() functions and related definitions, which were used in archive_write_disk.c only. SVN-Revision: 2948 --- diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c index 30218d95c..6f5d07b81 100644 --- a/libarchive/archive_read_disk_windows.c +++ b/libarchive/archive_read_disk_windows.c @@ -1180,89 +1180,6 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path, } } -/* - * Prepend "\\?\" to the path name and convert it to unicode to permit - * an extended-length path for a maximum total path length of 32767 - * characters. - * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx - */ -static wchar_t * -permissive_name(const wchar_t *name) -{ - wchar_t *wn, *wnp; - wchar_t *ws, *wsp; - DWORD l, len, slen; - int unc; - - /* Get a full path names */ - l = GetFullPathNameW(name, 0, NULL, NULL); - if (l == 0) - return (NULL); - wnp = malloc(l * sizeof(wchar_t)); - if (wnp == NULL) - return (NULL); - len = GetFullPathNameW(name, l, wnp, NULL); - wn = wnp; - - if (wnp[0] == L'\\' && wnp[1] == L'\\' && - wnp[2] == L'?' && wnp[3] == L'\\') - /* We have already permissive names. */ - return (wn); - - if (wnp[0] == L'\\' && wnp[1] == L'\\' && - wnp[2] == L'.' && wnp[3] == L'\\') { - /* Device names */ - if (((wnp[4] >= L'a' && wnp[4] <= L'z') || - (wnp[4] >= L'A' && wnp[4] <= L'Z')) && - wnp[5] == L':' && wnp[6] == L'\\') - wnp[2] = L'?';/* Not device names. */ - return (wn); - } - - unc = 0; - if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { - wchar_t *p = &wnp[2]; - - /* Skip server-name letters. */ - while (*p != L'\\' && *p != L'\0') - ++p; - if (*p == L'\\') { - wchar_t *rp = ++p; - /* Skip share-name letters. */ - while (*p != L'\\' && *p != L'\0') - ++p; - if (*p == L'\\' && p != rp) { - /* Now, match patterns such as - * "\\server-name\share-name\" */ - wnp += 2; - len -= 2; - unc = 1; - } - } - } - - slen = 4 + (unc * 4) + len + 1; - ws = wsp = malloc(slen * sizeof(wchar_t)); - if (ws == NULL) { - free(wn); - return (NULL); - } - /* prepend "\\?\" */ - wcsncpy(wsp, L"\\\\?\\", 4); - wsp += 4; - slen -= 4; - if (unc) { - /* append "UNC\" ---> "\\?\UNC\" */ - wcsncpy(wsp, L"UNC\\", 4); - wsp += 4; - slen -= 4; - } - wcsncpy(wsp, wnp, slen); - wsp[slen - 1] = L'\0'; /* Ensure null termination. */ - free(wn); - return (ws); -} - /* * Append a name to the current dir path. */ @@ -1353,7 +1270,7 @@ tree_reopen(struct tree *t, const char *path, int restore_time) } base = pathname; - p = permissive_name(base); + p = __la_win_permissive_name(path); if (p == NULL) { free(pathname); goto failed; @@ -1761,14 +1678,6 @@ tree_target_is_same_as_parent(struct tree *t, static const wchar_t * tree_current_access_path(struct tree *t) { -#if defined(_DEBUG) - wchar_t *wp; - - wp = permissive_name(t->path.s); - if (wcscmp(wp, t->full_path.s) != 0) - DebugBreak(); - free(wp); -#endif return (t->full_path.s); } diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 5c724bb47..f613b1746 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -122,8 +122,8 @@ getino(struct ustat *ub) * characters. * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx */ -static wchar_t * -permissive_name(const char *name) +wchar_t * +__la_win_permissive_name(const char *name) { wchar_t *wn, *wnp; wchar_t *ws, *wsp; @@ -230,7 +230,7 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, return (handle); if (GetLastError() != ERROR_PATH_NOT_FOUND) return (handle); - wpath = permissive_name(path); + wpath = __la_win_permissive_name(path); if (wpath == NULL) return (handle); handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, @@ -282,8 +282,8 @@ __link(const char *src, const char *dst) return -1; } - wsrc = permissive_name(src); - wdst = permissive_name(dst); + wsrc = __la_win_permissive_name(src); + wdst = __la_win_permissive_name(dst); if (wsrc == NULL || wdst == NULL) { free(wsrc); free(wdst); @@ -396,51 +396,6 @@ __la_ftruncate(int fd, int64_t length) return (0); } -#define WINTIME(sec, usec) ((Int32x32To64(sec, 10000000) + EPOC_TIME) + (usec * 10)) -static int -__hutimes(HANDLE handle, const struct __timeval *times) -{ - ULARGE_INTEGER wintm; - FILETIME fatime, fmtime; - - wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec); - fatime.dwLowDateTime = wintm.LowPart; - fatime.dwHighDateTime = wintm.HighPart; - wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec); - fmtime.dwLowDateTime = wintm.LowPart; - fmtime.dwHighDateTime = wintm.HighPart; - if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) { - errno = EINVAL; - return (-1); - } - return (0); -} - -int -__la_futimes(int fd, const struct __timeval *times) -{ - - return (__hutimes((HANDLE)_get_osfhandle(fd), times)); -} - -int -__la_utimes(const char *name, const struct __timeval *times) -{ - int ret; - HANDLE handle; - - handle = la_CreateFile(name, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (handle == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - return (-1); - } - ret = __hutimes(handle, times); - CloseHandle(handle); - return (ret); -} - int __la_chdir(const char *path) { @@ -455,7 +410,7 @@ __la_chdir(const char *path) } } else return (0); - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -483,7 +438,7 @@ __la_chmod(const char *path, mode_t mode) la_dosmaperr(GetLastError()); return (-1); } - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -582,7 +537,7 @@ __la_mkdir(const char *path, mode_t mode) } } else return (0); - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -629,7 +584,7 @@ __la_open(const char *path, int flags, ...) */ attr = GetFileAttributesA(path); if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) { - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -686,7 +641,7 @@ __la_open(const char *path, int flags, ...) } if (r >= 0 || errno != ENOENT) return (r); - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -768,7 +723,7 @@ __la_rmdir(const char *path) r = _rmdir(path); if (r >= 0 || errno != ENOENT) return (r); - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -987,7 +942,7 @@ __la_unlink(const char *path) r = _unlink(path); if (r >= 0 || errno != ENOENT) return (r); - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -1300,7 +1255,7 @@ __archive_mktemp(const char *tmpdir) la_dosmaperr(GetLastError()); goto exit_tmpfile; } - ws = permissive_name(temp_name.s); + ws = __la_win_permissive_name(temp_name.s); if (ws == NULL) { errno = EINVAL; goto exit_tmpfile; @@ -1344,7 +1299,7 @@ __archive_mktemp(const char *tmpdir) *p = num[*p % sizeof(num)]; free(ws); - ws = permissive_name(temp_name.s); + ws = __la_win_permissive_name(temp_name.s); if (ws == NULL) { errno = EINVAL; goto exit_tmpfile; diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index b3f4f9781..068cdaa5e 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -98,7 +98,6 @@ #endif #define fstat __la_fstat #define ftruncate __la_ftruncate -#define futimes __la_futimes #define link __la_link #define lseek __la_lseek #define lstat __la_stat @@ -119,7 +118,6 @@ #define umask _umask #endif #define unlink __la_unlink -#define utimes __la_utimes #define waitpid __la_waitpid #define write __la_write @@ -280,29 +278,12 @@ #endif /* __MINGW32__ */ #endif /* LARGE_FILES */ -#ifdef USE_WINSOCK_TIMEVAL -/* Winsock timeval has long size tv_sec. */ -#define __timeval timeval -#else -struct _timeval64i32 { - time_t tv_sec; - long tv_usec; -}; -#define __timeval _timeval64i32 -#endif - /* End of Win32 definitions. */ /* Tell libarchive code that we have simulations for these. */ #ifndef HAVE_FTRUNCATE #define HAVE_FTRUNCATE 1 #endif -#ifndef HAVE_FUTIMES -#define HAVE_FUTIMES 1 -#endif -#ifndef HAVE_UTIMES -#define HAVE_UTIMES 1 -#endif #ifndef HAVE_LINK #define HAVE_LINK 1 #endif @@ -313,7 +294,6 @@ extern int __la_chmod(const char *path, mode_t mode); extern int __la_fcntl(int fd, int cmd, int val); extern int __la_fstat(int fd, struct stat *st); extern int __la_ftruncate(int fd, int64_t length); -extern int __la_futimes(int fd, const struct __timeval *times); extern int __la_link(const char *src, const char *dst); extern __int64 __la_lseek(int fd, __int64 offset, int whence); extern int __la_lstat(const char *path, struct stat *st); @@ -325,7 +305,6 @@ extern ssize_t __la_read(int fd, void *buf, size_t nbytes); extern int __la_rmdir(const char *path); extern int __la_stat(const char *path, struct stat *st); extern int __la_unlink(const char *path); -extern int __la_utimes(const char *name, const struct __timeval *times); extern pid_t __la_waitpid(pid_t wpid, int *status, int option); extern ssize_t __la_write(int fd, const void *buf, size_t nbytes); @@ -335,4 +314,6 @@ extern ssize_t __la_write(int fd, const void *buf, size_t nbytes); #define WIFEXITED(sts) ((sts & 0x100) == 0) #define WEXITSTATUS(sts) (sts & 0x0FF) +extern wchar_t *__la_win_permissive_name(const char *name); + #endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */ diff --git a/libarchive/archive_write_disk.c b/libarchive/archive_write_disk.c index 7115a4a66..8bc7c7d73 100644 --- a/libarchive/archive_write_disk.c +++ b/libarchive/archive_write_disk.c @@ -278,7 +278,9 @@ static int set_fflags_platform(struct archive_write_disk *, int fd, unsigned long fflags_set, unsigned long fflags_clear); static int set_ownership(struct archive_write_disk *); static int set_mode(struct archive_write_disk *, int mode); +#if !defined(_WIN32) || defined(__CYGWIN__) static int set_time(int, int, const char *, time_t, long, time_t, long); +#endif static int set_times(struct archive_write_disk *, int, int, const char *, time_t, long, time_t, long, time_t, long); static int set_times_from_entry(struct archive_write_disk *); @@ -1976,6 +1978,73 @@ set_ownership(struct archive_write_disk *a) return (ARCHIVE_WARN); } +#if defined(_WIN32) && !defined(__CYGWIN__) + +static int +set_times(struct archive_write_disk *a, + int fd, int mode, const char *name, + time_t atime, long atime_nanos, + time_t birthtime, long birthtime_nanos, + time_t mtime, long mtime_nanos) +{ +#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) +#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ + + (((nsec)/1000)*10)) + + HANDLE h, hw; + ULARGE_INTEGER wintm; + wchar_t *ws; + FILETIME *pfbtime; + FILETIME fatime, fbtime, fmtime; + + if (fd >= 0) { + h = (HANDLE)_get_osfhandle(fd); + hw = NULL; + ws = NULL; + } else { + if (S_ISLNK(mode)) + return (ARCHIVE_OK); + ws = __la_win_permissive_name(name); + if (ws == NULL) + goto settimes_failed; + hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES, + 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hw == INVALID_HANDLE_VALUE) + goto settimes_failed; + h = hw; + } + + wintm.QuadPart = WINTIME(atime, atime_nanos); + fatime.dwLowDateTime = wintm.LowPart; + fatime.dwHighDateTime = wintm.HighPart; + wintm.QuadPart = WINTIME(mtime, mtime_nanos); + fmtime.dwLowDateTime = wintm.LowPart; + fmtime.dwHighDateTime = wintm.HighPart; + /* + * SetFileTime() supports birthtime. + */ + if (birthtime > 0 || birthtime_nanos > 0) { + wintm.QuadPart = WINTIME(birthtime, birthtime_nanos); + fbtime.dwLowDateTime = wintm.LowPart; + fbtime.dwHighDateTime = wintm.HighPart; + pfbtime = &fbtime; + } else + pfbtime = NULL; + if (SetFileTime(h, pfbtime, &fatime, &fmtime) == 0) + goto settimes_failed; + free(ws); + CloseHandle(hw); + return (ARCHIVE_OK); + +settimes_failed: + free(ws); + CloseHandle(hw); + archive_set_error(&a->archive, EINVAL, "Can't restore time"); + return (ARCHIVE_WARN); +} + +#else /* defined(_WIN32) && !defined(__CYGWIN__) */ + /* * Note: Returns 0 on success, non-zero on failure. */ @@ -2007,11 +2076,7 @@ set_time(int fd, int mode, const char *name, * LEGACY by POSIX, futimes() and lutimes() are not described * in POSIX. */ -#if defined(_WIN32) && !defined(__CYGWIN__) - struct __timeval times[2]; -#else struct timeval times[2]; -#endif times[0].tv_sec = atime; times[0].tv_usec = atime_nsec / 1000; @@ -2094,6 +2159,8 @@ set_times(struct archive_write_disk *a, return (ARCHIVE_OK); } +#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ + static int set_times_from_entry(struct archive_write_disk *a) {