blob: a2abf20d716f0368ac9d3bde7aa7ac1b08fb7e5b [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
Copyright 2015-2024 Rivoreo
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <windows.h>
#include <nt.h>
#include <errno.h>
#include <pathname.h>
#include <ntstatus.h>
#include <assert.h>
//#include <stdio.h>
int readlink(const char *path, char *buffer, size_t size) {
//printf("function: readlink(%p<%s>, %p, %lu)\n", path, path, buffer, (long int)size);
if(!path || !buffer) {
errno = EFAULT;
return -1;
}
if(!size) {
errno = EINVAL;
return -1;
}
if(!*path) {
errno = ENOENT;
return -1;
}
UNICODE_STRING wpath;
if(!RtlCreateUnicodeStringFromAsciiz(&wpath, path)) {
errno = ENOMEM;
return -1;
}
PATHNAME_UNIX2NT_UTF16_STRUCT(wpath);
OBJECT_ATTRIBUTES object_attribute = { sizeof(OBJECT_ATTRIBUTES), NULL, &wpath, 0, NULL, NULL };
void *handle;
long int status = NtOpenSymbolicLinkObject(&handle, GENERIC_READ, &object_attribute);
RtlFreeUnicodeString(&wpath);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
UNICODE_STRING rpath = { size * sizeof(wchar_t), (size + 1) * sizeof(wchar_t), malloc((size + 1) * sizeof(wchar_t)) };
if(!rpath.Buffer) {
NtClose(handle);
errno = ENOMEM;
return -1;
}
char tmp_buffer[size * 2];
unsigned long int rsize; // Size of the wide char string including L'\0' (MaximumLength)
status = NtQuerySymbolicLinkObject(handle, &rpath, &rsize);
if(status == STATUS_BUFFER_TOO_SMALL) {
UNICODE_STRING tpath = { rsize - sizeof(wchar_t), rsize, malloc(rsize) };
if(!tpath.Buffer) {
free(rpath.Buffer);
NtClose(handle);
errno = ENOMEM;
return -1;
}
status = NtQuerySymbolicLinkObject(handle, &tpath, NULL);
if(status < 0) goto failed;
memcpy(rpath.Buffer, tpath.Buffer, rpath.Length);
rpath.Buffer[rpath.Length / sizeof(wchar_t)] = 0;
rsize = rpath.MaximumLength;
free(tpath.Buffer);
} else if(status < 0) {
failed:
free(rpath.Buffer);
NtClose(handle);
__set_errno_from_ntstatus(status);
return -1;
}
NtClose(handle);
assert(rsize / 2 - 1 <= size);
PATHNAME_NT2UNIX_UTF16_STRUCT(rpath);
int r = wcstombs(tmp_buffer, rpath.Buffer, rsize * 2);
//printf("nativelibc debug: r = %d\n", r);
free(rpath.Buffer);
if(r < 0) r = 0;
memcpy(buffer, tmp_buffer, r);
assert(r <= size);
return r;
}