Patchwork [3,of,4,V2] procutil: introduce pseudo file object that just raises EBADF

login
register
mail settings
Submitter Yuya Nishihara
Date Dec. 19, 2020, 2:49 a.m.
Message ID <ca07a5705bf78401bf7c.1608346159@lemosa>
Download mbox | patch
Permalink /patch/47938/
State Accepted
Headers show

Comments

Yuya Nishihara - Dec. 19, 2020, 2:49 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1608343818 -32400
#      Sat Dec 19 11:10:18 2020 +0900
# Node ID ca07a5705bf78401bf7c910b9be9a6c5a16ceb64
# Parent  a5fa4ea662d52a6eccb538e79ca36b2a4745a9b8
procutil: introduce pseudo file object that just raises EBADF

This should be safer than closing underlying fd as the fd may be reused.

On Python 2, closed sys.stdin could be redirected to a random file having
fd=0, but we'd be better not copying this behavior.

Only readinto() and write() are implemented according to the following ABC
table. fileno() is not implemented since fd=0/1/2 may be assigned later
to other files.

https://docs.python.org/3/library/io.html#class-hierarchy

Patch

diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py
--- a/mercurial/utils/procutil.py
+++ b/mercurial/utils/procutil.py
@@ -50,6 +50,16 @@  def isatty(fp):
         return False
 
 
+class BadFile(io.RawIOBase):
+    """Dummy file object to simulate closed stdio behavior"""
+
+    def readinto(self, b):
+        raise IOError(errno.EBADF, 'Bad file descriptor')
+
+    def write(self, b):
+        raise IOError(errno.EBADF, 'Bad file descriptor')
+
+
 class LineBufferedWrapper(object):
     def __init__(self, orig):
         self.orig = orig
@@ -129,8 +139,7 @@  if pycompat.ispy3:
     if sys.stdin:
         stdin = sys.stdin.buffer
     else:
-        stdin = open(os.devnull, 'rb')
-        os.close(stdin.fileno())
+        stdin = BadFile()
     stdout = _make_write_all(sys.stdout.buffer)
     stderr = _make_write_all(sys.stderr.buffer)
     if pycompat.iswindows: