How to delete Windows NTFS hard link (mklink /h) while original is in use?

06
2014-04
  • Marnix Klooster

    On a Windows NTFS file system, I have a file (say, orig.mp3). I open this file, through this path orig.mp3, in such a way that it is in use (say, by playing it in VLC).

    Then I create a hard link (cmd /c mklink /h link.mp3 orig.mp3). This results in two NTFS paths pointing to exactly the same file.

    Finally I try to delete linked file again (del link.mp3, or delete in Windows Explorer).

    This fails with an error: "The process cannot access the file because it is being used by another process."

    Why? And more importantly: how can I avoid this (apart from making sure no process has the original file in use)? Can I perhaps tell Windows to do a 'delayed delete', so that the linked file is automatically deleted when the original is no longer in use?

  • Answers
  • Robert Goldwein

    This is quite expected behavior, the hard link is just another name for the same file. E.g., if you have file A.PDF, create hard link B.PDF to the same file, it doesn't matter whether the file is opened under the name A.PDF or B.PDF - it's still the same file, so if this file is simply opened, you can't delete either link.

    The actual reason is that the name is stored as an attribute in the file record of master file table (in case of NTFS) and since the file is opened, you can't delete either link (you can't modify opened file).

    In this case there's nothing like original file, since both names belong to the same (and the only one) file and both names are equal. The file is actually deleted when link count reaches zero.

  • Marnix Klooster

    As detailed in Robert Goldwein's answer, such a hard link cannot be deleted while the file is in use. However, a delayed delete turns out to be possible.

    Damon's comment on this question suggests to use movefile from the Sysinternals Suite.

    In my case, where I want to do this from PowerShell, I can use Lee Holmes's Move-LockedFilelink.mp3 $null, to have Windows delete the file at the next boot.

    Both of the above use the Win32 MoveFileEx function with the MOVEFILE_DELAY_UNTIL_REBOOT flag.

    Update: See https://gist.github.com/marnix/7565364 for a Remove-File-Eventually which I just hacked up. No guarantees. :-)


  • Related Question

    windows xp - How can one undo many hard links?
  • Questioner

    I foolishly used Dupemerge to change all my duplicate files into hard links. Now Windows XP is not running right, eg, explorer won't start.

    Is there a utility which would traverse the filesystem looking for hard links, copy the file, delete the original link, and rename the copy, keeping the original attributes and name?


  • Related Answers
  • Bender

    I doubt that there's a utility for undoing what was done. You can search for duplicates again, check their link counts and attributes (or maybe Dupemerge can help identify hard links to the same files) and do the copying by hand. This may at least help you find out whether hard links are the cause of problems.

  • Redandwhite
    • Since you've converted them into hard links, you might be in luck and they might still show up as duplicates using something like DoubleKiller.

    • Either way, I doubt there's a utility for this exact task.

    If all else fails I recommend a re-install...

  • Tom Wijsman

    to fix the operating system use the system file checker:

    insert the windows xp installation CD

    press CTRL + ALT + DEL to bring up the task manager, go to File > Run (New Task) and type sfc /scannow and click OK.

    note: this will only restore the system files, but it will get you going again. as for other software affected you'll have to re-install or repair install where necessary.

  • Mokubai

    SameFiles Assistant 3.1 might work:

    Same Files Assistant is the hard links managing utility.

    Specifically one feature it has:

    • You can roll back hard links to the regular files at any time.
  • harrymc

    Try Hard Link Magic, it might help.

    Also Microsoft's Junction has the ability to recursively traverse directories and list/delete junction-points.

    Just be careful to create a system restore point before you do these manipulations.

  • Peter John Acklam

    I have written a Perl script that identifies all regular files that are hard links to the same data. The script works fine on UNIX and Cygwin. I haven’t tested it with Strawberry Perl or any other Windows port of Perl, but I thought I’d share it anyhow. On Windows (Cygwin) I would open a terminal and do ./list-dup-hard-links /cygdrive/c/.

    #!/usr/bin/perl
    #
    # NAME
    #
    #   list-dup-hard-links - list regular file names pointing to the same inode
    #
    # SYNOPSIS
    #
    #   list-dup-hard-links DIRECTORY
    #
    # DESCRIPTION
    #
    #   For each inode that is referred to by more than one regular file, print
    #   the inode number and the list of corresponding files.
    #
    # AUTHOR
    #
    #   Peter John Acklam <[email protected]>
    
    use strict;                             # restrict unsafe constructs
    use warnings;                           # control optional warnings
    use File::Find;                         # traverse a file tree
    
    if (@ARGV != 1) {
        die "Usage: $0 DIRECTORY\n";
    }
    
    my $start_dir = shift;                  # starting directory
    my $start_dev = (stat $start_dir)[0];   # device number of where we start
    my %inum2files;                         # map each inode number to file(s)
    
    sub wanted {
        return if -l;                       # skip symlinks
        my @fileinfo = stat();              # get file info
    
        if (-d _) {                         # if a directory
            my $this_dev = $fileinfo[0];    # get device number
            if ($this_dev != $start_dev) {  # if we crossed a device boundary
                $File::Find::prune = 1;     #   mark directory for pruning
                return;                     #   and return
            }
        }
    
        return unless -f _;                 # continue only if a regular file
    
        my $inum = $fileinfo[1];            # get inode number
        push @{ $inum2files{$inum} },       # append this file to the list of
          $File::Find::name;                #   all files with this inode number
    }
    
    find(\&wanted, $start_dir);             # traverse the file tree
    
    while (my ($inum, $files) = each %inum2files) {
        next if @$files < 2;                # skip non-duplicates
    
        print "\nInode number: $inum\n\n"   # print header
          or die "$0: print failed: $!\n";
    
        for my $file (@$files) {
            print "    $file\n"             # print file name
              or die "$0: print failed: $!\n";
        }
    }
    
  • Carlos Almiro

    In Unix, hard links to one file links same "inode number". "stat" function returns file properties like size, mode, alter date, modification date, inode number, ..., but return inode number "0" for any file in Windows. Use perl Win32::IdentifyFile (CPAN) to get a file disk "localization". Hard links "links" to same disk "localization".