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