@@ -56,9 +56,10 @@ def _get_exports_list(module):
5656 pass
5757 import posixpath as path
5858
59- import posix
60- __all__ .extend (_get_exports_list (posix ))
61- del posix
59+ try :
60+ from posix import _have_functions
61+ except ImportError :
62+ pass
6263
6364elif 'nt' in _names :
6465 name = 'nt'
@@ -75,6 +76,11 @@ def _get_exports_list(module):
7576 __all__ .extend (_get_exports_list (nt ))
7677 del nt
7778
79+ try :
80+ from nt import _have_functions
81+ except ImportError :
82+ pass
83+
7884elif 'os2' in _names :
7985 name = 'os2'
8086 linesep = '\r \n '
@@ -94,6 +100,11 @@ def _get_exports_list(module):
94100 __all__ .extend (_get_exports_list (os2 ))
95101 del os2
96102
103+ try :
104+ from os2 import _have_functions
105+ except ImportError :
106+ pass
107+
97108elif 'ce' in _names :
98109 name = 'ce'
99110 linesep = '\r \n '
@@ -110,6 +121,11 @@ def _get_exports_list(module):
110121 __all__ .extend (_get_exports_list (ce ))
111122 del ce
112123
124+ try :
125+ from ce import _have_functions
126+ except ImportError :
127+ pass
128+
113129else :
114130 raise ImportError ('no os specific module found' )
115131
@@ -119,6 +135,84 @@ def _get_exports_list(module):
119135
120136del _names
121137
138+
139+ if _exists ("_have_functions" ):
140+ _globals = globals ()
141+ def _add (str , fn ):
142+ if (fn in _globals ) and (str in _have_functions ):
143+ _set .add (_globals [fn ])
144+
145+ _set = set ()
146+ _add ("HAVE_FACCESSAT" , "access" )
147+ _add ("HAVE_FCHMODAT" , "chmod" )
148+ _add ("HAVE_FCHOWNAT" , "chown" )
149+ _add ("HAVE_FSTATAT" , "stat" )
150+ _add ("HAVE_FUTIMESAT" , "utime" )
151+ _add ("HAVE_LINKAT" , "link" )
152+ _add ("HAVE_MKDIRAT" , "mkdir" )
153+ _add ("HAVE_MKFIFOAT" , "mkfifo" )
154+ _add ("HAVE_MKNODAT" , "mknod" )
155+ _add ("HAVE_OPENAT" , "open" )
156+ _add ("HAVE_READLINKAT" , "readlink" )
157+ _add ("HAVE_RENAMEAT" , "rename" )
158+ _add ("HAVE_SYMLINKAT" , "symlink" )
159+ _add ("HAVE_UNLINKAT" , "unlink" )
160+ _add ("HAVE_UTIMENSAT" , "utime" )
161+ supports_dir_fd = _set
162+
163+ _set = set ()
164+ _add ("HAVE_FACCESSAT" , "access" )
165+ supports_effective_ids = _set
166+
167+ _set = set ()
168+ _add ("HAVE_FCHDIR" , "chdir" )
169+ _add ("HAVE_FCHMOD" , "chmod" )
170+ _add ("HAVE_FCHOWN" , "chown" )
171+ _add ("HAVE_FDOPENDIR" , "listdir" )
172+ _add ("HAVE_FEXECVE" , "execve" )
173+ _set .add (stat ) # fstat always works
174+ _add ("HAVE_FUTIMENS" , "utime" )
175+ _add ("HAVE_FUTIMES" , "utime" )
176+ if _exists ("statvfs" ) and _exists ("fstatvfs" ): # mac os x10.3
177+ _add ("HAVE_FSTATVFS" , "statvfs" )
178+ supports_fd = _set
179+
180+ _set = set ()
181+ _add ("HAVE_FACCESSAT" , "access" )
182+ # Current linux (kernel 3.2, glibc 2.15) doesn't support lchmod.
183+ # (The function exists, but it's a stub that always returns ENOSUP.)
184+ # Now, linux *does* have fchmodat, which says it can ignore
185+ # symbolic links. But that doesn't work either (also returns ENOSUP).
186+ # I'm guessing that if they fix fchmodat, they'll also add lchmod at
187+ # the same time. So, for now, assume that fchmodat doesn't support
188+ # follow_symlinks unless lchmod works.
189+ if ((sys .platform != "linux" ) or
190+ ("HAVE_LCHMOD" in _have_functions )):
191+ _add ("HAVE_FCHMODAT" , "chmod" )
192+ _add ("HAVE_FCHOWNAT" , "chown" )
193+ _add ("HAVE_FSTATAT" , "stat" )
194+ _add ("HAVE_LCHFLAGS" , "chflags" )
195+ _add ("HAVE_LCHMOD" , "chmod" )
196+ if _exists ("lchown" ): # mac os x10.3
197+ _add ("HAVE_LCHOWN" , "chown" )
198+ _add ("HAVE_LINKAT" , "link" )
199+ _add ("HAVE_LUTIMES" , "utime" )
200+ _add ("HAVE_LSTAT" , "stat" )
201+ _add ("HAVE_FSTATAT" , "stat" )
202+ _add ("HAVE_UTIMENSAT" , "utime" )
203+ _add ("MS_WINDOWS" , "stat" )
204+ supports_follow_symlinks = _set
205+
206+ _set = set ()
207+ _add ("HAVE_UNLINKAT" , "unlink" )
208+ supports_remove_directory = _set
209+
210+ del _set
211+ del _have_functions
212+ del _globals
213+ del _add
214+
215+
122216# Python uses fixed values for the SEEK_ constants; they are mapped
123217# to native constants if necessary in posixmodule.c
124218# Other possible SEEK values are directly imported from posixmodule.c
@@ -318,7 +412,7 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
318412
319413__all__ .append ("walk" )
320414
321- if _exists ( "openat" ) :
415+ if open in supports_dir_fd :
322416
323417 def fwalk (top , topdown = True , onerror = None , followlinks = False ):
324418 """Directory tree generator.
@@ -343,7 +437,7 @@ def fwalk(top, topdown=True, onerror=None, followlinks=False):
343437 import os
344438 for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
345439 print(root, "consumes", end="")
346- print(sum([os.fstatat(rootfd, name ).st_size for name in files]),
440+ print(sum([os.stat(name, dir_fd=rootfd ).st_size for name in files]),
347441 end="")
348442 print("bytes in", len(files), "non-directory files")
349443 if 'CVS' in dirs:
@@ -365,25 +459,22 @@ def _fwalk(topfd, toppath, topdown, onerror, followlinks):
365459 # necessary, it can be adapted to only require O(1) FDs, see issue
366460 # #13734.
367461
368- # whether to follow symlinks
369- flag = 0 if followlinks else AT_SYMLINK_NOFOLLOW
370-
371- names = flistdir (topfd )
462+ names = listdir (topfd )
372463 dirs , nondirs = [], []
373464 for name in names :
374465 try :
375466 # Here, we don't use AT_SYMLINK_NOFOLLOW to be consistent with
376467 # walk() which reports symlinks to directories as directories.
377468 # We do however check for symlinks before recursing into
378469 # a subdirectory.
379- if st .S_ISDIR (fstatat ( topfd , name ).st_mode ):
470+ if st .S_ISDIR (stat ( name , dir_fd = topfd ).st_mode ):
380471 dirs .append (name )
381472 else :
382473 nondirs .append (name )
383474 except FileNotFoundError :
384475 try :
385476 # Add dangling symlinks, ignore disappeared files
386- if st .S_ISLNK (fstatat ( topfd , name , AT_SYMLINK_NOFOLLOW )
477+ if st .S_ISLNK (stat ( name , dir_fd = topfd , follow_symlinks = False )
387478 .st_mode ):
388479 nondirs .append (name )
389480 except FileNotFoundError :
@@ -394,8 +485,8 @@ def _fwalk(topfd, toppath, topdown, onerror, followlinks):
394485
395486 for name in dirs :
396487 try :
397- orig_st = fstatat ( topfd , name , flag )
398- dirfd = openat ( topfd , name , O_RDONLY )
488+ orig_st = stat ( name , dir_fd = topfd , follow_symlinks = followlinks )
489+ dirfd = open ( name , O_RDONLY , dir_fd = topfd )
399490 except error as err :
400491 if onerror is not None :
401492 onerror (err )
0 commit comments