1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import os
18 import stat
19 import time
20 import shutil
21 import errno
22
23 from libxyz.exceptions import VFSError
24 from libxyz.exceptions import XYZRuntimeError
25 from libxyz.exceptions import XYZValueError
26 from libxyz.vfs import vfsobj
27 from libxyz.vfs import types
28 from libxyz.vfs import util
29 from libxyz.vfs import mode
30 from libxyz.core.utils import ustring, bstring
31 from libxyz.ui import BlockEntries
34 def wrap(self, *args, **kwargs):
35 if self.fileobj is None:
36 raise VFSError(_(u"Object must be opened before any operation"))
37 else:
38 return func(self, *args, **kwargs)
39
40 return wrap
41
43 """
44 Local VFS object is used to access local filesystem
45 """
46
47
48
50 """
51 Directory tree walker
52 @return: tuple (parent, dir, objects) where:
53 parent - parent dir LocalVFSObject instance
54 dir - current LocalVFSObject instance
55 objects - BlockEntries of LocalVFSObject objects
56 """
57
58 try:
59 _dir, _dirs, _files = os.walk(self.path).next()
60 except StopIteration:
61 raise XYZRuntimeError(_(u"Unable to walk on %s") %
62 ustring(self.path))
63
64 _dirs.sort()
65 _files.sort()
66
67 _parent = self.xyz.vfs.get_parent(_dir, self.enc)
68
69 get_path = lambda x: os.path.abspath(os.path.join(self.path, x))
70
71 return [_parent, self,
72 BlockEntries(self.xyz, _dirs + _files, get_path)]
73
74
75
76 - def remove(self, recursive=True):
77 """
78 [Recursively] remove object
79 """
80
81 if self.is_dir():
82 if recursive:
83 shutil.rmtree(self.path)
84 else:
85 os.rmdir(self.path)
86 else:
87 os.unlink(self.path)
88
89
90
92 """
93 Create new dir inside object (only valid for directory object types)
94 """
95
96 if not (self.is_dir() or
97 (self.is_link() and self.data.is_dir())):
98 raise XYZValueError(
99 _(u"Unable to create directory inside %s object type") %
100 self.ftype)
101 else:
102 os.mkdir(newdir)
103
104
105
106 - def copy(self, path, existcb=None, errorcb=None, save_attrs=True,
107 follow_links=False, cancel=None):
108
109 env = {
110 'override': 'abort',
111 'error': 'abort'
112 }
113
114 try:
115 if self.is_dir():
116 f = self._copy_dir
117 else:
118 f = self._copy_file
119
120 f(self.full_path, path, existcb, errorcb,
121 save_attrs, follow_links, env, cancel)
122 except XYZRuntimeError:
123
124 return False
125 else:
126 return True
127
128
129
130 - def move(self, path, existcb=None, errorcb=None, save_attrs=True,
131 follow_links=False, cancel=None):
132 """
133 Move object
134 """
135
136 def _handle_error(e, obj):
137 if env['error'] != 'skip all':
138 if errorcb:
139 try:
140 env['error'] = errorcb(obj, str(e))
141 except Exception:
142 env['error'] = 'abort'
143
144 if env['error'] == 'abort':
145 raise XYZRuntimeError()
146
147
148
149 def _move_file(src, dst, *args, **kwargs):
150 if os.path.exists(dst) and os.path.isdir(dst):
151 dstto = os.path.join(dst, os.path.basename(src))
152 else:
153 dstto = dst
154
155 if os.path.exists(dstto):
156 if env['override'] not in ('override all', 'skip all'):
157 if existcb:
158 try:
159 env['override'] = existcb(
160 self.xyz.vfs.dispatch(dstto))
161 except Exception:
162 env['override'] = 'abort'
163
164 if env['override'] == 'abort':
165 raise XYZRuntimeError()
166 elif env['override'] in ('skip', 'skip all'):
167 return False
168
169 try:
170 os.rename(src, dstto)
171
172 return True
173 except OSError, e:
174
175 if e.errno == errno.EXDEV:
176 if self._copy_file(src, dst, *args, **kwargs):
177
178 try:
179 os.unlink(src)
180 except Exception, e2:
181 _handle_error(e2, self.xyz.vfs.dispatch(src))
182 else:
183 _handle_error(e, self.xyz.vfs.dispatch(src))
184 except XYZRuntimeError:
185 raise
186 except Exception, e3:
187 _handle_error(e3, self.xyz.vfs.dispatch(src))
188
189
190
191 def _move_dir(src, dst, *args, **kwargs):
192 if os.path.exists(dst) and os.path.isdir(dst) and \
193 os.path.basename(src) != os.path.basename(dst):
194 dst = os.path.join(dst, os.path.basename(src))
195
196 if os.path.isdir(src) and not os.path.exists(dst):
197 os.makedirs(dst)
198
199 files = os.listdir(src)
200
201 cancel = kwargs.get('cancel', None)
202
203 for f in files:
204 if cancel is not None and cancel.isSet():
205 raise StopIteration()
206
207 srcobj = os.path.join(src, f)
208 dstobj = os.path.join(dst, f)
209
210 if os.path.isdir(srcobj):
211 fun = _move_dir
212 else:
213 fun = _move_file
214
215 fun(srcobj, dstobj, *args, **kwargs)
216
217 try:
218 os.rmdir(src)
219 except Exception, e:
220 _handle_error(e, self.xyz.vfs.dispatch(src))
221
222 return True
223
224
225
226 env = {
227 'override': 'abort',
228 'error': 'abort'
229 }
230
231 try:
232 if self.is_dir():
233 fun = _move_dir
234 else:
235 fun = _move_file
236
237 fun(self.full_path, path, existcb, errorcb, save_attrs,
238 follow_links, env, cancel=cancel)
239 except XYZRuntimeError:
240
241 return False
242
243
244
245 - def open(self, mode='r'):
246 """
247 Open self object in provided mode
248 """
249
250 if self.fileobj:
251 return self
252 else:
253 self.fileobj = open(self.path, mode)
254
255 return self
256
257
258
260 """
261 Close self object
262 """
263
264 if self.fileobj is None:
265 return
266 else:
267 try:
268 self.fileobj.close()
269 finally:
270 self.fileobj = None
271
272
273
274 @ensure_opened
275 - def read(self, bytes=None):
276 """
277 Read bytes from self object
278 """
279
280 return self.fileobj.read(bytes)
281
282
283
284 @ensure_opened
286 """
287 Tell file position
288 """
289
290 return self.fileobj.tell()
291
292
293
294 @ensure_opened
295 - def seek(self, offset, whence=0):
296 """
297 Perform seek() on object
298 """
299
300 return self.fileobj.seek(offset, whence)
301
302
303
304
306 self.ftype = self._find_type(self.path)
307 self.vtype = self.ftype.vtype
308
309 self._set_attributes()
310
311 _time = lambda x: ustring(time.ctime(x))
312
313 self.attributes = (
314 (_(u"Name"), ustring(self.name)),
315 (_(u"Type"), ustring(self.ftype)),
316 (_(u"Access time"), _time(self.atime)),
317 (_(u"Modification time"), _time(self.mtime)),
318 (_(u"Change time"), _time(self.ctime)),
319 (_(u"Size in bytes"), ustring(self.size)),
320 (_(u"Owner"), ustring(self._uid(self.uid))),
321 (_(u"Group"), ustring(self._gid(self.gid))),
322 (_(u"Access mode"), ustring(self.mode)),
323 (_(u"Inode"), ustring(self.inode)),
324 (_(u"Type-specific data"), self.data),
325 )
326
327
328
330 return "<LocalVFSObject object: %s>" % self.path
331
332
333
334 - def _uid(self, uid):
335 _name = util.get_user(uid)
336
337 if _name is not None:
338 return "%s (%s)" % (bstring(uid), _name)
339 else:
340 return bstring(uid)
341
342
343
344 - def _gid(self, gid):
345 _name = util.get_group(gid)
346
347 if _name is not None:
348 return "%s (%s)" % (bstring(gid), _name)
349 else:
350 return bstring(gid)
351
352
353
355 """
356 Find out file type
357 """
358
359 try:
360 self._stat = os.lstat(path)
361 except OSError, e:
362 raise VFSError(_(u"Unable to stat file %s: %s") %
363 (ustring(path), unicode(e.strerror, xyzenc)))
364
365 return util.get_file_type(self._stat.st_mode)
366
367
368
370 """
371 Set file attibutes
372 """
373
374 def set_link_attributes():
375 """
376 Set appropriate soft link attibutes
377 """
378
379 _realpath = os.readlink(self.path)
380 _fullpath = os.path.realpath(self.path)
381
382 if not os.path.exists(_fullpath):
383 self.vtype = "!"
384 else:
385 try:
386 self.data = self.xyz.vfs.dispatch(_fullpath, self.enc)
387 except VFSError, e:
388 xyzlog.error(_(u"Error creating VFS object: %s") %
389 unicode(e))
390 else:
391 if isinstance(self.data.ftype, types.VFSTypeDir):
392 self.vtype = "~"
393 self.info = ""
394 self.visual = "-> %s" % _realpath
395
396
397
398 def set_char_attributes():
399 """
400 Set appropriate character device attibutes
401 """
402
403 _dev = self._stat.st_rdev
404 self.info = "%s, %s %s" % (os.major(_dev), os.minor(_dev),
405 self.mode)
406
407
408
409 self.atime = self._stat.st_atime
410 self.mtime = self._stat.st_mtime
411 self.ctime = self._stat.st_ctime
412 self.size = self._stat.st_size
413 self.uid = self._stat.st_uid
414 self.gid = self._stat.st_gid
415 self.inode = self._stat.st_ino
416 self.mode = mode.Mode(self._stat.st_mode, self.ftype)
417 self.visual = "%s%s" % (self.vtype, self.name)
418 self.info = "%s %s" % (util.format_size(self.size), self.mode)
419
420 if self.is_link():
421 set_link_attributes()
422 elif self.is_char():
423 set_char_attributes()
424 elif self.is_file():
425 _mode = stat.S_IMODE(self.mode.raw)
426
427
428 if _mode & 0111:
429 self.vtype = "*"
430 self.visual = "*%s" % self.name
431
432
433
434 - def _copy_file(self, src, dst, existcb, errorcb, save_attrs,
435 follow_links, env, cancel=None):
436 """
437 File-to-file copy
438 """
439
440 if os.path.exists(dst) and os.path.isdir(dst):
441 dstto = os.path.join(dst, os.path.basename(src))
442 else:
443 dstto = dst
444
445 if os.path.exists(dstto):
446 if env['override'] not in ('override all', 'skip all'):
447 if existcb:
448 try:
449 env['override'] = existcb(
450 self.xyz.vfs.dispatch(dstto))
451 except Exception:
452 env['override'] = 'abort'
453
454 if env['override'] == 'abort':
455 raise XYZRuntimeError()
456 elif env['override'] in ('skip', 'skip all'):
457 return False
458
459 try:
460 if not follow_links and os.path.islink(src):
461 linkto = os.readlink(src)
462 os.symlink(linkto, dstto)
463 else:
464 if save_attrs:
465 fun = shutil.copy2
466 else:
467 fun = shutil.copyfile
468
469 fun(src, dstto)
470
471 return True
472 except Exception, e:
473 if env['error'] != 'skip all':
474 if errorcb:
475 try:
476 env['error'] = errorcb(
477 self.xyz.vfs.dispatch(src), str(e))
478 except Exception:
479 env['error'] = 'abort'
480
481 if env['error'] == 'abort':
482 raise XYZRuntimeError()
483
484 return False
485
486
487
488 - def _copy_dir(self, src, dst, existcb, errorcb, save_attrs,
489 follow_links, env, cancel=None):
490 """
491 Dir-to-dir copy
492 """
493
494 if os.path.exists(dst) and os.path.isdir(dst) and \
495 os.path.basename(src) != os.path.basename(dst):
496 dst = os.path.join(dst, os.path.basename(src))
497
498 if not follow_links and os.path.islink(src):
499 linkto = os.readlink(src)
500 os.symlink(linkto, dst)
501
502 return True
503
504 if os.path.isdir(src) and not os.path.exists(dst):
505 os.makedirs(dst)
506
507 files = os.listdir(src)
508
509 for f in files:
510 if cancel is not None and cancel.isSet():
511 raise StopIteration()
512
513 srcobj = os.path.join(src, f)
514 dstobj = os.path.join(dst, f)
515
516 if os.path.isdir(srcobj):
517 fun = self._copy_dir
518 else:
519 fun = self._copy_file
520
521 fun(srcobj, dstobj, existcb, errorcb, save_attrs,
522 follow_links, env, cancel)
523
524 if os.path.isdir(src) and save_attrs:
525 shutil.copystat(src, dst)
526