]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Revert r838,r839 and r840.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 25 Mar 2009 09:14:53 +0000 (05:14 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 25 Mar 2009 09:14:53 +0000 (05:14 -0400)
SVN-Revision: 842

16 files changed:
CMakeLists.txt
Makefile.am
cpio/CMakeLists.txt
cpio/cpio_cygwin.c
cpio/cpio_windows.c
cpio/cpio_windows.h
cpio/test/CMakeLists.txt
libarchive/CMakeLists.txt
libarchive/archive_windows.c
libarchive/archive_windows.h
libarchive/test/CMakeLists.txt
tar/CMakeLists.txt
tar/bsdtar_cygwin.c
tar/bsdtar_windows.c
tar/bsdtar_windows.h
tar/test/CMakeLists.txt

index 8b6ffa86eedc80cfc084ac5fc5bbf1013c4254ea..646f4f44c5ff9cf4dd9e907feeb2a894d785309d 100644 (file)
@@ -39,6 +39,11 @@ OPTION(ENABLE_TEST "Enable unit and regression tests" ON)
 IF(ENABLE_TEST)
        ENABLE_TESTING()
 ENDIF(ENABLE_TEST)
+IF(WIN32 AND NOT CYGWIN)
+  # Currently, dynamic build only.
+  SET(ENABLE_TAR_SHARED ON)
+  SET(ENABLE_CPIO_SHARED ON)
+ENDIF(WIN32 AND NOT CYGWIN)
 
 #
 INCLUDE(CheckFileOffsetBits)
index a6fecb6c109534492d7bf878230c84bd0d8234e6..4cde47ea37495ec136c7ed926b0a9ef777303ec7 100644 (file)
@@ -342,8 +342,7 @@ bsdtar_SOURCES=                             \
 if INC_WINDOWS_FILES
 bsdtar_SOURCES+=                       \
                tar/bsdtar_windows.h    \
-               tar/bsdtar_windows.c    \
-               libarchive/archive_windows.c
+               tar/bsdtar_windows.c
 endif
 if INC_CYGWIN_FILES
 bsdtar_SOURCES+=                       \
@@ -446,8 +445,7 @@ bsdcpio_SOURCES=                    \
 if INC_WINDOWS_FILES
 bsdcpio_SOURCES+=                      \
                cpio/cpio_windows.h     \
-               cpio/cpio_windows.c     \
-               libarchive/archive_windows.c
+               cpio/cpio_windows.c
 endif
 if INC_CYGWIN_FILES
 bsdcpio_SOURCES+=                      \
index fe5b13f2ef350e33c1de5750c5d667a5d8af5b7b..4744ba142506a304b7f3fb36e43b00fb8893dccf 100644 (file)
@@ -26,15 +26,10 @@ IF(ENABLE_CPIO)
   # Register target
   #
   ADD_EXECUTABLE(bsdcpio ${bsdcpio_SOURCES})
-  IF(WIN32 AND NOT CYGWIN)
-    ADD_DEPENDENCIES(bsdcpio archive_windows_static)
-  ENDIF(WIN32 AND NOT CYGWIN)
   IF(ENABLE_CPIO_SHARED)
     TARGET_LINK_LIBRARIES(bsdcpio archive ${ADDITIONAL_LIBS})
   ELSE(ENABLE_CPIO_SHARED)
     TARGET_LINK_LIBRARIES(bsdcpio archive_static ${ADDITIONAL_LIBS})
-    SET_TARGET_PROPERTIES(bsdcpio PROPERTIES COMPILE_DEFINITIONS
-      LIBARCHIVE_STATIC)
   ENDIF(ENABLE_CPIO_SHARED)
   IF(WIN32 AND NOT CYGWIN)
     SET_TARGET_PROPERTIES(bsdcpio PROPERTIES
index 2c8d072bc3309c557485de06c9957361fa080636..f2157c55f85c62e7d3d6214143e87e50123adee8 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "cpio.h"
 
+#ifndef LIST_H
 static int
 _is_privileged(HANDLE thandle, const char *sidlist[])
 {
@@ -133,4 +134,6 @@ bsdcpio_is_privileged()
        return (ret);
 }
 
+#endif /* LIST_H */
+
 #endif
index 25c680de262bdd459c6b323f03c574c4394a0824..ea67d9867fc9cc08a2c45b78651f3ee844c5e3a4 100644 (file)
 
 #include "cpio.h"
 
+#define EPOC_TIME      (116444736000000000ULL)
+
+struct ustat {
+       int64_t         st_atime;
+       uint32_t        st_atime_nsec;
+       int64_t         st_ctime;
+       uint32_t        st_ctime_nsec;
+       int64_t         st_mtime;
+       uint32_t        st_mtime_nsec;
+       gid_t           st_gid;
+       /* 64bits ino */
+       int64_t         st_ino;
+       mode_t          st_mode;
+       uint32_t        st_nlink;
+       uint64_t        st_size;
+       uid_t           st_uid;
+       dev_t           st_dev;
+       dev_t           st_rdev;
+};
+
+/* Transform 64-bits ino into 32-bits by hashing.
+ * You do not forget that really unique number size is 64-bits.
+ */
+#define INOSIZE (8*sizeof(ino_t)) /* 32 */
+static __inline ino_t
+getino(struct ustat *ub)
+{
+       ULARGE_INTEGER ino64;
+
+       ino64.QuadPart = ub->st_ino;
+       /* I don't know this hashing is correct way */
+       return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE));
+}
+
+/*
+ * 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 char *name)
+{
+       wchar_t *wn, *wnp;
+       wchar_t *ws, *wsp;
+       size_t l, len, slen;
+       int unc;
+
+       len = strlen(name);
+       wn = malloc((len + 1) * sizeof(wchar_t));
+       if (wn == NULL)
+               return (NULL);
+       l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
+       if (l == 0) {
+               free(wn);
+               return (NULL);
+       }
+       wn[l] = L'\0';
+
+       /* Get a full path names */
+       l = GetFullPathNameW(wn, 0, NULL, NULL);
+       if (l == 0) {
+               free(wn);
+               return (NULL);
+       }
+       wnp = malloc(l * sizeof(wchar_t));
+       if (wnp == NULL) {
+               free(wn);
+               return (NULL);
+       }
+       len = GetFullPathNameW(wn, l, wnp, NULL);
+       free(wn);
+       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_s(wsp, slen, wnp, _TRUNCATE);
+       free(wn);
+       return (ws);
+}
+
+static HANDLE
+la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
+    LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
+    DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
+{
+       wchar_t *wpath;
+       HANDLE handle;
+
+       handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
+           lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
+           hTemplateFile);
+       if (handle != INVALID_HANDLE_VALUE)
+               return (handle);
+       if (GetLastError() != ERROR_PATH_NOT_FOUND)
+               return (handle);
+       wpath = permissive_name(path);
+       if (wpath == NULL)
+               return (handle);
+       handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
+           lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
+           hTemplateFile);
+       free(wpath);
+       return (handle);
+}
+
+static size_t
+wequallen(const wchar_t *s1, const wchar_t *s2)
+{
+       size_t i = 0;
+
+       while (*s1 != L'\0' && *s2 != L'\0' && *s1 == *s2) {
+               ++s1; ++s2; ++i;
+       }
+       return (i);
+}
+
+/* Check that path1 and path2 can be hard-linked by each other.
+ * Both arguments must be made by permissive_name function. 
+ */
+static int
+canHardLinkW(const wchar_t *path1, const wchar_t *path2)
+{
+       wchar_t root[MAX_PATH];
+       wchar_t fs[32];
+       const wchar_t *s;
+       int r;
+
+       r = wequallen(path1, path2);
+       /* Is volume-name the same? */
+       if (r < 7)
+               return (0);
+       if (wcsncmp(path1, L"\\\\?\\UNC\\", 8) == 0) {
+               int len;
+
+               s = path1 + 8;
+               if (*s == L'\\')
+                       return (0);
+               /*         012345678
+                * Name : "\\?\UNC\Server\Share\"
+                *                       ^ search
+                */
+               s = wcschr(++s, L'\\');
+               if (s == NULL)
+                       return (0);
+               if (*++s == L'\\')
+                       return (0);
+               /*         012345678
+                * Name : "\\?\UNC\Server\Share\"
+                *                             ^ search
+                */
+               s = wcschr(++s, L'\\');
+               if (s == NULL)
+                       return (0);
+               s++;
+               /*         012345678
+                * Name : "\\?\UNC\Server\Share\xxxx"
+                *                 ^--- len ----^
+                */
+               len = (int)(s - path1 - 8);
+               /* Is volume-name the same? */
+               if (r < len + 8)
+                       return (0);
+               /* Is volume-name too long? */
+               if (sizeof(root) -3 < len)
+                       return (0);
+               root[0] = root[1] = L'\\';
+               wcsncpy(root + 2, path1 + 8 , len);
+               /* root : "\\Server\Share\" */
+               root[2 + len] = L'\0';
+       } else if (wcsncmp(path1, L"\\\\?\\", 4) == 0) {
+               s = path1 + 4;
+               if ((!iswalpha(*s)) || s[1] != L':' || s[2] != L'\\')
+                       return (0);
+               wcsncpy(root, path1 + 4, 3);
+               root[3] = L'\0';
+       } else
+               return (0);
+       if (!GetVolumeInformationW(root, NULL, 0, NULL, NULL, NULL, fs, sizeof(fs)))
+               return (0);
+       if (wcscmp(fs, L"NTFS") == 0)
+               return (1);
+       else
+               return (0);
+}
+
+/* Make a link to src called dst.  */
+static int
+__link(const char *src, const char *dst, int sym)
+{
+       wchar_t *wsrc, *wdst;
+       int res, retval;
+       DWORD attr;
+
+       if (src == NULL || dst == NULL) {
+               set_errno (EINVAL);
+               return -1;
+       }
+
+       wsrc = permissive_name(src);
+       wdst = permissive_name(dst);
+       if (wsrc == NULL || wdst == NULL) {
+               if (wsrc != NULL)
+                       free(wsrc);
+               if (wdst != NULL)
+                       free(wdst);
+               set_errno (EINVAL);
+               return -1;
+       }
+
+       if ((attr = GetFileAttributesW(wsrc)) != -1) {
+               if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+                       errno = EPERM;
+                       retval = -1;
+                       goto exit;
+               }
+               if (!sym && canHardLinkW(wsrc, wdst))
+                       res = CreateHardLinkW(wdst, wsrc, NULL);
+               else
+                       res = CopyFileW(wsrc, wdst, FALSE);
+       } else {
+               /* wsrc does not exist; try src prepend it with the dirname of wdst */
+               wchar_t *wnewsrc, *slash;
+               int i, n, slen, wlen;
+
+               if (strlen(src) >= 3 && isalpha((unsigned char )src[0]) &&
+                   src[1] == ':' && src[2] == '\\') {
+                       /* Original src name is already full-path */
+                       retval = -1;
+                       goto exit;
+               }
+               if (src[0] == '\\') {
+                       /* Original src name is almost full-path
+                        * (maybe src name is without drive) */
+                       retval = -1;
+                       goto exit;
+               }
+
+               wnewsrc = malloc ((wcslen(wsrc) + wcslen(wdst) + 1) * sizeof(wchar_t));
+               if (wnewsrc == NULL) {
+                       errno = ENOMEM;
+                       retval = -1;
+                       goto exit;
+               }
+               /* Copying a dirname of wdst */
+               wcscpy(wnewsrc, wdst);
+               slash = wcsrchr(wnewsrc, L'\\');
+               if (slash != NULL)
+                       *++slash = L'\0';
+               else
+                       wcscat(wnewsrc, L"\\");
+               /* Converting multi-byte src to wide-char src */
+               wlen = wcslen(wsrc);
+               slen = strlen(src);
+               n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, slen);
+               if (n == 0) {
+                       free (wnewsrc);
+                       retval = -1;
+                       goto exit;
+               }
+               for (i = 0; i < n; i++)
+                       if (wsrc[i] == L'/')
+                               wsrc[i] = L'\\';
+               wcsncat(wnewsrc, wsrc, n);
+               /* Check again */
+               attr = GetFileAttributesW(wnewsrc);
+               if (attr == -1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+                       if (attr == -1)
+                               _dosmaperr(GetLastError());
+                       else
+                               errno = EPERM;
+                       free (wnewsrc);
+                       retval = -1;
+                       goto exit;
+               }
+               if (!sym && canHardLinkW(wnewsrc, wdst))
+                       res = CreateHardLinkW(wdst, wnewsrc, NULL);
+               else
+                       res = CopyFileW(wnewsrc, wdst, FALSE);
+               free (wnewsrc);
+       }
+       if (res == 0) {
+               _dosmaperr(GetLastError());
+               retval = -1;
+       } else
+               retval = 0;
+exit:
+       free(wsrc);
+       free(wdst);
+       return (retval);
+}
+
+/* Make a hard link to src called dst.  */
+int
+link(const char *src, const char *dst)
+{
+       return __link (src, dst, 0);
+}
+
+/* Make a symbolic link to FROM called TO.  */
+int symlink (from, to)
+     const char *from;
+     const char *to;
+{
+       return __link (from, to, 1);
+}
+
+unsigned int
+sleep(unsigned int seconds)
+{
+       Sleep(seconds * 1000);
+       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
+futimes(int fd, const struct __timeval *times)
+{
+
+       return (__hutimes((HANDLE)_get_osfhandle(fd), times));
+}
+
+int
+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) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       ret = __hutimes(handle, times);
+       CloseHandle(handle);
+       return (ret);
+}
+
+int
+la_chdir(const char *path)
+{
+       wchar_t *ws;
+       int r;
+
+       r = SetCurrentDirectoryA(path);
+       if (r == 0) {
+               if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+                       _dosmaperr(GetLastError());
+                       return (-1);
+               }
+       } else
+               return (0);
+       ws = permissive_name(path);
+       if (ws == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       r = SetCurrentDirectoryW(ws);
+       free(ws);
+       if (r == 0) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       return (0);
+}
+
+int
+la_mkdir(const char *path, mode_t mode)
+{
+       wchar_t *ws;
+       int r;
+
+       (void)mode;/* UNUSED */
+       r = CreateDirectoryA(path, NULL);
+       if (r == 0) {
+               DWORD lasterr = GetLastError();
+               if (lasterr != ERROR_FILENAME_EXCED_RANGE &&
+                       lasterr != ERROR_PATH_NOT_FOUND) {
+                       _dosmaperr(GetLastError());
+                       return (-1);
+               }
+       } else
+               return (0);
+       ws = permissive_name(path);
+       if (ws == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       r = CreateDirectoryW(ws, NULL);
+       free(ws);
+       if (r == 0) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       return (0);
+}
+
+int
+la_open(const char *path, int flags, ...)
+{
+       va_list ap;
+       wchar_t *ws;
+       int r, pmode;
+       DWORD attr;
+
+       va_start(ap, flags);
+       pmode = va_arg(ap, int);
+       va_end(ap);
+       ws = NULL;
+       if ((flags & ~O_BINARY) == O_RDONLY) {
+               /*
+                * When we open a directory, _open function returns 
+                * "Permission denied" error.
+                */
+               attr = GetFileAttributesA(path);
+               if (attr == -1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
+                       ws = permissive_name(path);
+                       if (ws == NULL) {
+                               errno = EINVAL;
+                               return (-1);
+                       }
+                       attr = GetFileAttributesW(ws);
+               }
+               if (attr == -1) {
+                       _dosmaperr(GetLastError());
+                       free(ws);
+                       return (-1);
+               }
+               if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+                       HANDLE handle;
+
+                       if (ws != NULL)
+                               handle = CreateFileW(ws, 0, 0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS |
+                                   FILE_ATTRIBUTE_READONLY,
+                                       NULL);
+                       else
+                               handle = CreateFileA(path, 0, 0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS |
+                                   FILE_ATTRIBUTE_READONLY,
+                                       NULL);
+                       free(ws);
+                       if (handle == INVALID_HANDLE_VALUE) {
+                               _dosmaperr(GetLastError());
+                               return (-1);
+                       }
+                       r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
+                       return (r);
+               }
+       }
+       if (ws == NULL) {
+               r = _open(path, flags, pmode);
+               if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
+                       /* simular other POSIX system action to pass a test */
+                       attr = GetFileAttributesA(path);
+                       if (attr == -1)
+                               _dosmaperr(GetLastError());
+                       else if (attr & FILE_ATTRIBUTE_DIRECTORY)
+                               errno = EISDIR;
+                       else
+                               errno = EACCES;
+                       return (-1);
+               }
+               if (r >= 0 || errno != ENOENT)
+                       return (r);
+               ws = permissive_name(path);
+               if (ws == NULL) {
+                       errno = EINVAL;
+                       return (-1);
+               }
+       }
+       r = _wopen(ws, flags, pmode);
+       if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
+               /* simular other POSIX system action to pass a test */
+               attr = GetFileAttributesW(ws);
+               if (attr == -1)
+                       _dosmaperr(GetLastError());
+               else if (attr & FILE_ATTRIBUTE_DIRECTORY)
+                       errno = EISDIR;
+               else
+                       errno = EACCES;
+       }
+       free(ws);
+       return (r);
+}
+
+ssize_t
+la_read(int fd, void *buf, size_t nbytes)
+{
+       HANDLE handle;
+       DWORD bytes_read, lasterr;
+       int r;
+
+#ifdef _WIN64
+       if (nbytes > UINT32_MAX)
+               nbytes = UINT32_MAX;
+#endif
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       handle = (HANDLE)_get_osfhandle(fd);
+       if (GetFileType(handle) == FILE_TYPE_PIPE) {
+               DWORD sta;
+               if (GetNamedPipeHandleState(
+                   handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 &&
+                   (sta & PIPE_NOWAIT) == 0) {
+                       DWORD avail = -1;
+                       int cnt = 3;
+
+                       while (PeekNamedPipe(
+                           handle, NULL, 0, NULL, &avail, NULL) != 0 &&
+                           avail == 0 && --cnt)
+                               Sleep(100);
+                       if (avail == 0)
+                               return (0);
+               }
+       }
+       r = ReadFile(handle, buf, (uint32_t)nbytes,
+           &bytes_read, NULL);
+       if (r == 0) {
+               lasterr = GetLastError();
+               if (lasterr == ERROR_NO_DATA) {
+                       errno = EAGAIN;
+                       return (-1);
+               }
+               if (lasterr == ERROR_BROKEN_PIPE)
+                       return (0);
+               if (lasterr == ERROR_ACCESS_DENIED)
+                       errno = EBADF;
+               else
+                       _dosmaperr(lasterr);
+               return (-1);
+       }
+       return ((ssize_t)bytes_read);
+}
+
+/* Remove directory */
+int
+la_rmdir(const char *path)
+{
+       wchar_t *ws;
+       int r;
+
+       r = _rmdir(path);
+       if (r >= 0 || errno != ENOENT)
+               return (r);
+       ws = permissive_name(path);
+       if (ws == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       r = _wrmdir(ws);
+       free(ws);
+       return (r);
+}
+
+/* Convert Windows FILETIME to UTC */
+__inline static void
+fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
+{
+       ULARGE_INTEGER utc;
+
+       utc.HighPart = filetime->dwHighDateTime;
+       utc.LowPart  = filetime->dwLowDateTime;
+       if (utc.QuadPart >= EPOC_TIME) {
+               utc.QuadPart -= EPOC_TIME;
+               *time = (time_t)(utc.QuadPart / 10000000);      /* milli seconds base */
+               *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
+       } else {
+               *time = 0;
+               *ns = 0;
+       }
+}
+
+/* Stat by handle
+ * Windows' stat() does not accept path which is added "\\?\" especially "?"
+ * character.
+ * It means we cannot access a long name path(which is longer than MAX_PATH).
+ * So I've implemented simular Windows' stat() to access the long name path.
+ * And I've added some feature.
+ * 1. set st_ino by nFileIndexHigh and nFileIndexLow of
+ *    BY_HANDLE_FILE_INFORMATION.
+ * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.
+ * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.
+ */
+static int
+__hstat(HANDLE handle, struct ustat *st)
+{
+       BY_HANDLE_FILE_INFORMATION info;
+       ULARGE_INTEGER ino64;
+       DWORD ftype;
+       mode_t mode;
+       time_t time;
+       long ns;
+
+       switch (ftype = GetFileType(handle)) {
+       case FILE_TYPE_UNKNOWN:
+               errno = EBADF;
+               return (-1);
+       case FILE_TYPE_CHAR:
+       case FILE_TYPE_PIPE:
+               if (ftype == FILE_TYPE_CHAR) {
+                       st->st_mode = S_IFCHR;
+                       st->st_size = 0;
+               } else {
+                       DWORD avail;
+
+                       st->st_mode = S_IFIFO;
+                       if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))
+                               st->st_size = avail;
+                       else
+                               st->st_size = 0;
+               }
+               st->st_atime = 0;
+               st->st_atime_nsec = 0;
+               st->st_mtime = 0;
+               st->st_mtime_nsec = 0;
+               st->st_ctime = 0;
+               st->st_ctime_nsec = 0;
+               st->st_ino = 0;
+               st->st_nlink = 1;
+               st->st_uid = 0;
+               st->st_gid = 0;
+               st->st_rdev = 0;
+               st->st_dev = 0;
+               return (0);
+       case FILE_TYPE_DISK:
+               break;
+       default:
+               /* This ftype is undocumented type. */
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+
+       ZeroMemory(&info, sizeof(info));
+       if (!GetFileInformationByHandle (handle, &info)) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+
+       mode = S_IRUSR | S_IRGRP | S_IROTH;
+       if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
+               mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+       if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+               mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+       else
+               mode |= S_IFREG;
+       st->st_mode = mode;
+       
+       fileTimeToUTC(&info.ftLastAccessTime, &time, &ns);
+       st->st_atime = time; 
+       st->st_atime_nsec = ns;
+       fileTimeToUTC(&info.ftLastWriteTime, &time, &ns);
+       st->st_mtime = time;
+       st->st_mtime_nsec = ns;
+       fileTimeToUTC(&info.ftCreationTime, &time, &ns);
+       st->st_ctime = time;
+       st->st_ctime_nsec = ns;
+       st->st_size = 
+           ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
+               + (int64_t)(info.nFileSizeLow);
+#ifdef SIMULATE_WIN_STAT
+       st->st_ino = 0;
+       st->st_nlink = 1;
+       st->st_dev = 0;
+#else
+       /* Getting FileIndex as i-node. We have to remove a sequence which
+        * is high-16-bits of nFileIndexHigh. */
+       ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;
+       ino64.LowPart  = info.nFileIndexLow;
+       st->st_ino = ino64.QuadPart;
+       st->st_nlink = info.nNumberOfLinks;
+       if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+               ++st->st_nlink;/* Add parent directory. */
+       st->st_dev = info.dwVolumeSerialNumber;
+#endif
+       st->st_uid = 0;
+       st->st_gid = 0;
+       st->st_rdev = 0;
+       return (0);
+}
+
+static void
+copy_stat(struct stat *st, struct ustat *us)
+{
+       st->st_atime = us->st_atime;
+       st->st_ctime = us->st_ctime;
+       st->st_mtime = us->st_mtime;
+       st->st_gid = us->st_gid;
+       st->st_ino = getino(us);
+       st->st_mode = us->st_mode;
+       st->st_nlink = us->st_nlink;
+       st->st_size = us->st_size;
+       st->st_uid = us->st_uid;
+       st->st_dev = us->st_dev;
+       st->st_rdev = us->st_rdev;
+}
+
+int
+la_fstat(int fd, struct stat *st)
+{
+       struct ustat u;
+       int ret;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
+       if (ret >= 0) {
+               copy_stat(st, &u);
+               if (u.st_mode & (S_IFCHR | S_IFIFO)) {
+                       st->st_dev = fd;
+                       st->st_rdev = fd;
+               }
+       }
+       return (ret);
+}
+
+int
+la_stat(const char *path, struct stat *st)
+{
+       HANDLE handle;
+       struct ustat u;
+       int ret;
+
+       handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
+               FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
+               NULL);
+       if (handle == INVALID_HANDLE_VALUE) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       ret = __hstat(handle, &u);
+       CloseHandle(handle);
+       if (ret >= 0) {
+               char *p;
+
+               copy_stat(st, &u);
+               p = strrchr(path, '.');
+               if (p != NULL && strlen(p) == 4) {
+                       char exttype[4];
+
+                       ++ p;
+                       exttype[0] = toupper(*p++);
+                       exttype[1] = toupper(*p++);
+                       exttype[2] = toupper(*p++);
+                       exttype[3] = '\0';
+                       if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
+                               !strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
+                               st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
+               }
+       }
+       return (ret);
+}
+
+ssize_t
+la_write(int fd, const void *buf, size_t nbytes)
+{
+       uint32_t bytes_written;
+
+#ifdef _WIN64
+       if (nbytes > UINT32_MAX)
+               nbytes = UINT32_MAX;
+#endif
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,
+           &bytes_written, NULL)) {
+               DWORD lasterr;
+
+               lasterr = GetLastError();
+               if (lasterr == ERROR_ACCESS_DENIED)
+                       errno = EBADF;
+               else
+                       _dosmaperr(lasterr);
+               return (-1);
+       }
+       return (bytes_written);
+}
+
+#ifndef LIST_H
+static int
+_is_privileged(HANDLE thandle, const char *sidlist[])
+{
+       TOKEN_USER *tuser;
+       TOKEN_GROUPS  *tgrp;
+       DWORD bytes;
+       PSID psid;
+       DWORD i, g;
+       int member;
+
+       psid = NULL;
+       tuser = NULL;
+       tgrp = NULL;
+       member = 0;
+       for (i = 0; sidlist[i] != NULL && member == 0; i++) {
+               if (psid != NULL)
+                       LocalFree(psid);
+               if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) {
+                       errno = EPERM;
+                       return (-1);
+               }
+               if (tuser == NULL) {
+                       GetTokenInformation(thandle, TokenUser, NULL, 0, &bytes);
+                       tuser = malloc(bytes);
+                       if (tuser == NULL) {
+                               errno = ENOMEM;
+                               member = -1;
+                               break;
+                       }
+                       if (GetTokenInformation(thandle, TokenUser, tuser, bytes, &bytes) == 0) {
+                               errno = EPERM;
+                               member = -1;
+                               break;
+                       }
+               }
+               member = EqualSid(tuser->User.Sid, psid);
+               if (member)
+                       break;
+               if (tgrp == NULL) {
+                       GetTokenInformation(thandle, TokenGroups, NULL, 0, &bytes);
+                       tgrp = malloc(bytes);
+                       if (tgrp == NULL) {
+                               errno = ENOMEM;
+                               member = -1;
+                               break;
+                       }
+                       if (GetTokenInformation(thandle, TokenGroups, tgrp, bytes, &bytes) == 0) {
+                               errno = EPERM;
+                               member = -1;
+                               break;
+                       }
+               }
+               for (g = 0; g < tgrp->GroupCount; g++) {
+                       member = EqualSid(tgrp->Groups[g].Sid, psid);
+                       if (member)
+                               break;
+               }
+       }
+       LocalFree(psid);
+       free(tuser);
+       free(tgrp);
+
+       return (member);
+}
+
 int
 bsdcpio_is_privileged()
 {
+       HANDLE thandle;
        int ret;
+       const char *sidlist[] = {
+               "S-1-5-32-544", /* Administrators */
+               "S-1-5-32-551", /* Backup Operators */
+               NULL
+       };
 
-       ret = la_is_privileged();
+       if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) {
+               cpio_warnc(EPERM, "Failed to check privilege");
+               return (0);
+       }
+       ret = _is_privileged(thandle, sidlist);
        if (ret < 0) {
                cpio_warnc(errno, "Failed to check privilege");
                return (0);
@@ -55,4 +989,6 @@ bsdcpio_is_privileged()
        return (ret);
 }
 
+#endif /* LIST_H */
+
 #endif
index 8c9395d071484fde78ff685dc4a8c142d2d54f16..5527dbcc131625cc9f4e2df173a50b2ebc0a72a2 100644 (file)
@@ -51,6 +51,7 @@ struct group {
 extern "C" {
 #endif
 
+extern unsigned int    sleep(unsigned int seconds);
 extern int             bsdcpio_is_privileged();
 
 #ifdef __cplusplus
index 59a89d59f37e67ec274e2b0217af8049deecdbae..56c484cb45546a3dcc138b30d873f11f728a9b95 100644 (file)
@@ -33,6 +33,10 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
     test_passthrough_reverse.c
     test_pathmatch.c
   )
+  IF(WIN32 AND NOT CYGWIN)
+    LIST(APPEND bsdcpio_test_SOURCES ../cpio_windows.c)
+    LIST(APPEND bsdcpio_test_SOURCES ../cpio_windows.h)
+  ENDIF(WIN32 AND NOT CYGWIN)
 
   #
   # Generate the list.h
@@ -45,9 +49,7 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
   # Register target
   #
   ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES})
-  IF(WIN32 AND NOT CYGWIN)
-    ADD_DEPENDENCIES(bsdcpio_test archive_windows_static)
-  ENDIF(WIN32 AND NOT CYGWIN)
+  SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H)
   SET(num 0)
   FOREACH(test ${bsdcpio_test_SOURCES})
     IF(test MATCHES "^test_[^/]+[.]c$")
index 36b52ab09015fa8fa0938735ed6c70ccfdf55fb2..0c2eee18f44632d75ef27dd7f3bfe5f365474ce3 100644 (file)
@@ -1,22 +1,3 @@
-############################################
-#
-# How to build libarchive_windows_static
-#
-# This library is internal library and is used for libarchive programs
-# on Windows platform only.
-# We don't install this one anywhere.
-#
-############################################
-IF(WIN32 AND NOT CYGWIN)
-  SET(libarchive_windows_SOURCES
-    archive_windows.c
-    archive_windows.h
-  )
-  #
-  # Register target
-  #
-  ADD_LIBRARY(archive_windows_static STATIC ${libarchive_windows_SOURCES})
-ENDIF(WIN32 AND NOT CYGWIN)
 
 ############################################
 #
@@ -116,6 +97,8 @@ SET(libarchive_MANS
 )
 
 IF(WIN32 AND NOT CYGWIN)
+  LIST(APPEND libarchive_SOURCES archive_windows.c)
+  LIST(APPEND libarchive_SOURCES archive_windows.h)
   LIST(APPEND libarchive_SOURCES filter_fork_windows.c)
 ENDIF(WIN32 AND NOT CYGWIN)
 
@@ -126,17 +109,10 @@ ENDIF(WIN32 AND NOT CYGWIN)
 # Libarchive is a library
 ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
 TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
-IF(WIN32 AND NOT CYGWIN)
-  ADD_DEPENDENCIES(archive archive_windows_static)
-ENDIF(WIN32 AND NOT CYGWIN)
 SET_TARGET_PROPERTIES(archive PROPERTIES SOVERSION ${SOVERSION})
 SET_TARGET_PROPERTIES(archive PROPERTIES
   RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
 ADD_LIBRARY(archive_static STATIC ${libarchive_SOURCES} ${include_HEADERS})
-TARGET_LINK_LIBRARIES(archive_static ${ADDITIONAL_LIBS})
-IF(WIN32 AND NOT CYGWIN)
-  ADD_DEPENDENCIES(archive_static archive_windows_static)
-ENDIF(WIN32 AND NOT CYGWIN)
 SET_TARGET_PROPERTIES(archive_static PROPERTIES COMPILE_DEFINITIONS
   LIBARCHIVE_STATIC)
 SET_TARGET_PROPERTIES(archive_static PROPERTIES
index 13104ec0544c2ac9c92a7f8780a2535fe5e57369..378232f751eec7821a2779fbbb729a39aca073a9 100644 (file)
 #define _WIN32_WINNT 0x0500
 #define WINVER       0x0500
 
-#if defined(HAVE_CONFIG_H)
-#include "config.h"
-#else
-/* Warn if the library hasn't been (automatically or manually) configured. */
-#error Oops: No config.h and no pre-built configuration in archive_platform.h.
-#endif
+#include "archive_platform.h"
 #include <errno.h>
 #include <stddef.h>
 #include <sys/utime.h>
@@ -62,7 +57,6 @@
 #include <stdlib.h>
 #include <wchar.h>
 #include <windows.h>
-#include <sddl.h>
 
 #define EPOC_TIME      (116444736000000000ULL)
 
@@ -84,14 +78,6 @@ struct ustat {
        dev_t           st_rdev;
 };
 
-struct __DIR {
-       HANDLE                  handle;
-       WIN32_FIND_DATAW        fileData;
-       struct direct           de;
-       int                     first;
-       BOOL                    finished;
-};
-
 /* Transform 64-bits ino into 32-bits by hashing.
  * You do not forget that really unique number size is 64-bits.
  */
@@ -502,117 +488,6 @@ utimes(const char *name, const struct __timeval *times)
        return (ret);
 }
 
-static DIR *
-__opendir(const char *path, int ff)
-{
-       DIR *dir;
-       wchar_t *wpath, *wfname;
-       size_t wlen;
-
-       dir = malloc(sizeof(*dir));
-       if (dir == NULL) {
-               errno = ENOMEM;
-               return (NULL);
-       }
-
-       wpath = permissive_name(path);
-       if (wpath == NULL) {
-               errno = EINVAL;
-               free(dir);
-               return (NULL);
-       }
-       if (ff) {
-               wfname = wpath;
-               wpath = NULL;
-       } else {
-               wlen = wcslen(wpath);
-               wfname = malloc((wlen + 3) * sizeof(wchar_t));
-               if (wfname == NULL) {
-                       errno = ENOMEM;
-                       free(dir);
-                       free(wpath);
-                       return (NULL);
-               }
-               wcscpy(wfname, wpath);
-               wcscat(wfname, L"\\*");
-               free(wpath);
-       }
-
-       dir->handle = FindFirstFileW(wfname, &dir->fileData);
-       if (dir->handle == INVALID_HANDLE_VALUE) {
-               _dosmaperr(GetLastError());
-               free(dir);
-               free(wfname);
-               return (NULL);
-       }
-       dir->first = 1;
-       dir->finished = FALSE;
-       free(wfname);
-
-       return (dir);
-}
-
-DIR *
-opendir_findfile(const char *path)
-{
-       return (__opendir(path, 1));
-}
-
-DIR *
-opendir(const char *path)
-{
-       return (__opendir(path, 0));
-}
-
-struct direct *
-readdir(DIR *dirp)
-{
-       size_t len;
-
-       while (!dirp->finished) {
-               if (!dirp->first && !FindNextFileW(dirp->handle, &dirp->fileData)) {
-                       if (GetLastError() != ERROR_NO_MORE_FILES)
-                               _dosmaperr(GetLastError());
-                       dirp->finished = TRUE;
-                       break;
-               }
-               dirp->first = 0;
-               len = wcstombs(dirp->de.d_name, dirp->fileData.cFileName,
-                   sizeof(dirp->de.d_name) -1);
-               if (len == -1) {
-                       errno = EINVAL;
-                       dirp->finished = TRUE;
-                       break;
-               }
-               dirp->de.d_name[len] = '\0';
-               dirp->de.d_nameln = strlen(dirp->de.d_name);
-               return (&dirp->de);
-       }
-
-       return (NULL);
-}
-
-int
-closedir(DIR *dirp)
-{
-       BOOL ret;
-
-       ret = FindClose(dirp->handle);
-       free(dirp);
-       if (ret == 0) {
-               _dosmaperr(GetLastError());
-               return (-1);
-       }
-       return (0);
-}
-
-unsigned int
-sleep(unsigned int seconds)
-{
-       Sleep(seconds * 1000);
-       return (0);
-}
-
 int
 la_chdir(const char *path)
 {
@@ -1299,95 +1174,4 @@ DIGEST_FINAL(SHA512, SHA384_DIGEST_LENGTH)
 
 #endif /* !HAVE_OPENSSL_MD5_H && !HAVE_OPENSSL_SHA_H */
 
-static int
-_is_privileged(HANDLE thandle, const char *sidlist[])
-{
-       TOKEN_USER *tuser;
-       TOKEN_GROUPS  *tgrp;
-       DWORD bytes;
-       PSID psid;
-       DWORD i, g;
-       int member;
-
-       psid = NULL;
-       tuser = NULL;
-       tgrp = NULL;
-       member = 0;
-       for (i = 0; sidlist[i] != NULL && member == 0; i++) {
-               if (psid != NULL)
-                       LocalFree(psid);
-               if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) {
-                       errno = EPERM;
-                       return (-1);
-               }
-               if (tuser == NULL) {
-                       GetTokenInformation(thandle, TokenUser, NULL, 0,
-                           &bytes);
-                       tuser = malloc(bytes);
-                       if (tuser == NULL) {
-                               errno = ENOMEM;
-                               member = -1;
-                               break;
-                       }
-                       if (GetTokenInformation(thandle, TokenUser, tuser,
-                           bytes, &bytes) == 0) {
-                               errno = EPERM;
-                               member = -1;
-                               break;
-                       }
-               }
-               member = EqualSid(tuser->User.Sid, psid);
-               if (member)
-                       break;
-               if (tgrp == NULL) {
-                       GetTokenInformation(thandle, TokenGroups, NULL, 0,
-                           &bytes);
-                       tgrp = malloc(bytes);
-                       if (tgrp == NULL) {
-                               errno = ENOMEM;
-                               member = -1;
-                               break;
-                       }
-                       if (GetTokenInformation(thandle, TokenGroups, tgrp,
-                           bytes, &bytes) == 0) {
-                               errno = EPERM;
-                               member = -1;
-                               break;
-                       }
-               }
-               for (g = 0; g < tgrp->GroupCount; g++) {
-                       member = EqualSid(tgrp->Groups[g].Sid, psid);
-                       if (member)
-                               break;
-               }
-       }
-       LocalFree(psid);
-       free(tuser);
-       free(tgrp);
-
-       return (member);
-}
-
-int
-la_is_privileged()
-{
-       HANDLE thandle;
-       int ret;
-       const char *sidlist[] = {
-               "S-1-5-32-544", /* Administrators */
-               "S-1-5-32-551", /* Backup Operators */
-               NULL
-       };
-
-       if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) {
-               errno = EPERM;
-               return (-1);
-       }
-       ret = _is_privileged(thandle, sidlist);
-       if (ret < 0) {
-               return (-1);
-       }
-       return (ret);
-}
-
 #endif /* _WIN32 && !__CYGWIN__ */
index 032c4be3876711d7b59412b292e67fdcf5d79fff..d3369013eae72446d26acfec74f81049a10090c0 100644 (file)
@@ -297,13 +297,6 @@ typedef struct {
 #endif
 #endif /* HAVE_OPENSSL_SHA_H */
 
-struct __DIR;
-typedef struct __DIR DIR;
-struct direct {
-       unsigned char   d_nameln;
-       char            d_name[MAX_PATH];
-};
-
 /* End of Win32 definitions. */
 
 #ifdef __cplusplus
@@ -316,11 +309,6 @@ extern int  symlink (const char *from, const char *to);
 extern int      ftruncate(int fd, off_t length);
 extern int      futimes(int fd, const struct __timeval *times);
 extern int      utimes(const char *name, const struct __timeval *times);
-extern DIR     *opendir_findfile(const char *path);
-extern DIR     *opendir(const char *path);
-extern struct direct *readdir(DIR *dirp);
-extern int      closedir(DIR *dirp);
-extern unsigned int    sleep(unsigned int seconds);
 
 /* Replacement POSIX function */
 extern int      la_chdir(const char *path);
@@ -388,9 +376,6 @@ extern void  SHA512_Final(unsigned char buf[SHA512_DIGEST_LENGTH],
 #endif
 #endif
 
-/* */
-extern int      la_is_privileged();
-
 #ifdef __cplusplus
 }
 #endif
index 2cb50d2c46882aa387e6a529cdbcf2de706c546b..6d4e6a3af760cde6a07d782e5fa02f19f5af6df7 100644 (file)
@@ -103,11 +103,8 @@ IF(ENABLE_TEST)
   #
   ADD_EXECUTABLE(libarchive_test ${libarchive_test_SOURCES})
   TARGET_LINK_LIBRARIES(libarchive_test ${ADDITIONAL_LIBS})
-  IF(WIN32 AND NOT CYGWIN)
-    ADD_DEPENDENCIES(libarchive_test archive_windows_static)
-  ENDIF(WIN32 AND NOT CYGWIN)
   SET_PROPERTY(TARGET libarchive_test PROPERTY COMPILE_DEFINITIONS
-    LIBARCHIVE_STATIC)
+    LIBARCHIVE_STATIC LIST_H)
   SET(num 0)
   FOREACH(test ${libarchive_test_SOURCES})
     IF(test MATCHES "^test_[^/]+[.]c$")
index 25b18aa2463be6100cf2d60eefaee2c063f93b5f..2d60f79a892bde1b5311be049ecda70c33b45ae2 100644 (file)
@@ -30,15 +30,10 @@ IF (ENABLE_TAR)
   # Register target
   #
   ADD_EXECUTABLE(bsdtar ${bsdtar_SOURCES})
-  IF(WIN32 AND NOT CYGWIN)
-    ADD_DEPENDENCIES(bsdtar archive_windows_static)
-  ENDIF(WIN32 AND NOT CYGWIN)
   IF(ENABLE_TAR_SHARED)
     TARGET_LINK_LIBRARIES(bsdtar archive ${ADDITIONAL_LIBS})
   ELSE(ENABLE_TAR_SHARED)
     TARGET_LINK_LIBRARIES(bsdtar archive_static ${ADDITIONAL_LIBS})
-    SET_TARGET_PROPERTIES(bsdtar PROPERTIES COMPILE_DEFINITIONS
-      LIBARCHIVE_STATIC)
   ENDIF(ENABLE_TAR_SHARED)
   IF(WIN32 AND NOT CYGWIN)
     SET_TARGET_PROPERTIES(bsdtar PROPERTIES
index 0408157f3184abdfd4ac4a618ef92450a7848aef..d31f1122d65628f8527820a52cb7f1bf11094118 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "bsdtar.h"
 
+#ifndef LIST_H
 static int
 _is_privileged(HANDLE thandle, const char *sidlist[])
 {
@@ -134,4 +135,7 @@ bsdtar_is_privileged(struct bsdtar *bsdtar)
        return (ret);
 }
 
+
+#endif /* LIST_H */
+
 #endif
index 9fc48aa8bac63bcdc26b3a179f8672ebf0e5625e..c4e77b45120a859af1c6baa56060c5899b1db989 100644 (file)
 
 #include "bsdtar.h"
 
+#define EPOC_TIME      (116444736000000000ULL)
+
+struct ustat {
+       int64_t         st_atime;
+       uint32_t        st_atime_nsec;
+       int64_t         st_ctime;
+       uint32_t        st_ctime_nsec;
+       int64_t         st_mtime;
+       uint32_t        st_mtime_nsec;
+       gid_t           st_gid;
+       /* 64bits ino */
+       int64_t         st_ino;
+       mode_t          st_mode;
+       uint32_t        st_nlink;
+       uint64_t        st_size;
+       uid_t           st_uid;
+       dev_t           st_dev;
+       dev_t           st_rdev;
+};
+
+struct __DIR {
+       HANDLE                  handle;
+       WIN32_FIND_DATAW        fileData;
+       struct dirent           de;
+       int                     first;
+       BOOL                    finished;
+};
+
+/* Transform 64-bits ino into 32-bits by hashing.
+ * You do not forget that really unique number size is 64-bits.
+ */
+#define INOSIZE (8*sizeof(ino_t)) /* 32 */
+static __inline ino_t
+getino(struct ustat *ub)
+{
+       ULARGE_INTEGER ino64;
+
+       ino64.QuadPart = ub->st_ino;
+       /* I don't know this hashing is correct way */
+       return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE));
+}
+
+/*
+ * 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 char *name)
+{
+       wchar_t *wn, *wnp;
+       wchar_t *ws, *wsp;
+       size_t l, len, slen;
+       int unc;
+
+       len = strlen(name);
+       wn = malloc((len + 1) * sizeof(wchar_t));
+       if (wn == NULL)
+               return (NULL);
+       l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
+       if (l == 0) {
+               free(wn);
+               return (NULL);
+       }
+       wn[l] = L'\0';
+
+       /* Get a full path names */
+       l = GetFullPathNameW(wn, 0, NULL, NULL);
+       if (l == 0) {
+               free(wn);
+               return (NULL);
+       }
+       wnp = malloc(l * sizeof(wchar_t));
+       if (wnp == NULL) {
+               free(wn);
+               return (NULL);
+       }
+       len = GetFullPathNameW(wn, l, wnp, NULL);
+       free(wn);
+       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_s(wsp, slen, wnp, _TRUNCATE);
+       free(wn);
+       return (ws);
+}
+
+static HANDLE
+la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
+    LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
+    DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
+{
+       wchar_t *wpath;
+       HANDLE handle;
+
+       handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
+           lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
+           hTemplateFile);
+       if (handle != INVALID_HANDLE_VALUE)
+               return (handle);
+       if (GetLastError() != ERROR_PATH_NOT_FOUND)
+               return (handle);
+       wpath = permissive_name(path);
+       if (wpath == NULL)
+               return (handle);
+       handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
+           lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
+           hTemplateFile);
+       free(wpath);
+       return (handle);
+}
+
+static size_t
+wequallen(const wchar_t *s1, const wchar_t *s2)
+{
+       size_t i = 0;
+
+       while (*s1 != L'\0' && *s2 != L'\0' && *s1 == *s2) {
+               ++s1; ++s2; ++i;
+       }
+       return (i);
+}
+
+/* Check that path1 and path2 can be hard-linked by each other.
+ * Both arguments must be made by permissive_name function. 
+ */
+static int
+canHardLinkW(const wchar_t *path1, const wchar_t *path2)
+{
+       wchar_t root[MAX_PATH];
+       wchar_t fs[32];
+       const wchar_t *s;
+       int r;
+
+       r = wequallen(path1, path2);
+       /* Is volume-name the same? */
+       if (r < 7)
+               return (0);
+       if (wcsncmp(path1, L"\\\\?\\UNC\\", 8) == 0) {
+               int len;
+
+               s = path1 + 8;
+               if (*s == L'\\')
+                       return (0);
+               /*         012345678
+                * Name : "\\?\UNC\Server\Share\"
+                *                       ^ search
+                */
+               s = wcschr(++s, L'\\');
+               if (s == NULL)
+                       return (0);
+               if (*++s == L'\\')
+                       return (0);
+               /*         012345678
+                * Name : "\\?\UNC\Server\Share\"
+                *                             ^ search
+                */
+               s = wcschr(++s, L'\\');
+               if (s == NULL)
+                       return (0);
+               s++;
+               /*         012345678
+                * Name : "\\?\UNC\Server\Share\xxxx"
+                *                 ^--- len ----^
+                */
+               len = (int)(s - path1 - 8);
+               /* Is volume-name the same? */
+               if (r < len + 8)
+                       return (0);
+               /* Is volume-name too long? */
+               if (sizeof(root) -3 < len)
+                       return (0);
+               root[0] = root[1] = L'\\';
+               wcsncpy(root + 2, path1 + 8 , len);
+               /* root : "\\Server\Share\" */
+               root[2 + len] = L'\0';
+       } else if (wcsncmp(path1, L"\\\\?\\", 4) == 0) {
+               s = path1 + 4;
+               if ((!iswalpha(*s)) || s[1] != L':' || s[2] != L'\\')
+                       return (0);
+               wcsncpy(root, path1 + 4, 3);
+               root[3] = L'\0';
+       } else
+               return (0);
+       if (!GetVolumeInformationW(root, NULL, 0, NULL, NULL, NULL, fs, sizeof(fs)))
+               return (0);
+       if (wcscmp(fs, L"NTFS") == 0)
+               return (1);
+       else
+               return (0);
+}
+
+/* Make a link to src called dst.  */
+static int
+__link(const char *src, const char *dst, int sym)
+{
+       wchar_t *wsrc, *wdst;
+       int res, retval;
+       DWORD attr;
+
+       if (src == NULL || dst == NULL) {
+               set_errno (EINVAL);
+               return -1;
+       }
+
+       wsrc = permissive_name(src);
+       wdst = permissive_name(dst);
+       if (wsrc == NULL || wdst == NULL) {
+               if (wsrc != NULL)
+                       free(wsrc);
+               if (wdst != NULL)
+                       free(wdst);
+               set_errno (EINVAL);
+               return -1;
+       }
+
+       if ((attr = GetFileAttributesW(wsrc)) != -1) {
+               if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+                       errno = EPERM;
+                       retval = -1;
+                       goto exit;
+               }
+               if (!sym && canHardLinkW(wsrc, wdst))
+                       res = CreateHardLinkW(wdst, wsrc, NULL);
+               else
+                       res = CopyFileW(wsrc, wdst, FALSE);
+       } else {
+               /* wsrc does not exist; try src prepend it with the dirname of wdst */
+               wchar_t *wnewsrc, *slash;
+               int i, n, slen, wlen;
+
+               if (strlen(src) >= 3 && isalpha((unsigned char)src[0]) &&
+                   src[1] == ':' && src[2] == '\\') {
+                       /* Original src name is already full-path */
+                       retval = -1;
+                       goto exit;
+               }
+               if (src[0] == '\\') {
+                       /* Original src name is almost full-path
+                        * (maybe src name is without drive) */
+                       retval = -1;
+                       goto exit;
+               }
+
+               wnewsrc = malloc ((wcslen(wsrc) + wcslen(wdst) + 1) * sizeof(wchar_t));
+               if (wnewsrc == NULL) {
+                       errno = ENOMEM;
+                       retval = -1;
+                       goto exit;
+               }
+               /* Copying a dirname of wdst */
+               wcscpy(wnewsrc, wdst);
+               slash = wcsrchr(wnewsrc, L'\\');
+               if (slash != NULL)
+                       *++slash = L'\0';
+               else
+                       wcscat(wnewsrc, L"\\");
+               /* Converting multi-byte src to wide-char src */
+               wlen = wcslen(wsrc);
+               slen = strlen(src);
+               n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, slen);
+               if (n == 0) {
+                       free (wnewsrc);
+                       retval = -1;
+                       goto exit;
+               }
+               for (i = 0; i < n; i++)
+                       if (wsrc[i] == L'/')
+                               wsrc[i] = L'\\';
+               wcsncat(wnewsrc, wsrc, n);
+               /* Check again */
+               attr = GetFileAttributesW(wnewsrc);
+               if (attr == -1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+                       if (attr == -1)
+                               _dosmaperr(GetLastError());
+                       else
+                               errno = EPERM;
+                       free (wnewsrc);
+                       retval = -1;
+                       goto exit;
+               }
+               if (!sym && canHardLinkW(wnewsrc, wdst))
+                       res = CreateHardLinkW(wdst, wnewsrc, NULL);
+               else
+                       res = CopyFileW(wnewsrc, wdst, FALSE);
+               free (wnewsrc);
+       }
+       if (res == 0) {
+               _dosmaperr(GetLastError());
+               retval = -1;
+       } else
+               retval = 0;
+exit:
+       free(wsrc);
+       free(wdst);
+       return (retval);
+}
+
+/* Make a hard link to src called dst.  */
+int
+link(const char *src, const char *dst)
+{
+       return __link (src, dst, 0);
+}
+
+/* Make a symbolic link to FROM called TO.  */
+int symlink (from, to)
+     const char *from;
+     const char *to;
+{
+       return __link (from, to, 1);
+}
+
+int
+ftruncate(int fd, off_t length)
+{
+       LARGE_INTEGER distance;
+       HANDLE handle;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       handle = (HANDLE)_get_osfhandle(fd);
+       if (GetFileType(handle) != FILE_TYPE_DISK) {
+               errno = EBADF;
+               return (-1);
+       }
+       distance.QuadPart = length;
+       if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN)) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       if (!SetEndOfFile(handle)) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       return (0);
+}
+
+DIR *
+__opendir(const char *path, int ff)
+{
+       DIR *dir;
+       wchar_t *wpath, *wfname;
+       size_t wlen;
+
+       dir = malloc(sizeof(*dir));
+       if (dir == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+
+       wpath = permissive_name(path);
+       if (wpath == NULL) {
+               errno = EINVAL;
+               free(dir);
+               return (NULL);
+       }
+       if (ff) {
+               wfname = wpath;
+               wpath = NULL;
+       } else {
+               wlen = wcslen(wpath);
+               wfname = malloc((wlen + 3) * sizeof(wchar_t));
+               if (wfname == NULL) {
+                       errno = ENOMEM;
+                       free(dir);
+                       free(wpath);
+                       return (NULL);
+               }
+               wcscpy(wfname, wpath);
+               wcscat(wfname, L"\\*");
+               free(wpath);
+       }
+
+       dir->handle = FindFirstFileW(wfname, &dir->fileData);
+       if (dir->handle == INVALID_HANDLE_VALUE) {
+               _dosmaperr(GetLastError());
+               free(dir);
+               free(wfname);
+               return (NULL);
+       }
+       dir->first = 1;
+       dir->finished = FALSE;
+       free(wfname);
+
+       return (dir);
+}
+
+static DIR *
+opendir_findfile(const char *path)
+{
+       return (__opendir(path, 1));
+}
+
+DIR *
+opendir(const char *path)
+{
+       return (__opendir(path, 0));
+}
+
+struct dirent *
+readdir(DIR *dirp)
+{
+       size_t len;
+
+       while (!dirp->finished) {
+               if (!dirp->first && !FindNextFileW(dirp->handle, &dirp->fileData)) {
+                       if (GetLastError() != ERROR_NO_MORE_FILES)
+                               _dosmaperr(GetLastError());
+                       dirp->finished = TRUE;
+                       break;
+               }
+               dirp->first = 0;
+               len = wcstombs(dirp->de.d_name, dirp->fileData.cFileName,
+                   sizeof(dirp->de.d_name) -1);
+               if (len == -1) {
+                       errno = EINVAL;
+                       dirp->finished = TRUE;
+                       break;
+               }
+               dirp->de.d_name[len] = '\0';
+               dirp->de.d_nameln = strlen(dirp->de.d_name);
+               return (&dirp->de);
+       }
+
+       return (NULL);
+}
+
+int
+closedir(DIR *dirp)
+{
+       BOOL ret;
+
+       ret = FindClose(dirp->handle);
+       free(dirp);
+       if (ret == 0) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       return (0);
+}
+
+int
+la_chdir(const char *path)
+{
+       wchar_t *ws;
+       int r;
+
+       r = SetCurrentDirectoryA(path);
+       if (r == 0) {
+               if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+                       _dosmaperr(GetLastError());
+                       return (-1);
+               }
+       } else
+               return (0);
+       ws = permissive_name(path);
+       if (ws == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       r = SetCurrentDirectoryW(ws);
+       free(ws);
+       if (r == 0) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       return (0);
+}
+
+__int64
+la_lseek(int fd, __int64 offset, int whence)
+{
+       LARGE_INTEGER distance;
+       LARGE_INTEGER newpointer;
+       HANDLE handle;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       handle = (HANDLE)_get_osfhandle(fd);
+       if (GetFileType(handle) != FILE_TYPE_DISK) {
+               errno = EBADF;
+               return (-1);
+       }
+       distance.QuadPart = offset;
+       if (!SetFilePointerEx(handle, distance, &newpointer, whence)) {
+               DWORD lasterr;
+
+               lasterr = GetLastError();
+               if (lasterr == ERROR_BROKEN_PIPE)
+                       return (0);
+               if (lasterr == ERROR_ACCESS_DENIED)
+                       errno = EBADF;
+               else
+                       _dosmaperr(lasterr);
+               return (-1);
+       }
+       return (newpointer.QuadPart);
+}
+
+int
+la_mkdir(const char *path, mode_t mode)
+{
+       wchar_t *ws;
+       int r;
+
+       (void)mode;/* UNUSED */
+       r = CreateDirectoryA(path, NULL);
+       if (r == 0) {
+               DWORD lasterr = GetLastError();
+               if (lasterr != ERROR_FILENAME_EXCED_RANGE &&
+                       lasterr != ERROR_PATH_NOT_FOUND) {
+                       _dosmaperr(GetLastError());
+                       return (-1);
+               }
+       } else
+               return (0);
+       ws = permissive_name(path);
+       if (ws == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       r = CreateDirectoryW(ws, NULL);
+       free(ws);
+       if (r == 0) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       return (0);
+}
+
+/* Windows' mbstowcs is differrent error handling from other unix mbstowcs.
+ * That one is using MultiByteToWideChar function with MB_PRECOMPOSED and
+ * MB_ERR_INVALID_CHARS flags.
+ * This implements for only to pass libarchive_test.
+ */
+size_t
+la_mbstowcs(wchar_t *wcstr, const char *mbstr, size_t nwchars)
+{
+
+       return (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
+           mbstr, (int)strlen(mbstr), wcstr,
+           (int)nwchars));
+}
+
+int
+la_open(const char *path, int flags, ...)
+{
+       va_list ap;
+       wchar_t *ws;
+       int r, pmode;
+       DWORD attr;
+
+       va_start(ap, flags);
+       pmode = va_arg(ap, int);
+       va_end(ap);
+       ws = NULL;
+       if ((flags & ~O_BINARY) == O_RDONLY) {
+               /*
+                * When we open a directory, _open function returns 
+                * "Permission denied" error.
+                */
+               attr = GetFileAttributesA(path);
+               if (attr == -1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
+                       ws = permissive_name(path);
+                       if (ws == NULL) {
+                               errno = EINVAL;
+                               return (-1);
+                       }
+                       attr = GetFileAttributesW(ws);
+               }
+               if (attr == -1) {
+                       _dosmaperr(GetLastError());
+                       free(ws);
+                       return (-1);
+               }
+               if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+                       HANDLE handle;
+
+                       if (ws != NULL)
+                               handle = CreateFileW(ws, 0, 0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS |
+                                   FILE_ATTRIBUTE_READONLY,
+                                       NULL);
+                       else
+                               handle = CreateFileA(path, 0, 0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS |
+                                   FILE_ATTRIBUTE_READONLY,
+                                       NULL);
+                       free(ws);
+                       if (handle == INVALID_HANDLE_VALUE) {
+                               _dosmaperr(GetLastError());
+                               return (-1);
+                       }
+                       r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
+                       return (r);
+               }
+       }
+       if (ws == NULL) {
+               r = _open(path, flags, pmode);
+               if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
+                       /* simular other POSIX system action to pass a test */
+                       attr = GetFileAttributesA(path);
+                       if (attr == -1)
+                               _dosmaperr(GetLastError());
+                       else if (attr & FILE_ATTRIBUTE_DIRECTORY)
+                               errno = EISDIR;
+                       else
+                               errno = EACCES;
+                       return (-1);
+               }
+               if (r >= 0 || errno != ENOENT)
+                       return (r);
+               ws = permissive_name(path);
+               if (ws == NULL) {
+                       errno = EINVAL;
+                       return (-1);
+               }
+       }
+       r = _wopen(ws, flags, pmode);
+       if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
+               /* simular other POSIX system action to pass a test */
+               attr = GetFileAttributesW(ws);
+               if (attr == -1)
+                       _dosmaperr(GetLastError());
+               else if (attr & FILE_ATTRIBUTE_DIRECTORY)
+                       errno = EISDIR;
+               else
+                       errno = EACCES;
+       }
+       free(ws);
+       return (r);
+}
+
+ssize_t
+la_read(int fd, void *buf, size_t nbytes)
+{
+       HANDLE handle;
+       DWORD bytes_read, lasterr;
+       int r;
+
+#ifdef _WIN64
+       if (nbytes > UINT32_MAX)
+               nbytes = UINT32_MAX;
+#endif
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       handle = (HANDLE)_get_osfhandle(fd);
+       if (GetFileType(handle) == FILE_TYPE_PIPE) {
+               DWORD sta;
+               if (GetNamedPipeHandleState(
+                   handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 &&
+                   (sta & PIPE_NOWAIT) == 0) {
+                       DWORD avail = -1;
+                       int cnt = 3;
+
+                       while (PeekNamedPipe(
+                           handle, NULL, 0, NULL, &avail, NULL) != 0 &&
+                           avail == 0 && --cnt)
+                               Sleep(100);
+                       if (avail == 0)
+                               return (0);
+               }
+       }
+       r = ReadFile(handle, buf, (uint32_t)nbytes,
+           &bytes_read, NULL);
+       if (r == 0) {
+               lasterr = GetLastError();
+               if (lasterr == ERROR_NO_DATA) {
+                       errno = EAGAIN;
+                       return (-1);
+               }
+               if (lasterr == ERROR_BROKEN_PIPE)
+                       return (0);
+               if (lasterr == ERROR_ACCESS_DENIED)
+                       errno = EBADF;
+               else
+                       _dosmaperr(lasterr);
+               return (-1);
+       }
+       return ((ssize_t)bytes_read);
+}
+
+/* Remove directory */
+int
+la_rmdir(const char *path)
+{
+       wchar_t *ws;
+       int r;
+
+       r = _rmdir(path);
+       if (r >= 0 || errno != ENOENT)
+               return (r);
+       ws = permissive_name(path);
+       if (ws == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       r = _wrmdir(ws);
+       free(ws);
+       return (r);
+}
+
+/* Convert Windows FILETIME to UTC */
+__inline static void
+fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
+{
+       ULARGE_INTEGER utc;
+
+       utc.HighPart = filetime->dwHighDateTime;
+       utc.LowPart  = filetime->dwLowDateTime;
+       if (utc.QuadPart >= EPOC_TIME) {
+               utc.QuadPart -= EPOC_TIME;
+               *time = (time_t)(utc.QuadPart / 10000000);      /* milli seconds base */
+               *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
+       } else {
+               *time = 0;
+               *ns = 0;
+       }
+}
+
+/* Stat by handle
+ * Windows' stat() does not accept path which is added "\\?\" especially "?"
+ * character.
+ * It means we cannot access a long name path(which is longer than MAX_PATH).
+ * So I've implemented simular Windows' stat() to access the long name path.
+ * And I've added some feature.
+ * 1. set st_ino by nFileIndexHigh and nFileIndexLow of
+ *    BY_HANDLE_FILE_INFORMATION.
+ * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.
+ * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.
+ */
+static int
+__hstat(HANDLE handle, struct ustat *st)
+{
+       BY_HANDLE_FILE_INFORMATION info;
+       ULARGE_INTEGER ino64;
+       DWORD ftype;
+       mode_t mode;
+       time_t time;
+       long ns;
+
+       switch (ftype = GetFileType(handle)) {
+       case FILE_TYPE_UNKNOWN:
+               errno = EBADF;
+               return (-1);
+       case FILE_TYPE_CHAR:
+       case FILE_TYPE_PIPE:
+               if (ftype == FILE_TYPE_CHAR) {
+                       st->st_mode = S_IFCHR;
+                       st->st_size = 0;
+               } else {
+                       DWORD avail;
+
+                       st->st_mode = S_IFIFO;
+                       if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))
+                               st->st_size = avail;
+                       else
+                               st->st_size = 0;
+               }
+               st->st_atime = 0;
+               st->st_atime_nsec = 0;
+               st->st_mtime = 0;
+               st->st_mtime_nsec = 0;
+               st->st_ctime = 0;
+               st->st_ctime_nsec = 0;
+               st->st_ino = 0;
+               st->st_nlink = 1;
+               st->st_uid = 0;
+               st->st_gid = 0;
+               st->st_rdev = 0;
+               st->st_dev = 0;
+               return (0);
+       case FILE_TYPE_DISK:
+               break;
+       default:
+               /* This ftype is undocumented type. */
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+
+       ZeroMemory(&info, sizeof(info));
+       if (!GetFileInformationByHandle (handle, &info)) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+
+       mode = S_IRUSR | S_IRGRP | S_IROTH;
+       if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
+               mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+       if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+               mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
+       else
+               mode |= S_IFREG;
+       st->st_mode = mode;
+       
+       fileTimeToUTC(&info.ftLastAccessTime, &time, &ns);
+       st->st_atime = time; 
+       st->st_atime_nsec = ns;
+       fileTimeToUTC(&info.ftLastWriteTime, &time, &ns);
+       st->st_mtime = time;
+       st->st_mtime_nsec = ns;
+       fileTimeToUTC(&info.ftCreationTime, &time, &ns);
+       st->st_ctime = time;
+       st->st_ctime_nsec = ns;
+       st->st_size = 
+           ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
+               + (int64_t)(info.nFileSizeLow);
+#ifdef SIMULATE_WIN_STAT
+       st->st_ino = 0;
+       st->st_nlink = 1;
+       st->st_dev = 0;
+#else
+       /* Getting FileIndex as i-node. We have to remove a sequence which
+        * is high-16-bits of nFileIndexHigh. */
+       ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;
+       ino64.LowPart  = info.nFileIndexLow;
+       st->st_ino = ino64.QuadPart;
+       st->st_nlink = info.nNumberOfLinks;
+       if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+               ++st->st_nlink;/* Add parent directory. */
+       st->st_dev = info.dwVolumeSerialNumber;
+#endif
+       st->st_uid = 0;
+       st->st_gid = 0;
+       st->st_rdev = 0;
+       return (0);
+}
+
+static void
+copy_stat(struct stat *st, struct ustat *us)
+{
+       st->st_atime = us->st_atime;
+       st->st_ctime = us->st_ctime;
+       st->st_mtime = us->st_mtime;
+       st->st_gid = us->st_gid;
+       st->st_ino = getino(us);
+       st->st_mode = us->st_mode;
+       st->st_nlink = us->st_nlink;
+       st->st_size = us->st_size;
+       st->st_uid = us->st_uid;
+       st->st_dev = us->st_dev;
+       st->st_rdev = us->st_rdev;
+}
+
+int
+la_fstat(int fd, struct stat *st)
+{
+       struct ustat u;
+       int ret;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
+       if (ret >= 0) {
+               copy_stat(st, &u);
+               if (u.st_mode & (S_IFCHR | S_IFIFO)) {
+                       st->st_dev = fd;
+                       st->st_rdev = fd;
+               }
+       }
+       return (ret);
+}
+
+int
+la_stat(const char *path, struct stat *st)
+{
+       HANDLE handle;
+       struct ustat u;
+       int ret;
+
+       handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
+               FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
+               NULL);
+       if (handle == INVALID_HANDLE_VALUE) {
+               _dosmaperr(GetLastError());
+               return (-1);
+       }
+       ret = __hstat(handle, &u);
+       CloseHandle(handle);
+       if (ret >= 0) {
+               char *p;
+
+               copy_stat(st, &u);
+               p = strrchr(path, '.');
+               if (p != NULL && strlen(p) == 4) {
+                       char exttype[4];
+
+                       ++ p;
+                       exttype[0] = toupper(*p++);
+                       exttype[1] = toupper(*p++);
+                       exttype[2] = toupper(*p++);
+                       exttype[3] = '\0';
+                       if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
+                               !strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
+                               st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
+               }
+       }
+       return (ret);
+}
+
+ssize_t
+la_write(int fd, const void *buf, size_t nbytes)
+{
+       uint32_t bytes_written;
+
+#ifdef _WIN64
+       if (nbytes > UINT32_MAX)
+               nbytes = UINT32_MAX;
+#endif
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,
+           &bytes_written, NULL)) {
+               DWORD lasterr;
+
+               lasterr = GetLastError();
+               if (lasterr == ERROR_ACCESS_DENIED)
+                       errno = EBADF;
+               else
+                       _dosmaperr(lasterr);
+               return (-1);
+       }
+       return (bytes_written);
+}
+
+#ifndef LIST_H
+static int
+_is_privileged(HANDLE thandle, const char *sidlist[])
+{
+       TOKEN_USER *tuser;
+       TOKEN_GROUPS  *tgrp;
+       DWORD bytes;
+       PSID psid;
+       DWORD i, g;
+       int member;
+
+       psid = NULL;
+       tuser = NULL;
+       tgrp = NULL;
+       member = 0;
+       for (i = 0; sidlist[i] != NULL && member == 0; i++) {
+               if (psid != NULL)
+                       LocalFree(psid);
+               if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) {
+                       errno = EPERM;
+                       return (-1);
+               }
+               if (tuser == NULL) {
+                       GetTokenInformation(thandle, TokenUser, NULL, 0, &bytes);
+                       tuser = malloc(bytes);
+                       if (tuser == NULL) {
+                               errno = ENOMEM;
+                               member = -1;
+                               break;
+                       }
+                       if (GetTokenInformation(thandle, TokenUser, tuser, bytes, &bytes) == 0) {
+                               errno = EPERM;
+                               member = -1;
+                               break;
+                       }
+               }
+               member = EqualSid(tuser->User.Sid, psid);
+               if (member)
+                       break;
+               if (tgrp == NULL) {
+                       GetTokenInformation(thandle, TokenGroups, NULL, 0, &bytes);
+                       tgrp = malloc(bytes);
+                       if (tgrp == NULL) {
+                               errno = ENOMEM;
+                               member = -1;
+                               break;
+                       }
+                       if (GetTokenInformation(thandle, TokenGroups, tgrp, bytes, &bytes) == 0) {
+                               errno = EPERM;
+                               member = -1;
+                               break;
+                       }
+               }
+               for (g = 0; g < tgrp->GroupCount; g++) {
+                       member = EqualSid(tgrp->Groups[g].Sid, psid);
+                       if (member)
+                               break;
+               }
+       }
+       LocalFree(psid);
+       free(tuser);
+       free(tgrp);
+
+       return (member);
+}
+
 int
 bsdtar_is_privileged(struct bsdtar *bsdtar)
 {
+       HANDLE thandle;
        int ret;
+       const char *sidlist[] = {
+               "S-1-5-32-544", /* Administrators */
+               "S-1-5-32-551", /* Backup Operators */
+               NULL
+       };
 
-       ret = la_is_privileged();
+       (void)bsdtar;/* UNUSED */
+       if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) {
+               bsdtar_warnc(bsdtar, EPERM, "Failed to check privilege");
+               return (0);
+       }
+       ret = _is_privileged(thandle, sidlist);
        if (ret < 0) {
                bsdtar_warnc(bsdtar, errno, "Failed to check privilege");
                return (0);
@@ -140,4 +1208,6 @@ try_plain:
        write_hierarchy(bsdtar, a, path);
 }
 
+#endif /* LIST_H */
+
 #endif
index 7624edcc5f2b1229e6e47ec350ff34ffacf859e4..5dfe02c5b533c2ddaad11feeae0d428a7370a0cc 100644 (file)
 #define PRId64 "I64"
 #define geteuid()      0
 
+struct __DIR;
+typedef struct __DIR DIR;
+struct direct {
+       unsigned char   d_nameln;
+       char            d_name[MAX_PATH];
+};
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+extern DIR     *opendir(const char *path);
+extern struct dirent *readdir(DIR *dirp);
+extern int     closedir(DIR *dirp);
+
 extern int     bsdtar_is_privileged(struct bsdtar *bsdtar);
 extern void    write_hierarchy_win(struct bsdtar *bsdtar, struct archive *a,
                const char *path,
index 8e6386a5a439e2864038b7c19bbe4130473b4251..8f1ec77a27c759f25824c197deba2e8c28b47afe 100644 (file)
@@ -23,6 +23,8 @@ IF(ENABLE_TAR AND ENABLE_TEST)
     test_version.c
   )
   IF(WIN32 AND NOT CYGWIN)
+    LIST(APPEND bsdtar_test_SOURCES ../bsdtar_windows.c)
+    LIST(APPEND bsdtar_test_SOURCES ../bsdtar_windows.h)
     LIST(APPEND bsdtar_test_SOURCES test_windows.c)
   ENDIF(WIN32 AND NOT CYGWIN)
 
@@ -37,9 +39,7 @@ IF(ENABLE_TAR AND ENABLE_TEST)
   # Register target
   #
   ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES})
-  IF(WIN32 AND NOT CYGWIN)
-    ADD_DEPENDENCIES(bsdtar_test archive_windows_static)
-  ENDIF(WIN32 AND NOT CYGWIN)
+  SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H)
   SET(num 0)
   FOREACH(test ${bsdtar_test_SOURCES})
     IF(test MATCHES "^test_[^/]+[.]c$")