/* Copyright (C) 2015-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). 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 */ /** @file dk4symlink.c The dk4symlink module. */ #line 73 "dk4symlink.ctr" #include "dk4conf.h" #include "dk4symlink.h" #if DK4_ON_WINDOWS #ifndef WINDOWS_H_INCLUDED #include #define WINDOWS_H_INCLUDED 1 #endif #if DK4_HAVE_NTIFS_H #ifndef NTIFS_H_INCLUDED #include #define NTIFS_H_INCLUDED 1 #endif #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif #include "dk4mpl.h" #include "dk4mem.h" #include "dk4strd.h" #line 118 "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 DK4_USE_ASSERT assert(NULL != bptr); assert(0 < szb); assert(NULL != sptr); #endif 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 223 "dk4symlink.ctr" #if DK4_USE_ASSERT assert(NULL != bptr); assert(0 < szb); assert(NULL != fn); #endif 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 253 "dk4symlink.ctr" #endif if (0 == back) { #if defined(FSCTL_GET_REPARSE_POINT) /* !!!!! Second attempt with legacy procedure */ #line 258 "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 273 "dk4symlink.ctr" result = DeviceIoControl( fh, FSCTL_GET_REPARSE_POINT, NULL, (DWORD)0U, (void *)repdabuf, (DWORD)sizeof(repdabuf), &dwres, NULL ); if (result) { #line 284 "dk4symlink.ctr" rdb = (REPARSE_DATA_BUFFER *)repdabuf; if (IO_REPARSE_TAG_MOUNT_POINT == rdb->ReparseTag) { #line 287 "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 297 "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 307 "dk4symlink.ctr" } } } else { #line 310 "dk4symlink.ctr" dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); } CloseHandle(fh); } else { #line 314 "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 ((size_t)res < szb) { bptr[res] = dkT('\0'); back = 1; } else { #line 370 "dk4symlink.ctr" bptr[0] = dkT('\0'); dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL); } } else { #line 374 "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 385 "dk4symlink.ctr" return back; }