ntfsutils/junction.py
def new_junction_reparse_buffer(path=None):    
    """
    Given a path, return a pair containing a new REPARSE_DATA_BUFFER and the
    length of the buffer (not necessarily the same as sizeof due to packing
    issues).
    If no path is provided, the maximum length is assumed.
    """

    if path is None:
        # The maximum reparse point data buffer length is 16384 bytes. We are a
        # bit conservative here and set a length of 16000 bytes (8000
        # characters) + a few more for the header.
        substnamebufferchars = 8000
    else:
        # 1 more character for the null terminator. Python 2.x calculates
        # len(surrogate pair) = 2, so multiplying this by 2 is the right thing
        # to do.
        substnamebufferchars = len(path) + 1

    # It is amazing how ugly MSDN's version of REPARSE_DATA_BUFFER is:
    # <http://msdn.microsoft.com/en-us/library/windows/hardware/ff552012>. It
    # is a variable-length struct with two strings in the wchar[] buffer at
    # the end. Both are supposed to be null-terminated, and the individual
    # lengths do not include that of the null character, but the total
    # ReparseDataLength does.
    #
    # In our case, only the SubstituteName part of the mount point/junction-
    # specific part is relevant. So we set PrintNameLength to 0, but we still
    # need to allow for one null character, so PrintNameBuffer has length 1.
    class REPARSE_DATA_BUFFER(ctypes.Structure):
        _fields_ = [("ReparseTag", ctypes.c_ulong),
                    ("ReparseDataLength", ctypes.c_ushort),
                    ("Reserved", ctypes.c_ushort),
                    ("SubstituteNameOffset", ctypes.c_ushort),
                    ("SubstituteNameLength", ctypes.c_ushort),
                    ("PrintNameOffset", ctypes.c_ushort),
                    ("PrintNameLength", ctypes.c_ushort),
                    ("SubstituteNameBuffer", ctypes.c_wchar * substnamebufferchars),
                    ("PrintNameBuffer", ctypes.c_wchar * 1)]

    numpathbytes = (substnamebufferchars - 1) * sizeof(ctypes.c_wchar)
    # We can't really use sizeof on the struct because of packing issues.
    # Instead, calculate the size manually
    buffersize = (numpathbytes + (sizeof(ctypes.c_wchar) * 2) + 
        (sizeof(ctypes.c_ushort) * 4))
    if path is None:
        buffer = REPARSE_DATA_BUFFER()
        buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT
    else:
        buffer = REPARSE_DATA_BUFFER(
            IO_REPARSE_TAG_MOUNT_POINT,
            buffersize,
            0,
            # print name offset, length
            0, numpathbytes,
            # substitute name offset, length
            numpathbytes + 2, 0,
            # print name
            path,
            # substitute name
            "")

    return (buffer, buffersize + REPARSE_DATA_BUFFER.SubstituteNameOffset.offset)
def new_junction_reparse_buffer(path=None):    
    """
    Given a path, return a pair containing a new REPARSE_DATA_BUFFER and the
    length of the buffer (not necessarily the same as sizeof due to packing
    issues).
    If no path is provided, the maximum length is assumed.
    """

    if path is None:
        # The maximum reparse point data buffer length is 16384 bytes. We are a
        # bit conservative here and set a length of 16000 bytes (8000
        # characters) + a few more for the header.
        substnamebufferchars = 8000
    else:
        # 1 more character for the null terminator. Python 2.x calculates
        # len(surrogate pair) = 2, so multiplying this by 2 is the right thing
        # to do.
        substnamebufferchars = len(path) + 1

    # It is amazing how ugly MSDN's version of REPARSE_DATA_BUFFER is:
    # <http://msdn.microsoft.com/en-us/library/windows/hardware/ff552012>. It
    # is a variable-length struct with two strings in the wchar[] buffer at
    # the end. Both are supposed to be null-terminated, and the individual
    # lengths do not include that of the null character, but the total
    # ReparseDataLength does.
    #
    # In our case, only the SubstituteName part of the mount point/junction-
    # specific part is relevant. So we set PrintNameLength to 0, but we still
    # need to allow for one null character, so PrintNameBuffer has length 1.
    class REPARSE_DATA_BUFFER(ctypes.Structure):
        _fields_ = [("ReparseTag", ctypes.c_ulong),
                    ("ReparseDataLength", ctypes.c_ushort),
                    ("Reserved", ctypes.c_ushort),
                    ("SubstituteNameOffset", ctypes.c_ushort),
                    ("SubstituteNameLength", ctypes.c_ushort),
                    ("PrintNameOffset", ctypes.c_ushort),
                    ("PrintNameLength", ctypes.c_ushort),
                    ("SubstituteNameBuffer", ctypes.c_wchar * substnamebufferchars),
                    ("PrintNameBuffer", ctypes.c_wchar * 1)]

    numpathbytes = (substnamebufferchars - 1) * sizeof(ctypes.c_wchar)
    # We can't really use sizeof on the struct because of packing issues.
    # Instead, calculate the size manually
    buffersize = (numpathbytes + (sizeof(ctypes.c_wchar) * 2) + 
        (sizeof(ctypes.c_ushort) * 4))
    if path is None:
        buffer = REPARSE_DATA_BUFFER()
        buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT
    else:
        buffer = REPARSE_DATA_BUFFER(
            IO_REPARSE_TAG_MOUNT_POINT,
            buffersize,
            0,
            # print name offset, length
            0, numpathbytes,
            # substitute name offset, length
            numpathbytes + 2, 0,
            # print name
            path,
            # substitute name
            "")

    return (buffer, buffersize + REPARSE_DATA_BUFFER.SubstituteNameOffset.offset)
Given a path, return a pair containing a new REPARSE_DATA_BUFFER and the
    length of the buffer (not necessarily the same as sizeof due to packing
    issues).
    If no path is provided, the maximum length is assumed.