##// END OF EJS Templates
merge with stable
Matt Mackall -
r15098:edf7ae54 merge default
parent child Browse files
Show More
@@ -1,578 +1,578
1 /*
1 /*
2 osutil.c - native operating system services
2 osutil.c - native operating system services
3
3
4 Copyright 2007 Matt Mackall and others
4 Copyright 2007 Matt Mackall and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define _ATFILE_SOURCE
10 #define _ATFILE_SOURCE
11 #include <Python.h>
11 #include <Python.h>
12 #include <fcntl.h>
12 #include <fcntl.h>
13 #include <stdio.h>
13 #include <stdio.h>
14 #include <string.h>
14 #include <string.h>
15 #include <errno.h>
15 #include <errno.h>
16
16
17 #ifdef _WIN32
17 #ifdef _WIN32
18 #include <windows.h>
18 #include <windows.h>
19 #include <io.h>
19 #include <io.h>
20 #else
20 #else
21 #include <dirent.h>
21 #include <dirent.h>
22 #include <sys/stat.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
23 #include <sys/types.h>
24 #include <unistd.h>
24 #include <unistd.h>
25 #endif
25 #endif
26
26
27 #include "util.h"
27 #include "util.h"
28
28
29 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
29 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
30 #ifndef PATH_MAX
30 #ifndef PATH_MAX
31 #define PATH_MAX 4096
31 #define PATH_MAX 4096
32 #endif
32 #endif
33
33
34 #ifdef _WIN32
34 #ifdef _WIN32
35 /*
35 /*
36 stat struct compatible with hg expectations
36 stat struct compatible with hg expectations
37 Mercurial only uses st_mode, st_size and st_mtime
37 Mercurial only uses st_mode, st_size and st_mtime
38 the rest is kept to minimize changes between implementations
38 the rest is kept to minimize changes between implementations
39 */
39 */
40 struct hg_stat {
40 struct hg_stat {
41 int st_dev;
41 int st_dev;
42 int st_mode;
42 int st_mode;
43 int st_nlink;
43 int st_nlink;
44 __int64 st_size;
44 __int64 st_size;
45 int st_mtime;
45 int st_mtime;
46 int st_ctime;
46 int st_ctime;
47 };
47 };
48 struct listdir_stat {
48 struct listdir_stat {
49 PyObject_HEAD
49 PyObject_HEAD
50 struct hg_stat st;
50 struct hg_stat st;
51 };
51 };
52 #else
52 #else
53 struct listdir_stat {
53 struct listdir_stat {
54 PyObject_HEAD
54 PyObject_HEAD
55 struct stat st;
55 struct stat st;
56 };
56 };
57 #endif
57 #endif
58
58
59 #define listdir_slot(name) \
59 #define listdir_slot(name) \
60 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
60 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
61 { \
61 { \
62 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
62 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
63 }
63 }
64
64
65 listdir_slot(st_dev)
65 listdir_slot(st_dev)
66 listdir_slot(st_mode)
66 listdir_slot(st_mode)
67 listdir_slot(st_nlink)
67 listdir_slot(st_nlink)
68 #ifdef _WIN32
68 #ifdef _WIN32
69 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
69 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
70 {
70 {
71 return PyLong_FromLongLong(
71 return PyLong_FromLongLong(
72 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
72 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
73 }
73 }
74 #else
74 #else
75 listdir_slot(st_size)
75 listdir_slot(st_size)
76 #endif
76 #endif
77 listdir_slot(st_mtime)
77 listdir_slot(st_mtime)
78 listdir_slot(st_ctime)
78 listdir_slot(st_ctime)
79
79
80 static struct PyGetSetDef listdir_stat_getsets[] = {
80 static struct PyGetSetDef listdir_stat_getsets[] = {
81 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
81 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
82 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
82 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
83 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
83 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
84 {"st_size", listdir_stat_st_size, 0, 0, 0},
84 {"st_size", listdir_stat_st_size, 0, 0, 0},
85 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
85 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
86 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
86 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
87 {0, 0, 0, 0, 0}
87 {0, 0, 0, 0, 0}
88 };
88 };
89
89
90 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
90 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
91 {
91 {
92 return t->tp_alloc(t, 0);
92 return t->tp_alloc(t, 0);
93 }
93 }
94
94
95 static void listdir_stat_dealloc(PyObject *o)
95 static void listdir_stat_dealloc(PyObject *o)
96 {
96 {
97 o->ob_type->tp_free(o);
97 o->ob_type->tp_free(o);
98 }
98 }
99
99
100 static PyTypeObject listdir_stat_type = {
100 static PyTypeObject listdir_stat_type = {
101 PyVarObject_HEAD_INIT(NULL, 0)
101 PyVarObject_HEAD_INIT(NULL, 0)
102 "osutil.stat", /*tp_name*/
102 "osutil.stat", /*tp_name*/
103 sizeof(struct listdir_stat), /*tp_basicsize*/
103 sizeof(struct listdir_stat), /*tp_basicsize*/
104 0, /*tp_itemsize*/
104 0, /*tp_itemsize*/
105 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
105 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
106 0, /*tp_print*/
106 0, /*tp_print*/
107 0, /*tp_getattr*/
107 0, /*tp_getattr*/
108 0, /*tp_setattr*/
108 0, /*tp_setattr*/
109 0, /*tp_compare*/
109 0, /*tp_compare*/
110 0, /*tp_repr*/
110 0, /*tp_repr*/
111 0, /*tp_as_number*/
111 0, /*tp_as_number*/
112 0, /*tp_as_sequence*/
112 0, /*tp_as_sequence*/
113 0, /*tp_as_mapping*/
113 0, /*tp_as_mapping*/
114 0, /*tp_hash */
114 0, /*tp_hash */
115 0, /*tp_call*/
115 0, /*tp_call*/
116 0, /*tp_str*/
116 0, /*tp_str*/
117 0, /*tp_getattro*/
117 0, /*tp_getattro*/
118 0, /*tp_setattro*/
118 0, /*tp_setattro*/
119 0, /*tp_as_buffer*/
119 0, /*tp_as_buffer*/
120 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
120 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
121 "stat objects", /* tp_doc */
121 "stat objects", /* tp_doc */
122 0, /* tp_traverse */
122 0, /* tp_traverse */
123 0, /* tp_clear */
123 0, /* tp_clear */
124 0, /* tp_richcompare */
124 0, /* tp_richcompare */
125 0, /* tp_weaklistoffset */
125 0, /* tp_weaklistoffset */
126 0, /* tp_iter */
126 0, /* tp_iter */
127 0, /* tp_iternext */
127 0, /* tp_iternext */
128 0, /* tp_methods */
128 0, /* tp_methods */
129 0, /* tp_members */
129 0, /* tp_members */
130 listdir_stat_getsets, /* tp_getset */
130 listdir_stat_getsets, /* tp_getset */
131 0, /* tp_base */
131 0, /* tp_base */
132 0, /* tp_dict */
132 0, /* tp_dict */
133 0, /* tp_descr_get */
133 0, /* tp_descr_get */
134 0, /* tp_descr_set */
134 0, /* tp_descr_set */
135 0, /* tp_dictoffset */
135 0, /* tp_dictoffset */
136 0, /* tp_init */
136 0, /* tp_init */
137 0, /* tp_alloc */
137 0, /* tp_alloc */
138 listdir_stat_new, /* tp_new */
138 listdir_stat_new, /* tp_new */
139 };
139 };
140
140
141 #ifdef _WIN32
141 #ifdef _WIN32
142
142
143 static int to_python_time(const FILETIME *tm)
143 static int to_python_time(const FILETIME *tm)
144 {
144 {
145 /* number of seconds between epoch and January 1 1601 */
145 /* number of seconds between epoch and January 1 1601 */
146 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
146 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
147 /* conversion factor from 100ns to 1s */
147 /* conversion factor from 100ns to 1s */
148 const __int64 a1 = 10000000;
148 const __int64 a1 = 10000000;
149 /* explicit (int) cast to suspend compiler warnings */
149 /* explicit (int) cast to suspend compiler warnings */
150 return (int)((((__int64)tm->dwHighDateTime << 32)
150 return (int)((((__int64)tm->dwHighDateTime << 32)
151 + tm->dwLowDateTime) / a1 - a0);
151 + tm->dwLowDateTime) / a1 - a0);
152 }
152 }
153
153
154 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
154 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
155 {
155 {
156 PyObject *py_st;
156 PyObject *py_st;
157 struct hg_stat *stp;
157 struct hg_stat *stp;
158
158
159 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
159 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
160 ? _S_IFDIR : _S_IFREG;
160 ? _S_IFDIR : _S_IFREG;
161
161
162 if (!wantstat)
162 if (!wantstat)
163 return Py_BuildValue("si", fd->cFileName, kind);
163 return Py_BuildValue("si", fd->cFileName, kind);
164
164
165 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
165 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
166 if (!py_st)
166 if (!py_st)
167 return NULL;
167 return NULL;
168
168
169 stp = &((struct listdir_stat *)py_st)->st;
169 stp = &((struct listdir_stat *)py_st)->st;
170 /*
170 /*
171 use kind as st_mode
171 use kind as st_mode
172 rwx bits on Win32 are meaningless
172 rwx bits on Win32 are meaningless
173 and Hg does not use them anyway
173 and Hg does not use them anyway
174 */
174 */
175 stp->st_mode = kind;
175 stp->st_mode = kind;
176 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
176 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
177 stp->st_ctime = to_python_time(&fd->ftCreationTime);
177 stp->st_ctime = to_python_time(&fd->ftCreationTime);
178 if (kind == _S_IFREG)
178 if (kind == _S_IFREG)
179 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
179 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
180 + fd->nFileSizeLow;
180 + fd->nFileSizeLow;
181 return Py_BuildValue("siN", fd->cFileName,
181 return Py_BuildValue("siN", fd->cFileName,
182 kind, py_st);
182 kind, py_st);
183 }
183 }
184
184
185 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
185 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
186 {
186 {
187 PyObject *rval = NULL; /* initialize - return value */
187 PyObject *rval = NULL; /* initialize - return value */
188 PyObject *list;
188 PyObject *list;
189 HANDLE fh;
189 HANDLE fh;
190 WIN32_FIND_DATAA fd;
190 WIN32_FIND_DATAA fd;
191 char *pattern;
191 char *pattern;
192
192
193 /* build the path + \* pattern string */
193 /* build the path + \* pattern string */
194 pattern = malloc(plen + 3); /* path + \* + \0 */
194 pattern = malloc(plen + 3); /* path + \* + \0 */
195 if (!pattern) {
195 if (!pattern) {
196 PyErr_NoMemory();
196 PyErr_NoMemory();
197 goto error_nomem;
197 goto error_nomem;
198 }
198 }
199 strcpy(pattern, path);
199 strcpy(pattern, path);
200
200
201 if (plen > 0) {
201 if (plen > 0) {
202 char c = path[plen-1];
202 char c = path[plen-1];
203 if (c != ':' && c != '/' && c != '\\')
203 if (c != ':' && c != '/' && c != '\\')
204 pattern[plen++] = '\\';
204 pattern[plen++] = '\\';
205 }
205 }
206 strcpy(pattern + plen, "*");
206 strcpy(pattern + plen, "*");
207
207
208 fh = FindFirstFileA(pattern, &fd);
208 fh = FindFirstFileA(pattern, &fd);
209 if (fh == INVALID_HANDLE_VALUE) {
209 if (fh == INVALID_HANDLE_VALUE) {
210 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
210 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
211 goto error_file;
211 goto error_file;
212 }
212 }
213
213
214 list = PyList_New(0);
214 list = PyList_New(0);
215 if (!list)
215 if (!list)
216 goto error_list;
216 goto error_list;
217
217
218 do {
218 do {
219 PyObject *item;
219 PyObject *item;
220
220
221 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
221 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
222 if (!strcmp(fd.cFileName, ".")
222 if (!strcmp(fd.cFileName, ".")
223 || !strcmp(fd.cFileName, ".."))
223 || !strcmp(fd.cFileName, ".."))
224 continue;
224 continue;
225
225
226 if (skip && !strcmp(fd.cFileName, skip)) {
226 if (skip && !strcmp(fd.cFileName, skip)) {
227 rval = PyList_New(0);
227 rval = PyList_New(0);
228 goto error;
228 goto error;
229 }
229 }
230 }
230 }
231
231
232 item = make_item(&fd, wantstat);
232 item = make_item(&fd, wantstat);
233 if (!item)
233 if (!item)
234 goto error;
234 goto error;
235
235
236 if (PyList_Append(list, item)) {
236 if (PyList_Append(list, item)) {
237 Py_XDECREF(item);
237 Py_XDECREF(item);
238 goto error;
238 goto error;
239 }
239 }
240
240
241 Py_XDECREF(item);
241 Py_XDECREF(item);
242 } while (FindNextFileA(fh, &fd));
242 } while (FindNextFileA(fh, &fd));
243
243
244 if (GetLastError() != ERROR_NO_MORE_FILES) {
244 if (GetLastError() != ERROR_NO_MORE_FILES) {
245 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
245 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
246 goto error;
246 goto error;
247 }
247 }
248
248
249 rval = list;
249 rval = list;
250 Py_XINCREF(rval);
250 Py_XINCREF(rval);
251 error:
251 error:
252 Py_XDECREF(list);
252 Py_XDECREF(list);
253 error_list:
253 error_list:
254 FindClose(fh);
254 FindClose(fh);
255 error_file:
255 error_file:
256 free(pattern);
256 free(pattern);
257 error_nomem:
257 error_nomem:
258 return rval;
258 return rval;
259 }
259 }
260
260
261 #else
261 #else
262
262
263 int entkind(struct dirent *ent)
263 int entkind(struct dirent *ent)
264 {
264 {
265 #ifdef DT_REG
265 #ifdef DT_REG
266 switch (ent->d_type) {
266 switch (ent->d_type) {
267 case DT_REG: return S_IFREG;
267 case DT_REG: return S_IFREG;
268 case DT_DIR: return S_IFDIR;
268 case DT_DIR: return S_IFDIR;
269 case DT_LNK: return S_IFLNK;
269 case DT_LNK: return S_IFLNK;
270 case DT_BLK: return S_IFBLK;
270 case DT_BLK: return S_IFBLK;
271 case DT_CHR: return S_IFCHR;
271 case DT_CHR: return S_IFCHR;
272 case DT_FIFO: return S_IFIFO;
272 case DT_FIFO: return S_IFIFO;
273 case DT_SOCK: return S_IFSOCK;
273 case DT_SOCK: return S_IFSOCK;
274 }
274 }
275 #endif
275 #endif
276 return -1;
276 return -1;
277 }
277 }
278
278
279 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
279 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
280 {
280 {
281 PyObject *list, *elem, *stat, *ret = NULL;
281 PyObject *list, *elem, *stat, *ret = NULL;
282 char fullpath[PATH_MAX + 10];
282 char fullpath[PATH_MAX + 10];
283 int kind, err;
283 int kind, err;
284 struct stat st;
284 struct stat st;
285 struct dirent *ent;
285 struct dirent *ent;
286 DIR *dir;
286 DIR *dir;
287 #ifdef AT_SYMLINK_NOFOLLOW
287 #ifdef AT_SYMLINK_NOFOLLOW
288 int dfd = -1;
288 int dfd = -1;
289 #endif
289 #endif
290
290
291 if (pathlen >= PATH_MAX) {
291 if (pathlen >= PATH_MAX) {
292 errno = ENAMETOOLONG;
292 errno = ENAMETOOLONG;
293 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
293 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
294 goto error_value;
294 goto error_value;
295 }
295 }
296 strncpy(fullpath, path, PATH_MAX);
296 strncpy(fullpath, path, PATH_MAX);
297 fullpath[pathlen] = '/';
297 fullpath[pathlen] = '/';
298
298
299 #ifdef AT_SYMLINK_NOFOLLOW
299 #ifdef AT_SYMLINK_NOFOLLOW
300 dfd = open(path, O_RDONLY);
300 dfd = open(path, O_RDONLY);
301 if (dfd == -1) {
301 if (dfd == -1) {
302 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
302 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
303 goto error_value;
303 goto error_value;
304 }
304 }
305 dir = fdopendir(dfd);
305 dir = fdopendir(dfd);
306 #else
306 #else
307 dir = opendir(path);
307 dir = opendir(path);
308 #endif
308 #endif
309 if (!dir) {
309 if (!dir) {
310 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
310 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
311 goto error_dir;
311 goto error_dir;
312 }
312 }
313
313
314 list = PyList_New(0);
314 list = PyList_New(0);
315 if (!list)
315 if (!list)
316 goto error_list;
316 goto error_list;
317
317
318 while ((ent = readdir(dir))) {
318 while ((ent = readdir(dir))) {
319 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
319 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
320 continue;
320 continue;
321
321
322 kind = entkind(ent);
322 kind = entkind(ent);
323 if (kind == -1 || keepstat) {
323 if (kind == -1 || keepstat) {
324 #ifdef AT_SYMLINK_NOFOLLOW
324 #ifdef AT_SYMLINK_NOFOLLOW
325 err = fstatat(dfd, ent->d_name, &st,
325 err = fstatat(dfd, ent->d_name, &st,
326 AT_SYMLINK_NOFOLLOW);
326 AT_SYMLINK_NOFOLLOW);
327 #else
327 #else
328 strncpy(fullpath + pathlen + 1, ent->d_name,
328 strncpy(fullpath + pathlen + 1, ent->d_name,
329 PATH_MAX - pathlen);
329 PATH_MAX - pathlen);
330 fullpath[PATH_MAX] = 0;
330 fullpath[PATH_MAX] = 0;
331 err = lstat(fullpath, &st);
331 err = lstat(fullpath, &st);
332 #endif
332 #endif
333 if (err == -1) {
333 if (err == -1) {
334 strncpy(fullpath + pathlen + 1, ent->d_name,
334 strncpy(fullpath + pathlen + 1, ent->d_name,
335 PATH_MAX - pathlen);
335 PATH_MAX - pathlen);
336 fullpath[PATH_MAX] = 0;
336 fullpath[PATH_MAX] = 0;
337 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
337 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
338 fullpath);
338 fullpath);
339 goto error;
339 goto error;
340 }
340 }
341 kind = st.st_mode & S_IFMT;
341 kind = st.st_mode & S_IFMT;
342 }
342 }
343
343
344 /* quit early? */
344 /* quit early? */
345 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
345 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
346 ret = PyList_New(0);
346 ret = PyList_New(0);
347 goto error;
347 goto error;
348 }
348 }
349
349
350 if (keepstat) {
350 if (keepstat) {
351 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
351 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
352 if (!stat)
352 if (!stat)
353 goto error;
353 goto error;
354 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
354 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
355 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
355 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
356 } else
356 } else
357 elem = Py_BuildValue("si", ent->d_name, kind);
357 elem = Py_BuildValue("si", ent->d_name, kind);
358 if (!elem)
358 if (!elem)
359 goto error;
359 goto error;
360
360
361 PyList_Append(list, elem);
361 PyList_Append(list, elem);
362 Py_DECREF(elem);
362 Py_DECREF(elem);
363 }
363 }
364
364
365 ret = list;
365 ret = list;
366 Py_INCREF(ret);
366 Py_INCREF(ret);
367
367
368 error:
368 error:
369 Py_DECREF(list);
369 Py_DECREF(list);
370 error_list:
370 error_list:
371 closedir(dir);
371 closedir(dir);
372 error_dir:
372 error_dir:
373 #ifdef AT_SYMLINK_NOFOLLOW
373 #ifdef AT_SYMLINK_NOFOLLOW
374 close(dfd);
374 close(dfd);
375 #endif
375 #endif
376 error_value:
376 error_value:
377 return ret;
377 return ret;
378 }
378 }
379
379
380 #endif /* ndef _WIN32 */
380 #endif /* ndef _WIN32 */
381
381
382 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
382 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
383 {
383 {
384 PyObject *statobj = NULL; /* initialize - optional arg */
384 PyObject *statobj = NULL; /* initialize - optional arg */
385 PyObject *skipobj = NULL; /* initialize - optional arg */
385 PyObject *skipobj = NULL; /* initialize - optional arg */
386 char *path, *skip = NULL;
386 char *path, *skip = NULL;
387 int wantstat, plen;
387 int wantstat, plen;
388
388
389 static char *kwlist[] = {"path", "stat", "skip", NULL};
389 static char *kwlist[] = {"path", "stat", "skip", NULL};
390
390
391 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
391 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
392 kwlist, &path, &plen, &statobj, &skipobj))
392 kwlist, &path, &plen, &statobj, &skipobj))
393 return NULL;
393 return NULL;
394
394
395 wantstat = statobj && PyObject_IsTrue(statobj);
395 wantstat = statobj && PyObject_IsTrue(statobj);
396
396
397 if (skipobj && skipobj != Py_None) {
397 if (skipobj && skipobj != Py_None) {
398 skip = PyBytes_AsString(skipobj);
398 skip = PyBytes_AsString(skipobj);
399 if (!skip)
399 if (!skip)
400 return NULL;
400 return NULL;
401 }
401 }
402
402
403 return _listdir(path, plen, wantstat, skip);
403 return _listdir(path, plen, wantstat, skip);
404 }
404 }
405
405
406 #ifdef _WIN32
406 #ifdef _WIN32
407 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
407 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
408 {
408 {
409 static char *kwlist[] = {"name", "mode", "buffering", NULL};
409 static char *kwlist[] = {"name", "mode", "buffering", NULL};
410 PyObject *file_obj = NULL;
410 PyObject *file_obj = NULL;
411 char *name = NULL;
411 char *name = NULL;
412 char *mode = "rb";
412 char *mode = "rb";
413 DWORD access = 0;
413 DWORD access = 0;
414 DWORD creation;
414 DWORD creation;
415 HANDLE handle;
415 HANDLE handle;
416 int fd, flags = 0;
416 int fd, flags = 0;
417 int bufsize = -1;
417 int bufsize = -1;
418 char m0, m1, m2;
418 char m0, m1, m2;
419 char fpmode[4];
419 char fpmode[4];
420 int fppos = 0;
420 int fppos = 0;
421 int plus;
421 int plus;
422 FILE *fp;
422 FILE *fp;
423
423
424 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
424 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
425 Py_FileSystemDefaultEncoding,
425 Py_FileSystemDefaultEncoding,
426 &name, &mode, &bufsize))
426 &name, &mode, &bufsize))
427 return NULL;
427 return NULL;
428
428
429 m0 = mode[0];
429 m0 = mode[0];
430 m1 = m0 ? mode[1] : '\0';
430 m1 = m0 ? mode[1] : '\0';
431 m2 = m1 ? mode[2] : '\0';
431 m2 = m1 ? mode[2] : '\0';
432 plus = m1 == '+' || m2 == '+';
432 plus = m1 == '+' || m2 == '+';
433
433
434 fpmode[fppos++] = m0;
434 fpmode[fppos++] = m0;
435 if (m1 == 'b' || m2 == 'b') {
435 if (m1 == 'b' || m2 == 'b') {
436 flags = _O_BINARY;
436 flags = _O_BINARY;
437 fpmode[fppos++] = 'b';
437 fpmode[fppos++] = 'b';
438 }
438 }
439 else
439 else
440 flags = _O_TEXT;
440 flags = _O_TEXT;
441 if (m0 == 'r' && !plus) {
441 if (m0 == 'r' && !plus) {
442 flags |= _O_RDONLY;
442 flags |= _O_RDONLY;
443 access = GENERIC_READ;
443 access = GENERIC_READ;
444 } else {
444 } else {
445 /*
445 /*
446 work around http://support.microsoft.com/kb/899149 and
446 work around http://support.microsoft.com/kb/899149 and
447 set _O_RDWR for 'w' and 'a', even if mode has no '+'
447 set _O_RDWR for 'w' and 'a', even if mode has no '+'
448 */
448 */
449 flags |= _O_RDWR;
449 flags |= _O_RDWR;
450 access = GENERIC_READ | GENERIC_WRITE;
450 access = GENERIC_READ | GENERIC_WRITE;
451 fpmode[fppos++] = '+';
451 fpmode[fppos++] = '+';
452 }
452 }
453 fpmode[fppos++] = '\0';
453 fpmode[fppos++] = '\0';
454
454
455 switch (m0) {
455 switch (m0) {
456 case 'r':
456 case 'r':
457 creation = OPEN_EXISTING;
457 creation = OPEN_EXISTING;
458 break;
458 break;
459 case 'w':
459 case 'w':
460 creation = CREATE_ALWAYS;
460 creation = CREATE_ALWAYS;
461 break;
461 break;
462 case 'a':
462 case 'a':
463 creation = OPEN_ALWAYS;
463 creation = OPEN_ALWAYS;
464 flags |= _O_APPEND;
464 flags |= _O_APPEND;
465 break;
465 break;
466 default:
466 default:
467 PyErr_Format(PyExc_ValueError,
467 PyErr_Format(PyExc_ValueError,
468 "mode string must begin with one of 'r', 'w', "
468 "mode string must begin with one of 'r', 'w', "
469 "or 'a', not '%c'", m0);
469 "or 'a', not '%c'", m0);
470 goto bail;
470 goto bail;
471 }
471 }
472
472
473 handle = CreateFile(name, access,
473 handle = CreateFile(name, access,
474 FILE_SHARE_READ | FILE_SHARE_WRITE |
474 FILE_SHARE_READ | FILE_SHARE_WRITE |
475 FILE_SHARE_DELETE,
475 FILE_SHARE_DELETE,
476 NULL,
476 NULL,
477 creation,
477 creation,
478 FILE_ATTRIBUTE_NORMAL,
478 FILE_ATTRIBUTE_NORMAL,
479 0);
479 0);
480
480
481 if (handle == INVALID_HANDLE_VALUE) {
481 if (handle == INVALID_HANDLE_VALUE) {
482 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
482 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
483 goto bail;
483 goto bail;
484 }
484 }
485
485
486 fd = _open_osfhandle((intptr_t)handle, flags);
486 fd = _open_osfhandle((intptr_t)handle, flags);
487
487
488 if (fd == -1) {
488 if (fd == -1) {
489 CloseHandle(handle);
489 CloseHandle(handle);
490 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
490 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
491 goto bail;
491 goto bail;
492 }
492 }
493 #ifndef IS_PY3K
493 #ifndef IS_PY3K
494 fp = _fdopen(fd, fpmode);
494 fp = _fdopen(fd, fpmode);
495 if (fp == NULL) {
495 if (fp == NULL) {
496 _close(fd);
496 _close(fd);
497 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
497 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
498 goto bail;
498 goto bail;
499 }
499 }
500
500
501 file_obj = PyFile_FromFile(fp, name, mode, fclose);
501 file_obj = PyFile_FromFile(fp, name, mode, fclose);
502 if (file_obj == NULL) {
502 if (file_obj == NULL) {
503 fclose(fp);
503 fclose(fp);
504 goto bail;
504 goto bail;
505 }
505 }
506
506
507 PyFile_SetBufSize(file_obj, bufsize);
507 PyFile_SetBufSize(file_obj, bufsize);
508 #else
508 #else
509 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
509 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
510 if (file_obj == NULL)
510 if (file_obj == NULL)
511 goto bail;
511 goto bail;
512 #endif
512 #endif
513 bail:
513 bail:
514 PyMem_Free(name);
514 PyMem_Free(name);
515 return file_obj;
515 return file_obj;
516 }
516 }
517 #endif
517 #endif
518
518
519 #ifdef __APPLE__
519 #ifdef __APPLE__
520 #include <ApplicationServices/ApplicationServices.h>
520 #include <ApplicationServices/ApplicationServices.h>
521
521
522 static PyObject *isgui(PyObject *self)
522 static PyObject *isgui(PyObject *self)
523 {
523 {
524 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
524 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
525
525
526 if (dict != NULL) {
526 if (dict != NULL) {
527 CFRelease(dict);
527 CFRelease(dict);
528 return Py_True;
528 Py_RETURN_TRUE;
529 } else {
529 } else {
530 return Py_False;
530 Py_RETURN_FALSE;
531 }
531 }
532 }
532 }
533 #endif
533 #endif
534
534
535 static char osutil_doc[] = "Native operating system services.";
535 static char osutil_doc[] = "Native operating system services.";
536
536
537 static PyMethodDef methods[] = {
537 static PyMethodDef methods[] = {
538 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
538 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
539 "list a directory\n"},
539 "list a directory\n"},
540 #ifdef _WIN32
540 #ifdef _WIN32
541 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
541 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
542 "Open a file with POSIX-like semantics.\n"
542 "Open a file with POSIX-like semantics.\n"
543 "On error, this function may raise either a WindowsError or an IOError."},
543 "On error, this function may raise either a WindowsError or an IOError."},
544 #endif
544 #endif
545 #ifdef __APPLE__
545 #ifdef __APPLE__
546 {
546 {
547 "isgui", (PyCFunction)isgui, METH_NOARGS,
547 "isgui", (PyCFunction)isgui, METH_NOARGS,
548 "Is a CoreGraphics session available?"
548 "Is a CoreGraphics session available?"
549 },
549 },
550 #endif
550 #endif
551 {NULL, NULL}
551 {NULL, NULL}
552 };
552 };
553
553
554 #ifdef IS_PY3K
554 #ifdef IS_PY3K
555 static struct PyModuleDef osutil_module = {
555 static struct PyModuleDef osutil_module = {
556 PyModuleDef_HEAD_INIT,
556 PyModuleDef_HEAD_INIT,
557 "osutil",
557 "osutil",
558 osutil_doc,
558 osutil_doc,
559 -1,
559 -1,
560 methods
560 methods
561 };
561 };
562
562
563 PyMODINIT_FUNC PyInit_osutil(void)
563 PyMODINIT_FUNC PyInit_osutil(void)
564 {
564 {
565 if (PyType_Ready(&listdir_stat_type) < 0)
565 if (PyType_Ready(&listdir_stat_type) < 0)
566 return NULL;
566 return NULL;
567
567
568 return PyModule_Create(&osutil_module);
568 return PyModule_Create(&osutil_module);
569 }
569 }
570 #else
570 #else
571 PyMODINIT_FUNC initosutil(void)
571 PyMODINIT_FUNC initosutil(void)
572 {
572 {
573 if (PyType_Ready(&listdir_stat_type) == -1)
573 if (PyType_Ready(&listdir_stat_type) == -1)
574 return;
574 return;
575
575
576 Py_InitModule3("osutil", methods, osutil_doc);
576 Py_InitModule3("osutil", methods, osutil_doc);
577 }
577 }
578 #endif
578 #endif
@@ -1,449 +1,452
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 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import encoding
8 import encoding
9 import ctypes, errno, os, struct, subprocess, random
9 import ctypes, errno, os, struct, subprocess, random
10
10
11 _kernel32 = ctypes.windll.kernel32
11 _kernel32 = ctypes.windll.kernel32
12 _advapi32 = ctypes.windll.advapi32
12 _advapi32 = ctypes.windll.advapi32
13 _user32 = ctypes.windll.user32
13 _user32 = ctypes.windll.user32
14
14
15 _BOOL = ctypes.c_long
15 _BOOL = ctypes.c_long
16 _WORD = ctypes.c_ushort
16 _WORD = ctypes.c_ushort
17 _DWORD = ctypes.c_ulong
17 _DWORD = ctypes.c_ulong
18 _UINT = ctypes.c_uint
18 _UINT = ctypes.c_uint
19 _LONG = ctypes.c_long
19 _LONG = ctypes.c_long
20 _LPCSTR = _LPSTR = ctypes.c_char_p
20 _LPCSTR = _LPSTR = ctypes.c_char_p
21 _HANDLE = ctypes.c_void_p
21 _HANDLE = ctypes.c_void_p
22 _HWND = _HANDLE
22 _HWND = _HANDLE
23
23
24 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
24 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
25
25
26 # GetLastError
26 # GetLastError
27 _ERROR_SUCCESS = 0
27 _ERROR_SUCCESS = 0
28 _ERROR_INVALID_PARAMETER = 87
28 _ERROR_INVALID_PARAMETER = 87
29 _ERROR_INSUFFICIENT_BUFFER = 122
29 _ERROR_INSUFFICIENT_BUFFER = 122
30
30
31 # WPARAM is defined as UINT_PTR (unsigned type)
31 # WPARAM is defined as UINT_PTR (unsigned type)
32 # LPARAM is defined as LONG_PTR (signed type)
32 # LPARAM is defined as LONG_PTR (signed type)
33 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
33 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
34 _WPARAM = ctypes.c_ulong
34 _WPARAM = ctypes.c_ulong
35 _LPARAM = ctypes.c_long
35 _LPARAM = ctypes.c_long
36 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
36 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
37 _WPARAM = ctypes.c_ulonglong
37 _WPARAM = ctypes.c_ulonglong
38 _LPARAM = ctypes.c_longlong
38 _LPARAM = ctypes.c_longlong
39
39
40 class _FILETIME(ctypes.Structure):
40 class _FILETIME(ctypes.Structure):
41 _fields_ = [('dwLowDateTime', _DWORD),
41 _fields_ = [('dwLowDateTime', _DWORD),
42 ('dwHighDateTime', _DWORD)]
42 ('dwHighDateTime', _DWORD)]
43
43
44 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
44 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
45 _fields_ = [('dwFileAttributes', _DWORD),
45 _fields_ = [('dwFileAttributes', _DWORD),
46 ('ftCreationTime', _FILETIME),
46 ('ftCreationTime', _FILETIME),
47 ('ftLastAccessTime', _FILETIME),
47 ('ftLastAccessTime', _FILETIME),
48 ('ftLastWriteTime', _FILETIME),
48 ('ftLastWriteTime', _FILETIME),
49 ('dwVolumeSerialNumber', _DWORD),
49 ('dwVolumeSerialNumber', _DWORD),
50 ('nFileSizeHigh', _DWORD),
50 ('nFileSizeHigh', _DWORD),
51 ('nFileSizeLow', _DWORD),
51 ('nFileSizeLow', _DWORD),
52 ('nNumberOfLinks', _DWORD),
52 ('nNumberOfLinks', _DWORD),
53 ('nFileIndexHigh', _DWORD),
53 ('nFileIndexHigh', _DWORD),
54 ('nFileIndexLow', _DWORD)]
54 ('nFileIndexLow', _DWORD)]
55
55
56 # CreateFile
56 # CreateFile
57 _FILE_SHARE_READ = 0x00000001
57 _FILE_SHARE_READ = 0x00000001
58 _FILE_SHARE_WRITE = 0x00000002
58 _FILE_SHARE_WRITE = 0x00000002
59 _FILE_SHARE_DELETE = 0x00000004
59 _FILE_SHARE_DELETE = 0x00000004
60
60
61 _OPEN_EXISTING = 3
61 _OPEN_EXISTING = 3
62
62
63 # SetFileAttributes
63 # SetFileAttributes
64 _FILE_ATTRIBUTE_NORMAL = 0x80
64 _FILE_ATTRIBUTE_NORMAL = 0x80
65 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
65 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
66
66
67 # Process Security and Access Rights
67 # Process Security and Access Rights
68 _PROCESS_QUERY_INFORMATION = 0x0400
68 _PROCESS_QUERY_INFORMATION = 0x0400
69
69
70 # GetExitCodeProcess
70 # GetExitCodeProcess
71 _STILL_ACTIVE = 259
71 _STILL_ACTIVE = 259
72
72
73 # registry
73 # registry
74 _HKEY_CURRENT_USER = 0x80000001L
74 _HKEY_CURRENT_USER = 0x80000001L
75 _HKEY_LOCAL_MACHINE = 0x80000002L
75 _HKEY_LOCAL_MACHINE = 0x80000002L
76 _KEY_READ = 0x20019
76 _KEY_READ = 0x20019
77 _REG_SZ = 1
77 _REG_SZ = 1
78 _REG_DWORD = 4
78 _REG_DWORD = 4
79
79
80 class _STARTUPINFO(ctypes.Structure):
80 class _STARTUPINFO(ctypes.Structure):
81 _fields_ = [('cb', _DWORD),
81 _fields_ = [('cb', _DWORD),
82 ('lpReserved', _LPSTR),
82 ('lpReserved', _LPSTR),
83 ('lpDesktop', _LPSTR),
83 ('lpDesktop', _LPSTR),
84 ('lpTitle', _LPSTR),
84 ('lpTitle', _LPSTR),
85 ('dwX', _DWORD),
85 ('dwX', _DWORD),
86 ('dwY', _DWORD),
86 ('dwY', _DWORD),
87 ('dwXSize', _DWORD),
87 ('dwXSize', _DWORD),
88 ('dwYSize', _DWORD),
88 ('dwYSize', _DWORD),
89 ('dwXCountChars', _DWORD),
89 ('dwXCountChars', _DWORD),
90 ('dwYCountChars', _DWORD),
90 ('dwYCountChars', _DWORD),
91 ('dwFillAttribute', _DWORD),
91 ('dwFillAttribute', _DWORD),
92 ('dwFlags', _DWORD),
92 ('dwFlags', _DWORD),
93 ('wShowWindow', _WORD),
93 ('wShowWindow', _WORD),
94 ('cbReserved2', _WORD),
94 ('cbReserved2', _WORD),
95 ('lpReserved2', ctypes.c_char_p),
95 ('lpReserved2', ctypes.c_char_p),
96 ('hStdInput', _HANDLE),
96 ('hStdInput', _HANDLE),
97 ('hStdOutput', _HANDLE),
97 ('hStdOutput', _HANDLE),
98 ('hStdError', _HANDLE)]
98 ('hStdError', _HANDLE)]
99
99
100 class _PROCESS_INFORMATION(ctypes.Structure):
100 class _PROCESS_INFORMATION(ctypes.Structure):
101 _fields_ = [('hProcess', _HANDLE),
101 _fields_ = [('hProcess', _HANDLE),
102 ('hThread', _HANDLE),
102 ('hThread', _HANDLE),
103 ('dwProcessId', _DWORD),
103 ('dwProcessId', _DWORD),
104 ('dwThreadId', _DWORD)]
104 ('dwThreadId', _DWORD)]
105
105
106 _DETACHED_PROCESS = 0x00000008
106 _DETACHED_PROCESS = 0x00000008
107 _STARTF_USESHOWWINDOW = 0x00000001
107 _STARTF_USESHOWWINDOW = 0x00000001
108 _SW_HIDE = 0
108 _SW_HIDE = 0
109
109
110 class _COORD(ctypes.Structure):
110 class _COORD(ctypes.Structure):
111 _fields_ = [('X', ctypes.c_short),
111 _fields_ = [('X', ctypes.c_short),
112 ('Y', ctypes.c_short)]
112 ('Y', ctypes.c_short)]
113
113
114 class _SMALL_RECT(ctypes.Structure):
114 class _SMALL_RECT(ctypes.Structure):
115 _fields_ = [('Left', ctypes.c_short),
115 _fields_ = [('Left', ctypes.c_short),
116 ('Top', ctypes.c_short),
116 ('Top', ctypes.c_short),
117 ('Right', ctypes.c_short),
117 ('Right', ctypes.c_short),
118 ('Bottom', ctypes.c_short)]
118 ('Bottom', ctypes.c_short)]
119
119
120 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
120 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
121 _fields_ = [('dwSize', _COORD),
121 _fields_ = [('dwSize', _COORD),
122 ('dwCursorPosition', _COORD),
122 ('dwCursorPosition', _COORD),
123 ('wAttributes', _WORD),
123 ('wAttributes', _WORD),
124 ('srWindow', _SMALL_RECT),
124 ('srWindow', _SMALL_RECT),
125 ('dwMaximumWindowSize', _COORD)]
125 ('dwMaximumWindowSize', _COORD)]
126
126
127 _STD_ERROR_HANDLE = _DWORD(-12).value
127 _STD_ERROR_HANDLE = _DWORD(-12).value
128
128
129 # types of parameters of C functions used (required by pypy)
129 # types of parameters of C functions used (required by pypy)
130
130
131 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
131 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
132 _DWORD, _DWORD, _HANDLE]
132 _DWORD, _DWORD, _HANDLE]
133 _kernel32.CreateFileA.restype = _HANDLE
133 _kernel32.CreateFileA.restype = _HANDLE
134
134
135 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
135 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
136 _kernel32.GetFileInformationByHandle.restype = _BOOL
136 _kernel32.GetFileInformationByHandle.restype = _BOOL
137
137
138 _kernel32.CloseHandle.argtypes = [_HANDLE]
138 _kernel32.CloseHandle.argtypes = [_HANDLE]
139 _kernel32.CloseHandle.restype = _BOOL
139 _kernel32.CloseHandle.restype = _BOOL
140
140
141 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
141 try:
142 _kernel32.CreateHardLinkA.restype = _BOOL
142 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
143 _kernel32.CreateHardLinkA.restype = _BOOL
144 except AttributeError:
145 pass
143
146
144 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
147 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
145 _kernel32.SetFileAttributesA.restype = _BOOL
148 _kernel32.SetFileAttributesA.restype = _BOOL
146
149
147 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
150 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
148 _kernel32.OpenProcess.restype = _HANDLE
151 _kernel32.OpenProcess.restype = _HANDLE
149
152
150 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
153 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
151 _kernel32.GetExitCodeProcess.restype = _BOOL
154 _kernel32.GetExitCodeProcess.restype = _BOOL
152
155
153 _kernel32.GetLastError.argtypes = []
156 _kernel32.GetLastError.argtypes = []
154 _kernel32.GetLastError.restype = _DWORD
157 _kernel32.GetLastError.restype = _DWORD
155
158
156 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
159 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
157 _kernel32.GetModuleFileNameA.restype = _DWORD
160 _kernel32.GetModuleFileNameA.restype = _DWORD
158
161
159 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
162 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
160 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
163 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
161 ctypes.c_void_p]
164 ctypes.c_void_p]
162 _kernel32.CreateProcessA.restype = _BOOL
165 _kernel32.CreateProcessA.restype = _BOOL
163
166
164 _kernel32.ExitProcess.argtypes = [_UINT]
167 _kernel32.ExitProcess.argtypes = [_UINT]
165 _kernel32.ExitProcess.restype = None
168 _kernel32.ExitProcess.restype = None
166
169
167 _kernel32.GetCurrentProcessId.argtypes = []
170 _kernel32.GetCurrentProcessId.argtypes = []
168 _kernel32.GetCurrentProcessId.restype = _DWORD
171 _kernel32.GetCurrentProcessId.restype = _DWORD
169
172
170 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
173 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
171 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
174 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
172 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
175 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
173
176
174 _kernel32.GetStdHandle.argtypes = [_DWORD]
177 _kernel32.GetStdHandle.argtypes = [_DWORD]
175 _kernel32.GetStdHandle.restype = _HANDLE
178 _kernel32.GetStdHandle.restype = _HANDLE
176
179
177 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
180 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
178 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
181 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
179
182
180 _advapi32.RegOpenKeyExA.argtypes = [_HANDLE, _LPCSTR, _DWORD, _DWORD,
183 _advapi32.RegOpenKeyExA.argtypes = [_HANDLE, _LPCSTR, _DWORD, _DWORD,
181 ctypes.c_void_p]
184 ctypes.c_void_p]
182 _advapi32.RegOpenKeyExA.restype = _LONG
185 _advapi32.RegOpenKeyExA.restype = _LONG
183
186
184 _advapi32.RegQueryValueExA.argtypes = [_HANDLE, _LPCSTR, ctypes.c_void_p,
187 _advapi32.RegQueryValueExA.argtypes = [_HANDLE, _LPCSTR, ctypes.c_void_p,
185 ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
188 ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
186 _advapi32.RegQueryValueExA.restype = _LONG
189 _advapi32.RegQueryValueExA.restype = _LONG
187
190
188 _advapi32.RegCloseKey.argtypes = [_HANDLE]
191 _advapi32.RegCloseKey.argtypes = [_HANDLE]
189 _advapi32.RegCloseKey.restype = _LONG
192 _advapi32.RegCloseKey.restype = _LONG
190
193
191 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
194 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
192 _advapi32.GetUserNameA.restype = _BOOL
195 _advapi32.GetUserNameA.restype = _BOOL
193
196
194 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
197 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
195 _user32.GetWindowThreadProcessId.restype = _DWORD
198 _user32.GetWindowThreadProcessId.restype = _DWORD
196
199
197 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
200 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
198 _user32.ShowWindow.restype = _BOOL
201 _user32.ShowWindow.restype = _BOOL
199
202
200 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
203 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
201 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
204 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
202 _user32.EnumWindows.restype = _BOOL
205 _user32.EnumWindows.restype = _BOOL
203
206
204 def _raiseoserror(name):
207 def _raiseoserror(name):
205 err = ctypes.WinError()
208 err = ctypes.WinError()
206 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
209 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
207
210
208 def _getfileinfo(name):
211 def _getfileinfo(name):
209 fh = _kernel32.CreateFileA(name, 0,
212 fh = _kernel32.CreateFileA(name, 0,
210 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
213 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
211 None, _OPEN_EXISTING, 0, None)
214 None, _OPEN_EXISTING, 0, None)
212 if fh == _INVALID_HANDLE_VALUE:
215 if fh == _INVALID_HANDLE_VALUE:
213 _raiseoserror(name)
216 _raiseoserror(name)
214 try:
217 try:
215 fi = _BY_HANDLE_FILE_INFORMATION()
218 fi = _BY_HANDLE_FILE_INFORMATION()
216 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
219 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
217 _raiseoserror(name)
220 _raiseoserror(name)
218 return fi
221 return fi
219 finally:
222 finally:
220 _kernel32.CloseHandle(fh)
223 _kernel32.CloseHandle(fh)
221
224
222 def oslink(src, dst):
225 def oslink(src, dst):
223 try:
226 try:
224 if not _kernel32.CreateHardLinkA(dst, src, None):
227 if not _kernel32.CreateHardLinkA(dst, src, None):
225 _raiseoserror(src)
228 _raiseoserror(src)
226 except AttributeError: # Wine doesn't support this function
229 except AttributeError: # Wine doesn't support this function
227 _raiseoserror(src)
230 _raiseoserror(src)
228
231
229 def nlinks(name):
232 def nlinks(name):
230 '''return number of hardlinks for the given file'''
233 '''return number of hardlinks for the given file'''
231 return _getfileinfo(name).nNumberOfLinks
234 return _getfileinfo(name).nNumberOfLinks
232
235
233 def samefile(fpath1, fpath2):
236 def samefile(fpath1, fpath2):
234 '''Returns whether fpath1 and fpath2 refer to the same file. This is only
237 '''Returns whether fpath1 and fpath2 refer to the same file. This is only
235 guaranteed to work for files, not directories.'''
238 guaranteed to work for files, not directories.'''
236 res1 = _getfileinfo(fpath1)
239 res1 = _getfileinfo(fpath1)
237 res2 = _getfileinfo(fpath2)
240 res2 = _getfileinfo(fpath2)
238 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
241 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
239 and res1.nFileIndexHigh == res2.nFileIndexHigh
242 and res1.nFileIndexHigh == res2.nFileIndexHigh
240 and res1.nFileIndexLow == res2.nFileIndexLow)
243 and res1.nFileIndexLow == res2.nFileIndexLow)
241
244
242 def samedevice(fpath1, fpath2):
245 def samedevice(fpath1, fpath2):
243 '''Returns whether fpath1 and fpath2 are on the same device. This is only
246 '''Returns whether fpath1 and fpath2 are on the same device. This is only
244 guaranteed to work for files, not directories.'''
247 guaranteed to work for files, not directories.'''
245 res1 = _getfileinfo(fpath1)
248 res1 = _getfileinfo(fpath1)
246 res2 = _getfileinfo(fpath2)
249 res2 = _getfileinfo(fpath2)
247 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
250 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
248
251
249 def testpid(pid):
252 def testpid(pid):
250 '''return True if pid is still running or unable to
253 '''return True if pid is still running or unable to
251 determine, False otherwise'''
254 determine, False otherwise'''
252 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
255 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
253 if h:
256 if h:
254 try:
257 try:
255 status = _DWORD()
258 status = _DWORD()
256 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
259 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
257 return status.value == _STILL_ACTIVE
260 return status.value == _STILL_ACTIVE
258 finally:
261 finally:
259 _kernel32.CloseHandle(h)
262 _kernel32.CloseHandle(h)
260 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
263 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
261
264
262 def lookupreg(key, valname=None, scope=None):
265 def lookupreg(key, valname=None, scope=None):
263 ''' Look up a key/value name in the Windows registry.
266 ''' Look up a key/value name in the Windows registry.
264
267
265 valname: value name. If unspecified, the default value for the key
268 valname: value name. If unspecified, the default value for the key
266 is used.
269 is used.
267 scope: optionally specify scope for registry lookup, this can be
270 scope: optionally specify scope for registry lookup, this can be
268 a sequence of scopes to look up in order. Default (CURRENT_USER,
271 a sequence of scopes to look up in order. Default (CURRENT_USER,
269 LOCAL_MACHINE).
272 LOCAL_MACHINE).
270 '''
273 '''
271 byref = ctypes.byref
274 byref = ctypes.byref
272 if scope is None:
275 if scope is None:
273 scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
276 scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
274 elif not isinstance(scope, (list, tuple)):
277 elif not isinstance(scope, (list, tuple)):
275 scope = (scope,)
278 scope = (scope,)
276 for s in scope:
279 for s in scope:
277 kh = _HANDLE()
280 kh = _HANDLE()
278 res = _advapi32.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
281 res = _advapi32.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
279 if res != _ERROR_SUCCESS:
282 if res != _ERROR_SUCCESS:
280 continue
283 continue
281 try:
284 try:
282 size = _DWORD(600)
285 size = _DWORD(600)
283 type = _DWORD()
286 type = _DWORD()
284 buf = ctypes.create_string_buffer(size.value + 1)
287 buf = ctypes.create_string_buffer(size.value + 1)
285 res = _advapi32.RegQueryValueExA(kh.value, valname, None,
288 res = _advapi32.RegQueryValueExA(kh.value, valname, None,
286 byref(type), buf, byref(size))
289 byref(type), buf, byref(size))
287 if res != _ERROR_SUCCESS:
290 if res != _ERROR_SUCCESS:
288 continue
291 continue
289 if type.value == _REG_SZ:
292 if type.value == _REG_SZ:
290 # never let a Unicode string escape into the wild
293 # never let a Unicode string escape into the wild
291 return encoding.tolocal(buf.value.encode('UTF-8'))
294 return encoding.tolocal(buf.value.encode('UTF-8'))
292 elif type.value == _REG_DWORD:
295 elif type.value == _REG_DWORD:
293 fmt = '<L'
296 fmt = '<L'
294 s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
297 s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
295 return struct.unpack(fmt, s)[0]
298 return struct.unpack(fmt, s)[0]
296 finally:
299 finally:
297 _advapi32.RegCloseKey(kh.value)
300 _advapi32.RegCloseKey(kh.value)
298
301
299 def executablepath():
302 def executablepath():
300 '''return full path of hg.exe'''
303 '''return full path of hg.exe'''
301 size = 600
304 size = 600
302 buf = ctypes.create_string_buffer(size + 1)
305 buf = ctypes.create_string_buffer(size + 1)
303 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
306 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
304 if len == 0:
307 if len == 0:
305 raise ctypes.WinError()
308 raise ctypes.WinError()
306 elif len == size:
309 elif len == size:
307 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
310 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
308 return buf.value
311 return buf.value
309
312
310 def getuser():
313 def getuser():
311 '''return name of current user'''
314 '''return name of current user'''
312 size = _DWORD(300)
315 size = _DWORD(300)
313 buf = ctypes.create_string_buffer(size.value + 1)
316 buf = ctypes.create_string_buffer(size.value + 1)
314 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
317 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
315 raise ctypes.WinError()
318 raise ctypes.WinError()
316 return buf.value
319 return buf.value
317
320
318 _signalhandler = []
321 _signalhandler = []
319
322
320 def setsignalhandler():
323 def setsignalhandler():
321 '''Register a termination handler for console events including
324 '''Register a termination handler for console events including
322 CTRL+C. python signal handlers do not work well with socket
325 CTRL+C. python signal handlers do not work well with socket
323 operations.
326 operations.
324 '''
327 '''
325 def handler(event):
328 def handler(event):
326 _kernel32.ExitProcess(1)
329 _kernel32.ExitProcess(1)
327
330
328 if _signalhandler:
331 if _signalhandler:
329 return # already registered
332 return # already registered
330 h = _SIGNAL_HANDLER(handler)
333 h = _SIGNAL_HANDLER(handler)
331 _signalhandler.append(h) # needed to prevent garbage collection
334 _signalhandler.append(h) # needed to prevent garbage collection
332 if not _kernel32.SetConsoleCtrlHandler(h, True):
335 if not _kernel32.SetConsoleCtrlHandler(h, True):
333 raise ctypes.WinError()
336 raise ctypes.WinError()
334
337
335 def hidewindow():
338 def hidewindow():
336
339
337 def callback(hwnd, pid):
340 def callback(hwnd, pid):
338 wpid = _DWORD()
341 wpid = _DWORD()
339 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
342 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
340 if pid == wpid.value:
343 if pid == wpid.value:
341 _user32.ShowWindow(hwnd, _SW_HIDE)
344 _user32.ShowWindow(hwnd, _SW_HIDE)
342 return False # stop enumerating windows
345 return False # stop enumerating windows
343 return True
346 return True
344
347
345 pid = _kernel32.GetCurrentProcessId()
348 pid = _kernel32.GetCurrentProcessId()
346 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
349 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
347
350
348 def termwidth():
351 def termwidth():
349 # cmd.exe does not handle CR like a unix console, the CR is
352 # cmd.exe does not handle CR like a unix console, the CR is
350 # counted in the line length. On 80 columns consoles, if 80
353 # counted in the line length. On 80 columns consoles, if 80
351 # characters are written, the following CR won't apply on the
354 # characters are written, the following CR won't apply on the
352 # current line but on the new one. Keep room for it.
355 # current line but on the new one. Keep room for it.
353 width = 79
356 width = 79
354 # Query stderr to avoid problems with redirections
357 # Query stderr to avoid problems with redirections
355 screenbuf = _kernel32.GetStdHandle(
358 screenbuf = _kernel32.GetStdHandle(
356 _STD_ERROR_HANDLE) # don't close the handle returned
359 _STD_ERROR_HANDLE) # don't close the handle returned
357 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
360 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
358 return width
361 return width
359 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
362 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
360 if not _kernel32.GetConsoleScreenBufferInfo(
363 if not _kernel32.GetConsoleScreenBufferInfo(
361 screenbuf, ctypes.byref(csbi)):
364 screenbuf, ctypes.byref(csbi)):
362 return width
365 return width
363 width = csbi.srWindow.Right - csbi.srWindow.Left
366 width = csbi.srWindow.Right - csbi.srWindow.Left
364 return width
367 return width
365
368
366 def spawndetached(args):
369 def spawndetached(args):
367 # No standard library function really spawns a fully detached
370 # No standard library function really spawns a fully detached
368 # process under win32 because they allocate pipes or other objects
371 # process under win32 because they allocate pipes or other objects
369 # to handle standard streams communications. Passing these objects
372 # to handle standard streams communications. Passing these objects
370 # to the child process requires handle inheritance to be enabled
373 # to the child process requires handle inheritance to be enabled
371 # which makes really detached processes impossible.
374 # which makes really detached processes impossible.
372 si = _STARTUPINFO()
375 si = _STARTUPINFO()
373 si.cb = ctypes.sizeof(_STARTUPINFO)
376 si.cb = ctypes.sizeof(_STARTUPINFO)
374 si.dwFlags = _STARTF_USESHOWWINDOW
377 si.dwFlags = _STARTF_USESHOWWINDOW
375 si.wShowWindow = _SW_HIDE
378 si.wShowWindow = _SW_HIDE
376
379
377 pi = _PROCESS_INFORMATION()
380 pi = _PROCESS_INFORMATION()
378
381
379 env = ''
382 env = ''
380 for k in os.environ:
383 for k in os.environ:
381 env += "%s=%s\0" % (k, os.environ[k])
384 env += "%s=%s\0" % (k, os.environ[k])
382 if not env:
385 if not env:
383 env = '\0'
386 env = '\0'
384 env += '\0'
387 env += '\0'
385
388
386 args = subprocess.list2cmdline(args)
389 args = subprocess.list2cmdline(args)
387 # Not running the command in shell mode makes python26 hang when
390 # Not running the command in shell mode makes python26 hang when
388 # writing to hgweb output socket.
391 # writing to hgweb output socket.
389 comspec = os.environ.get("COMSPEC", "cmd.exe")
392 comspec = os.environ.get("COMSPEC", "cmd.exe")
390 args = comspec + " /c " + args
393 args = comspec + " /c " + args
391
394
392 res = _kernel32.CreateProcessA(
395 res = _kernel32.CreateProcessA(
393 None, args, None, None, False, _DETACHED_PROCESS,
396 None, args, None, None, False, _DETACHED_PROCESS,
394 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
397 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
395 if not res:
398 if not res:
396 raise ctypes.WinError()
399 raise ctypes.WinError()
397
400
398 return pi.dwProcessId
401 return pi.dwProcessId
399
402
400 def unlink(f):
403 def unlink(f):
401 '''try to implement POSIX' unlink semantics on Windows'''
404 '''try to implement POSIX' unlink semantics on Windows'''
402
405
403 # POSIX allows to unlink and rename open files. Windows has serious
406 # POSIX allows to unlink and rename open files. Windows has serious
404 # problems with doing that:
407 # problems with doing that:
405 # - Calling os.unlink (or os.rename) on a file f fails if f or any
408 # - Calling os.unlink (or os.rename) on a file f fails if f or any
406 # hardlinked copy of f has been opened with Python's open(). There is no
409 # hardlinked copy of f has been opened with Python's open(). There is no
407 # way such a file can be deleted or renamed on Windows (other than
410 # way such a file can be deleted or renamed on Windows (other than
408 # scheduling the delete or rename for the next reboot).
411 # scheduling the delete or rename for the next reboot).
409 # - Calling os.unlink on a file that has been opened with Mercurial's
412 # - Calling os.unlink on a file that has been opened with Mercurial's
410 # posixfile (or comparable methods) will delay the actual deletion of
413 # posixfile (or comparable methods) will delay the actual deletion of
411 # the file for as long as the file is held open. The filename is blocked
414 # the file for as long as the file is held open. The filename is blocked
412 # during that time and cannot be used for recreating a new file under
415 # during that time and cannot be used for recreating a new file under
413 # that same name ("zombie file"). Directories containing such zombie files
416 # that same name ("zombie file"). Directories containing such zombie files
414 # cannot be removed or moved.
417 # cannot be removed or moved.
415 # A file that has been opened with posixfile can be renamed, so we rename
418 # A file that has been opened with posixfile can be renamed, so we rename
416 # f to a random temporary name before calling os.unlink on it. This allows
419 # f to a random temporary name before calling os.unlink on it. This allows
417 # callers to recreate f immediately while having other readers do their
420 # callers to recreate f immediately while having other readers do their
418 # implicit zombie filename blocking on a temporary name.
421 # implicit zombie filename blocking on a temporary name.
419
422
420 for tries in xrange(10):
423 for tries in xrange(10):
421 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
424 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
422 try:
425 try:
423 os.rename(f, temp) # raises OSError EEXIST if temp exists
426 os.rename(f, temp) # raises OSError EEXIST if temp exists
424 break
427 break
425 except OSError, e:
428 except OSError, e:
426 if e.errno != errno.EEXIST:
429 if e.errno != errno.EEXIST:
427 raise
430 raise
428 else:
431 else:
429 raise IOError, (errno.EEXIST, "No usable temporary filename found")
432 raise IOError, (errno.EEXIST, "No usable temporary filename found")
430
433
431 try:
434 try:
432 os.unlink(temp)
435 os.unlink(temp)
433 except OSError:
436 except OSError:
434 # The unlink might have failed because the READONLY attribute may heave
437 # The unlink might have failed because the READONLY attribute may heave
435 # been set on the original file. Rename works fine with READONLY set,
438 # been set on the original file. Rename works fine with READONLY set,
436 # but not os.unlink. Reset all attributes and try again.
439 # but not os.unlink. Reset all attributes and try again.
437 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
440 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
438 try:
441 try:
439 os.unlink(temp)
442 os.unlink(temp)
440 except OSError:
443 except OSError:
441 # The unlink might have failed due to some very rude AV-Scanners.
444 # The unlink might have failed due to some very rude AV-Scanners.
442 # Leaking a tempfile is the lesser evil than aborting here and
445 # Leaking a tempfile is the lesser evil than aborting here and
443 # leaving some potentially serious inconsistencies.
446 # leaving some potentially serious inconsistencies.
444 pass
447 pass
445
448
446 def makedir(path, notindexed):
449 def makedir(path, notindexed):
447 os.mkdir(path)
450 os.mkdir(path)
448 if notindexed:
451 if notindexed:
449 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
452 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now