Browse code

Initial version of S3fs module - can create filesystem via "S3fs.mkfs()"

git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3py/trunk@64 830e0280-6d2a-0410-9c65-932aecc39d9d

Michal Ludvig authored on 2007/01/26 11:34:08
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,162 @@
0
+## Amazon S3 manager
1
+## Author: Michal Ludvig <michal@logix.cz>
2
+##         http://www.logix.cz/michal
3
+## License: GPL Version 2
4
+
5
+import os, os.path
6
+import errno
7
+import random
8
+import pickle
9
+
10
+class S3fs(object):
11
+	_sync_attrs = [ "tree" ]
12
+	fsname = None
13
+	tree = None
14
+	def __init__(self, fsname = None):
15
+		self.n = S3fsObjectName()
16
+		if fsname:
17
+			self.openfs(fsname)
18
+
19
+	def mkfs(self, fsname):
20
+		self._object_name = self.n.fs(fsname)
21
+		if self.object_exists(self._object_name):
22
+			raise S3fsError("Filesystem already exists", errno.EEXIST)
23
+		self.fsname = fsname
24
+		root_inode = S3fsInode(self)
25
+		S3fsSync.store(self, root_inode)
26
+		self.tree = { "/" : root_inode.inode_id }
27
+		S3fsSync.store(self, self)
28
+	
29
+	def openfs(self, fsname):
30
+		raise S3fsError("Not implemented", errno.ENOSYS)
31
+	
32
+class S3fsInode(object):
33
+	_fs = None
34
+
35
+	## Interface for S3fsSync
36
+	_sync_attrs = [ "properties" ]
37
+	_object_name = None
38
+
39
+	## Properties
40
+	inode_id = None
41
+	properties = {
42
+		"ctime" : None,
43
+		"mtime" : None,
44
+		"uid" : None,
45
+		"gid" : None,
46
+		"mode" : None,
47
+	}
48
+
49
+	def __init__(self, fs, inode_id = None):
50
+		if not inode_id:
51
+			inode_id = fs.n.rndstr(10)
52
+		self.inode_id = inode_id
53
+		self._object_name = fs.n.inode(fs.fsname, inode_id)
54
+		self._fs = fs
55
+
56
+	def setprop(self, property, value):
57
+		self.assert_property_name(property)
58
+		self.properties[property] = value
59
+		return value
60
+	
61
+	def getprop(self, property):
62
+		self.assert_property_name(property)
63
+		return self.properties[property]
64
+	
65
+	def assert_property_name(self, property):
66
+		if not self.properties.has_key(property):
67
+			raise ValueError("Property '%s' not known to S3fsInode")
68
+
69
+class S3fsLocalDir(S3fs):
70
+	def __init__(self, directory):
71
+		S3fs.__init__(self)
72
+		if not os.path.isdir(directory):
73
+			raise S3fsError("Directory %s does not exist" % directory, errno.ENOENT)
74
+		self._dir = directory
75
+	
76
+	def lock(self):
77
+		pass
78
+
79
+	def unlock(self):
80
+		pass
81
+
82
+	def object_exists(self, object_name):
83
+		real_path = os.path.join(self._dir, object_name)
84
+		if os.path.isfile(real_path):	## Is file, all good
85
+			return True
86
+		if os.path.exists(real_path):	## Exists but is not file!
87
+			raise S3fsError("Object %s (%s) is not a regular file" % (object_name, real_path), errno.EINVAL)
88
+		return False
89
+
90
+	def object_write(self, object_name, contents):
91
+		real_path = os.path.join(self._dir, object_name)
92
+		f = open(real_path, "wb")
93
+		f.write(contents)
94
+		f.close()
95
+
96
+	def object_read(self, object_name):
97
+		real_path = os.path.join(self._dir, object_name)
98
+		f = open(real_path, "rb")
99
+		contents = f.read()
100
+		f.close()
101
+		return contents
102
+
103
+class S3fsObjectName(object):
104
+	_rnd_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
105
+	_rnd_chars_len = len(_rnd_chars)
106
+
107
+	def __init__(self):
108
+		random.seed()
109
+
110
+	def rndstr(self, len):
111
+		retval = ""
112
+		while len > 0:
113
+			retval += self._rnd_chars[random.randint(0, self._rnd_chars_len-1)]
114
+			len -= 1
115
+		return retval
116
+
117
+	def fs(self, fsname):
118
+		return "fs-%s" % fsname
119
+
120
+	def inode(self, fsname, inode_id):
121
+		return "%s-i-%s" % (fsname, inode_id)
122
+	
123
+class S3fsSync(object):
124
+	@staticmethod
125
+	def store(fs, instance, object_name = None):
126
+		if not object_name:
127
+			object_name = instance._object_name
128
+		to_sync = {}
129
+		for attr in instance._sync_attrs:
130
+			if hasattr(instance, attr):
131
+				to_sync[attr] = getattr(instance, attr)
132
+		fs.object_write(object_name, pickle.dumps(to_sync))
133
+		print "Stored object: %s" % (object_name)
134
+
135
+	@staticmethod
136
+	def load(fs, instance, object_name = None):
137
+		if not object_name:
138
+			object_name = instance._object_name
139
+		from_sync = pickle.loads(fs.object_read(object_name))
140
+		for attr in instance._sync_attrs:
141
+			if from_sync.has_key[attr]:
142
+				setattr(instance, attr, from_sync[attr])
143
+		print "Loaded object: %s" % (object_name)
144
+
145
+class S3fsError(Exception):
146
+	def __init__(self, message, errno = -1):
147
+		Exception.__init__(self, message)
148
+		self.errno = errno
149
+	
150
+if __name__ == "__main__":
151
+	local_dir = "/tmp/s3fs"
152
+	try:
153
+		fs = S3fsLocalDir(local_dir)
154
+	except S3fsError, e:
155
+		if e.errno == errno.ENOENT:
156
+			os.mkdir(local_dir)
157
+		else:
158
+			raise
159
+	print "RandomStrings = %s %s" % (fs.n.rndstr(5), fs.n.rndstr(10))
160
+
161
+	fs.mkfs("testFs")