305
301
:param retries: Number of retries after temporary failures so far
306
302
for this operation.
308
TODO: jam 20051215 ftp as a protocol seems to support chmod, but
304
TODO: jam 20051215 ftp as a protocol seems to support chmod, but ftplib does not
311
306
abspath = self._abspath(relpath)
312
307
tmp_abspath = '%s.tmp.%.9f.%d.%d' % (abspath, time.time(),
318
313
f = self._get_FTP()
320
315
f.storbinary('STOR '+tmp_abspath, fp)
321
self._rename_and_overwrite(tmp_abspath, abspath, f)
316
f.rename(tmp_abspath, abspath)
322
317
except (ftplib.error_temp,EOFError), e:
323
318
warning("Failure during ftp PUT. Deleting temporary file.")
437
432
# to give it its own address as the 'to' location.
438
433
# So implement a fancier 'copy()'
440
def rename(self, rel_from, rel_to):
441
abs_from = self._abspath(rel_from)
442
abs_to = self._abspath(rel_to)
443
mutter("FTP rename: %s => %s", abs_from, abs_to)
445
return self._rename(abs_from, abs_to, f)
447
def _rename(self, abs_from, abs_to, f):
449
f.rename(abs_from, abs_to)
450
except ftplib.error_perm, e:
451
self._translate_perm_error(e, abs_from,
452
': unable to rename to %r' % (abs_to))
454
435
def move(self, rel_from, rel_to):
455
436
"""Move the item at rel_from to the location at rel_to"""
456
437
abs_from = self._abspath(rel_from)
459
440
mutter("FTP mv: %s => %s", abs_from, abs_to)
460
441
f = self._get_FTP()
461
self._rename_and_overwrite(abs_from, abs_to, f)
442
f.rename(abs_from, abs_to)
462
443
except ftplib.error_perm, e:
463
444
self._translate_perm_error(e, abs_from,
464
445
extra='unable to rename to %r' % (rel_to,),
465
446
unknown_exc=errors.PathError)
467
def _rename_and_overwrite(self, abs_from, abs_to, f):
468
"""Do a fancy rename on the remote server.
470
Using the implementation provided by osutils.
472
osutils.fancy_rename(abs_from, abs_to,
473
rename_func=lambda p1, p2: self._rename(p1, p2, f),
474
unlink_func=lambda p: self._delete(p, f))
476
450
def delete(self, relpath):
477
451
"""Delete the item at relpath"""
478
452
abspath = self._abspath(relpath)
480
self._delete(abspath, f)
482
def _delete(self, abspath, f):
484
454
mutter("FTP rm: %s", abspath)
485
456
f.delete(abspath)
486
457
except ftplib.error_perm, e:
487
458
self._translate_perm_error(e, abspath, 'error deleting',
579
550
"""This is used by medusa.ftp_server to log connections, etc."""
580
551
self.logs.append(message)
582
def setUp(self, vfs_server=None):
583
555
if not _have_medusa:
584
556
raise RuntimeError('Must have medusa to run the FtpServer')
586
assert vfs_server is None or isinstance(vfs_server, LocalURLServer), \
587
"FtpServer currently assumes local transport, got %s" % vfs_server
589
558
self._root = os.getcwdu()
590
559
self._ftp_server = _ftp_server(
591
560
authorizer=_test_authorizer(root=self._root),
597
566
self._port = self._ftp_server.getsockname()[1]
598
567
# Don't let it loop forever, or handle an infinite number of requests.
599
568
# In this case it will run for 100s, or 1000 requests
600
self._async_thread = threading.Thread(
601
target=FtpServer._asyncore_loop_ignore_EBADF,
569
self._async_thread = threading.Thread(target=asyncore.loop,
602
570
kwargs={'timeout':0.1, 'count':1000})
603
571
self._async_thread.setDaemon(True)
604
572
self._async_thread.start()
610
578
asyncore.close_all()
611
579
self._async_thread.join()
614
def _asyncore_loop_ignore_EBADF(*args, **kwargs):
615
"""Ignore EBADF during server shutdown.
617
We close the socket to get the server to shutdown, but this causes
618
select.select() to raise EBADF.
621
asyncore.loop(*args, **kwargs)
622
except select.error, e:
623
if e.args[0] != errno.EBADF:
627
582
_ftp_channel = None
628
583
_ftp_server = None
693
648
pfrom = self.filesystem.translate(self._renaming)
694
649
self._renaming = None
695
650
pto = self.filesystem.translate(line[1])
696
if os.path.exists(pto):
697
self.respond('550 RNTO failed: file exists')
700
652
os.rename(pfrom, pto)
701
653
except (IOError, OSError), e: