def demo(): """ Definition of buffer used with FSCTL_TXFS_CREATE_MINIVERSION: typedef struct _TXFS_CREATE_MINIVERSION_INFO{ USHORT StructureVersion; USHORT StructureLength; ULONG BaseVersion; USHORT MiniVersion;} """ buf_fmt='HHLH0L' ## buffer size must include struct padding buf_size=struct.calcsize(buf_fmt) tempdir=win32api.GetTempPath() tempfile=win32api.GetTempFileName(tempdir,'cft')[0] print("Demonstrating transactions on tempfile", tempfile) f=open(tempfile,'w') f.write('This is original file.\n') f.close() trans=win32transaction.CreateTransaction(Description='Test creating miniversions of a file') hfile=win32file.CreateFileW(tempfile, win32con.GENERIC_READ|win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans) win32file.WriteFile(hfile, str2bytes('This is first miniversion.\n')) buf=win32file.DeviceIoControl(hfile, winioctlcon.FSCTL_TXFS_CREATE_MINIVERSION,None,buf_size,None) struct_ver, struct_len, base_ver, ver_1=struct.unpack(buf_fmt, buf) win32file.SetFilePointer(hfile, 0, win32con.FILE_BEGIN) win32file.WriteFile(hfile, str2bytes('This is second miniversion!\n')) buf=win32file.DeviceIoControl(hfile, winioctlcon.FSCTL_TXFS_CREATE_MINIVERSION,None,buf_size,None) struct_ver, struct_len, base_ver, ver_2=struct.unpack(buf_fmt, buf) hfile.Close() ## miniversions can't be opened with write access hfile_0=win32file.CreateFileW(tempfile, win32con.GENERIC_READ, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans, MiniVersion=base_ver) print('version:',base_ver,win32file.ReadFile(hfile_0, 100)) hfile_0.Close() hfile_1=win32file.CreateFileW(tempfile, win32con.GENERIC_READ, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans, MiniVersion=ver_1) print('version:',ver_1,win32file.ReadFile(hfile_1, 100)) hfile_1.Close() hfile_2=win32file.CreateFileW(tempfile, win32con.GENERIC_READ, win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0 , None, Transaction=trans, MiniVersion=ver_2) print('version:',ver_2,win32file.ReadFile(hfile_2, 100)) hfile_2.Close() ## MiniVersions are destroyed when transaction is committed or rolled back win32transaction.CommitTransaction(trans) os.unlink(tempfile)
def readlink(fpath): """ Windows readlink implementation. """ # This wouldn't return true if the file didn't exist, as far as I know. if not islink(fpath): return None try: # Open the file correctly depending on the string type. if type(fpath) == unicode: handle = win32file.CreateFileW(fpath, win32file.GENERIC_READ, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_OPEN_REPARSE_POINT | win32file.FILE_FLAG_BACKUP_SEMANTICS, 0) else: handle = win32file.CreateFile(fpath, win32file.GENERIC_READ, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_OPEN_REPARSE_POINT | win32file.FILE_FLAG_BACKUP_SEMANTICS, 0) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) buffer = win32file.DeviceIoControl(handle, winioctlcon.FSCTL_GET_REPARSE_POINT, None, 16*1024) # Above will return an ugly string (byte array), so we'll need to parse it. # But first, we'll close the handle to our file so we're not locking it anymore. win32file.CloseHandle(handle) # Minimum possible length (assuming that the length of the target is bigger than 0) if len(buffer) < 9: return None # Parse and return our result. result = _parse_reparse_buffer(buffer) offset = result[SYMBOLIC_LINK]['substitute_name_offset'] ending = offset + result[SYMBOLIC_LINK]['substitute_name_length'] rpath = result[SYMBOLIC_LINK]['buffer'][offset:ending].replace('\x00','') if len(rpath) > 4 and rpath[0:4] == '\\??\\': rpath = rpath[4:] return rpath except pywintypes.error, e: raise OSError(e.winerror, e.strerror, fpath)
def __init__(self, path, flags): self.flags = flags self.handle = None self.event = None try: self.handle = win32file.CreateFileW( path, 0x0001, # FILE_LIST_DIRECTORY win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None) self.buffer = win32file.AllocateReadBuffer(8192) self.event = win32event.CreateEvent(None, True, False, None) self.overlapped = pywintypes.OVERLAPPED() self.overlapped.hEvent = self.event self._start() except: self.close() raise
def __init__(self, path_to_watch, modified_queue): Thread.__init__(self, name='TreeWatcher') self.modified_queue = modified_queue self.path_to_watch = path_to_watch self.dir_handle = win32file.CreateFileW( path_to_watch, FILE_LIST_DIRECTORY, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS, None)
def windows_nlinks(path): import win32file dwFlagsAndAttributes = win32file.FILE_FLAG_BACKUP_SEMANTICS if os.path.isdir(path) else 0 if isbytestring(path): path = path.decode(filesystem_encoding) handle = win32file.CreateFileW(path, win32file.GENERIC_READ, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, dwFlagsAndAttributes, None) try: return win32file.GetFileInformationByHandle(handle)[7] finally: handle.Close()
def open(file, flags, mode=0o777, share_flags=None): # pylint: disable=redefined-builtin,too-many-branches """Replacement for os.open() allowing moving or unlinking before closing.""" if isinstance(file, bytes): file = file.decode("mbcs") if u"\0" in file: raise ValueError("embedded null character in path") if not isinstance(flags, int) and flags >= 0: raise ValueError("invalid flags: %r" % (flags, )) if not isinstance(mode, int) and mode >= 0: raise ValueError("invalid mode: %r" % (mode, )) if share_flags is None: share_flags = winnan.flags.FILE_SHARE_VALID_FLAGS if share_flags & ~winnan.flags.FILE_SHARE_VALID_FLAGS: raise ValueError("invalid share_flags: %r" % (share_flags, )) access_flags = _ACCESS_MAP[flags & _ACCESS_MASK] create_flags = _CREATE_MAP[flags & _CREATE_MASK] attrib_flags = win32file.FILE_ATTRIBUTE_NORMAL if flags & os.O_CREAT and mode & stat.S_IWRITE == 0: attrib_flags = win32file.FILE_ATTRIBUTE_READONLY if flags & os.O_TEMPORARY: # pylint: disable=no-member share_flags |= win32file.FILE_SHARE_DELETE attrib_flags |= win32file.FILE_FLAG_DELETE_ON_CLOSE access_flags |= ntsecuritycon.DELETE if flags & os.O_SHORT_LIVED: # pylint: disable=no-member attrib_flags |= win32file.FILE_ATTRIBUTE_TEMPORARY if flags & os.O_SEQUENTIAL: # pylint: disable=no-member attrib_flags |= win32file.FILE_FLAG_SEQUENTIAL_SCAN if flags & os.O_RANDOM: # pylint: disable=no-member attrib_flags |= win32file.FILE_FLAG_RANDOM_ACCESS try: handle = win32file.CreateFileW(file, access_flags, share_flags, None, create_flags, attrib_flags, None) except win32file.error as err: if err.winerror == winerror.ERROR_FILE_EXISTS: raise FileExistsError(errno.EEXIST, "File exists", file) raise return msvcrt.open_osfhandle(handle.Detach(), flags | winnan.flags.O_NOINHERIT)
def run(self): hDir = win32file.CreateFileW( self._watch_path, FILE_LIST_DIRECTORY, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED, None ) while self._windows_sucks_flag: buf = win32file.AllocateReadBuffer(1024) win32file.ReadDirectoryChangesW( hDir, buf, True, win32con.FILE_NOTIFY_CHANGE_FILE_NAME | win32con.FILE_NOTIFY_CHANGE_DIR_NAME | win32con.FILE_NOTIFY_CHANGE_SIZE | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE, self._overlapped ) result_stack = {} rc = win32event.WaitForMultipleObjects((self._wait_stop, self._overlapped.hEvent), 0, win32event.INFINITE) if rc == win32event.WAIT_OBJECT_0: # Stop event break data = win32file.GetOverlappedResult(hDir, self._overlapped, True) # lets read the data and store it in the results results = win32file.FILE_NOTIFY_INFORMATION(buf, data) for action, afile in results: if action in ACTIONS: full_filename = os.path.join(self._watch_path, afile) result_stack.setdefault(full_filename, []).append(ACTIONS.get(action)) keys = list(result_stack.keys()) while len(keys): key = keys.pop(0) event = result_stack.pop(key) if (ADDED in event) and (DELETED in event): event = [e for e in event if e not in (ADDED, DELETED)] noticed = [] for each_event in event: if each_event not in noticed: self._callback(each_event, full_filename) noticed.append(each_event)
def change_created_time(self, filepath: Path, d_ctime: datetime) -> None: """Change the created time of a given file.""" winfile = win32file.CreateFileW( str(filepath), win32con.GENERIC_WRITE, (win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE), None, win32con.OPEN_EXISTING, win32con.FILE_ATTRIBUTE_NORMAL, None, ) win32file.SetFileTime(winfile, d_ctime)
def windows_get_size(path): ''' On windows file sizes are only accurately stored in the actual file, not in the directory entry (which could be out of date). So we open the file, and get the actual size. ''' import win32file if isbytestring(path): path = path.decode(filesystem_encoding) h = win32file.CreateFileW( path, 0, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE | win32file.FILE_SHARE_DELETE, None, win32file.OPEN_EXISTING, 0, None) try: return win32file.GetFileSize(h) finally: win32file.CloseHandle(h)
def change_file_date(self, filepath: Path, mtime: str = None, ctime: str = None) -> None: """ Change the FS modification and creation dates of a file. Since there is no creation time on GNU/Linux, the ctime will not be taken into account if running on this platform. :param filename: The file to modify :param mtime: The modification time :param ctime: The creation time """ filepath = safe_long_path(filepath) log.debug( f"Setting file dates for {filepath!r} (ctime={ctime!r}, mtime={mtime!r})" ) # Set the creation time first as on macOS using touch will change ctime and mtime. # The modification time will be updated just after, if needed. if ctime: d_ctime = datetime.strptime(str(ctime), "%Y-%m-%d %H:%M:%S") if MAC: cmd = [ "touch", "-mt", d_ctime.strftime("%Y%m%d%H%M.%S"), str(filepath) ] subprocess.check_call(cmd) elif WINDOWS: winfile = win32file.CreateFileW( str(filepath), win32con.GENERIC_WRITE, (win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE), None, win32con.OPEN_EXISTING, win32con.FILE_ATTRIBUTE_NORMAL, None, ) win32file.SetFileTime(winfile, d_ctime) if mtime: d_mtime = mktime(strptime(str(mtime), "%Y-%m-%d %H:%M:%S")) os.utime(filepath, (d_mtime, d_mtime))
def windows_get_fileid(path): ''' The fileid uniquely identifies actual file contents (it is the same for all hardlinks to a file). Similar to inode number on linux. ''' import win32file from pywintypes import error if isbytestring(path): path = path.decode(filesystem_encoding) try: h = win32file.CreateFileW(path, 0, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_BACKUP_SEMANTICS, 0) try: data = win32file.GetFileInformationByHandle(h) finally: win32file.CloseHandle(h) except (error, EnvironmentError): return None return data[4], data[8], data[9]
def windows_open(path): if isinstance(path, bytes): path = path.decode('mbcs') try: h = win32file.CreateFileW( path, win32file.GENERIC_READ | win32file.GENERIC_WRITE, # Open for reading and writing 0, # Open exclusive None, # No security attributes, ensures handle is not inherited by children win32file.OPEN_ALWAYS, # If file does not exist, create it win32file.FILE_ATTRIBUTE_NORMAL, # Normal attributes None, # No template file ) except pywintypes.error as err: raise WindowsError(err[0], err[2], path) fd = msvcrt.open_osfhandle(h.Detach(), 0) return os.fdopen(fd, 'r+b')
def old_windows_get_fileid(path): # we dont use this anymore as the win32 implementation reads the windows # registry to convert file times which is slow and breaks on systems with # registry issues. import win32file from pywintypes import error if isbytestring(path): path = path.decode(filesystem_encoding) try: h = win32file.CreateFileW(path, 0, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_BACKUP_SEMANTICS, 0) try: data = win32file.GetFileInformationByHandle(h) finally: win32file.CloseHandle(h) except (error, EnvironmentError): return None return data[4], data[8], data[9]
def _get_reparse_data(path): ''' Retrieves the reparse point data structure for the given path. If the path is not a reparse point, None is returned. See http://msdn.microsoft.com/en-us/library/ff552012.aspx for details on the REPARSE_DATA_BUFFER structure returned. ''' if sys.getwindowsversion().major < 6: raise SaltInvocationError( 'Symlinks are only supported on Windows Vista or later.') # ensure paths are using the right slashes path = os.path.normpath(path) if not _is_reparse_point(path): return None fileHandle = None try: fileHandle = win32file.CreateFileW( path, 0x80000000, # GENERIC_READ 1, # share with other readers None, # no inherit, default security descriptor 3, # OPEN_EXISTING 0x00200000 | 0x02000000 # FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS ) reparseData = win32file.DeviceIoControl( fileHandle, 0x900a8, # FSCTL_GET_REPARSE_POINT None, # in buffer 16384 # out buffer size (MAXIMUM_REPARSE_DATA_BUFFER_SIZE) ) finally: if fileHandle: win32file.CloseHandle(fileHandle) return reparseData
def os_open(path, flags, mode=0o777, share_flags=FILE_SHARE_VALID_FLAGS): ''' Replacement for os.open() allowing moving or unlinking before closing ''' if not isinstance(flags, Integral): raise TypeError('flags must be an integer') if not isinstance(mode, Integral): raise TypeError('mode must be an integer') if share_flags & ~FILE_SHARE_VALID_FLAGS: raise ValueError('bad share_flags: %r' % share_flags) access_flags = _ACCESS_MAP[flags & _ACCESS_MASK] create_flags = _CREATE_MAP[flags & _CREATE_MASK] attrib_flags = FILE_ATTRIBUTE_NORMAL if flags & os.O_CREAT and mode & ~0o444 == 0: attrib_flags = FILE_ATTRIBUTE_READONLY if flags & os.O_TEMPORARY: share_flags |= FILE_SHARE_DELETE attrib_flags |= FILE_FLAG_DELETE_ON_CLOSE access_flags |= DELETE if flags & os.O_SHORT_LIVED: attrib_flags |= FILE_ATTRIBUTE_TEMPORARY if flags & os.O_SEQUENTIAL: attrib_flags |= FILE_FLAG_SEQUENTIAL_SCAN if flags & os.O_RANDOM: attrib_flags |= FILE_FLAG_RANDOM_ACCESS try: h = win32file.CreateFileW(path, access_flags, share_flags, None, create_flags, attrib_flags, None) except pywintypes.error as e: raise_winerror(e) ans = msvcrt.open_osfhandle(h, flags | os.O_NOINHERIT) h.Detach( ) # We dont want the handle to be automatically closed when h is deleted return ans
def get_read_handle(filename): if os.path.isdir(filename): dwFlagsAndAttributes = win32file.FILE_FLAG_BACKUP_SEMANTICS else: dwFlagsAndAttributes = 0 # CreateFile(fileName, desiredAccess, shareMode, attributes, # CreationDisposition, flagsAndAttributes, hTemplateFile) try: handle = win32file.CreateFileW( filename, # with 'W' accepts unicode win32file.GENERIC_READ, win32file.FILE_SHARE_READ, None, win32file.OPEN_EXISTING, dwFlagsAndAttributes, None) return handle except Exception as e: raise PygcamException("get_read_handle(%s) failed: %s" % (filename, e))
def readlink(fpath): """ Parses a symlink to get the target path. :param fpath: path to the symlink :type fpath: basestring :return: target path :rtype: basestring """ if not islink(fpath): return None # open the file handle = win32file.CreateFileW(fpath, win32file.GENERIC_READ, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_OPEN_REPARSE_POINT, 0) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) _buffer = win32file.DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, None, 16 * 1024) # above will return an ugly string (byte array), so we'll need to parse it win32file.CloseHandle(handle) # minimum possible length # (assuming that the length of the target is bigger than 0) if len(_buffer) < 9: return None # parse and return our result result = parse_reparse_buffer(_buffer) offset = result[SYMBOLIC_LINK]['substitute_name_offset'] ending = offset + result[SYMBOLIC_LINK]['substitute_name_length'] rpath = result[SYMBOLIC_LINK]['buffer'][offset:ending].replace('\x00', '') if len(rpath) > 4 and rpath[0:4] == '\\??\\': rpath = rpath[4:] return rpath
def set_file_time(path, creation_time, last_access_time, last_write_time): # First windows API call handle = win32file.CreateFileW( path, SYMBOLS.GENERIC_WRITE, SYMBOLS.FILE_SHARE_READ | SYMBOLS.FILE_SHARE_WRITE | SYMBOLS.FILE_SHARE_DELETE, None, SYMBOLS.OPEN_EXISTING, SYMBOLS.FILE_FLAG_OPEN_REPARSE_POINT | SYMBOLS.FILE_FLAG_BACKUP_SEMANTICS, 0, ) # Prepare arguments def prepare(x): if x == 0: return None if isinstance(x, int): from datetime import timezone x = datetime(year=x, month=1, day=1, tzinfo=timezone.utc) return x creation_time = prepare(creation_time) last_access_time = prepare(last_access_time) last_write_time = prepare(last_write_time) # Second windows API call assert handle != win32file.INVALID_HANDLE_VALUE win32file.SetFileTime( handle, creation_time, last_access_time, last_write_time, ) # Close the handle # This is necessary since we use a single process # for running all the commands from a single test case win32file.CloseHandle(handle)
buf_size = struct.calcsize(buf_fmt) tempdir = win32api.GetTempPath() tempfile = win32api.GetTempFileName(tempdir, 'cft')[0] print tempfile f = open(tempfile, 'w') f.write('This is original file.\n') f.close() trans = win32transaction.CreateTransaction( Description='Test creating miniversions of a file') hfile = win32file.CreateFileW(tempfile, win32con.GENERIC_READ | win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0, None, Transaction=trans) win32file.WriteFile(hfile, 'This is first miniversion.\n') buf = win32file.DeviceIoControl(hfile, winioctlcon.FSCTL_TXFS_CREATE_MINIVERSION, '', buf_size, None) struct_ver, struct_len, base_ver, ver_1 = struct.unpack(buf_fmt, buf) win32file.SetFilePointer(hfile, 0, win32con.FILE_BEGIN) win32file.WriteFile(hfile, 'This is second miniversion!\n') buf = win32file.DeviceIoControl(hfile, winioctlcon.FSCTL_TXFS_CREATE_MINIVERSION, '',
def __init__(self, path): self.handle_map = {} import win32file, winerror from pywintypes import error from collections import defaultdict if isbytestring(path): path = path.decode(filesystem_encoding) if not os.path.exists(path): return names = os.listdir(path) name_to_fileid = {x:windows_get_fileid(os.path.join(path, x)) for x in names} fileid_to_names = defaultdict(set) for name, fileid in iteritems(name_to_fileid): fileid_to_names[fileid].add(name) for x in names: f = os.path.normcase(os.path.abspath(os.path.join(path, x))) if not os.path.isfile(f): continue try: # Ensure the file is not read-only win32file.SetFileAttributes(f, win32file.FILE_ATTRIBUTE_NORMAL) except: pass try: h = win32file.CreateFileW(f, win32file.GENERIC_READ, win32file.FILE_SHARE_DELETE, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_SEQUENTIAL_SCAN, 0) except error as e: if getattr(e, 'winerror', 0) == winerror.ERROR_SHARING_VIOLATION: # The file could be a hardlink to an already opened file, # in which case we use the same handle for both files fileid = name_to_fileid[x] found = False if fileid is not None: for other in fileid_to_names[fileid]: other = os.path.normcase(os.path.abspath(os.path.join(path, other))) if other in self.handle_map: self.handle_map[f] = self.handle_map[other] found = True break if found: continue self.close_handles() if getattr(e, 'winerror', 0) == winerror.ERROR_SHARING_VIOLATION: err = IOError(errno.EACCES, _('File is open in another process')) err.filename = f raise err prints('CreateFile failed for: %r' % f) raise except: self.close_handles() prints('CreateFile failed for: %r' % f) raise self.handle_map[f] = h
def readlink(path): ''' Return the path that a symlink points to This is only supported on Windows Vista or later. Inline with *nix behaviour, this function will raise an error if the path is not a symlink, however, the error raised will be a SaltInvocationError, not an OSError. CLI Example: .. code-block:: bash salt '*' file.readlink /path/to/link ''' if sys.getwindowsversion().major < 6: raise SaltInvocationError( 'Symlinks are only supported on Windows Vista or later.') if not os.path.isabs(path): raise SaltInvocationError('Path to link must be absolute.') # ensure paths are using the right slashes path = os.path.normpath(path) if not _islink(path): raise SaltInvocationError('The path specified is not a symlink.') fileHandle = None try: fileHandle = win32file.CreateFileW( path, 0x80000000, # GENERIC_READ 0, # no sharing None, # no inherit, default security descriptor 3, # OPEN_EXISTING 0x00200000 | 0x02000000 # FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS ) reparseData = win32file.DeviceIoControl( fileHandle, 0x900a8, # FSCTL_GET_REPARSE_POINT None, # in buffer 16384 # out buffer size (MAXIMUM_REPARSE_DATA_BUFFER_SIZE) ) finally: if fileHandle: win32file.CloseHandle(fileHandle) # REPARSE_DATA_BUFFER structure - see # http://msdn.microsoft.com/en-us/library/ff552012.aspx # parse the structure header to work out which type of reparse point this is header_parser = struct.Struct('L') ReparseTag, = header_parser.unpack(reparseData[:header_parser.size]) # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511.aspx if not ReparseTag & 0x0000FFFF == 0x0000000C: raise SaltInvocationError( 'The path specified is not a symlink, but another type of reparse point ({0:x}).' .format(ReparseTag)) # parse as a symlink reparse point structure (the structure for other # reparse points is different) data_parser = struct.Struct('LHHHHHHL') ReparseTag, ReparseDataLength, Reserved, SubstituteNameOffset, \ SubstituteNameLength, PrintNameOffset, \ PrintNameLength, Flags = data_parser.unpack(reparseData[:data_parser.size]) path_buffer_offset = data_parser.size absolute_substitute_name_offset = path_buffer_offset + SubstituteNameOffset target_bytes = reparseData[ absolute_substitute_name_offset:absolute_substitute_name_offset + SubstituteNameLength] target = target_bytes.decode('UTF-16') if target.startswith('\\??\\'): target = target[4:] # comes out in 8.3 form; convert it to LFN to make it look nicer target = win32file.GetLongPathName(target) return target