4

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.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • 1
    IF you don't want this migrated to superuser, then ask a programming question. This means specifying acceptable languages and toolsets, noting what APIs you've looked at that don't work for you, what errors or exceptions you are getting from your attempts, and so on. I can't really tell how to answer this as it stands. I won't vote to close, though - just asking you to edit those things in. – Philip Rieck Jun 16 '10 at 17:44
  • Any working method from user mode is acceptable. DeleteFile won't delete readonly files. GetFileAttributes/SetFileAttributes probably doesn't work too well because they take file names rather than handles (good luck changing readonly on the file you just deleted). – Joshua Jun 16 '10 at 19:23
  • What kind of links? This question doesn't make much sense. – Robaticus Jun 16 '10 at 20:07
  • @Robaticus: Ever heard of CreateHardLink? – Joshua Jun 16 '10 at 21:03
  • @Joshua nope, sorry, I haven't. Frankly, your comment about TFS seems a bit of a red-herring, here. Since TFS doesn't really care (much) about the existence of a file on a hard disk somewhere, it's somewhat irrelevant to this question. Now, if you go through your experience and think about the number of different types of links there are in the world, all the way from hyper- to missing-, you might understand why I was confused. – Robaticus Jun 17 '10 at 13:28
  • Well since TFS is the one that wants the readonly bit preserved it's no red herring at all. – Joshua Jun 17 '10 at 15:06

3 Answers3

4

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
  • 277,958
  • 43
  • 419
  • 720
  • I'm pretty sure that only gets you around the file security (ACLs); you will still need to clear the read only attribute. – Luke Jun 18 '10 at 11:44
  • I'd rather not assume I have admin rights; however this might be a solution. I'll try it. – Joshua Jun 18 '10 at 14:00
  • 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 Jun 19 '10 at 01:46
  • FYI, I don't care about race conditions. – Joshua Jun 27 '10 at 15:14
  • 2
    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 Jun 27 '10 at 15:41
  • I wasn't feeling like searching the entire directory tree to find the other link. – Joshua Jun 28 '10 at 22:58
  • `FindFirstFileName` != `FindFirstFile`. No recursive search necessary. – Ben Voigt Jun 29 '10 at 02:09
4

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
  • 40,822
  • 8
  • 72
  • 132
  • Ben, you probably can't see this is your answer w/ the transactional calls removed but rest assured it is. – Joshua Jun 28 '10 at 23:29
2

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
  • 11,211
  • 2
  • 27
  • 38
  • 1
    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 Jul 03 '10 at 23:42
  • That was implied in "there are no potential race conditions" – Joshua Jul 04 '10 at 19:48