##// END OF EJS Templates
osutil: fix some braindamage...
Matt Mackall -
r7033:892d27fb default
parent child Browse files
Show More
@@ -1,226 +1,225
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 <dirent.h>
12 #include <dirent.h>
13 #include <fcntl.h>
13 #include <fcntl.h>
14 #include <string.h>
14 #include <string.h>
15 #include <sys/stat.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
16 #include <sys/types.h>
17 #include <unistd.h>
17 #include <unistd.h>
18
18
19 struct listdir_stat {
19 struct listdir_stat {
20 PyObject_HEAD
20 PyObject_HEAD
21 struct stat st;
21 struct stat st;
22 };
22 };
23
23
24 #define listdir_slot(name) \
24 #define listdir_slot(name) \
25 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
25 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
26 { \
26 { \
27 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
27 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
28 }
28 }
29
29
30 listdir_slot(st_dev)
30 listdir_slot(st_dev)
31 listdir_slot(st_mode)
31 listdir_slot(st_mode)
32 listdir_slot(st_nlink)
32 listdir_slot(st_nlink)
33 listdir_slot(st_size)
33 listdir_slot(st_size)
34 listdir_slot(st_mtime)
34 listdir_slot(st_mtime)
35 listdir_slot(st_ctime)
35 listdir_slot(st_ctime)
36
36
37 static struct PyGetSetDef listdir_stat_getsets[] = {
37 static struct PyGetSetDef listdir_stat_getsets[] = {
38 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
38 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
39 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
39 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
40 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
40 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
41 {"st_size", listdir_stat_st_size, 0, 0, 0},
41 {"st_size", listdir_stat_st_size, 0, 0, 0},
42 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
42 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
43 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
43 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
44 {0, 0, 0, 0, 0}
44 {0, 0, 0, 0, 0}
45 };
45 };
46
46
47 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
47 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
48 {
48 {
49 return t->tp_alloc(t, 0);
49 return t->tp_alloc(t, 0);
50 }
50 }
51
51
52 static void listdir_stat_dealloc(PyObject *o)
52 static void listdir_stat_dealloc(PyObject *o)
53 {
53 {
54 o->ob_type->tp_free(o);
54 o->ob_type->tp_free(o);
55 }
55 }
56
56
57 static PyTypeObject listdir_stat_type = {
57 static PyTypeObject listdir_stat_type = {
58 PyObject_HEAD_INIT(NULL)
58 PyObject_HEAD_INIT(NULL)
59 0, /*ob_size*/
59 0, /*ob_size*/
60 "osutil.stat", /*tp_name*/
60 "osutil.stat", /*tp_name*/
61 sizeof(struct listdir_stat), /*tp_basicsize*/
61 sizeof(struct listdir_stat), /*tp_basicsize*/
62 0, /*tp_itemsize*/
62 0, /*tp_itemsize*/
63 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
63 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
64 0, /*tp_print*/
64 0, /*tp_print*/
65 0, /*tp_getattr*/
65 0, /*tp_getattr*/
66 0, /*tp_setattr*/
66 0, /*tp_setattr*/
67 0, /*tp_compare*/
67 0, /*tp_compare*/
68 0, /*tp_repr*/
68 0, /*tp_repr*/
69 0, /*tp_as_number*/
69 0, /*tp_as_number*/
70 0, /*tp_as_sequence*/
70 0, /*tp_as_sequence*/
71 0, /*tp_as_mapping*/
71 0, /*tp_as_mapping*/
72 0, /*tp_hash */
72 0, /*tp_hash */
73 0, /*tp_call*/
73 0, /*tp_call*/
74 0, /*tp_str*/
74 0, /*tp_str*/
75 0, /*tp_getattro*/
75 0, /*tp_getattro*/
76 0, /*tp_setattro*/
76 0, /*tp_setattro*/
77 0, /*tp_as_buffer*/
77 0, /*tp_as_buffer*/
78 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
78 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
79 "stat objects", /* tp_doc */
79 "stat objects", /* tp_doc */
80 0, /* tp_traverse */
80 0, /* tp_traverse */
81 0, /* tp_clear */
81 0, /* tp_clear */
82 0, /* tp_richcompare */
82 0, /* tp_richcompare */
83 0, /* tp_weaklistoffset */
83 0, /* tp_weaklistoffset */
84 0, /* tp_iter */
84 0, /* tp_iter */
85 0, /* tp_iternext */
85 0, /* tp_iternext */
86 0, /* tp_methods */
86 0, /* tp_methods */
87 0, /* tp_members */
87 0, /* tp_members */
88 listdir_stat_getsets, /* tp_getset */
88 listdir_stat_getsets, /* tp_getset */
89 0, /* tp_base */
89 0, /* tp_base */
90 0, /* tp_dict */
90 0, /* tp_dict */
91 0, /* tp_descr_get */
91 0, /* tp_descr_get */
92 0, /* tp_descr_set */
92 0, /* tp_descr_set */
93 0, /* tp_dictoffset */
93 0, /* tp_dictoffset */
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 #ifdef AT_SYMLINK_NOFOLLOW
100 #define USEFDOPEN 1
101 #else
102 #define USEFDOPEN 0
103 #endif
104
105 int entkind(struct dirent *ent)
99 int entkind(struct dirent *ent)
106 {
100 {
107 #ifdef DT_REG
101 #ifdef DT_REG
108 switch (ent->d_type) {
102 switch (ent->d_type) {
109 case DT_REG: return S_IFREG;
103 case DT_REG: return S_IFREG;
110 case DT_DIR: return S_IFDIR;
104 case DT_DIR: return S_IFDIR;
111 case DT_LNK: return S_IFLNK;
105 case DT_LNK: return S_IFLNK;
112 case DT_BLK: return S_IFBLK;
106 case DT_BLK: return S_IFBLK;
113 case DT_CHR: return S_IFCHR;
107 case DT_CHR: return S_IFCHR;
114 case DT_FIFO: return S_IFIFO;
108 case DT_FIFO: return S_IFIFO;
115 case DT_SOCK: return S_IFSOCK;
109 case DT_SOCK: return S_IFSOCK;
116 }
110 }
117 #endif
111 #endif
112 return -1;
118 }
113 }
119
114
120 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
115 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
121 {
116 {
122 static char *kwlist[] = { "path", "stat", NULL };
117 static char *kwlist[] = { "path", "stat", NULL };
123 PyObject *statflag = NULL, *list, *elem, *stat, *ret = NULL;
118 PyObject *statflag = NULL, *list, *elem, *stat, *ret = NULL;
124 char fullpath[PATH_MAX + 10], *path;
119 char fullpath[PATH_MAX + 10], *path;
125 int pathlen, keepstat, kind, dfd, err;
120 int pathlen, keepstat, kind, dfd = -1, err;
126 struct stat st;
121 struct stat st;
127 struct dirent *ent;
122 struct dirent *ent;
128 DIR *dir;
123 DIR *dir;
129
124
130 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
125 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
131 &path, &pathlen, &statflag))
126 &path, &pathlen, &statflag))
132 goto error_parse;
127 goto error_parse;
128 if (pathlen >= PATH_MAX)
129 goto error_parse;
133
130
134 strncpy(fullpath, path, PATH_MAX);
131 strncpy(fullpath, path, PATH_MAX);
135 fullpath[pathlen] = '/';
132 fullpath[pathlen] = '/';
136 keepstat = statflag && PyObject_IsTrue(statflag);
133 keepstat = statflag && PyObject_IsTrue(statflag);
137
134
138 if (USEFDOPEN) {
135 #ifdef AT_SYMLINK_NOFOLLOW
139 dfd = open(path, O_RDONLY);
136 dfd = open(path, O_RDONLY);
140 if (dfd == -1) {
137 if (dfd == -1) {
141 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
138 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
142 goto error_parse;
139 goto error_parse;
143 }
140 }
144 dir = fdopendir(dfd);
141 dir = fdopendir(dfd);
145 } else
142 #else
146 dir = opendir(path);
143 dir = opendir(path);
144 #endif
147 if (!dir) {
145 if (!dir) {
148 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
146 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
149 goto error_dir;
147 goto error_dir;
150 }
148 }
151
149
152 list = PyList_New(0);
150 list = PyList_New(0);
153 if (!list)
151 if (!list)
154 goto error_list;
152 goto error_list;
155
153
156 while ((ent = readdir(dir))) {
154 while ((ent = readdir(dir))) {
157 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
155 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
158 continue;
156 continue;
159
157
160 kind = entkind(ent);
158 kind = entkind(ent);
161 if (kind == -1 || keepstat) {
159 if (kind == -1 || keepstat) {
162 if (USEFDOPEN)
160 #ifdef AT_SYMLINK_NOFOLLOW
163 err = fstatat(dfd, ent->d_name, &st,
161 err = fstatat(dfd, ent->d_name, &st,
164 AT_SYMLINK_NOFOLLOW);
162 AT_SYMLINK_NOFOLLOW);
165 else {
163 #else
166 strncpy(fullpath + pathlen + 1, ent->d_name,
164 strncpy(fullpath + pathlen + 1, ent->d_name,
167 PATH_MAX - pathlen);
165 PATH_MAX - pathlen);
168 fullpath[PATH_MAX] = 0;
166 fullpath[PATH_MAX] = 0;
169 err = lstat(fullpath, &st);
167 err = lstat(fullpath, &st);
170 }
168 #endif
171 if (err == -1) {
169 if (err == -1) {
172 strncpy(fullpath + pathlen + 1, ent->d_name,
170 strncpy(fullpath + pathlen + 1, ent->d_name,
173 PATH_MAX - pathlen);
171 PATH_MAX - pathlen);
174 fullpath[PATH_MAX] = 0;
172 fullpath[PATH_MAX] = 0;
175 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
173 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
176 fullpath);
174 fullpath);
177 goto error;
175 goto error;
178 }
176 }
179 kind = st.st_mode & S_IFMT;
177 kind = st.st_mode & S_IFMT;
180 }
178 }
181
179
182 if (keepstat) {
180 if (keepstat) {
183 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
181 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
184 if (!stat)
182 if (!stat)
185 goto error;
183 goto error;
186 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
184 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
187 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
185 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
188 } else
186 } else
189 elem = Py_BuildValue("si", ent->d_name, kind);
187 elem = Py_BuildValue("si", ent->d_name, kind);
190 if (!elem)
188 if (!elem)
191 goto error;
189 goto error;
192
190
193 PyList_Append(list, elem);
191 PyList_Append(list, elem);
194 Py_DECREF(elem);
192 Py_DECREF(elem);
195 }
193 }
196
194
197 PyList_Sort(list);
195 PyList_Sort(list);
198 ret = list;
196 ret = list;
199 Py_INCREF(ret);
197 Py_INCREF(ret);
200
198
201 error:
199 error:
202 Py_DECREF(list);
200 Py_DECREF(list);
203 error_list:
201 error_list:
204 closedir(dir);
202 closedir(dir);
205 error_dir:
203 error_dir:
206 if (USEFDOPEN)
204 #ifdef AT_SYMLINK_NOFOLLOW
207 close(dfd);
205 close(dfd);
206 #endif
208 error_parse:
207 error_parse:
209 return ret;
208 return ret;
210 }
209 }
211
210
212 static char osutil_doc[] = "Native operating system services.";
211 static char osutil_doc[] = "Native operating system services.";
213
212
214 static PyMethodDef methods[] = {
213 static PyMethodDef methods[] = {
215 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
214 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
216 "list a directory\n"},
215 "list a directory\n"},
217 {NULL, NULL}
216 {NULL, NULL}
218 };
217 };
219
218
220 PyMODINIT_FUNC initosutil(void)
219 PyMODINIT_FUNC initosutil(void)
221 {
220 {
222 if (PyType_Ready(&listdir_stat_type) == -1)
221 if (PyType_Ready(&listdir_stat_type) == -1)
223 return;
222 return;
224
223
225 Py_InitModule3("osutil", methods, osutil_doc);
224 Py_InitModule3("osutil", methods, osutil_doc);
226 }
225 }
General Comments 0
You need to be logged in to leave comments. Login now