aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMathieu Blondel <mathieu@mblondel.org>2009-09-17 07:39:39 +0000
committerMathieu Blondel <mathieu@mblondel.org>2009-09-17 07:39:39 +0000
commitf9574d04652c557a0348cdfe537316a9c55b219c (patch)
tree04e9883101009a412db9ee3716cd0124da9b8441 /src
parent916e28a1c9e8d221f1c13ad66e5d62aab8a1488f (diff)
downloadwikipediafs-f9574d04652c557a0348cdfe537316a9c55b219c.tar.gz
I would like to break this up more, but it's a big mess. But this fixes a fair
bit. config.py: Handle a new general configuration variable, login-cache-time, which defaults to 7200 seconds (two hours). metadir.py: Report mtime for stat. Refuse to create a file (With EACCES) if it is not a valid wiki filename. (Potential data loss.) Implement fsync and flush, which attempts to actually write the file, so we can report write failures to an application. (Potential data loss) Slightly improved debug logging for release and mkdir. In rename, try to report failure to write to the wiki. (Potential data loss) fs.py: Cache the login time for class ArticleDir. Add a force argument to set_cookie_string to force it to get a new one regardless of if one already exists. Add a 'get_art' function which handles all the logic for getting the article object, including caching and login timeouts. Make all the functions use the get_art function. Add a function for getting the mtime, used by the above change to metadir. Add some debug logging. article.py: Lots and lots and lots of debug logging, trying to get all the above sorted out. Add some code to Article set to return false on success and true on failure, so that we can report back to the application when a write failed. (Potential data loss.) git-svn-id: http://svn.code.sf.net/p/wikipediafs/code/trunk@68 59acd704-e115-0410-a914-e735a229ed7c
Diffstat (limited to 'src')
-rw-r--r--src/wikipediafs/article.py17
-rw-r--r--src/wikipediafs/config.py13
-rw-r--r--src/wikipediafs/fs.py78
-rw-r--r--src/wikipediafs/metadir.py54
4 files changed, 114 insertions, 48 deletions
diff --git a/src/wikipediafs/article.py b/src/wikipediafs/article.py
index 4793bce..c323ae4 100644
--- a/src/wikipediafs/article.py
+++ b/src/wikipediafs/article.py
@@ -119,6 +119,7 @@ class Article(SGMLParser):
# Do not get article if cache is still ok
if int(time.time()) - self.last_get > self.cache_time:
+ self.logger.debug("pre-GET wpStarttime: '%s', wpEdittime: '%s', cookies: '%s', time diff: %d\n", self.wpEdittime, self.wpStarttime, self.cookie_str, int(time.time()) - self.last_get)
headers = {"User-agent" : "WikipediaFS"}
if self.cookie_str is not None:
@@ -143,6 +144,7 @@ class Article(SGMLParser):
conn.close()
self.last_get = int(time.time())
+ self.logger.debug("post-GET wpStarttime: '%s', wpEdittime: '%s', cookies: '%s', time diff: %d\n", self.wpEdittime, self.wpStarttime, self.cookie_str, int(time.time()) - self.last_get)
else:
if self.logger:
self.logger.debug("Get %s from cache" % self.name)
@@ -158,7 +160,9 @@ class Article(SGMLParser):
def set(self, text):
if text == self.content:
- return # useless to continue further...
+ return True # useless to continue further...
+
+ self.logger.debug("POST wpStarttime: '%s', wpEdittime: '%s', cookies: '%s', time diff: %d\n", self.wpEdittime, self.wpStarttime, self.cookie_str, int(time.time()) - self.last_get)
# Looking for a [[Summary:*]]
regexp = '((\[\[)((s|S)ummary:)(.*)(\]\])(( )*\n)?)'
@@ -208,6 +212,8 @@ class Article(SGMLParser):
self.logger.info("Succesful")
elif response.status == 200:
self.logger.error("Problems occured %s\n" % response.read())
+ self.logger.debug("Headers: '%s'\n" % headers)
+ self.logger.debug("Text: '%s'\n" % text)
else:
self.logger.info("%d \n %s " % \
(response.status,response.read()))
@@ -226,6 +232,13 @@ class Article(SGMLParser):
else:
self.is_empty = False
+ # Did the write actually succeed?
+ if response.status == 302:
+ return True
+ else:
+ self.logger.debug("article.set: Returning false.\n")
+ return False
+
if __name__ == "__main__":
import random
@@ -254,4 +267,4 @@ if __name__ == "__main__":
print art.get()
art.set("Test ! (%s)" % str(random.random()))
- \ No newline at end of file
+
diff --git a/src/wikipediafs/config.py b/src/wikipediafs/config.py
index 6a906c7..2d42b29 100644
--- a/src/wikipediafs/config.py
+++ b/src/wikipediafs/config.py
@@ -32,6 +32,7 @@ class Config:
<general>
<!-- Cache time in seconds -->
<article-cache-time>30</article-cache-time>
+ <login-cache-time>7200</login-cache-time>
</general>
<sites>
<!--
@@ -85,7 +86,7 @@ class Config:
else:
self.__config = minidom.parseString(config_str).documentElement
- self.__setCacheTime()
+ self.__setCacheTimes()
self.__setDebug()
@@ -123,12 +124,17 @@ class Config:
self.sites[dic["dirname"]] = dic
- def __setCacheTime(self):
+ def __setCacheTimes(self):
element = self.__config.getElementsByTagName("article-cache-time")
if element.length == 0:
self.cache_time = 30
else:
self.cache_time = int(str(element[0].firstChild.nodeValue))
+ element = self.__config.getElementsByTagName("login-cache-time")
+ if element.length == 0:
+ self.login_cache_time = 7200
+ else:
+ self.login_cache_time = int(str(element[0].firstChild.nodeValue))
def __setDebug(self):
element = self.__config.getElementsByTagName("debug")
@@ -147,6 +153,7 @@ else:
<general>
<!-- Cache time in seconds -->
<article-cache-time>30</article-cache-time>
+ <login-cache-time>7200</login-cache-time>
<debug />
</general>
<sites>
@@ -172,4 +179,4 @@ else:
print "cache time:", config.cache_time
print "debug:", config.debug_mode
for k, v in config.sites.items():
- print k, v \ No newline at end of file
+ print k, v
diff --git a/src/wikipediafs/fs.py b/src/wikipediafs/fs.py
index 78dcf5e..42c94e5 100644
--- a/src/wikipediafs/fs.py
+++ b/src/wikipediafs/fs.py
@@ -17,7 +17,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-import os.path, re
+import os.path, re, time
from metadir import MetaDir
from config import CONFIG
from article import Article
@@ -27,7 +27,8 @@ from logger import LOGGER
class ArticleDir:
def __init__(self, fs, config):
self.fs = fs
- self.config = config
+ self.config = config
+ self.login_time = 0
self.files = {}
self.dirs = {}
@@ -73,52 +74,68 @@ class ArticleDir:
else:
return False
- def set_cookie_string(self):
- if not self.config.has_key("cookie_str"):
+ def set_cookie_string(self, force):
+ if force or not self.config.has_key("cookie_str"):
if self.config["username"] is not None and \
self.config["password"] is not None:
user = User(logger=LOGGER, **self.config)
cookie_str = user.getCookieString()
self.config["cookie_str"] = cookie_str
- def read_file(self, path):
+ self.login_time = time.time()
+
+ def get_art(self, path):
file_name = self.get_article_file_name(path)
full_name = self.get_article_full_name(path)
- if self.files.has_key(file_name):
- art = self.files[file_name]
+
+ if int(time.time()) - self.login_time > CONFIG.login_cache_time:
+ self.set_cookie_string(1)
else:
- self.set_cookie_string()
-
- art = Article(full_name[0:-3], # removes .mw from the name
- cache_time=CONFIG.cache_time,
- logger = LOGGER,
- **self.config)
- txt = art.get()
- self.files[file_name] = art
- return art.get()
+ if self.files.has_key(file_name):
+ return self.files[file_name]
+ else:
+ self.set_cookie_string(0)
+
+ art = Article(full_name[0:-3], # removes .mw from the name
+ cache_time=CONFIG.cache_time,
+ logger = LOGGER,
+ **self.config)
+ self.files[file_name] = art
+
+ return art
+
+ def read_file(self, path):
+ art = self.get_art(path)
+ txt = art.get()
+ return txt
def write_to(self, path, txt):
- file_name = self.get_article_file_name(path)
- full_name = self.get_article_full_name(path)
- if self.files.has_key(file_name):
- art = self.files[file_name]
- else:
- self.set_cookie_string()
-
- art = Article(full_name[0:-3],
- cache_time=CONFIG.cache_time,
- logger = LOGGER,
- **self.config)
- self.files[file_name] = art
- art.set(txt)
+ art = self.get_art(path);
+ return art.set(txt)
def size(self, path):
+ LOGGER.debug("FSdir size %s" % (path))
return len(self.read_file(path))
+
+ def mtime(self, path):
+ art = self.get_art(path)
+ # Do a get here just so we have a current Edittime.
+ art.get()
+ tmp = art.wpEdittime
+ t = time.mktime((int(tmp[0:4]), int(tmp[4:6]), int(tmp[6:8]), int(tmp[8:10]), int(tmp[10:12]), int(tmp[12:21]), 0, 0, -1))
+ if time.daylight:
+ t -= time.altzone
+ else:
+ t -= time.timezone
+
+ return t
def mode(self, path):
+ LOGGER.debug("FSdir mode %s" % (path))
return 0755
def unlink(self, path):
+ LOGGER.debug("FSdir unlink %s" % (path))
file_name = self.get_article_file_name(path)
if self.files.has_key(file_name):
self.files.pop(file_name)
@@ -127,6 +144,7 @@ class ArticleDir:
return False
def mkdir(self, path):
+ LOGGER.debug("FSdir mkdir %s" % (path))
name = self.get_article_file_name(path)
self.dirs[name] = True
self.fs.set_dir(path, ArticleDir(self.fs, self.config))
@@ -200,4 +218,4 @@ if __name__ == "__main__":
server.parse(errex=1)
server.multithreaded = 0
- server.main() \ No newline at end of file
+ server.main()
diff --git a/src/wikipediafs/metadir.py b/src/wikipediafs/metadir.py
index c48b2f3..8a0481a 100644
--- a/src/wikipediafs/metadir.py
+++ b/src/wikipediafs/metadir.py
@@ -132,6 +132,7 @@ class MetaDir(Fuse):
st.st_mode = stat.S_IFREG | d.mode(path)
st.st_nlink = 1
st.st_size = d.size(path)
+ st.st_mtime = d.mtime(path)
else:
return -errno.ENOENT # No such file or directory
return st
@@ -169,6 +170,8 @@ class MetaDir(Fuse):
# We also need to check if it is a valid file for the fs
if dir(d).count("is_valid_file") == 1 and not d.is_valid_file(path):
return -errno.EACCES # Permission denied
+ else:
+ return -errno.EACCES # Permission denied
self.get_file_buf(path)
@@ -218,27 +221,54 @@ class MetaDir(Fuse):
buf.write(txt)
return len(txt)
+
+ def fsync(self, path, isfsyncfile = 0):
+ LOGGER.info("Fsync %s %s" % (path, isfsyncfile))
+ return self.flush (path, 0)
+
+ def flush(self, path, flags = 0):
+ # Did we succeed?
+ success = True
+
+ # Called to close the file
+ LOGGER.debug("flush %s %x" % (path, flags))
+
+ if self.open_mode == self.WRITE and self.is_valid_file(path):
+ # for valid files
+ buf = self.get_file_buf(path)
+ d = self.get_dir(path)
+ success = d.write_to(path, buf.getvalue())
+ LOGGER.debug("flush: success: %d\n" % (success));
+ if success == False:
+ LOGGER.debug("flush: Returning\n" % (-errno.EIO));
+ return -errno.EIO
+
+ return None
+
def release(self, path, flags):
# Called to close the file
- LOGGER.debug("release %s %d" % (path, flags))
+ LOGGER.debug("release %s %x" % (path, flags))
+ # Release can not return errors, but try anyhow because we have no other choices.
+ # XXX: Is the flush called reliably enough to do this there?
if self.open_mode == self.WRITE and self.is_valid_file(path):
# for valid files
buf = self.get_file_buf(path)
d = self.get_dir(path)
- d.write_to(path, buf.getvalue())
+ success = d.write_to(path, buf.getvalue())
+ LOGGER.debug("release: success: %d\n" % (success));
if self.is_valid_file(path):
self.remove_file_buf(path) # Do not keep buffer in memory...
- self.open_mode = None
-
+ self.open_mode = None
+
return None
def mkdir(self, path, mode):
- LOGGER.debug("mkdir %s %d" % (path, mode))
+ LOGGER.debug("mkdir %s %x" % (path, mode))
d = self.get_dir(path)
-
+
if dir(d).count("mkdir") == 0:
return -errno.EACCES # Permission denied
else:
@@ -291,10 +321,12 @@ class MetaDir(Fuse):
elif not self.is_valid_file(path):
if self.is_valid_file(path1) and d.is_file(path1):
# from an editor file to a valid file
- buf = self.get_file_buf(path)
- d.write_to(path1, buf.getvalue())
+ buf = self.get_file_buf(path)
+ ret = d.write_to(path1, buf.getvalue())
self.open_mode = None
self.remove_file_buf(path)
+ if ret == False:
+ return -errno.EIO
elif not self.is_valid_file(path):
# from an editor file to an editor file
# TODO
@@ -317,10 +349,6 @@ class MetaDir(Fuse):
def chown(self, path, user, group):
LOGGER.debug("chown %s %s %s" % (path,user,group))
return None
-
- def fsync(self, path, isfsyncfile):
- LOGGER.info("Fsync %s %s" % (path, isfsyncfile))
- return 0
if __name__ == "__main__":
class Hello:
@@ -387,4 +415,4 @@ if __name__ == "__main__":
fs.release('/hello_file', 32768)
print fs.mkdir('/new_dir', 32768)
- \ No newline at end of file
+