Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

BACKUP_REPARSE_DATA

Posted on 2006-06-13
23
566 Views
Last Modified: 2008-01-09
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.
0
Comment
Question by:mike2036
  • 10
  • 9
  • 4
23 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 16895004
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)?
0
 

Author Comment

by:mike2036
ID: 16895145
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
0
 
LVL 86

Expert Comment

by:jkr
ID: 16895188
Only directories can have BACKUP_REPARSE_DATA, it does not make sense for files at all. Strange...
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 

Author Comment

by:mike2036
ID: 16895240
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
0
 
LVL 86

Expert Comment

by:jkr
ID: 16895721
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'.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16896590
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!
0
 

Author Comment

by:mike2036
ID: 16904588
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
0
 
LVL 86

Expert Comment

by:jkr
ID: 16904905
Hm, why don't you have your customer send you the file in question?
0
 

Author Comment

by:mike2036
ID: 16904953
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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16905012
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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16905025
>>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).
0
 

Author Comment

by:mike2036
ID: 16905069
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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16905199
>>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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16905384
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;
}
0
 
LVL 30

Expert Comment

by:Axter
ID: 16905408
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.
0
 

Author Comment

by:mike2036
ID: 16907059
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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16907221
>>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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16907289
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.
0
 

Author Comment

by:mike2036
ID: 16912171
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.
0
 
LVL 30

Accepted Solution

by:
Axter earned 250 total points
ID: 16912387
>> Or do I just need to run the restore utility.

You just need to run the utility (Ntbackup).

NtBackup uses backupread and backupwrite API functions, and that's why it's able to preserve the reparse point stream.
0
 

Author Comment

by:mike2036
ID: 16913770
Thanks very much axter!  I see the reparse point in this file.
0
 

Author Comment

by:mike2036
ID: 16915249
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
0
 
LVL 30

Expert Comment

by:Axter
ID: 16917620
>>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.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

792 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question