From d8eb6cf4482087f473101e32ef02aba5180093ec Mon Sep 17 00:00:00 2001 From: Steve Slaven Date: Tue, 28 Jul 2009 14:19:04 -0700 Subject: This is a workaround for a bug with lseek causing a getattr instead of fgetattr on an already opened file, so it reports the wrong file size if you use seek_end for whence by reading the on-disk info instead of the open-file info diff --git a/fusearchive.py b/fusearchive.py index a0cdb18..f3567aa 100755 --- a/fusearchive.py +++ b/fusearchive.py @@ -46,6 +46,14 @@ dirty_size = 1024 * 1024 * 1; # This is the number of actualy blocks in that size dirty_flush = int( dirty_size / magic_blocksize ) +# This is a cache of open files by inode, to fix the lseek == size problem +# this causes a failure in fsx-linux becuase to to lseek(fd,0,seek_end) it +# apparently does a getattr to find the file length then subtracts the +# offset from that to pass to write or whatever, since the offset is passed +# to write and we don't maintain one internally. xmp.py also fails this +# test. +dirty_cache = {} + def flag2mode(flags): md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] @@ -344,11 +352,19 @@ class FuseArchive(Fuse): treefile = "./tree" + path if os.path.isfile( treefile ): - logging.debug( "Delegating getattr to FuserArchiveFile" ) - - f = self.FuseArchiveFile( path, os.O_RDONLY, 0 ) - stats = f.fgetattr() - f.release( 0 ) + logging.debug( "Delegating getattr to FuserArchiveFile for " + path ) + + # Check in the dirty cache first (to handle lseek and the + # relatively broken implmentation in fuse/python) + if path in dirty_cache: + logging.info( "WORKAROUND: lseek appears to do a gettattr if whence is SEEK_END, using dirty cache object" ) + f = dirty_cache[ path ] + stats = f.fgetattr() + # no release, it's still being used + else: + f = self.FuseArchiveFile( path, os.O_RDONLY, 0 ) + stats = f.fgetattr() + f.release( 0 ) else: logging.debug( "Using os.lstat to get stats" ) stats = os.lstat( treefile ) @@ -725,6 +741,10 @@ class FuseArchive(Fuse): logging.debug( "Chunk size is now: " + str(len(self.chunk)) ) logging.debug( "File size is now: " + str(self.size) ) + + # Mark us in the dirty cache + dirty_cache[ self.orig_path ] = self + return len(buf) # BUG: If you cp -a a file then quickly ls -l sometimes it doesn't show @@ -766,6 +786,10 @@ class FuseArchive(Fuse): 'chunk_size': self.chunk_size } ) + # Not dirty anymore + if self.orig_path in dirty_cache: + del dirty_cache[ self.orig_path ] + logging.debug( "_fflush exit" ) return 1 @@ -854,6 +878,7 @@ class FuseArchive(Fuse): self.modified = True self.size = length self._load_chunk( 0 ) + # Don't need to mark dirty cache because we're flushing self._fflush() def lock(self, cmd, owner, **kw): -- cgit v0.10.2