##// END OF EJS Templates
win32: close file when leaving _getfileinfo()
Patrick Mezard -
r10219:3b941208 stable
parent child Browse files
Show More
@@ -1,173 +1,174 b''
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 """Utility functions that use win32 API.
8 """Utility functions that use win32 API.
9
9
10 Mark Hammond's win32all package allows better functionality on
10 Mark Hammond's win32all package allows better functionality on
11 Windows. This module overrides definitions in util.py. If not
11 Windows. This module overrides definitions in util.py. If not
12 available, import of this module will fail, and generic code will be
12 available, import of this module will fail, and generic code will be
13 used.
13 used.
14 """
14 """
15
15
16 import win32api
16 import win32api
17
17
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
19 import winerror
19 import winerror
20 import osutil, encoding
20 import osutil, encoding
21 from win32com.shell import shell, shellcon
21 from win32com.shell import shell, shellcon
22
22
23 def os_link(src, dst):
23 def os_link(src, dst):
24 try:
24 try:
25 win32file.CreateHardLink(dst, src)
25 win32file.CreateHardLink(dst, src)
26 # CreateHardLink sometimes succeeds on mapped drives but
26 # CreateHardLink sometimes succeeds on mapped drives but
27 # following nlinks() returns 1. Check it now and bail out.
27 # following nlinks() returns 1. Check it now and bail out.
28 if nlinks(src) < 2:
28 if nlinks(src) < 2:
29 try:
29 try:
30 win32file.DeleteFile(dst)
30 win32file.DeleteFile(dst)
31 except:
31 except:
32 pass
32 pass
33 # Fake hardlinking error
33 # Fake hardlinking error
34 raise OSError(errno.EINVAL, 'Hardlinking not supported')
34 raise OSError(errno.EINVAL, 'Hardlinking not supported')
35 except pywintypes.error, details:
35 except pywintypes.error, details:
36 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
36 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
37 except NotImplementedError: # Another fake error win Win98
37 except NotImplementedError: # Another fake error win Win98
38 raise OSError(errno.EINVAL, 'Hardlinking not supported')
38 raise OSError(errno.EINVAL, 'Hardlinking not supported')
39
39
40 def _getfileinfo(pathname):
40 def _getfileinfo(pathname):
41 """Return number of hardlinks for the given file."""
41 """Return number of hardlinks for the given file."""
42 try:
42 try:
43 fh = win32file.CreateFile(pathname,
43 fh = win32file.CreateFile(pathname,
44 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
44 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
45 None, win32file.OPEN_EXISTING, 0, None)
45 None, win32file.OPEN_EXISTING, 0, None)
46 res = win32file.GetFileInformationByHandle(fh)
46 try:
47 fh.Close()
47 return win32file.GetFileInformationByHandle(fh)
48 return res
48 finally:
49 fh.Close()
49 except pywintypes.error:
50 except pywintypes.error:
50 return None
51 return None
51
52
52 def nlinks(pathname):
53 def nlinks(pathname):
53 """Return number of hardlinks for the given file."""
54 """Return number of hardlinks for the given file."""
54 res = _getfileinfo(pathname)
55 res = _getfileinfo(pathname)
55 if res is not None:
56 if res is not None:
56 return res[7]
57 return res[7]
57 else:
58 else:
58 return os.lstat(pathname).st_nlink
59 return os.lstat(pathname).st_nlink
59
60
60 def samefile(fpath1, fpath2):
61 def samefile(fpath1, fpath2):
61 """Returns whether fpath1 and fpath2 refer to the same file. This is only
62 """Returns whether fpath1 and fpath2 refer to the same file. This is only
62 guaranteed to work for files, not directories."""
63 guaranteed to work for files, not directories."""
63 res1 = _getfileinfo(fpath1)
64 res1 = _getfileinfo(fpath1)
64 res2 = _getfileinfo(fpath2)
65 res2 = _getfileinfo(fpath2)
65 if res1 is not None and res2 is not None:
66 if res1 is not None and res2 is not None:
66 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
67 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
67 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
68 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
68 else:
69 else:
69 return False
70 return False
70
71
71 def samedevice(fpath1, fpath2):
72 def samedevice(fpath1, fpath2):
72 """Returns whether fpath1 and fpath2 are on the same device. This is only
73 """Returns whether fpath1 and fpath2 are on the same device. This is only
73 guaranteed to work for files, not directories."""
74 guaranteed to work for files, not directories."""
74 res1 = _getfileinfo(fpath1)
75 res1 = _getfileinfo(fpath1)
75 res2 = _getfileinfo(fpath2)
76 res2 = _getfileinfo(fpath2)
76 if res1 is not None and res2 is not None:
77 if res1 is not None and res2 is not None:
77 return res1[4] == res2[4]
78 return res1[4] == res2[4]
78 else:
79 else:
79 return False
80 return False
80
81
81 def testpid(pid):
82 def testpid(pid):
82 '''return True if pid is still running or unable to
83 '''return True if pid is still running or unable to
83 determine, False otherwise'''
84 determine, False otherwise'''
84 try:
85 try:
85 handle = win32api.OpenProcess(
86 handle = win32api.OpenProcess(
86 win32con.PROCESS_QUERY_INFORMATION, False, pid)
87 win32con.PROCESS_QUERY_INFORMATION, False, pid)
87 if handle:
88 if handle:
88 status = win32process.GetExitCodeProcess(handle)
89 status = win32process.GetExitCodeProcess(handle)
89 return status == win32con.STILL_ACTIVE
90 return status == win32con.STILL_ACTIVE
90 except pywintypes.error, details:
91 except pywintypes.error, details:
91 return details[0] != winerror.ERROR_INVALID_PARAMETER
92 return details[0] != winerror.ERROR_INVALID_PARAMETER
92 return True
93 return True
93
94
94 def lookup_reg(key, valname=None, scope=None):
95 def lookup_reg(key, valname=None, scope=None):
95 ''' Look up a key/value name in the Windows registry.
96 ''' Look up a key/value name in the Windows registry.
96
97
97 valname: value name. If unspecified, the default value for the key
98 valname: value name. If unspecified, the default value for the key
98 is used.
99 is used.
99 scope: optionally specify scope for registry lookup, this can be
100 scope: optionally specify scope for registry lookup, this can be
100 a sequence of scopes to look up in order. Default (CURRENT_USER,
101 a sequence of scopes to look up in order. Default (CURRENT_USER,
101 LOCAL_MACHINE).
102 LOCAL_MACHINE).
102 '''
103 '''
103 try:
104 try:
104 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
105 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
105 QueryValueEx, OpenKey
106 QueryValueEx, OpenKey
106 except ImportError:
107 except ImportError:
107 return None
108 return None
108
109
109 if scope is None:
110 if scope is None:
110 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
111 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
111 elif not isinstance(scope, (list, tuple)):
112 elif not isinstance(scope, (list, tuple)):
112 scope = (scope,)
113 scope = (scope,)
113 for s in scope:
114 for s in scope:
114 try:
115 try:
115 val = QueryValueEx(OpenKey(s, key), valname)[0]
116 val = QueryValueEx(OpenKey(s, key), valname)[0]
116 # never let a Unicode string escape into the wild
117 # never let a Unicode string escape into the wild
117 return encoding.tolocal(val.encode('UTF-8'))
118 return encoding.tolocal(val.encode('UTF-8'))
118 except EnvironmentError:
119 except EnvironmentError:
119 pass
120 pass
120
121
121 def system_rcpath_win32():
122 def system_rcpath_win32():
122 '''return default os-specific hgrc search path'''
123 '''return default os-specific hgrc search path'''
123 proc = win32api.GetCurrentProcess()
124 proc = win32api.GetCurrentProcess()
124 try:
125 try:
125 # This will fail on windows < NT
126 # This will fail on windows < NT
126 filename = win32process.GetModuleFileNameEx(proc, 0)
127 filename = win32process.GetModuleFileNameEx(proc, 0)
127 except:
128 except:
128 filename = win32api.GetModuleFileName(0)
129 filename = win32api.GetModuleFileName(0)
129 # Use mercurial.ini found in directory with hg.exe
130 # Use mercurial.ini found in directory with hg.exe
130 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
131 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
131 if os.path.isfile(progrc):
132 if os.path.isfile(progrc):
132 return [progrc]
133 return [progrc]
133 # else look for a system rcpath in the registry
134 # else look for a system rcpath in the registry
134 try:
135 try:
135 value = win32api.RegQueryValue(
136 value = win32api.RegQueryValue(
136 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
137 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
137 rcpath = []
138 rcpath = []
138 for p in value.split(os.pathsep):
139 for p in value.split(os.pathsep):
139 if p.lower().endswith('mercurial.ini'):
140 if p.lower().endswith('mercurial.ini'):
140 rcpath.append(p)
141 rcpath.append(p)
141 elif os.path.isdir(p):
142 elif os.path.isdir(p):
142 for f, kind in osutil.listdir(p):
143 for f, kind in osutil.listdir(p):
143 if f.endswith('.rc'):
144 if f.endswith('.rc'):
144 rcpath.append(os.path.join(p, f))
145 rcpath.append(os.path.join(p, f))
145 return rcpath
146 return rcpath
146 except pywintypes.error:
147 except pywintypes.error:
147 return []
148 return []
148
149
149 def user_rcpath_win32():
150 def user_rcpath_win32():
150 '''return os-specific hgrc search path to the user dir'''
151 '''return os-specific hgrc search path to the user dir'''
151 userdir = os.path.expanduser('~')
152 userdir = os.path.expanduser('~')
152 if sys.getwindowsversion()[3] != 2 and userdir == '~':
153 if sys.getwindowsversion()[3] != 2 and userdir == '~':
153 # We are on win < nt: fetch the APPDATA directory location and use
154 # We are on win < nt: fetch the APPDATA directory location and use
154 # the parent directory as the user home dir.
155 # the parent directory as the user home dir.
155 appdir = shell.SHGetPathFromIDList(
156 appdir = shell.SHGetPathFromIDList(
156 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
157 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
157 userdir = os.path.dirname(appdir)
158 userdir = os.path.dirname(appdir)
158 return [os.path.join(userdir, 'mercurial.ini'),
159 return [os.path.join(userdir, 'mercurial.ini'),
159 os.path.join(userdir, '.hgrc')]
160 os.path.join(userdir, '.hgrc')]
160
161
161 def getuser():
162 def getuser():
162 '''return name of current user'''
163 '''return name of current user'''
163 return win32api.GetUserName()
164 return win32api.GetUserName()
164
165
165 def set_signal_handler_win32():
166 def set_signal_handler_win32():
166 """Register a termination handler for console events including
167 """Register a termination handler for console events including
167 CTRL+C. python signal handlers do not work well with socket
168 CTRL+C. python signal handlers do not work well with socket
168 operations.
169 operations.
169 """
170 """
170 def handler(event):
171 def handler(event):
171 win32process.ExitProcess(1)
172 win32process.ExitProcess(1)
172 win32api.SetConsoleCtrlHandler(handler)
173 win32api.SetConsoleCtrlHandler(handler)
173
174
General Comments 0
You need to be logged in to leave comments. Login now