##// END OF EJS Templates
osutil: stop using strcpy...
Augie Fackler -
r28593:e60c492a default
parent child Browse files
Show More
@@ -1,927 +1,928
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 <stdlib.h>
14 #include <stdlib.h>
15 #include <string.h>
15 #include <string.h>
16 #include <errno.h>
16 #include <errno.h>
17
17
18 #ifdef _WIN32
18 #ifdef _WIN32
19 #include <windows.h>
19 #include <windows.h>
20 #include <io.h>
20 #include <io.h>
21 #else
21 #else
22 #include <dirent.h>
22 #include <dirent.h>
23 #include <sys/socket.h>
23 #include <sys/socket.h>
24 #include <sys/stat.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
25 #include <sys/types.h>
26 #include <unistd.h>
26 #include <unistd.h>
27 #endif
27 #endif
28
28
29 #ifdef __APPLE__
29 #ifdef __APPLE__
30 #include <sys/attr.h>
30 #include <sys/attr.h>
31 #include <sys/vnode.h>
31 #include <sys/vnode.h>
32 #endif
32 #endif
33
33
34 #include "util.h"
34 #include "util.h"
35
35
36 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
36 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
37 #ifndef PATH_MAX
37 #ifndef PATH_MAX
38 #define PATH_MAX 4096
38 #define PATH_MAX 4096
39 #endif
39 #endif
40
40
41 #ifdef _WIN32
41 #ifdef _WIN32
42 /*
42 /*
43 stat struct compatible with hg expectations
43 stat struct compatible with hg expectations
44 Mercurial only uses st_mode, st_size and st_mtime
44 Mercurial only uses st_mode, st_size and st_mtime
45 the rest is kept to minimize changes between implementations
45 the rest is kept to minimize changes between implementations
46 */
46 */
47 struct hg_stat {
47 struct hg_stat {
48 int st_dev;
48 int st_dev;
49 int st_mode;
49 int st_mode;
50 int st_nlink;
50 int st_nlink;
51 __int64 st_size;
51 __int64 st_size;
52 int st_mtime;
52 int st_mtime;
53 int st_ctime;
53 int st_ctime;
54 };
54 };
55 struct listdir_stat {
55 struct listdir_stat {
56 PyObject_HEAD
56 PyObject_HEAD
57 struct hg_stat st;
57 struct hg_stat st;
58 };
58 };
59 #else
59 #else
60 struct listdir_stat {
60 struct listdir_stat {
61 PyObject_HEAD
61 PyObject_HEAD
62 struct stat st;
62 struct stat st;
63 };
63 };
64 #endif
64 #endif
65
65
66 #define listdir_slot(name) \
66 #define listdir_slot(name) \
67 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
67 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
68 { \
68 { \
69 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
69 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
70 }
70 }
71
71
72 listdir_slot(st_dev)
72 listdir_slot(st_dev)
73 listdir_slot(st_mode)
73 listdir_slot(st_mode)
74 listdir_slot(st_nlink)
74 listdir_slot(st_nlink)
75 #ifdef _WIN32
75 #ifdef _WIN32
76 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
76 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
77 {
77 {
78 return PyLong_FromLongLong(
78 return PyLong_FromLongLong(
79 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
79 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
80 }
80 }
81 #else
81 #else
82 listdir_slot(st_size)
82 listdir_slot(st_size)
83 #endif
83 #endif
84 listdir_slot(st_mtime)
84 listdir_slot(st_mtime)
85 listdir_slot(st_ctime)
85 listdir_slot(st_ctime)
86
86
87 static struct PyGetSetDef listdir_stat_getsets[] = {
87 static struct PyGetSetDef listdir_stat_getsets[] = {
88 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
88 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
89 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
89 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
90 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
90 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
91 {"st_size", listdir_stat_st_size, 0, 0, 0},
91 {"st_size", listdir_stat_st_size, 0, 0, 0},
92 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
92 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
93 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
93 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
94 {0, 0, 0, 0, 0}
94 {0, 0, 0, 0, 0}
95 };
95 };
96
96
97 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
97 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
98 {
98 {
99 return t->tp_alloc(t, 0);
99 return t->tp_alloc(t, 0);
100 }
100 }
101
101
102 static void listdir_stat_dealloc(PyObject *o)
102 static void listdir_stat_dealloc(PyObject *o)
103 {
103 {
104 o->ob_type->tp_free(o);
104 o->ob_type->tp_free(o);
105 }
105 }
106
106
107 static PyTypeObject listdir_stat_type = {
107 static PyTypeObject listdir_stat_type = {
108 PyVarObject_HEAD_INIT(NULL, 0)
108 PyVarObject_HEAD_INIT(NULL, 0)
109 "osutil.stat", /*tp_name*/
109 "osutil.stat", /*tp_name*/
110 sizeof(struct listdir_stat), /*tp_basicsize*/
110 sizeof(struct listdir_stat), /*tp_basicsize*/
111 0, /*tp_itemsize*/
111 0, /*tp_itemsize*/
112 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
112 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
113 0, /*tp_print*/
113 0, /*tp_print*/
114 0, /*tp_getattr*/
114 0, /*tp_getattr*/
115 0, /*tp_setattr*/
115 0, /*tp_setattr*/
116 0, /*tp_compare*/
116 0, /*tp_compare*/
117 0, /*tp_repr*/
117 0, /*tp_repr*/
118 0, /*tp_as_number*/
118 0, /*tp_as_number*/
119 0, /*tp_as_sequence*/
119 0, /*tp_as_sequence*/
120 0, /*tp_as_mapping*/
120 0, /*tp_as_mapping*/
121 0, /*tp_hash */
121 0, /*tp_hash */
122 0, /*tp_call*/
122 0, /*tp_call*/
123 0, /*tp_str*/
123 0, /*tp_str*/
124 0, /*tp_getattro*/
124 0, /*tp_getattro*/
125 0, /*tp_setattro*/
125 0, /*tp_setattro*/
126 0, /*tp_as_buffer*/
126 0, /*tp_as_buffer*/
127 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
127 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
128 "stat objects", /* tp_doc */
128 "stat objects", /* tp_doc */
129 0, /* tp_traverse */
129 0, /* tp_traverse */
130 0, /* tp_clear */
130 0, /* tp_clear */
131 0, /* tp_richcompare */
131 0, /* tp_richcompare */
132 0, /* tp_weaklistoffset */
132 0, /* tp_weaklistoffset */
133 0, /* tp_iter */
133 0, /* tp_iter */
134 0, /* tp_iternext */
134 0, /* tp_iternext */
135 0, /* tp_methods */
135 0, /* tp_methods */
136 0, /* tp_members */
136 0, /* tp_members */
137 listdir_stat_getsets, /* tp_getset */
137 listdir_stat_getsets, /* tp_getset */
138 0, /* tp_base */
138 0, /* tp_base */
139 0, /* tp_dict */
139 0, /* tp_dict */
140 0, /* tp_descr_get */
140 0, /* tp_descr_get */
141 0, /* tp_descr_set */
141 0, /* tp_descr_set */
142 0, /* tp_dictoffset */
142 0, /* tp_dictoffset */
143 0, /* tp_init */
143 0, /* tp_init */
144 0, /* tp_alloc */
144 0, /* tp_alloc */
145 listdir_stat_new, /* tp_new */
145 listdir_stat_new, /* tp_new */
146 };
146 };
147
147
148 #ifdef _WIN32
148 #ifdef _WIN32
149
149
150 static int to_python_time(const FILETIME *tm)
150 static int to_python_time(const FILETIME *tm)
151 {
151 {
152 /* number of seconds between epoch and January 1 1601 */
152 /* number of seconds between epoch and January 1 1601 */
153 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
153 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
154 /* conversion factor from 100ns to 1s */
154 /* conversion factor from 100ns to 1s */
155 const __int64 a1 = 10000000;
155 const __int64 a1 = 10000000;
156 /* explicit (int) cast to suspend compiler warnings */
156 /* explicit (int) cast to suspend compiler warnings */
157 return (int)((((__int64)tm->dwHighDateTime << 32)
157 return (int)((((__int64)tm->dwHighDateTime << 32)
158 + tm->dwLowDateTime) / a1 - a0);
158 + tm->dwLowDateTime) / a1 - a0);
159 }
159 }
160
160
161 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
161 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
162 {
162 {
163 PyObject *py_st;
163 PyObject *py_st;
164 struct hg_stat *stp;
164 struct hg_stat *stp;
165
165
166 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
166 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
167 ? _S_IFDIR : _S_IFREG;
167 ? _S_IFDIR : _S_IFREG;
168
168
169 if (!wantstat)
169 if (!wantstat)
170 return Py_BuildValue("si", fd->cFileName, kind);
170 return Py_BuildValue("si", fd->cFileName, kind);
171
171
172 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
172 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
173 if (!py_st)
173 if (!py_st)
174 return NULL;
174 return NULL;
175
175
176 stp = &((struct listdir_stat *)py_st)->st;
176 stp = &((struct listdir_stat *)py_st)->st;
177 /*
177 /*
178 use kind as st_mode
178 use kind as st_mode
179 rwx bits on Win32 are meaningless
179 rwx bits on Win32 are meaningless
180 and Hg does not use them anyway
180 and Hg does not use them anyway
181 */
181 */
182 stp->st_mode = kind;
182 stp->st_mode = kind;
183 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
183 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
184 stp->st_ctime = to_python_time(&fd->ftCreationTime);
184 stp->st_ctime = to_python_time(&fd->ftCreationTime);
185 if (kind == _S_IFREG)
185 if (kind == _S_IFREG)
186 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
186 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
187 + fd->nFileSizeLow;
187 + fd->nFileSizeLow;
188 return Py_BuildValue("siN", fd->cFileName,
188 return Py_BuildValue("siN", fd->cFileName,
189 kind, py_st);
189 kind, py_st);
190 }
190 }
191
191
192 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
192 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
193 {
193 {
194 PyObject *rval = NULL; /* initialize - return value */
194 PyObject *rval = NULL; /* initialize - return value */
195 PyObject *list;
195 PyObject *list;
196 HANDLE fh;
196 HANDLE fh;
197 WIN32_FIND_DATAA fd;
197 WIN32_FIND_DATAA fd;
198 char *pattern;
198 char *pattern;
199
199
200 /* build the path + \* pattern string */
200 /* build the path + \* pattern string */
201 pattern = malloc(plen + 3); /* path + \* + \0 */
201 pattern = malloc(plen + 3); /* path + \* + \0 */
202 if (!pattern) {
202 if (!pattern) {
203 PyErr_NoMemory();
203 PyErr_NoMemory();
204 goto error_nomem;
204 goto error_nomem;
205 }
205 }
206 strcpy(pattern, path);
206 memcpy(pattern, path, plen);
207
207
208 if (plen > 0) {
208 if (plen > 0) {
209 char c = path[plen-1];
209 char c = path[plen-1];
210 if (c != ':' && c != '/' && c != '\\')
210 if (c != ':' && c != '/' && c != '\\')
211 pattern[plen++] = '\\';
211 pattern[plen++] = '\\';
212 }
212 }
213 strcpy(pattern + plen, "*");
213 pattern[plen++] = '*';
214 pattern[plen] = '\0';
214
215
215 fh = FindFirstFileA(pattern, &fd);
216 fh = FindFirstFileA(pattern, &fd);
216 if (fh == INVALID_HANDLE_VALUE) {
217 if (fh == INVALID_HANDLE_VALUE) {
217 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
218 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
218 goto error_file;
219 goto error_file;
219 }
220 }
220
221
221 list = PyList_New(0);
222 list = PyList_New(0);
222 if (!list)
223 if (!list)
223 goto error_list;
224 goto error_list;
224
225
225 do {
226 do {
226 PyObject *item;
227 PyObject *item;
227
228
228 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
229 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
229 if (!strcmp(fd.cFileName, ".")
230 if (!strcmp(fd.cFileName, ".")
230 || !strcmp(fd.cFileName, ".."))
231 || !strcmp(fd.cFileName, ".."))
231 continue;
232 continue;
232
233
233 if (skip && !strcmp(fd.cFileName, skip)) {
234 if (skip && !strcmp(fd.cFileName, skip)) {
234 rval = PyList_New(0);
235 rval = PyList_New(0);
235 goto error;
236 goto error;
236 }
237 }
237 }
238 }
238
239
239 item = make_item(&fd, wantstat);
240 item = make_item(&fd, wantstat);
240 if (!item)
241 if (!item)
241 goto error;
242 goto error;
242
243
243 if (PyList_Append(list, item)) {
244 if (PyList_Append(list, item)) {
244 Py_XDECREF(item);
245 Py_XDECREF(item);
245 goto error;
246 goto error;
246 }
247 }
247
248
248 Py_XDECREF(item);
249 Py_XDECREF(item);
249 } while (FindNextFileA(fh, &fd));
250 } while (FindNextFileA(fh, &fd));
250
251
251 if (GetLastError() != ERROR_NO_MORE_FILES) {
252 if (GetLastError() != ERROR_NO_MORE_FILES) {
252 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
253 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
253 goto error;
254 goto error;
254 }
255 }
255
256
256 rval = list;
257 rval = list;
257 Py_XINCREF(rval);
258 Py_XINCREF(rval);
258 error:
259 error:
259 Py_XDECREF(list);
260 Py_XDECREF(list);
260 error_list:
261 error_list:
261 FindClose(fh);
262 FindClose(fh);
262 error_file:
263 error_file:
263 free(pattern);
264 free(pattern);
264 error_nomem:
265 error_nomem:
265 return rval;
266 return rval;
266 }
267 }
267
268
268 #else
269 #else
269
270
270 int entkind(struct dirent *ent)
271 int entkind(struct dirent *ent)
271 {
272 {
272 #ifdef DT_REG
273 #ifdef DT_REG
273 switch (ent->d_type) {
274 switch (ent->d_type) {
274 case DT_REG: return S_IFREG;
275 case DT_REG: return S_IFREG;
275 case DT_DIR: return S_IFDIR;
276 case DT_DIR: return S_IFDIR;
276 case DT_LNK: return S_IFLNK;
277 case DT_LNK: return S_IFLNK;
277 case DT_BLK: return S_IFBLK;
278 case DT_BLK: return S_IFBLK;
278 case DT_CHR: return S_IFCHR;
279 case DT_CHR: return S_IFCHR;
279 case DT_FIFO: return S_IFIFO;
280 case DT_FIFO: return S_IFIFO;
280 case DT_SOCK: return S_IFSOCK;
281 case DT_SOCK: return S_IFSOCK;
281 }
282 }
282 #endif
283 #endif
283 return -1;
284 return -1;
284 }
285 }
285
286
286 static PyObject *makestat(const struct stat *st)
287 static PyObject *makestat(const struct stat *st)
287 {
288 {
288 PyObject *stat;
289 PyObject *stat;
289
290
290 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
291 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
291 if (stat)
292 if (stat)
292 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
293 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
293 return stat;
294 return stat;
294 }
295 }
295
296
296 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
297 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
297 char *skip)
298 char *skip)
298 {
299 {
299 PyObject *list, *elem, *stat = NULL, *ret = NULL;
300 PyObject *list, *elem, *stat = NULL, *ret = NULL;
300 char fullpath[PATH_MAX + 10];
301 char fullpath[PATH_MAX + 10];
301 int kind, err;
302 int kind, err;
302 struct stat st;
303 struct stat st;
303 struct dirent *ent;
304 struct dirent *ent;
304 DIR *dir;
305 DIR *dir;
305 #ifdef AT_SYMLINK_NOFOLLOW
306 #ifdef AT_SYMLINK_NOFOLLOW
306 int dfd = -1;
307 int dfd = -1;
307 #endif
308 #endif
308
309
309 if (pathlen >= PATH_MAX) {
310 if (pathlen >= PATH_MAX) {
310 errno = ENAMETOOLONG;
311 errno = ENAMETOOLONG;
311 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
312 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
312 goto error_value;
313 goto error_value;
313 }
314 }
314 strncpy(fullpath, path, PATH_MAX);
315 strncpy(fullpath, path, PATH_MAX);
315 fullpath[pathlen] = '/';
316 fullpath[pathlen] = '/';
316
317
317 #ifdef AT_SYMLINK_NOFOLLOW
318 #ifdef AT_SYMLINK_NOFOLLOW
318 dfd = open(path, O_RDONLY);
319 dfd = open(path, O_RDONLY);
319 if (dfd == -1) {
320 if (dfd == -1) {
320 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
321 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
321 goto error_value;
322 goto error_value;
322 }
323 }
323 dir = fdopendir(dfd);
324 dir = fdopendir(dfd);
324 #else
325 #else
325 dir = opendir(path);
326 dir = opendir(path);
326 #endif
327 #endif
327 if (!dir) {
328 if (!dir) {
328 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
329 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
329 goto error_dir;
330 goto error_dir;
330 }
331 }
331
332
332 list = PyList_New(0);
333 list = PyList_New(0);
333 if (!list)
334 if (!list)
334 goto error_list;
335 goto error_list;
335
336
336 while ((ent = readdir(dir))) {
337 while ((ent = readdir(dir))) {
337 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
338 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
338 continue;
339 continue;
339
340
340 kind = entkind(ent);
341 kind = entkind(ent);
341 if (kind == -1 || keepstat) {
342 if (kind == -1 || keepstat) {
342 #ifdef AT_SYMLINK_NOFOLLOW
343 #ifdef AT_SYMLINK_NOFOLLOW
343 err = fstatat(dfd, ent->d_name, &st,
344 err = fstatat(dfd, ent->d_name, &st,
344 AT_SYMLINK_NOFOLLOW);
345 AT_SYMLINK_NOFOLLOW);
345 #else
346 #else
346 strncpy(fullpath + pathlen + 1, ent->d_name,
347 strncpy(fullpath + pathlen + 1, ent->d_name,
347 PATH_MAX - pathlen);
348 PATH_MAX - pathlen);
348 fullpath[PATH_MAX] = '\0';
349 fullpath[PATH_MAX] = '\0';
349 err = lstat(fullpath, &st);
350 err = lstat(fullpath, &st);
350 #endif
351 #endif
351 if (err == -1) {
352 if (err == -1) {
352 /* race with file deletion? */
353 /* race with file deletion? */
353 if (errno == ENOENT)
354 if (errno == ENOENT)
354 continue;
355 continue;
355 strncpy(fullpath + pathlen + 1, ent->d_name,
356 strncpy(fullpath + pathlen + 1, ent->d_name,
356 PATH_MAX - pathlen);
357 PATH_MAX - pathlen);
357 fullpath[PATH_MAX] = 0;
358 fullpath[PATH_MAX] = 0;
358 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
359 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
359 fullpath);
360 fullpath);
360 goto error;
361 goto error;
361 }
362 }
362 kind = st.st_mode & S_IFMT;
363 kind = st.st_mode & S_IFMT;
363 }
364 }
364
365
365 /* quit early? */
366 /* quit early? */
366 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
367 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
367 ret = PyList_New(0);
368 ret = PyList_New(0);
368 goto error;
369 goto error;
369 }
370 }
370
371
371 if (keepstat) {
372 if (keepstat) {
372 stat = makestat(&st);
373 stat = makestat(&st);
373 if (!stat)
374 if (!stat)
374 goto error;
375 goto error;
375 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
376 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
376 } else
377 } else
377 elem = Py_BuildValue("si", ent->d_name, kind);
378 elem = Py_BuildValue("si", ent->d_name, kind);
378 if (!elem)
379 if (!elem)
379 goto error;
380 goto error;
380 stat = NULL;
381 stat = NULL;
381
382
382 PyList_Append(list, elem);
383 PyList_Append(list, elem);
383 Py_DECREF(elem);
384 Py_DECREF(elem);
384 }
385 }
385
386
386 ret = list;
387 ret = list;
387 Py_INCREF(ret);
388 Py_INCREF(ret);
388
389
389 error:
390 error:
390 Py_DECREF(list);
391 Py_DECREF(list);
391 Py_XDECREF(stat);
392 Py_XDECREF(stat);
392 error_list:
393 error_list:
393 closedir(dir);
394 closedir(dir);
394 error_dir:
395 error_dir:
395 #ifdef AT_SYMLINK_NOFOLLOW
396 #ifdef AT_SYMLINK_NOFOLLOW
396 close(dfd);
397 close(dfd);
397 #endif
398 #endif
398 error_value:
399 error_value:
399 return ret;
400 return ret;
400 }
401 }
401
402
402 #ifdef __APPLE__
403 #ifdef __APPLE__
403
404
404 typedef struct {
405 typedef struct {
405 u_int32_t length;
406 u_int32_t length;
406 attrreference_t name;
407 attrreference_t name;
407 fsobj_type_t obj_type;
408 fsobj_type_t obj_type;
408 struct timespec mtime;
409 struct timespec mtime;
409 #if __LITTLE_ENDIAN__
410 #if __LITTLE_ENDIAN__
410 mode_t access_mask;
411 mode_t access_mask;
411 uint16_t padding;
412 uint16_t padding;
412 #else
413 #else
413 uint16_t padding;
414 uint16_t padding;
414 mode_t access_mask;
415 mode_t access_mask;
415 #endif
416 #endif
416 off_t size;
417 off_t size;
417 } __attribute__((packed)) attrbuf_entry;
418 } __attribute__((packed)) attrbuf_entry;
418
419
419 int attrkind(attrbuf_entry *entry)
420 int attrkind(attrbuf_entry *entry)
420 {
421 {
421 switch (entry->obj_type) {
422 switch (entry->obj_type) {
422 case VREG: return S_IFREG;
423 case VREG: return S_IFREG;
423 case VDIR: return S_IFDIR;
424 case VDIR: return S_IFDIR;
424 case VLNK: return S_IFLNK;
425 case VLNK: return S_IFLNK;
425 case VBLK: return S_IFBLK;
426 case VBLK: return S_IFBLK;
426 case VCHR: return S_IFCHR;
427 case VCHR: return S_IFCHR;
427 case VFIFO: return S_IFIFO;
428 case VFIFO: return S_IFIFO;
428 case VSOCK: return S_IFSOCK;
429 case VSOCK: return S_IFSOCK;
429 }
430 }
430 return -1;
431 return -1;
431 }
432 }
432
433
433 /* get these many entries at a time */
434 /* get these many entries at a time */
434 #define LISTDIR_BATCH_SIZE 50
435 #define LISTDIR_BATCH_SIZE 50
435
436
436 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
437 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
437 char *skip, bool *fallback)
438 char *skip, bool *fallback)
438 {
439 {
439 PyObject *list, *elem, *stat = NULL, *ret = NULL;
440 PyObject *list, *elem, *stat = NULL, *ret = NULL;
440 int kind, err;
441 int kind, err;
441 unsigned long index;
442 unsigned long index;
442 unsigned int count, old_state, new_state;
443 unsigned int count, old_state, new_state;
443 bool state_seen = false;
444 bool state_seen = false;
444 attrbuf_entry *entry;
445 attrbuf_entry *entry;
445 /* from the getattrlist(2) man page: a path can be no longer than
446 /* from the getattrlist(2) man page: a path can be no longer than
446 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
447 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
447 silently truncate attribute data if attrBufSize is too small." So
448 silently truncate attribute data if attrBufSize is too small." So
448 pass in a buffer big enough for the worst case. */
449 pass in a buffer big enough for the worst case. */
449 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
450 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
450 unsigned int basep_unused;
451 unsigned int basep_unused;
451
452
452 struct stat st;
453 struct stat st;
453 int dfd = -1;
454 int dfd = -1;
454
455
455 /* these must match the attrbuf_entry struct, otherwise you'll end up
456 /* these must match the attrbuf_entry struct, otherwise you'll end up
456 with garbage */
457 with garbage */
457 struct attrlist requested_attr = {0};
458 struct attrlist requested_attr = {0};
458 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
459 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
459 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
460 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
460 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
461 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
461 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
462 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
462
463
463 *fallback = false;
464 *fallback = false;
464
465
465 if (pathlen >= PATH_MAX) {
466 if (pathlen >= PATH_MAX) {
466 errno = ENAMETOOLONG;
467 errno = ENAMETOOLONG;
467 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
468 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
468 goto error_value;
469 goto error_value;
469 }
470 }
470
471
471 dfd = open(path, O_RDONLY);
472 dfd = open(path, O_RDONLY);
472 if (dfd == -1) {
473 if (dfd == -1) {
473 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
474 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
474 goto error_value;
475 goto error_value;
475 }
476 }
476
477
477 list = PyList_New(0);
478 list = PyList_New(0);
478 if (!list)
479 if (!list)
479 goto error_dir;
480 goto error_dir;
480
481
481 do {
482 do {
482 count = LISTDIR_BATCH_SIZE;
483 count = LISTDIR_BATCH_SIZE;
483 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
484 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
484 sizeof(attrbuf), &count, &basep_unused,
485 sizeof(attrbuf), &count, &basep_unused,
485 &new_state, 0);
486 &new_state, 0);
486 if (err < 0) {
487 if (err < 0) {
487 if (errno == ENOTSUP) {
488 if (errno == ENOTSUP) {
488 /* We're on a filesystem that doesn't support
489 /* We're on a filesystem that doesn't support
489 getdirentriesattr. Fall back to the
490 getdirentriesattr. Fall back to the
490 stat-based implementation. */
491 stat-based implementation. */
491 *fallback = true;
492 *fallback = true;
492 } else
493 } else
493 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
494 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
494 goto error;
495 goto error;
495 }
496 }
496
497
497 if (!state_seen) {
498 if (!state_seen) {
498 old_state = new_state;
499 old_state = new_state;
499 state_seen = true;
500 state_seen = true;
500 } else if (old_state != new_state) {
501 } else if (old_state != new_state) {
501 /* There's an edge case with getdirentriesattr. Consider
502 /* There's an edge case with getdirentriesattr. Consider
502 the following initial list of files:
503 the following initial list of files:
503
504
504 a
505 a
505 b
506 b
506 <--
507 <--
507 c
508 c
508 d
509 d
509
510
510 If the iteration is paused at the arrow, and b is
511 If the iteration is paused at the arrow, and b is
511 deleted before it is resumed, getdirentriesattr will
512 deleted before it is resumed, getdirentriesattr will
512 not return d at all! Ordinarily we're expected to
513 not return d at all! Ordinarily we're expected to
513 restart the iteration from the beginning. To avoid
514 restart the iteration from the beginning. To avoid
514 getting stuck in a retry loop here, fall back to
515 getting stuck in a retry loop here, fall back to
515 stat. */
516 stat. */
516 *fallback = true;
517 *fallback = true;
517 goto error;
518 goto error;
518 }
519 }
519
520
520 entry = (attrbuf_entry *)attrbuf;
521 entry = (attrbuf_entry *)attrbuf;
521
522
522 for (index = 0; index < count; index++) {
523 for (index = 0; index < count; index++) {
523 char *filename = ((char *)&entry->name) +
524 char *filename = ((char *)&entry->name) +
524 entry->name.attr_dataoffset;
525 entry->name.attr_dataoffset;
525
526
526 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
527 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
527 continue;
528 continue;
528
529
529 kind = attrkind(entry);
530 kind = attrkind(entry);
530 if (kind == -1) {
531 if (kind == -1) {
531 PyErr_Format(PyExc_OSError,
532 PyErr_Format(PyExc_OSError,
532 "unknown object type %u for file "
533 "unknown object type %u for file "
533 "%s%s!",
534 "%s%s!",
534 entry->obj_type, path, filename);
535 entry->obj_type, path, filename);
535 goto error;
536 goto error;
536 }
537 }
537
538
538 /* quit early? */
539 /* quit early? */
539 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
540 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
540 ret = PyList_New(0);
541 ret = PyList_New(0);
541 goto error;
542 goto error;
542 }
543 }
543
544
544 if (keepstat) {
545 if (keepstat) {
545 /* from the getattrlist(2) man page: "Only the
546 /* from the getattrlist(2) man page: "Only the
546 permission bits ... are valid". */
547 permission bits ... are valid". */
547 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
548 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
548 st.st_mtime = entry->mtime.tv_sec;
549 st.st_mtime = entry->mtime.tv_sec;
549 st.st_size = entry->size;
550 st.st_size = entry->size;
550 stat = makestat(&st);
551 stat = makestat(&st);
551 if (!stat)
552 if (!stat)
552 goto error;
553 goto error;
553 elem = Py_BuildValue("siN", filename, kind, stat);
554 elem = Py_BuildValue("siN", filename, kind, stat);
554 } else
555 } else
555 elem = Py_BuildValue("si", filename, kind);
556 elem = Py_BuildValue("si", filename, kind);
556 if (!elem)
557 if (!elem)
557 goto error;
558 goto error;
558 stat = NULL;
559 stat = NULL;
559
560
560 PyList_Append(list, elem);
561 PyList_Append(list, elem);
561 Py_DECREF(elem);
562 Py_DECREF(elem);
562
563
563 entry = (attrbuf_entry *)((char *)entry + entry->length);
564 entry = (attrbuf_entry *)((char *)entry + entry->length);
564 }
565 }
565 } while (err == 0);
566 } while (err == 0);
566
567
567 ret = list;
568 ret = list;
568 Py_INCREF(ret);
569 Py_INCREF(ret);
569
570
570 error:
571 error:
571 Py_DECREF(list);
572 Py_DECREF(list);
572 Py_XDECREF(stat);
573 Py_XDECREF(stat);
573 error_dir:
574 error_dir:
574 close(dfd);
575 close(dfd);
575 error_value:
576 error_value:
576 return ret;
577 return ret;
577 }
578 }
578
579
579 #endif /* __APPLE__ */
580 #endif /* __APPLE__ */
580
581
581 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
582 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
582 {
583 {
583 #ifdef __APPLE__
584 #ifdef __APPLE__
584 PyObject *ret;
585 PyObject *ret;
585 bool fallback = false;
586 bool fallback = false;
586
587
587 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
588 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
588 if (ret != NULL || !fallback)
589 if (ret != NULL || !fallback)
589 return ret;
590 return ret;
590 #endif
591 #endif
591 return _listdir_stat(path, pathlen, keepstat, skip);
592 return _listdir_stat(path, pathlen, keepstat, skip);
592 }
593 }
593
594
594 static PyObject *statfiles(PyObject *self, PyObject *args)
595 static PyObject *statfiles(PyObject *self, PyObject *args)
595 {
596 {
596 PyObject *names, *stats;
597 PyObject *names, *stats;
597 Py_ssize_t i, count;
598 Py_ssize_t i, count;
598
599
599 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
600 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
600 return NULL;
601 return NULL;
601
602
602 count = PySequence_Length(names);
603 count = PySequence_Length(names);
603 if (count == -1) {
604 if (count == -1) {
604 PyErr_SetString(PyExc_TypeError, "not a sequence");
605 PyErr_SetString(PyExc_TypeError, "not a sequence");
605 return NULL;
606 return NULL;
606 }
607 }
607
608
608 stats = PyList_New(count);
609 stats = PyList_New(count);
609 if (stats == NULL)
610 if (stats == NULL)
610 return NULL;
611 return NULL;
611
612
612 for (i = 0; i < count; i++) {
613 for (i = 0; i < count; i++) {
613 PyObject *stat, *pypath;
614 PyObject *stat, *pypath;
614 struct stat st;
615 struct stat st;
615 int ret, kind;
616 int ret, kind;
616 char *path;
617 char *path;
617
618
618 /* With a large file count or on a slow filesystem,
619 /* With a large file count or on a slow filesystem,
619 don't block signals for long (issue4878). */
620 don't block signals for long (issue4878). */
620 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
621 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
621 goto bail;
622 goto bail;
622
623
623 pypath = PySequence_GetItem(names, i);
624 pypath = PySequence_GetItem(names, i);
624 if (!pypath)
625 if (!pypath)
625 goto bail;
626 goto bail;
626 path = PyString_AsString(pypath);
627 path = PyString_AsString(pypath);
627 if (path == NULL) {
628 if (path == NULL) {
628 Py_DECREF(pypath);
629 Py_DECREF(pypath);
629 PyErr_SetString(PyExc_TypeError, "not a string");
630 PyErr_SetString(PyExc_TypeError, "not a string");
630 goto bail;
631 goto bail;
631 }
632 }
632 ret = lstat(path, &st);
633 ret = lstat(path, &st);
633 Py_DECREF(pypath);
634 Py_DECREF(pypath);
634 kind = st.st_mode & S_IFMT;
635 kind = st.st_mode & S_IFMT;
635 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
636 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
636 stat = makestat(&st);
637 stat = makestat(&st);
637 if (stat == NULL)
638 if (stat == NULL)
638 goto bail;
639 goto bail;
639 PyList_SET_ITEM(stats, i, stat);
640 PyList_SET_ITEM(stats, i, stat);
640 } else {
641 } else {
641 Py_INCREF(Py_None);
642 Py_INCREF(Py_None);
642 PyList_SET_ITEM(stats, i, Py_None);
643 PyList_SET_ITEM(stats, i, Py_None);
643 }
644 }
644 }
645 }
645
646
646 return stats;
647 return stats;
647
648
648 bail:
649 bail:
649 Py_DECREF(stats);
650 Py_DECREF(stats);
650 return NULL;
651 return NULL;
651 }
652 }
652
653
653 /*
654 /*
654 * recvfds() simply does not release GIL during blocking io operation because
655 * recvfds() simply does not release GIL during blocking io operation because
655 * command server is known to be single-threaded.
656 * command server is known to be single-threaded.
656 *
657 *
657 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
658 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
658 * Currently, recvfds() is not supported on these platforms.
659 * Currently, recvfds() is not supported on these platforms.
659 */
660 */
660 #ifdef CMSG_LEN
661 #ifdef CMSG_LEN
661
662
662 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
663 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
663 {
664 {
664 char dummy[1];
665 char dummy[1];
665 struct iovec iov = {dummy, sizeof(dummy)};
666 struct iovec iov = {dummy, sizeof(dummy)};
666 struct msghdr msgh = {0};
667 struct msghdr msgh = {0};
667 struct cmsghdr *cmsg;
668 struct cmsghdr *cmsg;
668
669
669 msgh.msg_iov = &iov;
670 msgh.msg_iov = &iov;
670 msgh.msg_iovlen = 1;
671 msgh.msg_iovlen = 1;
671 msgh.msg_control = cbuf;
672 msgh.msg_control = cbuf;
672 msgh.msg_controllen = (socklen_t)cbufsize;
673 msgh.msg_controllen = (socklen_t)cbufsize;
673 if (recvmsg(sockfd, &msgh, 0) < 0)
674 if (recvmsg(sockfd, &msgh, 0) < 0)
674 return -1;
675 return -1;
675
676
676 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
677 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
677 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
678 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
678 if (cmsg->cmsg_level != SOL_SOCKET ||
679 if (cmsg->cmsg_level != SOL_SOCKET ||
679 cmsg->cmsg_type != SCM_RIGHTS)
680 cmsg->cmsg_type != SCM_RIGHTS)
680 continue;
681 continue;
681 *rfds = (int *)CMSG_DATA(cmsg);
682 *rfds = (int *)CMSG_DATA(cmsg);
682 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
683 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
683 }
684 }
684
685
685 *rfds = cbuf;
686 *rfds = cbuf;
686 return 0;
687 return 0;
687 }
688 }
688
689
689 static PyObject *recvfds(PyObject *self, PyObject *args)
690 static PyObject *recvfds(PyObject *self, PyObject *args)
690 {
691 {
691 int sockfd;
692 int sockfd;
692 int *rfds = NULL;
693 int *rfds = NULL;
693 ssize_t rfdscount, i;
694 ssize_t rfdscount, i;
694 char cbuf[256];
695 char cbuf[256];
695 PyObject *rfdslist = NULL;
696 PyObject *rfdslist = NULL;
696
697
697 if (!PyArg_ParseTuple(args, "i", &sockfd))
698 if (!PyArg_ParseTuple(args, "i", &sockfd))
698 return NULL;
699 return NULL;
699
700
700 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
701 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
701 if (rfdscount < 0)
702 if (rfdscount < 0)
702 return PyErr_SetFromErrno(PyExc_OSError);
703 return PyErr_SetFromErrno(PyExc_OSError);
703
704
704 rfdslist = PyList_New(rfdscount);
705 rfdslist = PyList_New(rfdscount);
705 if (!rfdslist)
706 if (!rfdslist)
706 goto bail;
707 goto bail;
707 for (i = 0; i < rfdscount; i++) {
708 for (i = 0; i < rfdscount; i++) {
708 PyObject *obj = PyInt_FromLong(rfds[i]);
709 PyObject *obj = PyInt_FromLong(rfds[i]);
709 if (!obj)
710 if (!obj)
710 goto bail;
711 goto bail;
711 PyList_SET_ITEM(rfdslist, i, obj);
712 PyList_SET_ITEM(rfdslist, i, obj);
712 }
713 }
713 return rfdslist;
714 return rfdslist;
714
715
715 bail:
716 bail:
716 Py_XDECREF(rfdslist);
717 Py_XDECREF(rfdslist);
717 return NULL;
718 return NULL;
718 }
719 }
719
720
720 #endif /* CMSG_LEN */
721 #endif /* CMSG_LEN */
721 #endif /* ndef _WIN32 */
722 #endif /* ndef _WIN32 */
722
723
723 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
724 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
724 {
725 {
725 PyObject *statobj = NULL; /* initialize - optional arg */
726 PyObject *statobj = NULL; /* initialize - optional arg */
726 PyObject *skipobj = NULL; /* initialize - optional arg */
727 PyObject *skipobj = NULL; /* initialize - optional arg */
727 char *path, *skip = NULL;
728 char *path, *skip = NULL;
728 int wantstat, plen;
729 int wantstat, plen;
729
730
730 static char *kwlist[] = {"path", "stat", "skip", NULL};
731 static char *kwlist[] = {"path", "stat", "skip", NULL};
731
732
732 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
733 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
733 kwlist, &path, &plen, &statobj, &skipobj))
734 kwlist, &path, &plen, &statobj, &skipobj))
734 return NULL;
735 return NULL;
735
736
736 wantstat = statobj && PyObject_IsTrue(statobj);
737 wantstat = statobj && PyObject_IsTrue(statobj);
737
738
738 if (skipobj && skipobj != Py_None) {
739 if (skipobj && skipobj != Py_None) {
739 skip = PyBytes_AsString(skipobj);
740 skip = PyBytes_AsString(skipobj);
740 if (!skip)
741 if (!skip)
741 return NULL;
742 return NULL;
742 }
743 }
743
744
744 return _listdir(path, plen, wantstat, skip);
745 return _listdir(path, plen, wantstat, skip);
745 }
746 }
746
747
747 #ifdef _WIN32
748 #ifdef _WIN32
748 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
749 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
749 {
750 {
750 static char *kwlist[] = {"name", "mode", "buffering", NULL};
751 static char *kwlist[] = {"name", "mode", "buffering", NULL};
751 PyObject *file_obj = NULL;
752 PyObject *file_obj = NULL;
752 char *name = NULL;
753 char *name = NULL;
753 char *mode = "rb";
754 char *mode = "rb";
754 DWORD access = 0;
755 DWORD access = 0;
755 DWORD creation;
756 DWORD creation;
756 HANDLE handle;
757 HANDLE handle;
757 int fd, flags = 0;
758 int fd, flags = 0;
758 int bufsize = -1;
759 int bufsize = -1;
759 char m0, m1, m2;
760 char m0, m1, m2;
760 char fpmode[4];
761 char fpmode[4];
761 int fppos = 0;
762 int fppos = 0;
762 int plus;
763 int plus;
763 FILE *fp;
764 FILE *fp;
764
765
765 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
766 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
766 Py_FileSystemDefaultEncoding,
767 Py_FileSystemDefaultEncoding,
767 &name, &mode, &bufsize))
768 &name, &mode, &bufsize))
768 return NULL;
769 return NULL;
769
770
770 m0 = mode[0];
771 m0 = mode[0];
771 m1 = m0 ? mode[1] : '\0';
772 m1 = m0 ? mode[1] : '\0';
772 m2 = m1 ? mode[2] : '\0';
773 m2 = m1 ? mode[2] : '\0';
773 plus = m1 == '+' || m2 == '+';
774 plus = m1 == '+' || m2 == '+';
774
775
775 fpmode[fppos++] = m0;
776 fpmode[fppos++] = m0;
776 if (m1 == 'b' || m2 == 'b') {
777 if (m1 == 'b' || m2 == 'b') {
777 flags = _O_BINARY;
778 flags = _O_BINARY;
778 fpmode[fppos++] = 'b';
779 fpmode[fppos++] = 'b';
779 }
780 }
780 else
781 else
781 flags = _O_TEXT;
782 flags = _O_TEXT;
782 if (m0 == 'r' && !plus) {
783 if (m0 == 'r' && !plus) {
783 flags |= _O_RDONLY;
784 flags |= _O_RDONLY;
784 access = GENERIC_READ;
785 access = GENERIC_READ;
785 } else {
786 } else {
786 /*
787 /*
787 work around http://support.microsoft.com/kb/899149 and
788 work around http://support.microsoft.com/kb/899149 and
788 set _O_RDWR for 'w' and 'a', even if mode has no '+'
789 set _O_RDWR for 'w' and 'a', even if mode has no '+'
789 */
790 */
790 flags |= _O_RDWR;
791 flags |= _O_RDWR;
791 access = GENERIC_READ | GENERIC_WRITE;
792 access = GENERIC_READ | GENERIC_WRITE;
792 fpmode[fppos++] = '+';
793 fpmode[fppos++] = '+';
793 }
794 }
794 fpmode[fppos++] = '\0';
795 fpmode[fppos++] = '\0';
795
796
796 switch (m0) {
797 switch (m0) {
797 case 'r':
798 case 'r':
798 creation = OPEN_EXISTING;
799 creation = OPEN_EXISTING;
799 break;
800 break;
800 case 'w':
801 case 'w':
801 creation = CREATE_ALWAYS;
802 creation = CREATE_ALWAYS;
802 break;
803 break;
803 case 'a':
804 case 'a':
804 creation = OPEN_ALWAYS;
805 creation = OPEN_ALWAYS;
805 flags |= _O_APPEND;
806 flags |= _O_APPEND;
806 break;
807 break;
807 default:
808 default:
808 PyErr_Format(PyExc_ValueError,
809 PyErr_Format(PyExc_ValueError,
809 "mode string must begin with one of 'r', 'w', "
810 "mode string must begin with one of 'r', 'w', "
810 "or 'a', not '%c'", m0);
811 "or 'a', not '%c'", m0);
811 goto bail;
812 goto bail;
812 }
813 }
813
814
814 handle = CreateFile(name, access,
815 handle = CreateFile(name, access,
815 FILE_SHARE_READ | FILE_SHARE_WRITE |
816 FILE_SHARE_READ | FILE_SHARE_WRITE |
816 FILE_SHARE_DELETE,
817 FILE_SHARE_DELETE,
817 NULL,
818 NULL,
818 creation,
819 creation,
819 FILE_ATTRIBUTE_NORMAL,
820 FILE_ATTRIBUTE_NORMAL,
820 0);
821 0);
821
822
822 if (handle == INVALID_HANDLE_VALUE) {
823 if (handle == INVALID_HANDLE_VALUE) {
823 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
824 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
824 goto bail;
825 goto bail;
825 }
826 }
826
827
827 fd = _open_osfhandle((intptr_t)handle, flags);
828 fd = _open_osfhandle((intptr_t)handle, flags);
828
829
829 if (fd == -1) {
830 if (fd == -1) {
830 CloseHandle(handle);
831 CloseHandle(handle);
831 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
832 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
832 goto bail;
833 goto bail;
833 }
834 }
834 #ifndef IS_PY3K
835 #ifndef IS_PY3K
835 fp = _fdopen(fd, fpmode);
836 fp = _fdopen(fd, fpmode);
836 if (fp == NULL) {
837 if (fp == NULL) {
837 _close(fd);
838 _close(fd);
838 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
839 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
839 goto bail;
840 goto bail;
840 }
841 }
841
842
842 file_obj = PyFile_FromFile(fp, name, mode, fclose);
843 file_obj = PyFile_FromFile(fp, name, mode, fclose);
843 if (file_obj == NULL) {
844 if (file_obj == NULL) {
844 fclose(fp);
845 fclose(fp);
845 goto bail;
846 goto bail;
846 }
847 }
847
848
848 PyFile_SetBufSize(file_obj, bufsize);
849 PyFile_SetBufSize(file_obj, bufsize);
849 #else
850 #else
850 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
851 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
851 if (file_obj == NULL)
852 if (file_obj == NULL)
852 goto bail;
853 goto bail;
853 #endif
854 #endif
854 bail:
855 bail:
855 PyMem_Free(name);
856 PyMem_Free(name);
856 return file_obj;
857 return file_obj;
857 }
858 }
858 #endif
859 #endif
859
860
860 #ifdef __APPLE__
861 #ifdef __APPLE__
861 #include <ApplicationServices/ApplicationServices.h>
862 #include <ApplicationServices/ApplicationServices.h>
862
863
863 static PyObject *isgui(PyObject *self)
864 static PyObject *isgui(PyObject *self)
864 {
865 {
865 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
866 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
866
867
867 if (dict != NULL) {
868 if (dict != NULL) {
868 CFRelease(dict);
869 CFRelease(dict);
869 Py_RETURN_TRUE;
870 Py_RETURN_TRUE;
870 } else {
871 } else {
871 Py_RETURN_FALSE;
872 Py_RETURN_FALSE;
872 }
873 }
873 }
874 }
874 #endif
875 #endif
875
876
876 static char osutil_doc[] = "Native operating system services.";
877 static char osutil_doc[] = "Native operating system services.";
877
878
878 static PyMethodDef methods[] = {
879 static PyMethodDef methods[] = {
879 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
880 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
880 "list a directory\n"},
881 "list a directory\n"},
881 #ifdef _WIN32
882 #ifdef _WIN32
882 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
883 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
883 "Open a file with POSIX-like semantics.\n"
884 "Open a file with POSIX-like semantics.\n"
884 "On error, this function may raise either a WindowsError or an IOError."},
885 "On error, this function may raise either a WindowsError or an IOError."},
885 #else
886 #else
886 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
887 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
887 "stat a series of files or symlinks\n"
888 "stat a series of files or symlinks\n"
888 "Returns None for non-existent entries and entries of other types.\n"},
889 "Returns None for non-existent entries and entries of other types.\n"},
889 #ifdef CMSG_LEN
890 #ifdef CMSG_LEN
890 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
891 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
891 "receive list of file descriptors via socket\n"},
892 "receive list of file descriptors via socket\n"},
892 #endif
893 #endif
893 #endif
894 #endif
894 #ifdef __APPLE__
895 #ifdef __APPLE__
895 {
896 {
896 "isgui", (PyCFunction)isgui, METH_NOARGS,
897 "isgui", (PyCFunction)isgui, METH_NOARGS,
897 "Is a CoreGraphics session available?"
898 "Is a CoreGraphics session available?"
898 },
899 },
899 #endif
900 #endif
900 {NULL, NULL}
901 {NULL, NULL}
901 };
902 };
902
903
903 #ifdef IS_PY3K
904 #ifdef IS_PY3K
904 static struct PyModuleDef osutil_module = {
905 static struct PyModuleDef osutil_module = {
905 PyModuleDef_HEAD_INIT,
906 PyModuleDef_HEAD_INIT,
906 "osutil",
907 "osutil",
907 osutil_doc,
908 osutil_doc,
908 -1,
909 -1,
909 methods
910 methods
910 };
911 };
911
912
912 PyMODINIT_FUNC PyInit_osutil(void)
913 PyMODINIT_FUNC PyInit_osutil(void)
913 {
914 {
914 if (PyType_Ready(&listdir_stat_type) < 0)
915 if (PyType_Ready(&listdir_stat_type) < 0)
915 return NULL;
916 return NULL;
916
917
917 return PyModule_Create(&osutil_module);
918 return PyModule_Create(&osutil_module);
918 }
919 }
919 #else
920 #else
920 PyMODINIT_FUNC initosutil(void)
921 PyMODINIT_FUNC initosutil(void)
921 {
922 {
922 if (PyType_Ready(&listdir_stat_type) == -1)
923 if (PyType_Ready(&listdir_stat_type) == -1)
923 return;
924 return;
924
925
925 Py_InitModule3("osutil", methods, osutil_doc);
926 Py_InitModule3("osutil", methods, osutil_doc);
926 }
927 }
927 #endif
928 #endif
General Comments 0
You need to be logged in to leave comments. Login now