views:

103

answers:

3

I have a set of files with multiple links to them.

The files are owned by TFS source control but other links to them are made to them. How do I delete the additional links without clearing the readonly bit.

It's safe to assume:

  • The files have more than one link to them
  • You are not deleting the name owned by TFS
  • There are no potential race conditions
  • You have ACL full control for the files
  • The machine will not lose power, nor will your program be killed unless it takes way too long.

It's not safe to assume:

  • The readonly bit is set (don't set it if its not)
  • You can leave the readonly bit clear if you encounter an error and it was initially set

Do not migrate to superuser -- if migrated there the answer is impossible because no standard tool can do this.

On a hypothetical *nix system in which one needs write permission on a file to delete it, there is a solution involving fchmod(). However the system that exhibiting this behavior is a Windows system.

A: 

This isn't possible. A hard link is just another name for a file; you can have many hard links, but there is only one underlying file object (data, security descriptor, attributes, file times, etc). If the file object has the read only attribute set, then any hard links by definition will also have the attribute set.

Luke
Is there any particular reason this was down-voted?
Luke
Because it was wrong.
Joshua
You asked how to delete a hard-link without clearing the read-only bit. In you answer you (temporarily) clear the read-only bit before deleting the hard-link. My answer is correct for the question posed. Maybe you meant to ask "how to delete a hard-link without *permanently* clearing the read-only bit" or something like that.
Luke
That was implied in "there are no potential race conditions"
Joshua
+1  A: 

Have you tried enabling SeBackupPrivilege and SeRestorePrivilege, which allow admins to relax many of the security checks?

You might find this newsgroup thread helpful.

EDIT: To do it without privileges, and without creating a race condition, you'll need transactional NTFS support present in Vista and above. BTW, you can set attributes using a handle, pass FILE_BASIC_INFO to SetFileInformationByHandle, which can be transacted, see the notes. Or you can use FindFirstFileName to find another hard link to the same file which isn't being deleted, with which to set read-only.

Ben Voigt
I'm pretty sure that only gets you around the file security (ACLs); you will still need to clear the read only attribute.
Luke
I'd rather not assume I have admin rights; however this might be a solution. I'll try it.
Joshua
I suppose your other option would be to read the read-only attribute, remove the read-only attribute, delete the link, and restore the read-only attribute, all within a transaction. I'll add some links within my answer.
Ben Voigt
FYI, I don't care about race conditions.
Joshua
Then just use `FindFirstFileNameW` and `FindNextFileNameW` to get a surviving name of the file which you can use to put read-only back.
Ben Voigt
I wasn't feeling like searching the entire directory tree to find the other link.
Joshua
`FindFirstFileName` != `FindFirstFile`. No recursive search necessary.
Ben Voigt
A: 

Thanks to Ben Voigt:

#include <windows.h>

int main(int argc, char **argv)
{
    while (*++argv) {
        HANDLE h;
        DWORD attrs;

        attrs = GetFileAttributes(*argv);
        SetFileAttributes(*argv, attrs & ~FILE_ATTRIBUTE_READONLY);
        h = CreateFile(*argv, GENERIC_READ|GENERIC_WRITE, 7, NULL, OPEN_EXISTING,
                    FILE_FLAG_DELETE_ON_CLOSE, NULL);
        SetFileAttributes(*argv, attrs);
        if (h != INVALID_HANDLE_VALUE) {
            CloseHandle(h);
        }
    }
}
Joshua
Ben, you probably can't see this is your answer w/ the transactional calls removed but rest assured it is.
Joshua