mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
	
	
		
			323 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			323 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | """File System Proxy.
 | ||
|  | 
 | ||
|  | Provide an OS-neutral view on a file system, locally or remotely. | ||
|  | The functionality is geared towards implementing some sort of | ||
|  | rdist-like utility between a Mac and a UNIX system. | ||
|  | 
 | ||
|  | The module defines three classes: | ||
|  | 
 | ||
|  | FSProxyLocal  -- used for local access | ||
|  | FSProxyServer -- used on the server side of remote access | ||
|  | FSProxyClient -- used on the client side of remote access | ||
|  | 
 | ||
|  | The remote classes are instantiated with an IP address and an optional | ||
|  | verbosity flag. | ||
|  | """
 | ||
|  | 
 | ||
|  | import server | ||
|  | import client | ||
|  | import md5 | ||
|  | import os | ||
|  | import fnmatch | ||
|  | from stat import * | ||
|  | import time | ||
|  | import fnmatch | ||
|  | 
 | ||
|  | if os.name == 'mac': | ||
|  | 	import macfs | ||
|  | 	maxnamelen = 31 | ||
|  | else: | ||
|  | 	macfs = None | ||
|  | 	maxnamelen = 255 | ||
|  | 
 | ||
|  | skipnames = (os.curdir, os.pardir) | ||
|  | 
 | ||
|  | 
 | ||
|  | class FSProxyLocal: | ||
|  | 	 | ||
|  | 	def __init__(self): | ||
|  | 		self._dirstack = [] | ||
|  | 		self._ignore = ['*.pyc'] + self._readignore() | ||
|  | 	 | ||
|  | 	def _close(self): | ||
|  | 		while self._dirstack: | ||
|  | 			self.back() | ||
|  | 	 | ||
|  | 	def _readignore(self): | ||
|  | 		file = self._hide('ignore') | ||
|  | 		try: | ||
|  | 			f = open(file) | ||
|  | 		except IOError: | ||
|  | 			file = self._hide('synctree.ignorefiles') | ||
|  | 			try: | ||
|  | 				f = open(file) | ||
|  | 			except IOError: | ||
|  | 				return [] | ||
|  | 		ignore = [] | ||
|  | 		while 1: | ||
|  | 			line = f.readline() | ||
|  | 			if not line: break | ||
|  | 			if line[-1] == '\n': line = line[:-1] | ||
|  | 			ignore.append(line) | ||
|  | 		f.close() | ||
|  | 		return ignore | ||
|  | 	 | ||
|  | 	def _hidden(self, name): | ||
|  | 		if os.name == 'mac': | ||
|  | 			return name[0] == '(' and name[-1] == ')' | ||
|  | 		else: | ||
|  | 			return name[0] == '.' | ||
|  | 	 | ||
|  | 	def _hide(self, name): | ||
|  | 		if os.name == 'mac': | ||
|  | 			return '(%s)' % name | ||
|  | 		else: | ||
|  | 			return '.%s' % name | ||
|  | 	 | ||
|  | 	def visible(self, name): | ||
|  | 		if len(name) > maxnamelen: return 0 | ||
|  | 		if name[-1] == '~': return 0 | ||
|  | 		if name in skipnames: return 0 | ||
|  | 		if self._hidden(name): return 0 | ||
|  | 		head, tail = os.path.split(name) | ||
|  | 		if head or not tail: return 0 | ||
|  | 		if macfs: | ||
|  | 			if os.path.exists(name) and not os.path.isdir(name): | ||
|  | 				try: | ||
|  | 					fs = macfs.FSSpec(name) | ||
|  | 					c, t = fs.GetCreatorType() | ||
|  | 					if t != 'TEXT': return 0 | ||
|  | 				except macfs.error, msg: | ||
|  | 					print "***", name, msg | ||
|  | 					return 0 | ||
|  | 		else: | ||
|  | 			if os.path.islink(name): return 0 | ||
|  | 			if '\0' in open(name, 'rb').read(512): return 0 | ||
|  | 		for ign in self._ignore: | ||
|  | 			if fnmatch.fnmatch(name, ign): return 0 | ||
|  | 		return 1 | ||
|  | 	 | ||
|  | 	def check(self, name): | ||
|  | 		if not self.visible(name): | ||
|  | 			raise os.error, "protected name %s" % repr(name) | ||
|  | 	 | ||
|  | 	def checkfile(self, name): | ||
|  | 		self.check(name) | ||
|  | 		if not os.path.isfile(name): | ||
|  | 			raise os.error, "not a plain file %s" % repr(name) | ||
|  | 	 | ||
|  | 	def pwd(self): | ||
|  | 		return os.getcwd() | ||
|  | 	 | ||
|  | 	def cd(self, name): | ||
|  | 		self.check(name) | ||
|  | 		save = os.getcwd(), self._ignore | ||
|  | 		os.chdir(name) | ||
|  | 		self._dirstack.append(save) | ||
|  | 		self._ignore = self._ignore + self._readignore() | ||
|  | 	 | ||
|  | 	def back(self): | ||
|  | 		if not self._dirstack: | ||
|  | 			raise os.error, "empty directory stack" | ||
|  | 		dir, ignore = self._dirstack[-1] | ||
|  | 		os.chdir(dir) | ||
|  | 		del self._dirstack[-1] | ||
|  | 		self._ignore = ignore | ||
|  | 	 | ||
|  | 	def _filter(self, files, pat = None): | ||
|  | 		if pat: | ||
|  | 			def keep(name, pat = pat): | ||
|  | 				return fnmatch.fnmatch(name, pat) | ||
|  | 			files = filter(keep, files) | ||
|  | 		files = filter(self.visible, files) | ||
|  | 		files.sort() | ||
|  | 		return files | ||
|  | 	 | ||
|  | 	def list(self, pat = None): | ||
|  | 		files = os.listdir(os.curdir) | ||
|  | 		return self._filter(files, pat) | ||
|  | 	 | ||
|  | 	def listfiles(self, pat = None): | ||
|  | 		files = os.listdir(os.curdir) | ||
|  | 		files = filter(os.path.isfile, files) | ||
|  | 		return self._filter(files, pat) | ||
|  | 	 | ||
|  | 	def listsubdirs(self, pat = None): | ||
|  | 		files = os.listdir(os.curdir) | ||
|  | 		files = filter(os.path.isdir, files) | ||
|  | 		return self._filter(files, pat) | ||
|  | 	 | ||
|  | 	def exists(self, name): | ||
|  | 		return self.visible(name) and os.path.exists(name) | ||
|  | 	 | ||
|  | 	def isdir(self, name): | ||
|  | 		return self.visible(name) and os.path.isdir(name) | ||
|  | 	 | ||
|  | 	def islink(self, name): | ||
|  | 		return self.visible(name) and os.path.islink(name) | ||
|  | 	 | ||
|  | 	def isfile(self, name): | ||
|  | 		return self.visible(name) and os.path.isfile(name) | ||
|  | 	 | ||
|  | 	def sum(self, name): | ||
|  | 		self.checkfile(name) | ||
|  | 		BUFFERSIZE = 1024*8 | ||
|  | 		f = open(name) | ||
|  | 		sum = md5.new() | ||
|  | 		while 1: | ||
|  | 			buffer = f.read(BUFFERSIZE) | ||
|  | 			if not buffer: | ||
|  | 				break | ||
|  | 			sum.update(buffer) | ||
|  | 		return sum.digest() | ||
|  | 	 | ||
|  | 	def size(self, name): | ||
|  | 		self.checkfile(name) | ||
|  | 		return os.stat(name)[ST_SIZE] | ||
|  | 	 | ||
|  | 	def mtime(self, name): | ||
|  | 		self.checkfile(name) | ||
|  | 		return time.localtime(os.stat(name)[ST_MTIME]) | ||
|  | 	 | ||
|  | 	def stat(self, name): | ||
|  | 		self.checkfile(name) | ||
|  | 		size = os.stat(name)[ST_SIZE] | ||
|  | 		mtime = time.localtime(os.stat(name)[ST_MTIME]) | ||
|  | 		return size, mtime | ||
|  | 	 | ||
|  | 	def info(self, name): | ||
|  | 		sum = self.sum(name) | ||
|  | 		size = os.stat(name)[ST_SIZE] | ||
|  | 		mtime = time.localtime(os.stat(name)[ST_MTIME]) | ||
|  | 		return sum, size, mtime | ||
|  | 	 | ||
|  | 	def _list(self, function, list): | ||
|  | 		if list is None: | ||
|  | 			list = self.listfiles() | ||
|  | 		res = [] | ||
|  | 		for name in list: | ||
|  | 			try: | ||
|  | 				res.append((name, function(name))) | ||
|  | 			except (os.error, IOError): | ||
|  | 				res.append((name, None)) | ||
|  | 		return res | ||
|  | 	 | ||
|  | 	def sumlist(self, list = None): | ||
|  | 		return self._list(self.sum, list) | ||
|  | 	 | ||
|  | 	def statlist(self, list = None): | ||
|  | 		return self._list(self.stat, list) | ||
|  | 	 | ||
|  | 	def mtimelist(self, list = None): | ||
|  | 		return self._list(self.mtime, list) | ||
|  | 	 | ||
|  | 	def sizelist(self, list = None): | ||
|  | 		return self._list(self.size, list) | ||
|  | 	 | ||
|  | 	def infolist(self, list = None): | ||
|  | 		return self._list(self.info, list) | ||
|  | 	 | ||
|  | 	def _dict(self, function, list): | ||
|  | 		if list is None: | ||
|  | 			list = self.listfiles() | ||
|  | 		dict = {} | ||
|  | 		for name in list: | ||
|  | 			try: | ||
|  | 				dict[name] = function(name) | ||
|  | 			except (os.error, IOError): | ||
|  | 				pass | ||
|  | 		return dict | ||
|  | 	 | ||
|  | 	def sumdict(self, list = None): | ||
|  | 		return self.dict(self.sum, list) | ||
|  | 	 | ||
|  | 	def sizedict(self, list = None): | ||
|  | 		return self.dict(self.size, list) | ||
|  | 	 | ||
|  | 	def mtimedict(self, list = None): | ||
|  | 		return self.dict(self.mtime, list) | ||
|  | 	 | ||
|  | 	def statdict(self, list = None): | ||
|  | 		return self.dict(self.stat, list) | ||
|  | 	 | ||
|  | 	def infodict(self, list = None): | ||
|  | 		return self._dict(self.info, list) | ||
|  | 	 | ||
|  | 	def read(self, name, offset = 0, length = -1): | ||
|  | 		self.checkfile(name) | ||
|  | 		f = open(name) | ||
|  | 		f.seek(offset) | ||
|  | 		if length == 0: | ||
|  | 			data = '' | ||
|  | 		elif length < 0: | ||
|  | 			data = f.read() | ||
|  | 		else: | ||
|  | 			data = f.read(length) | ||
|  | 		f.close() | ||
|  | 		return data | ||
|  | 	 | ||
|  | 	def create(self, name): | ||
|  | 		self.check(name) | ||
|  | 		if os.path.exists(name): | ||
|  | 			self.checkfile(name) | ||
|  | 			bname = name + '~' | ||
|  | 			try: | ||
|  | 				os.unlink(bname) | ||
|  | 			except os.error: | ||
|  | 				pass | ||
|  | 			os.rename(name, bname) | ||
|  | 		f = open(name, 'w') | ||
|  | 		f.close() | ||
|  | 	 | ||
|  | 	def write(self, name, data, offset = 0): | ||
|  | 		self.checkfile(name) | ||
|  | 		f = open(name, 'r+') | ||
|  | 		f.seek(offset) | ||
|  | 		f.write(data) | ||
|  | 		f.close() | ||
|  | 	 | ||
|  | 	def mkdir(self, name): | ||
|  | 		self.check(name) | ||
|  | 		os.mkdir(name, 0777) | ||
|  | 	 | ||
|  | 	def rmdir(self, name): | ||
|  | 		self.check(name) | ||
|  | 		os.rmdir(name) | ||
|  | 
 | ||
|  | 
 | ||
|  | class FSProxyServer(FSProxyLocal, server.Server): | ||
|  | 	 | ||
|  | 	def __init__(self, address, verbose = server.VERBOSE): | ||
|  | 		FSProxyLocal.__init__(self) | ||
|  | 		server.Server.__init__(self, address, verbose) | ||
|  | 	 | ||
|  | 	def _close(self): | ||
|  | 		server.Server._close(self) | ||
|  | 		FSProxyLocal._close(self) | ||
|  | 	 | ||
|  | 	def _serve(self): | ||
|  | 		server.Server._serve(self) | ||
|  | 		# Retreat into start directory | ||
|  | 		while self._dirstack: self.back() | ||
|  | 
 | ||
|  | 
 | ||
|  | class FSProxyClient(client.Client): | ||
|  | 	 | ||
|  | 	def __init__(self, address, verbose = client.VERBOSE): | ||
|  | 		client.Client.__init__(self, address, verbose) | ||
|  | 
 | ||
|  | 
 | ||
|  | def test(): | ||
|  | 	import string | ||
|  | 	import sys | ||
|  | 	if sys.argv[1:]: | ||
|  | 		port = string.atoi(sys.argv[1]) | ||
|  | 	else: | ||
|  | 		port = 4127 | ||
|  | 	proxy = FSProxyServer(('', port)) | ||
|  | 	proxy._serverloop() | ||
|  | 
 | ||
|  | 
 | ||
|  | if __name__ == '__main__': | ||
|  | 	test() |