Example #1
0
	def __initialize(self):
		try:
			X = self.getCover
		except:
			self.getCover = "Dont Care"

		self.logger = TagHelper.getLogger('DHTFS')
		self.tagdir = TagDir(db_path=self.root, db_file=self.DB_FILE, logger=self.logger)
		self.__initSequenceNumberGenerator()

		self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
		self.logger.info("Tagging and TagDir instances created for path %s" % self.root)
		self.logger.info("self.getCover = %s" % self.getCover)
Example #2
0
class Dhtfs(Fuse):

	MAX_DIR_ENTRIES = 210
	MISSING_FILE = '__MISSING_FILE_qwertyuiopasdfghjklzxcvbnm0987654321'		

	DB_FILE = '.dhtfs.db'
	SEQ_FILE = '.dhtfs.seq'

	def checkSetup(cls, path):
		"""
		D.checkSetup() -> Check whether dhtfs filesystem is setup at path

		@param path: Path to be checked
		@type path: str

		@return: True is dhtfs is setup at path, False otherwise
		@rtype: bool
		"""

		if not Tagging.checkSetup(db_path=path, db_file=cls.DB_FILE):	
			return False
		if not GPStor.checkSetup(db_path=path, db_file=cls.SEQ_FILE):
			return False

		return True
		
	checkSetup = classmethod(checkSetup)

	def setup(cls, path, forceInit=False):
		"""
		D.setup(path, forceInitFlag) -> Do the necessary setup to mount the specified path as a dhtfs file system

		@param path: Path for which to setup
		@type path: str

		@param forceInit: If forceInit is True, do a new setup regardless of whether an older setup is present.
		@type forceInit: bool
		"""

		# If forceInit flag is true, clean up the directory
		if forceInit:
			for root, dirs, files in os.walk(path, topdown=False):
				for name in files:
					os.remove(os.path.join(root, name))
				for name in dirs:
					os.rmdir(os.path.join(root, name))

		# Initialize tagging

		t = Tagging(db_path=path, db_file=cls.DB_FILE)
		t.initDB(forceInit = forceInit)

		# Initialize sequence generator
		seqStore = GPStor(db_path=path, db_file=cls.SEQ_FILE)

		ret, currentSeqNumber = seqStore.getDataRO()

		if (ret != 0) or (not isinstance(currentSeqNumber, long) ) or forceInit:
			seqStore.getDataRW()
			currentSeqNumber = long(0)
			seqStore.writeData(currentSeqNumber)

	setup = classmethod(setup)

	def __init__(self, *args, **kw):

		Fuse.__init__(self, *args, **kw)
		self.fileCache = {}

	def __initialize(self):
		try:
			X = self.getCover
		except:
			self.getCover = "Dont Care"

		self.logger = TagHelper.getLogger('DHTFS')
		self.tagdir = TagDir(db_path=self.root, db_file=self.DB_FILE, logger=self.logger)
		self.__initSequenceNumberGenerator()

		self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
		self.logger.info("Tagging and TagDir instances created for path %s" % self.root)
		self.logger.info("self.getCover = %s" % self.getCover)

	def __initSequenceNumberGenerator(self):
		self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
		self.seqStore = GPStor(db_path=self.root, db_file='.dhtfs.seq')
		ret, self.currentSeqNumber = self.seqStore.getDataRO()
		if ret != 0:
			self.seqStore.getDataRW()
			self.currentSeqNumber = long(0)
			self.seqStore.writeData(self.currentSeqNumber)
			self.logger.info("Initialized seq store with %s" % long(0))
			
	def __getNextSeqNumber(self):
		self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
		ret, num = self.seqStore.getDataRW()
		self.logger.info("ret = %s, num = %s" % (ret, num))
		self.currentSeqNumber = num + 1
		self.seqStore.writeData(self.currentSeqNumber)
		return self.currentSeqNumber

	def getActualPath(self, path):
		self.logger.info("In function : %s" % sys._getframe().f_code.co_name)

		if path in self.fileCache:
			self.logger.info("CACHE: Path %s found in cache" % path)
			self.logger.info("CACHE: ActualPath = %s" % self.fileCache[path])
			return self.fileCache[path]

		if path == '/':
			self.logger.info("Path is root directory")
			actualPath = self.root

		elif self.tagdir.isDir(os.path.basename(path)):
			dirpath = os.path.dirname(path)
			dirname = os.path.basename(path)
			fileInstances, dirs = self.getDirectoryEntries(dirpath)
			self.logger.info("dirname = %s, dirs = %s" % (dirname, dirs))
			if dirname in dirs:
				self.logger.info("Path is directory")
				actualPath = os.path.join(self.root, 't_' + os.path.basename(path))
			else:
				self.logger.info("Directory not found here")
				actualPath = os.path.join(self.root, Dhtfs.MISSING_FILE)
		else:
			self.logger.info("get actual path from TagHelper")
			dirs = [x for x in os.path.dirname(path).split(os.path.sep) if x != '']
			filename = os.path.basename(path)
			actualLocation = self.tagdir.getActualLocation(dirs, filename)
			if actualLocation:
				actualPath = os.path.join(self.root, actualLocation)
			else:
				actualPath = os.path.join(self.root, Dhtfs.MISSING_FILE)

		self.logger.info("Path =  %s, ActualPath =  %s" % (path, actualPath))
		
		# Add path to cache
		self.logger.info("CACHE: Adding path %s to cache" % path)
		self.fileCache[path] = actualPath

		return actualPath

	def opendir(self, path):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		self.logger.info("path = %s" % path)

	def releasedir(self, path):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		self.logger.info("path = %s" % path)

	def getattr(self, path):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		self.logger.info("path = %s" % path)
		return os.lstat(self.getActualPath(path))

	def readdir(self, path, offset):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		self.logger.info("path = %s" % path)

		fileInstances, dirs = self.getDirectoryEntries(path)

		# Cache the mapping between 'location in our file system' -> 'location in the underlying file system'
		self.logger.info("CACHE: Clearing cache")
		self.fileCache.clear()
		self.fileCache.update([(os.path.join(path, f.name), os.path.join(self.root, f.location)) for f in fileInstances])
		self.fileCache.update([(os.path.join(path, dir), os.path.join(self.root, 't_' + dir)) for dir in dirs])
		self.logger.info("CACHE: Added info for dir %s to cache" % path)

		# Get file names from the file object
		filenames = [f.name for f in fileInstances] 

		# Create a generator for the directory entries
		for e in filenames + dirs:
			yield fuse.Direntry(e)

	def getDirectoryEntries(self, path):
		# Get the directories in the specified path
		# The directories in the path will be treated as tags
		dirsInPath = [x for x in path.split(os.path.sep) if x != '']

		# get files and directories associated with the given tags
		if self.getCover != 'Always':
			dirs, files = self.tagdir.getDirsAndFilesForDirs(dirsInPath, beRestrictive=True)
			self.logger.info("After getDirsAndFilesForDirs beRestrictive=True, \
					dirs = %s, files = %s" %(dirs, files))

		# Too many directory entries cause problems
		#	It takes too long to display all entries
		#	Too cumbersome to go through all the entries
		#
		# If we get too many directory entries just get tags which cover
		# all the files + the remaining files
		if (self.getCover == 'Always') or len(files) < 2 or \
				(	len(dirs) > 0 and 
					len(dirs) + len(files) > Dhtfs.MAX_DIR_ENTRIES and
					self.getCover != 'Never'
				):
			dirs, files = self.tagdir.getDirsAndFilesForDirs(dirsInPath, getCover=True)
			self.logger.info("After getDirsAndFilesForDirs getCover=True, \
					dirs = %s, files = %s" %(dirs, files))
				
		files = [f for f in files if f.location != Dhtfs.MISSING_FILE]

		self.logger.info("Returning Dir entries = %s, %s" % (files, dirs))
		return files, dirs

	def rmdir(self, path):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		self.tagdir.delDirs([os.path.basename(path)])

		# Clear cache
		self.logger.info("CACHE: Clearing cache")
		self.fileCache.clear()

	def rename(self, path, path1):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)

		self.logger.info("rename %s to %s" %(path, path1))
		if self.tagdir.isDir(os.path.basename(path)): # Path is a directory
			self.logger.info("Renaming dir %s to %s" % (path, path1))
			dirs = [x for x in path.split(os.path.sep) if x != '']
			dirs1 = [x for x in path1.split(os.path.sep) if x != '']
			self.logger.info("Renaming dir %s to %s" % (dirs, dirs1))
			self.tagdir.renameDir(dirs, dirs1)

		else: # Path is a file
			dirs = [x for x in os.path.dirname(path).split(os.path.sep) if x != '']

			# create an instance of class TagFile
			filename = os.path.basename(path)
			location = self.tagdir.getActualLocation(dirs, filename)

			fi = TagFile(location, filename)

			# Remove the directories asociated with the file
			self.tagdir.delFiles([fi], dirs)
			self.logger.info("Deleted %s" % path)

			# change name of file
			newfilename = os.path.basename(path1)
			fi = TagFile(location, newfilename)

			# Associate directories to the file
			dirs = [x for x in os.path.dirname(path1).split(os.path.sep) if x != '']
			self.tagdir.addDirsToFiles([fi], dirs)

		# Clear cache
		self.logger.info("CACHE: Clearing cache")
		self.fileCache.clear()

	def chmod(self, path, mode):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		os.chmod(self.getActualPath(path), mode)

	def chown(self, path, user, group):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		os.chown(self.getActualPath(path), user, group)

	def truncate(self, path, len):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		f = open(self.getActualPath(path), "a")
		f.truncate(len)
		f.close()

	def mkdir(self, path, mode):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		dirs = [x for x in path.split(os.path.sep) if x != '']
		nf = TagFile(Dhtfs.MISSING_FILE, self.generateNewFileName())
		self.tagdir.addDirsToFiles([nf], dirs, mode)

		if path in self.fileCache:
			self.logger.info("CACHE: Remove entry for path %s" % path)
			del self.fileCache[path]

	def utime(self, path, times):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		os.utime(self.getActualPath(path), times)

	def access(self, path, mode):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		if not os.access(self.getActualPath(path), mode):
			return -EACCES

	def statfs(self):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)
		"""
		Should return an object with statvfs attributes (f_bsize, f_frsize...).
		Eg., the return value of os.statvfs() is such a thing (since py 2.2).
		If you are not reusing an existing statvfs object, start with
		fuse.StatVFS(), and define the attributes.

		To provide usable information (ie., you want sensible df(1)
		output, you are suggested to specify the following attributes:

			- f_bsize - preferred size of file blocks, in bytes
			- f_frsize - fundamental size of file blcoks, in bytes
				[if you have no idea, use the same as blocksize]
			- f_blocks - total number of blocks in the filesystem
			- f_bfree - number of free blocks
			- f_files - total number of file inodes
			- f_ffree - nunber of free file inodes
		"""

		return os.statvfs(self.root)

	def unlink(self, path):
		self.logger.info("###### In function : %s" % sys._getframe().f_code.co_name)

		# Get dirs in path
		dirs = [x for x in os.path.dirname(path).split(os.path.sep) if x != '']

		# create an instance of class TagFile
		filename = os.path.basename(path)
		fi = TagFile(self.tagdir.getActualLocation(dirs, filename), filename)

		# Remove the directories asociated with the file
		if len( self.tagdir.getDirsForFiles([fi]) ) > 0:
			self.logger.info("Calling delFiles with fileList = %s, dirlist = %s" % ([fi], dirs))
			self.tagdir.delFiles([fi], dirs)
			self.logger.info("Deleted %s" % path)

		# If all directories asociated with the file are removed remove the file
		if len( self.tagdir.getDirsForFiles([fi]) ) == 0:
			actualPath = self.getActualPath(path)
			self.logger.info("Deleting actual file since last reference is being deleted")	
			self.logger.info("Calling delFiles with fileList = %s" % [fi])
			self.tagdir.delFiles([fi])
			self.logger.info("Deleting actual file %s" % actualPath)
			os.unlink(actualPath)

		# Clear cache
		self.logger.info("CACHE: Clearing cache")
		self.fileCache.clear()

	def generateNewFileName(self):
		number = self.__getNextSeqNumber()
		newfilename = 'f_' + ('%x' % number).rjust(32, '0')
		self.logger.info("newfilename = %s" % newfilename)
		actualPath = newfilename

		return actualPath

	def main(self, *a, **kw):

		# Define the file class locally as that seems to be the easiest way to
		# inject instance specific data into it...

		server = self

		if server.fuse_args.mount_expected():
			server.__initialize()

		class DhtfsFile(object):

			def __init__(self, path, flags, *mode):
				# set logger
				self.logger = server.logger
				self.logger.info("###### Initiating file object In function : %s" % sys._getframe().f_code.co_name)

				# set the dirs which are associated with this file
				self.dirs = [x for x in os.path.dirname(path).split(os.path.sep) if x != '']

				# Get actual path for the specified path
				actualPath = server.getActualPath(path)

				newCreated = False
				if os.path.basename(actualPath) == Dhtfs.MISSING_FILE:
					# File is not yet created. Create file
					self.logger.info("Actual path missing")
					actualPath = server.generateNewFileName()
					newCreated = True
					if path in server.fileCache:
						self.logger.info("CACHE: Remove entry for path %s" % path)
						del server.fileCache[path]

				self.file = os.fdopen(os.open(os.path.join(server.root, actualPath), flags, *mode),
										flag2mode(flags))
				self.fd = self.file.fileno()

				filename = os.path.basename(path)
				self.fi = TagFile(actualPath, filename)

				if newCreated:
					self.logger.info("Adding tags %s, to file %s" %(self.dirs, self.fi))
					# Add tag information for the newly created file
					server.tagdir.addDirsToFiles([self.fi], self.dirs)

			def read(self, length, offset):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				self.file.seek(offset)
				return self.file.read(length)

			def write(self, buf, offset):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				self.file.seek(offset)
				self.file.write(buf)
				return len(buf)

			def release(self, flags):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				self.file.close()

			def fsync(self, isfsyncfile):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				if isfsyncfile and hasattr(os, 'fdatasync'):
					os.fdatasync(self.fd)
				else:
					os.fsync(self.fd)

			def flush(self):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				self.file.flush()
				# cf. xmp_flush() in fusexmp_fh.c
				os.close(os.dup(self.fd))

			def fgetattr(self):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				return os.fstat(self.fd)

			def ftruncate(self, len):
				self.logger.info("In function : %s" % sys._getframe().f_code.co_name)
				self.file.truncate(len)

		self.file_class = DhtfsFile

		return Fuse.main(self, *a, **kw)