##// END OF EJS Templates
osutil: fix memory leak of PyBytes of path in statfiles...
Augie Fackler -
r23966:2d2c0a8e stable
parent child Browse files
Show More
@@ -1,645 +1,650 b''
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 *makestat(const struct stat *st)
279 static PyObject *makestat(const struct stat *st)
280 {
280 {
281 PyObject *stat;
281 PyObject *stat;
282
282
283 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
283 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
284 if (stat)
284 if (stat)
285 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
285 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
286 return stat;
286 return stat;
287 }
287 }
288
288
289 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
289 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
290 {
290 {
291 PyObject *list, *elem, *stat = NULL, *ret = NULL;
291 PyObject *list, *elem, *stat = NULL, *ret = NULL;
292 char fullpath[PATH_MAX + 10];
292 char fullpath[PATH_MAX + 10];
293 int kind, err;
293 int kind, err;
294 struct stat st;
294 struct stat st;
295 struct dirent *ent;
295 struct dirent *ent;
296 DIR *dir;
296 DIR *dir;
297 #ifdef AT_SYMLINK_NOFOLLOW
297 #ifdef AT_SYMLINK_NOFOLLOW
298 int dfd = -1;
298 int dfd = -1;
299 #endif
299 #endif
300
300
301 if (pathlen >= PATH_MAX) {
301 if (pathlen >= PATH_MAX) {
302 errno = ENAMETOOLONG;
302 errno = ENAMETOOLONG;
303 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
303 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
304 goto error_value;
304 goto error_value;
305 }
305 }
306 strncpy(fullpath, path, PATH_MAX);
306 strncpy(fullpath, path, PATH_MAX);
307 fullpath[pathlen] = '/';
307 fullpath[pathlen] = '/';
308
308
309 #ifdef AT_SYMLINK_NOFOLLOW
309 #ifdef AT_SYMLINK_NOFOLLOW
310 dfd = open(path, O_RDONLY);
310 dfd = open(path, O_RDONLY);
311 if (dfd == -1) {
311 if (dfd == -1) {
312 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
312 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
313 goto error_value;
313 goto error_value;
314 }
314 }
315 dir = fdopendir(dfd);
315 dir = fdopendir(dfd);
316 #else
316 #else
317 dir = opendir(path);
317 dir = opendir(path);
318 #endif
318 #endif
319 if (!dir) {
319 if (!dir) {
320 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
320 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
321 goto error_dir;
321 goto error_dir;
322 }
322 }
323
323
324 list = PyList_New(0);
324 list = PyList_New(0);
325 if (!list)
325 if (!list)
326 goto error_list;
326 goto error_list;
327
327
328 while ((ent = readdir(dir))) {
328 while ((ent = readdir(dir))) {
329 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
329 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
330 continue;
330 continue;
331
331
332 kind = entkind(ent);
332 kind = entkind(ent);
333 if (kind == -1 || keepstat) {
333 if (kind == -1 || keepstat) {
334 #ifdef AT_SYMLINK_NOFOLLOW
334 #ifdef AT_SYMLINK_NOFOLLOW
335 err = fstatat(dfd, ent->d_name, &st,
335 err = fstatat(dfd, ent->d_name, &st,
336 AT_SYMLINK_NOFOLLOW);
336 AT_SYMLINK_NOFOLLOW);
337 #else
337 #else
338 strncpy(fullpath + pathlen + 1, ent->d_name,
338 strncpy(fullpath + pathlen + 1, ent->d_name,
339 PATH_MAX - pathlen);
339 PATH_MAX - pathlen);
340 fullpath[PATH_MAX] = 0;
340 fullpath[PATH_MAX] = 0;
341 err = lstat(fullpath, &st);
341 err = lstat(fullpath, &st);
342 #endif
342 #endif
343 if (err == -1) {
343 if (err == -1) {
344 /* race with file deletion? */
344 /* race with file deletion? */
345 if (errno == ENOENT)
345 if (errno == ENOENT)
346 continue;
346 continue;
347 strncpy(fullpath + pathlen + 1, ent->d_name,
347 strncpy(fullpath + pathlen + 1, ent->d_name,
348 PATH_MAX - pathlen);
348 PATH_MAX - pathlen);
349 fullpath[PATH_MAX] = 0;
349 fullpath[PATH_MAX] = 0;
350 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
350 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
351 fullpath);
351 fullpath);
352 goto error;
352 goto error;
353 }
353 }
354 kind = st.st_mode & S_IFMT;
354 kind = st.st_mode & S_IFMT;
355 }
355 }
356
356
357 /* quit early? */
357 /* quit early? */
358 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
358 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
359 ret = PyList_New(0);
359 ret = PyList_New(0);
360 goto error;
360 goto error;
361 }
361 }
362
362
363 if (keepstat) {
363 if (keepstat) {
364 stat = makestat(&st);
364 stat = makestat(&st);
365 if (!stat)
365 if (!stat)
366 goto error;
366 goto error;
367 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
367 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
368 } else
368 } else
369 elem = Py_BuildValue("si", ent->d_name, kind);
369 elem = Py_BuildValue("si", ent->d_name, kind);
370 if (!elem)
370 if (!elem)
371 goto error;
371 goto error;
372 stat = NULL;
372 stat = NULL;
373
373
374 PyList_Append(list, elem);
374 PyList_Append(list, elem);
375 Py_DECREF(elem);
375 Py_DECREF(elem);
376 }
376 }
377
377
378 ret = list;
378 ret = list;
379 Py_INCREF(ret);
379 Py_INCREF(ret);
380
380
381 error:
381 error:
382 Py_DECREF(list);
382 Py_DECREF(list);
383 Py_XDECREF(stat);
383 Py_XDECREF(stat);
384 error_list:
384 error_list:
385 closedir(dir);
385 closedir(dir);
386 error_dir:
386 error_dir:
387 #ifdef AT_SYMLINK_NOFOLLOW
387 #ifdef AT_SYMLINK_NOFOLLOW
388 close(dfd);
388 close(dfd);
389 #endif
389 #endif
390 error_value:
390 error_value:
391 return ret;
391 return ret;
392 }
392 }
393
393
394 static PyObject *statfiles(PyObject *self, PyObject *args)
394 static PyObject *statfiles(PyObject *self, PyObject *args)
395 {
395 {
396 PyObject *names, *stats;
396 PyObject *names, *stats;
397 Py_ssize_t i, count;
397 Py_ssize_t i, count;
398
398
399 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
399 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
400 return NULL;
400 return NULL;
401
401
402 count = PySequence_Length(names);
402 count = PySequence_Length(names);
403 if (count == -1) {
403 if (count == -1) {
404 PyErr_SetString(PyExc_TypeError, "not a sequence");
404 PyErr_SetString(PyExc_TypeError, "not a sequence");
405 return NULL;
405 return NULL;
406 }
406 }
407
407
408 stats = PyList_New(count);
408 stats = PyList_New(count);
409 if (stats == NULL)
409 if (stats == NULL)
410 return NULL;
410 return NULL;
411
411
412 for (i = 0; i < count; i++) {
412 for (i = 0; i < count; i++) {
413 PyObject *stat;
413 PyObject *stat, *pypath;
414 struct stat st;
414 struct stat st;
415 int ret, kind;
415 int ret, kind;
416 char *path;
416 char *path;
417
417
418 path = PyString_AsString(PySequence_GetItem(names, i));
418 pypath = PySequence_GetItem(names, i);
419 if (!pypath)
420 return NULL;
421 path = PyString_AsString(pypath);
419 if (path == NULL) {
422 if (path == NULL) {
423 Py_DECREF(pypath);
420 PyErr_SetString(PyExc_TypeError, "not a string");
424 PyErr_SetString(PyExc_TypeError, "not a string");
421 goto bail;
425 goto bail;
422 }
426 }
423 ret = lstat(path, &st);
427 ret = lstat(path, &st);
428 Py_DECREF(pypath);
424 kind = st.st_mode & S_IFMT;
429 kind = st.st_mode & S_IFMT;
425 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
430 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
426 stat = makestat(&st);
431 stat = makestat(&st);
427 if (stat == NULL)
432 if (stat == NULL)
428 goto bail;
433 goto bail;
429 PyList_SET_ITEM(stats, i, stat);
434 PyList_SET_ITEM(stats, i, stat);
430 } else {
435 } else {
431 Py_INCREF(Py_None);
436 Py_INCREF(Py_None);
432 PyList_SET_ITEM(stats, i, Py_None);
437 PyList_SET_ITEM(stats, i, Py_None);
433 }
438 }
434 }
439 }
435
440
436 return stats;
441 return stats;
437
442
438 bail:
443 bail:
439 Py_DECREF(stats);
444 Py_DECREF(stats);
440 return NULL;
445 return NULL;
441 }
446 }
442
447
443 #endif /* ndef _WIN32 */
448 #endif /* ndef _WIN32 */
444
449
445 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
450 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
446 {
451 {
447 PyObject *statobj = NULL; /* initialize - optional arg */
452 PyObject *statobj = NULL; /* initialize - optional arg */
448 PyObject *skipobj = NULL; /* initialize - optional arg */
453 PyObject *skipobj = NULL; /* initialize - optional arg */
449 char *path, *skip = NULL;
454 char *path, *skip = NULL;
450 int wantstat, plen;
455 int wantstat, plen;
451
456
452 static char *kwlist[] = {"path", "stat", "skip", NULL};
457 static char *kwlist[] = {"path", "stat", "skip", NULL};
453
458
454 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
459 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
455 kwlist, &path, &plen, &statobj, &skipobj))
460 kwlist, &path, &plen, &statobj, &skipobj))
456 return NULL;
461 return NULL;
457
462
458 wantstat = statobj && PyObject_IsTrue(statobj);
463 wantstat = statobj && PyObject_IsTrue(statobj);
459
464
460 if (skipobj && skipobj != Py_None) {
465 if (skipobj && skipobj != Py_None) {
461 skip = PyBytes_AsString(skipobj);
466 skip = PyBytes_AsString(skipobj);
462 if (!skip)
467 if (!skip)
463 return NULL;
468 return NULL;
464 }
469 }
465
470
466 return _listdir(path, plen, wantstat, skip);
471 return _listdir(path, plen, wantstat, skip);
467 }
472 }
468
473
469 #ifdef _WIN32
474 #ifdef _WIN32
470 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
475 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
471 {
476 {
472 static char *kwlist[] = {"name", "mode", "buffering", NULL};
477 static char *kwlist[] = {"name", "mode", "buffering", NULL};
473 PyObject *file_obj = NULL;
478 PyObject *file_obj = NULL;
474 char *name = NULL;
479 char *name = NULL;
475 char *mode = "rb";
480 char *mode = "rb";
476 DWORD access = 0;
481 DWORD access = 0;
477 DWORD creation;
482 DWORD creation;
478 HANDLE handle;
483 HANDLE handle;
479 int fd, flags = 0;
484 int fd, flags = 0;
480 int bufsize = -1;
485 int bufsize = -1;
481 char m0, m1, m2;
486 char m0, m1, m2;
482 char fpmode[4];
487 char fpmode[4];
483 int fppos = 0;
488 int fppos = 0;
484 int plus;
489 int plus;
485 FILE *fp;
490 FILE *fp;
486
491
487 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
492 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
488 Py_FileSystemDefaultEncoding,
493 Py_FileSystemDefaultEncoding,
489 &name, &mode, &bufsize))
494 &name, &mode, &bufsize))
490 return NULL;
495 return NULL;
491
496
492 m0 = mode[0];
497 m0 = mode[0];
493 m1 = m0 ? mode[1] : '\0';
498 m1 = m0 ? mode[1] : '\0';
494 m2 = m1 ? mode[2] : '\0';
499 m2 = m1 ? mode[2] : '\0';
495 plus = m1 == '+' || m2 == '+';
500 plus = m1 == '+' || m2 == '+';
496
501
497 fpmode[fppos++] = m0;
502 fpmode[fppos++] = m0;
498 if (m1 == 'b' || m2 == 'b') {
503 if (m1 == 'b' || m2 == 'b') {
499 flags = _O_BINARY;
504 flags = _O_BINARY;
500 fpmode[fppos++] = 'b';
505 fpmode[fppos++] = 'b';
501 }
506 }
502 else
507 else
503 flags = _O_TEXT;
508 flags = _O_TEXT;
504 if (m0 == 'r' && !plus) {
509 if (m0 == 'r' && !plus) {
505 flags |= _O_RDONLY;
510 flags |= _O_RDONLY;
506 access = GENERIC_READ;
511 access = GENERIC_READ;
507 } else {
512 } else {
508 /*
513 /*
509 work around http://support.microsoft.com/kb/899149 and
514 work around http://support.microsoft.com/kb/899149 and
510 set _O_RDWR for 'w' and 'a', even if mode has no '+'
515 set _O_RDWR for 'w' and 'a', even if mode has no '+'
511 */
516 */
512 flags |= _O_RDWR;
517 flags |= _O_RDWR;
513 access = GENERIC_READ | GENERIC_WRITE;
518 access = GENERIC_READ | GENERIC_WRITE;
514 fpmode[fppos++] = '+';
519 fpmode[fppos++] = '+';
515 }
520 }
516 fpmode[fppos++] = '\0';
521 fpmode[fppos++] = '\0';
517
522
518 switch (m0) {
523 switch (m0) {
519 case 'r':
524 case 'r':
520 creation = OPEN_EXISTING;
525 creation = OPEN_EXISTING;
521 break;
526 break;
522 case 'w':
527 case 'w':
523 creation = CREATE_ALWAYS;
528 creation = CREATE_ALWAYS;
524 break;
529 break;
525 case 'a':
530 case 'a':
526 creation = OPEN_ALWAYS;
531 creation = OPEN_ALWAYS;
527 flags |= _O_APPEND;
532 flags |= _O_APPEND;
528 break;
533 break;
529 default:
534 default:
530 PyErr_Format(PyExc_ValueError,
535 PyErr_Format(PyExc_ValueError,
531 "mode string must begin with one of 'r', 'w', "
536 "mode string must begin with one of 'r', 'w', "
532 "or 'a', not '%c'", m0);
537 "or 'a', not '%c'", m0);
533 goto bail;
538 goto bail;
534 }
539 }
535
540
536 handle = CreateFile(name, access,
541 handle = CreateFile(name, access,
537 FILE_SHARE_READ | FILE_SHARE_WRITE |
542 FILE_SHARE_READ | FILE_SHARE_WRITE |
538 FILE_SHARE_DELETE,
543 FILE_SHARE_DELETE,
539 NULL,
544 NULL,
540 creation,
545 creation,
541 FILE_ATTRIBUTE_NORMAL,
546 FILE_ATTRIBUTE_NORMAL,
542 0);
547 0);
543
548
544 if (handle == INVALID_HANDLE_VALUE) {
549 if (handle == INVALID_HANDLE_VALUE) {
545 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
550 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
546 goto bail;
551 goto bail;
547 }
552 }
548
553
549 fd = _open_osfhandle((intptr_t)handle, flags);
554 fd = _open_osfhandle((intptr_t)handle, flags);
550
555
551 if (fd == -1) {
556 if (fd == -1) {
552 CloseHandle(handle);
557 CloseHandle(handle);
553 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
558 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
554 goto bail;
559 goto bail;
555 }
560 }
556 #ifndef IS_PY3K
561 #ifndef IS_PY3K
557 fp = _fdopen(fd, fpmode);
562 fp = _fdopen(fd, fpmode);
558 if (fp == NULL) {
563 if (fp == NULL) {
559 _close(fd);
564 _close(fd);
560 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
565 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
561 goto bail;
566 goto bail;
562 }
567 }
563
568
564 file_obj = PyFile_FromFile(fp, name, mode, fclose);
569 file_obj = PyFile_FromFile(fp, name, mode, fclose);
565 if (file_obj == NULL) {
570 if (file_obj == NULL) {
566 fclose(fp);
571 fclose(fp);
567 goto bail;
572 goto bail;
568 }
573 }
569
574
570 PyFile_SetBufSize(file_obj, bufsize);
575 PyFile_SetBufSize(file_obj, bufsize);
571 #else
576 #else
572 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
577 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
573 if (file_obj == NULL)
578 if (file_obj == NULL)
574 goto bail;
579 goto bail;
575 #endif
580 #endif
576 bail:
581 bail:
577 PyMem_Free(name);
582 PyMem_Free(name);
578 return file_obj;
583 return file_obj;
579 }
584 }
580 #endif
585 #endif
581
586
582 #ifdef __APPLE__
587 #ifdef __APPLE__
583 #include <ApplicationServices/ApplicationServices.h>
588 #include <ApplicationServices/ApplicationServices.h>
584
589
585 static PyObject *isgui(PyObject *self)
590 static PyObject *isgui(PyObject *self)
586 {
591 {
587 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
592 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
588
593
589 if (dict != NULL) {
594 if (dict != NULL) {
590 CFRelease(dict);
595 CFRelease(dict);
591 Py_RETURN_TRUE;
596 Py_RETURN_TRUE;
592 } else {
597 } else {
593 Py_RETURN_FALSE;
598 Py_RETURN_FALSE;
594 }
599 }
595 }
600 }
596 #endif
601 #endif
597
602
598 static char osutil_doc[] = "Native operating system services.";
603 static char osutil_doc[] = "Native operating system services.";
599
604
600 static PyMethodDef methods[] = {
605 static PyMethodDef methods[] = {
601 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
606 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
602 "list a directory\n"},
607 "list a directory\n"},
603 #ifdef _WIN32
608 #ifdef _WIN32
604 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
609 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
605 "Open a file with POSIX-like semantics.\n"
610 "Open a file with POSIX-like semantics.\n"
606 "On error, this function may raise either a WindowsError or an IOError."},
611 "On error, this function may raise either a WindowsError or an IOError."},
607 #else
612 #else
608 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
613 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
609 "stat a series of files or symlinks\n"
614 "stat a series of files or symlinks\n"
610 "Returns None for non-existent entries and entries of other types.\n"},
615 "Returns None for non-existent entries and entries of other types.\n"},
611 #endif
616 #endif
612 #ifdef __APPLE__
617 #ifdef __APPLE__
613 {
618 {
614 "isgui", (PyCFunction)isgui, METH_NOARGS,
619 "isgui", (PyCFunction)isgui, METH_NOARGS,
615 "Is a CoreGraphics session available?"
620 "Is a CoreGraphics session available?"
616 },
621 },
617 #endif
622 #endif
618 {NULL, NULL}
623 {NULL, NULL}
619 };
624 };
620
625
621 #ifdef IS_PY3K
626 #ifdef IS_PY3K
622 static struct PyModuleDef osutil_module = {
627 static struct PyModuleDef osutil_module = {
623 PyModuleDef_HEAD_INIT,
628 PyModuleDef_HEAD_INIT,
624 "osutil",
629 "osutil",
625 osutil_doc,
630 osutil_doc,
626 -1,
631 -1,
627 methods
632 methods
628 };
633 };
629
634
630 PyMODINIT_FUNC PyInit_osutil(void)
635 PyMODINIT_FUNC PyInit_osutil(void)
631 {
636 {
632 if (PyType_Ready(&listdir_stat_type) < 0)
637 if (PyType_Ready(&listdir_stat_type) < 0)
633 return NULL;
638 return NULL;
634
639
635 return PyModule_Create(&osutil_module);
640 return PyModule_Create(&osutil_module);
636 }
641 }
637 #else
642 #else
638 PyMODINIT_FUNC initosutil(void)
643 PyMODINIT_FUNC initosutil(void)
639 {
644 {
640 if (PyType_Ready(&listdir_stat_type) == -1)
645 if (PyType_Ready(&listdir_stat_type) == -1)
641 return;
646 return;
642
647
643 Py_InitModule3("osutil", methods, osutil_doc);
648 Py_InitModule3("osutil", methods, osutil_doc);
644 }
649 }
645 #endif
650 #endif
General Comments 0
You need to be logged in to leave comments. Login now