##// END OF EJS Templates
posix: always seek to EOF when opening a file in append mode...
Augie Fackler -
r42778:97ada9b8 5.0.2 stable
parent child Browse files
Show More
@@ -1,706 +1,718 b''
1 1 # posix.py - Posix utility function implementations for Mercurial
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import fcntl
12 12 import getpass
13 13 import grp
14 14 import os
15 15 import pwd
16 16 import re
17 17 import select
18 18 import stat
19 19 import sys
20 20 import tempfile
21 21 import unicodedata
22 22
23 23 from .i18n import _
24 24 from . import (
25 25 encoding,
26 26 error,
27 27 policy,
28 28 pycompat,
29 29 )
30 30
31 31 osutil = policy.importmod(r'osutil')
32 32
33 posixfile = open
34 33 normpath = os.path.normpath
35 34 samestat = os.path.samestat
36 35 try:
37 36 oslink = os.link
38 37 except AttributeError:
39 38 # Some platforms build Python without os.link on systems that are
40 39 # vaguely unix-like but don't have hardlink support. For those
41 40 # poor souls, just say we tried and that it failed so we fall back
42 41 # to copies.
43 42 def oslink(src, dst):
44 43 raise OSError(errno.EINVAL,
45 44 'hardlinks not supported: %s to %s' % (src, dst))
46 45 readlink = os.readlink
47 46 unlink = os.unlink
48 47 rename = os.rename
49 48 removedirs = os.removedirs
50 49 expandglobs = False
51 50
52 51 umask = os.umask(0)
53 52 os.umask(umask)
54 53
54 if not pycompat.ispy3:
55 def posixfile(name, mode=r'r', buffering=-1):
56 fp = open(name, mode=mode, buffering=buffering)
57 # The position when opening in append mode is implementation defined, so
58 # make it consistent by always seeking to the end.
59 if r'a' in mode:
60 fp.seek(0, os.SEEK_END)
61 return fp
62 else:
63 # The underlying file object seeks as required in Python 3:
64 # https://github.com/python/cpython/blob/v3.7.3/Modules/_io/fileio.c#L474
65 posixfile = open
66
55 67 def split(p):
56 68 '''Same as posixpath.split, but faster
57 69
58 70 >>> import posixpath
59 71 >>> for f in [b'/absolute/path/to/file',
60 72 ... b'relative/path/to/file',
61 73 ... b'file_alone',
62 74 ... b'path/to/directory/',
63 75 ... b'/multiple/path//separators',
64 76 ... b'/file_at_root',
65 77 ... b'///multiple_leading_separators_at_root',
66 78 ... b'']:
67 79 ... assert split(f) == posixpath.split(f), f
68 80 '''
69 81 ht = p.rsplit('/', 1)
70 82 if len(ht) == 1:
71 83 return '', p
72 84 nh = ht[0].rstrip('/')
73 85 if nh:
74 86 return nh, ht[1]
75 87 return ht[0] + '/', ht[1]
76 88
77 89 def openhardlinks():
78 90 '''return true if it is safe to hold open file handles to hardlinks'''
79 91 return True
80 92
81 93 def nlinks(name):
82 94 '''return number of hardlinks for the given file'''
83 95 return os.lstat(name).st_nlink
84 96
85 97 def parsepatchoutput(output_line):
86 98 """parses the output produced by patch and returns the filename"""
87 99 pf = output_line[14:]
88 100 if pycompat.sysplatform == 'OpenVMS':
89 101 if pf[0] == '`':
90 102 pf = pf[1:-1] # Remove the quotes
91 103 else:
92 104 if pf.startswith("'") and pf.endswith("'") and " " in pf:
93 105 pf = pf[1:-1] # Remove the quotes
94 106 return pf
95 107
96 108 def sshargs(sshcmd, host, user, port):
97 109 '''Build argument list for ssh'''
98 110 args = user and ("%s@%s" % (user, host)) or host
99 111 if '-' in args[:1]:
100 112 raise error.Abort(
101 113 _('illegal ssh hostname or username starting with -: %s') % args)
102 114 args = shellquote(args)
103 115 if port:
104 116 args = '-p %s %s' % (shellquote(port), args)
105 117 return args
106 118
107 119 def isexec(f):
108 120 """check whether a file is executable"""
109 121 return (os.lstat(f).st_mode & 0o100 != 0)
110 122
111 123 def setflags(f, l, x):
112 124 st = os.lstat(f)
113 125 s = st.st_mode
114 126 if l:
115 127 if not stat.S_ISLNK(s):
116 128 # switch file to link
117 129 fp = open(f, 'rb')
118 130 data = fp.read()
119 131 fp.close()
120 132 unlink(f)
121 133 try:
122 134 os.symlink(data, f)
123 135 except OSError:
124 136 # failed to make a link, rewrite file
125 137 fp = open(f, "wb")
126 138 fp.write(data)
127 139 fp.close()
128 140 # no chmod needed at this point
129 141 return
130 142 if stat.S_ISLNK(s):
131 143 # switch link to file
132 144 data = os.readlink(f)
133 145 unlink(f)
134 146 fp = open(f, "wb")
135 147 fp.write(data)
136 148 fp.close()
137 149 s = 0o666 & ~umask # avoid restatting for chmod
138 150
139 151 sx = s & 0o100
140 152 if st.st_nlink > 1 and bool(x) != bool(sx):
141 153 # the file is a hardlink, break it
142 154 with open(f, "rb") as fp:
143 155 data = fp.read()
144 156 unlink(f)
145 157 with open(f, "wb") as fp:
146 158 fp.write(data)
147 159
148 160 if x and not sx:
149 161 # Turn on +x for every +r bit when making a file executable
150 162 # and obey umask.
151 163 os.chmod(f, s | (s & 0o444) >> 2 & ~umask)
152 164 elif not x and sx:
153 165 # Turn off all +x bits
154 166 os.chmod(f, s & 0o666)
155 167
156 168 def copymode(src, dst, mode=None, enforcewritable=False):
157 169 '''Copy the file mode from the file at path src to dst.
158 170 If src doesn't exist, we're using mode instead. If mode is None, we're
159 171 using umask.'''
160 172 try:
161 173 st_mode = os.lstat(src).st_mode & 0o777
162 174 except OSError as inst:
163 175 if inst.errno != errno.ENOENT:
164 176 raise
165 177 st_mode = mode
166 178 if st_mode is None:
167 179 st_mode = ~umask
168 180 st_mode &= 0o666
169 181
170 182 new_mode = st_mode
171 183
172 184 if enforcewritable:
173 185 new_mode |= stat.S_IWUSR
174 186
175 187 os.chmod(dst, new_mode)
176 188
177 189 def checkexec(path):
178 190 """
179 191 Check whether the given path is on a filesystem with UNIX-like exec flags
180 192
181 193 Requires a directory (like /foo/.hg)
182 194 """
183 195
184 196 # VFAT on some Linux versions can flip mode but it doesn't persist
185 197 # a FS remount. Frequently we can detect it if files are created
186 198 # with exec bit on.
187 199
188 200 try:
189 201 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
190 202 basedir = os.path.join(path, '.hg')
191 203 cachedir = os.path.join(basedir, 'wcache')
192 204 storedir = os.path.join(basedir, 'store')
193 205 if not os.path.exists(cachedir):
194 206 try:
195 207 # we want to create the 'cache' directory, not the '.hg' one.
196 208 # Automatically creating '.hg' directory could silently spawn
197 209 # invalid Mercurial repositories. That seems like a bad idea.
198 210 os.mkdir(cachedir)
199 211 if os.path.exists(storedir):
200 212 copymode(storedir, cachedir)
201 213 else:
202 214 copymode(basedir, cachedir)
203 215 except (IOError, OSError):
204 216 # we other fallback logic triggers
205 217 pass
206 218 if os.path.isdir(cachedir):
207 219 checkisexec = os.path.join(cachedir, 'checkisexec')
208 220 checknoexec = os.path.join(cachedir, 'checknoexec')
209 221
210 222 try:
211 223 m = os.stat(checkisexec).st_mode
212 224 except OSError as e:
213 225 if e.errno != errno.ENOENT:
214 226 raise
215 227 # checkisexec does not exist - fall through ...
216 228 else:
217 229 # checkisexec exists, check if it actually is exec
218 230 if m & EXECFLAGS != 0:
219 231 # ensure checkisexec exists, check it isn't exec
220 232 try:
221 233 m = os.stat(checknoexec).st_mode
222 234 except OSError as e:
223 235 if e.errno != errno.ENOENT:
224 236 raise
225 237 open(checknoexec, 'w').close() # might fail
226 238 m = os.stat(checknoexec).st_mode
227 239 if m & EXECFLAGS == 0:
228 240 # check-exec is exec and check-no-exec is not exec
229 241 return True
230 242 # checknoexec exists but is exec - delete it
231 243 unlink(checknoexec)
232 244 # checkisexec exists but is not exec - delete it
233 245 unlink(checkisexec)
234 246
235 247 # check using one file, leave it as checkisexec
236 248 checkdir = cachedir
237 249 else:
238 250 # check directly in path and don't leave checkisexec behind
239 251 checkdir = path
240 252 checkisexec = None
241 253 fh, fn = pycompat.mkstemp(dir=checkdir, prefix='hg-checkexec-')
242 254 try:
243 255 os.close(fh)
244 256 m = os.stat(fn).st_mode
245 257 if m & EXECFLAGS == 0:
246 258 os.chmod(fn, m & 0o777 | EXECFLAGS)
247 259 if os.stat(fn).st_mode & EXECFLAGS != 0:
248 260 if checkisexec is not None:
249 261 os.rename(fn, checkisexec)
250 262 fn = None
251 263 return True
252 264 finally:
253 265 if fn is not None:
254 266 unlink(fn)
255 267 except (IOError, OSError):
256 268 # we don't care, the user probably won't be able to commit anyway
257 269 return False
258 270
259 271 def checklink(path):
260 272 """check whether the given path is on a symlink-capable filesystem"""
261 273 # mktemp is not racy because symlink creation will fail if the
262 274 # file already exists
263 275 while True:
264 276 cachedir = os.path.join(path, '.hg', 'wcache')
265 277 checklink = os.path.join(cachedir, 'checklink')
266 278 # try fast path, read only
267 279 if os.path.islink(checklink):
268 280 return True
269 281 if os.path.isdir(cachedir):
270 282 checkdir = cachedir
271 283 else:
272 284 checkdir = path
273 285 cachedir = None
274 286 name = tempfile.mktemp(dir=pycompat.fsdecode(checkdir),
275 287 prefix=r'checklink-')
276 288 name = pycompat.fsencode(name)
277 289 try:
278 290 fd = None
279 291 if cachedir is None:
280 292 fd = pycompat.namedtempfile(dir=checkdir,
281 293 prefix='hg-checklink-')
282 294 target = os.path.basename(fd.name)
283 295 else:
284 296 # create a fixed file to link to; doesn't matter if it
285 297 # already exists.
286 298 target = 'checklink-target'
287 299 try:
288 300 fullpath = os.path.join(cachedir, target)
289 301 open(fullpath, 'w').close()
290 302 except IOError as inst:
291 303 if inst[0] == errno.EACCES:
292 304 # If we can't write to cachedir, just pretend
293 305 # that the fs is readonly and by association
294 306 # that the fs won't support symlinks. This
295 307 # seems like the least dangerous way to avoid
296 308 # data loss.
297 309 return False
298 310 raise
299 311 try:
300 312 os.symlink(target, name)
301 313 if cachedir is None:
302 314 unlink(name)
303 315 else:
304 316 try:
305 317 os.rename(name, checklink)
306 318 except OSError:
307 319 unlink(name)
308 320 return True
309 321 except OSError as inst:
310 322 # link creation might race, try again
311 323 if inst.errno == errno.EEXIST:
312 324 continue
313 325 raise
314 326 finally:
315 327 if fd is not None:
316 328 fd.close()
317 329 except AttributeError:
318 330 return False
319 331 except OSError as inst:
320 332 # sshfs might report failure while successfully creating the link
321 333 if inst.errno == errno.EIO and os.path.exists(name):
322 334 unlink(name)
323 335 return False
324 336
325 337 def checkosfilename(path):
326 338 '''Check that the base-relative path is a valid filename on this platform.
327 339 Returns None if the path is ok, or a UI string describing the problem.'''
328 340 return None # on posix platforms, every path is ok
329 341
330 342 def getfsmountpoint(dirpath):
331 343 '''Get the filesystem mount point from a directory (best-effort)
332 344
333 345 Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
334 346 '''
335 347 return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath)
336 348
337 349 def getfstype(dirpath):
338 350 '''Get the filesystem type name from a directory (best-effort)
339 351
340 352 Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
341 353 '''
342 354 return getattr(osutil, 'getfstype', lambda x: None)(dirpath)
343 355
344 356 def setbinary(fd):
345 357 pass
346 358
347 359 def pconvert(path):
348 360 return path
349 361
350 362 def localpath(path):
351 363 return path
352 364
353 365 def samefile(fpath1, fpath2):
354 366 """Returns whether path1 and path2 refer to the same file. This is only
355 367 guaranteed to work for files, not directories."""
356 368 return os.path.samefile(fpath1, fpath2)
357 369
358 370 def samedevice(fpath1, fpath2):
359 371 """Returns whether fpath1 and fpath2 are on the same device. This is only
360 372 guaranteed to work for files, not directories."""
361 373 st1 = os.lstat(fpath1)
362 374 st2 = os.lstat(fpath2)
363 375 return st1.st_dev == st2.st_dev
364 376
365 377 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
366 378 def normcase(path):
367 379 return path.lower()
368 380
369 381 # what normcase does to ASCII strings
370 382 normcasespec = encoding.normcasespecs.lower
371 383 # fallback normcase function for non-ASCII strings
372 384 normcasefallback = normcase
373 385
374 386 if pycompat.isdarwin:
375 387
376 388 def normcase(path):
377 389 '''
378 390 Normalize a filename for OS X-compatible comparison:
379 391 - escape-encode invalid characters
380 392 - decompose to NFD
381 393 - lowercase
382 394 - omit ignored characters [200c-200f, 202a-202e, 206a-206f,feff]
383 395
384 396 >>> normcase(b'UPPER')
385 397 'upper'
386 398 >>> normcase(b'Caf\\xc3\\xa9')
387 399 'cafe\\xcc\\x81'
388 400 >>> normcase(b'\\xc3\\x89')
389 401 'e\\xcc\\x81'
390 402 >>> normcase(b'\\xb8\\xca\\xc3\\xca\\xbe\\xc8.JPG') # issue3918
391 403 '%b8%ca%c3\\xca\\xbe%c8.jpg'
392 404 '''
393 405
394 406 try:
395 407 return encoding.asciilower(path) # exception for non-ASCII
396 408 except UnicodeDecodeError:
397 409 return normcasefallback(path)
398 410
399 411 normcasespec = encoding.normcasespecs.lower
400 412
401 413 def normcasefallback(path):
402 414 try:
403 415 u = path.decode('utf-8')
404 416 except UnicodeDecodeError:
405 417 # OS X percent-encodes any bytes that aren't valid utf-8
406 418 s = ''
407 419 pos = 0
408 420 l = len(path)
409 421 while pos < l:
410 422 try:
411 423 c = encoding.getutf8char(path, pos)
412 424 pos += len(c)
413 425 except ValueError:
414 426 c = '%%%02X' % ord(path[pos:pos + 1])
415 427 pos += 1
416 428 s += c
417 429
418 430 u = s.decode('utf-8')
419 431
420 432 # Decompose then lowercase (HFS+ technote specifies lower)
421 433 enc = unicodedata.normalize(r'NFD', u).lower().encode('utf-8')
422 434 # drop HFS+ ignored characters
423 435 return encoding.hfsignoreclean(enc)
424 436
425 437 if pycompat.sysplatform == 'cygwin':
426 438 # workaround for cygwin, in which mount point part of path is
427 439 # treated as case sensitive, even though underlying NTFS is case
428 440 # insensitive.
429 441
430 442 # default mount points
431 443 cygwinmountpoints = sorted([
432 444 "/usr/bin",
433 445 "/usr/lib",
434 446 "/cygdrive",
435 447 ], reverse=True)
436 448
437 449 # use upper-ing as normcase as same as NTFS workaround
438 450 def normcase(path):
439 451 pathlen = len(path)
440 452 if (pathlen == 0) or (path[0] != pycompat.ossep):
441 453 # treat as relative
442 454 return encoding.upper(path)
443 455
444 456 # to preserve case of mountpoint part
445 457 for mp in cygwinmountpoints:
446 458 if not path.startswith(mp):
447 459 continue
448 460
449 461 mplen = len(mp)
450 462 if mplen == pathlen: # mount point itself
451 463 return mp
452 464 if path[mplen] == pycompat.ossep:
453 465 return mp + encoding.upper(path[mplen:])
454 466
455 467 return encoding.upper(path)
456 468
457 469 normcasespec = encoding.normcasespecs.other
458 470 normcasefallback = normcase
459 471
460 472 # Cygwin translates native ACLs to POSIX permissions,
461 473 # but these translations are not supported by native
462 474 # tools, so the exec bit tends to be set erroneously.
463 475 # Therefore, disable executable bit access on Cygwin.
464 476 def checkexec(path):
465 477 return False
466 478
467 479 # Similarly, Cygwin's symlink emulation is likely to create
468 480 # problems when Mercurial is used from both Cygwin and native
469 481 # Windows, with other native tools, or on shared volumes
470 482 def checklink(path):
471 483 return False
472 484
473 485 _needsshellquote = None
474 486 def shellquote(s):
475 487 if pycompat.sysplatform == 'OpenVMS':
476 488 return '"%s"' % s
477 489 global _needsshellquote
478 490 if _needsshellquote is None:
479 491 _needsshellquote = re.compile(br'[^a-zA-Z0-9._/+-]').search
480 492 if s and not _needsshellquote(s):
481 493 # "s" shouldn't have to be quoted
482 494 return s
483 495 else:
484 496 return "'%s'" % s.replace("'", "'\\''")
485 497
486 498 def shellsplit(s):
487 499 """Parse a command string in POSIX shell way (best-effort)"""
488 500 return pycompat.shlexsplit(s, posix=True)
489 501
490 502 def quotecommand(cmd):
491 503 return cmd
492 504
493 505 def testpid(pid):
494 506 '''return False if pid dead, True if running or not sure'''
495 507 if pycompat.sysplatform == 'OpenVMS':
496 508 return True
497 509 try:
498 510 os.kill(pid, 0)
499 511 return True
500 512 except OSError as inst:
501 513 return inst.errno != errno.ESRCH
502 514
503 515 def isowner(st):
504 516 """Return True if the stat object st is from the current user."""
505 517 return st.st_uid == os.getuid()
506 518
507 519 def findexe(command):
508 520 '''Find executable for command searching like which does.
509 521 If command is a basename then PATH is searched for command.
510 522 PATH isn't searched if command is an absolute or relative path.
511 523 If command isn't found None is returned.'''
512 524 if pycompat.sysplatform == 'OpenVMS':
513 525 return command
514 526
515 527 def findexisting(executable):
516 528 'Will return executable if existing file'
517 529 if os.path.isfile(executable) and os.access(executable, os.X_OK):
518 530 return executable
519 531 return None
520 532
521 533 if pycompat.ossep in command:
522 534 return findexisting(command)
523 535
524 536 if pycompat.sysplatform == 'plan9':
525 537 return findexisting(os.path.join('/bin', command))
526 538
527 539 for path in encoding.environ.get('PATH', '').split(pycompat.ospathsep):
528 540 executable = findexisting(os.path.join(path, command))
529 541 if executable is not None:
530 542 return executable
531 543 return None
532 544
533 545 def setsignalhandler():
534 546 pass
535 547
536 548 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
537 549
538 550 def statfiles(files):
539 551 '''Stat each file in files. Yield each stat, or None if a file does not
540 552 exist or has a type we don't care about.'''
541 553 lstat = os.lstat
542 554 getkind = stat.S_IFMT
543 555 for nf in files:
544 556 try:
545 557 st = lstat(nf)
546 558 if getkind(st.st_mode) not in _wantedkinds:
547 559 st = None
548 560 except OSError as err:
549 561 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
550 562 raise
551 563 st = None
552 564 yield st
553 565
554 566 def getuser():
555 567 '''return name of current user'''
556 568 return pycompat.fsencode(getpass.getuser())
557 569
558 570 def username(uid=None):
559 571 """Return the name of the user with the given uid.
560 572
561 573 If uid is None, return the name of the current user."""
562 574
563 575 if uid is None:
564 576 uid = os.getuid()
565 577 try:
566 578 return pycompat.fsencode(pwd.getpwuid(uid)[0])
567 579 except KeyError:
568 580 return b'%d' % uid
569 581
570 582 def groupname(gid=None):
571 583 """Return the name of the group with the given gid.
572 584
573 585 If gid is None, return the name of the current group."""
574 586
575 587 if gid is None:
576 588 gid = os.getgid()
577 589 try:
578 590 return pycompat.fsencode(grp.getgrgid(gid)[0])
579 591 except KeyError:
580 592 return pycompat.bytestr(gid)
581 593
582 594 def groupmembers(name):
583 595 """Return the list of members of the group with the given
584 596 name, KeyError if the group does not exist.
585 597 """
586 598 name = pycompat.fsdecode(name)
587 599 return pycompat.rapply(pycompat.fsencode, list(grp.getgrnam(name).gr_mem))
588 600
589 601 def spawndetached(args):
590 602 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
591 603 args[0], args)
592 604
593 605 def gethgcmd():
594 606 return sys.argv[:1]
595 607
596 608 def makedir(path, notindexed):
597 609 os.mkdir(path)
598 610
599 611 def lookupreg(key, name=None, scope=None):
600 612 return None
601 613
602 614 def hidewindow():
603 615 """Hide current shell window.
604 616
605 617 Used to hide the window opened when starting asynchronous
606 618 child process under Windows, unneeded on other systems.
607 619 """
608 620 pass
609 621
610 622 class cachestat(object):
611 623 def __init__(self, path):
612 624 self.stat = os.stat(path)
613 625
614 626 def cacheable(self):
615 627 return bool(self.stat.st_ino)
616 628
617 629 __hash__ = object.__hash__
618 630
619 631 def __eq__(self, other):
620 632 try:
621 633 # Only dev, ino, size, mtime and atime are likely to change. Out
622 634 # of these, we shouldn't compare atime but should compare the
623 635 # rest. However, one of the other fields changing indicates
624 636 # something fishy going on, so return False if anything but atime
625 637 # changes.
626 638 return (self.stat.st_mode == other.stat.st_mode and
627 639 self.stat.st_ino == other.stat.st_ino and
628 640 self.stat.st_dev == other.stat.st_dev and
629 641 self.stat.st_nlink == other.stat.st_nlink and
630 642 self.stat.st_uid == other.stat.st_uid and
631 643 self.stat.st_gid == other.stat.st_gid and
632 644 self.stat.st_size == other.stat.st_size and
633 645 self.stat[stat.ST_MTIME] == other.stat[stat.ST_MTIME] and
634 646 self.stat[stat.ST_CTIME] == other.stat[stat.ST_CTIME])
635 647 except AttributeError:
636 648 return False
637 649
638 650 def __ne__(self, other):
639 651 return not self == other
640 652
641 653 def statislink(st):
642 654 '''check whether a stat result is a symlink'''
643 655 return st and stat.S_ISLNK(st.st_mode)
644 656
645 657 def statisexec(st):
646 658 '''check whether a stat result is an executable file'''
647 659 return st and (st.st_mode & 0o100 != 0)
648 660
649 661 def poll(fds):
650 662 """block until something happens on any file descriptor
651 663
652 664 This is a generic helper that will check for any activity
653 665 (read, write. exception) and return the list of touched files.
654 666
655 667 In unsupported cases, it will raise a NotImplementedError"""
656 668 try:
657 669 while True:
658 670 try:
659 671 res = select.select(fds, fds, fds)
660 672 break
661 673 except select.error as inst:
662 674 if inst.args[0] == errno.EINTR:
663 675 continue
664 676 raise
665 677 except ValueError: # out of range file descriptor
666 678 raise NotImplementedError()
667 679 return sorted(list(set(sum(res, []))))
668 680
669 681 def readpipe(pipe):
670 682 """Read all available data from a pipe."""
671 683 # We can't fstat() a pipe because Linux will always report 0.
672 684 # So, we set the pipe to non-blocking mode and read everything
673 685 # that's available.
674 686 flags = fcntl.fcntl(pipe, fcntl.F_GETFL)
675 687 flags |= os.O_NONBLOCK
676 688 oldflags = fcntl.fcntl(pipe, fcntl.F_SETFL, flags)
677 689
678 690 try:
679 691 chunks = []
680 692 while True:
681 693 try:
682 694 s = pipe.read()
683 695 if not s:
684 696 break
685 697 chunks.append(s)
686 698 except IOError:
687 699 break
688 700
689 701 return ''.join(chunks)
690 702 finally:
691 703 fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags)
692 704
693 705 def bindunixsocket(sock, path):
694 706 """Bind the UNIX domain socket to the specified path"""
695 707 # use relative path instead of full path at bind() if possible, since
696 708 # AF_UNIX path has very small length limit (107 chars) on common
697 709 # platforms (see sys/un.h)
698 710 dirname, basename = os.path.split(path)
699 711 bakwdfd = None
700 712 if dirname:
701 713 bakwdfd = os.open('.', os.O_DIRECTORY)
702 714 os.chdir(dirname)
703 715 sock.bind(basename)
704 716 if bakwdfd:
705 717 os.fchdir(bakwdfd)
706 718 os.close(bakwdfd)
General Comments 0
You need to be logged in to leave comments. Login now