Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
5.8 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. winlink.c
  5. Abstract:
  6. This module implements Win32 CreateHardLink
  7. Author:
  8. Felipe Cabrera (cabrera) 28-Feb-1997
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. BOOL
  13. APIENTRY
  14. CreateHardLinkA(
  15. LPCSTR lpLinkName,
  16. LPCSTR lpExistingFileName,
  17. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  18. )
  19. /*++
  20. Routine Description:
  21. ANSI thunk to CreateHardLinkW
  22. --*/
  23. {
  24. PUNICODE_STRING Unicode;
  25. UNICODE_STRING UnicodeExistingFileName;
  26. BOOL ReturnValue;
  27. Unicode = Basep8BitStringToStaticUnicodeString( lpLinkName );
  28. if (Unicode == NULL) {
  29. return FALSE;
  30. }
  31. if ( ARGUMENT_PRESENT(lpExistingFileName) ) {
  32. if (!Basep8BitStringToDynamicUnicodeString( &UnicodeExistingFileName, lpExistingFileName )) {
  33. return FALSE;
  34. }
  35. }
  36. else {
  37. UnicodeExistingFileName.Buffer = NULL;
  38. }
  39. ReturnValue = CreateHardLinkW((LPCWSTR)Unicode->Buffer, (LPCWSTR)UnicodeExistingFileName.Buffer, lpSecurityAttributes);
  40. RtlFreeUnicodeString(&UnicodeExistingFileName);
  41. return ReturnValue;
  42. }
  43. BOOL
  44. APIENTRY
  45. CreateHardLinkW(
  46. LPCWSTR lpLinkName,
  47. LPCWSTR lpExistingFileName,
  48. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  49. )
  50. /*++
  51. Routine Description:
  52. A file can be made to be a hard link to an existing file.
  53. The existing file can be a reparse point or not.
  54. Arguments:
  55. lpLinkName - Supplies the name of a file that is to be to be made a hard link. As
  56. this is to be a new hard link, there should be no file or directory present
  57. with this name.
  58. lpExistingFileName - Supplies the name of an existing file that is the target for
  59. the hard link.
  60. lpSecurityAttributes - this is currently not used
  61. Return Value:
  62. TRUE - The operation was successful.
  63. FALSE/NULL - The operation failed. Extended error status is available
  64. using GetLastError.
  65. --*/
  66. {
  67. NTSTATUS Status;
  68. BOOLEAN TranslationStatus;
  69. UNICODE_STRING OldFileName;
  70. UNICODE_STRING NewFileName;
  71. PVOID FreeBuffer;
  72. OBJECT_ATTRIBUTES ObjectAttributes;
  73. IO_STATUS_BLOCK IoStatusBlock;
  74. PFILE_LINK_INFORMATION NewName;
  75. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  76. BOOLEAN ReturnValue = FALSE;
  77. //
  78. // Check to see that both names are present.
  79. //
  80. if ( !ARGUMENT_PRESENT(lpLinkName) ||
  81. !ARGUMENT_PRESENT(lpExistingFileName) ) {
  82. SetLastError(ERROR_INVALID_PARAMETER);
  83. return FALSE;
  84. }
  85. OldFileName.Buffer = NULL;
  86. NewFileName.Buffer = NULL;
  87. try {
  88. TranslationStatus = RtlDosPathNameToNtPathName_U(
  89. lpExistingFileName,
  90. &OldFileName,
  91. NULL,
  92. NULL
  93. );
  94. if ( !TranslationStatus ) {
  95. SetLastError(ERROR_PATH_NOT_FOUND);
  96. __leave;
  97. }
  98. //
  99. // Initialize the object name.
  100. //
  101. InitializeObjectAttributes(
  102. &ObjectAttributes,
  103. &OldFileName,
  104. OBJ_CASE_INSENSITIVE,
  105. NULL,
  106. NULL
  107. );
  108. //
  109. // Account the inheritance of the security descriptor. Note: this argument has no effect currently
  110. //
  111. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  112. ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  113. }
  114. //
  115. // Notice that FILE_OPEN_REPARSE_POINT inhibits the reparse behavior.
  116. // Thus, the hard link is established to the local entity, be it a reparse
  117. // point or not.
  118. //
  119. Status = NtOpenFile(
  120. &FileHandle,
  121. FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  122. &ObjectAttributes,
  123. &IoStatusBlock,
  124. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  125. FILE_FLAG_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT
  126. );
  127. if ( !NT_SUCCESS(Status) ) {
  128. BaseSetLastNTError( Status );
  129. __leave;
  130. }
  131. TranslationStatus = RtlDosPathNameToNtPathName_U(
  132. lpLinkName,
  133. &NewFileName,
  134. NULL,
  135. NULL
  136. );
  137. if ( !TranslationStatus ) {
  138. SetLastError(ERROR_PATH_NOT_FOUND);
  139. __leave;
  140. }
  141. NewName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), NewFileName.Length+sizeof(*NewName));
  142. if ( NewName == NULL ) {
  143. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  144. __leave;
  145. }
  146. RtlMoveMemory(NewName->FileName, NewFileName.Buffer, NewFileName.Length);
  147. NewName->ReplaceIfExists = FALSE;
  148. NewName->RootDirectory = NULL;
  149. NewName->FileNameLength = NewFileName.Length;
  150. Status = NtSetInformationFile(
  151. FileHandle,
  152. &IoStatusBlock,
  153. NewName,
  154. NewFileName.Length+sizeof(*NewName),
  155. FileLinkInformation
  156. );
  157. if ( !NT_SUCCESS(Status) ) {
  158. BaseSetLastNTError( Status );
  159. __leave;
  160. }
  161. ReturnValue = TRUE;
  162. } finally {
  163. //
  164. // Cleanup allocate memory and handles
  165. //
  166. if (FileHandle != INVALID_HANDLE_VALUE) {
  167. NtClose( FileHandle );
  168. }
  169. if (NewFileName.Buffer != NULL) {
  170. RtlFreeHeap(RtlProcessHeap(), 0, NewFileName.Buffer);
  171. }
  172. if (OldFileName.Buffer != NULL) {
  173. RtlFreeHeap(RtlProcessHeap(), 0, OldFileName.Buffer);
  174. }
  175. }
  176. return ReturnValue;
  177. }