diff options
author | Martin Matuska <martin@matuska.org> | 2019-04-15 01:50:29 +0200 |
---|---|---|
committer | Martin Matuska <martin@matuska.org> | 2019-04-15 23:36:06 +0200 |
commit | b0ed582e68fe6e474d321934d29b0f229c0feb9f (patch) | |
tree | 04d67b7fa3d5631736f850a1aead1dbe88e4f30a /libarchive/archive_read_disk_windows.c | |
parent | 19bd077987ff26a4cb108edde5eaf970837aa1f0 (diff) | |
download | libarchive-b0ed582e68fe6e474d321934d29b0f229c0feb9f.tar.gz |
Windows symlinks: new functions and extended tar header
New functions:
archive_entry_symlink_type()
archive_entry_set_symlink_type()
Suppoted value constants:
AE_SYMLINK_TYPE_UNDEFINED
AE_SYMLINK_TYPE_FILE
AE_SYMLINK_TYPE_DIRECTORY
New extended tar header:
LIBARCHIVE.symlinktype
The function archive_entry_symlink_type() retrieves and the function
archive_entry_set_symlink_type() sets the symbolic link type of an archive
entry. The information about the symbolic link type is required to properly
restore symbolic links on Microsoft Windows. If the symlink type is set
to AE_SYMLINK_TYPE_FILE or AE_SYMLINK_TYPE_DIRECTORY and a tar archive
is written, an extended tar header LIBARCHIVE.symlinktype is stored with
the value "file" or "dir". When reading symbolic links on Windows, the
link type is automatically stored in the archive_entry structure.
On unix systems, the symlink type has no effect when reading or writing
symbolic links.
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; |