##// END OF EJS Templates
osutil: tab damage, how i hate thee
Bryan O'Sullivan -
r18027:4ca43450 default
parent child Browse files
Show More
@@ -1,643 +1,643 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, *ret = NULL;
291 PyObject *list, *elem, *stat, *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
372
373 PyList_Append(list, elem);
373 PyList_Append(list, elem);
374 Py_DECREF(elem);
374 Py_DECREF(elem);
375 }
375 }
376
376
377 ret = list;
377 ret = list;
378 Py_INCREF(ret);
378 Py_INCREF(ret);
379
379
380 error:
380 error:
381 Py_DECREF(list);
381 Py_DECREF(list);
382 error_list:
382 error_list:
383 closedir(dir);
383 closedir(dir);
384 error_dir:
384 error_dir:
385 #ifdef AT_SYMLINK_NOFOLLOW
385 #ifdef AT_SYMLINK_NOFOLLOW
386 close(dfd);
386 close(dfd);
387 #endif
387 #endif
388 error_value:
388 error_value:
389 return ret;
389 return ret;
390 }
390 }
391
391
392 static PyObject *statfiles(PyObject *self, PyObject *args)
392 static PyObject *statfiles(PyObject *self, PyObject *args)
393 {
393 {
394 PyObject *names, *stats;
394 PyObject *names, *stats;
395 Py_ssize_t i, count;
395 Py_ssize_t i, count;
396
396
397 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
397 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
398 return NULL;
398 return NULL;
399
399
400 count = PySequence_Length(names);
400 count = PySequence_Length(names);
401 if (count == -1) {
401 if (count == -1) {
402 PyErr_SetString(PyExc_TypeError, "not a sequence");
402 PyErr_SetString(PyExc_TypeError, "not a sequence");
403 return NULL;
403 return NULL;
404 }
404 }
405
405
406 stats = PyList_New(count);
406 stats = PyList_New(count);
407 if (stats == NULL)
407 if (stats == NULL)
408 return NULL;
408 return NULL;
409
409
410 for (i = 0; i < count; i++) {
410 for (i = 0; i < count; i++) {
411 PyObject *stat;
411 PyObject *stat;
412 struct stat st;
412 struct stat st;
413 int ret, kind;
413 int ret, kind;
414 char *path;
414 char *path;
415
415
416 path = PyString_AsString(PySequence_GetItem(names, i));
416 path = PyString_AsString(PySequence_GetItem(names, i));
417 if (path == NULL) {
417 if (path == NULL) {
418 PyErr_SetString(PyExc_TypeError, "not a string");
418 PyErr_SetString(PyExc_TypeError, "not a string");
419 goto bail;
419 goto bail;
420 }
420 }
421 ret = lstat(path, &st);
421 ret = lstat(path, &st);
422 kind = st.st_mode & S_IFMT;
422 kind = st.st_mode & S_IFMT;
423 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
423 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
424 stat = makestat(&st);
424 stat = makestat(&st);
425 if (stat == NULL)
425 if (stat == NULL)
426 goto bail;
426 goto bail;
427 PyList_SET_ITEM(stats, i, stat);
427 PyList_SET_ITEM(stats, i, stat);
428 } else {
428 } else {
429 Py_INCREF(Py_None);
429 Py_INCREF(Py_None);
430 PyList_SET_ITEM(stats, i, Py_None);
430 PyList_SET_ITEM(stats, i, Py_None);
431 }
431 }
432 }
432 }
433
433
434 return stats;
434 return stats;
435
435
436 bail:
436 bail:
437 Py_DECREF(stats);
437 Py_DECREF(stats);
438 return NULL;
438 return NULL;
439 }
439 }
440
440
441 #endif /* ndef _WIN32 */
441 #endif /* ndef _WIN32 */
442
442
443 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
443 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
444 {
444 {
445 PyObject *statobj = NULL; /* initialize - optional arg */
445 PyObject *statobj = NULL; /* initialize - optional arg */
446 PyObject *skipobj = NULL; /* initialize - optional arg */
446 PyObject *skipobj = NULL; /* initialize - optional arg */
447 char *path, *skip = NULL;
447 char *path, *skip = NULL;
448 int wantstat, plen;
448 int wantstat, plen;
449
449
450 static char *kwlist[] = {"path", "stat", "skip", NULL};
450 static char *kwlist[] = {"path", "stat", "skip", NULL};
451
451
452 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
452 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
453 kwlist, &path, &plen, &statobj, &skipobj))
453 kwlist, &path, &plen, &statobj, &skipobj))
454 return NULL;
454 return NULL;
455
455
456 wantstat = statobj && PyObject_IsTrue(statobj);
456 wantstat = statobj && PyObject_IsTrue(statobj);
457
457
458 if (skipobj && skipobj != Py_None) {
458 if (skipobj && skipobj != Py_None) {
459 skip = PyBytes_AsString(skipobj);
459 skip = PyBytes_AsString(skipobj);
460 if (!skip)
460 if (!skip)
461 return NULL;
461 return NULL;
462 }
462 }
463
463
464 return _listdir(path, plen, wantstat, skip);
464 return _listdir(path, plen, wantstat, skip);
465 }
465 }
466
466
467 #ifdef _WIN32
467 #ifdef _WIN32
468 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
468 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
469 {
469 {
470 static char *kwlist[] = {"name", "mode", "buffering", NULL};
470 static char *kwlist[] = {"name", "mode", "buffering", NULL};
471 PyObject *file_obj = NULL;
471 PyObject *file_obj = NULL;
472 char *name = NULL;
472 char *name = NULL;
473 char *mode = "rb";
473 char *mode = "rb";
474 DWORD access = 0;
474 DWORD access = 0;
475 DWORD creation;
475 DWORD creation;
476 HANDLE handle;
476 HANDLE handle;
477 int fd, flags = 0;
477 int fd, flags = 0;
478 int bufsize = -1;
478 int bufsize = -1;
479 char m0, m1, m2;
479 char m0, m1, m2;
480 char fpmode[4];
480 char fpmode[4];
481 int fppos = 0;
481 int fppos = 0;
482 int plus;
482 int plus;
483 FILE *fp;
483 FILE *fp;
484
484
485 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
485 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
486 Py_FileSystemDefaultEncoding,
486 Py_FileSystemDefaultEncoding,
487 &name, &mode, &bufsize))
487 &name, &mode, &bufsize))
488 return NULL;
488 return NULL;
489
489
490 m0 = mode[0];
490 m0 = mode[0];
491 m1 = m0 ? mode[1] : '\0';
491 m1 = m0 ? mode[1] : '\0';
492 m2 = m1 ? mode[2] : '\0';
492 m2 = m1 ? mode[2] : '\0';
493 plus = m1 == '+' || m2 == '+';
493 plus = m1 == '+' || m2 == '+';
494
494
495 fpmode[fppos++] = m0;
495 fpmode[fppos++] = m0;
496 if (m1 == 'b' || m2 == 'b') {
496 if (m1 == 'b' || m2 == 'b') {
497 flags = _O_BINARY;
497 flags = _O_BINARY;
498 fpmode[fppos++] = 'b';
498 fpmode[fppos++] = 'b';
499 }
499 }
500 else
500 else
501 flags = _O_TEXT;
501 flags = _O_TEXT;
502 if (m0 == 'r' && !plus) {
502 if (m0 == 'r' && !plus) {
503 flags |= _O_RDONLY;
503 flags |= _O_RDONLY;
504 access = GENERIC_READ;
504 access = GENERIC_READ;
505 } else {
505 } else {
506 /*
506 /*
507 work around http://support.microsoft.com/kb/899149 and
507 work around http://support.microsoft.com/kb/899149 and
508 set _O_RDWR for 'w' and 'a', even if mode has no '+'
508 set _O_RDWR for 'w' and 'a', even if mode has no '+'
509 */
509 */
510 flags |= _O_RDWR;
510 flags |= _O_RDWR;
511 access = GENERIC_READ | GENERIC_WRITE;
511 access = GENERIC_READ | GENERIC_WRITE;
512 fpmode[fppos++] = '+';
512 fpmode[fppos++] = '+';
513 }
513 }
514 fpmode[fppos++] = '\0';
514 fpmode[fppos++] = '\0';
515
515
516 switch (m0) {
516 switch (m0) {
517 case 'r':
517 case 'r':
518 creation = OPEN_EXISTING;
518 creation = OPEN_EXISTING;
519 break;
519 break;
520 case 'w':
520 case 'w':
521 creation = CREATE_ALWAYS;
521 creation = CREATE_ALWAYS;
522 break;
522 break;
523 case 'a':
523 case 'a':
524 creation = OPEN_ALWAYS;
524 creation = OPEN_ALWAYS;
525 flags |= _O_APPEND;
525 flags |= _O_APPEND;
526 break;
526 break;
527 default:
527 default:
528 PyErr_Format(PyExc_ValueError,
528 PyErr_Format(PyExc_ValueError,
529 "mode string must begin with one of 'r', 'w', "
529 "mode string must begin with one of 'r', 'w', "
530 "or 'a', not '%c'", m0);
530 "or 'a', not '%c'", m0);
531 goto bail;
531 goto bail;
532 }
532 }
533
533
534 handle = CreateFile(name, access,
534 handle = CreateFile(name, access,
535 FILE_SHARE_READ | FILE_SHARE_WRITE |
535 FILE_SHARE_READ | FILE_SHARE_WRITE |
536 FILE_SHARE_DELETE,
536 FILE_SHARE_DELETE,
537 NULL,
537 NULL,
538 creation,
538 creation,
539 FILE_ATTRIBUTE_NORMAL,
539 FILE_ATTRIBUTE_NORMAL,
540 0);
540 0);
541
541
542 if (handle == INVALID_HANDLE_VALUE) {
542 if (handle == INVALID_HANDLE_VALUE) {
543 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
543 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
544 goto bail;
544 goto bail;
545 }
545 }
546
546
547 fd = _open_osfhandle((intptr_t)handle, flags);
547 fd = _open_osfhandle((intptr_t)handle, flags);
548
548
549 if (fd == -1) {
549 if (fd == -1) {
550 CloseHandle(handle);
550 CloseHandle(handle);
551 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
551 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
552 goto bail;
552 goto bail;
553 }
553 }
554 #ifndef IS_PY3K
554 #ifndef IS_PY3K
555 fp = _fdopen(fd, fpmode);
555 fp = _fdopen(fd, fpmode);
556 if (fp == NULL) {
556 if (fp == NULL) {
557 _close(fd);
557 _close(fd);
558 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
558 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
559 goto bail;
559 goto bail;
560 }
560 }
561
561
562 file_obj = PyFile_FromFile(fp, name, mode, fclose);
562 file_obj = PyFile_FromFile(fp, name, mode, fclose);
563 if (file_obj == NULL) {
563 if (file_obj == NULL) {
564 fclose(fp);
564 fclose(fp);
565 goto bail;
565 goto bail;
566 }
566 }
567
567
568 PyFile_SetBufSize(file_obj, bufsize);
568 PyFile_SetBufSize(file_obj, bufsize);
569 #else
569 #else
570 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
570 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
571 if (file_obj == NULL)
571 if (file_obj == NULL)
572 goto bail;
572 goto bail;
573 #endif
573 #endif
574 bail:
574 bail:
575 PyMem_Free(name);
575 PyMem_Free(name);
576 return file_obj;
576 return file_obj;
577 }
577 }
578 #endif
578 #endif
579
579
580 #ifdef __APPLE__
580 #ifdef __APPLE__
581 #include <ApplicationServices/ApplicationServices.h>
581 #include <ApplicationServices/ApplicationServices.h>
582
582
583 static PyObject *isgui(PyObject *self)
583 static PyObject *isgui(PyObject *self)
584 {
584 {
585 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
585 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
586
586
587 if (dict != NULL) {
587 if (dict != NULL) {
588 CFRelease(dict);
588 CFRelease(dict);
589 Py_RETURN_TRUE;
589 Py_RETURN_TRUE;
590 } else {
590 } else {
591 Py_RETURN_FALSE;
591 Py_RETURN_FALSE;
592 }
592 }
593 }
593 }
594 #endif
594 #endif
595
595
596 static char osutil_doc[] = "Native operating system services.";
596 static char osutil_doc[] = "Native operating system services.";
597
597
598 static PyMethodDef methods[] = {
598 static PyMethodDef methods[] = {
599 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
599 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
600 "list a directory\n"},
600 "list a directory\n"},
601 #ifdef _WIN32
601 #ifdef _WIN32
602 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
602 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
603 "Open a file with POSIX-like semantics.\n"
603 "Open a file with POSIX-like semantics.\n"
604 "On error, this function may raise either a WindowsError or an IOError."},
604 "On error, this function may raise either a WindowsError or an IOError."},
605 #else
605 #else
606 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
606 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
607 "stat a series of files or symlinks\n"
607 "stat a series of files or symlinks\n"
608 "Returns None for non-existent entries and entries of other types.\n"},
608 "Returns None for non-existent entries and entries of other types.\n"},
609 #endif
609 #endif
610 #ifdef __APPLE__
610 #ifdef __APPLE__
611 {
611 {
612 "isgui", (PyCFunction)isgui, METH_NOARGS,
612 "isgui", (PyCFunction)isgui, METH_NOARGS,
613 "Is a CoreGraphics session available?"
613 "Is a CoreGraphics session available?"
614 },
614 },
615 #endif
615 #endif
616 {NULL, NULL}
616 {NULL, NULL}
617 };
617 };
618
618
619 #ifdef IS_PY3K
619 #ifdef IS_PY3K
620 static struct PyModuleDef osutil_module = {
620 static struct PyModuleDef osutil_module = {
621 PyModuleDef_HEAD_INIT,
621 PyModuleDef_HEAD_INIT,
622 "osutil",
622 "osutil",
623 osutil_doc,
623 osutil_doc,
624 -1,
624 -1,
625 methods
625 methods
626 };
626 };
627
627
628 PyMODINIT_FUNC PyInit_osutil(void)
628 PyMODINIT_FUNC PyInit_osutil(void)
629 {
629 {
630 if (PyType_Ready(&listdir_stat_type) < 0)
630 if (PyType_Ready(&listdir_stat_type) < 0)
631 return NULL;
631 return NULL;
632
632
633 return PyModule_Create(&osutil_module);
633 return PyModule_Create(&osutil_module);
634 }
634 }
635 #else
635 #else
636 PyMODINIT_FUNC initosutil(void)
636 PyMODINIT_FUNC initosutil(void)
637 {
637 {
638 if (PyType_Ready(&listdir_stat_type) == -1)
638 if (PyType_Ready(&listdir_stat_type) == -1)
639 return;
639 return;
640
640
641 Py_InitModule3("osutil", methods, osutil_doc);
641 Py_InitModule3("osutil", methods, osutil_doc);
642 }
642 }
643 #endif
643 #endif
General Comments 0
You need to be logged in to leave comments. Login now