diff options
Diffstat (limited to 'libarchive/archive_read_disk_windows.c')
-rw-r--r-- | libarchive/archive_read_disk_windows.c | 59 |
1 files changed, 31 insertions, 28 deletions
diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c index 964de749..ff79cc05 100644 --- a/libarchive/archive_read_disk_windows.c +++ b/libarchive/archive_read_disk_windows.c @@ -299,8 +299,8 @@ static int close_and_restore_time(HANDLE, struct tree *, struct restore_time *); static int setup_sparse_from_disk(struct archive_read_disk *, struct archive_entry *, HANDLE); -static int la_linkname_from_handle(HANDLE, wchar_t **, int); -static int la_linkname_from_pathw(const wchar_t *, wchar_t **); +static int la_linkname_from_handle(HANDLE, wchar_t **, int *); +static int la_linkname_from_pathw(const wchar_t *, wchar_t **, int *); static void entry_symlink_from_pathw(struct archive_entry *, const wchar_t *path); @@ -337,15 +337,22 @@ typedef struct _REPARSE_DATA_BUFFER { * outbuf is allocated in the function */ static int -la_linkname_from_handle(HANDLE h, wchar_t **linkname, int isdir) +la_linkname_from_handle(HANDLE h, wchar_t **linkname, int *linktype) { DWORD inbytes; REPARSE_DATA_BUFFER *buf; + BY_HANDLE_FILE_INFORMATION st; size_t len; BOOL ret; BYTE *indata; wchar_t *tbuf; + ret = GetFileInformationByHandle(h, &st); + if (ret == 0 || + (st.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) { + return (-1); + } + indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata, 1024, &inbytes, NULL); @@ -369,8 +376,7 @@ la_linkname_from_handle(HANDLE h, wchar_t **linkname, int isdir) return (-1); } - /* We need an extra character here to append directory slash */ - tbuf = malloc(len + 2 * sizeof(wchar_t)); + tbuf = malloc(len + 1 * sizeof(wchar_t)); if (tbuf == NULL) { free(indata); return (-1); @@ -393,42 +399,35 @@ la_linkname_from_handle(HANDLE h, wchar_t **linkname, int isdir) tbuf++; } - /* - * Directory symlinks need special treatment - */ - if (isdir && wcscmp(*linkname, L".") != 0 && - wcscmp(*linkname, L"..") != 0) { - if (*(tbuf - 1) != L'/') { - *tbuf = L'/'; - *(tbuf + 1) = L'\0'; - } - } + if ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + *linktype = AE_SYMLINK_TYPE_FILE; + else + *linktype = AE_SYMLINK_TYPE_DIRECTORY; + return (0); } +/* + * Returns AE_SYMLINK_TYPE_FILE, AE_SYMLINK_TYPE_DIRECTORY or -1 on error + */ static int -la_linkname_from_pathw(const wchar_t *path, wchar_t **outbuf) +la_linkname_from_pathw(const wchar_t *path, wchar_t **outbuf, int *linktype) { HANDLE h; - DWORD attrs; - DWORD flag = FILE_FLAG_BACKUP_SEMANTICS | + const DWORD flag = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT; int ret; - attrs = GetFileAttributesW(path); - if (attrs == INVALID_FILE_ATTRIBUTES || - (!(attrs & FILE_ATTRIBUTE_REPARSE_POINT))) - return (-1); - h = CreateFileW(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, flag, NULL); if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); return (-1); } - ret = la_linkname_from_handle(h, outbuf, - attrs & FILE_ATTRIBUTE_DIRECTORY); + + ret = la_linkname_from_handle(h, outbuf, linktype); CloseHandle(h); + return (ret); } @@ -436,11 +435,15 @@ static void entry_symlink_from_pathw(struct archive_entry *entry, const wchar_t *path) { wchar_t *linkname = NULL; - int ret; + int ret, linktype; - ret = la_linkname_from_pathw(path, &linkname); - if (ret == 0) + ret = la_linkname_from_pathw(path, &linkname, &linktype); + if (ret != 0) + return; + if (linktype >= 0) { archive_entry_copy_symlink_w(entry, linkname); + archive_entry_set_symlink_type(entry, linktype); + } free(linkname); return; |