#!/usr/bin/python
"""
This module makes it possible to ensure that data is not corrupted
between files whose version numbers are not important but must be
synchronized. It protects these files from crashes. It does, however,
require that critical files do not disappear between executions.
It can only account for cases where the computer does not do what it
is told, not cases where it does what it is not told.
Copyright (c) 2008 Collin Ross Mechlowitz Stocks
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 3 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, see .
"""
import os
class SyncFiles(object):
def __init__(self,pathcons,*paths):
self.pathcons=pathcons
self.paths=list(paths)
self.TEMP="-temp~"
self.BACK="-back~"
self.PACKETSIZE=1<<20
def _testfiles(self):
if os.path.exists(self.pathcons):
#update had not even been called yet, so temps are bad
#and currs are not bad
return False,False
tempsaregood=True
currsarebad1=False
currsarebad2=False
if not os.path.exists(self.pathcons+self.TEMP):
tempsaregood=False
currsarebad1=True
else:
currsarebad2=True
for path in self.paths:
if not os.path.exists(path+self.TEMP):
tempsaregood=False
currsarebad1=True
else:
currsarebad2=True
return tempsaregood,(currsarebad1 and currsarebad2)
def _safeupdatefrom(self,ext):
for path in self.paths:
fread=open(path+ext,"rb")
fwrite=open(path,"wb")
data=fread.read(self.PACKETSIZE)
while data:
fwrite.write(data)
data=fread.read(self.PACKETSIZE)
fread.close()
fwrite.close()
def openread(self):
ret=[]
tempsaregood,currsarebad=self._testfiles()
if tempsaregood:
self._safeupdatefrom(self.TEMP)
for path in self.paths:
ret.append(open(path,"rb"))
elif currsarebad:
for path in self.paths:
ret.append(open(path+self.BACK,"rb"))
else:
for path in self.paths:
ret.append(open(path,"rb"))
return ret
def openwrite(self):
ret=[]
firsttime=True
for path in self.paths:
if os.path.exists(path):
firsttime=False
if not firsttime:
tempsaregood,currsarebad=self._testfiles()
if tempsaregood:
self._safeupdatefrom(self.TEMP)
elif currsarebad:
self._safeupdatefrom(self.BACK)
open(self.pathcons,"wb").close()
for path in self.paths:
ret.append(open(path+self.TEMP,"wb"))
return ret
def update(self):
os.remove(self.pathcons)
open(self.pathcons+self.TEMP,"wb").close()
for path in self.paths:
try:
os.remove(path+self.BACK)
except OSError:
pass
for path in self.paths:
try:
os.rename(path,path+self.BACK)
except OSError:
pass
os.remove(self.pathcons+self.TEMP)
for path in self.paths:
os.rename(path+self.TEMP,path)