comparison mercurial/posix.py @ 52364:7ac7d5f20cb0

posix: (mostly) stop using the `pycompat.open()` shim We still need it for the `posixfile` alias, because fixing all of those callers is outside of the scope of this, and spills into the Windows implementation of `posixfile`. But the other direct uses of `open()` can be dropped.
author Matt Harbison <matt_harbison@yahoo.com>
date Wed, 04 Dec 2024 20:52:05 -0500
parents f4733654f144
children dd052842fc8e
comparison
equal deleted inserted replaced
52363:6a8edf9f0a6d 52364:7ac7d5f20cb0
35 Tuple, 35 Tuple,
36 Union, 36 Union,
37 ) 37 )
38 38
39 from .i18n import _ 39 from .i18n import _
40 from .pycompat import (
41 open,
42 )
43 from . import ( 40 from . import (
44 encoding, 41 encoding,
45 error, 42 error,
46 policy, 43 policy,
47 pycompat, 44 pycompat,
98 expandglobs: bool = False 95 expandglobs: bool = False
99 96
100 umask: int = os.umask(0) 97 umask: int = os.umask(0)
101 os.umask(umask) 98 os.umask(umask)
102 99
103 posixfile = open 100 posixfile = pycompat.open
104 101
105 102
106 def split(p: bytes) -> Tuple[bytes, bytes]: 103 def split(p: bytes) -> Tuple[bytes, bytes]:
107 """Same as posixpath.split, but faster 104 """Same as posixpath.split, but faster
108 105
172 st = os.lstat(f) 169 st = os.lstat(f)
173 s = st.st_mode 170 s = st.st_mode
174 if l: 171 if l:
175 if not stat.S_ISLNK(s): 172 if not stat.S_ISLNK(s):
176 # switch file to link 173 # switch file to link
177 with open(f, b'rb') as fp: 174 with open(f, 'rb') as fp:
178 data = fp.read() 175 data = fp.read()
179 unlink(f) 176 unlink(f)
180 try: 177 try:
181 os.symlink(data, f) 178 os.symlink(data, f)
182 except OSError: 179 except OSError:
183 # failed to make a link, rewrite file 180 # failed to make a link, rewrite file
184 with open(f, b"wb") as fp: 181 with open(f, "wb") as fp:
185 fp.write(data) 182 fp.write(data)
186 183
187 # no chmod needed at this point 184 # no chmod needed at this point
188 return 185 return
189 if stat.S_ISLNK(s): 186 if stat.S_ISLNK(s):
190 # switch link to file 187 # switch link to file
191 data = os.readlink(f) 188 data = os.readlink(f)
192 unlink(f) 189 unlink(f)
193 with open(f, b"wb") as fp: 190 with open(f, "wb") as fp:
194 fp.write(data) 191 fp.write(data)
195 s = 0o666 & ~umask # avoid restatting for chmod 192 s = 0o666 & ~umask # avoid restatting for chmod
196 193
197 sx = s & 0o100 194 sx = s & 0o100
198 if st.st_nlink > 1 and bool(x) != bool(sx): 195 if st.st_nlink > 1 and bool(x) != bool(sx):
199 # the file is a hardlink, break it 196 # the file is a hardlink, break it
200 with open(f, b"rb") as fp: 197 with open(f, "rb") as fp:
201 data = fp.read() 198 data = fp.read()
202 unlink(f) 199 unlink(f)
203 with open(f, b"wb") as fp: 200 with open(f, "wb") as fp:
204 fp.write(data) 201 fp.write(data)
205 202
206 if x and not sx: 203 if x and not sx:
207 # Turn on +x for every +r bit when making a file executable 204 # Turn on +x for every +r bit when making a file executable
208 # and obey umask. 205 # and obey umask.
280 if m & EXECFLAGS != 0: 277 if m & EXECFLAGS != 0:
281 # ensure checknoexec exists, check it isn't exec 278 # ensure checknoexec exists, check it isn't exec
282 try: 279 try:
283 m = os.stat(checknoexec).st_mode 280 m = os.stat(checknoexec).st_mode
284 except FileNotFoundError: 281 except FileNotFoundError:
285 open(checknoexec, b'w').close() # might fail 282 open(checknoexec, 'w').close() # might fail
286 m = os.stat(checknoexec).st_mode 283 m = os.stat(checknoexec).st_mode
287 if m & EXECFLAGS == 0: 284 if m & EXECFLAGS == 0:
288 # check-exec is exec and check-no-exec is not exec 285 # check-exec is exec and check-no-exec is not exec
289 return True 286 return True
290 # checknoexec exists but is exec - delete it 287 # checknoexec exists but is exec - delete it
347 # create a fixed file to link to; doesn't matter if it 344 # create a fixed file to link to; doesn't matter if it
348 # already exists. 345 # already exists.
349 target = b'checklink-target' 346 target = b'checklink-target'
350 try: 347 try:
351 fullpath = os.path.join(cachedir, target) 348 fullpath = os.path.join(cachedir, target)
352 open(fullpath, b'w').close() 349 open(fullpath, 'w').close()
353 except PermissionError: 350 except PermissionError:
354 # If we can't write to cachedir, just pretend 351 # If we can't write to cachedir, just pretend
355 # that the fs is readonly and by association 352 # that the fs is readonly and by association
356 # that the fs won't support symlinks. This 353 # that the fs won't support symlinks. This
357 # seems like the least dangerous way to avoid 354 # seems like the least dangerous way to avoid