@@ -2066,7 +2066,7 @@ def MkTempFile(data=None,
20662066 Return a file-like handle with consistent behavior on Py2.7 and Py3.x.
20672067
20682068 Storage:
2069- - inmem=True -> BytesIO (bytes) or StringIO (text)
2069+ - inmem=True -> BytesIO (bytes) or StringIO (text), or memfd for bytes if available
20702070 - inmem=False, use_spool=True -> SpooledTemporaryFile (binary), optionally TextIOWrapper for text
20712071 - inmem=False, use_spool=False -> NamedTemporaryFile (binary), optionally TextIOWrapper for text
20722072
@@ -2079,6 +2079,8 @@ def MkTempFile(data=None,
20792079 - On Windows, NamedTemporaryFile(delete=True) keeps the file open and cannot be reopened by other processes.
20802080 Use delete=False if you need to pass the path elsewhere.
20812081 - For text: in-memory StringIO ignores 'newline' (as usual).
2082+ - When available, memfd is used only for inmem=True and isbytes=True, providing an anonymous in-memory
2083+ file descriptor (Linux-only). Text in-memory still uses StringIO to preserve newline semantics.
20822084 """
20832085
20842086 # -- sanitize simple params (avoid None surprises) --
@@ -2112,20 +2114,36 @@ def MkTempFile(data=None,
21122114
21132115 # -------- In-memory --------
21142116 if inmem:
2117+ # Use memfd only for bytes, and only where available (Linux, Python 3.8+)
2118+ if isbytes and hasattr(os, "memfd_create"):
2119+ flags = 0
2120+ # Close-on-exec is almost always what you want for temps
2121+ if hasattr(os, "MFD_CLOEXEC"):
2122+ flags |= os.MFD_CLOEXEC
2123+
2124+ fd = os.memfd_create("MkTempFile", flags)
2125+ # Binary read/write file-like object backed by RAM
2126+ f = os.fdopen(fd, "w+b")
2127+
2128+ if init is not None:
2129+ f.write(init)
2130+ f.seek(0)
2131+ return f
2132+
2133+ # Fallback: pure Python in-memory objects
21152134 if isbytes:
21162135 f = io.BytesIO(init if init is not None else b"")
21172136 else:
21182137 # newline not enforced for StringIO; matches stdlib semantics
21192138 f = io.StringIO(init if init is not None else "")
2120- # already positioned at 0 with provided init; ensure rewind for symmetry
2139+
21212140 f.seek(0)
21222141 return f
21232142
21242143 # Helper: wrap a binary file into a text file with encoding/newline
21252144 def _wrap_text(handle):
21262145 # For both Py2 & Py3, TextIOWrapper gives consistent newline/encoding behavior
21272146 tw = io.TextIOWrapper(handle, encoding=encoding, newline=newline)
2128- # Position at start; if we wrote initial data below, we will rewind after writing
21292147 return tw
21302148
21312149 # -------- Spooled (RAM then disk) --------
@@ -2134,6 +2152,7 @@ def _wrap_text(handle):
21342152 bin_mode = "w+b" # read/write, binary
21352153 b = tempfile.SpooledTemporaryFile(max_size=spool_max, mode=bin_mode, dir=spool_dir)
21362154 f = b if isbytes else _wrap_text(b)
2155+
21372156 if init is not None:
21382157 f.write(init)
21392158 f.seek(0)
@@ -5946,14 +5965,14 @@ def AppendFilesWithContent(infiles, fp, dirlistfromtxt=False, extradata=[], json
59465965 if(hasattr(fstatinfo, "st_flags")):
59475966 fflags = format(int(fstatinfo.st_flags), 'x').lower()
59485967 ftype = 0
5949- if(hasattr(os.path, "isjunction") and os.path.isjunction(fname)):
5968+ if(not followlink and hasattr(os.path, "isjunction") and os.path.isjunction(fname)):
59505969 ftype = 13
59515970 elif(stat.S_ISREG(fpremode)):
59525971 if(hasattr(fstatinfo, "st_blocks") and fstatinfo.st_size > 0 and fstatinfo.st_blocks * 512 < fstatinfo.st_size):
59535972 ftype = 12
59545973 else:
59555974 ftype = 0
5956- elif(stat.S_ISLNK(fpremode)):
5975+ elif(not followlink and stat.S_ISLNK(fpremode)):
59575976 ftype = 2
59585977 elif(stat.S_ISCHR(fpremode)):
59595978 ftype = 3
0 commit comments