This repository has been archived by the owner on Aug 23, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwebrofs-fuse
executable file
·162 lines (143 loc) · 5.68 KB
/
webrofs-fuse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python3
from __future__ import with_statement
from sys import argv, exit
from threading import Lock
from errno import ENOENT, EREMOTEIO, EIO
import time
from fuse import FUSE, FuseOSError, Operations, LoggingMixIn
import urllib.request
import urllib.error
from os.path import join as pathjoin
CACHE_AGE = 3600
class WebROfs(LoggingMixIn, Operations):
def __init__(self, urls):
# download manifest
self._folders = {}
self._files = {}
self._links = {}
self._cache = {}
# split urls
for url in urls.split(","):
self._load_manifest(url)
print("Manifest download complete")
def _load_manifest(self, url):
print("Download manifest " + url)
try:
mfile = url + "/manifest"
response = urllib.request.urlopen(mfile)
charset = response.info().get_param('charset', 'utf-8')
data = response.read().decode(charset)
for line in data.split("\n"):
if not line == "":
line = line.split("|")
if line[0] == "M":
# we link another manifest
self._load_manifest(line[1])
elif line[0] == "F":
# if this folder exists, dont empty it!
if line[1] not in self._folders:
self._folders[line[1]] = []
self._files[line[1]] = line[2:] + [url]
elif line[0] == "S":
# symlink
self._links[line[1]] = line[2]
else:
# this is a file
fullpath = pathjoin(line[0], line[1])
self._files[fullpath] = line[2:] + [url]
# if a file exists in a higher stack, don't make two references in
# the directory list
if line[1] not in self._folders[line[0]]:
self._folders[line[0]].append(line[1])
except Exception as e:
print("Could not load manifest for volume " + mfile)
print(e)
raise SystemExit()
def _add_cached(self, path, data, time):
self._cache[path] = (time, data)
def _remove_cached(self, path):
try:
del self._cache[path]
except:
pass
def _is_cached(self, path):
if path in self._cache:
# check it has not passed cache age
if self._cache[path][0] < (int(time.time()) - CACHE_AGE):
# possible race condition
self._remove_cached(path)
return False
else:
return True
else:
return False
def read(self, path, size, offset, fh):
try:
if path in self._files:
if self._is_cached(path):
# return cached version
try:
return self._cache[path][1][offset:(offset + size)]
except:
# there was a problem getting file from cache, get remote copy
return urllib.request.urlopen(self.url + path).read()[offset:(offset + size)]
else:
# data is not cached or old, get remote copy
try:
# get url for this file
try:
url = self._files[path][8]
except KeyError:
raise FuseOSError(ENOENT)
# get remote copy
data = urllib.request.urlopen(url + path).read()
except urllib.error.HTTPError:
raise FuseOSError(EREMOTEIO)
except Exception as e:
# TODO log the uncaught exception
raise FuseOSError(EIO)
# add to cache and return
self._add_cached(path, data, int(time.time()))
return data[offset:(offset + size)]
except Exception as e:
# TODO log the uncaught exception
raise FuseOSError(EIO)
def readlink(self, path):
try:
return self._links[path]
except KeyError:
raise FuseOSError(ENOENT)
except Exception as e:
# TODO log the uncaught exception
raise FuseOSError(EIO)
def getattr(self, path, fh=None):
try:
return {'st_atime': float(self._files[path][0]),
'st_ctime': float(self._files[path][1]),
'st_gid': int(self._files[path][2]),
'st_mode': int(self._files[path][3]),
'st_mtime': float(self._files[path][4]),
'st_nlink': int(self._files[path][5]),
'st_size': int(self._files[path][6]),
'st_uid': int(self._files[path][7])}
except KeyError:
raise FuseOSError(ENOENT)
except Exception as e:
# TODO log the uncaught exception
raise FuseOSError(EIO)
def readdir(self, path, fh):
rlist = ['.', '..']
try:
for f in self._folders[path]:
rlist.append(f)
return rlist
except KeyError:
raise FuseOSError(ENOENT)
except Exception as e:
# TODO log the uncaught exception
raise FuseOSError(EIO)
if __name__ == '__main__':
if len(argv) != 3:
print('usage: %s <urls seperate by ,> <mountpoint>' % argv[0])
exit(1)
fuse = FUSE(WebROfs(argv[1]), argv[2], foreground=True)