From 963a0cd98366ecd6b72c9c824f87f876796536c2 Mon Sep 17 00:00:00 2001 From: Steve Slaven Date: Mon, 27 Jul 2009 22:44:41 -0700 Subject: Modified to open a fh at the init using the mode requested, and just shuttling the pickle data in and out of this fh so the cp -a on files with perm of 444 should work correctly diff --git a/fusearchive.py b/fusearchive.py index 13d56dd..f8cce35 100755 --- a/fusearchive.py +++ b/fusearchive.py @@ -24,7 +24,7 @@ fuse.feature_assert('stateful_files', 'has_init') magic_profiling = False enable_stats = False enable_psyco = False -debug_level = 0 +debug_level = 3 # These control some of the file output magic_blocksize = 1024 * 128 @@ -39,6 +39,15 @@ dirty_size = 1024 * 1024 * 1; # This is the number of actualy blocks in that size dirty_flush = int( dirty_size / magic_blocksize ) +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)] + + if flags | os.O_APPEND: + m = m.replace('w', 'a', 1) + + return m + def dmsg(level,message): if level <= debug_level: print str(level) + ": " + str(message) @@ -257,25 +266,7 @@ class FuseArchiveStream: """This just allows switching out writer classes easily""" @staticmethod def open( path, mode = 'r' ): - # This was added to fix the case of copying a read-only file, cp - # will create the new file then it gets chmod or something but we - # don't keep an fh around to write to later, we open and close it - # every time we need to update the file info. We should keep an fh - # around from creation time and use that instead though and allow - # passing an fh here instead of a filename - if os.path.exists( path ): - st = os.stat( path ) - # Make it writable - os.chmod( path, stat.S_IWUSR ) - else: - st = None - fh = gzip.open( path, mode, gzip_compress_level ) - - if st: - # Reset permissions - os.chmod( path, st.st_mode ) - #fh = open( path, mode ) return fh @@ -284,20 +275,36 @@ class FuseArchiveSerializer: @staticmethod def dump( file, obj ): out = FuseArchiveStream.open( file, "wb" ) - if not magic_profiling: - cPickle.dump( obj, out, -1 ) # new file format + FuseArchiveSerializer.dumpfh( obj, out, -1 ) # new file format out.close() @staticmethod + def dumpfh( fh, obj ): + fh.truncate( 0 ) + file = gzip.GzipFile( None, "wb", gzip_compress_level, fh ) + #file = fh + cPickle.dump( obj, file, -1 ) # new file format + file.flush() + + @staticmethod def load( file ): if magic_profiling: return { 'size': 0, 'chunks': 0, 'chunk_size': 0 } inp = FuseArchiveStream.open( file, "rb" ) - magic = cPickle.load( inp ) + magic = FuseArchiveSerialize.loadfh( inp ) inp.close() return magic + @staticmethod + def loadfh( fh ): + fh.seek( 0 ) + file = gzip.GzipFile( None, "rb", gzip_compress_level, fh ) + #file = fh + #pdb.set_trace() + magic = cPickle.load( file ) + return( magic ) + class FuseArchiveStat(fuse.Stat): def __init__(self, stat): self.st_mode = stat.st_mode @@ -483,11 +490,22 @@ class FuseArchive(Fuse): self.offset = -1 if os.path.exists( "./tree" + self.orig_path ): + preexist = True + else: + preexist = False + + # Open the file now and keep the fh around so that cp -a on r/o + # files works (in the create a read-only file for writing case) + src = "./tree" + path + dmsg( 3, "Saving fh for " + src ) + self.file = os.fdopen( os.open( src, flags, *mode ), + flag2mode( flags ) ) + + if preexist: # Read in file info table - src = "./tree" + self.orig_path - dmsg( 3, "Unpickling: " + src ) + dmsg( 3, "Unpickling: " + str( self.file ) ) # TODO: return an IO error if inflating fails - magic = FuseArchiveSerializer.load( src ) + magic = FuseArchiveSerializer.loadfh( self.file ) dmsg( 3, "Got data: " + str( magic ) ) self.size = magic[ 'size' ] self.chunks = magic[ 'chunks' ] @@ -679,6 +697,7 @@ class FuseArchive(Fuse): # Deflate the file dmsg( 2, "Release: " + self.orig_path ) self.flush() + self.file.close() def _fflush(self): if self.wr and self.modified: @@ -704,7 +723,7 @@ class FuseArchive(Fuse): dmsg( 3, "Size calculated is: " + str( self.size ) ) - FuseArchiveSerializer.dump( "./tree" + self.orig_path, { + FuseArchiveSerializer.dumpfh( self.file, { 'size': self.size, 'chunks': self.chunks, 'chunk_size': self.chunk_size -- cgit v0.10.2