blob: 81c6f4414044e1c333a7f6db2447538ebc630445 [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
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) {
errno = ENOMEM;
return -1;
}
char tmp_buffer[size * 2];
unsigned long int len; // Size of the wide char string including L'\0' (MaximumLength)
status = NtQuerySymbolicLinkObject(handle, &rpath, &len);
//printf("nativelibc debug: readlink: status = 0x%lx, len = %lu\n", status, len);
if(status == STATUS_BUFFER_TOO_SMALL) {
UNICODE_STRING tpath = { len - sizeof(wchar_t), len, malloc(len) };
if(!tpath.Buffer) {
RtlFreeUnicodeString(&rpath);
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;
len = rpath.MaximumLength;
RtlFreeUnicodeString(&tpath);
//printf("nativelibc debug: len = %lu\n", len);
} else if(status < 0) {
failed:
RtlFreeUnicodeString(&rpath);
__set_errno_from_ntstatus(status);
return -1;
}
assert(len / 2 - 1 <= size);
PATHNAME_NT2UNIX_UTF16_STRUCT(rpath);
int r = wcstombs(tmp_buffer, rpath.Buffer, len * 2);
//printf("nativelibc debug: r = %d\n", r);
RtlFreeUnicodeString(&rpath);
if(r < 0) r = strlen(tmp_buffer);
memcpy(buffer, tmp_buffer, r);
return r;
}