##// END OF EJS Templates
mac: ignore resource fork when checking file sizes...
Matt Mackall -
r27877:f6d1e92f default
parent child Browse files
Show More
@@ -1,920 +1,920
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 <stdlib.h>
15 15 #include <string.h>
16 16 #include <errno.h>
17 17
18 18 #ifdef _WIN32
19 19 #include <windows.h>
20 20 #include <io.h>
21 21 #else
22 22 #include <dirent.h>
23 23 #include <sys/socket.h>
24 24 #include <sys/stat.h>
25 25 #include <sys/types.h>
26 26 #include <unistd.h>
27 27 #endif
28 28
29 29 #ifdef __APPLE__
30 30 #include <sys/attr.h>
31 31 #include <sys/vnode.h>
32 32 #endif
33 33
34 34 #include "util.h"
35 35
36 36 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
37 37 #ifndef PATH_MAX
38 38 #define PATH_MAX 4096
39 39 #endif
40 40
41 41 #ifdef _WIN32
42 42 /*
43 43 stat struct compatible with hg expectations
44 44 Mercurial only uses st_mode, st_size and st_mtime
45 45 the rest is kept to minimize changes between implementations
46 46 */
47 47 struct hg_stat {
48 48 int st_dev;
49 49 int st_mode;
50 50 int st_nlink;
51 51 __int64 st_size;
52 52 int st_mtime;
53 53 int st_ctime;
54 54 };
55 55 struct listdir_stat {
56 56 PyObject_HEAD
57 57 struct hg_stat st;
58 58 };
59 59 #else
60 60 struct listdir_stat {
61 61 PyObject_HEAD
62 62 struct stat st;
63 63 };
64 64 #endif
65 65
66 66 #define listdir_slot(name) \
67 67 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
68 68 { \
69 69 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
70 70 }
71 71
72 72 listdir_slot(st_dev)
73 73 listdir_slot(st_mode)
74 74 listdir_slot(st_nlink)
75 75 #ifdef _WIN32
76 76 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
77 77 {
78 78 return PyLong_FromLongLong(
79 79 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
80 80 }
81 81 #else
82 82 listdir_slot(st_size)
83 83 #endif
84 84 listdir_slot(st_mtime)
85 85 listdir_slot(st_ctime)
86 86
87 87 static struct PyGetSetDef listdir_stat_getsets[] = {
88 88 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
89 89 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
90 90 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
91 91 {"st_size", listdir_stat_st_size, 0, 0, 0},
92 92 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
93 93 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
94 94 {0, 0, 0, 0, 0}
95 95 };
96 96
97 97 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
98 98 {
99 99 return t->tp_alloc(t, 0);
100 100 }
101 101
102 102 static void listdir_stat_dealloc(PyObject *o)
103 103 {
104 104 o->ob_type->tp_free(o);
105 105 }
106 106
107 107 static PyTypeObject listdir_stat_type = {
108 108 PyVarObject_HEAD_INIT(NULL, 0)
109 109 "osutil.stat", /*tp_name*/
110 110 sizeof(struct listdir_stat), /*tp_basicsize*/
111 111 0, /*tp_itemsize*/
112 112 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
113 113 0, /*tp_print*/
114 114 0, /*tp_getattr*/
115 115 0, /*tp_setattr*/
116 116 0, /*tp_compare*/
117 117 0, /*tp_repr*/
118 118 0, /*tp_as_number*/
119 119 0, /*tp_as_sequence*/
120 120 0, /*tp_as_mapping*/
121 121 0, /*tp_hash */
122 122 0, /*tp_call*/
123 123 0, /*tp_str*/
124 124 0, /*tp_getattro*/
125 125 0, /*tp_setattro*/
126 126 0, /*tp_as_buffer*/
127 127 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
128 128 "stat objects", /* tp_doc */
129 129 0, /* tp_traverse */
130 130 0, /* tp_clear */
131 131 0, /* tp_richcompare */
132 132 0, /* tp_weaklistoffset */
133 133 0, /* tp_iter */
134 134 0, /* tp_iternext */
135 135 0, /* tp_methods */
136 136 0, /* tp_members */
137 137 listdir_stat_getsets, /* tp_getset */
138 138 0, /* tp_base */
139 139 0, /* tp_dict */
140 140 0, /* tp_descr_get */
141 141 0, /* tp_descr_set */
142 142 0, /* tp_dictoffset */
143 143 0, /* tp_init */
144 144 0, /* tp_alloc */
145 145 listdir_stat_new, /* tp_new */
146 146 };
147 147
148 148 #ifdef _WIN32
149 149
150 150 static int to_python_time(const FILETIME *tm)
151 151 {
152 152 /* number of seconds between epoch and January 1 1601 */
153 153 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
154 154 /* conversion factor from 100ns to 1s */
155 155 const __int64 a1 = 10000000;
156 156 /* explicit (int) cast to suspend compiler warnings */
157 157 return (int)((((__int64)tm->dwHighDateTime << 32)
158 158 + tm->dwLowDateTime) / a1 - a0);
159 159 }
160 160
161 161 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
162 162 {
163 163 PyObject *py_st;
164 164 struct hg_stat *stp;
165 165
166 166 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
167 167 ? _S_IFDIR : _S_IFREG;
168 168
169 169 if (!wantstat)
170 170 return Py_BuildValue("si", fd->cFileName, kind);
171 171
172 172 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
173 173 if (!py_st)
174 174 return NULL;
175 175
176 176 stp = &((struct listdir_stat *)py_st)->st;
177 177 /*
178 178 use kind as st_mode
179 179 rwx bits on Win32 are meaningless
180 180 and Hg does not use them anyway
181 181 */
182 182 stp->st_mode = kind;
183 183 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
184 184 stp->st_ctime = to_python_time(&fd->ftCreationTime);
185 185 if (kind == _S_IFREG)
186 186 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
187 187 + fd->nFileSizeLow;
188 188 return Py_BuildValue("siN", fd->cFileName,
189 189 kind, py_st);
190 190 }
191 191
192 192 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
193 193 {
194 194 PyObject *rval = NULL; /* initialize - return value */
195 195 PyObject *list;
196 196 HANDLE fh;
197 197 WIN32_FIND_DATAA fd;
198 198 char *pattern;
199 199
200 200 /* build the path + \* pattern string */
201 201 pattern = malloc(plen + 3); /* path + \* + \0 */
202 202 if (!pattern) {
203 203 PyErr_NoMemory();
204 204 goto error_nomem;
205 205 }
206 206 strcpy(pattern, path);
207 207
208 208 if (plen > 0) {
209 209 char c = path[plen-1];
210 210 if (c != ':' && c != '/' && c != '\\')
211 211 pattern[plen++] = '\\';
212 212 }
213 213 strcpy(pattern + plen, "*");
214 214
215 215 fh = FindFirstFileA(pattern, &fd);
216 216 if (fh == INVALID_HANDLE_VALUE) {
217 217 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
218 218 goto error_file;
219 219 }
220 220
221 221 list = PyList_New(0);
222 222 if (!list)
223 223 goto error_list;
224 224
225 225 do {
226 226 PyObject *item;
227 227
228 228 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
229 229 if (!strcmp(fd.cFileName, ".")
230 230 || !strcmp(fd.cFileName, ".."))
231 231 continue;
232 232
233 233 if (skip && !strcmp(fd.cFileName, skip)) {
234 234 rval = PyList_New(0);
235 235 goto error;
236 236 }
237 237 }
238 238
239 239 item = make_item(&fd, wantstat);
240 240 if (!item)
241 241 goto error;
242 242
243 243 if (PyList_Append(list, item)) {
244 244 Py_XDECREF(item);
245 245 goto error;
246 246 }
247 247
248 248 Py_XDECREF(item);
249 249 } while (FindNextFileA(fh, &fd));
250 250
251 251 if (GetLastError() != ERROR_NO_MORE_FILES) {
252 252 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
253 253 goto error;
254 254 }
255 255
256 256 rval = list;
257 257 Py_XINCREF(rval);
258 258 error:
259 259 Py_XDECREF(list);
260 260 error_list:
261 261 FindClose(fh);
262 262 error_file:
263 263 free(pattern);
264 264 error_nomem:
265 265 return rval;
266 266 }
267 267
268 268 #else
269 269
270 270 int entkind(struct dirent *ent)
271 271 {
272 272 #ifdef DT_REG
273 273 switch (ent->d_type) {
274 274 case DT_REG: return S_IFREG;
275 275 case DT_DIR: return S_IFDIR;
276 276 case DT_LNK: return S_IFLNK;
277 277 case DT_BLK: return S_IFBLK;
278 278 case DT_CHR: return S_IFCHR;
279 279 case DT_FIFO: return S_IFIFO;
280 280 case DT_SOCK: return S_IFSOCK;
281 281 }
282 282 #endif
283 283 return -1;
284 284 }
285 285
286 286 static PyObject *makestat(const struct stat *st)
287 287 {
288 288 PyObject *stat;
289 289
290 290 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
291 291 if (stat)
292 292 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
293 293 return stat;
294 294 }
295 295
296 296 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
297 297 char *skip)
298 298 {
299 299 PyObject *list, *elem, *stat = NULL, *ret = NULL;
300 300 char fullpath[PATH_MAX + 10];
301 301 int kind, err;
302 302 struct stat st;
303 303 struct dirent *ent;
304 304 DIR *dir;
305 305 #ifdef AT_SYMLINK_NOFOLLOW
306 306 int dfd = -1;
307 307 #endif
308 308
309 309 if (pathlen >= PATH_MAX) {
310 310 errno = ENAMETOOLONG;
311 311 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
312 312 goto error_value;
313 313 }
314 314 strncpy(fullpath, path, PATH_MAX);
315 315 fullpath[pathlen] = '/';
316 316
317 317 #ifdef AT_SYMLINK_NOFOLLOW
318 318 dfd = open(path, O_RDONLY);
319 319 if (dfd == -1) {
320 320 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
321 321 goto error_value;
322 322 }
323 323 dir = fdopendir(dfd);
324 324 #else
325 325 dir = opendir(path);
326 326 #endif
327 327 if (!dir) {
328 328 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
329 329 goto error_dir;
330 330 }
331 331
332 332 list = PyList_New(0);
333 333 if (!list)
334 334 goto error_list;
335 335
336 336 while ((ent = readdir(dir))) {
337 337 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
338 338 continue;
339 339
340 340 kind = entkind(ent);
341 341 if (kind == -1 || keepstat) {
342 342 #ifdef AT_SYMLINK_NOFOLLOW
343 343 err = fstatat(dfd, ent->d_name, &st,
344 344 AT_SYMLINK_NOFOLLOW);
345 345 #else
346 346 strncpy(fullpath + pathlen + 1, ent->d_name,
347 347 PATH_MAX - pathlen);
348 348 fullpath[PATH_MAX] = '\0';
349 349 err = lstat(fullpath, &st);
350 350 #endif
351 351 if (err == -1) {
352 352 /* race with file deletion? */
353 353 if (errno == ENOENT)
354 354 continue;
355 355 strncpy(fullpath + pathlen + 1, ent->d_name,
356 356 PATH_MAX - pathlen);
357 357 fullpath[PATH_MAX] = 0;
358 358 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
359 359 fullpath);
360 360 goto error;
361 361 }
362 362 kind = st.st_mode & S_IFMT;
363 363 }
364 364
365 365 /* quit early? */
366 366 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
367 367 ret = PyList_New(0);
368 368 goto error;
369 369 }
370 370
371 371 if (keepstat) {
372 372 stat = makestat(&st);
373 373 if (!stat)
374 374 goto error;
375 375 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
376 376 } else
377 377 elem = Py_BuildValue("si", ent->d_name, kind);
378 378 if (!elem)
379 379 goto error;
380 380 stat = NULL;
381 381
382 382 PyList_Append(list, elem);
383 383 Py_DECREF(elem);
384 384 }
385 385
386 386 ret = list;
387 387 Py_INCREF(ret);
388 388
389 389 error:
390 390 Py_DECREF(list);
391 391 Py_XDECREF(stat);
392 392 error_list:
393 393 closedir(dir);
394 394 error_dir:
395 395 #ifdef AT_SYMLINK_NOFOLLOW
396 396 close(dfd);
397 397 #endif
398 398 error_value:
399 399 return ret;
400 400 }
401 401
402 402 #ifdef __APPLE__
403 403
404 404 typedef struct {
405 405 u_int32_t length;
406 406 attrreference_t name;
407 407 fsobj_type_t obj_type;
408 408 struct timespec mtime;
409 409 #if __LITTLE_ENDIAN__
410 410 mode_t access_mask;
411 411 uint16_t padding;
412 412 #else
413 413 uint16_t padding;
414 414 mode_t access_mask;
415 415 #endif
416 416 off_t size;
417 417 } __attribute__((packed)) attrbuf_entry;
418 418
419 419 int attrkind(attrbuf_entry *entry)
420 420 {
421 421 switch (entry->obj_type) {
422 422 case VREG: return S_IFREG;
423 423 case VDIR: return S_IFDIR;
424 424 case VLNK: return S_IFLNK;
425 425 case VBLK: return S_IFBLK;
426 426 case VCHR: return S_IFCHR;
427 427 case VFIFO: return S_IFIFO;
428 428 case VSOCK: return S_IFSOCK;
429 429 }
430 430 return -1;
431 431 }
432 432
433 433 /* get these many entries at a time */
434 434 #define LISTDIR_BATCH_SIZE 50
435 435
436 436 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
437 437 char *skip, bool *fallback)
438 438 {
439 439 PyObject *list, *elem, *stat = NULL, *ret = NULL;
440 440 int kind, err;
441 441 unsigned long index;
442 442 unsigned int count, old_state, new_state;
443 443 bool state_seen = false;
444 444 attrbuf_entry *entry;
445 445 /* from the getattrlist(2) man page: a path can be no longer than
446 446 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
447 447 silently truncate attribute data if attrBufSize is too small." So
448 448 pass in a buffer big enough for the worst case. */
449 449 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
450 450 unsigned int basep_unused;
451 451
452 452 struct stat st;
453 453 int dfd = -1;
454 454
455 455 /* these must match the attrbuf_entry struct, otherwise you'll end up
456 456 with garbage */
457 457 struct attrlist requested_attr = {0};
458 458 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
459 459 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
460 460 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
461 requested_attr.fileattr = ATTR_FILE_TOTALSIZE;
461 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
462 462
463 463 *fallback = false;
464 464
465 465 if (pathlen >= PATH_MAX) {
466 466 errno = ENAMETOOLONG;
467 467 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
468 468 goto error_value;
469 469 }
470 470
471 471 dfd = open(path, O_RDONLY);
472 472 if (dfd == -1) {
473 473 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
474 474 goto error_value;
475 475 }
476 476
477 477 list = PyList_New(0);
478 478 if (!list)
479 479 goto error_dir;
480 480
481 481 do {
482 482 count = LISTDIR_BATCH_SIZE;
483 483 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
484 484 sizeof(attrbuf), &count, &basep_unused,
485 485 &new_state, 0);
486 486 if (err < 0) {
487 487 if (errno == ENOTSUP) {
488 488 /* We're on a filesystem that doesn't support
489 489 getdirentriesattr. Fall back to the
490 490 stat-based implementation. */
491 491 *fallback = true;
492 492 } else
493 493 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
494 494 goto error;
495 495 }
496 496
497 497 if (!state_seen) {
498 498 old_state = new_state;
499 499 state_seen = true;
500 500 } else if (old_state != new_state) {
501 501 /* There's an edge case with getdirentriesattr. Consider
502 502 the following initial list of files:
503 503
504 504 a
505 505 b
506 506 <--
507 507 c
508 508 d
509 509
510 510 If the iteration is paused at the arrow, and b is
511 511 deleted before it is resumed, getdirentriesattr will
512 512 not return d at all! Ordinarily we're expected to
513 513 restart the iteration from the beginning. To avoid
514 514 getting stuck in a retry loop here, fall back to
515 515 stat. */
516 516 *fallback = true;
517 517 goto error;
518 518 }
519 519
520 520 entry = (attrbuf_entry *)attrbuf;
521 521
522 522 for (index = 0; index < count; index++) {
523 523 char *filename = ((char *)&entry->name) +
524 524 entry->name.attr_dataoffset;
525 525
526 526 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
527 527 continue;
528 528
529 529 kind = attrkind(entry);
530 530 if (kind == -1) {
531 531 PyErr_Format(PyExc_OSError,
532 532 "unknown object type %u for file "
533 533 "%s%s!",
534 534 entry->obj_type, path, filename);
535 535 goto error;
536 536 }
537 537
538 538 /* quit early? */
539 539 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
540 540 ret = PyList_New(0);
541 541 goto error;
542 542 }
543 543
544 544 if (keepstat) {
545 545 /* from the getattrlist(2) man page: "Only the
546 546 permission bits ... are valid". */
547 547 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
548 548 st.st_mtime = entry->mtime.tv_sec;
549 549 st.st_size = entry->size;
550 550 stat = makestat(&st);
551 551 if (!stat)
552 552 goto error;
553 553 elem = Py_BuildValue("siN", filename, kind, stat);
554 554 } else
555 555 elem = Py_BuildValue("si", filename, kind);
556 556 if (!elem)
557 557 goto error;
558 558 stat = NULL;
559 559
560 560 PyList_Append(list, elem);
561 561 Py_DECREF(elem);
562 562
563 563 entry = (attrbuf_entry *)((char *)entry + entry->length);
564 564 }
565 565 } while (err == 0);
566 566
567 567 ret = list;
568 568 Py_INCREF(ret);
569 569
570 570 error:
571 571 Py_DECREF(list);
572 572 Py_XDECREF(stat);
573 573 error_dir:
574 574 close(dfd);
575 575 error_value:
576 576 return ret;
577 577 }
578 578
579 579 #endif /* __APPLE__ */
580 580
581 581 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
582 582 {
583 583 #ifdef __APPLE__
584 584 PyObject *ret;
585 585 bool fallback = false;
586 586
587 587 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
588 588 if (ret != NULL || !fallback)
589 589 return ret;
590 590 #endif
591 591 return _listdir_stat(path, pathlen, keepstat, skip);
592 592 }
593 593
594 594 static PyObject *statfiles(PyObject *self, PyObject *args)
595 595 {
596 596 PyObject *names, *stats;
597 597 Py_ssize_t i, count;
598 598
599 599 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
600 600 return NULL;
601 601
602 602 count = PySequence_Length(names);
603 603 if (count == -1) {
604 604 PyErr_SetString(PyExc_TypeError, "not a sequence");
605 605 return NULL;
606 606 }
607 607
608 608 stats = PyList_New(count);
609 609 if (stats == NULL)
610 610 return NULL;
611 611
612 612 for (i = 0; i < count; i++) {
613 613 PyObject *stat, *pypath;
614 614 struct stat st;
615 615 int ret, kind;
616 616 char *path;
617 617
618 618 /* With a large file count or on a slow filesystem,
619 619 don't block signals for long (issue4878). */
620 620 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
621 621 goto bail;
622 622
623 623 pypath = PySequence_GetItem(names, i);
624 624 if (!pypath)
625 625 goto bail;
626 626 path = PyString_AsString(pypath);
627 627 if (path == NULL) {
628 628 Py_DECREF(pypath);
629 629 PyErr_SetString(PyExc_TypeError, "not a string");
630 630 goto bail;
631 631 }
632 632 ret = lstat(path, &st);
633 633 Py_DECREF(pypath);
634 634 kind = st.st_mode & S_IFMT;
635 635 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
636 636 stat = makestat(&st);
637 637 if (stat == NULL)
638 638 goto bail;
639 639 PyList_SET_ITEM(stats, i, stat);
640 640 } else {
641 641 Py_INCREF(Py_None);
642 642 PyList_SET_ITEM(stats, i, Py_None);
643 643 }
644 644 }
645 645
646 646 return stats;
647 647
648 648 bail:
649 649 Py_DECREF(stats);
650 650 return NULL;
651 651 }
652 652
653 653 /*
654 654 * recvfds() simply does not release GIL during blocking io operation because
655 655 * command server is known to be single-threaded.
656 656 */
657 657
658 658 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
659 659 {
660 660 char dummy[1];
661 661 struct iovec iov = {dummy, sizeof(dummy)};
662 662 struct msghdr msgh = {0};
663 663 struct cmsghdr *cmsg;
664 664
665 665 msgh.msg_iov = &iov;
666 666 msgh.msg_iovlen = 1;
667 667 msgh.msg_control = cbuf;
668 668 msgh.msg_controllen = (socklen_t)cbufsize;
669 669 if (recvmsg(sockfd, &msgh, 0) < 0)
670 670 return -1;
671 671
672 672 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
673 673 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
674 674 if (cmsg->cmsg_level != SOL_SOCKET ||
675 675 cmsg->cmsg_type != SCM_RIGHTS)
676 676 continue;
677 677 *rfds = (int *)CMSG_DATA(cmsg);
678 678 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
679 679 }
680 680
681 681 *rfds = cbuf;
682 682 return 0;
683 683 }
684 684
685 685 static PyObject *recvfds(PyObject *self, PyObject *args)
686 686 {
687 687 int sockfd;
688 688 int *rfds = NULL;
689 689 ssize_t rfdscount, i;
690 690 char cbuf[256];
691 691 PyObject *rfdslist = NULL;
692 692
693 693 if (!PyArg_ParseTuple(args, "i", &sockfd))
694 694 return NULL;
695 695
696 696 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
697 697 if (rfdscount < 0)
698 698 return PyErr_SetFromErrno(PyExc_OSError);
699 699
700 700 rfdslist = PyList_New(rfdscount);
701 701 if (!rfdslist)
702 702 goto bail;
703 703 for (i = 0; i < rfdscount; i++) {
704 704 PyObject *obj = PyInt_FromLong(rfds[i]);
705 705 if (!obj)
706 706 goto bail;
707 707 PyList_SET_ITEM(rfdslist, i, obj);
708 708 }
709 709 return rfdslist;
710 710
711 711 bail:
712 712 Py_XDECREF(rfdslist);
713 713 return NULL;
714 714 }
715 715
716 716 #endif /* ndef _WIN32 */
717 717
718 718 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
719 719 {
720 720 PyObject *statobj = NULL; /* initialize - optional arg */
721 721 PyObject *skipobj = NULL; /* initialize - optional arg */
722 722 char *path, *skip = NULL;
723 723 int wantstat, plen;
724 724
725 725 static char *kwlist[] = {"path", "stat", "skip", NULL};
726 726
727 727 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
728 728 kwlist, &path, &plen, &statobj, &skipobj))
729 729 return NULL;
730 730
731 731 wantstat = statobj && PyObject_IsTrue(statobj);
732 732
733 733 if (skipobj && skipobj != Py_None) {
734 734 skip = PyBytes_AsString(skipobj);
735 735 if (!skip)
736 736 return NULL;
737 737 }
738 738
739 739 return _listdir(path, plen, wantstat, skip);
740 740 }
741 741
742 742 #ifdef _WIN32
743 743 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
744 744 {
745 745 static char *kwlist[] = {"name", "mode", "buffering", NULL};
746 746 PyObject *file_obj = NULL;
747 747 char *name = NULL;
748 748 char *mode = "rb";
749 749 DWORD access = 0;
750 750 DWORD creation;
751 751 HANDLE handle;
752 752 int fd, flags = 0;
753 753 int bufsize = -1;
754 754 char m0, m1, m2;
755 755 char fpmode[4];
756 756 int fppos = 0;
757 757 int plus;
758 758 FILE *fp;
759 759
760 760 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
761 761 Py_FileSystemDefaultEncoding,
762 762 &name, &mode, &bufsize))
763 763 return NULL;
764 764
765 765 m0 = mode[0];
766 766 m1 = m0 ? mode[1] : '\0';
767 767 m2 = m1 ? mode[2] : '\0';
768 768 plus = m1 == '+' || m2 == '+';
769 769
770 770 fpmode[fppos++] = m0;
771 771 if (m1 == 'b' || m2 == 'b') {
772 772 flags = _O_BINARY;
773 773 fpmode[fppos++] = 'b';
774 774 }
775 775 else
776 776 flags = _O_TEXT;
777 777 if (m0 == 'r' && !plus) {
778 778 flags |= _O_RDONLY;
779 779 access = GENERIC_READ;
780 780 } else {
781 781 /*
782 782 work around http://support.microsoft.com/kb/899149 and
783 783 set _O_RDWR for 'w' and 'a', even if mode has no '+'
784 784 */
785 785 flags |= _O_RDWR;
786 786 access = GENERIC_READ | GENERIC_WRITE;
787 787 fpmode[fppos++] = '+';
788 788 }
789 789 fpmode[fppos++] = '\0';
790 790
791 791 switch (m0) {
792 792 case 'r':
793 793 creation = OPEN_EXISTING;
794 794 break;
795 795 case 'w':
796 796 creation = CREATE_ALWAYS;
797 797 break;
798 798 case 'a':
799 799 creation = OPEN_ALWAYS;
800 800 flags |= _O_APPEND;
801 801 break;
802 802 default:
803 803 PyErr_Format(PyExc_ValueError,
804 804 "mode string must begin with one of 'r', 'w', "
805 805 "or 'a', not '%c'", m0);
806 806 goto bail;
807 807 }
808 808
809 809 handle = CreateFile(name, access,
810 810 FILE_SHARE_READ | FILE_SHARE_WRITE |
811 811 FILE_SHARE_DELETE,
812 812 NULL,
813 813 creation,
814 814 FILE_ATTRIBUTE_NORMAL,
815 815 0);
816 816
817 817 if (handle == INVALID_HANDLE_VALUE) {
818 818 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
819 819 goto bail;
820 820 }
821 821
822 822 fd = _open_osfhandle((intptr_t)handle, flags);
823 823
824 824 if (fd == -1) {
825 825 CloseHandle(handle);
826 826 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
827 827 goto bail;
828 828 }
829 829 #ifndef IS_PY3K
830 830 fp = _fdopen(fd, fpmode);
831 831 if (fp == NULL) {
832 832 _close(fd);
833 833 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
834 834 goto bail;
835 835 }
836 836
837 837 file_obj = PyFile_FromFile(fp, name, mode, fclose);
838 838 if (file_obj == NULL) {
839 839 fclose(fp);
840 840 goto bail;
841 841 }
842 842
843 843 PyFile_SetBufSize(file_obj, bufsize);
844 844 #else
845 845 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
846 846 if (file_obj == NULL)
847 847 goto bail;
848 848 #endif
849 849 bail:
850 850 PyMem_Free(name);
851 851 return file_obj;
852 852 }
853 853 #endif
854 854
855 855 #ifdef __APPLE__
856 856 #include <ApplicationServices/ApplicationServices.h>
857 857
858 858 static PyObject *isgui(PyObject *self)
859 859 {
860 860 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
861 861
862 862 if (dict != NULL) {
863 863 CFRelease(dict);
864 864 Py_RETURN_TRUE;
865 865 } else {
866 866 Py_RETURN_FALSE;
867 867 }
868 868 }
869 869 #endif
870 870
871 871 static char osutil_doc[] = "Native operating system services.";
872 872
873 873 static PyMethodDef methods[] = {
874 874 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
875 875 "list a directory\n"},
876 876 #ifdef _WIN32
877 877 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
878 878 "Open a file with POSIX-like semantics.\n"
879 879 "On error, this function may raise either a WindowsError or an IOError."},
880 880 #else
881 881 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
882 882 "stat a series of files or symlinks\n"
883 883 "Returns None for non-existent entries and entries of other types.\n"},
884 884 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
885 885 "receive list of file descriptors via socket\n"},
886 886 #endif
887 887 #ifdef __APPLE__
888 888 {
889 889 "isgui", (PyCFunction)isgui, METH_NOARGS,
890 890 "Is a CoreGraphics session available?"
891 891 },
892 892 #endif
893 893 {NULL, NULL}
894 894 };
895 895
896 896 #ifdef IS_PY3K
897 897 static struct PyModuleDef osutil_module = {
898 898 PyModuleDef_HEAD_INIT,
899 899 "osutil",
900 900 osutil_doc,
901 901 -1,
902 902 methods
903 903 };
904 904
905 905 PyMODINIT_FUNC PyInit_osutil(void)
906 906 {
907 907 if (PyType_Ready(&listdir_stat_type) < 0)
908 908 return NULL;
909 909
910 910 return PyModule_Create(&osutil_module);
911 911 }
912 912 #else
913 913 PyMODINIT_FUNC initosutil(void)
914 914 {
915 915 if (PyType_Ready(&listdir_stat_type) == -1)
916 916 return;
917 917
918 918 Py_InitModule3("osutil", methods, osutil_doc);
919 919 }
920 920 #endif
General Comments 0
You need to be logged in to leave comments. Login now