1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import os
18 import stat
19 import zipfile
20 import time
21
22 from libxyz.exceptions import XYZRuntimeError
23 from libxyz.core.utils import ustring
24 from libxyz.vfs import types as vfstypes
25 from libxyz.vfs import vfsobj
26 from libxyz.vfs import util
27 from libxyz.vfs import mode
28
30 """
31 Zip archive interface
32 """
33
35 if self.root:
36 return a
37 else:
38 return b()
39
40
41
42 get_name = lambda self, x: os.path.basename(x.name.rstrip(os.path.sep))
43 get_path = lambda self, x: os.path.join(self.ext_path, x.lstrip(os.sep))
44
45 file_type_map = {
46 lambda obj: obj.isfile(): vfstypes.VFSTypeFile(),
47 lambda obj: obj.isdir(): vfstypes.VFSTypeDir(),
48 lambda obj: obj.issym(): vfstypes.VFSTypeLink(),
49 lambda obj: obj.ischr(): vfstypes.VFSTypeChar(),
50 lambda obj: obj.isblk(): vfstypes.VFSTypeBlock(),
51 lambda obj: obj.isfifo(): vfstypes.VFSTypeFifo(),
52 }
53
58
59
60
62 """
63 Directory tree walker
64 @return: tuple (parent, dir, dirs, files) where:
65 parent - parent dir *VFSObject instance
66 dir - current dir TarVFSObject instance
67 dirs - list of TarVFSObject objects of directories
68 files - list of TarVFSObject objects of files
69 """
70
71 tarobj = self._open_archive()
72 entries = tarobj.getmembers()
73
74 _dirs = [x for x in entries if x.isdir() and
75 self.in_dir(self.path, x.name)]
76 _files = [x for x in entries if not x.isdir() and
77 self.in_dir(self.path, x.name)]
78
79 _dirs.sort(cmp=lambda x, y: cmp(self.get_name(x),
80 self.get_name(y)))
81 _files.sort(cmp=lambda x, y: cmp(self.get_name(x),
82 self.get_name(y)))
83
84 if self.path == os.sep:
85 _parent = self.xyz.vfs.get_parent(self.parent.path, self.enc)
86 else:
87 _parent = self.xyz.vfs.dispatch(
88 self.get_path(os.path.dirname(self.path)), self.enc)
89 _parent.name = ".."
90
91 return [
92 _parent,
93 self,
94 [self.xyz.vfs.dispatch(self.get_path(x.name), self.enc)
95 for x in _dirs],
96 [self.xyz.vfs.dispatch(self.get_path(x.name), self.enc)
97 for x in _files],
98 ]
99
100
101
102 - def copy(self, path, existcb=None, errorcb=None, save_attrs=True,
103 follow_links=False, cancel=None):
104
105 env = {
106 'override': 'abort',
107 'error': 'abort'
108 }
109
110 tarobj = self._open_archive()
111
112 try:
113 if self.is_dir():
114 f = self._copy_dir
115 else:
116 f = self._copy_file
117
118 f(self.path, path, existcb, errorcb,
119 save_attrs, follow_links, env, cancel, tarobj=tarobj)
120 except XYZRuntimeError:
121
122 return False
123 else:
124 return True
125
126
127
129 if self.path == os.sep:
130 self.root = True
131 else:
132 self.root = False
133
134 self.tarobj = self.kwargs.get("tarobj", None)
135
136 if self.root:
137 self.obj = None
138 else:
139 self.obj = self._init_obj()
140
141 self.ftype = self._find_type()
142 self.vtype = self.ftype.vtype
143
144 self._set_attributes()
145
146 self.attributes = (
147 (_(u"Name"), ustring(self.name)),
148 (_(u"Type"), ustring(self.ftype)),
149 (_(u"Modification time"), ustring(time.ctime(self.mtime))),
150 (_(u"Size in bytes"), ustring(self.size)),
151 (_(u"Owner"), ustring(self.uid)),
152 (_(u"Group"), ustring(self.gid)),
153 (_(u"Access mode"), ustring(self.mode)),
154 (_(u"Type-specific data"), self.data),
155 )
156
157
158
160 """
161 Normalize path
162 """
163
164 if path.startswith(os.sep):
165 return path.lstrip(os.sep)
166 else:
167 return path
168
169
170
172 return "<TarVFSObject object: %s>" % self.path
173
174
175
177 """
178 Filter only those archive entries which exist in the same
179 directory level
180 """
181
182 if e.startswith(d.lstrip(os.sep)) and \
183 len(util.split_path(e)) == (len(util.split_path(d)) + 1):
184 return True
185 else:
186 return False
187
188
189
191 """
192 Find out file type
193 """
194
195 if self.root:
196 return self.parent.ftype
197
198 for k, v in self.file_type_map.iteritems():
199 if k(self.obj):
200 return v
201
202 return vfstypes.VFSTypeUnknown()
203
204
205
207 """
208 Set file attibutes
209 """
210
211 def set_link_attributes():
212 """
213 Set appropriate soft link attibutes
214 """
215
216 self.info = ""
217 self.visual = "-> %s" % self.obj.linkname or ""
218
219
220
221 self.name = self.either(self.parent.name, lambda: self.name)
222 self.mtime = self.either(self.parent.mtime, lambda: self.obj.mtime)
223 self.size = self.either(self.parent.size, lambda: self.obj.size)
224 self.uid = self.either(self.parent.uid, lambda: self.obj.uid)
225 self.gid = self.either(self.parent.gid, lambda: self.obj.gid)
226 self.mode = mode.Mode(self.either(self.parent.mode.raw,
227 lambda: self.obj.mode), self.ftype)
228 self.visual = "%s%s" % (self.vtype, self.name)
229
230 self.info = "%s %s" % (util.format_size(self.size), self.mode)
231
232 if self.is_link():
233 set_link_attributes()
234 elif self.is_file():
235 _mode = stat.S_IMODE(self.mode.raw)
236
237
238 if _mode & 0111:
239 self.vtype = "*"
240 self.visual = "*%s" % self.name
241
242
243
245 tarobj = self._open_archive()
246 path = (altpath or self.path).lstrip(os.sep)
247
248 try:
249 obj = tarobj.getmember(path)
250 except KeyError:
251 obj = tarobj.getmember(path + os.sep)
252
253 return obj
254
255
256
258 if self.tarobj is None:
259 _mode = "r"
260
261 if self.driver == "gztar":
262 _mode = "r:gz"
263 elif self.driver == "bz2tar":
264 _mode = "r:bz2"
265
266 self.tarobj = tarfile.open(self.parent.path, mode=_mode)
267 self.xyz.vfs.set_cache(self.parent.path, {'tarobj': self.tarobj})
268
269 return self.tarobj
270
271
272
273 - def _copy_file(self, src, dst, existcb, errorcb, save_attrs,
274 follow_links, env, cancel=None, tarobj=None):
275 """
276 File-to-file copy
277 """
278
279 obj = self._init_obj(src)
280
281 if os.path.exists(dst) and os.path.isdir(dst):
282 dstto = os.path.join(dst, os.path.basename(src))
283 else:
284 dstto = dst
285
286 if os.path.exists(dstto):
287 if env['override'] not in ('override all', 'skip all'):
288 if existcb:
289 try:
290 env['override'] = existcb(
291 self.xyz.vfs.dispatch(dstto))
292 except Exception:
293 env['override'] = 'abort'
294
295 if env['override'] == 'abort':
296 raise XYZRuntimeError()
297 elif env['override'] in ('skip', 'skip all'):
298 return False
299
300 try:
301 if not follow_links and obj.issym():
302 os.symlink(obj.linkname, dstto)
303 else:
304 if obj.issym():
305 objdir = os.path.dirname(obj.name)
306 src = os.path.join(objdir, obj.linkname)
307
308 self._do_copy(src, dstto, save_attrs, tarobj, obj)
309
310 return True
311 except Exception, e:
312 if env['error'] != 'skip all':
313 if errorcb:
314 try:
315 env['error'] = errorcb(
316 self.xyz.vfs.dispatch(self.full_path), str(e))
317 except Exception:
318 env['error'] = 'abort'
319
320 if env['error'] == 'abort':
321 raise XYZRuntimeError()
322
323 return False
324
325
326
327 - def _copy_dir(self, src, dst, existcb, errorcb, save_attrs,
328 follow_links, env, cancel=None, tarobj=None):
329 """
330 Dir-to-dir copy
331 """
332
333 obj = self._init_obj(src)
334
335 if os.path.exists(dst) and os.path.isdir(dst) and \
336 os.path.basename(src) != os.path.basename(dst):
337 dst = os.path.join(dst, os.path.basename(src))
338
339 if not follow_links and obj.issym():
340 os.symlink(obj.linkname, dst)
341
342 return True
343
344 if obj.isdir() and not os.path.exists(dst):
345 os.makedirs(dst)
346
347 files = [x for x in tarobj.getmembers() if
348 self.in_dir(obj.name, x.name)]
349
350 for f in files:
351 if cancel is not None and cancel.isSet():
352 raise StopIteration()
353
354 srcobj = f.name
355 dstobj = os.path.join(dst, self.get_name(f))
356
357 if self._init_obj(srcobj).isdir():
358 fun = self._copy_dir
359 else:
360 fun = self._copy_file
361
362 fun(srcobj, dstobj, existcb, errorcb, save_attrs,
363 follow_links, env, cancel, tarobj)
364
365 if obj.isdir() and save_attrs:
366 self._copystat(obj, dst)
367
368
369
370 - def _do_copy(self, src, dst, save_attrs, tarobj, obj):
371 """
372 Copy file from inside archive
373 """
374
375 fsrc = tarobj.extractfile(self._normalize(src))
376
377 fdst = open(dst, "w")
378
379 while True:
380 block = fsrc.read(4096)
381
382
383 if block == '':
384 break
385
386 fdst.write(block)
387
388 fsrc.close()
389 fdst.close()
390
391 if save_attrs:
392 self._copystat(obj, dst)
393
394
395
397 try:
398 os.chown(dst, obj.uid, obj.gid)
399 except Exception, e:
400 xyzlog.warning(_(u"Unable to chown %s: %s") %
401 (ustring(dst), ustring(str(e))))
402
403 try:
404 os.chmod(dst, obj.mode)
405 except Exception, e:
406 xyzlog.warning(_(u"Unable to chmod %s: %s") %
407 (ustring(dst), ustring(str(e))))
408