aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xfusearchive.py84
1 files changed, 49 insertions, 35 deletions
diff --git a/fusearchive.py b/fusearchive.py
index 6f6305f..328ee49 100755
--- a/fusearchive.py
+++ b/fusearchive.py
@@ -2,6 +2,7 @@
# Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
# Copyright (C) 2006 Csaba Henk <csaba.henk@creo.hu>
+# Copyright (C) 2009 Steve Slaven <bpk@hoopajoo.net>
#
# This program can be distributed under the terms of the GNU LGPL.
# See the file COPYING.
@@ -25,6 +26,11 @@ fuse.feature_assert('stateful_files', 'has_init')
magic_blocksize = 1024 * 32
magic_depth = 5
+debug_level = 2
+
+def dmsg(level,message):
+ if level <= debug_level:
+ print str(level) + ": " + message
def flag2mode(flags):
md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
@@ -39,16 +45,16 @@ def flag2mode(flags):
# should go
# we assume our chunks are in storage/
def inflate( src, dest ):
- print "inflate!"
+ dmsg( 1, "inflate!" )
out = open( dest, "w" )
- print "Unpickling: " + src
+ dmsg( 2, "Unpickling: " + src )
# TODO: return an IO error if inflating fails
inp = gzip.open( src, "r" )
magic = pickle.load( inp )
inp.close()
- print "Got data: " + str( magic )
+ dmsg( 2, "Got data: " + str( magic ) )
#pdb.set_trace()
@@ -57,27 +63,27 @@ def inflate( src, dest ):
( hash, seq ) = key
chars = list( hash )
- print chars
+ dmsg( 4, chars )
# Todo: make a digest -> path function to share with deflate
hexdigest = ''.join( [ "%02x" % ord( x ) for x in chars ] );
subparts = [ "%02x" % ord( x ) for x in chars[ :magic_depth ] ]
subpath = '/'.join( subparts );
- print "Subpath: " + subpath
+ dmsg( 3, "Subpath: " + subpath )
subpath += "/" + hexdigest + "_" + str( seq );
- print "Chunk path: " + subpath
+ dmsg( 3, "Chunk path: " + subpath )
if os.path.exists( "./storage/" + subpath ):
- print "Exporting chunk"
+ dmsg( 3, "Exporting chunk" )
readchunk = gzip.open( "./storage/" + subpath )
out.write( readchunk.read() )
readchunk.close()
else:
raise IOError
- print "File inflated"
+ dmsg( 2, "File inflated" )
out.close()
# TODO: deflate only if the file has been modified
@@ -85,7 +91,7 @@ def inflate( src, dest ):
# Deflate a file, src is the unpacked file, dest is where we want to pack
# to, and we assume storage/ is where chunks are stored
def deflate( src, dest ):
- print "deflate!"
+ dmsg( 2, "deflate!" )
inp = open( src, "r" )
hashs = [];
@@ -106,7 +112,7 @@ def deflate( src, dest ):
# Write out our chunk
chars = list( digest )
- print chars
+ dmsg( 4, chars )
# We make the hexdigest here, yeah we could just call hexdigest()
# but we need to essentially do this same thing to reassemble the
@@ -116,23 +122,23 @@ def deflate( src, dest ):
# Subparts just needs the first N chars
subparts = [ "%02x" % ord( x ) for x in chars[ :magic_depth ] ]
- print subparts
+ dmsg( 4, subparts )
subpath = '/'.join( subparts );
- print "Subpath: " + subpath
+ dmsg( 3, "Subpath: " + subpath )
# Make sure this sub path exists
nextpart = "./storage"
for part in subparts:
nextpart += "/" + part
if not os.path.exists( nextpart ):
- print "Creating subdir: " + nextpart
+ dmsg( 3, "Creating subdir: " + nextpart )
os.mkdir( nextpart )
# Find a chunk slot
sub = 0
while True:
checkpath = "./storage/" + subpath + "/" + hexdigest + "_" + str( sub )
- print "Checking: " + checkpath
+ dmsg( 3, "Checking: " + checkpath )
if os.path.exists( checkpath ):
# Check if this is our data
verify = gzip.open( checkpath, "r" )
@@ -140,20 +146,20 @@ def deflate( src, dest ):
verify.close()
if verify_contents == chunk:
- print "Found existing block"
+ dmsg( 2, "Found existing block" )
break
else:
- print "Block exists but is not the same"
+ dmsg( 2, "Block exists but is not the same" )
sub += 1
else:
# We found a spot, dump our data here
- print "No block here, creating new block"
+ dmsg( 2, "No block here, creating new block" )
savechunk = gzip.open( checkpath, "w" )
savechunk.write( chunk )
savechunk.close
break
- print "Got chunk slot: " + str( sub )
+ dmsg( 2, "Got chunk slot: " + str( sub ) )
hashs.append( [ digest, sub ] )
inp.close()
@@ -195,7 +201,7 @@ class FuseArchive(Fuse):
stats = os.lstat( treefile )
if os.path.isfile( treefile ):
- print "Reading file to get size: " + path
+ dmsg( 3, "Reading file to get size: " + path )
#pdb.set_trace()
@@ -204,7 +210,7 @@ class FuseArchive(Fuse):
magic = pickle.load( inp )
inp.close()
- print "Overridding getattr"
+ dmsg( 3, "Overridding getattr" )
stats = FuseArchiveStat( stats, magic[ 'stat' ] )
return stats
@@ -238,9 +244,11 @@ class FuseArchive(Fuse):
os.chown("./tree" + path, user, group)
def truncate(self, path, len):
- f = open("./tree" + path, "a")
- f.truncate(len)
- f.close()
+ # Truncate using the ftruncate on the file
+ dmsg( 2, "Using FuseArchiveFile to truncate " + path + " to " + str(len) )
+ f = self.FuseArchiveFile( path, os.O_APPEND, 0 )
+ f.ftruncate(len)
+ f.release( 0 )
def mknod(self, path, mode, dev):
os.mknod("./tree" + path, mode, dev)
@@ -310,56 +318,62 @@ class FuseArchive(Fuse):
def __init__(self, path, flags, *mode):
# Inflate the file
- print "Init file: " + path
+ dmsg( 2, "Init file: " + path )
self.orig_path = path;
( fdnum, self.tmp_name ) = tempfile.mkstemp();
#os.close( fdnum );
if os.path.exists( "./tree" + self.orig_path ):
inflate( "./tree" + path, self.tmp_name )
+ else:
+ if re.match( '(a|w)', flag2mode( flags ) ):
+ dmsg( 2, "File doesn't exist and we're going to write, creating temp empty file" )
+ deflate( "/dev/null", "./tree" + path )
- print "Shadow file: " + self.tmp_name + " for " + self.orig_path
- print "Going to open shadow file with flags: " + str(flags) + " mode " + str(mode)
+ dmsg( 2, "Shadow file: " + self.tmp_name + " for " + self.orig_path )
+ dmsg( 2, "Going to open shadow file with flags: " + str(flags) + " mode " + str(mode) )
# pdb.set_trace()
- print "Flag2mode is: " + str( flag2mode( flags ) )
+ dmsg( 2, "Flag2mode is: " + str( flag2mode( flags ) ) )
# Just use the fdnum they gave us instead of reopening it,
# since that might fail
# fdnum = os.open( self.tmp_name, flags, *mode )
#print "Got fdnum: " + str(fdnum)
self.file = os.fdopen( fdnum, flag2mode( flags ) )
- print "Open"
+ dmsg( 2, "Open" )
self.fd = self.file.fileno()
self.direct_io = False
self.keep_cache = False
- print str(self) + " init complete"
+ self.modified = False
+
+ dmsg( 2, str(self) + " init complete" )
def read(self, length, offset):
- print "Reading from " + self.orig_path
+ dmsg( 2, "Reading from " + self.orig_path )
self.file.seek(offset)
return self.file.read(length)
def write(self, buf, offset):
- print "Writing to " + self.orig_path
+ dmsg( 2, "Writing to " + self.orig_path )
self.file.seek(offset)
self.file.write(buf)
return len(buf)
def release(self, flags):
# Deflate the file
- print "Release: " + self.orig_path
+ dmsg( 2, "Release: " + self.orig_path )
self.file.close()
- print "Copying working file back to storage: " + \
- self.tmp_name + " -> " + self.orig_path
+ dmsg( 2, "Copying working file back to storage: " + \
+ self.tmp_name + " -> " + self.orig_path )
#pdb.set_trace()
deflate( self.tmp_name, "./tree" + self.orig_path );
- print "Deleting old file: " + self.tmp_name
+ dmsg( 2, "Deleting old file: " + self.tmp_name )
os.unlink( self.tmp_name );
def _fflush(self):