@@ -2074,7 +2074,7 @@ def MkTempFile(data=None,
20742074 Return a file-like handle with consistent behavior on Py2.7 and Py3.x.
20752075
20762076 Storage:
2077- - inmem=True -> BytesIO (bytes) or StringIO (text)
2077+ - inmem=True -> BytesIO (bytes) or StringIO (text), or memfd for bytes if available
20782078 - inmem=False, use_spool=True -> SpooledTemporaryFile (binary), optionally TextIOWrapper for text
20792079 - inmem=False, use_spool=False -> NamedTemporaryFile (binary), optionally TextIOWrapper for text
20802080
@@ -2087,6 +2087,8 @@ def MkTempFile(data=None,
20872087 - On Windows, NamedTemporaryFile(delete=True) keeps the file open and cannot be reopened by other processes.
20882088 Use delete=False if you need to pass the path elsewhere.
20892089 - For text: in-memory StringIO ignores 'newline' (as usual).
2090+ - When available, memfd is used only for inmem=True and isbytes=True, providing an anonymous in-memory
2091+ file descriptor (Linux-only). Text in-memory still uses StringIO to preserve newline semantics.
20902092 """
20912093
20922094 # -- sanitize simple params (avoid None surprises) --
@@ -2120,20 +2122,36 @@ def MkTempFile(data=None,
21202122
21212123 # -------- In-memory --------
21222124 if inmem:
2125+ # Use memfd only for bytes, and only where available (Linux, Python 3.8+)
2126+ if isbytes and hasattr(os, "memfd_create"):
2127+ flags = 0
2128+ # Close-on-exec is almost always what you want for temps
2129+ if hasattr(os, "MFD_CLOEXEC"):
2130+ flags |= os.MFD_CLOEXEC
2131+
2132+ fd = os.memfd_create("MkTempFile", flags)
2133+ # Binary read/write file-like object backed by RAM
2134+ f = os.fdopen(fd, "w+b")
2135+
2136+ if init is not None:
2137+ f.write(init)
2138+ f.seek(0)
2139+ return f
2140+
2141+ # Fallback: pure Python in-memory objects
21232142 if isbytes:
21242143 f = io.BytesIO(init if init is not None else b"")
21252144 else:
21262145 # newline not enforced for StringIO; matches stdlib semantics
21272146 f = io.StringIO(init if init is not None else "")
2128- # already positioned at 0 with provided init; ensure rewind for symmetry
2147+
21292148 f.seek(0)
21302149 return f
21312150
21322151 # Helper: wrap a binary file into a text file with encoding/newline
21332152 def _wrap_text(handle):
21342153 # For both Py2 & Py3, TextIOWrapper gives consistent newline/encoding behavior
21352154 tw = io.TextIOWrapper(handle, encoding=encoding, newline=newline)
2136- # Position at start; if we wrote initial data below, we will rewind after writing
21372155 return tw
21382156
21392157 # -------- Spooled (RAM then disk) --------
@@ -2142,6 +2160,7 @@ def _wrap_text(handle):
21422160 bin_mode = "w+b" # read/write, binary
21432161 b = tempfile.SpooledTemporaryFile(max_size=spool_max, mode=bin_mode, dir=spool_dir)
21442162 f = b if isbytes else _wrap_text(b)
2163+
21452164 if init is not None:
21462165 f.write(init)
21472166 f.seek(0)
@@ -2158,6 +2177,7 @@ def _wrap_text(handle):
21582177 return f
21592178
21602179
2180+
21612181def RemoveWindowsPath(dpath):
21622182 """
21632183 Normalize a path by converting backslashes to forward slashes
@@ -5954,14 +5974,14 @@ def AppendFilesWithContent(infiles, fp, dirlistfromtxt=False, extradata=[], json
59545974 if(hasattr(fstatinfo, "st_flags")):
59555975 fflags = format(int(fstatinfo.st_flags), 'x').lower()
59565976 ftype = 0
5957- if(hasattr(os.path, "isjunction") and os.path.isjunction(fname)):
5977+ if(not followlink and hasattr(os.path, "isjunction") and os.path.isjunction(fname)):
59585978 ftype = 13
59595979 elif(stat.S_ISREG(fpremode)):
59605980 if(hasattr(fstatinfo, "st_blocks") and fstatinfo.st_size > 0 and fstatinfo.st_blocks * 512 < fstatinfo.st_size):
59615981 ftype = 12
59625982 else:
59635983 ftype = 0
5964- elif(stat.S_ISLNK(fpremode)):
5984+ elif(not followlink and stat.S_ISLNK(fpremode)):
59655985 ftype = 2
59665986 elif(stat.S_ISCHR(fpremode)):
59675987 ftype = 3
0 commit comments