Link to home
Start Free TrialLog in
Avatar of mike2036
mike2036Flag for United States of America

asked on

BACKUP_REPARSE_DATA

I need to test a scenario where a file contains a BACKUP_REPARSE_DATA stream.  We have a customer that is unable to perform a BackupWrite() to this stream; they get an ERROR_ACCESS_DENIED.  I want to try performing a normal ReadFile() when I encounter a BACKUP_REPARSE_DATA and do some in-house testing before I build a patch.  What's the easiest way to create a test file with this stream?  Thanks for any help.
Avatar of jkr
jkr
Flag of Germany image

Can you check whether the ACLs on the reparse point target prohibit access (you can use e.g. http://www.sysinternals.com/Utilities/Junction.html to find that target)?
Avatar of mike2036

ASKER

Hi jkr,

Thanks for your response.  The customer can successfully BackupRead() the BACKUP_REPARSE_DATA stream but gets the 0x5 on BackupWrite().  The customer is running with admin rights.  We BackupWrite() to a temporary file we create and then rename to the destination file name (located in a separate destination folder) when the write is completed.  If understand your question correctly, if the ACLs prohibited access on the reparse point target, would we not fail on BackupRead()?  I've used the junction utility to attempt to make files have reparse points, but it apparently only sets reparse points on directories.

-Mike
Only directories can have BACKUP_REPARSE_DATA, it does not make sense for files at all. Strange...
According to an MSDN article, and the trace logs our app produces, it appears files can and do have BACKUP_REPARSE_DATA streams:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/reparse_points_and_file_operations.asp
Argh, yes, I forgot that you can set a NTFS hard link on files that way. BTW, the IMO easiest way to create such a file is calling 'DeviceIoControl()' with 'FSCTL_SET_REPARSE_POINT' or as shown in the code of 'ln' for Win32 at http://ashedel.chat.ru/source/ln/ln.c - the tricky part is filling the 'REPARSE_DATA_BUFFER'.
Hi mike2036,
> We have a customer that is unable to perform a BackupWrite() to this
> stream; they get an ERROR_ACCESS_DENIED.

FYI:
Have your customer check the antivirus program.
Antivirus programs like Symantic, can cause problems with BACKUP_REPARSE_DATA.

David Maisonave (Axter)
Cheers!
I've been tinkering with the ln.c program (thanks for the link).  Unfortunately I haven't been able to successfully create a file that contains both reparse points and actual data.  It looks like there used to be a reparse tag of type IO_REPARSE_TAG_SYMBOLIC_LINK but that no longer is supported.  The author had it commented out and has the symbolic linking to always do a mount point, which is essentially a directory and not a file.  *Sigh*.  Ideally I would symbolically link a target file to a source file, and the target file would probably contain reparse points.  I've tried all the different reparse tags with no success.  Is there a way to create a symbolic link specific to a file that's not a mount point?

-Mike
Hm, why don't you have your customer send you the file in question?
I had thought of that, but I wasn't sure if the reparse points would be lost when they make a copy of the file.  I figured when they copied it, the reparse points would be resolved in the file system and not represented as a separate stream.  I guess it's worth a try though.
You need a driver and a service application to create a file that is a reparse point.
It's no easy task.

>>Hm, why don't you have your customer send you the file in question?

This is not practical, unless you have a utility program from the reparse point driver author.

If you try to copy a file that has a reparse point, it will normally trigger a recall of (or redirect to) the original file, so you will not get the reparse data, and instead get what the reparse point is pointing to.

What can sometimes work is if you do a backup of the file using backup software that uses the Windows Backup API functions.
>>if the reparse points would be lost when they make a copy of the file.  

Noramlly, you would not get the repase point data, and instead you would get what it's pointing to, or what it represents (the original file).
Hi Axter,

Thanks for your posts.  Do you know of any backup software that's freeware (or relatively cheap) that might accomplish this?  I've tried using Microsoft's backup utlity with no luck.  It's too bad there's no effective way to simulate reparse points without having to install a backup utility.
>>Do you know of any backup software that's freeware (or relatively cheap) that might accomplish this?

I've been told that Nt-Backup can do it, but I've never tried it myself.
If you're interested in creating your own utility program, you should be able to read the raw data from the file by opening the file via following method:
template<class T>
bool OpenReparseFile(const T *fileName,HANDLE &hFile)
{
      _ASSERT(fileName);
      hFile = CreateFileT(fileName,
                                    GENERIC_READ | GENERIC_WRITE,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                                    NULL,
                                    OPEN_EXISTING,
                                    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN,
                                    NULL);

      if( hFile == INVALID_HANDLE_VALUE )
      {
            return FALSE;
      }

      return TRUE;
}

Then use the handle to read the file using Backup API functions:
      for(;;)
      {
            DWORD bytesRead = 0,bytesWritten = 0;
            if(!BackupRead( srcHandle, writeBuf,writeBufSize, &bytesRead, FALSE, TRUE, &srcContext ) )
            {
                  ret = FALSE;
                  break;
            }
            
            //done if bytes read is zero
            if (bytesRead == 0)
                  break;

This will give you the RAW data that should include all the streams.
You could store the raw data in a binary file, and then when you recieve the data in the destination box, you can write to the file using BackupWrite API function.
To open that target file, you'll want to use the following method:

template<class T>
bool OpenReparseFileForRestore(const T *fileName,HANDLE &hFile)
{
      _ASSERT(fileName);
      hFile = CreateFileT(fileName,
                                    GENERIC_READ | GENERIC_WRITE | WRITE_DAC| WRITE_OWNER,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                                    NULL,
                                    CREATE_ALWAYS ,
                                    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN,
                                    NULL);

      if( hFile == INVALID_HANDLE_VALUE ) {
            return FALSE;
      }

      return TRUE;
}
FYI:
You can replace above CreateFileT with CreateFile, or if you want to keep the function as a template, you can add the following to your code:
inline HANDLE CreateFileT( IN LPCSTR lpFileName, IN DWORD dwDesiredAccess, IN DWORD dwShareMode, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes, IN DWORD dwCreationDisposition, IN DWORD dwFlagsAndAttributes, IN HANDLE hTemplateFile     ) {return CreateFileA(GetValidPath(lpFileName), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);}
inline HANDLE CreateFileT( IN LPCWSTR lpFileName, IN DWORD dwDesiredAccess, IN DWORD dwShareMode, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes, IN DWORD dwCreationDisposition, IN DWORD dwFlagsAndAttributes, IN HANDLE hTemplateFile     ) {return CreateFileW(GetValidPath(lpFileName), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);}

By keeping it as a template, you can use it with both UNICODE or ANSI file names.
Thanks for the sample code Axter.  I can't get NTBackup to produce a file with reparse points.  :(  It looks to only work with tape drives, and I don't have a tape drive handy for testing.  I tried using a floppy drive (yes I'm that desperate) but the bkp file is bigger than 1.44MB!  Are there any tape drive emulators out there?  Are there any usable driver/services I could use to build reparse data streams?  Man I can't believe how hard it has been just trying to create a test file.
>>I tried using a floppy drive

You don't need to use a floppy.
I know the interface would lead you to believe that, but when you try to backup the file, ask to select from the list.
It should then prompt you for a file name (c:\Backup.bkf).
You should be able to back it up to your C: drive, as long as your source is a sub folder.
If you want to try the backup I just created of files with reparse point, download the following file:
http://axter.com/Backup.bkf.zip

You'll want to right click the above link, and select save target as.
Axter,

Thanks for the zip file.  How does the backup.bkf file work with backupread() and backupwrite()?  Or do I just need to run the restore utility.  Forgive my ignorance.
ASKER CERTIFIED SOLUTION
Avatar of Axter
Axter
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks very much axter!  I see the reparse point in this file.
Okay, a follow-up question:

I can successfully read the reparse points and write them to a destination folder.  When I write the file to the destination, I create a temporary file that I then rename to back to the original file name.  However, when I attempt to do this (via MoveFile), I get an ERROR_CANT_ACCESS_FILE.  I was also getting this error in CreateFile until I took your advice and set the FLAG_OPEN_REPARSE_POINT attribute on.  So is there a way to rename a file with reparse points?  Thanks for your continued help.

-Mike
>>So is there a way to rename a file with reparse points?

You should be able to rename the  file, but probably not by using the MoveFile API function.

Try use rename function.