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