Avoid 00changelog.i corruption

Ingo Proetel proetel at aicas.de
Tue Jul 21 09:33:46 CDT 2009


Ingo Proetel wrote:
> Matt Mackall wrote:
>> There are lots of places we append to files, is this the only one
>> affected? Are the nuls at the end of the file or somewhere else?
>>
> Yes, there are several places where this could happen. So probably a more general solution is required:
> A new class 'appender' util.py could be used to create a copy of the original file and return a special sub class of
> posixfile. This subclass would forward the written data to the copy and on close() do the rename.
> 
> In most of the other places opener(xxx , 'a') would be replaced with appender(xxx).
> 
I looked at the code and found that most of the required stuff is there already. So the following patch is more generic.
(For my original problem this detects that the written file is broken and aborts cleanly.)

Cheers,
Ingo


changeset:   9047:db5c3797dfba
tag:         tip
parent:      9045:996c1cd8f530
user:        Ingo Proetel <proetel at aicas.com>
date:        Tue Jul 21 16:21:15 2009 +0200
summary:     Force all file writes through atomictempfile. This allows additional checks to avoid file corruption as
much as possible.

diff -r 996c1cd8f530 -r db5c3797dfba mercurial/util.py
--- a/mercurial/util.py	Tue Jul 14 14:05:07 2009 +0200
+++ b/mercurial/util.py	Tue Jul 21 16:21:15 2009 +0200
@@ -775,6 +775,8 @@
             ofp.write(chunk)
         ifp.close()
         ofp.close()
+        if not os.path.getsize(ifp.name) == os.path.getsize(ofp.name):
+            raise IOError, "could ot create proper copy of "+ifp.name
     except:
         try: os.unlink(temp)
         except: pass
@@ -794,6 +796,7 @@
         self.temp = mktempcopy(name, emptyok=('w' in mode),
                                createmode=createmode)
         self._fp = posixfile(self.temp, mode)
+        self._written = 0

     def __getattr__(self, name):
         return getattr(self._fp, name)
@@ -801,8 +804,22 @@
     def rename(self):
         if not self._fp.closed:
             self._fp.close()
+            if not os.path.getsize(self.temp) == os.path.getsize(self.__name)+self._written:
+                raise IOError, "corrupt copy of "+self.__name
             rename(self.temp, localpath(self.__name))

+    def close(self):
+        self.rename()
+
+    def write(self,string):
+        self._written += len(string)
+        self._fp.write(string)
+
+    def writelines(self,lines):
+        for line in lines:
+          self._written += len(line)
+        self._fp.write(lines)
+
     def __del__(self):
         if not self._fp:
             return
@@ -869,10 +886,7 @@
                 d = os.path.dirname(f)
                 if not os.path.isdir(d):
                     makedirs(d, self.createmode)
-            if atomictemp:
-                return atomictempfile(f, mode, self.createmode)
-            if nlink > 1:
-                rename(mktempcopy(f), f)
+            return atomictempfile(f, mode, self.createmode)
         fp = posixfile(f, mode)
         if nlink == 0:
             self._fixfilemode(f)


-- 
aicas Allerton Interworks Computer Automated Systems GmbH
Haid-und-Neu-Straße 18 * D-76131 Karlsruhe * Germany
http://www.aicas.com   * Tel: +49-721-663 968-0

USt-Id: DE216375633, Handelsregister HRB 109481, AG Karlsruhe
Geschäftsführer: Dr. James J. Hunt



More information about the Mercurial mailing list