[Win32utils-devel] Dir.create_junction with FFI

Daniel Berger djberg96 at gmail.com
Fri May 18 16:40:00 UTC 2012


On Fri, May 18, 2012 at 9:52 AM, Heesob Park <phasis at gmail.com> wrote:
> Hi, Dan
>
> 2012/5/19 Daniel Berger <djberg96 at gmail.com>
>>
>> On Fri, May 18, 2012 at 1:35 AM, Heesob Park <phasis at gmail.com> wrote:
>> > Hi,
>> >
>> > 2012/5/18 Daniel Berger <djberg96 at gmail.com>
>> >>
>> >> On Thu, May 17, 2012 at 9:44 PM, Heesob Park <phasis at gmail.com> wrote:
>> >> > Hi,
>> >> >
>> >> > 2012/5/18 Daniel Berger <djberg96 at gmail.com>
>> >> >>
>> >> >> Hi,
>> >> >>
>> >> >> Try as I might, I just cannot get Dir.create_junction to work with
>> >> >> FFI
>> >> >> in the ffi branch of the win32-dir project. The problem is the
>> >> >> REPARSE_JDATA_BUFFER struct. I'm just not sure how to set those
>> >> >> members, specifically, the PathBuffer member. The target looks good,
>> >> >> it's UTF-16LE encoded, but I can't make it work, despite trying
>> >> >> several ways of defining the struct, and setting various struct
>> >> >> members.
>> >> >>
>> >> >> A quick gist for reference: https://gist.github.com/2721257
>> >> >>
>> >> >> Help much appreciated!
>> >> >>
>> >> >
>> >> > The REPARSE_JDATA_BUFFER  is a kind of  the variable length
>> >> > structure.
>> >> > The actual size of structure is determined by ReparseDataLength
>> >> > member.
>> >> >
>> >> > Here is my trial.
>> >> >
>> >> > # define sufficient size of structure.
>> >> > class REPARSE_JDATA_BUFFER < FFI::Struct
>> >> >     layout(
>> >> >       :ReparseTag, :ulong,
>> >> >       :ReparseDataLength, :ushort,
>> >> >       :Reserved, :ushort,
>> >> >       :SubstituteNameOffset, :ushort,
>> >> >       :SubstituteNameLength, :ushort,
>> >> >       :PrintNameOffset, :ushort,
>> >> >       :PrintNameLength, :ushort,
>> >> >       :PathBuffer, [:char, 1024]
>> >> >     )
>> >> > end
>> >> >
>> >> >  # UTF-16LE encoded string
>> >> >   target = "\\??\\".encode('UTF-16LE') + from_path
>> >> >
>> >> >   rdb = REPARSE_JDATA_BUFFER.new
>> >> >   rdb[:ReparseTag] = 2684354563 # IO_REPARSE_TAG_MOUNT_POINT
>> >> >   rdb[:ReparseDataLength] = target.bytesize + 12
>> >> >   rdb[:Reserved] = 0
>> >> >   rdb[:SubstituteNameOffset] = 0
>> >> >   rdb[:SubstituteNameLength] = target.bytesize
>> >> >   rdb[:PrintNameOffset] = target.bytesize + 2
>> >> >   rdb[:PrintNameLength] = 0
>> >> >   rdb[:PathBuffer]  = target
>> >>
>> >> I tried that, but I still got: DeviceIoControl: The data present in
>> >> the reparse point buffer is invalid.
>> >>
>> >> Did it work for you?
>> >>
>> >
>> > Here is a working code.
>> > https://gist.github.com/1c431b679b26c947a7d2
>>
>> Excellent, thank you!
>>
>> Wayne Meissner showed me a trick. For PathBuffer,he said I could
>> declare it as "PathBuffer, [:char, 2]" (since it's really a wchar),
>> and then assign PathBuffer like this:
>>
>> rdb[:PathBuffer].to_ptr.put_bytes(0, target, target.bytesize)
>>
>> However, when I tried that I end up with a "to []" directory as a
>> result and, although it doesn't raise an error in the code, I can't
>> actually cd into that directory after it's created.
>>
>> I also realized there's a bug (in the original version) in that it
>> never checks if the "from" (2nd) argument actually exists! So, I've
>> added that. I'm not sure what it's doing if there's nothing for it to
>> junction from. I think I should add an check to make sure the 2nd arg
>> actually exists before proceeding.
>>
>> Why rdb[:ReparseDataLength] + 8? What's the "+8" for?
>>
>
> The 8 is called REPARSE_DATA_BUFFER_HEADER_SIZE.
> It is calculated by
> sizeof(ReparseTag)+sizeof(ReparseDataLength)+sizeof(Reserved).
>
>>
>> Thanks again for all your help.
>>
> It's my pleasure to help you.

Ok, thanks. I guess I thought that was baked into the rdb.size.

Any idea why the .to_ptr.put_bytes approach gives strange results?

Regards,

Dan


More information about the win32utils-devel mailing list