mirror of
https://github.com/reactos/reactos.git
synced 2024-11-03 05:18:55 +00:00
174 lines
5.5 KiB
C
174 lines
5.5 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: dll/win32/kernel32/client/file/hardlink.c
|
|
* PURPOSE: Hardlink functions
|
|
* PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
|
|
* Pierre Schweitzer (pierre.schweitzer@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <k32.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
CreateHardLinkW(IN LPCWSTR lpFileName,
|
|
IN LPCWSTR lpExistingFileName,
|
|
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
{
|
|
NTSTATUS Status;
|
|
BOOL Ret = FALSE;
|
|
ULONG NeededSize;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hTarget = INVALID_HANDLE_VALUE;
|
|
PFILE_LINK_INFORMATION LinkInformation = NULL;
|
|
UNICODE_STRING LinkTarget, LinkName;
|
|
|
|
/* Initialize */
|
|
LinkTarget.Buffer = LinkName.Buffer = NULL;
|
|
|
|
/* Validate parameters */
|
|
if (!(lpFileName) || !(lpExistingFileName))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
_SEH2_TRY
|
|
{
|
|
/* Get target UNC path */
|
|
if (!RtlDosPathNameToNtPathName_U(lpExistingFileName,
|
|
&LinkTarget,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
/* Set the error and fail */
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* Open target */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&LinkTarget,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
lpSecurityAttributes ?
|
|
lpSecurityAttributes->lpSecurityDescriptor :
|
|
NULL);
|
|
Status = NtOpenFile(&hTarget,
|
|
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Convert the error and fail */
|
|
BaseSetLastNTError(Status);
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* Get UNC path name for link */
|
|
if (!RtlDosPathNameToNtPathName_U(lpFileName, &LinkName, NULL, NULL))
|
|
{
|
|
/* Set the error and fail */
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* Allocate data for link */
|
|
NeededSize = sizeof(FILE_LINK_INFORMATION) + LinkName.Length;
|
|
LinkInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, NeededSize);
|
|
if (!LinkInformation)
|
|
{
|
|
/* We're out of memory */
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* Setup data for link and create it */
|
|
RtlMoveMemory(LinkInformation->FileName, LinkName.Buffer, LinkName.Length);
|
|
LinkInformation->ReplaceIfExists = FALSE;
|
|
LinkInformation->RootDirectory = 0;
|
|
LinkInformation->FileNameLength = LinkName.Length;
|
|
Status = NtSetInformationFile(hTarget,
|
|
&IoStatusBlock,
|
|
LinkInformation,
|
|
NeededSize,
|
|
FileLinkInformation);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Set success code */
|
|
Ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Convert error code and return default (FALSE) */
|
|
BaseSetLastNTError(Status);
|
|
}
|
|
}
|
|
_SEH2_FINALLY
|
|
{
|
|
/* Cleanup all allocations */
|
|
if (LinkTarget.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, LinkTarget.Buffer);
|
|
if (hTarget != INVALID_HANDLE_VALUE) NtClose(hTarget);
|
|
if (LinkName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, LinkName.Buffer);
|
|
if (LinkInformation) RtlFreeHeap(RtlGetProcessHeap(), 0, LinkInformation);
|
|
}
|
|
_SEH2_END;
|
|
return Ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
CreateHardLinkA(IN LPCSTR lpFileName,
|
|
IN LPCSTR lpExistingFileName,
|
|
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
{
|
|
BOOL Ret;
|
|
PUNICODE_STRING lpFileNameW;
|
|
UNICODE_STRING ExistingFileNameW;
|
|
|
|
/* Convert the filename to unicode, using MAX_PATH limitations */
|
|
lpFileNameW = Basep8BitStringToStaticUnicodeString(lpFileName);
|
|
if (!lpFileNameW) return FALSE;
|
|
|
|
/* Check if there's an existing name as well */
|
|
if (lpExistingFileName)
|
|
{
|
|
/* We're already using the static string above, so do this dynamically */
|
|
if (!Basep8BitStringToDynamicUnicodeString(&ExistingFileNameW,
|
|
lpExistingFileName))
|
|
{
|
|
/* Out of memory -- fail */
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No existing file name */
|
|
ExistingFileNameW.Buffer = NULL;
|
|
}
|
|
|
|
/* Call the Wide function, and then free our dynamic string */
|
|
Ret = CreateHardLinkW(lpFileNameW->Buffer,
|
|
ExistingFileNameW.Buffer,
|
|
lpSecurityAttributes);
|
|
RtlFreeUnicodeString(&ExistingFileNameW);
|
|
return Ret;
|
|
}
|
|
|
|
/* EOF */
|