1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import os.path
23 import urllib
24
25 import duplicity.backend
26 from duplicity import globals
27 from duplicity import log
28 from duplicity.errors import *
29 from duplicity import tempdir
30
32 """Connect to remote store using File Transfer Protocol"""
34 duplicity.backend.Backend.__init__(self, parsed_url)
35
36
37 try:
38 p = os.popen("ncftpls -v")
39 fout = p.read()
40 ret = p.close()
41 except Exception:
42 pass
43
44 if ret != 0x0800 or not fout:
45 log.FatalError("NcFTP not found: Please install NcFTP version 3.1.9 or later",
46 log.ErrorCode.ftp_ncftp_missing)
47
48
49 version = fout.split('\n')[0].split()[1]
50 if version < "3.1.9":
51 log.FatalError("NcFTP too old: Duplicity requires NcFTP version 3.1.9,"
52 "3.2.1 or later. Version 3.2.0 will not work properly.",
53 log.ErrorCode.ftp_ncftp_too_old)
54 elif version == "3.2.0":
55 log.Warn("NcFTP (ncftpput) version 3.2.0 may fail with duplicity.\n"
56 "see: http://www.ncftpd.com/ncftp/doc/changelog.html\n"
57 "If you have trouble, please upgrade to 3.2.1 or later",
58 log.WarningCode.ftp_ncftp_v320)
59 log.Notice("NcFTP version is %s" % version)
60
61 self.parsed_url = parsed_url
62
63 self.url_string = duplicity.backend.strip_auth_from_url(self.parsed_url)
64
65
66
67
68 self.popen_persist_breaks[ 'ncftpls' ] = [ 5, 1280 ]
69
70
71 if self.url_string[-1] != '/':
72 self.url_string += '/'
73
74 self.password = self.get_password()
75
76 if globals.ftp_connection == 'regular':
77 self.conn_opt = '-E'
78 else:
79 self.conn_opt = '-F'
80
81 self.tempfile, self.tempname = tempdir.default().mkstemp()
82 os.write(self.tempfile, "host %s\n" % self.parsed_url.hostname)
83 os.write(self.tempfile, "user %s\n" % self.parsed_url.username)
84 os.write(self.tempfile, "pass %s\n" % self.password)
85 os.close(self.tempfile)
86 self.flags = "-f %s %s -t %s -o useCLNT=0,useHELP_SITE=0 " % \
87 (self.tempname, self.conn_opt, globals.timeout)
88 if parsed_url.port != None and parsed_url.port != 21:
89 self.flags += " -P '%s'" % (parsed_url.port)
90
91 - def put(self, source_path, remote_filename = None):
92 """Transfer source_path to remote_filename"""
93 if not remote_filename:
94 remote_filename = source_path.get_filename()
95 remote_path = os.path.join(urllib.unquote(self.parsed_url.path.lstrip('/')), remote_filename).rstrip()
96 commandline = "ncftpput %s -m -V -C '%s' '%s'" % \
97 (self.flags, source_path.name, remote_path)
98 self.run_command_persist(commandline)
99
100 - def get(self, remote_filename, local_path):
107
109 """List files in directory"""
110
111 commandline = "ncftpls %s -l '%s'" % (self.flags, self.url_string)
112 l = self.popen_persist(commandline).split('\n')
113 l = filter(lambda x: x, l)
114
115 return [x.split()[-1] for x in l if not x.startswith("total ")]
116
117 - def delete(self, filename_list):
118 """Delete files in filename_list"""
119 for filename in filename_list:
120 commandline = "ncftpls %s -l -X 'DELE %s' '%s'" % \
121 (self.flags, filename, self.url_string)
122 self.popen_persist(commandline)
123
124 duplicity.backend.register_backend("ftp", FTPBackend)
125