#include "bsdtar.h"
#include "err.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;
-};
-
+/* This may actually not be needed anymore.
+ * TODO: Review the error handling for chdir() failures and
+ * simply dump this if it's not really needed. */
static void __tar_dosmaperr(unsigned long);
-/* 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 (ino_t)(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
return (ws);
}
-static HANDLE
-__tar_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);
-}
-
int
__tar_chdir(const char *path)
{
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
-__tar_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
-__tar_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) {
- __tar_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) {
- __tar_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)
- __tar_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)
- __tar_dosmaperr(GetLastError());
- else if (attr & FILE_ATTRIBUTE_DIRECTORY)
- errno = EISDIR;
- else
- errno = EACCES;
- }
- 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. */
- __tar_dosmaperr(GetLastError());
- return (-1);
- }
-
- ZeroMemory(&info, sizeof(info));
- if (!GetFileInformationByHandle (handle, &info)) {
- __tar_dosmaperr(GetLastError());
- return (-1);
- }
-
- mode = 0444;
- if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
- mode |= 0222;
- if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- mode |= S_IFDIR | 0111;
- 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
-__tar_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
-__tar_stat(const char *path, struct stat *st)
-{
- HANDLE handle;
- struct ustat u;
- int ret;
-
- handle = __tar_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
- NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- __tar_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 |= 0111;
- }
- }
- return (ret);
-}
-
-
/*
* The following function was modified from PostgreSQL sources and is
* subject to the copyright below.