blob: 7c13458b941be332e635cb09d47256ec708464d0 [file] [log] [blame]
Guido van Rossumc6360141990-10-13 19:23:40 +00001# Module 'path' -- common operations on POSIX pathnames
2
3import posix
Guido van Rossum40d93041990-10-21 16:17:34 +00004import stat
Guido van Rossumc6360141990-10-13 19:23:40 +00005
6
Guido van Rossum4d0fdc31991-08-16 13:27:58 +00007# 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 Rossumc6360141990-10-13 19:23:40 +000010# (begins with '/').
11#
Guido van Rossum4d0fdc31991-08-16 13:27:58 +000012def join(a, b):
Guido van Rossumc6360141990-10-13 19:23:40 +000013 if b[:1] = '/': return b
14 if a = '' or a[-1:] = '/': return a + b
Guido van Rossum4d0fdc31991-08-16 13:27:58 +000015 # Note: join('x', '') returns 'x/'; is this what we want?
Guido van Rossumc6360141990-10-13 19:23:40 +000016 return a + '/' + b
17
18
Guido van Rossum4d0fdc31991-08-16 13:27:58 +000019cat = join # For compatibility
20
21
Guido van Rossumc6360141990-10-13 19:23:40 +000022# 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 Rossum4d0fdc31991-08-16 13:27:58 +000024# It is always true that head+tail = p.
Guido van Rossumc6360141990-10-13 19:23:40 +000025#
26def 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 Rossum4d0fdc31991-08-16 13:27:58 +000035# 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#
40def 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 Rossumc6360141990-10-13 19:23:40 +000052# Return the tail (basename) part of a path.
53#
54def basename(p):
55 return split(p)[1]
56
57
58# Return the longest prefix of all list elements.
59#
60def 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#
74def 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#
84def isdir(path):
85 try:
86 st = posix.stat(path)
87 except posix.error:
88 return 0
Guido van Rossum40d93041990-10-21 16:17:34 +000089 return stat.S_ISDIR(st[stat.ST_MODE])
Guido van Rossumc6360141990-10-13 19:23:40 +000090
91
92# Is a path a symbolic link?
93# This will always return false on systems where posix.lstat doesn't exist.
94#
95def islink(path):
96 try:
97 st = posix.lstat(path)
98 except (posix.error, NameError):
99 return 0
Guido van Rossum40d93041990-10-21 16:17:34 +0000100 return stat.S_ISLNK(st[stat.ST_MODE])
Guido van Rossumc6360141990-10-13 19:23:40 +0000101
102
Guido van Rossumd3778f91991-11-12 15:37:40 +0000103# Are two filenames really pointing to the same file?
104#
105def samefile(f1, f2):
106 s1 = posix.stat(f1)
107 s2 = posix.stat(f2)
108 return samestat(s1, s2)
109
110
111# Are two open files really referencing the same file?
112# (Not necessarily the same file descriptor!)
113# XXX Oops, posix.fstat() doesn't exist yet!
114#
115def sameopenfile(fp1, fp2):
116 s1 = posix.fstat(fp1)
117 s2 = posix.fstat(fp2)
118 return samestat(s1, s2)
119
120
121# Are two stat buffers (obtained from stat, fstat or lstat)
122# describing the same file?
123#
124def samestat(s1, s2):
125 return s1[stat.ST_INO] = s2[stat.ST_INO] and \
126 s1[stat.ST_DEV] = s2[stat.STD_DEV]
127
128
129# Subroutine and global data used by ismount().
130
Guido van Rossumc6360141990-10-13 19:23:40 +0000131_mounts = []
132
133def _getmounts():
134 import commands, string
135 mounts = []
136 data = commands.getoutput('/etc/mount')
137 lines = string.splitfields(data, '\n')
138 for line in lines:
139 words = string.split(line)
140 if len(words) >= 3 and words[1] = 'on':
141 mounts.append(words[2])
142 return mounts
143
144
145# Is a path a mount point?
146# This only works for normalized, absolute paths,
147# and only if the mount table as printed by /etc/mount is correct.
148# Sorry.
149#
150def ismount(path):
151 if not _mounts:
152 _mounts[:] = _getmounts()
153 return path in _mounts
154
155
156# Directory tree walk.
157# For each directory under top (including top itself),
158# func(arg, dirname, filenames) is called, where dirname
159# is the name of the directory and filenames is the list of
160# files (and subdirectories etc.) in the directory.
161# func may modify the filenames list, to implement a filter,
162# or to impose a different order of visiting.
163#
164def walk(top, func, arg):
165 try:
166 names = posix.listdir(top)
167 except posix.error:
168 return
169 func(arg, top, names)
170 exceptions = ('.', '..')
171 for name in names:
172 if name not in exceptions:
Guido van Rossum4d0fdc31991-08-16 13:27:58 +0000173 name = join(top, name)
Guido van Rossumc6360141990-10-13 19:23:40 +0000174 if isdir(name):
175 walk(name, func, arg)