##// END OF EJS Templates
Merge with crew-stable
Brendan Cully -
r8723:b4a1b901 merge default
parent child Browse files
Show More
@@ -1,529 +1,534 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
15
16 #ifdef _WIN32
16 #ifdef _WIN32
17 # include <windows.h>
17 # include <windows.h>
18 # include <io.h>
18 # include <io.h>
19 #else
19 #else
20 # include <dirent.h>
20 # include <dirent.h>
21 # include <sys/stat.h>
21 # include <sys/stat.h>
22 # include <sys/types.h>
22 # include <sys/types.h>
23 # include <unistd.h>
23 # include <unistd.h>
24 #endif
24 #endif
25
25
26 // some platforms lack the PATH_MAX definition (eg. GNU/Hurd)
27 #ifndef PATH_MAX
28 #define PATH_MAX 4096
29 #endif
30
26 #ifdef _WIN32
31 #ifdef _WIN32
27 /*
32 /*
28 stat struct compatible with hg expectations
33 stat struct compatible with hg expectations
29 Mercurial only uses st_mode, st_size and st_mtime
34 Mercurial only uses st_mode, st_size and st_mtime
30 the rest is kept to minimize changes between implementations
35 the rest is kept to minimize changes between implementations
31 */
36 */
32 struct hg_stat {
37 struct hg_stat {
33 int st_dev;
38 int st_dev;
34 int st_mode;
39 int st_mode;
35 int st_nlink;
40 int st_nlink;
36 __int64 st_size;
41 __int64 st_size;
37 int st_mtime;
42 int st_mtime;
38 int st_ctime;
43 int st_ctime;
39 };
44 };
40 struct listdir_stat {
45 struct listdir_stat {
41 PyObject_HEAD
46 PyObject_HEAD
42 struct hg_stat st;
47 struct hg_stat st;
43 };
48 };
44 #else
49 #else
45 struct listdir_stat {
50 struct listdir_stat {
46 PyObject_HEAD
51 PyObject_HEAD
47 struct stat st;
52 struct stat st;
48 };
53 };
49 #endif
54 #endif
50
55
51 #define listdir_slot(name) \
56 #define listdir_slot(name) \
52 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
57 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
53 { \
58 { \
54 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
59 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
55 }
60 }
56
61
57 listdir_slot(st_dev)
62 listdir_slot(st_dev)
58 listdir_slot(st_mode)
63 listdir_slot(st_mode)
59 listdir_slot(st_nlink)
64 listdir_slot(st_nlink)
60 #ifdef _WIN32
65 #ifdef _WIN32
61 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
66 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
62 {
67 {
63 return PyLong_FromLongLong(
68 return PyLong_FromLongLong(
64 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
69 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
65 }
70 }
66 #else
71 #else
67 listdir_slot(st_size)
72 listdir_slot(st_size)
68 #endif
73 #endif
69 listdir_slot(st_mtime)
74 listdir_slot(st_mtime)
70 listdir_slot(st_ctime)
75 listdir_slot(st_ctime)
71
76
72 static struct PyGetSetDef listdir_stat_getsets[] = {
77 static struct PyGetSetDef listdir_stat_getsets[] = {
73 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
78 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
74 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
79 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
75 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
80 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
76 {"st_size", listdir_stat_st_size, 0, 0, 0},
81 {"st_size", listdir_stat_st_size, 0, 0, 0},
77 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
82 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
78 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
83 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
79 {0, 0, 0, 0, 0}
84 {0, 0, 0, 0, 0}
80 };
85 };
81
86
82 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
87 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
83 {
88 {
84 return t->tp_alloc(t, 0);
89 return t->tp_alloc(t, 0);
85 }
90 }
86
91
87 static void listdir_stat_dealloc(PyObject *o)
92 static void listdir_stat_dealloc(PyObject *o)
88 {
93 {
89 o->ob_type->tp_free(o);
94 o->ob_type->tp_free(o);
90 }
95 }
91
96
92 static PyTypeObject listdir_stat_type = {
97 static PyTypeObject listdir_stat_type = {
93 PyObject_HEAD_INIT(NULL)
98 PyObject_HEAD_INIT(NULL)
94 0, /*ob_size*/
99 0, /*ob_size*/
95 "osutil.stat", /*tp_name*/
100 "osutil.stat", /*tp_name*/
96 sizeof(struct listdir_stat), /*tp_basicsize*/
101 sizeof(struct listdir_stat), /*tp_basicsize*/
97 0, /*tp_itemsize*/
102 0, /*tp_itemsize*/
98 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
103 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
99 0, /*tp_print*/
104 0, /*tp_print*/
100 0, /*tp_getattr*/
105 0, /*tp_getattr*/
101 0, /*tp_setattr*/
106 0, /*tp_setattr*/
102 0, /*tp_compare*/
107 0, /*tp_compare*/
103 0, /*tp_repr*/
108 0, /*tp_repr*/
104 0, /*tp_as_number*/
109 0, /*tp_as_number*/
105 0, /*tp_as_sequence*/
110 0, /*tp_as_sequence*/
106 0, /*tp_as_mapping*/
111 0, /*tp_as_mapping*/
107 0, /*tp_hash */
112 0, /*tp_hash */
108 0, /*tp_call*/
113 0, /*tp_call*/
109 0, /*tp_str*/
114 0, /*tp_str*/
110 0, /*tp_getattro*/
115 0, /*tp_getattro*/
111 0, /*tp_setattro*/
116 0, /*tp_setattro*/
112 0, /*tp_as_buffer*/
117 0, /*tp_as_buffer*/
113 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
118 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
114 "stat objects", /* tp_doc */
119 "stat objects", /* tp_doc */
115 0, /* tp_traverse */
120 0, /* tp_traverse */
116 0, /* tp_clear */
121 0, /* tp_clear */
117 0, /* tp_richcompare */
122 0, /* tp_richcompare */
118 0, /* tp_weaklistoffset */
123 0, /* tp_weaklistoffset */
119 0, /* tp_iter */
124 0, /* tp_iter */
120 0, /* tp_iternext */
125 0, /* tp_iternext */
121 0, /* tp_methods */
126 0, /* tp_methods */
122 0, /* tp_members */
127 0, /* tp_members */
123 listdir_stat_getsets, /* tp_getset */
128 listdir_stat_getsets, /* tp_getset */
124 0, /* tp_base */
129 0, /* tp_base */
125 0, /* tp_dict */
130 0, /* tp_dict */
126 0, /* tp_descr_get */
131 0, /* tp_descr_get */
127 0, /* tp_descr_set */
132 0, /* tp_descr_set */
128 0, /* tp_dictoffset */
133 0, /* tp_dictoffset */
129 0, /* tp_init */
134 0, /* tp_init */
130 0, /* tp_alloc */
135 0, /* tp_alloc */
131 listdir_stat_new, /* tp_new */
136 listdir_stat_new, /* tp_new */
132 };
137 };
133
138
134 #ifdef _WIN32
139 #ifdef _WIN32
135
140
136 static int to_python_time(const FILETIME *tm)
141 static int to_python_time(const FILETIME *tm)
137 {
142 {
138 /* number of seconds between epoch and January 1 1601 */
143 /* number of seconds between epoch and January 1 1601 */
139 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
144 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
140 /* conversion factor from 100ns to 1s */
145 /* conversion factor from 100ns to 1s */
141 const __int64 a1 = 10000000;
146 const __int64 a1 = 10000000;
142 /* explicit (int) cast to suspend compiler warnings */
147 /* explicit (int) cast to suspend compiler warnings */
143 return (int)((((__int64)tm->dwHighDateTime << 32)
148 return (int)((((__int64)tm->dwHighDateTime << 32)
144 + tm->dwLowDateTime) / a1 - a0);
149 + tm->dwLowDateTime) / a1 - a0);
145 }
150 }
146
151
147 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
152 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
148 {
153 {
149 PyObject *py_st;
154 PyObject *py_st;
150 struct hg_stat *stp;
155 struct hg_stat *stp;
151
156
152 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
157 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
153 ? _S_IFDIR : _S_IFREG;
158 ? _S_IFDIR : _S_IFREG;
154
159
155 if (!wantstat)
160 if (!wantstat)
156 return Py_BuildValue("si", fd->cFileName, kind);
161 return Py_BuildValue("si", fd->cFileName, kind);
157
162
158 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
163 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
159 if (!py_st)
164 if (!py_st)
160 return NULL;
165 return NULL;
161
166
162 stp = &((struct listdir_stat *)py_st)->st;
167 stp = &((struct listdir_stat *)py_st)->st;
163 /*
168 /*
164 use kind as st_mode
169 use kind as st_mode
165 rwx bits on Win32 are meaningless
170 rwx bits on Win32 are meaningless
166 and Hg does not use them anyway
171 and Hg does not use them anyway
167 */
172 */
168 stp->st_mode = kind;
173 stp->st_mode = kind;
169 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
174 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
170 stp->st_ctime = to_python_time(&fd->ftCreationTime);
175 stp->st_ctime = to_python_time(&fd->ftCreationTime);
171 if (kind == _S_IFREG)
176 if (kind == _S_IFREG)
172 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
177 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
173 + fd->nFileSizeLow;
178 + fd->nFileSizeLow;
174 return Py_BuildValue("siN", fd->cFileName,
179 return Py_BuildValue("siN", fd->cFileName,
175 kind, py_st);
180 kind, py_st);
176 }
181 }
177
182
178 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
183 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
179 {
184 {
180 PyObject *rval = NULL; /* initialize - return value */
185 PyObject *rval = NULL; /* initialize - return value */
181 PyObject *list;
186 PyObject *list;
182 HANDLE fh;
187 HANDLE fh;
183 WIN32_FIND_DATAA fd;
188 WIN32_FIND_DATAA fd;
184 char *pattern;
189 char *pattern;
185
190
186 /* build the path + \* pattern string */
191 /* build the path + \* pattern string */
187 pattern = malloc(plen+3); /* path + \* + \0 */
192 pattern = malloc(plen+3); /* path + \* + \0 */
188 if (!pattern) {
193 if (!pattern) {
189 PyErr_NoMemory();
194 PyErr_NoMemory();
190 goto error_nomem;
195 goto error_nomem;
191 }
196 }
192 strcpy(pattern, path);
197 strcpy(pattern, path);
193
198
194 if (plen > 0) {
199 if (plen > 0) {
195 char c = path[plen-1];
200 char c = path[plen-1];
196 if (c != ':' && c != '/' && c != '\\')
201 if (c != ':' && c != '/' && c != '\\')
197 pattern[plen++] = '\\';
202 pattern[plen++] = '\\';
198 }
203 }
199 strcpy(pattern + plen, "*");
204 strcpy(pattern + plen, "*");
200
205
201 fh = FindFirstFileA(pattern, &fd);
206 fh = FindFirstFileA(pattern, &fd);
202 if (fh == INVALID_HANDLE_VALUE) {
207 if (fh == INVALID_HANDLE_VALUE) {
203 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
208 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
204 goto error_file;
209 goto error_file;
205 }
210 }
206
211
207 list = PyList_New(0);
212 list = PyList_New(0);
208 if (!list)
213 if (!list)
209 goto error_list;
214 goto error_list;
210
215
211 do {
216 do {
212 PyObject *item;
217 PyObject *item;
213
218
214 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
219 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
215 if (!strcmp(fd.cFileName, ".")
220 if (!strcmp(fd.cFileName, ".")
216 || !strcmp(fd.cFileName, ".."))
221 || !strcmp(fd.cFileName, ".."))
217 continue;
222 continue;
218
223
219 if (skip && !strcmp(fd.cFileName, skip)) {
224 if (skip && !strcmp(fd.cFileName, skip)) {
220 rval = PyList_New(0);
225 rval = PyList_New(0);
221 goto error;
226 goto error;
222 }
227 }
223 }
228 }
224
229
225 item = make_item(&fd, wantstat);
230 item = make_item(&fd, wantstat);
226 if (!item)
231 if (!item)
227 goto error;
232 goto error;
228
233
229 if (PyList_Append(list, item)) {
234 if (PyList_Append(list, item)) {
230 Py_XDECREF(item);
235 Py_XDECREF(item);
231 goto error;
236 goto error;
232 }
237 }
233
238
234 Py_XDECREF(item);
239 Py_XDECREF(item);
235 } while (FindNextFileA(fh, &fd));
240 } while (FindNextFileA(fh, &fd));
236
241
237 if (GetLastError() != ERROR_NO_MORE_FILES) {
242 if (GetLastError() != ERROR_NO_MORE_FILES) {
238 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
243 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
239 goto error;
244 goto error;
240 }
245 }
241
246
242 rval = list;
247 rval = list;
243 Py_XINCREF(rval);
248 Py_XINCREF(rval);
244 error:
249 error:
245 Py_XDECREF(list);
250 Py_XDECREF(list);
246 error_list:
251 error_list:
247 FindClose(fh);
252 FindClose(fh);
248 error_file:
253 error_file:
249 free(pattern);
254 free(pattern);
250 error_nomem:
255 error_nomem:
251 return rval;
256 return rval;
252 }
257 }
253
258
254 #else
259 #else
255
260
256 int entkind(struct dirent *ent)
261 int entkind(struct dirent *ent)
257 {
262 {
258 #ifdef DT_REG
263 #ifdef DT_REG
259 switch (ent->d_type) {
264 switch (ent->d_type) {
260 case DT_REG: return S_IFREG;
265 case DT_REG: return S_IFREG;
261 case DT_DIR: return S_IFDIR;
266 case DT_DIR: return S_IFDIR;
262 case DT_LNK: return S_IFLNK;
267 case DT_LNK: return S_IFLNK;
263 case DT_BLK: return S_IFBLK;
268 case DT_BLK: return S_IFBLK;
264 case DT_CHR: return S_IFCHR;
269 case DT_CHR: return S_IFCHR;
265 case DT_FIFO: return S_IFIFO;
270 case DT_FIFO: return S_IFIFO;
266 case DT_SOCK: return S_IFSOCK;
271 case DT_SOCK: return S_IFSOCK;
267 }
272 }
268 #endif
273 #endif
269 return -1;
274 return -1;
270 }
275 }
271
276
272 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
277 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
273 {
278 {
274 PyObject *list, *elem, *stat, *ret = NULL;
279 PyObject *list, *elem, *stat, *ret = NULL;
275 char fullpath[PATH_MAX + 10];
280 char fullpath[PATH_MAX + 10];
276 int kind, err;
281 int kind, err;
277 struct stat st;
282 struct stat st;
278 struct dirent *ent;
283 struct dirent *ent;
279 DIR *dir;
284 DIR *dir;
280 #ifdef AT_SYMLINK_NOFOLLOW
285 #ifdef AT_SYMLINK_NOFOLLOW
281 int dfd = -1;
286 int dfd = -1;
282 #endif
287 #endif
283
288
284 if (pathlen >= PATH_MAX) {
289 if (pathlen >= PATH_MAX) {
285 PyErr_SetString(PyExc_ValueError, "path too long");
290 PyErr_SetString(PyExc_ValueError, "path too long");
286 goto error_value;
291 goto error_value;
287 }
292 }
288 strncpy(fullpath, path, PATH_MAX);
293 strncpy(fullpath, path, PATH_MAX);
289 fullpath[pathlen] = '/';
294 fullpath[pathlen] = '/';
290
295
291 #ifdef AT_SYMLINK_NOFOLLOW
296 #ifdef AT_SYMLINK_NOFOLLOW
292 dfd = open(path, O_RDONLY);
297 dfd = open(path, O_RDONLY);
293 if (dfd == -1) {
298 if (dfd == -1) {
294 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
299 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
295 goto error_value;
300 goto error_value;
296 }
301 }
297 dir = fdopendir(dfd);
302 dir = fdopendir(dfd);
298 #else
303 #else
299 dir = opendir(path);
304 dir = opendir(path);
300 #endif
305 #endif
301 if (!dir) {
306 if (!dir) {
302 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
307 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
303 goto error_dir;
308 goto error_dir;
304 }
309 }
305
310
306 list = PyList_New(0);
311 list = PyList_New(0);
307 if (!list)
312 if (!list)
308 goto error_list;
313 goto error_list;
309
314
310 while ((ent = readdir(dir))) {
315 while ((ent = readdir(dir))) {
311 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
316 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
312 continue;
317 continue;
313
318
314 kind = entkind(ent);
319 kind = entkind(ent);
315 if (kind == -1 || keepstat) {
320 if (kind == -1 || keepstat) {
316 #ifdef AT_SYMLINK_NOFOLLOW
321 #ifdef AT_SYMLINK_NOFOLLOW
317 err = fstatat(dfd, ent->d_name, &st,
322 err = fstatat(dfd, ent->d_name, &st,
318 AT_SYMLINK_NOFOLLOW);
323 AT_SYMLINK_NOFOLLOW);
319 #else
324 #else
320 strncpy(fullpath + pathlen + 1, ent->d_name,
325 strncpy(fullpath + pathlen + 1, ent->d_name,
321 PATH_MAX - pathlen);
326 PATH_MAX - pathlen);
322 fullpath[PATH_MAX] = 0;
327 fullpath[PATH_MAX] = 0;
323 err = lstat(fullpath, &st);
328 err = lstat(fullpath, &st);
324 #endif
329 #endif
325 if (err == -1) {
330 if (err == -1) {
326 strncpy(fullpath + pathlen + 1, ent->d_name,
331 strncpy(fullpath + pathlen + 1, ent->d_name,
327 PATH_MAX - pathlen);
332 PATH_MAX - pathlen);
328 fullpath[PATH_MAX] = 0;
333 fullpath[PATH_MAX] = 0;
329 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
334 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
330 fullpath);
335 fullpath);
331 goto error;
336 goto error;
332 }
337 }
333 kind = st.st_mode & S_IFMT;
338 kind = st.st_mode & S_IFMT;
334 }
339 }
335
340
336 /* quit early? */
341 /* quit early? */
337 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
342 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
338 ret = PyList_New(0);
343 ret = PyList_New(0);
339 goto error;
344 goto error;
340 }
345 }
341
346
342 if (keepstat) {
347 if (keepstat) {
343 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
348 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
344 if (!stat)
349 if (!stat)
345 goto error;
350 goto error;
346 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
351 memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st));
347 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
352 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
348 } else
353 } else
349 elem = Py_BuildValue("si", ent->d_name, kind);
354 elem = Py_BuildValue("si", ent->d_name, kind);
350 if (!elem)
355 if (!elem)
351 goto error;
356 goto error;
352
357
353 PyList_Append(list, elem);
358 PyList_Append(list, elem);
354 Py_DECREF(elem);
359 Py_DECREF(elem);
355 }
360 }
356
361
357 ret = list;
362 ret = list;
358 Py_INCREF(ret);
363 Py_INCREF(ret);
359
364
360 error:
365 error:
361 Py_DECREF(list);
366 Py_DECREF(list);
362 error_list:
367 error_list:
363 closedir(dir);
368 closedir(dir);
364 error_dir:
369 error_dir:
365 #ifdef AT_SYMLINK_NOFOLLOW
370 #ifdef AT_SYMLINK_NOFOLLOW
366 close(dfd);
371 close(dfd);
367 #endif
372 #endif
368 error_value:
373 error_value:
369 return ret;
374 return ret;
370 }
375 }
371
376
372 #endif /* ndef _WIN32 */
377 #endif /* ndef _WIN32 */
373
378
374 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
379 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
375 {
380 {
376 PyObject *statobj = NULL; /* initialize - optional arg */
381 PyObject *statobj = NULL; /* initialize - optional arg */
377 PyObject *skipobj = NULL; /* initialize - optional arg */
382 PyObject *skipobj = NULL; /* initialize - optional arg */
378 char *path, *skip = NULL;
383 char *path, *skip = NULL;
379 int wantstat, plen;
384 int wantstat, plen;
380
385
381 static char *kwlist[] = {"path", "stat", "skip", NULL};
386 static char *kwlist[] = {"path", "stat", "skip", NULL};
382
387
383 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
388 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
384 kwlist, &path, &plen, &statobj, &skipobj))
389 kwlist, &path, &plen, &statobj, &skipobj))
385 return NULL;
390 return NULL;
386
391
387 wantstat = statobj && PyObject_IsTrue(statobj);
392 wantstat = statobj && PyObject_IsTrue(statobj);
388
393
389 if (skipobj && skipobj != Py_None) {
394 if (skipobj && skipobj != Py_None) {
390 skip = PyString_AsString(skipobj);
395 skip = PyString_AsString(skipobj);
391 if (!skip)
396 if (!skip)
392 return NULL;
397 return NULL;
393 }
398 }
394
399
395 return _listdir(path, plen, wantstat, skip);
400 return _listdir(path, plen, wantstat, skip);
396 }
401 }
397
402
398 #ifdef _WIN32
403 #ifdef _WIN32
399 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
404 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
400 {
405 {
401 static char *kwlist[] = {"name", "mode", "buffering", NULL};
406 static char *kwlist[] = {"name", "mode", "buffering", NULL};
402 PyObject *file_obj = NULL;
407 PyObject *file_obj = NULL;
403 char *name = NULL;
408 char *name = NULL;
404 char *mode = "rb";
409 char *mode = "rb";
405 DWORD access = 0;
410 DWORD access = 0;
406 DWORD creation;
411 DWORD creation;
407 HANDLE handle;
412 HANDLE handle;
408 int fd, flags = 0;
413 int fd, flags = 0;
409 int bufsize = -1;
414 int bufsize = -1;
410 char m0, m1, m2;
415 char m0, m1, m2;
411 char fpmode[4];
416 char fpmode[4];
412 int fppos = 0;
417 int fppos = 0;
413 int plus;
418 int plus;
414 FILE *fp;
419 FILE *fp;
415
420
416 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
421 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
417 Py_FileSystemDefaultEncoding,
422 Py_FileSystemDefaultEncoding,
418 &name, &mode, &bufsize))
423 &name, &mode, &bufsize))
419 return NULL;
424 return NULL;
420
425
421 m0 = mode[0];
426 m0 = mode[0];
422 m1 = m0 ? mode[1] : '\0';
427 m1 = m0 ? mode[1] : '\0';
423 m2 = m1 ? mode[2] : '\0';
428 m2 = m1 ? mode[2] : '\0';
424 plus = m1 == '+' || m2 == '+';
429 plus = m1 == '+' || m2 == '+';
425
430
426 fpmode[fppos++] = m0;
431 fpmode[fppos++] = m0;
427 if (m1 == 'b' || m2 == 'b') {
432 if (m1 == 'b' || m2 == 'b') {
428 flags = _O_BINARY;
433 flags = _O_BINARY;
429 fpmode[fppos++] = 'b';
434 fpmode[fppos++] = 'b';
430 }
435 }
431 else
436 else
432 flags = _O_TEXT;
437 flags = _O_TEXT;
433 if (plus) {
438 if (plus) {
434 flags |= _O_RDWR;
439 flags |= _O_RDWR;
435 access = GENERIC_READ | GENERIC_WRITE;
440 access = GENERIC_READ | GENERIC_WRITE;
436 fpmode[fppos++] = '+';
441 fpmode[fppos++] = '+';
437 }
442 }
438 fpmode[fppos++] = '\0';
443 fpmode[fppos++] = '\0';
439
444
440 switch (m0) {
445 switch (m0) {
441 case 'r':
446 case 'r':
442 creation = OPEN_EXISTING;
447 creation = OPEN_EXISTING;
443 if (!plus) {
448 if (!plus) {
444 flags |= _O_RDONLY;
449 flags |= _O_RDONLY;
445 access = GENERIC_READ;
450 access = GENERIC_READ;
446 }
451 }
447 break;
452 break;
448 case 'w':
453 case 'w':
449 creation = CREATE_ALWAYS;
454 creation = CREATE_ALWAYS;
450 if (!plus) {
455 if (!plus) {
451 access = GENERIC_WRITE;
456 access = GENERIC_WRITE;
452 flags |= _O_WRONLY;
457 flags |= _O_WRONLY;
453 }
458 }
454 break;
459 break;
455 case 'a':
460 case 'a':
456 creation = OPEN_ALWAYS;
461 creation = OPEN_ALWAYS;
457 flags |= _O_APPEND;
462 flags |= _O_APPEND;
458 if (!plus) {
463 if (!plus) {
459 flags |= _O_WRONLY;
464 flags |= _O_WRONLY;
460 access = GENERIC_WRITE;
465 access = GENERIC_WRITE;
461 }
466 }
462 break;
467 break;
463 default:
468 default:
464 PyErr_Format(PyExc_ValueError,
469 PyErr_Format(PyExc_ValueError,
465 "mode string must begin with one of 'r', 'w', "
470 "mode string must begin with one of 'r', 'w', "
466 "or 'a', not '%c'", m0);
471 "or 'a', not '%c'", m0);
467 goto bail;
472 goto bail;
468 }
473 }
469
474
470 handle = CreateFile(name, access,
475 handle = CreateFile(name, access,
471 FILE_SHARE_READ | FILE_SHARE_WRITE |
476 FILE_SHARE_READ | FILE_SHARE_WRITE |
472 FILE_SHARE_DELETE,
477 FILE_SHARE_DELETE,
473 NULL,
478 NULL,
474 creation,
479 creation,
475 FILE_ATTRIBUTE_NORMAL,
480 FILE_ATTRIBUTE_NORMAL,
476 0);
481 0);
477
482
478 if (handle == INVALID_HANDLE_VALUE) {
483 if (handle == INVALID_HANDLE_VALUE) {
479 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
484 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
480 goto bail;
485 goto bail;
481 }
486 }
482
487
483 fd = _open_osfhandle((intptr_t) handle, flags);
488 fd = _open_osfhandle((intptr_t) handle, flags);
484 if (fd == -1) {
489 if (fd == -1) {
485 CloseHandle(handle);
490 CloseHandle(handle);
486 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
491 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
487 goto bail;
492 goto bail;
488 }
493 }
489
494
490 fp = _fdopen(fd, fpmode);
495 fp = _fdopen(fd, fpmode);
491 if (fp == NULL) {
496 if (fp == NULL) {
492 _close(fd);
497 _close(fd);
493 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
498 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
494 goto bail;
499 goto bail;
495 }
500 }
496
501
497 file_obj = PyFile_FromFile(fp, name, mode, fclose);
502 file_obj = PyFile_FromFile(fp, name, mode, fclose);
498 if (file_obj == NULL) {
503 if (file_obj == NULL) {
499 fclose(fp);
504 fclose(fp);
500 goto bail;
505 goto bail;
501 }
506 }
502
507
503 PyFile_SetBufSize(file_obj, bufsize);
508 PyFile_SetBufSize(file_obj, bufsize);
504 bail:
509 bail:
505 PyMem_Free(name);
510 PyMem_Free(name);
506 return file_obj;
511 return file_obj;
507 }
512 }
508 #endif
513 #endif
509
514
510 static char osutil_doc[] = "Native operating system services.";
515 static char osutil_doc[] = "Native operating system services.";
511
516
512 static PyMethodDef methods[] = {
517 static PyMethodDef methods[] = {
513 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
518 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
514 "list a directory\n"},
519 "list a directory\n"},
515 #ifdef _WIN32
520 #ifdef _WIN32
516 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
521 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
517 "Open a file with POSIX-like semantics.\n"
522 "Open a file with POSIX-like semantics.\n"
518 "On error, this function may raise either a WindowsError or an IOError."},
523 "On error, this function may raise either a WindowsError or an IOError."},
519 #endif
524 #endif
520 {NULL, NULL}
525 {NULL, NULL}
521 };
526 };
522
527
523 PyMODINIT_FUNC initosutil(void)
528 PyMODINIT_FUNC initosutil(void)
524 {
529 {
525 if (PyType_Ready(&listdir_stat_type) == -1)
530 if (PyType_Ready(&listdir_stat_type) == -1)
526 return;
531 return;
527
532
528 Py_InitModule3("osutil", methods, osutil_doc);
533 Py_InitModule3("osutil", methods, osutil_doc);
529 }
534 }
General Comments 0
You need to be logged in to leave comments. Login now