File: path_utils.py

package info (click to toggle)
watchman 4.9.0-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,992 kB
  • sloc: cpp: 27,459; python: 6,538; java: 3,404; php: 3,257; ansic: 2,803; javascript: 1,116; makefile: 671; ruby: 364; sh: 124; xml: 102; lisp: 4
file content (84 lines) | stat: -rw-r--r-- 2,771 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# no unicode literals

import os.path
import os
import platform
import ctypes

from pywatchman import compat

if os.name == 'nt':

    def open_file_win(path):

        create_file = ctypes.windll.kernel32.CreateFileW

        c_path = ctypes.create_unicode_buffer(path)
        access = 0
        mode = 7  # FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE
        disposition = 3  # OPEN_EXISTING
        flags = 33554432  # FILE_FLAG_BACKUP_SEMANTICS

        h = create_file(c_path, access, mode, 0, disposition, flags, 0)
        if h == -1:
            raise WindowsError("Failed to open file: " + path)

        return h

    def get_canonical_filesystem_path(name):
        gfpnbh = ctypes.windll.kernel32.GetFinalPathNameByHandleW
        close_handle = ctypes.windll.kernel32.CloseHandle

        h = open_file_win(name)
        try:
            gfpnbh = ctypes.windll.kernel32.GetFinalPathNameByHandleW
            numwchars = 1024
            while True:
                buf = ctypes.create_unicode_buffer(numwchars)
                result = gfpnbh(h, buf, numwchars, 0)
                if result == 0:
                    raise Exception("unknown error while normalizing path")

                # The first four chars are //?/
                if result <= numwchars:
                    return buf.value[4:].replace('\\', '/').encode('utf8')

                # Not big enough; the result is the amount we need
                numwchars = result + 1
        finally:
            close_handle(h)

elif platform.system() == 'Darwin':
    import ctypes.util

    F_GETPATH = 50
    libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
    getpath_fcntl = libc.fcntl
    getpath_fcntl.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_char_p]
    getpath_fcntl.restype = ctypes.c_int

    def get_canonical_filesystem_path(name):
        fd = os.open(name, os.O_RDONLY, 0)
        try:
            numchars = 1024  # MAXPATHLEN
            # The kernel caps this routine to MAXPATHLEN, so there is no
            # point in over-allocating or trying again with a larger buffer
            buf = ctypes.create_string_buffer(numchars)
            ctypes.set_errno(0)
            result = getpath_fcntl(fd, F_GETPATH, buf)
            if result != 0:
                raise OSError(ctypes.get_errno())
            # buf is a bytes buffer, so normalize it if necessary
            ret = buf.value
            if isinstance(name, compat.UNICODE):
                ret = os.fsdecode(ret)
            return ret
        finally:
            os.close(fd)

else:
    def get_canonical_filesystem_path(name):
        return os.path.normpath(name)