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