mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Implemented CreateHardLink()
svn path=/trunk/; revision=8700
This commit is contained in:
parent
8dc9f6bf9c
commit
89265e0151
6 changed files with 264 additions and 34 deletions
|
@ -1,6 +1,6 @@
|
|||
#ifndef __INCLUDE_DDK_FSTYPES_H
|
||||
#define __INCLUDE_DDK_FSTYPES_H
|
||||
/* $Id: fstypes.h,v 1.13 2003/08/14 18:30:27 silverblade Exp $ */
|
||||
/* $Id: fstypes.h,v 1.14 2004/03/14 09:21:41 weiden Exp $ */
|
||||
|
||||
#ifndef __USE_W32API
|
||||
|
||||
|
@ -14,6 +14,12 @@ typedef struct _FILE_LOCK_INFO {
|
|||
LARGE_INTEGER EndingByte;
|
||||
} FILE_LOCK_INFO, *PFILE_LOCK_INFO;
|
||||
|
||||
typedef struct _FILE_LINK_INFORMATION {
|
||||
BOOLEAN ReplaceIfExists;
|
||||
HANDLE RootDirectory;
|
||||
ULONG FileNameLength;
|
||||
WCHAR FileName[1];
|
||||
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;
|
||||
|
||||
typedef NTSTATUS (*PCOMPLETE_LOCK_IRP_ROUTINE) (
|
||||
IN PVOID Context,
|
||||
|
|
|
@ -428,6 +428,8 @@ enum
|
|||
#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032
|
||||
#define FILE_VALID_SET_FLAGS 0x00001036
|
||||
|
||||
#define FILE_OPEN_REPARSE_POINT 0x00200000
|
||||
|
||||
/*
|
||||
* special ByteOffset values
|
||||
*/
|
||||
|
|
251
reactos/lib/kernel32/file/hardlink.c
Normal file
251
reactos/lib/kernel32/file/hardlink.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* $Id: hardlink.c,v 1.1 2004/03/14 09:21:42 weiden Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS system libraries
|
||||
* FILE: lib/kernel32/file/hardlink.c
|
||||
* PURPOSE: Hardlink functions
|
||||
* PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
|
||||
* UPDATE HISTORY:
|
||||
* Created 13/03/2004
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <k32.h>
|
||||
#include <ddk/ntifs.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include "../include/debug.h"
|
||||
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOL STDCALL
|
||||
CreateHardLinkW(
|
||||
LPCWSTR lpFileName,
|
||||
LPCWSTR lpExistingFileName,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
||||
)
|
||||
{
|
||||
UNICODE_STRING LinkTarget, LinkName, CheckDrive, LinkDrive, LanManager;
|
||||
LPWSTR lpNtLinkTarget, lpFilePart;
|
||||
ULONG NeededSize;
|
||||
LPVOID lpSecurityDescriptor;
|
||||
WCHAR wCheckDrive[10];
|
||||
OBJECT_ATTRIBUTES ObjectAttribues;
|
||||
PFILE_LINK_INFORMATION LinkInformation;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
HANDLE hFile, hTarget;
|
||||
NTSTATUS Status;
|
||||
|
||||
if(!lpFileName || !lpExistingFileName)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lpSecurityDescriptor = (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL);
|
||||
|
||||
if(RtlDetermineDosPathNameType_U((LPWSTR)lpFileName) == 1 ||
|
||||
RtlDetermineDosPathNameType_U((LPWSTR)lpExistingFileName) == 1)
|
||||
{
|
||||
DPRINT1("CreateHardLinkW() cannot handle UNC Paths!\n");
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!RtlDosPathNameToNtPathName_U((LPWSTR)lpExistingFileName, &LinkTarget, NULL, NULL))
|
||||
{
|
||||
SetLastError(ERROR_PATH_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!(NeededSize = RtlGetFullPathName_U((LPWSTR)lpExistingFileName, 0, NULL, NULL)))
|
||||
{
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NeededSize += 2;
|
||||
if(!(lpNtLinkTarget = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize * sizeof(WCHAR))))
|
||||
{
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!RtlGetFullPathName_U((LPWSTR)lpExistingFileName, NeededSize, lpNtLinkTarget, &lpFilePart))
|
||||
{
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
swprintf(wCheckDrive, L"\\??\\%c:", (WCHAR)(*lpNtLinkTarget));
|
||||
RtlInitUnicodeString(&CheckDrive, wCheckDrive);
|
||||
|
||||
RtlZeroMemory(&LinkDrive, sizeof(UNICODE_STRING));
|
||||
if(!(LinkDrive.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
(MAX_PATH + 1) * sizeof(WCHAR))))
|
||||
{
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttribues,
|
||||
&CheckDrive,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = ZwOpenSymbolicLinkObject(&hFile, 1, &ObjectAttribues);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkDrive.Buffer);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastErrorByStatus(Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&LanManager, L"\\Device\\LanmanRedirector\\");
|
||||
|
||||
ZwQuerySymbolicLinkObject(hFile, &LinkDrive, NULL);
|
||||
|
||||
if(RtlPrefixUnicodeString(&LanManager, &LinkDrive, TRUE))
|
||||
{
|
||||
ZwClose(hFile);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkDrive.Buffer);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
DPRINT1("Path \"%wZ\" must not be a mapped drive!\n", &LinkDrive);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttribues,
|
||||
&LinkTarget,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
lpSecurityDescriptor);
|
||||
|
||||
Status = ZwOpenFile(&hTarget, SYNCHRONIZE | DELETE, &ObjectAttribues, &IoStatus,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
ZwClose(hFile);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkDrive.Buffer);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
DPRINT1("Unable to open link destination \"%wZ\"!\n", &LinkTarget);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!RtlDosPathNameToNtPathName_U((LPWSTR)lpFileName, &LinkName, NULL, NULL))
|
||||
{
|
||||
ZwClose(hTarget);
|
||||
ZwClose(hFile);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkDrive.Buffer);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NeededSize = sizeof(FILE_LINK_INFORMATION) + LinkName.Length + sizeof(WCHAR);
|
||||
if(!(LinkInformation = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
|
||||
{
|
||||
ZwClose(hTarget);
|
||||
ZwClose(hFile);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkDrive.Buffer);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LinkInformation->ReplaceIfExists = FALSE;
|
||||
LinkInformation->RootDirectory = 0;
|
||||
LinkInformation->FileNameLength = LinkName.Length;
|
||||
RtlCopyMemory(LinkInformation->FileName, LinkName.Buffer, LinkName.Length);
|
||||
|
||||
Status = ZwSetInformationFile(hTarget, &IoStatus, LinkInformation, NeededSize, FileLinkInformation);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastErrorByStatus(Status);
|
||||
}
|
||||
|
||||
ZwClose(hTarget);
|
||||
ZwClose(hFile);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkInformation);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, LinkDrive.Buffer);
|
||||
RtlFreeHeap(RtlGetProcessHeap(), 0, lpNtLinkTarget);
|
||||
RtlFreeUnicodeString(&LinkTarget);
|
||||
return NT_SUCCESS(Status);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOL STDCALL
|
||||
CreateHardLinkA(
|
||||
LPCSTR lpFileName,
|
||||
LPCSTR lpExistingFileName,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
||||
)
|
||||
{
|
||||
ANSI_STRING FileNameA, ExistingFileNameA;
|
||||
UNICODE_STRING FileName, ExistingFileName;
|
||||
NTSTATUS Status;
|
||||
BOOL Ret;
|
||||
|
||||
if(!lpFileName || !lpExistingFileName)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RtlInitAnsiString(&FileNameA, (LPSTR)lpFileName);
|
||||
RtlInitAnsiString(&ExistingFileNameA, (LPSTR)lpExistingFileName);
|
||||
|
||||
if(bIsFileApiAnsi)
|
||||
Status = RtlAnsiStringToUnicodeString(&FileName, &FileNameA, TRUE);
|
||||
else
|
||||
Status = RtlOemStringToUnicodeString(&FileName, &FileNameA, TRUE);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastErrorByStatus(Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(bIsFileApiAnsi)
|
||||
Status = RtlAnsiStringToUnicodeString(&ExistingFileName, &ExistingFileNameA, TRUE);
|
||||
else
|
||||
Status = RtlOemStringToUnicodeString(&ExistingFileName, &ExistingFileNameA, TRUE);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
RtlFreeUnicodeString(&FileName);
|
||||
SetLastErrorByStatus(Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Ret = CreateHardLinkW(FileName.Buffer, ExistingFileName.Buffer, lpSecurityAttributes);
|
||||
|
||||
RtlFreeUnicodeString(&FileName);
|
||||
RtlFreeUnicodeString(&ExistingFileName);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -18,6 +18,7 @@
|
|||
#include <napi/i386/segment.h>
|
||||
#include <napi/teb.h>
|
||||
#include <napi/npipe.h>
|
||||
#include <napi/types.h>
|
||||
#include <ntos/minmax.h>
|
||||
#include <csrss/csrss.h>
|
||||
#include <reactos/buildno.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: makefile,v 1.77 2004/02/22 17:30:32 chorns Exp $
|
||||
# $Id: makefile,v 1.78 2004/03/14 09:21:41 weiden Exp $
|
||||
|
||||
PATH_TO_TOP = ../..
|
||||
|
||||
|
@ -41,7 +41,7 @@ FILE_OBJECTS = file/file.o file/curdir.o file/lfile.o file/dir.o \
|
|||
file/create.o file/find.o file/copy.o file/pipe.o \
|
||||
file/move.o file/lock.o file/rw.o file/delete.o \
|
||||
file/npipe.o file/tape.o file/mailslot.o file/backup.o \
|
||||
file/cnotify.o
|
||||
file/cnotify.o file/hardlink.o
|
||||
|
||||
MEM_OBJECTS = mem/global.o mem/heap.o mem/isbad.o mem/local.o \
|
||||
mem/procmem.o mem/section.o mem/virtual.o
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: stubs.c,v 1.62 2004/02/15 07:03:56 arty Exp $
|
||||
/* $Id: stubs.c,v 1.63 2004/03/14 09:21:41 weiden Exp $
|
||||
*
|
||||
* KERNEL32.DLL stubs (unimplemented functions)
|
||||
* Remove from this file, if you implement them.
|
||||
|
@ -1653,21 +1653,6 @@ CheckNameLegalDOS8Dot3W(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
BOOL
|
||||
STDCALL
|
||||
CreateHardLinkW(
|
||||
LPCWSTR lpFileName,
|
||||
LPCWSTR lpExistingFileName,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
||||
)
|
||||
{
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
|
@ -2042,21 +2027,6 @@ CheckNameLegalDOS8Dot3A(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
BOOL
|
||||
STDCALL
|
||||
CreateHardLinkA(
|
||||
LPCSTR lpFileName,
|
||||
LPCSTR lpExistingFileName,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
||||
)
|
||||
{
|
||||
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue