windows-nt/Source/XPSP1/NT/base/win32/client/winlinks.c
2020-09-26 16:20:57 +08:00

240 lines
5.8 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
winlink.c
Abstract:
This module implements Win32 CreateHardLink
Author:
Felipe Cabrera (cabrera) 28-Feb-1997
Revision History:
--*/
#include "basedll.h"
BOOL
APIENTRY
CreateHardLinkA(
LPCSTR lpLinkName,
LPCSTR lpExistingFileName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
/*++
Routine Description:
ANSI thunk to CreateHardLinkW
--*/
{
PUNICODE_STRING Unicode;
UNICODE_STRING UnicodeExistingFileName;
BOOL ReturnValue;
Unicode = Basep8BitStringToStaticUnicodeString( lpLinkName );
if (Unicode == NULL) {
return FALSE;
}
if ( ARGUMENT_PRESENT(lpExistingFileName) ) {
if (!Basep8BitStringToDynamicUnicodeString( &UnicodeExistingFileName, lpExistingFileName )) {
return FALSE;
}
}
else {
UnicodeExistingFileName.Buffer = NULL;
}
ReturnValue = CreateHardLinkW((LPCWSTR)Unicode->Buffer, (LPCWSTR)UnicodeExistingFileName.Buffer, lpSecurityAttributes);
RtlFreeUnicodeString(&UnicodeExistingFileName);
return ReturnValue;
}
BOOL
APIENTRY
CreateHardLinkW(
LPCWSTR lpLinkName,
LPCWSTR lpExistingFileName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
/*++
Routine Description:
A file can be made to be a hard link to an existing file.
The existing file can be a reparse point or not.
Arguments:
lpLinkName - Supplies the name of a file that is to be to be made a hard link. As
this is to be a new hard link, there should be no file or directory present
with this name.
lpExistingFileName - Supplies the name of an existing file that is the target for
the hard link.
lpSecurityAttributes - this is currently not used
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN TranslationStatus;
UNICODE_STRING OldFileName;
UNICODE_STRING NewFileName;
PVOID FreeBuffer;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_LINK_INFORMATION NewName;
HANDLE FileHandle = INVALID_HANDLE_VALUE;
BOOLEAN ReturnValue = FALSE;
//
// Check to see that both names are present.
//
if ( !ARGUMENT_PRESENT(lpLinkName) ||
!ARGUMENT_PRESENT(lpExistingFileName) ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
OldFileName.Buffer = NULL;
NewFileName.Buffer = NULL;
try {
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpExistingFileName,
&OldFileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
__leave;
}
//
// Initialize the object name.
//
InitializeObjectAttributes(
&ObjectAttributes,
&OldFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
//
// Account the inheritance of the security descriptor. Note: this argument has no effect currently
//
if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
}
//
// Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior.
// Thus, the hard link is established to the local entity, be it a reparse
// point or not.
//
Status = NtOpenFile(
&FileHandle,
FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError( Status );
__leave;
}
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpLinkName,
&NewFileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
__leave;
}
NewName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), NewFileName.Length+sizeof(*NewName));
if ( NewName == NULL ) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
__leave;
}
RtlMoveMemory(NewName->FileName, NewFileName.Buffer, NewFileName.Length);
NewName->ReplaceIfExists = FALSE;
NewName->RootDirectory = NULL;
NewName->FileNameLength = NewFileName.Length;
Status = NtSetInformationFile(
FileHandle,
&IoStatusBlock,
NewName,
NewFileName.Length+sizeof(*NewName),
FileLinkInformation
);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError( Status );
__leave;
}
ReturnValue = TRUE;
} finally {
//
// Cleanup allocate memory and handles
//
if (FileHandle != INVALID_HANDLE_VALUE) {
NtClose( FileHandle );
}
if (NewFileName.Buffer != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, NewFileName.Buffer);
}
if (OldFileName.Buffer != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, OldFileName.Buffer);
}
}
return ReturnValue;
}