94 0, /* tp_init */ |
94 0, /* tp_init */ |
95 0, /* tp_alloc */ |
95 0, /* tp_alloc */ |
96 listdir_stat_new, /* tp_new */ |
96 listdir_stat_new, /* tp_new */ |
97 }; |
97 }; |
98 |
98 |
99 static PyObject *listfiles(PyObject *list, DIR *dir, |
99 #ifdef AT_SYMLINK_NOFOLLOW |
100 int keep_stat, int *need_stat) |
100 #define USEFDOPEN 1 |
101 { |
101 #else |
|
102 #define USEFDOPEN 0 |
|
103 #endif |
|
104 |
|
105 int entkind(struct dirent *ent) |
|
106 { |
|
107 #ifdef DT_REG |
|
108 switch (ent->d_type) { |
|
109 case DT_REG: return S_IFREG; |
|
110 case DT_DIR: return S_IFDIR; |
|
111 case DT_LNK: return S_IFLNK; |
|
112 case DT_BLK: return S_IFBLK; |
|
113 case DT_CHR: return S_IFCHR; |
|
114 case DT_FIFO: return S_IFIFO; |
|
115 case DT_SOCK: return S_IFSOCK; |
|
116 } |
|
117 #endif |
|
118 } |
|
119 |
|
120 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs) |
|
121 { |
|
122 static char *kwlist[] = { "path", "stat", NULL }; |
|
123 PyObject *statflag = NULL, *list, *elem, *stat, *ret = NULL; |
|
124 char fullpath[PATH_MAX + 10], *path; |
|
125 int pathlen, keepstat, kind, dfd, err; |
|
126 struct stat st; |
102 struct dirent *ent; |
127 struct dirent *ent; |
103 PyObject *name, *py_kind, *val; |
128 DIR *dir; |
104 |
129 |
105 #ifdef DT_REG |
130 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist, |
106 *need_stat = 0; |
131 &path, &pathlen, &statflag)) |
107 #else |
132 goto error_parse; |
108 *need_stat = 1; |
133 |
109 #endif |
134 strncpy(fullpath, path, PATH_MAX); |
110 |
135 fullpath[pathlen] = '/'; |
111 for (ent = readdir(dir); ent; ent = readdir(dir)) { |
136 keepstat = statflag && PyObject_IsTrue(statflag); |
112 int kind = -1; |
137 |
113 |
138 if (USEFDOPEN) { |
|
139 dfd = open(path, O_RDONLY); |
|
140 if (dfd == -1) { |
|
141 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); |
|
142 goto error_parse; |
|
143 } |
|
144 dir = fdopendir(dfd); |
|
145 } else |
|
146 dir = opendir(path); |
|
147 if (!dir) { |
|
148 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); |
|
149 goto error_dir; |
|
150 } |
|
151 |
|
152 list = PyList_New(0); |
|
153 if (!list) |
|
154 goto error_list; |
|
155 |
|
156 while ((ent = readdir(dir))) { |
114 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) |
157 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) |
115 continue; |
158 continue; |
116 |
159 |
117 #ifdef DT_REG |
160 kind = entkind(ent); |
118 if (!keep_stat) |
161 if (kind == -1 || keepstat) { |
119 switch (ent->d_type) { |
162 if (USEFDOPEN) |
120 case DT_REG: kind = S_IFREG; break; |
163 err = fstatat(dfd, ent->d_name, &st, |
121 case DT_DIR: kind = S_IFDIR; break; |
164 AT_SYMLINK_NOFOLLOW); |
122 case DT_LNK: kind = S_IFLNK; break; |
165 else { |
123 case DT_BLK: kind = S_IFBLK; break; |
166 strncpy(fullpath + pathlen + 1, ent->d_name, |
124 case DT_CHR: kind = S_IFCHR; break; |
167 PATH_MAX - pathlen); |
125 case DT_FIFO: kind = S_IFIFO; break; |
168 fullpath[PATH_MAX] = 0; |
126 case DT_SOCK: kind = S_IFSOCK; break; |
169 err = lstat(fullpath, &st); |
127 default: |
|
128 *need_stat = 0; |
|
129 break; |
|
130 } |
170 } |
131 #endif |
171 if (err == -1) { |
132 |
172 strncpy(fullpath + pathlen + 1, ent->d_name, |
133 if (kind != -1) |
173 PATH_MAX - pathlen); |
134 py_kind = PyInt_FromLong(kind); |
174 fullpath[PATH_MAX] = 0; |
135 else { |
175 PyErr_SetFromErrnoWithFilename(PyExc_OSError, |
136 py_kind = Py_None; |
176 fullpath); |
137 Py_INCREF(Py_None); |
177 goto error; |
|
178 } |
|
179 kind = st.st_mode & S_IFMT; |
138 } |
180 } |
139 |
181 |
140 val = PyTuple_New(keep_stat ? 3 : 2); |
182 if (keepstat) { |
141 name = PyString_FromString(ent->d_name); |
183 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL); |
142 |
184 if (!stat) |
143 if (!name || !py_kind || !val) { |
185 goto error; |
144 Py_XDECREF(name); |
186 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st)); |
145 Py_XDECREF(py_kind); |
187 elem = Py_BuildValue("siN", ent->d_name, kind, stat); |
146 Py_XDECREF(val); |
188 } else |
147 return PyErr_NoMemory(); |
189 elem = Py_BuildValue("si", ent->d_name, kind); |
148 } |
190 if (!elem) |
149 |
191 goto error; |
150 PyTuple_SET_ITEM(val, 0, name); |
192 |
151 PyTuple_SET_ITEM(val, 1, py_kind); |
193 PyList_Append(list, elem); |
152 if (keep_stat) { |
194 Py_DECREF(elem); |
153 PyTuple_SET_ITEM(val, 2, Py_None); |
|
154 Py_INCREF(Py_None); |
|
155 } |
|
156 |
|
157 PyList_Append(list, val); |
|
158 Py_DECREF(val); |
|
159 } |
195 } |
160 |
196 |
161 return 0; |
|
162 } |
|
163 |
|
164 static PyObject *statfiles(PyObject *list, PyObject *ctor_args, int keep, |
|
165 char *path, int len, int dfd) |
|
166 { |
|
167 struct stat buf; |
|
168 struct stat *stp = &buf; |
|
169 int kind; |
|
170 int ret; |
|
171 ssize_t i; |
|
172 ssize_t size = PyList_Size(list); |
|
173 |
|
174 for (i = 0; i < size; i++) { |
|
175 PyObject *elt = PyList_GetItem(list, i); |
|
176 char *name = PyString_AsString(PyTuple_GET_ITEM(elt, 0)); |
|
177 PyObject *py_st = NULL; |
|
178 PyObject *py_kind = PyTuple_GET_ITEM(elt, 1); |
|
179 |
|
180 kind = py_kind == Py_None ? -1 : PyInt_AsLong(py_kind); |
|
181 if (kind != -1 && !keep) |
|
182 continue; |
|
183 |
|
184 strncpy(path + len + 1, name, PATH_MAX - len); |
|
185 path[PATH_MAX] = 0; |
|
186 |
|
187 if (keep) { |
|
188 py_st = PyObject_CallObject( |
|
189 (PyObject *)&listdir_stat_type, ctor_args); |
|
190 if (!py_st) |
|
191 return PyErr_NoMemory(); |
|
192 stp = &((struct listdir_stat *)py_st)->st; |
|
193 PyTuple_SET_ITEM(elt, 2, py_st); |
|
194 } |
|
195 |
|
196 #ifdef AT_SYMLINK_NOFOLLOW |
|
197 ret = fstatat(dfd, name, stp, AT_SYMLINK_NOFOLLOW); |
|
198 #else |
|
199 ret = lstat(path, stp); |
|
200 #endif |
|
201 if (ret == -1) |
|
202 return PyErr_SetFromErrnoWithFilename(PyExc_OSError, |
|
203 path); |
|
204 |
|
205 if (kind == -1) { |
|
206 if (S_ISREG(stp->st_mode)) |
|
207 kind = S_IFREG; |
|
208 else if (S_ISDIR(stp->st_mode)) |
|
209 kind = S_IFDIR; |
|
210 else if (S_ISLNK(stp->st_mode)) |
|
211 kind = S_IFLNK; |
|
212 else if (S_ISBLK(stp->st_mode)) |
|
213 kind = S_IFBLK; |
|
214 else if (S_ISCHR(stp->st_mode)) |
|
215 kind = S_IFCHR; |
|
216 else if (S_ISFIFO(stp->st_mode)) |
|
217 kind = S_IFIFO; |
|
218 else if (S_ISSOCK(stp->st_mode)) |
|
219 kind = S_IFSOCK; |
|
220 else |
|
221 kind = stp->st_mode; |
|
222 } |
|
223 |
|
224 if (py_kind == Py_None && kind != -1) { |
|
225 py_kind = PyInt_FromLong(kind); |
|
226 if (!py_kind) |
|
227 return PyErr_NoMemory(); |
|
228 Py_XDECREF(Py_None); |
|
229 PyTuple_SET_ITEM(elt, 1, py_kind); |
|
230 } |
|
231 } |
|
232 |
|
233 return 0; |
|
234 } |
|
235 |
|
236 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs) |
|
237 { |
|
238 static char *kwlist[] = { "path", "stat", NULL }; |
|
239 DIR *dir = NULL; |
|
240 PyObject *statobj = NULL; |
|
241 PyObject *list = NULL; |
|
242 PyObject *err = NULL; |
|
243 PyObject *ctor_args = NULL; |
|
244 char *path; |
|
245 char full_path[PATH_MAX + 10]; |
|
246 int path_len; |
|
247 int need_stat, keep_stat; |
|
248 int dfd; |
|
249 |
|
250 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist, |
|
251 &path, &path_len, &statobj)) |
|
252 goto bail; |
|
253 |
|
254 keep_stat = statobj && PyObject_IsTrue(statobj); |
|
255 |
|
256 #ifdef AT_SYMLINK_NOFOLLOW |
|
257 dfd = open(path, O_RDONLY); |
|
258 if (dfd != -1) |
|
259 dir = fdopendir(dfd); |
|
260 #else |
|
261 dir = opendir(path); |
|
262 dfd = -1; |
|
263 #endif |
|
264 if (!dir) { |
|
265 err = PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); |
|
266 goto bail; |
|
267 } |
|
268 |
|
269 list = PyList_New(0); |
|
270 ctor_args = PyTuple_New(0); |
|
271 if (!list || !ctor_args) |
|
272 goto bail; |
|
273 |
|
274 strncpy(full_path, path, PATH_MAX); |
|
275 full_path[path_len] = '/'; |
|
276 |
|
277 err = listfiles(list, dir, keep_stat, &need_stat); |
|
278 if (err) |
|
279 goto bail; |
|
280 |
|
281 PyList_Sort(list); |
197 PyList_Sort(list); |
282 |
198 ret = list; |
283 if (!keep_stat && !need_stat) |
199 Py_INCREF(ret); |
284 goto done; |
200 |
285 |
201 error: |
286 err = statfiles(list, ctor_args, keep_stat, full_path, path_len, dfd); |
202 Py_DECREF(list); |
287 if (!err) |
203 error_list: |
288 goto done; |
204 closedir(dir); |
289 |
205 error_dir: |
290 bail: |
206 if (USEFDOPEN) |
291 Py_XDECREF(list); |
207 close(dfd); |
292 |
208 error_parse: |
293 done: |
209 return ret; |
294 Py_XDECREF(ctor_args); |
210 } |
295 if (dir) |
|
296 closedir(dir); |
|
297 return err ? err : list; |
|
298 } |
|
299 |
|
300 |
211 |
301 static char osutil_doc[] = "Native operating system services."; |
212 static char osutil_doc[] = "Native operating system services."; |
302 |
213 |
303 static PyMethodDef methods[] = { |
214 static PyMethodDef methods[] = { |
304 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS, |
215 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS, |