HOWTO: Create Hard Links in Windows NT and Windows 2000

ID: Q234727


The information in this article applies to:


SUMMARY

Windows NT and Windows 2000 support hard links on NTFS disk volumes. Following are two programmatic approaches that exist for creating hard links:

  1. Use CreateHardLink() in Windows 2000.


  2. Use the Win32 BackupWrite() function to construct a hard link in Windows NT and Windows 2000.


If your application requires Windows 2000, use method one because it is simpler; if your application must run on Windows NT and Windows 2000, you should use method two. The remainder of this article provides more detailed information about hard links and how to create them with both methods.


MORE INFORMATION

A hard link is a directory entry for a file. Every file can be considered to have at least one hard link. On NTFS volumes, each file can have multiple hard links, and thus a single file can appear in many directories (or even in the same directory with different names). Since all of the links reference the same file, applications can open any of the links and modify the file. A file is deleted from the file system only after all links to it have been deleted. Once a hard link is created, applications can use it like any other file name. Therefore, you can use the full Win32 file I/O API to access a file through a link. The changes made to a file through one link will be reflected by all other links (because they point to the same file). To remove a link use DeleteFile(). Hard links are supported on NTFS only; they may not be created on FAT or FAT32 volumes. In addition, a hard link must reside on the same volume as the file it references. You cannot create a hard link on one volume that points to a file on another volume. This is because a hard link is a directory entry that points to a file.

The security descriptor for a file belongs to the file, not the links that reference it. Thus, all links to a file grant the same access to the file. If the security descriptor for the file is changed by using one link, all other links will reflect that change.

The hard links created with BackupWrite() and CreateHardLink() are identical; the only difference is in the functions the applications call to create them. Creating hard links with BackupWrite() is supported on Windows 2000 and should be used when your application must also run on Windows NT version 4.0 and earlier. If your application is designed to run on Windows 2000, use CreateHardLink() because it is easier to use.

CreateHardLink() Example

The following code snippet demonstrates how to call CreateHardLink() so that it doesn't modify the file's security descriptor.

/*
   Set security descriptor argument to NULL to leave file's security
   descriptor alone.
*/ 
fCreatedLink = CreateHardLink (pszNewLinkName, pszExistingFileName, 
                               NULL);
if (!fCreatedLink)
   // error occurred, handle it. 
NOTE: PszExistingFileName can be the original filename, or any already-existing link to the file. After this code is executed, pszNewLinkName will refer to the file.

BackupWrite() Example

The following sample code demonstrates how to use BackupWrite() to create a hard link on an NTFS volume. Basically, it "restores" a link to the file.


/*++

Copyright (c) 1996-1999  Microsoft Corporation

Module Name:

   ln.c

Abstract:

This module illustrates how to use the Win32 BackupWrite() API to
create hard links.

NOTE: The new link file name path must be supplied to the BackupWrite()Win32 API call in Unicode.

--*/ 

#ifndef UNICODE
#define UNICODE
#define _UNICODE
#endif

#include <windows.h>
#include <stdio.h>

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

int __cdecl wmain( int argc, wchar_t *argv[] )
{
   LPWSTR FileSource;
   WCHAR FileLink[ MAX_PATH + 1 ];
   LPWSTR FilePart;

   HANDLE hFileSource;

   WIN32_STREAM_ID StreamId;
   DWORD dwBytesWritten;
   LPVOID lpContext;
   DWORD cbPathLen;
   DWORD StreamHeaderSize;

   BOOL bSuccess;

   if (argc != 3)
   {
      printf("Usage: %ls <existing_source_file> <link_file>\n",
             argv[0]);
      return RTN_USAGE;
   }

   FileSource = argv[1];

   // 
   // open existing file that we link to
   // 
   hFileSource = CreateFile(
                           FileSource,
                           FILE_WRITE_ATTRIBUTES,
                           FILE_SHARE_READ | FILE_SHARE_WRITE
                           | FILE_SHARE_DELETE,
                           NULL, // sa
                           OPEN_EXISTING,
                           0,
                           NULL
                           );

   if (hFileSource == INVALID_HANDLE_VALUE)
   {
      printf("CreateFile (source) error! (rc=%lu)\n", GetLastError());
      return RTN_ERROR;
   }

   // 
   // validate and sanitize supplied link path and use the result
   // the full path MUST be Unicode for BackupWrite
   // 
   cbPathLen = GetFullPathNameW( argv[2], MAX_PATH, FileLink, &FilePart);

   if (cbPathLen == 0)
   {
      printf("GetFullPathName error! (rc=%lu)\n", GetLastError());
      return RTN_ERROR;
   }

   cbPathLen = (cbPathLen + 1) * sizeof(WCHAR); // adjust for byte count

   // 
   // it might also be a good idea to verify the existence of the link,
   // (and possibly bail), as the file specified in FileLink will be
   // overwritten if it already exists
   // 

   // 
   // prepare and write the WIN32_STREAM_ID out
   // 
   lpContext = NULL;

   StreamId.dwStreamId = BACKUP_LINK;
   StreamId.dwStreamAttributes = 0;
   StreamId.dwStreamNameSize = 0;
   StreamId.Size.HighPart = 0;
   StreamId.Size.LowPart = cbPathLen;

   // 
   // compute length of variable size WIN32_STREAM_ID
   // 
   StreamHeaderSize = (LPBYTE)&StreamId.cStreamName - (LPBYTE)&
                      StreamId+ StreamId.dwStreamNameSize ;

   bSuccess = BackupWrite(
                         hFileSource,
                         (LPBYTE)&StreamId,  // buffer to write
                         StreamHeaderSize,   // number of bytes to write
                         &dwBytesWritten,
                         FALSE,              // don't abort yet
                         FALSE,              // don't process security
                         &lpContext
                         );

   if (bSuccess)
   {

      // 
      // write out the buffer containing the path
      // 
      bSuccess = BackupWrite(
                            hFileSource,
                            (LPBYTE)FileLink,   // buffer to write
                            cbPathLen,          // number of bytes to write
                            &dwBytesWritten,
                            FALSE,              // don't abort yet
                            FALSE,              // don't process security
                            &lpContext
                            );

      // 
      // free context
      // 
      BackupWrite(
                 hFileSource,
                 NULL,               // buffer to write
                 0,                  // number of bytes to write
                 &dwBytesWritten,
                 TRUE,               // abort
                 FALSE,              // don't process security
                 &lpContext
                 );
   }

   CloseHandle( hFileSource );

   if (!bSuccess)
   {
      printf("BackupWrite error! (rc=%lu)\n", GetLastError());
      return RTN_ERROR;
   }

   return RTN_OK;
} 

Additional query words: ln link symbolic hard POSIX


Keywords          : kbAPI kbFileIO kbKernBase 
Version           : winnt:3.51,4.0
Platform          : winnt 
Issue type        : kbhowto 

Last Reviewed: June 16, 1999