##// END OF EJS Templates
osutil: fix tab damage
Bryan O'Sullivan -
r18021:9b05b31b default
parent child Browse files
Show More
@@ -1,590 +1,590 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 #endif /* ndef _WIN32 */
392 #endif /* ndef _WIN32 */
393
393
394 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
394 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
395 {
395 {
396 PyObject *statobj = NULL; /* initialize - optional arg */
396 PyObject *statobj = NULL; /* initialize - optional arg */
397 PyObject *skipobj = NULL; /* initialize - optional arg */
397 PyObject *skipobj = NULL; /* initialize - optional arg */
398 char *path, *skip = NULL;
398 char *path, *skip = NULL;
399 int wantstat, plen;
399 int wantstat, plen;
400
400
401 static char *kwlist[] = {"path", "stat", "skip", NULL};
401 static char *kwlist[] = {"path", "stat", "skip", NULL};
402
402
403 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
403 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
404 kwlist, &path, &plen, &statobj, &skipobj))
404 kwlist, &path, &plen, &statobj, &skipobj))
405 return NULL;
405 return NULL;
406
406
407 wantstat = statobj && PyObject_IsTrue(statobj);
407 wantstat = statobj && PyObject_IsTrue(statobj);
408
408
409 if (skipobj && skipobj != Py_None) {
409 if (skipobj && skipobj != Py_None) {
410 skip = PyBytes_AsString(skipobj);
410 skip = PyBytes_AsString(skipobj);
411 if (!skip)
411 if (!skip)
412 return NULL;
412 return NULL;
413 }
413 }
414
414
415 return _listdir(path, plen, wantstat, skip);
415 return _listdir(path, plen, wantstat, skip);
416 }
416 }
417
417
418 #ifdef _WIN32
418 #ifdef _WIN32
419 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
419 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
420 {
420 {
421 static char *kwlist[] = {"name", "mode", "buffering", NULL};
421 static char *kwlist[] = {"name", "mode", "buffering", NULL};
422 PyObject *file_obj = NULL;
422 PyObject *file_obj = NULL;
423 char *name = NULL;
423 char *name = NULL;
424 char *mode = "rb";
424 char *mode = "rb";
425 DWORD access = 0;
425 DWORD access = 0;
426 DWORD creation;
426 DWORD creation;
427 HANDLE handle;
427 HANDLE handle;
428 int fd, flags = 0;
428 int fd, flags = 0;
429 int bufsize = -1;
429 int bufsize = -1;
430 char m0, m1, m2;
430 char m0, m1, m2;
431 char fpmode[4];
431 char fpmode[4];
432 int fppos = 0;
432 int fppos = 0;
433 int plus;
433 int plus;
434 FILE *fp;
434 FILE *fp;
435
435
436 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
436 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
437 Py_FileSystemDefaultEncoding,
437 Py_FileSystemDefaultEncoding,
438 &name, &mode, &bufsize))
438 &name, &mode, &bufsize))
439 return NULL;
439 return NULL;
440
440
441 m0 = mode[0];
441 m0 = mode[0];
442 m1 = m0 ? mode[1] : '\0';
442 m1 = m0 ? mode[1] : '\0';
443 m2 = m1 ? mode[2] : '\0';
443 m2 = m1 ? mode[2] : '\0';
444 plus = m1 == '+' || m2 == '+';
444 plus = m1 == '+' || m2 == '+';
445
445
446 fpmode[fppos++] = m0;
446 fpmode[fppos++] = m0;
447 if (m1 == 'b' || m2 == 'b') {
447 if (m1 == 'b' || m2 == 'b') {
448 flags = _O_BINARY;
448 flags = _O_BINARY;
449 fpmode[fppos++] = 'b';
449 fpmode[fppos++] = 'b';
450 }
450 }
451 else
451 else
452 flags = _O_TEXT;
452 flags = _O_TEXT;
453 if (m0 == 'r' && !plus) {
453 if (m0 == 'r' && !plus) {
454 flags |= _O_RDONLY;
454 flags |= _O_RDONLY;
455 access = GENERIC_READ;
455 access = GENERIC_READ;
456 } else {
456 } else {
457 /*
457 /*
458 work around http://support.microsoft.com/kb/899149 and
458 work around http://support.microsoft.com/kb/899149 and
459 set _O_RDWR for 'w' and 'a', even if mode has no '+'
459 set _O_RDWR for 'w' and 'a', even if mode has no '+'
460 */
460 */
461 flags |= _O_RDWR;
461 flags |= _O_RDWR;
462 access = GENERIC_READ | GENERIC_WRITE;
462 access = GENERIC_READ | GENERIC_WRITE;
463 fpmode[fppos++] = '+';
463 fpmode[fppos++] = '+';
464 }
464 }
465 fpmode[fppos++] = '\0';
465 fpmode[fppos++] = '\0';
466
466
467 switch (m0) {
467 switch (m0) {
468 case 'r':
468 case 'r':
469 creation = OPEN_EXISTING;
469 creation = OPEN_EXISTING;
470 break;
470 break;
471 case 'w':
471 case 'w':
472 creation = CREATE_ALWAYS;
472 creation = CREATE_ALWAYS;
473 break;
473 break;
474 case 'a':
474 case 'a':
475 creation = OPEN_ALWAYS;
475 creation = OPEN_ALWAYS;
476 flags |= _O_APPEND;
476 flags |= _O_APPEND;
477 break;
477 break;
478 default:
478 default:
479 PyErr_Format(PyExc_ValueError,
479 PyErr_Format(PyExc_ValueError,
480 "mode string must begin with one of 'r', 'w', "
480 "mode string must begin with one of 'r', 'w', "
481 "or 'a', not '%c'", m0);
481 "or 'a', not '%c'", m0);
482 goto bail;
482 goto bail;
483 }
483 }
484
484
485 handle = CreateFile(name, access,
485 handle = CreateFile(name, access,
486 FILE_SHARE_READ | FILE_SHARE_WRITE |
486 FILE_SHARE_READ | FILE_SHARE_WRITE |
487 FILE_SHARE_DELETE,
487 FILE_SHARE_DELETE,
488 NULL,
488 NULL,
489 creation,
489 creation,
490 FILE_ATTRIBUTE_NORMAL,
490 FILE_ATTRIBUTE_NORMAL,
491 0);
491 0);
492
492
493 if (handle == INVALID_HANDLE_VALUE) {
493 if (handle == INVALID_HANDLE_VALUE) {
494 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
494 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
495 goto bail;
495 goto bail;
496 }
496 }
497
497
498 fd = _open_osfhandle((intptr_t)handle, flags);
498 fd = _open_osfhandle((intptr_t)handle, flags);
499
499
500 if (fd == -1) {
500 if (fd == -1) {
501 CloseHandle(handle);
501 CloseHandle(handle);
502 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
502 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
503 goto bail;
503 goto bail;
504 }
504 }
505 #ifndef IS_PY3K
505 #ifndef IS_PY3K
506 fp = _fdopen(fd, fpmode);
506 fp = _fdopen(fd, fpmode);
507 if (fp == NULL) {
507 if (fp == NULL) {
508 _close(fd);
508 _close(fd);
509 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
509 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
510 goto bail;
510 goto bail;
511 }
511 }
512
512
513 file_obj = PyFile_FromFile(fp, name, mode, fclose);
513 file_obj = PyFile_FromFile(fp, name, mode, fclose);
514 if (file_obj == NULL) {
514 if (file_obj == NULL) {
515 fclose(fp);
515 fclose(fp);
516 goto bail;
516 goto bail;
517 }
517 }
518
518
519 PyFile_SetBufSize(file_obj, bufsize);
519 PyFile_SetBufSize(file_obj, bufsize);
520 #else
520 #else
521 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
521 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
522 if (file_obj == NULL)
522 if (file_obj == NULL)
523 goto bail;
523 goto bail;
524 #endif
524 #endif
525 bail:
525 bail:
526 PyMem_Free(name);
526 PyMem_Free(name);
527 return file_obj;
527 return file_obj;
528 }
528 }
529 #endif
529 #endif
530
530
531 #ifdef __APPLE__
531 #ifdef __APPLE__
532 #include <ApplicationServices/ApplicationServices.h>
532 #include <ApplicationServices/ApplicationServices.h>
533
533
534 static PyObject *isgui(PyObject *self)
534 static PyObject *isgui(PyObject *self)
535 {
535 {
536 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
536 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
537
537
538 if (dict != NULL) {
538 if (dict != NULL) {
539 CFRelease(dict);
539 CFRelease(dict);
540 Py_RETURN_TRUE;
540 Py_RETURN_TRUE;
541 } else {
541 } else {
542 Py_RETURN_FALSE;
542 Py_RETURN_FALSE;
543 }
543 }
544 }
544 }
545 #endif
545 #endif
546
546
547 static char osutil_doc[] = "Native operating system services.";
547 static char osutil_doc[] = "Native operating system services.";
548
548
549 static PyMethodDef methods[] = {
549 static PyMethodDef methods[] = {
550 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
550 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
551 "list a directory\n"},
551 "list a directory\n"},
552 #ifdef _WIN32
552 #ifdef _WIN32
553 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
553 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
554 "Open a file with POSIX-like semantics.\n"
554 "Open a file with POSIX-like semantics.\n"
555 "On error, this function may raise either a WindowsError or an IOError."},
555 "On error, this function may raise either a WindowsError or an IOError."},
556 #endif
556 #endif
557 #ifdef __APPLE__
557 #ifdef __APPLE__
558 {
558 {
559 "isgui", (PyCFunction)isgui, METH_NOARGS,
559 "isgui", (PyCFunction)isgui, METH_NOARGS,
560 "Is a CoreGraphics session available?"
560 "Is a CoreGraphics session available?"
561 },
561 },
562 #endif
562 #endif
563 {NULL, NULL}
563 {NULL, NULL}
564 };
564 };
565
565
566 #ifdef IS_PY3K
566 #ifdef IS_PY3K
567 static struct PyModuleDef osutil_module = {
567 static struct PyModuleDef osutil_module = {
568 PyModuleDef_HEAD_INIT,
568 PyModuleDef_HEAD_INIT,
569 "osutil",
569 "osutil",
570 osutil_doc,
570 osutil_doc,
571 -1,
571 -1,
572 methods
572 methods
573 };
573 };
574
574
575 PyMODINIT_FUNC PyInit_osutil(void)
575 PyMODINIT_FUNC PyInit_osutil(void)
576 {
576 {
577 if (PyType_Ready(&listdir_stat_type) < 0)
577 if (PyType_Ready(&listdir_stat_type) < 0)
578 return NULL;
578 return NULL;
579
579
580 return PyModule_Create(&osutil_module);
580 return PyModule_Create(&osutil_module);
581 }
581 }
582 #else
582 #else
583 PyMODINIT_FUNC initosutil(void)
583 PyMODINIT_FUNC initosutil(void)
584 {
584 {
585 if (PyType_Ready(&listdir_stat_type) == -1)
585 if (PyType_Ready(&listdir_stat_type) == -1)
586 return;
586 return;
587
587
588 Py_InitModule3("osutil", methods, osutil_doc);
588 Py_InitModule3("osutil", methods, osutil_doc);
589 }
589 }
590 #endif
590 #endif
General Comments 0
You need to be logged in to leave comments. Login now