Package duplicity :: Module dup_temp
[hide private]
[frames] | no frames]

Source Code for Module duplicity.dup_temp

  1  # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- 
  2  # 
  3  # Copyright 2002 Ben Escoto <ben@emerose.org> 
  4  # Copyright 2007 Kenneth Loafman <kenneth@loafman.com> 
  5  # 
  6  # This file is part of duplicity. 
  7  # 
  8  # Duplicity is free software; you can redistribute it and/or modify it 
  9  # under the terms of the GNU General Public License as published by the 
 10  # Free Software Foundation; either version 2 of the License, or (at your 
 11  # option) any later version. 
 12  # 
 13  # Duplicity is distributed in the hope that it will be useful, but 
 14  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 16  # General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with duplicity; if not, write to the Free Software Foundation, 
 20  # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 21   
 22  """Manage temporary files""" 
 23   
 24  import os, sys 
 25   
 26  from duplicity import log 
 27  from duplicity import util 
 28  from duplicity import path 
 29  from duplicity import file_naming 
 30  from duplicity import tempdir 
 31  from duplicity import globals 
 32  from duplicity import gpg 
 33   
 34   
35 -def new_temppath():
36 """ 37 Return a new TempPath 38 """ 39 filename = tempdir.default().mktemp() 40 return TempPath(filename)
41 42
43 -class TempPath(path.Path):
44 """ 45 Path object used as a temporary file 46 """
47 - def delete(self):
48 """ 49 Forget and delete 50 """ 51 path.Path.delete(self) 52 tempdir.default().forget(self.name)
53
54 - def open_with_delete(self, mode):
55 """ 56 Returns a fileobj. When that is closed, delete file 57 """ 58 fh = FileobjHooked(path.Path.open(self, mode)) 59 fh.addhook(self.delete) 60 return fh
61 62
63 -def get_fileobj_duppath(dirpath, partname, permname, remname):
64 """ 65 Return a file object open for writing, will write to filename 66 67 Data will be processed and written to a temporary file. When the 68 return fileobject is closed, rename to final position. filename 69 must be a recognizable duplicity data file. 70 """ 71 if not globals.restart: 72 td = tempdir.TemporaryDirectory(dirpath.name) 73 tdpname = td.mktemp() 74 tdp = TempDupPath(tdpname, parseresults = file_naming.parse(partname)) 75 fh = FileobjHooked(tdp.filtered_open("wb"), tdp = tdp, dirpath = dirpath, 76 partname = partname, permname = permname, remname = remname) 77 else: 78 dp = path.DupPath(dirpath.name, index = (partname,)) 79 fh = FileobjHooked(dp.filtered_open("ab"), tdp = None, dirpath = dirpath, 80 partname = partname, permname = permname, remname = remname) 81 82 def rename_and_forget(): 83 tdp.rename(dirpath.append(partname)) 84 td.forget(tdpname)
85 86 if not globals.restart: 87 fh.addhook(rename_and_forget) 88 89 return fh 90 91
92 -def new_tempduppath(parseresults):
93 """ 94 Return a new TempDupPath, using settings from parseresults 95 """ 96 filename = tempdir.default().mktemp() 97 return TempDupPath(filename, parseresults = parseresults)
98 99
100 -class TempDupPath(path.DupPath):
101 """ 102 Like TempPath, but build around DupPath 103 """
104 - def delete(self):
105 """ 106 Forget and delete 107 """ 108 path.DupPath.delete(self) 109 tempdir.default().forget(self.name)
110
111 - def filtered_open_with_delete(self, mode):
112 """ 113 Returns a filtered fileobj. When that is closed, delete file 114 """ 115 fh = FileobjHooked(path.DupPath.filtered_open(self, mode)) 116 fh.addhook(self.delete) 117 return fh
118
119 - def open_with_delete(self, mode = "rb"):
120 """ 121 Returns a fileobj. When that is closed, delete file 122 """ 123 assert mode == "rb" # Why write a file and then close it immediately? 124 fh = FileobjHooked(path.DupPath.open(self, mode)) 125 fh.addhook(self.delete) 126 return fh
127 128
129 -class FileobjHooked:
130 """ 131 Simulate a file, but add hook on close 132 """
133 - def __init__(self, fileobj, tdp = None, dirpath = None, 134 partname = None, permname = None, remname = None):
135 """ 136 Initializer. fileobj is the file object to simulate 137 """ 138 self.fileobj = fileobj # the actual file object 139 self.closed = False # True if closed 140 self.hooklist = [] # filled later with thunks to run on close 141 self.tdp = tdp # TempDupPath object 142 self.dirpath = dirpath # path to directory 143 self.partname = partname # partial filename 144 self.permname = permname # permanent filename 145 self.remname = remname # remote filename
146
147 - def write(self, buf):
148 """ 149 Write fileobj, return result of write() 150 """ 151 return self.fileobj.write(buf)
152
153 - def flush(self):
154 """ 155 Flush fileobj and force sync. 156 """ 157 self.fileobj.flush() 158 os.fsync(self.fileobj.fileno())
159
160 - def to_partial(self):
161 """ 162 We have achieved the first checkpoint, make file visible and permanent. 163 """ 164 assert not globals.restart 165 self.tdp.rename(self.dirpath.append(self.partname)) 166 self.fileobj.flush() 167 del self.hooklist[0]
168
169 - def to_remote(self):
170 """ 171 We have written the last checkpoint, now encrypt or compress 172 and send a copy of it to the remote for final storage. 173 """ 174 pr = file_naming.parse(self.remname) 175 src = self.dirpath.append(self.partname) 176 tgt = self.dirpath.append(self.remname) 177 src_iter = SrcIter(src) 178 if pr.compressed: 179 gpg.GzipWriteFile(src_iter, tgt.name, size = sys.maxint) 180 elif pr.encrypted: 181 gpg.GPGWriteFile(src_iter, tgt.name, globals.gpg_profile, size = sys.maxint) 182 else: 183 os.system("cp -p \"%s\" \"%s\"" % (src.name, tgt.name)) 184 globals.backend.move(tgt) #@UndefinedVariable
185
186 - def to_final(self):
187 """ 188 We are finished, rename to final, gzip if needed. 189 """ 190 src = self.dirpath.append(self.partname) 191 tgt = self.dirpath.append(self.permname) 192 src_iter = SrcIter(src) 193 pr = file_naming.parse(self.permname) 194 if pr.compressed: 195 gpg.GzipWriteFile(src_iter, tgt.name, size = sys.maxint) 196 os.unlink(src.name) 197 else: 198 os.rename(src.name, tgt.name)
199
200 - def read(self, length = -1):
201 """ 202 Read fileobj, return result of read() 203 """ 204 return self.fileobj.read(length)
205
206 - def tell(self):
207 """ 208 Returns current location of fileobj 209 """ 210 return self.fileobj.tell()
211
212 - def seek(self, offset):
213 """ 214 Seeks to a location of fileobj 215 """ 216 return self.fileobj.seek(offset)
217
218 - def close(self):
219 """ 220 Close fileobj, running hooks right afterwards 221 """ 222 assert not self.fileobj.close() 223 for hook in self.hooklist: 224 hook()
225
226 - def addhook(self, hook):
227 """ 228 Add hook (function taking no arguments) to run upon closing 229 """ 230 self.hooklist.append(hook)
231 232
233 - def get_name(self):
234 """ 235 Return the name of the file 236 """ 237 return self.fileobj.name
238 239 name = property(get_name)
240 241
242 -class Block:
243 """ 244 Data block to return from SrcIter 245 """
246 - def __init__(self, data):
247 self.data = data
248
249 -class SrcIter:
250 """ 251 Iterate over source and return Block of data. 252 """
253 - def __init__(self, src):
254 self.src = src 255 self.fp = src.open("rb")
256 - def next(self, size):
257 try: 258 res = Block(self.fp.read(size)) 259 except Exception: 260 log.FatalError(_("Failed to read %s: %s") % 261 (self.src.name, sys.exc_info()), 262 log.ErrorCode.generic) 263 if not res.data: 264 self.fp.close() 265 raise StopIteration 266 return res
269