[Win32utils-devel] Dir.create_junction with FFI

Daniel Berger djberg96 at gmail.com
Fri May 18 15:28:55 UTC 2012


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?

Thanks again for all your help.

Regards,

Dan


More information about the win32utils-devel mailing list