Update copyright notices to use a central AUTHORS file.
[cumulus.git] / python / cumulus / store / ftp.py
index 52a7aad..95dd14e 100644 (file)
@@ -1,5 +1,22 @@
+# Cumulus: Efficient Filesystem Backup to the Cloud
+# Copyright (C) 2009 The Cumulus Developers
+# See the AUTHORS file for a list of contributors.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-from ftplib        import FTP, all_errors
+from ftplib        import FTP, all_errors, error_temp
 from netrc         import netrc, NetrcParseError
 from cumulus.store import Store, type_patterns, NotFoundError
 
@@ -30,16 +47,24 @@ class FtpStore (Store):
                     pass
             except (IOError, NetrcParseError):
                 pass
-        self.ftp = FTP ()
-        self.ftp.connect (host, port)
-        self.ftp.login (user, passwd)
+        self.host   = host
+        self.port   = port
+        self.user   = user
+        self.passwd = passwd
         self.prefix = self.path [1:] # skip *only* first '/'
-        self.ftp.cwd (self.prefix)
+        self.ftp    = FTP ()
+        self.connect ()
 
     def _get_path (self, type, name):
         # we are in right directory
         return name
 
+    def connect (self) :
+        self.ftp.connect (self.host, self.port)
+        self.ftp.login (self.user, self.passwd)
+        self.ftp.cwd (self.prefix)
+    # end def connect
+
     def list (self, type):
         self.sync ()
         files = self.ftp.nlst ()
@@ -47,6 +72,7 @@ class FtpStore (Store):
 
     def get (self, type, name):
         self.sync ()
+        self.ftp.sendcmd ('TYPE I')
         sock = self.ftp.transfercmd ('RETR %s' % self._get_path (type, name))
         self.synced = False
         return sock.makefile ()
@@ -85,10 +111,19 @@ class FtpStore (Store):
 
     def sync (self):
         """ After a get command at end of transfer a 2XX reply is still
-        in the input-queue, we have to get rid of that
+        in the input-queue, we have to get rid of that.
+        We also test here that the connection is still alive. If we get
+        a temporary error 421 ("error_temp") we reconnect: It was
+        probably a timeout.
         """
-        if not self.synced:
-            self.ftp.voidresp()
+        try :
+            if not self.synced:
+                self.ftp.voidresp()
+            self.ftp.sendcmd ('TYPE A')
+        except error_temp, err :
+            if not err.message.startswith ('421') :
+                raise
+            self.connect ()
         self.synced = True
 
 Store = FtpStore