aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xfusearchive.py71
1 files changed, 45 insertions, 26 deletions
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