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