##// END OF EJS Templates
osutil: stop using strcpy...
Augie Fackler -
r28593:e60c492a default
parent child Browse files
Show More
@@ -1,927 +1,928
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 strcpy(pattern, path);
206 memcpy(pattern, path, plen);
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 strcpy(pattern + plen, "*");
213 pattern[plen++] = '*';
214 pattern[plen] = '\0';
214 215
215 216 fh = FindFirstFileA(pattern, &fd);
216 217 if (fh == INVALID_HANDLE_VALUE) {
217 218 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
218 219 goto error_file;
219 220 }
220 221
221 222 list = PyList_New(0);
222 223 if (!list)
223 224 goto error_list;
224 225
225 226 do {
226 227 PyObject *item;
227 228
228 229 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
229 230 if (!strcmp(fd.cFileName, ".")
230 231 || !strcmp(fd.cFileName, ".."))
231 232 continue;
232 233
233 234 if (skip && !strcmp(fd.cFileName, skip)) {
234 235 rval = PyList_New(0);
235 236 goto error;
236 237 }
237 238 }
238 239
239 240 item = make_item(&fd, wantstat);
240 241 if (!item)
241 242 goto error;
242 243
243 244 if (PyList_Append(list, item)) {
244 245 Py_XDECREF(item);
245 246 goto error;
246 247 }
247 248
248 249 Py_XDECREF(item);
249 250 } while (FindNextFileA(fh, &fd));
250 251
251 252 if (GetLastError() != ERROR_NO_MORE_FILES) {
252 253 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
253 254 goto error;
254 255 }
255 256
256 257 rval = list;
257 258 Py_XINCREF(rval);
258 259 error:
259 260 Py_XDECREF(list);
260 261 error_list:
261 262 FindClose(fh);
262 263 error_file:
263 264 free(pattern);
264 265 error_nomem:
265 266 return rval;
266 267 }
267 268
268 269 #else
269 270
270 271 int entkind(struct dirent *ent)
271 272 {
272 273 #ifdef DT_REG
273 274 switch (ent->d_type) {
274 275 case DT_REG: return S_IFREG;
275 276 case DT_DIR: return S_IFDIR;
276 277 case DT_LNK: return S_IFLNK;
277 278 case DT_BLK: return S_IFBLK;
278 279 case DT_CHR: return S_IFCHR;
279 280 case DT_FIFO: return S_IFIFO;
280 281 case DT_SOCK: return S_IFSOCK;
281 282 }
282 283 #endif
283 284 return -1;
284 285 }
285 286
286 287 static PyObject *makestat(const struct stat *st)
287 288 {
288 289 PyObject *stat;
289 290
290 291 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
291 292 if (stat)
292 293 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
293 294 return stat;
294 295 }
295 296
296 297 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
297 298 char *skip)
298 299 {
299 300 PyObject *list, *elem, *stat = NULL, *ret = NULL;
300 301 char fullpath[PATH_MAX + 10];
301 302 int kind, err;
302 303 struct stat st;
303 304 struct dirent *ent;
304 305 DIR *dir;
305 306 #ifdef AT_SYMLINK_NOFOLLOW
306 307 int dfd = -1;
307 308 #endif
308 309
309 310 if (pathlen >= PATH_MAX) {
310 311 errno = ENAMETOOLONG;
311 312 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
312 313 goto error_value;
313 314 }
314 315 strncpy(fullpath, path, PATH_MAX);
315 316 fullpath[pathlen] = '/';
316 317
317 318 #ifdef AT_SYMLINK_NOFOLLOW
318 319 dfd = open(path, O_RDONLY);
319 320 if (dfd == -1) {
320 321 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
321 322 goto error_value;
322 323 }
323 324 dir = fdopendir(dfd);
324 325 #else
325 326 dir = opendir(path);
326 327 #endif
327 328 if (!dir) {
328 329 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
329 330 goto error_dir;
330 331 }
331 332
332 333 list = PyList_New(0);
333 334 if (!list)
334 335 goto error_list;
335 336
336 337 while ((ent = readdir(dir))) {
337 338 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
338 339 continue;
339 340
340 341 kind = entkind(ent);
341 342 if (kind == -1 || keepstat) {
342 343 #ifdef AT_SYMLINK_NOFOLLOW
343 344 err = fstatat(dfd, ent->d_name, &st,
344 345 AT_SYMLINK_NOFOLLOW);
345 346 #else
346 347 strncpy(fullpath + pathlen + 1, ent->d_name,
347 348 PATH_MAX - pathlen);
348 349 fullpath[PATH_MAX] = '\0';
349 350 err = lstat(fullpath, &st);
350 351 #endif
351 352 if (err == -1) {
352 353 /* race with file deletion? */
353 354 if (errno == ENOENT)
354 355 continue;
355 356 strncpy(fullpath + pathlen + 1, ent->d_name,
356 357 PATH_MAX - pathlen);
357 358 fullpath[PATH_MAX] = 0;
358 359 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
359 360 fullpath);
360 361 goto error;
361 362 }
362 363 kind = st.st_mode & S_IFMT;
363 364 }
364 365
365 366 /* quit early? */
366 367 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
367 368 ret = PyList_New(0);
368 369 goto error;
369 370 }
370 371
371 372 if (keepstat) {
372 373 stat = makestat(&st);
373 374 if (!stat)
374 375 goto error;
375 376 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
376 377 } else
377 378 elem = Py_BuildValue("si", ent->d_name, kind);
378 379 if (!elem)
379 380 goto error;
380 381 stat = NULL;
381 382
382 383 PyList_Append(list, elem);
383 384 Py_DECREF(elem);
384 385 }
385 386
386 387 ret = list;
387 388 Py_INCREF(ret);
388 389
389 390 error:
390 391 Py_DECREF(list);
391 392 Py_XDECREF(stat);
392 393 error_list:
393 394 closedir(dir);
394 395 error_dir:
395 396 #ifdef AT_SYMLINK_NOFOLLOW
396 397 close(dfd);
397 398 #endif
398 399 error_value:
399 400 return ret;
400 401 }
401 402
402 403 #ifdef __APPLE__
403 404
404 405 typedef struct {
405 406 u_int32_t length;
406 407 attrreference_t name;
407 408 fsobj_type_t obj_type;
408 409 struct timespec mtime;
409 410 #if __LITTLE_ENDIAN__
410 411 mode_t access_mask;
411 412 uint16_t padding;
412 413 #else
413 414 uint16_t padding;
414 415 mode_t access_mask;
415 416 #endif
416 417 off_t size;
417 418 } __attribute__((packed)) attrbuf_entry;
418 419
419 420 int attrkind(attrbuf_entry *entry)
420 421 {
421 422 switch (entry->obj_type) {
422 423 case VREG: return S_IFREG;
423 424 case VDIR: return S_IFDIR;
424 425 case VLNK: return S_IFLNK;
425 426 case VBLK: return S_IFBLK;
426 427 case VCHR: return S_IFCHR;
427 428 case VFIFO: return S_IFIFO;
428 429 case VSOCK: return S_IFSOCK;
429 430 }
430 431 return -1;
431 432 }
432 433
433 434 /* get these many entries at a time */
434 435 #define LISTDIR_BATCH_SIZE 50
435 436
436 437 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
437 438 char *skip, bool *fallback)
438 439 {
439 440 PyObject *list, *elem, *stat = NULL, *ret = NULL;
440 441 int kind, err;
441 442 unsigned long index;
442 443 unsigned int count, old_state, new_state;
443 444 bool state_seen = false;
444 445 attrbuf_entry *entry;
445 446 /* from the getattrlist(2) man page: a path can be no longer than
446 447 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
447 448 silently truncate attribute data if attrBufSize is too small." So
448 449 pass in a buffer big enough for the worst case. */
449 450 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
450 451 unsigned int basep_unused;
451 452
452 453 struct stat st;
453 454 int dfd = -1;
454 455
455 456 /* these must match the attrbuf_entry struct, otherwise you'll end up
456 457 with garbage */
457 458 struct attrlist requested_attr = {0};
458 459 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
459 460 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
460 461 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
461 462 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
462 463
463 464 *fallback = false;
464 465
465 466 if (pathlen >= PATH_MAX) {
466 467 errno = ENAMETOOLONG;
467 468 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
468 469 goto error_value;
469 470 }
470 471
471 472 dfd = open(path, O_RDONLY);
472 473 if (dfd == -1) {
473 474 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
474 475 goto error_value;
475 476 }
476 477
477 478 list = PyList_New(0);
478 479 if (!list)
479 480 goto error_dir;
480 481
481 482 do {
482 483 count = LISTDIR_BATCH_SIZE;
483 484 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
484 485 sizeof(attrbuf), &count, &basep_unused,
485 486 &new_state, 0);
486 487 if (err < 0) {
487 488 if (errno == ENOTSUP) {
488 489 /* We're on a filesystem that doesn't support
489 490 getdirentriesattr. Fall back to the
490 491 stat-based implementation. */
491 492 *fallback = true;
492 493 } else
493 494 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
494 495 goto error;
495 496 }
496 497
497 498 if (!state_seen) {
498 499 old_state = new_state;
499 500 state_seen = true;
500 501 } else if (old_state != new_state) {
501 502 /* There's an edge case with getdirentriesattr. Consider
502 503 the following initial list of files:
503 504
504 505 a
505 506 b
506 507 <--
507 508 c
508 509 d
509 510
510 511 If the iteration is paused at the arrow, and b is
511 512 deleted before it is resumed, getdirentriesattr will
512 513 not return d at all! Ordinarily we're expected to
513 514 restart the iteration from the beginning. To avoid
514 515 getting stuck in a retry loop here, fall back to
515 516 stat. */
516 517 *fallback = true;
517 518 goto error;
518 519 }
519 520
520 521 entry = (attrbuf_entry *)attrbuf;
521 522
522 523 for (index = 0; index < count; index++) {
523 524 char *filename = ((char *)&entry->name) +
524 525 entry->name.attr_dataoffset;
525 526
526 527 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
527 528 continue;
528 529
529 530 kind = attrkind(entry);
530 531 if (kind == -1) {
531 532 PyErr_Format(PyExc_OSError,
532 533 "unknown object type %u for file "
533 534 "%s%s!",
534 535 entry->obj_type, path, filename);
535 536 goto error;
536 537 }
537 538
538 539 /* quit early? */
539 540 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
540 541 ret = PyList_New(0);
541 542 goto error;
542 543 }
543 544
544 545 if (keepstat) {
545 546 /* from the getattrlist(2) man page: "Only the
546 547 permission bits ... are valid". */
547 548 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
548 549 st.st_mtime = entry->mtime.tv_sec;
549 550 st.st_size = entry->size;
550 551 stat = makestat(&st);
551 552 if (!stat)
552 553 goto error;
553 554 elem = Py_BuildValue("siN", filename, kind, stat);
554 555 } else
555 556 elem = Py_BuildValue("si", filename, kind);
556 557 if (!elem)
557 558 goto error;
558 559 stat = NULL;
559 560
560 561 PyList_Append(list, elem);
561 562 Py_DECREF(elem);
562 563
563 564 entry = (attrbuf_entry *)((char *)entry + entry->length);
564 565 }
565 566 } while (err == 0);
566 567
567 568 ret = list;
568 569 Py_INCREF(ret);
569 570
570 571 error:
571 572 Py_DECREF(list);
572 573 Py_XDECREF(stat);
573 574 error_dir:
574 575 close(dfd);
575 576 error_value:
576 577 return ret;
577 578 }
578 579
579 580 #endif /* __APPLE__ */
580 581
581 582 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
582 583 {
583 584 #ifdef __APPLE__
584 585 PyObject *ret;
585 586 bool fallback = false;
586 587
587 588 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
588 589 if (ret != NULL || !fallback)
589 590 return ret;
590 591 #endif
591 592 return _listdir_stat(path, pathlen, keepstat, skip);
592 593 }
593 594
594 595 static PyObject *statfiles(PyObject *self, PyObject *args)
595 596 {
596 597 PyObject *names, *stats;
597 598 Py_ssize_t i, count;
598 599
599 600 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
600 601 return NULL;
601 602
602 603 count = PySequence_Length(names);
603 604 if (count == -1) {
604 605 PyErr_SetString(PyExc_TypeError, "not a sequence");
605 606 return NULL;
606 607 }
607 608
608 609 stats = PyList_New(count);
609 610 if (stats == NULL)
610 611 return NULL;
611 612
612 613 for (i = 0; i < count; i++) {
613 614 PyObject *stat, *pypath;
614 615 struct stat st;
615 616 int ret, kind;
616 617 char *path;
617 618
618 619 /* With a large file count or on a slow filesystem,
619 620 don't block signals for long (issue4878). */
620 621 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
621 622 goto bail;
622 623
623 624 pypath = PySequence_GetItem(names, i);
624 625 if (!pypath)
625 626 goto bail;
626 627 path = PyString_AsString(pypath);
627 628 if (path == NULL) {
628 629 Py_DECREF(pypath);
629 630 PyErr_SetString(PyExc_TypeError, "not a string");
630 631 goto bail;
631 632 }
632 633 ret = lstat(path, &st);
633 634 Py_DECREF(pypath);
634 635 kind = st.st_mode & S_IFMT;
635 636 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
636 637 stat = makestat(&st);
637 638 if (stat == NULL)
638 639 goto bail;
639 640 PyList_SET_ITEM(stats, i, stat);
640 641 } else {
641 642 Py_INCREF(Py_None);
642 643 PyList_SET_ITEM(stats, i, Py_None);
643 644 }
644 645 }
645 646
646 647 return stats;
647 648
648 649 bail:
649 650 Py_DECREF(stats);
650 651 return NULL;
651 652 }
652 653
653 654 /*
654 655 * recvfds() simply does not release GIL during blocking io operation because
655 656 * command server is known to be single-threaded.
656 657 *
657 658 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
658 659 * Currently, recvfds() is not supported on these platforms.
659 660 */
660 661 #ifdef CMSG_LEN
661 662
662 663 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
663 664 {
664 665 char dummy[1];
665 666 struct iovec iov = {dummy, sizeof(dummy)};
666 667 struct msghdr msgh = {0};
667 668 struct cmsghdr *cmsg;
668 669
669 670 msgh.msg_iov = &iov;
670 671 msgh.msg_iovlen = 1;
671 672 msgh.msg_control = cbuf;
672 673 msgh.msg_controllen = (socklen_t)cbufsize;
673 674 if (recvmsg(sockfd, &msgh, 0) < 0)
674 675 return -1;
675 676
676 677 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
677 678 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
678 679 if (cmsg->cmsg_level != SOL_SOCKET ||
679 680 cmsg->cmsg_type != SCM_RIGHTS)
680 681 continue;
681 682 *rfds = (int *)CMSG_DATA(cmsg);
682 683 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
683 684 }
684 685
685 686 *rfds = cbuf;
686 687 return 0;
687 688 }
688 689
689 690 static PyObject *recvfds(PyObject *self, PyObject *args)
690 691 {
691 692 int sockfd;
692 693 int *rfds = NULL;
693 694 ssize_t rfdscount, i;
694 695 char cbuf[256];
695 696 PyObject *rfdslist = NULL;
696 697
697 698 if (!PyArg_ParseTuple(args, "i", &sockfd))
698 699 return NULL;
699 700
700 701 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
701 702 if (rfdscount < 0)
702 703 return PyErr_SetFromErrno(PyExc_OSError);
703 704
704 705 rfdslist = PyList_New(rfdscount);
705 706 if (!rfdslist)
706 707 goto bail;
707 708 for (i = 0; i < rfdscount; i++) {
708 709 PyObject *obj = PyInt_FromLong(rfds[i]);
709 710 if (!obj)
710 711 goto bail;
711 712 PyList_SET_ITEM(rfdslist, i, obj);
712 713 }
713 714 return rfdslist;
714 715
715 716 bail:
716 717 Py_XDECREF(rfdslist);
717 718 return NULL;
718 719 }
719 720
720 721 #endif /* CMSG_LEN */
721 722 #endif /* ndef _WIN32 */
722 723
723 724 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
724 725 {
725 726 PyObject *statobj = NULL; /* initialize - optional arg */
726 727 PyObject *skipobj = NULL; /* initialize - optional arg */
727 728 char *path, *skip = NULL;
728 729 int wantstat, plen;
729 730
730 731 static char *kwlist[] = {"path", "stat", "skip", NULL};
731 732
732 733 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
733 734 kwlist, &path, &plen, &statobj, &skipobj))
734 735 return NULL;
735 736
736 737 wantstat = statobj && PyObject_IsTrue(statobj);
737 738
738 739 if (skipobj && skipobj != Py_None) {
739 740 skip = PyBytes_AsString(skipobj);
740 741 if (!skip)
741 742 return NULL;
742 743 }
743 744
744 745 return _listdir(path, plen, wantstat, skip);
745 746 }
746 747
747 748 #ifdef _WIN32
748 749 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
749 750 {
750 751 static char *kwlist[] = {"name", "mode", "buffering", NULL};
751 752 PyObject *file_obj = NULL;
752 753 char *name = NULL;
753 754 char *mode = "rb";
754 755 DWORD access = 0;
755 756 DWORD creation;
756 757 HANDLE handle;
757 758 int fd, flags = 0;
758 759 int bufsize = -1;
759 760 char m0, m1, m2;
760 761 char fpmode[4];
761 762 int fppos = 0;
762 763 int plus;
763 764 FILE *fp;
764 765
765 766 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
766 767 Py_FileSystemDefaultEncoding,
767 768 &name, &mode, &bufsize))
768 769 return NULL;
769 770
770 771 m0 = mode[0];
771 772 m1 = m0 ? mode[1] : '\0';
772 773 m2 = m1 ? mode[2] : '\0';
773 774 plus = m1 == '+' || m2 == '+';
774 775
775 776 fpmode[fppos++] = m0;
776 777 if (m1 == 'b' || m2 == 'b') {
777 778 flags = _O_BINARY;
778 779 fpmode[fppos++] = 'b';
779 780 }
780 781 else
781 782 flags = _O_TEXT;
782 783 if (m0 == 'r' && !plus) {
783 784 flags |= _O_RDONLY;
784 785 access = GENERIC_READ;
785 786 } else {
786 787 /*
787 788 work around http://support.microsoft.com/kb/899149 and
788 789 set _O_RDWR for 'w' and 'a', even if mode has no '+'
789 790 */
790 791 flags |= _O_RDWR;
791 792 access = GENERIC_READ | GENERIC_WRITE;
792 793 fpmode[fppos++] = '+';
793 794 }
794 795 fpmode[fppos++] = '\0';
795 796
796 797 switch (m0) {
797 798 case 'r':
798 799 creation = OPEN_EXISTING;
799 800 break;
800 801 case 'w':
801 802 creation = CREATE_ALWAYS;
802 803 break;
803 804 case 'a':
804 805 creation = OPEN_ALWAYS;
805 806 flags |= _O_APPEND;
806 807 break;
807 808 default:
808 809 PyErr_Format(PyExc_ValueError,
809 810 "mode string must begin with one of 'r', 'w', "
810 811 "or 'a', not '%c'", m0);
811 812 goto bail;
812 813 }
813 814
814 815 handle = CreateFile(name, access,
815 816 FILE_SHARE_READ | FILE_SHARE_WRITE |
816 817 FILE_SHARE_DELETE,
817 818 NULL,
818 819 creation,
819 820 FILE_ATTRIBUTE_NORMAL,
820 821 0);
821 822
822 823 if (handle == INVALID_HANDLE_VALUE) {
823 824 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
824 825 goto bail;
825 826 }
826 827
827 828 fd = _open_osfhandle((intptr_t)handle, flags);
828 829
829 830 if (fd == -1) {
830 831 CloseHandle(handle);
831 832 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
832 833 goto bail;
833 834 }
834 835 #ifndef IS_PY3K
835 836 fp = _fdopen(fd, fpmode);
836 837 if (fp == NULL) {
837 838 _close(fd);
838 839 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
839 840 goto bail;
840 841 }
841 842
842 843 file_obj = PyFile_FromFile(fp, name, mode, fclose);
843 844 if (file_obj == NULL) {
844 845 fclose(fp);
845 846 goto bail;
846 847 }
847 848
848 849 PyFile_SetBufSize(file_obj, bufsize);
849 850 #else
850 851 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
851 852 if (file_obj == NULL)
852 853 goto bail;
853 854 #endif
854 855 bail:
855 856 PyMem_Free(name);
856 857 return file_obj;
857 858 }
858 859 #endif
859 860
860 861 #ifdef __APPLE__
861 862 #include <ApplicationServices/ApplicationServices.h>
862 863
863 864 static PyObject *isgui(PyObject *self)
864 865 {
865 866 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
866 867
867 868 if (dict != NULL) {
868 869 CFRelease(dict);
869 870 Py_RETURN_TRUE;
870 871 } else {
871 872 Py_RETURN_FALSE;
872 873 }
873 874 }
874 875 #endif
875 876
876 877 static char osutil_doc[] = "Native operating system services.";
877 878
878 879 static PyMethodDef methods[] = {
879 880 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
880 881 "list a directory\n"},
881 882 #ifdef _WIN32
882 883 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
883 884 "Open a file with POSIX-like semantics.\n"
884 885 "On error, this function may raise either a WindowsError or an IOError."},
885 886 #else
886 887 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
887 888 "stat a series of files or symlinks\n"
888 889 "Returns None for non-existent entries and entries of other types.\n"},
889 890 #ifdef CMSG_LEN
890 891 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
891 892 "receive list of file descriptors via socket\n"},
892 893 #endif
893 894 #endif
894 895 #ifdef __APPLE__
895 896 {
896 897 "isgui", (PyCFunction)isgui, METH_NOARGS,
897 898 "Is a CoreGraphics session available?"
898 899 },
899 900 #endif
900 901 {NULL, NULL}
901 902 };
902 903
903 904 #ifdef IS_PY3K
904 905 static struct PyModuleDef osutil_module = {
905 906 PyModuleDef_HEAD_INIT,
906 907 "osutil",
907 908 osutil_doc,
908 909 -1,
909 910 methods
910 911 };
911 912
912 913 PyMODINIT_FUNC PyInit_osutil(void)
913 914 {
914 915 if (PyType_Ready(&listdir_stat_type) < 0)
915 916 return NULL;
916 917
917 918 return PyModule_Create(&osutil_module);
918 919 }
919 920 #else
920 921 PyMODINIT_FUNC initosutil(void)
921 922 {
922 923 if (PyType_Ready(&listdir_stat_type) == -1)
923 924 return;
924 925
925 926 Py_InitModule3("osutil", methods, osutil_doc);
926 927 }
927 928 #endif
General Comments 0
You need to be logged in to leave comments. Login now