##// END OF EJS Templates
Improve error handling in osutil.c...
Petr Kodl -
r7059:6a76cf98 default
parent child Browse files
Show More
@@ -1,401 +1,398
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 #ifdef _WIN32
12 #ifdef _WIN32
13 #include <windows.h>
13 #include <windows.h>
14 #else
14 #else
15 #include <dirent.h>
15 #include <dirent.h>
16 #include <fcntl.h>
16 #include <fcntl.h>
17 #include <string.h>
17 #include <string.h>
18 #include <sys/stat.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
19 #include <sys/types.h>
20 #include <unistd.h>
20 #include <unistd.h>
21 #endif
21 #endif
22
22
23 #ifdef _WIN32
23 #ifdef _WIN32
24 /*
24 /*
25 stat struct compatible with hg expectations
25 stat struct compatible with hg expectations
26 Mercurial only uses st_mode, st_size and st_mtime
26 Mercurial only uses st_mode, st_size and st_mtime
27 the rest is kept to minimize changes between implementations
27 the rest is kept to minimize changes between implementations
28 */
28 */
29 struct hg_stat {
29 struct hg_stat {
30 int st_dev;
30 int st_dev;
31 int st_mode;
31 int st_mode;
32 int st_nlink;
32 int st_nlink;
33 __int64 st_size;
33 __int64 st_size;
34 int st_mtime;
34 int st_mtime;
35 int st_ctime;
35 int st_ctime;
36 };
36 };
37 struct listdir_stat {
37 struct listdir_stat {
38 PyObject_HEAD
38 PyObject_HEAD
39 struct hg_stat st;
39 struct hg_stat st;
40 };
40 };
41 #else
41 #else
42 struct listdir_stat {
42 struct listdir_stat {
43 PyObject_HEAD
43 PyObject_HEAD
44 struct stat st;
44 struct stat st;
45 };
45 };
46 #endif
46 #endif
47
47
48 #define listdir_slot(name) \
48 #define listdir_slot(name) \
49 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
49 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
50 { \
50 { \
51 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
51 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
52 }
52 }
53
53
54 listdir_slot(st_dev)
54 listdir_slot(st_dev)
55 listdir_slot(st_mode)
55 listdir_slot(st_mode)
56 listdir_slot(st_nlink)
56 listdir_slot(st_nlink)
57 #ifdef _WIN32
57 #ifdef _WIN32
58 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
58 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
59 {
59 {
60 return PyLong_FromLongLong(
60 return PyLong_FromLongLong(
61 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
61 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
62 }
62 }
63 #else
63 #else
64 listdir_slot(st_size)
64 listdir_slot(st_size)
65 #endif
65 #endif
66 listdir_slot(st_mtime)
66 listdir_slot(st_mtime)
67 listdir_slot(st_ctime)
67 listdir_slot(st_ctime)
68
68
69 static struct PyGetSetDef listdir_stat_getsets[] = {
69 static struct PyGetSetDef listdir_stat_getsets[] = {
70 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
70 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
71 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
71 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
72 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
72 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
73 {"st_size", listdir_stat_st_size, 0, 0, 0},
73 {"st_size", listdir_stat_st_size, 0, 0, 0},
74 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
74 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
75 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
75 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
76 {0, 0, 0, 0, 0}
76 {0, 0, 0, 0, 0}
77 };
77 };
78
78
79 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
79 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
80 {
80 {
81 return t->tp_alloc(t, 0);
81 return t->tp_alloc(t, 0);
82 }
82 }
83
83
84 static void listdir_stat_dealloc(PyObject *o)
84 static void listdir_stat_dealloc(PyObject *o)
85 {
85 {
86 o->ob_type->tp_free(o);
86 o->ob_type->tp_free(o);
87 }
87 }
88
88
89 static PyTypeObject listdir_stat_type = {
89 static PyTypeObject listdir_stat_type = {
90 PyObject_HEAD_INIT(NULL)
90 PyObject_HEAD_INIT(NULL)
91 0, /*ob_size*/
91 0, /*ob_size*/
92 "osutil.stat", /*tp_name*/
92 "osutil.stat", /*tp_name*/
93 sizeof(struct listdir_stat), /*tp_basicsize*/
93 sizeof(struct listdir_stat), /*tp_basicsize*/
94 0, /*tp_itemsize*/
94 0, /*tp_itemsize*/
95 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
95 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
96 0, /*tp_print*/
96 0, /*tp_print*/
97 0, /*tp_getattr*/
97 0, /*tp_getattr*/
98 0, /*tp_setattr*/
98 0, /*tp_setattr*/
99 0, /*tp_compare*/
99 0, /*tp_compare*/
100 0, /*tp_repr*/
100 0, /*tp_repr*/
101 0, /*tp_as_number*/
101 0, /*tp_as_number*/
102 0, /*tp_as_sequence*/
102 0, /*tp_as_sequence*/
103 0, /*tp_as_mapping*/
103 0, /*tp_as_mapping*/
104 0, /*tp_hash */
104 0, /*tp_hash */
105 0, /*tp_call*/
105 0, /*tp_call*/
106 0, /*tp_str*/
106 0, /*tp_str*/
107 0, /*tp_getattro*/
107 0, /*tp_getattro*/
108 0, /*tp_setattro*/
108 0, /*tp_setattro*/
109 0, /*tp_as_buffer*/
109 0, /*tp_as_buffer*/
110 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
110 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
111 "stat objects", /* tp_doc */
111 "stat objects", /* tp_doc */
112 0, /* tp_traverse */
112 0, /* tp_traverse */
113 0, /* tp_clear */
113 0, /* tp_clear */
114 0, /* tp_richcompare */
114 0, /* tp_richcompare */
115 0, /* tp_weaklistoffset */
115 0, /* tp_weaklistoffset */
116 0, /* tp_iter */
116 0, /* tp_iter */
117 0, /* tp_iternext */
117 0, /* tp_iternext */
118 0, /* tp_methods */
118 0, /* tp_methods */
119 0, /* tp_members */
119 0, /* tp_members */
120 listdir_stat_getsets, /* tp_getset */
120 listdir_stat_getsets, /* tp_getset */
121 0, /* tp_base */
121 0, /* tp_base */
122 0, /* tp_dict */
122 0, /* tp_dict */
123 0, /* tp_descr_get */
123 0, /* tp_descr_get */
124 0, /* tp_descr_set */
124 0, /* tp_descr_set */
125 0, /* tp_dictoffset */
125 0, /* tp_dictoffset */
126 0, /* tp_init */
126 0, /* tp_init */
127 0, /* tp_alloc */
127 0, /* tp_alloc */
128 listdir_stat_new, /* tp_new */
128 listdir_stat_new, /* tp_new */
129 };
129 };
130
130
131 #ifdef _WIN32
131 #ifdef _WIN32
132
132
133 static int to_python_time(const FILETIME *tm)
133 static int to_python_time(const FILETIME *tm)
134 {
134 {
135 /* number of seconds between epoch and January 1 1601 */
135 /* number of seconds between epoch and January 1 1601 */
136 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
136 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
137 /* conversion factor from 100ns to 1s */
137 /* conversion factor from 100ns to 1s */
138 const __int64 a1 = 10000000;
138 const __int64 a1 = 10000000;
139 /* explicit (int) cast to suspend compiler warnings */
139 /* explicit (int) cast to suspend compiler warnings */
140 return (int)((((__int64)tm->dwHighDateTime << 32)
140 return (int)((((__int64)tm->dwHighDateTime << 32)
141 + tm->dwLowDateTime) / a1 - a0);
141 + tm->dwLowDateTime) / a1 - a0);
142 }
142 }
143
143
144 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
144 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
145 {
145 {
146 PyObject *py_st;
146 PyObject *py_st;
147 struct hg_stat *stp;
147 struct hg_stat *stp;
148
148
149 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
149 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
150 ? _S_IFDIR : _S_IFREG;
150 ? _S_IFDIR : _S_IFREG;
151
151
152 if (!wantstat)
152 if (!wantstat)
153 return Py_BuildValue("si", fd->cFileName, kind);
153 return Py_BuildValue("si", fd->cFileName, kind);
154
154
155 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
155 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
156 if (!py_st)
156 if (!py_st)
157 return NULL;
157 return NULL;
158
158
159 stp = &((struct listdir_stat *)py_st)->st;
159 stp = &((struct listdir_stat *)py_st)->st;
160 /*
160 /*
161 use kind as st_mode
161 use kind as st_mode
162 rwx bits on Win32 are meaningless
162 rwx bits on Win32 are meaningless
163 and Hg does not use them anyway
163 and Hg does not use them anyway
164 */
164 */
165 stp->st_mode = kind;
165 stp->st_mode = kind;
166 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
166 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
167 stp->st_ctime = to_python_time(&fd->ftCreationTime);
167 stp->st_ctime = to_python_time(&fd->ftCreationTime);
168 if (kind == _S_IFREG)
168 if (kind == _S_IFREG)
169 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
169 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
170 + fd->nFileSizeLow;
170 + fd->nFileSizeLow;
171 return Py_BuildValue("siN", fd->cFileName,
171 return Py_BuildValue("siN", fd->cFileName,
172 kind, py_st);
172 kind, py_st);
173 }
173 }
174
174
175 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
175 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
176 {
176 {
177 PyObject *rval = NULL; /* initialize - return value */
177 PyObject *rval = NULL; /* initialize - return value */
178 PyObject *statobj = NULL; /* initialize - optional arg */
178 PyObject *statobj = NULL; /* initialize - optional arg */
179 PyObject *list;
179 PyObject *list;
180 HANDLE fh;
180 HANDLE fh;
181 WIN32_FIND_DATAA fd;
181 WIN32_FIND_DATAA fd;
182 char *path, *pattern, *skip = NULL;
182 char *path, *pattern, *skip = NULL;
183 int plen, wantstat;
183 int plen, wantstat;
184
184
185 static char *kwlist[] = {"path", "stat", "skip", NULL};
185 static char *kwlist[] = {"path", "stat", "skip", NULL};
186
186
187 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|Os:listdir",
187 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|Os:listdir",
188 kwlist, &path, &plen, &statobj, &skip))
188 kwlist, &path, &plen, &statobj, &skip))
189 goto error_parse;
189 goto error_parse;
190
190
191 wantstat = statobj && PyObject_IsTrue(statobj);
191 wantstat = statobj && PyObject_IsTrue(statobj);
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_parse;
197 goto error_parse;
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_SetExcFromWindowsErrWithFilename(PyExc_OSError,
210 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
211 GetLastError(),
212 path);
213 goto error_file;
211 goto error_file;
214 }
212 }
215
213
216 list = PyList_New(0);
214 list = PyList_New(0);
217 if (!list)
215 if (!list)
218 goto error_list;
216 goto error_list;
219
217
220 do {
218 do {
221 PyObject *item;
219 PyObject *item;
222
220
223 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
221 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
224 if (!strcmp(fd.cFileName, ".")
222 if (!strcmp(fd.cFileName, ".")
225 || !strcmp(fd.cFileName, ".."))
223 || !strcmp(fd.cFileName, ".."))
226 continue;
224 continue;
227
225
228 if (skip && !strcmp(fd.cFileName, skip)) {
226 if (skip && !strcmp(fd.cFileName, skip)) {
229 rval = PyList_New(0);
227 rval = PyList_New(0);
230 goto error;
228 goto error;
231 }
229 }
232 }
230 }
233
231
234 item = make_item(&fd, wantstat);
232 item = make_item(&fd, wantstat);
235 if (!item)
233 if (!item)
236 goto error;
234 goto error;
237
235
238 if (PyList_Append(list, item)) {
236 if (PyList_Append(list, item)) {
239 Py_XDECREF(item);
237 Py_XDECREF(item);
240 goto error;
238 goto error;
241 }
239 }
242
240
243 Py_XDECREF(item);
241 Py_XDECREF(item);
244 } while (FindNextFileA(fh, &fd));
242 } while (FindNextFileA(fh, &fd));
245
243
246 if (GetLastError() != ERROR_NO_MORE_FILES) {
244 if (GetLastError() != ERROR_NO_MORE_FILES) {
247 PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError,
245 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
248 GetLastError(),
249 path);
250 goto error;
246 goto error;
251 }
247 }
252
248
253 rval = list;
249 rval = list;
254 Py_XINCREF(rval);
250 Py_XINCREF(rval);
255 error:
251 error:
256 Py_XDECREF(list);
252 Py_XDECREF(list);
257 error_list:
253 error_list:
258 FindClose(fh);
254 FindClose(fh);
259 error_file:
255 error_file:
260 free(pattern);
256 free(pattern);
261 error_parse:
257 error_parse:
262 return rval;
258 return rval;
263 }
259 }
264
260
265 #else
261 #else
266
262
267 int entkind(struct dirent *ent)
263 int entkind(struct dirent *ent)
268 {
264 {
269 #ifdef DT_REG
265 #ifdef DT_REG
270 switch (ent->d_type) {
266 switch (ent->d_type) {
271 case DT_REG: return S_IFREG;
267 case DT_REG: return S_IFREG;
272 case DT_DIR: return S_IFDIR;
268 case DT_DIR: return S_IFDIR;
273 case DT_LNK: return S_IFLNK;
269 case DT_LNK: return S_IFLNK;
274 case DT_BLK: return S_IFBLK;
270 case DT_BLK: return S_IFBLK;
275 case DT_CHR: return S_IFCHR;
271 case DT_CHR: return S_IFCHR;
276 case DT_FIFO: return S_IFIFO;
272 case DT_FIFO: return S_IFIFO;
277 case DT_SOCK: return S_IFSOCK;
273 case DT_SOCK: return S_IFSOCK;
278 }
274 }
279 #endif
275 #endif
280 return -1;
276 return -1;
281 }
277 }
282
278
283 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
279 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
284 {
280 {
285 static char *kwlist[] = { "path", "stat", "skip", NULL };
281 static char *kwlist[] = { "path", "stat", "skip", NULL };
286 PyObject *statflag = NULL, *list, *elem, *stat, *ret = NULL;
282 PyObject *statflag = NULL, *list, *elem, *stat, *ret = NULL;
287 char fullpath[PATH_MAX + 10], *path, *skip = NULL;
283 char fullpath[PATH_MAX + 10], *path, *skip = NULL;
288 int pathlen, keepstat, kind, dfd = -1, err;
284 int pathlen, keepstat, kind, dfd = -1, err;
289 struct stat st;
285 struct stat st;
290 struct dirent *ent;
286 struct dirent *ent;
291 DIR *dir;
287 DIR *dir;
292
288
293 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|Os:listdir", kwlist,
289 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|Os:listdir", kwlist,
294 &path, &pathlen, &statflag, &skip))
290 &path, &pathlen, &statflag, &skip))
295 goto error_parse;
291 goto error_parse;
296
292
297 if (pathlen >= PATH_MAX)
293 if (pathlen >= PATH_MAX) {
294 PyErr_SetString(PyExc_ValueError, "path too long");
298 goto error_parse;
295 goto error_parse;
299
296 }
300 strncpy(fullpath, path, PATH_MAX);
297 strncpy(fullpath, path, PATH_MAX);
301 fullpath[pathlen] = '/';
298 fullpath[pathlen] = '/';
302 keepstat = statflag && PyObject_IsTrue(statflag);
299 keepstat = statflag && PyObject_IsTrue(statflag);
303
300
304 #ifdef AT_SYMLINK_NOFOLLOW
301 #ifdef AT_SYMLINK_NOFOLLOW
305 dfd = open(path, O_RDONLY);
302 dfd = open(path, O_RDONLY);
306 if (dfd == -1) {
303 if (dfd == -1) {
307 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
304 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
308 goto error_parse;
305 goto error_parse;
309 }
306 }
310 dir = fdopendir(dfd);
307 dir = fdopendir(dfd);
311 #else
308 #else
312 dir = opendir(path);
309 dir = opendir(path);
313 #endif
310 #endif
314 if (!dir) {
311 if (!dir) {
315 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
312 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
316 goto error_dir;
313 goto error_dir;
317 }
314 }
318
315
319 list = PyList_New(0);
316 list = PyList_New(0);
320 if (!list)
317 if (!list)
321 goto error_list;
318 goto error_list;
322
319
323 while ((ent = readdir(dir))) {
320 while ((ent = readdir(dir))) {
324 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
321 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
325 continue;
322 continue;
326
323
327 kind = entkind(ent);
324 kind = entkind(ent);
328 if (kind == -1 || keepstat) {
325 if (kind == -1 || keepstat) {
329 #ifdef AT_SYMLINK_NOFOLLOW
326 #ifdef AT_SYMLINK_NOFOLLOW
330 err = fstatat(dfd, ent->d_name, &st,
327 err = fstatat(dfd, ent->d_name, &st,
331 AT_SYMLINK_NOFOLLOW);
328 AT_SYMLINK_NOFOLLOW);
332 #else
329 #else
333 strncpy(fullpath + pathlen + 1, ent->d_name,
330 strncpy(fullpath + pathlen + 1, ent->d_name,
334 PATH_MAX - pathlen);
331 PATH_MAX - pathlen);
335 fullpath[PATH_MAX] = 0;
332 fullpath[PATH_MAX] = 0;
336 err = lstat(fullpath, &st);
333 err = lstat(fullpath, &st);
337 #endif
334 #endif
338 if (err == -1) {
335 if (err == -1) {
339 strncpy(fullpath + pathlen + 1, ent->d_name,
336 strncpy(fullpath + pathlen + 1, ent->d_name,
340 PATH_MAX - pathlen);
337 PATH_MAX - pathlen);
341 fullpath[PATH_MAX] = 0;
338 fullpath[PATH_MAX] = 0;
342 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
339 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
343 fullpath);
340 fullpath);
344 goto error;
341 goto error;
345 }
342 }
346 kind = st.st_mode & S_IFMT;
343 kind = st.st_mode & S_IFMT;
347 }
344 }
348
345
349 /* quit early? */
346 /* quit early? */
350 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
347 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
351 ret = PyList_New(0);
348 ret = PyList_New(0);
352 goto error;
349 goto error;
353 }
350 }
354
351
355 if (keepstat) {
352 if (keepstat) {
356 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
353 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
357 if (!stat)
354 if (!stat)
358 goto error;
355 goto error;
359 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
356 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
360 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
357 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
361 } else
358 } else
362 elem = Py_BuildValue("si", ent->d_name, kind);
359 elem = Py_BuildValue("si", ent->d_name, kind);
363 if (!elem)
360 if (!elem)
364 goto error;
361 goto error;
365
362
366 PyList_Append(list, elem);
363 PyList_Append(list, elem);
367 Py_DECREF(elem);
364 Py_DECREF(elem);
368 }
365 }
369
366
370 ret = list;
367 ret = list;
371 Py_INCREF(ret);
368 Py_INCREF(ret);
372
369
373 error:
370 error:
374 Py_DECREF(list);
371 Py_DECREF(list);
375 error_list:
372 error_list:
376 closedir(dir);
373 closedir(dir);
377 error_dir:
374 error_dir:
378 #ifdef AT_SYMLINK_NOFOLLOW
375 #ifdef AT_SYMLINK_NOFOLLOW
379 close(dfd);
376 close(dfd);
380 #endif
377 #endif
381 error_parse:
378 error_parse:
382 return ret;
379 return ret;
383 }
380 }
384
381
385 #endif /* ndef _WIN32 */
382 #endif /* ndef _WIN32 */
386
383
387 static char osutil_doc[] = "Native operating system services.";
384 static char osutil_doc[] = "Native operating system services.";
388
385
389 static PyMethodDef methods[] = {
386 static PyMethodDef methods[] = {
390 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
387 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
391 "list a directory\n"},
388 "list a directory\n"},
392 {NULL, NULL}
389 {NULL, NULL}
393 };
390 };
394
391
395 PyMODINIT_FUNC initosutil(void)
392 PyMODINIT_FUNC initosutil(void)
396 {
393 {
397 if (PyType_Ready(&listdir_stat_type) == -1)
394 if (PyType_Ready(&listdir_stat_type) == -1)
398 return;
395 return;
399
396
400 Py_InitModule3("osutil", methods, osutil_doc);
397 Py_InitModule3("osutil", methods, osutil_doc);
401 }
398 }
General Comments 0
You need to be logged in to leave comments. Login now