blob: 47fa8f97cf46d22fe32a5e81f33b4e5744c61fa1 [file] [log] [blame]
Guido van Rossum07a272d1995-04-10 11:40:52 +00001"""File System Proxy.
2
3Provide an OS-neutral view on a file system, locally or remotely.
4The functionality is geared towards implementing some sort of
5rdist-like utility between a Mac and a UNIX system.
6
7The module defines three classes:
8
9FSProxyLocal -- used for local access
10FSProxyServer -- used on the server side of remote access
11FSProxyClient -- used on the client side of remote access
12
13The remote classes are instantiated with an IP address and an optional
14verbosity flag.
15"""
16
17import server
18import client
19import md5
20import os
21import fnmatch
22from stat import *
23import time
24import fnmatch
25
Ronald Oussoren94f25282010-05-05 19:11:21 +000026maxnamelen = 255
Guido van Rossum07a272d1995-04-10 11:40:52 +000027
28skipnames = (os.curdir, os.pardir)
29
30
31class FSProxyLocal:
Tim Peterse6ddc8b2004-07-18 05:56:09 +000032
33 def __init__(self):
34 self._dirstack = []
35 self._ignore = ['*.pyc'] + self._readignore()
36
37 def _close(self):
38 while self._dirstack:
39 self.back()
40
41 def _readignore(self):
42 file = self._hide('ignore')
43 try:
44 f = open(file)
45 except IOError:
46 file = self._hide('synctree.ignorefiles')
47 try:
48 f = open(file)
49 except IOError:
50 return []
51 ignore = []
52 while 1:
53 line = f.readline()
54 if not line: break
55 if line[-1] == '\n': line = line[:-1]
56 ignore.append(line)
57 f.close()
58 return ignore
59
60 def _hidden(self, name):
Ronald Oussoren94f25282010-05-05 19:11:21 +000061 return name[0] == '.'
Tim Peterse6ddc8b2004-07-18 05:56:09 +000062
63 def _hide(self, name):
Ronald Oussoren94f25282010-05-05 19:11:21 +000064 return '.%s' % name
Tim Peterse6ddc8b2004-07-18 05:56:09 +000065
66 def visible(self, name):
67 if len(name) > maxnamelen: return 0
68 if name[-1] == '~': return 0
69 if name in skipnames: return 0
70 if self._hidden(name): return 0
71 head, tail = os.path.split(name)
72 if head or not tail: return 0
Ronald Oussoren94f25282010-05-05 19:11:21 +000073 if os.path.islink(name): return 0
74 if '\0' in open(name, 'rb').read(512): return 0
Tim Peterse6ddc8b2004-07-18 05:56:09 +000075 for ign in self._ignore:
76 if fnmatch.fnmatch(name, ign): return 0
77 return 1
78
79 def check(self, name):
80 if not self.visible(name):
Collin Winter6f2df4d2007-07-17 20:59:35 +000081 raise os.error("protected name %s" % repr(name))
Tim Peterse6ddc8b2004-07-18 05:56:09 +000082
83 def checkfile(self, name):
84 self.check(name)
85 if not os.path.isfile(name):
Collin Winter6f2df4d2007-07-17 20:59:35 +000086 raise os.error("not a plain file %s" % repr(name))
Tim Peterse6ddc8b2004-07-18 05:56:09 +000087
88 def pwd(self):
89 return os.getcwd()
90
91 def cd(self, name):
92 self.check(name)
93 save = os.getcwd(), self._ignore
94 os.chdir(name)
95 self._dirstack.append(save)
96 self._ignore = self._ignore + self._readignore()
97
98 def back(self):
99 if not self._dirstack:
Collin Winter6f2df4d2007-07-17 20:59:35 +0000100 raise os.error("empty directory stack")
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000101 dir, ignore = self._dirstack[-1]
102 os.chdir(dir)
103 del self._dirstack[-1]
104 self._ignore = ignore
105
106 def _filter(self, files, pat = None):
107 if pat:
108 def keep(name, pat = pat):
109 return fnmatch.fnmatch(name, pat)
Collin Winter6f2df4d2007-07-17 20:59:35 +0000110 files = list(filter(keep, files))
111 files = list(filter(self.visible, files))
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000112 files.sort()
113 return files
114
115 def list(self, pat = None):
116 files = os.listdir(os.curdir)
117 return self._filter(files, pat)
118
119 def listfiles(self, pat = None):
120 files = os.listdir(os.curdir)
Collin Winter6f2df4d2007-07-17 20:59:35 +0000121 files = list(filter(os.path.isfile, files))
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000122 return self._filter(files, pat)
123
124 def listsubdirs(self, pat = None):
125 files = os.listdir(os.curdir)
Collin Winter6f2df4d2007-07-17 20:59:35 +0000126 files = list(filter(os.path.isdir, files))
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000127 return self._filter(files, pat)
128
129 def exists(self, name):
130 return self.visible(name) and os.path.exists(name)
131
132 def isdir(self, name):
133 return self.visible(name) and os.path.isdir(name)
134
135 def islink(self, name):
136 return self.visible(name) and os.path.islink(name)
137
138 def isfile(self, name):
139 return self.visible(name) and os.path.isfile(name)
140
141 def sum(self, name):
142 self.checkfile(name)
143 BUFFERSIZE = 1024*8
144 f = open(name)
145 sum = md5.new()
146 while 1:
147 buffer = f.read(BUFFERSIZE)
148 if not buffer:
149 break
150 sum.update(buffer)
151 return sum.digest()
152
153 def size(self, name):
154 self.checkfile(name)
155 return os.stat(name)[ST_SIZE]
156
157 def mtime(self, name):
158 self.checkfile(name)
159 return time.localtime(os.stat(name)[ST_MTIME])
160
161 def stat(self, name):
162 self.checkfile(name)
163 size = os.stat(name)[ST_SIZE]
164 mtime = time.localtime(os.stat(name)[ST_MTIME])
165 return size, mtime
166
167 def info(self, name):
168 sum = self.sum(name)
169 size = os.stat(name)[ST_SIZE]
170 mtime = time.localtime(os.stat(name)[ST_MTIME])
171 return sum, size, mtime
172
173 def _list(self, function, list):
174 if list is None:
175 list = self.listfiles()
176 res = []
177 for name in list:
178 try:
179 res.append((name, function(name)))
180 except (os.error, IOError):
181 res.append((name, None))
182 return res
183
184 def sumlist(self, list = None):
185 return self._list(self.sum, list)
186
187 def statlist(self, list = None):
188 return self._list(self.stat, list)
189
190 def mtimelist(self, list = None):
191 return self._list(self.mtime, list)
192
193 def sizelist(self, list = None):
194 return self._list(self.size, list)
195
196 def infolist(self, list = None):
197 return self._list(self.info, list)
198
199 def _dict(self, function, list):
200 if list is None:
201 list = self.listfiles()
202 dict = {}
203 for name in list:
204 try:
205 dict[name] = function(name)
206 except (os.error, IOError):
207 pass
208 return dict
209
210 def sumdict(self, list = None):
211 return self.dict(self.sum, list)
212
213 def sizedict(self, list = None):
214 return self.dict(self.size, list)
215
216 def mtimedict(self, list = None):
217 return self.dict(self.mtime, list)
218
219 def statdict(self, list = None):
220 return self.dict(self.stat, list)
221
222 def infodict(self, list = None):
223 return self._dict(self.info, list)
224
225 def read(self, name, offset = 0, length = -1):
226 self.checkfile(name)
227 f = open(name)
228 f.seek(offset)
229 if length == 0:
230 data = ''
231 elif length < 0:
232 data = f.read()
233 else:
234 data = f.read(length)
235 f.close()
236 return data
237
238 def create(self, name):
239 self.check(name)
240 if os.path.exists(name):
241 self.checkfile(name)
242 bname = name + '~'
243 try:
244 os.unlink(bname)
245 except os.error:
246 pass
247 os.rename(name, bname)
248 f = open(name, 'w')
249 f.close()
250
251 def write(self, name, data, offset = 0):
252 self.checkfile(name)
253 f = open(name, 'r+')
254 f.seek(offset)
255 f.write(data)
256 f.close()
257
258 def mkdir(self, name):
259 self.check(name)
Collin Winter6f2df4d2007-07-17 20:59:35 +0000260 os.mkdir(name, 0o777)
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000261
262 def rmdir(self, name):
263 self.check(name)
264 os.rmdir(name)
Guido van Rossum07a272d1995-04-10 11:40:52 +0000265
266
267class FSProxyServer(FSProxyLocal, server.Server):
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000268
269 def __init__(self, address, verbose = server.VERBOSE):
270 FSProxyLocal.__init__(self)
271 server.Server.__init__(self, address, verbose)
272
273 def _close(self):
274 server.Server._close(self)
275 FSProxyLocal._close(self)
276
277 def _serve(self):
278 server.Server._serve(self)
279 # Retreat into start directory
280 while self._dirstack: self.back()
Guido van Rossum07a272d1995-04-10 11:40:52 +0000281
282
283class FSProxyClient(client.Client):
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000284
285 def __init__(self, address, verbose = client.VERBOSE):
286 client.Client.__init__(self, address, verbose)
Guido van Rossum07a272d1995-04-10 11:40:52 +0000287
288
289def test():
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000290 import string
291 import sys
292 if sys.argv[1:]:
293 port = string.atoi(sys.argv[1])
294 else:
295 port = 4127
296 proxy = FSProxyServer(('', port))
297 proxy._serverloop()
Guido van Rossum07a272d1995-04-10 11:40:52 +0000298
299
300if __name__ == '__main__':
Tim Peterse6ddc8b2004-07-18 05:56:09 +0000301 test()