1*cda5da8dSAndroid Build Coastguard Worker""" 2*cda5da8dSAndroid Build Coastguard WorkerPath operations common to more than one OS 3*cda5da8dSAndroid Build Coastguard WorkerDo not use directly. The OS specific modules import the appropriate 4*cda5da8dSAndroid Build Coastguard Workerfunctions from this module themselves. 5*cda5da8dSAndroid Build Coastguard Worker""" 6*cda5da8dSAndroid Build Coastguard Workerimport os 7*cda5da8dSAndroid Build Coastguard Workerimport stat 8*cda5da8dSAndroid Build Coastguard Worker 9*cda5da8dSAndroid Build Coastguard Worker__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime', 10*cda5da8dSAndroid Build Coastguard Worker 'getsize', 'isdir', 'isfile', 'samefile', 'sameopenfile', 11*cda5da8dSAndroid Build Coastguard Worker 'samestat'] 12*cda5da8dSAndroid Build Coastguard Worker 13*cda5da8dSAndroid Build Coastguard Worker 14*cda5da8dSAndroid Build Coastguard Worker# Does a path exist? 15*cda5da8dSAndroid Build Coastguard Worker# This is false for dangling symbolic links on systems that support them. 16*cda5da8dSAndroid Build Coastguard Workerdef exists(path): 17*cda5da8dSAndroid Build Coastguard Worker """Test whether a path exists. Returns False for broken symbolic links""" 18*cda5da8dSAndroid Build Coastguard Worker try: 19*cda5da8dSAndroid Build Coastguard Worker os.stat(path) 20*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError): 21*cda5da8dSAndroid Build Coastguard Worker return False 22*cda5da8dSAndroid Build Coastguard Worker return True 23*cda5da8dSAndroid Build Coastguard Worker 24*cda5da8dSAndroid Build Coastguard Worker 25*cda5da8dSAndroid Build Coastguard Worker# This follows symbolic links, so both islink() and isdir() can be true 26*cda5da8dSAndroid Build Coastguard Worker# for the same path on systems that support symlinks 27*cda5da8dSAndroid Build Coastguard Workerdef isfile(path): 28*cda5da8dSAndroid Build Coastguard Worker """Test whether a path is a regular file""" 29*cda5da8dSAndroid Build Coastguard Worker try: 30*cda5da8dSAndroid Build Coastguard Worker st = os.stat(path) 31*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError): 32*cda5da8dSAndroid Build Coastguard Worker return False 33*cda5da8dSAndroid Build Coastguard Worker return stat.S_ISREG(st.st_mode) 34*cda5da8dSAndroid Build Coastguard Worker 35*cda5da8dSAndroid Build Coastguard Worker 36*cda5da8dSAndroid Build Coastguard Worker# Is a path a directory? 37*cda5da8dSAndroid Build Coastguard Worker# This follows symbolic links, so both islink() and isdir() 38*cda5da8dSAndroid Build Coastguard Worker# can be true for the same path on systems that support symlinks 39*cda5da8dSAndroid Build Coastguard Workerdef isdir(s): 40*cda5da8dSAndroid Build Coastguard Worker """Return true if the pathname refers to an existing directory.""" 41*cda5da8dSAndroid Build Coastguard Worker try: 42*cda5da8dSAndroid Build Coastguard Worker st = os.stat(s) 43*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError): 44*cda5da8dSAndroid Build Coastguard Worker return False 45*cda5da8dSAndroid Build Coastguard Worker return stat.S_ISDIR(st.st_mode) 46*cda5da8dSAndroid Build Coastguard Worker 47*cda5da8dSAndroid Build Coastguard Worker 48*cda5da8dSAndroid Build Coastguard Workerdef getsize(filename): 49*cda5da8dSAndroid Build Coastguard Worker """Return the size of a file, reported by os.stat().""" 50*cda5da8dSAndroid Build Coastguard Worker return os.stat(filename).st_size 51*cda5da8dSAndroid Build Coastguard Worker 52*cda5da8dSAndroid Build Coastguard Worker 53*cda5da8dSAndroid Build Coastguard Workerdef getmtime(filename): 54*cda5da8dSAndroid Build Coastguard Worker """Return the last modification time of a file, reported by os.stat().""" 55*cda5da8dSAndroid Build Coastguard Worker return os.stat(filename).st_mtime 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Worker 58*cda5da8dSAndroid Build Coastguard Workerdef getatime(filename): 59*cda5da8dSAndroid Build Coastguard Worker """Return the last access time of a file, reported by os.stat().""" 60*cda5da8dSAndroid Build Coastguard Worker return os.stat(filename).st_atime 61*cda5da8dSAndroid Build Coastguard Worker 62*cda5da8dSAndroid Build Coastguard Worker 63*cda5da8dSAndroid Build Coastguard Workerdef getctime(filename): 64*cda5da8dSAndroid Build Coastguard Worker """Return the metadata change time of a file, reported by os.stat().""" 65*cda5da8dSAndroid Build Coastguard Worker return os.stat(filename).st_ctime 66*cda5da8dSAndroid Build Coastguard Worker 67*cda5da8dSAndroid Build Coastguard Worker 68*cda5da8dSAndroid Build Coastguard Worker# Return the longest prefix of all list elements. 69*cda5da8dSAndroid Build Coastguard Workerdef commonprefix(m): 70*cda5da8dSAndroid Build Coastguard Worker "Given a list of pathnames, returns the longest common leading component" 71*cda5da8dSAndroid Build Coastguard Worker if not m: return '' 72*cda5da8dSAndroid Build Coastguard Worker # Some people pass in a list of pathname parts to operate in an OS-agnostic 73*cda5da8dSAndroid Build Coastguard Worker # fashion; don't try to translate in that case as that's an abuse of the 74*cda5da8dSAndroid Build Coastguard Worker # API and they are already doing what they need to be OS-agnostic and so 75*cda5da8dSAndroid Build Coastguard Worker # they most likely won't be using an os.PathLike object in the sublists. 76*cda5da8dSAndroid Build Coastguard Worker if not isinstance(m[0], (list, tuple)): 77*cda5da8dSAndroid Build Coastguard Worker m = tuple(map(os.fspath, m)) 78*cda5da8dSAndroid Build Coastguard Worker s1 = min(m) 79*cda5da8dSAndroid Build Coastguard Worker s2 = max(m) 80*cda5da8dSAndroid Build Coastguard Worker for i, c in enumerate(s1): 81*cda5da8dSAndroid Build Coastguard Worker if c != s2[i]: 82*cda5da8dSAndroid Build Coastguard Worker return s1[:i] 83*cda5da8dSAndroid Build Coastguard Worker return s1 84*cda5da8dSAndroid Build Coastguard Worker 85*cda5da8dSAndroid Build Coastguard Worker# Are two stat buffers (obtained from stat, fstat or lstat) 86*cda5da8dSAndroid Build Coastguard Worker# describing the same file? 87*cda5da8dSAndroid Build Coastguard Workerdef samestat(s1, s2): 88*cda5da8dSAndroid Build Coastguard Worker """Test whether two stat buffers reference the same file""" 89*cda5da8dSAndroid Build Coastguard Worker return (s1.st_ino == s2.st_ino and 90*cda5da8dSAndroid Build Coastguard Worker s1.st_dev == s2.st_dev) 91*cda5da8dSAndroid Build Coastguard Worker 92*cda5da8dSAndroid Build Coastguard Worker 93*cda5da8dSAndroid Build Coastguard Worker# Are two filenames really pointing to the same file? 94*cda5da8dSAndroid Build Coastguard Workerdef samefile(f1, f2): 95*cda5da8dSAndroid Build Coastguard Worker """Test whether two pathnames reference the same actual file or directory 96*cda5da8dSAndroid Build Coastguard Worker 97*cda5da8dSAndroid Build Coastguard Worker This is determined by the device number and i-node number and 98*cda5da8dSAndroid Build Coastguard Worker raises an exception if an os.stat() call on either pathname fails. 99*cda5da8dSAndroid Build Coastguard Worker """ 100*cda5da8dSAndroid Build Coastguard Worker s1 = os.stat(f1) 101*cda5da8dSAndroid Build Coastguard Worker s2 = os.stat(f2) 102*cda5da8dSAndroid Build Coastguard Worker return samestat(s1, s2) 103*cda5da8dSAndroid Build Coastguard Worker 104*cda5da8dSAndroid Build Coastguard Worker 105*cda5da8dSAndroid Build Coastguard Worker# Are two open files really referencing the same file? 106*cda5da8dSAndroid Build Coastguard Worker# (Not necessarily the same file descriptor!) 107*cda5da8dSAndroid Build Coastguard Workerdef sameopenfile(fp1, fp2): 108*cda5da8dSAndroid Build Coastguard Worker """Test whether two open file objects reference the same file""" 109*cda5da8dSAndroid Build Coastguard Worker s1 = os.fstat(fp1) 110*cda5da8dSAndroid Build Coastguard Worker s2 = os.fstat(fp2) 111*cda5da8dSAndroid Build Coastguard Worker return samestat(s1, s2) 112*cda5da8dSAndroid Build Coastguard Worker 113*cda5da8dSAndroid Build Coastguard Worker 114*cda5da8dSAndroid Build Coastguard Worker# Split a path in root and extension. 115*cda5da8dSAndroid Build Coastguard Worker# The extension is everything starting at the last dot in the last 116*cda5da8dSAndroid Build Coastguard Worker# pathname component; the root is everything before that. 117*cda5da8dSAndroid Build Coastguard Worker# It is always true that root + ext == p. 118*cda5da8dSAndroid Build Coastguard Worker 119*cda5da8dSAndroid Build Coastguard Worker# Generic implementation of splitext, to be parametrized with 120*cda5da8dSAndroid Build Coastguard Worker# the separators 121*cda5da8dSAndroid Build Coastguard Workerdef _splitext(p, sep, altsep, extsep): 122*cda5da8dSAndroid Build Coastguard Worker """Split the extension from a pathname. 123*cda5da8dSAndroid Build Coastguard Worker 124*cda5da8dSAndroid Build Coastguard Worker Extension is everything from the last dot to the end, ignoring 125*cda5da8dSAndroid Build Coastguard Worker leading dots. Returns "(root, ext)"; ext may be empty.""" 126*cda5da8dSAndroid Build Coastguard Worker # NOTE: This code must work for text and bytes strings. 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker sepIndex = p.rfind(sep) 129*cda5da8dSAndroid Build Coastguard Worker if altsep: 130*cda5da8dSAndroid Build Coastguard Worker altsepIndex = p.rfind(altsep) 131*cda5da8dSAndroid Build Coastguard Worker sepIndex = max(sepIndex, altsepIndex) 132*cda5da8dSAndroid Build Coastguard Worker 133*cda5da8dSAndroid Build Coastguard Worker dotIndex = p.rfind(extsep) 134*cda5da8dSAndroid Build Coastguard Worker if dotIndex > sepIndex: 135*cda5da8dSAndroid Build Coastguard Worker # skip all leading dots 136*cda5da8dSAndroid Build Coastguard Worker filenameIndex = sepIndex + 1 137*cda5da8dSAndroid Build Coastguard Worker while filenameIndex < dotIndex: 138*cda5da8dSAndroid Build Coastguard Worker if p[filenameIndex:filenameIndex+1] != extsep: 139*cda5da8dSAndroid Build Coastguard Worker return p[:dotIndex], p[dotIndex:] 140*cda5da8dSAndroid Build Coastguard Worker filenameIndex += 1 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Worker return p, p[:0] 143*cda5da8dSAndroid Build Coastguard Worker 144*cda5da8dSAndroid Build Coastguard Workerdef _check_arg_types(funcname, *args): 145*cda5da8dSAndroid Build Coastguard Worker hasstr = hasbytes = False 146*cda5da8dSAndroid Build Coastguard Worker for s in args: 147*cda5da8dSAndroid Build Coastguard Worker if isinstance(s, str): 148*cda5da8dSAndroid Build Coastguard Worker hasstr = True 149*cda5da8dSAndroid Build Coastguard Worker elif isinstance(s, bytes): 150*cda5da8dSAndroid Build Coastguard Worker hasbytes = True 151*cda5da8dSAndroid Build Coastguard Worker else: 152*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'{funcname}() argument must be str, bytes, or ' 153*cda5da8dSAndroid Build Coastguard Worker f'os.PathLike object, not {s.__class__.__name__!r}') from None 154*cda5da8dSAndroid Build Coastguard Worker if hasstr and hasbytes: 155*cda5da8dSAndroid Build Coastguard Worker raise TypeError("Can't mix strings and bytes in path components") from None 156