FSCTL_SET_REPARSE_POINT returns ERROR_INVALID_REPARSE_DATA

Hey,

I’m trying to create a reparse point from userspace with arbitrary data, via DeviceIoControl and FSCTL_SET_REPARSE_POINT. The following code always returns ERROR_INVALID_REPARSE_DATA, no matter what I store in the reparse point. As far as I can see, there aren’t any limitations on what kind of data user-defined reparse points can or cannot store… so the error message doesn’t seem logical. Any thoughts on what might be causing this error, or how to diagnose/fix it? Thanks!

Dustin

  
HANDLE hFile;  
DWORD ret = 0, written = 0, err = 0;  
REPARSE_GUID_DATA_BUFFER \* reparse;  
  
hFile = CreateFile(  
 _T("c:\\test2\\test2.txt"),   
 GENERIC_READ | GENERIC_WRITE ,   
 0,   
 0,  
 OPEN_EXISTING,   
 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,  
 0);   
  
if (hFile == INVALID_HANDLE_VALUE){  
 err = GetLastError();  
 printf("Error %d\n", GetLastError());  
  
}else{  
  
reparse = (REPARSE_GUID_DATA_BUFFER\*)malloc(sizeof(REPARSE_GUID_DATA_BUFFER) + 8);  
 memset(reparse, 0, sizeof(REPARSE_GUID_DATA_BUFFER) + 8);  
  
reparse-\>ReparseGuid = my_guid;  
  
// some arbitrary tag (only for testing at the moment)  
 reparse-\>ReparseTag = 0x15;  
 reparse-\>ReparseDataLength = 8;  
  
// just some meaningless data here  
 reparse-\>GenericReparseBuffer.DataBuffer[0] = 8;  
 reparse-\>GenericReparseBuffer.DataBuffer[1] = 0x83;  
  
if (!DeviceIoControl(hFile,   
 FSCTL_SET_REPARSE_POINT,   
 reparse ,   
 sizeof(REPARSE_GUID_DATA_BUFFER) + reparse-\>ReparseDataLength ,   
 NULL,   
 0,   
 &ret,   
 0)){  
 err = GetLastError();  
 printf("DeviceIoControl Error: %d\n", err);  
 }  
  
free(reparse);  
 CloseHandle(hFile);  
}  
  

It is not entirely arbitrary. You must use a REPARSE_GUID_DATA_BUFFER
structure to store and define your arbitrary date. As well if you are
using this in a real application you need to obtain a reparse point GUID
from Msft. Some of the earlier Msft defined reparse tags do not use
REPARSE_GUID_DATA_BUFFERs (REPARSE_DATA_BUFFER instead), but they appear
to have special handling in the file system.

t.

On Fri, 4 Apr 2008, xxxxx@virtualroadside.com wrote:

Hey,

I’m trying to create a reparse point from userspace with arbitrary data, via DeviceIoControl and FSCTL_SET_REPARSE_POINT. The following code always returns ERROR_INVALID_REPARSE_DATA, no matter what I store in the reparse point. As far as I can see, there aren’t any limitations on what kind of data user-defined reparse points can or cannot store… so the error message doesn’t seem logical. Any thoughts on what might be causing this error, or how to diagnose/fix it? Thanks!

Dustin

 
HANDLE hFile;  
DWORD ret = 0, written = 0, err = 0;  
REPARSE_GUID_DATA_BUFFER \* reparse;  
 
 
hFile = CreateFile(  
_T("c:\\test2\\test2.txt"),  
GENERIC_READ | GENERIC_WRITE ,  
0,  
0,  
OPEN_EXISTING,  
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,  
0);  
 
if (hFile == INVALID_HANDLE_VALUE){  
err = GetLastError();  
printf("Error %d\n", GetLastError());  
 
}else{  
 
reparse = (REPARSE_GUID_DATA_BUFFER\*)malloc(sizeof(REPARSE_GUID_DATA_BUFFER) + 8);  
memset(reparse, 0, sizeof(REPARSE_GUID_DATA_BUFFER) + 8);  
 
reparse-\>ReparseGuid = my_guid;  
 
// some arbitrary tag (only for testing at the moment)  
reparse-\>ReparseTag = 0x15;  
reparse-\>ReparseDataLength = 8;  
 
// just some meaningless data here  
reparse-\>GenericReparseBuffer.DataBuffer[0] = 8;  
reparse-\>GenericReparseBuffer.DataBuffer[1] = 0x83;  
 
 
if (!DeviceIoControl(hFile,  
FSCTL_SET_REPARSE_POINT,  
reparse ,  
sizeof(REPARSE_GUID_DATA_BUFFER) + reparse-\>ReparseDataLength ,  
NULL,  
0,  
&ret,  
0)){  
err = GetLastError();  
printf("DeviceIoControl Error: %d\n", err);  
}  
 
free(reparse);  
CloseHandle(hFile);  
}  
 

NTFSD is sponsored by OSR

For our schedule debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@openmars.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

> It is not entirely arbitrary. You must use a REPARSE_GUID_DATA_BUFFER

structure to store and define your arbitrary date.

Right, I do use a REPARSE_GUID_DATA_BUFFER, and I set the ReparseTag and ReparseGuid data members to (properly formatted, at least) values. The arbitrary data I was referring to is the ->GenericReparseBuffer.DataBuffer members… since that member doesn’t seem to have any constraints.

As well if you are using this in a real application you need to obtain
a reparse point GUID from Msft.

At the moment its just for testing. However, I thought you needed to obtain a reparse tag, not a GUID from Msft?

Some of the earlier Msft defined reparse tags do not use
REPARSE_GUID_DATA_BUFFERs (REPARSE_DATA_BUFFER instead),
but they appear to have special handling in the file system.

Correct. Interestingly enough I’ve used some code that I’ve found to create junction points and etc, and these work with FSCTL_SET_REPARSE_POINT with no errors. I only come across the error when I change things to try and use REPARSE_GUID_DATA_BUFFER.

Thanks.

Have you tried memcpying the guid instead of assignment? I know that’s
technically legal, but it’s the only thing that jumped out at me as
sketchy.

~Eric

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@virtualroadside.com
Sent: Friday, April 04, 2008 11:44 AM
To: Windows File Systems Devs Interest List
Subject: RE:[ntfsd] FSCTL_SET_REPARSE_POINT returns
ERROR_INVALID_REPARSE_DATA

It is not entirely arbitrary. You must use a REPARSE_GUID_DATA_BUFFER
structure to store and define your arbitrary date.

Right, I do use a REPARSE_GUID_DATA_BUFFER, and I set the ReparseTag and
ReparseGuid data members to (properly formatted, at least) values. The
arbitrary data I was referring to is the
->GenericReparseBuffer.DataBuffer members… since that member doesn’t
seem to have any constraints.

As well if you are using this in a real application you need to obtain

a reparse point GUID from Msft.

At the moment its just for testing. However, I thought you needed to
obtain a reparse tag, not a GUID from Msft?

Some of the earlier Msft defined reparse tags do not use
REPARSE_GUID_DATA_BUFFERs (REPARSE_DATA_BUFFER instead), but they
appear to have special handling in the file system.

Correct. Interestingly enough I’ve used some code that I’ve found to
create junction points and etc, and these work with
FSCTL_SET_REPARSE_POINT with no errors. I only come across the error
when I change things to try and use REPARSE_GUID_DATA_BUFFER.

Thanks.


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars (including our new
fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@edsiohio.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

> Have you tried memcpying the guid instead of assignment? I know that’s

technically legal, but it’s the only thing that jumped out at me as sketchy.

Yep, my original code used memcpy, then I noticed other people just assigned GUID’s directly in their code (since structs get directly copied as value types), so I did that too since it seemed more intuitive to read. :slight_smile:

You are using an existing reparse tag that is used by other application.
Try to use other tag value. You did not set GUID values to your buffer. You
need copy 16 bytes of GUID to your data buffer instead of assigning a
pointer to it.

wrote in message news:xxxxx@ntfsd…
> Hey,
>
> I’m trying to create a reparse point from userspace with arbitrary data,
> via DeviceIoControl and FSCTL_SET_REPARSE_POINT. The following code always
> returns ERROR_INVALID_REPARSE_DATA, no matter what I store in the reparse
> point. As far as I can see, there aren’t any limitations on what kind of
> data user-defined reparse points can or cannot store… so the error
> message doesn’t seem logical. Any thoughts on what might be causing this
> error, or how to diagnose/fix it? Thanks!
>
> Dustin
>
>
> <br>&gt;<br>&gt; HANDLE hFile;<br>&gt; DWORD ret = 0, written = 0, err = 0;<br>&gt; REPARSE_GUID_DATA_BUFFER * reparse;<br>&gt;<br>&gt;<br>&gt; hFile = CreateFile(<br>&gt; _T("c:\\test2\\test2.txt"),<br>&gt; GENERIC_READ | GENERIC_WRITE ,<br>&gt; 0,<br>&gt; 0,<br>&gt; OPEN_EXISTING,<br>&gt; FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,<br>&gt; 0);<br>&gt;<br>&gt; if (hFile == INVALID_HANDLE_VALUE){<br>&gt; err = GetLastError();<br>&gt; printf("Error %d\n", GetLastError());<br>&gt;<br>&gt; }else{<br>&gt;<br>&gt; reparse = <br>&gt; (REPARSE_GUID_DATA_BUFFER*)malloc(sizeof(REPARSE_GUID_DATA_BUFFER) + 8);<br>&gt; memset(reparse, 0, sizeof(REPARSE_GUID_DATA_BUFFER) + 8);<br>&gt;<br>&gt; reparse-&gt;ReparseGuid = my_guid;<br>&gt;<br>&gt; // some arbitrary tag (only for testing at the moment)<br>&gt; reparse-&gt;ReparseTag = 0x15;<br>&gt; reparse-&gt;ReparseDataLength = 8;<br>&gt;<br>&gt; // just some meaningless data here<br>&gt; reparse-&gt;GenericReparseBuffer.DataBuffer[0] = 8;<br>&gt; reparse-&gt;GenericReparseBuffer.DataBuffer[1] = 0x83;<br>&gt;<br>&gt;<br>&gt; if (!DeviceIoControl(hFile,<br>&gt; FSCTL_SET_REPARSE_POINT,<br>&gt; reparse ,<br>&gt; sizeof(REPARSE_GUID_DATA_BUFFER) + reparse-&gt;ReparseDataLength ,<br>&gt; NULL,<br>&gt; 0,<br>&gt; &amp;ret,<br>&gt; 0)){<br>&gt; err = GetLastError();<br>&gt; printf("DeviceIoControl Error: %d\n", err);<br>&gt; }<br>&gt;<br>&gt; free(reparse);<br>&gt; CloseHandle(hFile);<br>&gt; }<br>&gt;<br>&gt;
>
>

Okay. Well if you have the basic’s covered. Fire up windbg and set a
break point in ntfs and step through.

t.

On Fri, 4 Apr 2008, xxxxx@virtualroadside.com wrote:

> It is not entirely arbitrary. You must use a REPARSE_GUID_DATA_BUFFER
> structure to store and define your arbitrary date.

Right, I do use a REPARSE_GUID_DATA_BUFFER, and I set the ReparseTag and ReparseGuid data members to (properly formatted, at least) values. The arbitrary data I was referring to is the ->GenericReparseBuffer.DataBuffer members… since that member doesn’t seem to have any constraints.

> As well if you are using this in a real application you need to obtain
> a reparse point GUID from Msft.

At the moment its just for testing. However, I thought you needed to obtain a reparse tag, not a GUID from Msft?

> Some of the earlier Msft defined reparse tags do not use
> REPARSE_GUID_DATA_BUFFERs (REPARSE_DATA_BUFFER instead),
> but they appear to have special handling in the file system.

Correct. Interestingly enough I’ve used some code that I’ve found to create junction points and etc, and these work with FSCTL_SET_REPARSE_POINT with no errors. I only come across the error when I change things to try and use REPARSE_GUID_DATA_BUFFER.

Thanks.


NTFSD is sponsored by OSR

For our schedule debugging and file system seminars
(including our new fs mini-filter seminar) visit:
http://www.osr.com/seminars

You are currently subscribed to ntfsd as: xxxxx@openmars.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

> You are using an existing reparse tag that is used by other application. Try to use other tag value.

On a whim, I ran the code in a loop with tag values up to 0x0FFFFFFF, all returned the same error (so far… still running, but after a few million I’m pretty sure its not making a difference).

You did not set GUID values to your buffer. You need copy 16 bytes of GUID to your data buffer
instead of assigning a pointer to it.

My original code used memcpy instead, both had the same results. Do you suppose that you need to register the GUID somewhere for it to recognize it?

Okay. Well if you have the basic’s covered. Fire up windbg and set a break point
in ntfs and step through.

Yeah, I think that’s gonna be the next step here… was just hoping someone else had hit this issue before.

Dustin

Is your volume a NTFS volume? Try to change ReparseDataLength to 9.

wrote in message news:xxxxx@ntfsd…
> Hey,
>
> I’m trying to create a reparse point from userspace with arbitrary data,
> via DeviceIoControl and FSCTL_SET_REPARSE_POINT. The following code always
> returns ERROR_INVALID_REPARSE_DATA, no matter what I store in the reparse
> point. As far as I can see, there aren’t any limitations on what kind of
> data user-defined reparse points can or cannot store… so the error
> message doesn’t seem logical. Any thoughts on what might be causing this
> error, or how to diagnose/fix it? Thanks!
>
> Dustin
>
>
> <br>&gt;<br>&gt; HANDLE hFile;<br>&gt; DWORD ret = 0, written = 0, err = 0;<br>&gt; REPARSE_GUID_DATA_BUFFER * reparse;<br>&gt;<br>&gt;<br>&gt; hFile = CreateFile(<br>&gt; _T("c:\\test2\\test2.txt"),<br>&gt; GENERIC_READ | GENERIC_WRITE ,<br>&gt; 0,<br>&gt; 0,<br>&gt; OPEN_EXISTING,<br>&gt; FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,<br>&gt; 0);<br>&gt;<br>&gt; if (hFile == INVALID_HANDLE_VALUE){<br>&gt; err = GetLastError();<br>&gt; printf("Error %d\n", GetLastError());<br>&gt;<br>&gt; }else{<br>&gt;<br>&gt; reparse = <br>&gt; (REPARSE_GUID_DATA_BUFFER*)malloc(sizeof(REPARSE_GUID_DATA_BUFFER) + 8);<br>&gt; memset(reparse, 0, sizeof(REPARSE_GUID_DATA_BUFFER) + 8);<br>&gt;<br>&gt; reparse-&gt;ReparseGuid = my_guid;<br>&gt;<br>&gt; // some arbitrary tag (only for testing at the moment)<br>&gt; reparse-&gt;ReparseTag = 0x15;<br>&gt; reparse-&gt;ReparseDataLength = 8;<br>&gt;<br>&gt; // just some meaningless data here<br>&gt; reparse-&gt;GenericReparseBuffer.DataBuffer[0] = 8;<br>&gt; reparse-&gt;GenericReparseBuffer.DataBuffer[1] = 0x83;<br>&gt;<br>&gt;<br>&gt; if (!DeviceIoControl(hFile,<br>&gt; FSCTL_SET_REPARSE_POINT,<br>&gt; reparse ,<br>&gt; sizeof(REPARSE_GUID_DATA_BUFFER) + reparse-&gt;ReparseDataLength ,<br>&gt; NULL,<br>&gt; 0,<br>&gt; &amp;ret,<br>&gt; 0)){<br>&gt; err = GetLastError();<br>&gt; printf("DeviceIoControl Error: %d\n", err);<br>&gt; }<br>&gt;<br>&gt; free(reparse);<br>&gt; CloseHandle(hFile);<br>&gt; }<br>&gt;<br>&gt;
>
>

Thank you, I completely missed that. I knew there was something wrong
with how the OP was handling the size but it flew over my head. I find
it easier to keep track of what I’m doing if I do as follows:

#define RP_DATASIZE = 8 /* or something */

int foo ()
{
/* abbreviated */
RGDB *buffer = NULL;

/* or #define this too, if appropriate */
size_t buffer_size = sizeof (RGDB) + RP_DATASIZE - 1;

buffer = malloc (buffer_size);

buffer->ReparseDataLength = RP_DATASIZE;

/* set other stuff */

DeviceIoControl(hFile, FSCTL_SET_REPARSE_POINT, buffer ,
buffer_size , NULL, 0, &ret, 0);

}

That way you’re not constantly looking after that extra byte.

I’m curious if that’s the source of the problem. I’d be sort of
surprised if DeviceIoControl actually checks the real buffer length.
After all, if you wanted to copy the RP data from one file to another
and you don’t care what’s in it, you could just malloc a 64k buffer and
use the length you get back from GET_RP as the argument to SET_RP. That
seems like a legitimate thing to do.

~Eric

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Shangwu
Sent: Friday, April 04, 2008 1:11 PM
To: Windows File Systems Devs Interest List
Subject: Re:[ntfsd] FSCTL_SET_REPARSE_POINT returns
ERROR_INVALID_REPARSE_DATA

Is your volume a NTFS volume? Try to change ReparseDataLength to 9.

> Is your volume a NTFS volume? Try to change ReparseDataLength to 9.

Yes it is an NTFS volume. FSCTL_SET_REPARSE_POINT works fine when creating junction points… just not when doing the user-defined reparse point.

I’m curious if that’s the source of the problem. I’d be sort of
surprised if DeviceIoControl actually checks the real buffer length.

Yeah, that would be really weird… but, apparently it doesn’t (or at least it doesn’t make a difference).

Thanks for pointing out that error… unfortunately it still doesn’t change the error code. Along those lines, heres a short of some other things I’ve tried:

  • Setting the buffer sizes to multiples of 8/32/64
  • Adjusting the token privileges to get SeBackupPrivilege
  • Changing the handle open flags from FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS to other various combinations of flags

However, none of these have made any difference. Its really weird… the thing that gets me is that code to create junction points works fine, but when I change it to use the user-defined stuff, no dice.

Something I was thinking, perhaps DeviceIoControl asks drivers/filters installed if the reparse point is of valid format – since at the moment I don’t have one created to actually handle this stuff yet. However, that doesn’t make sense since MS says by using FILE_FLAG_OPEN_REPARSE_POINT… “Normal reparse point processing will not occur”.

Can you post your definition of REPARSE_GUID_DATA_BUFFER here? Probably your
data structure is obsolete.

wrote in message news:xxxxx@ntfsd…
> Hey,
>
> I’m trying to create a reparse point from userspace with arbitrary data,
> via DeviceIoControl and FSCTL_SET_REPARSE_POINT. The following code always
> returns ERROR_INVALID_REPARSE_DATA, no matter what I store in the reparse
> point. As far as I can see, there aren’t any limitations on what kind of
> data user-defined reparse points can or cannot store… so the error
> message doesn’t seem logical. Any thoughts on what might be causing this
> error, or how to diagnose/fix it? Thanks!
>
> Dustin
>
>
> <br>&gt;<br>&gt; HANDLE hFile;<br>&gt; DWORD ret = 0, written = 0, err = 0;<br>&gt; REPARSE_GUID_DATA_BUFFER * reparse;<br>&gt;<br>&gt;<br>&gt; hFile = CreateFile(<br>&gt; _T("c:\\test2\\test2.txt"),<br>&gt; GENERIC_READ | GENERIC_WRITE ,<br>&gt; 0,<br>&gt; 0,<br>&gt; OPEN_EXISTING,<br>&gt; FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,<br>&gt; 0);<br>&gt;<br>&gt; if (hFile == INVALID_HANDLE_VALUE){<br>&gt; err = GetLastError();<br>&gt; printf("Error %d\n", GetLastError());<br>&gt;<br>&gt; }else{<br>&gt;<br>&gt; reparse = <br>&gt; (REPARSE_GUID_DATA_BUFFER*)malloc(sizeof(REPARSE_GUID_DATA_BUFFER) + 8);<br>&gt; memset(reparse, 0, sizeof(REPARSE_GUID_DATA_BUFFER) + 8);<br>&gt;<br>&gt; reparse-&gt;ReparseGuid = my_guid;<br>&gt;<br>&gt; // some arbitrary tag (only for testing at the moment)<br>&gt; reparse-&gt;ReparseTag = 0x15;<br>&gt; reparse-&gt;ReparseDataLength = 8;<br>&gt;<br>&gt; // just some meaningless data here<br>&gt; reparse-&gt;GenericReparseBuffer.DataBuffer[0] = 8;<br>&gt; reparse-&gt;GenericReparseBuffer.DataBuffer[1] = 0x83;<br>&gt;<br>&gt;<br>&gt; if (!DeviceIoControl(hFile,<br>&gt; FSCTL_SET_REPARSE_POINT,<br>&gt; reparse ,<br>&gt; sizeof(REPARSE_GUID_DATA_BUFFER) + reparse-&gt;ReparseDataLength ,<br>&gt; NULL,<br>&gt; 0,<br>&gt; &amp;ret,<br>&gt; 0)){<br>&gt; err = GetLastError();<br>&gt; printf("DeviceIoControl Error: %d\n", err);<br>&gt; }<br>&gt;<br>&gt; free(reparse);<br>&gt; CloseHandle(hFile);<br>&gt; }<br>&gt;<br>&gt;
>
>

> Can you post your definition of REPARSE_GUID_DATA_BUFFER here? Probably

your data structure is obsolete.

Hehe… I hope not, I’m using Visual Studio 2008 (though, its the express edition). Anyways, from WinNt.h:

//
// The reparse GUID structure is used by all 3rd party layered drivers to
// store data in a reparse point. For non-Microsoft tags, The GUID field
// cannot be GUID_NULL.
// The constraints on reparse tags are defined below.
// Microsoft tags can also be used with this format of the reparse point buffer.
//

typedef struct _REPARSE_GUID_DATA_BUFFER {
DWORD ReparseTag;
WORD ReparseDataLength;
WORD Reserved;
GUID ReparseGuid;
struct {
BYTE DataBuffer[1];
} GenericReparseBuffer;
} REPARSE_GUID_DATA_BUFFER, *PREPARSE_GUID_DATA_BUFFER;

#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer)

//
// Maximum allowed size of the reparse data.
//

#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )

//
// Predefined reparse tags.
// These tags need to avoid conflicting with IO_REMOUNT defined in ntos\inc\io.h
//

#define IO_REPARSE_TAG_RESERVED_ZERO (0)
#define IO_REPARSE_TAG_RESERVED_ONE (1)

//
// The value of the following constant needs to satisfy the following conditions:
// (1) Be at least as large as the largest of the reserved tags.
// (2) Be strictly smaller than all the tags in use.
//

#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE

//
// The reparse tags are a DWORD. The 32 bits are laid out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// ±±±±±----------------------±------------------------------+
// |M|R|N|R| Reserved bits | Reparse Tag Value |
// ±±±±±----------------------±------------------------------+
//
// M is the Microsoft bit. When set to 1, it denotes a tag owned by Microsoft.
// All ISVs must use a tag with a 0 in this position.
// Note: If a Microsoft tag is used by non-Microsoft software, the
// behavior is not defined.
//
// R is reserved. Must be zero for non-Microsoft tags.
//
// N is name surrogate. When set to 1, the file represents another named
// entity in the system.
//
// The M and N bits are OR-able.
// The following macros check for the M and N bit values:
//

//
// Macro to determine whether a reparse point tag corresponds to a tag
// owned by Microsoft.
//

#define IsReparseTagMicrosoft(_tag) ( \
((_tag) & 0x80000000) \
)

//
// Macro to determine whether a reparse point tag is a name surrogate
//

#define IsReparseTagNameSurrogate(_tag) ( \
((_tag) & 0x20000000) \
)

#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
#define IO_REPARSE_TAG_HSM (0xC0000004L)
#define IO_REPARSE_TAG_SIS (0x80000007L)
#define IO_REPARSE_TAG_DFS (0x8000000AL)
#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
#define IO_REPARSE_TAG_DFSR (0x80000012L)

NTSTATUS CreateReparsePoint(POBJECT_ATTRIBUTES poa, LPCWSTR SubstituteName, LPCWSTR PrintName)
{
HANDLE hFile;
IO_STATUS_BLOCK iosb;

NTSTATUS status = ZwCreateFile(&hFile, FILE_ALL_ACCESS, poa, &iosb, 0,
0, 0, FILE_CREATE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);

if (0 > status) return status;

USHORT SubstituteNameLength = (USHORT)wcslen(SubstituteName) * sizeof WCHAR;
USHORT PrintNameLength = (USHORT)wcslen(PrintName) * sizeof WCHAR;

USHORT cb = 2 * sizeof (WCHAR) + FIELD_OFFSET(REPARSE_DATA_BUFFER,
MountPointReparseBuffer.PathBuffer) + SubstituteNameLength + PrintNameLength;

PREPARSE_DATA_BUFFER prdb = (PREPARSE_DATA_BUFFER)alloca(cb);

RtlZeroMemory(prdb, cb);

prdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
prdb->ReparseDataLength = cb - REPARSE_DATA_BUFFER_HEADER_SIZE;
prdb->MountPointReparseBuffer.SubstituteNameLength = SubstituteNameLength;
prdb->MountPointReparseBuffer.PrintNameLength = PrintNameLength;
prdb->MountPointReparseBuffer.PrintNameOffset = SubstituteNameLength + sizeof (WCHAR);

memcpy(prdb->MountPointReparseBuffer.PathBuffer, SubstituteName, SubstituteNameLength);
memcpy(RtlOffsetToPointer(prdb->MountPointReparseBuffer.PathBuffer,
SubstituteNameLength + sizeof (WCHAR)),
PrintName, PrintNameLength);

status = ZwFsControlFile(hFile, 0, 0, 0, &iosb, FSCTL_SET_REPARSE_POINT, prdb, cb, 0, 0);

if (0 > status)
{
static FILE_DISPOSITION_INFORMATION fdi = { TRUE };
ZwSetInformationFile(hFile, &iosb, &fdi, sizeof fdi, FileDispositionInformation);
}

ZwClose(hFile);

return status;
}

CreateReparsePoint(poa, L"\??\f:\txt\src", L"any name")

Max: Thanks for the code… but as previously stated above, I don’t want to create a mount point or junction point… I can get those bits of code working correctly without an error. Its the matter of having user-defined reparse points that seems to be so elusive…

NTSTATUS CreateCustomReparsePoint(POBJECT_ATTRIBUTES poa, const GUID& ReparseGuid, LPCVOID lpData, DWORD cbData)
{
HANDLE hFile;
IO_STATUS_BLOCK iosb;

NTSTATUS status = ZwCreateFile(&hFile, FILE_ALL_ACCESS, poa, &iosb, 0,
0, 0, FILE_CREATE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);

if (0 > status) return status;

DWORD cb = FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer[cbData]);

PREPARSE_GUID_DATA_BUFFER prdb = (PREPARSE_GUID_DATA_BUFFER)alloca(cb);

prdb->ReparseTag = 0x15;
prdb->Reserved = 0;
prdb->ReparseDataLength = (USHORT)cbData;
prdb->ReparseGuid = ReparseGuid;
memcpy(prdb->GenericReparseBuffer.DataBuffer, lpData, cbData);

DbgBreak();
status = ZwFsControlFile(hFile, 0, 0, 0, &iosb, FSCTL_SET_REPARSE_POINT, prdb, cb, 0, 0);

if (0 > status)
{
static FILE_DISPOSITION_INFORMATION fdi = { TRUE };
ZwSetInformationFile(hFile, &iosb, &fdi, sizeof fdi, FileDispositionInformation);
}

ZwClose(hFile);

return status;
}

NTSTATUS TestReparsePoint(POBJECT_ATTRIBUTES poa)
{
HANDLE hFile;
IO_STATUS_BLOCK iosb;

NTSTATUS status = ZwOpenFile(&hFile, FILE_GENERIC_READ, poa, &iosb,
FILE_SHARE_READ, FILE_OPEN_REPARSE_POINT|FILE_SYNCHRONOUS_IO_NONALERT);

if (0 > status) return status;

PREPARSE_GUID_DATA_BUFFER prdb = 0;

DWORD cb = 0, rcb = sizeof REPARSE_GUID_DATA_BUFFER + 0x100;
do
{

if (cb < rcb) prdb = (PREPARSE_GUID_DATA_BUFFER)alloca(rcb - cb), cb = rcb;

status = ZwFsControlFile(hFile, 0, 0, 0, &iosb, FSCTL_GET_REPARSE_POINT, 0, 0, prdb, cb);

rcb = FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER,
GenericReparseBuffer.DataBuffer[prdb->ReparseDataLength]);

} while(status == STATUS_BUFFER_OVERFLOW);

ZwClose(hFile);

if (0 <= status)
{
WCHAR sz[39];
StringFromGUID2(prdb->ReparseGuid, sz, 39);
DbgPrint(“%X %S %s\n”, prdb->ReparseTag, sz, prdb->GenericReparseBuffer.DataBuffer);
}

return status;
}

#pragma comment(lib, “ole32.lib”)
static char s_d = “some data”;
if (0 <= CreateCustomReparsePoint(poa, __uuidof(IUnknown), s_d, sizeof s_d))
TestReparsePoint(poa);

In your original code example try changing

sizeof(REPARSE_GUID_DATA_BUFFER) + reparse->ReparseDataLength

to

REPARSE_GUID_DATA_BUFFER_HEADER_SIZE + reparse->ReparseDataLength

That’s totally maddening… Rick, you’re right. the buffer header size is 4 bytes less than sizeof(REPARSE_GUID_DATA_BUFFER).

As a sidenote, max’s code (which took the same thing into account) also worked (though, I just grabbed the allocating code, and didn’t use the Zw* stuff since I was in user mode).

Thanks a ton!