Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 1 | # Module 'path' -- common operations on POSIX pathnames |
| 2 | |
| 3 | import posix |
Guido van Rossum | 40d9304 | 1990-10-21 16:17:34 +0000 | [diff] [blame] | 4 | import stat |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 5 | |
| 6 | |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 7 | # Join two pathnames. |
| 8 | # Insert a '/' unless the first part is empty or already ends in '/'. |
| 9 | # Ignore the first part altogether if the second part is absolute |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 10 | # (begins with '/'). |
| 11 | # |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 12 | def join(a, b): |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 13 | if b[:1] = '/': return b |
| 14 | if a = '' or a[-1:] = '/': return a + b |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 15 | # Note: join('x', '') returns 'x/'; is this what we want? |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 16 | return a + '/' + b |
| 17 | |
| 18 | |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 19 | cat = join # For compatibility |
| 20 | |
| 21 | |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 22 | # Split a path in head (empty or ending in '/') and tail (no '/'). |
| 23 | # The tail will be empty if the path ends in '/'. |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 24 | # It is always true that head+tail = p. |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 25 | # |
| 26 | def split(p): |
| 27 | head, tail = '', '' |
| 28 | for c in p: |
| 29 | tail = tail + c |
| 30 | if c = '/': |
| 31 | head, tail = head + tail, '' |
| 32 | return head, tail |
| 33 | |
| 34 | |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 35 | # Split a path in root and extension. |
| 36 | # The extension is everything starting at the first dot in the last |
| 37 | # pathname component; the root is everything before that. |
| 38 | # It is always true that root+ext = p. |
| 39 | # |
| 40 | def splitext(p): |
| 41 | root, ext = '', '' |
| 42 | for c in p: |
| 43 | if c = '/': |
| 44 | root, ext = root + ext + c, '' |
| 45 | elif c = '.' or ext: |
| 46 | ext = ext + c |
| 47 | else: |
| 48 | root = root + c |
| 49 | return root, ext |
| 50 | |
| 51 | |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 52 | # Return the tail (basename) part of a path. |
| 53 | # |
| 54 | def basename(p): |
| 55 | return split(p)[1] |
| 56 | |
| 57 | |
| 58 | # Return the longest prefix of all list elements. |
| 59 | # |
| 60 | def commonprefix(m): |
| 61 | if not m: return '' |
| 62 | prefix = m[0] |
| 63 | for item in m: |
| 64 | for i in range(len(prefix)): |
| 65 | if prefix[:i+1] <> item[:i+1]: |
| 66 | prefix = prefix[:i] |
| 67 | if i = 0: return '' |
| 68 | break |
| 69 | return prefix |
| 70 | |
| 71 | |
| 72 | # Does a file/directory exist? |
| 73 | # |
| 74 | def exists(path): |
| 75 | try: |
| 76 | st = posix.stat(path) |
| 77 | except posix.error: |
| 78 | return 0 |
| 79 | return 1 |
| 80 | |
| 81 | |
| 82 | # Is a path a posix directory? |
| 83 | # |
| 84 | def isdir(path): |
| 85 | try: |
| 86 | st = posix.stat(path) |
| 87 | except posix.error: |
| 88 | return 0 |
Guido van Rossum | 40d9304 | 1990-10-21 16:17:34 +0000 | [diff] [blame] | 89 | return stat.S_ISDIR(st[stat.ST_MODE]) |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 90 | |
| 91 | |
| 92 | # Is a path a symbolic link? |
| 93 | # This will always return false on systems where posix.lstat doesn't exist. |
| 94 | # |
| 95 | def islink(path): |
| 96 | try: |
| 97 | st = posix.lstat(path) |
| 98 | except (posix.error, NameError): |
| 99 | return 0 |
Guido van Rossum | 40d9304 | 1990-10-21 16:17:34 +0000 | [diff] [blame] | 100 | return stat.S_ISLNK(st[stat.ST_MODE]) |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 101 | |
| 102 | |
| 103 | _mounts = [] |
| 104 | |
| 105 | def _getmounts(): |
| 106 | import commands, string |
| 107 | mounts = [] |
| 108 | data = commands.getoutput('/etc/mount') |
| 109 | lines = string.splitfields(data, '\n') |
| 110 | for line in lines: |
| 111 | words = string.split(line) |
| 112 | if len(words) >= 3 and words[1] = 'on': |
| 113 | mounts.append(words[2]) |
| 114 | return mounts |
| 115 | |
| 116 | |
| 117 | # Is a path a mount point? |
| 118 | # This only works for normalized, absolute paths, |
| 119 | # and only if the mount table as printed by /etc/mount is correct. |
| 120 | # Sorry. |
| 121 | # |
| 122 | def ismount(path): |
| 123 | if not _mounts: |
| 124 | _mounts[:] = _getmounts() |
| 125 | return path in _mounts |
| 126 | |
| 127 | |
| 128 | # Directory tree walk. |
| 129 | # For each directory under top (including top itself), |
| 130 | # func(arg, dirname, filenames) is called, where dirname |
| 131 | # is the name of the directory and filenames is the list of |
| 132 | # files (and subdirectories etc.) in the directory. |
| 133 | # func may modify the filenames list, to implement a filter, |
| 134 | # or to impose a different order of visiting. |
| 135 | # |
| 136 | def walk(top, func, arg): |
| 137 | try: |
| 138 | names = posix.listdir(top) |
| 139 | except posix.error: |
| 140 | return |
| 141 | func(arg, top, names) |
| 142 | exceptions = ('.', '..') |
| 143 | for name in names: |
| 144 | if name not in exceptions: |
Guido van Rossum | 4d0fdc3 | 1991-08-16 13:27:58 +0000 | [diff] [blame] | 145 | name = join(top, name) |
Guido van Rossum | c636014 | 1990-10-13 19:23:40 +0000 | [diff] [blame] | 146 | if isdir(name): |
| 147 | walk(name, func, arg) |