diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dk4symlink.c |
Initial commit
Diffstat (limited to 'support/dktools/dk4symlink.c')
-rw-r--r-- | support/dktools/dk4symlink.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/support/dktools/dk4symlink.c b/support/dktools/dk4symlink.c new file mode 100644 index 0000000000..39f4fb57ea --- /dev/null +++ b/support/dktools/dk4symlink.c @@ -0,0 +1,365 @@ +/* + WARNING: This file was generated by dkct. + Changes you make here will be lost if dkct is run again! + You should modify the original source and run dkct on it. + Original source: dk4symlink.ctr +*/ + +/* +Copyright (C) 2015-2017, Dirk Krause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above opyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the author nor the names of contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** @file dk4symlink.c The dk4symlink module. +*/ + + +#line 61 "dk4symlink.ctr" + +#include "dk4symlink.h" + +#if DK4_ON_WINDOWS +#ifndef WINDOWS_H_INCLUDED +#include <windows.h> +#define WINDOWS_H_INCLUDED 1 +#endif +#if DK4_HAVE_NTIFS_H +#ifndef NTIFS_H_INCLUDED +#include <ntifs.h> +#define NTIFS_H_INCLUDED 1 +#endif +#endif +#endif + +#if DK4_HAVE_UNISTD_H +#ifndef UNISTD_H_INCLUDED +#include <unistd.h> +#define UNISTD_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_ERRNO_H +#ifndef ERRNO_H_INCLUDED +#include <errno.h> +#define ERRNO_H_INCLUDED 1 +#endif +#endif + +#include "dk4mpl.h" +#include "dk4mem.h" +#include "dk4strd.h" + + + + + +#line 98 "dk4symlink.ctr" + + + +#if DK4_ON_WINDOWS + +#if !DK4_HAVE_NTIFS_H + +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +#endif + + +#if defined(FSCTL_GET_REPARSE_POINT) +/** Size of reparse point information for a symlink. +*/ +#define SYMLINK_INFO_SIZE ((8 * (DK4_MAX_PATH))+sizeof(REPARSE_DATA_BUFFER)) +/** The above size aligned to 16 bytes. +*/ +#define SYMLINK_INFO_ALIGNED (16 * (((SYMLINK_INFO_SIZE) / 16) + 1)) + +#ifdef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define SYMLINK_BUFFER_SIZE \ +(MAXIMUM_REPARSE_DATA_BUFFER_SIZE + SYMLINK_INFO_ALIGNED) +#endif +#endif + +/** Copy path name from reparse point buffer to destination buffer. + @param bptr Destination buffer. + @param szb Destination buffer size (number of wchar_t). + @param sptr Source pointer. + @param offs Offset of path name in source (in bytes). + @param length Length of path name (in bytes). + @param erp Error report, may be NULL. + @return 1 on success, 0 on error. +*/ +static +int +dk4symlink_copy_string( + wchar_t *bptr, + size_t szb, + const wchar_t *sptr, + USHORT offs, + USHORT length, + dk4_er_t *erp +) +{ + int back = 0; + if ((length / sizeof(wchar_t)) < szb) { + DK4_MEMCPY(bptr,&(sptr[offs / sizeof(wchar_t)]),length); + bptr[length / sizeof(wchar_t)] = L'\0'; + back = 1; + } else { + dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); + } + return back; +} + +#endif + +int +dk4symlink_target(dkChar *bptr, size_t szb, const dkChar *fn, dk4_er_t *erp) +{ +#if DK4_ON_WINDOWS +#if defined(FSCTL_GET_REPARSE_POINT) + char repdabuf[SYMLINK_BUFFER_SIZE]; + REPARSE_DATA_BUFFER *rdb; +#endif + HANDLE fh; + DWORD dwres; + BOOL result; +#else + ssize_t res; +#endif + int back = 0; + + + +#line 198 "dk4symlink.ctr" + if ((NULL != bptr) && (NULL != fn) && (0 < szb)) { + *bptr = dkT('\0'); +#if DK4_ON_WINDOWS +#if DK4_CHAR_SIZE > 1 +#if DK4_HAVE_GETFINALPATHNAMEBYHANDLE + fh = CreateFileW( + fn, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + if (INVALID_HANDLE_VALUE != fh) { + dwres = GetFinalPathNameByHandleW(fh, bptr, (DWORD)szb, 0); + if (0 < dwres) { + if (dwres < (DWORD)szb) { + back = 1; + } + } + CloseHandle(fh); + } +#else + + +#line 223 "dk4symlink.ctr" +#endif + if (0 == back) { +#if defined(FSCTL_GET_REPARSE_POINT) + /* !!!!! Second attempt with legacy procedure */ + + +#line 228 "dk4symlink.ctr" + fh = CreateFileW( + fn, + FILE_READ_ATTRIBUTES, + (FILE_SHARE_READ | FILE_SHARE_WRITE), + NULL, + OPEN_EXISTING, + ( + FILE_FLAG_BACKUP_SEMANTICS + | FILE_FLAG_OPEN_REPARSE_POINT + | FILE_ATTRIBUTE_REPARSE_POINT + ), + NULL + ); + if (INVALID_HANDLE_VALUE != fh) { + dwres = 0; + +#line 243 "dk4symlink.ctr" + result = DeviceIoControl( + fh, + FSCTL_GET_REPARSE_POINT, + NULL, + (DWORD)0U, + (void *)repdabuf, + (DWORD)sizeof(repdabuf), + &dwres, + NULL + ); + if (result) { + +#line 254 "dk4symlink.ctr" + rdb = (REPARSE_DATA_BUFFER *)repdabuf; + if (IO_REPARSE_TAG_MOUNT_POINT == rdb->ReparseTag) { + + +#line 257 "dk4symlink.ctr" + back = dk4symlink_copy_string( + bptr, szb, + &(rdb->MountPointReparseBuffer.PathBuffer[0]), + rdb->MountPointReparseBuffer.SubstituteNameOffset, + rdb->MountPointReparseBuffer.SubstituteNameLength, + erp + ); + } else { + if (IO_REPARSE_TAG_SYMLINK == rdb->ReparseTag) { + + +#line 267 "dk4symlink.ctr" + back = dk4symlink_copy_string( + bptr, szb, + &(rdb->SymbolicLinkReparseBuffer.PathBuffer[0]), + rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset, + rdb->SymbolicLinkReparseBuffer.SubstituteNameLength, + erp + ); + } else { + /* !!!!! Not mount point, not symlink */ + + +#line 277 "dk4symlink.ctr" + } + } + } else { + +#line 280 "dk4symlink.ctr" + dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); + } + CloseHandle(fh); + } else { + +#line 284 "dk4symlink.ctr" + dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); + } +#else + dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); +#endif + } +#else +#if DK4_HAVE_GETFINALPATHNAMEBYHANDLE + fh = CreateFileA( + fn, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + if (INVALID_HANDLE_VALUE != fh) { + dwres = GetFinalPathNameByHandleA(fh, bptr, (DWORD)szb, 0); + if (0 < dwres) { + if (dwres < (DWORD)szb) { + back = 1; + } + } + CloseHandle(fh); + } +#else + /* Legacy procedure only available for wchar_t. + */ + dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); +#endif +#endif + if (0 < back) { + if (dkT('\\') == bptr[0]) { + if ((dkT('\\') == bptr[1]) || (dkT('?') == bptr[1])) { + if (dkT('?') == bptr[2]) { + if (dkT('\\') == bptr[3]) { + if (260 > dk4str_len(&(bptr[4]))) { + dk4str_cpy_to_left(bptr, &(bptr[4])); + } + } + } + } + } + } +#else +#if DK4_CHAR_SIZE > 1 + dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); +#else + errno = 0; + res = readlink(fn, bptr, szb); + if (0 < res) { + if (res < szb) { + bptr[res] = dkT('\0'); + back = 1; + } else { + +#line 340 "dk4symlink.ctr" + bptr[0] = dkT('\0'); + dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); + } + } else { + +#line 344 "dk4symlink.ctr" + bptr[0] = dkT('\0'); + if (0 > res) { + dk4error_set_idetails(erp, DK4_E_SYSTEM, errno); + } + } +#endif +#endif + if (0 == back) { *bptr = dkT('\0'); } + } else { + dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); + } + +#line 355 "dk4symlink.ctr" + return back; +} + |