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