Below is the file 'storage.py' from this revision. You can also download the file.


import datetime
import urlparse
import string
import stat
import sha
import os

import config

class StorageException(Exception):
    pass

class Storage:
    def __init__(self, site, uri):
        self.site, self.uri = site, uri
        self.dir = self.__storage_dir()

    def __storage_dir(self):
        # list of directories in the storage path to get to this URI
        dirs = []
        site = filter(lambda x: x in string.letters or x in string.digits or x == '.', self.site)
        # no .. entries to climb the filesystem :-)
        site = site.lstrip('.')
        dirs.append(site)

        # but this should be safe
        hash = sha.new(self.uri).hexdigest()
        dirs += [hash[:8], hash[8:16], hash[16:24], hash[24:32], hash[32:40]]

        c_dir = config.storage_path
        for dir in dirs:
            c_dir = os.path.join(c_dir, dir)
            if not os.access(c_dir, os.R_OK):
                os.mkdir(c_dir)
        return c_dir

    def file(self, fname):
        if fname.startswith('/'):
            raise StorageException("fname may not start with a slash.")
        return os.path.join(self.dir, fname)

    def mtime(self, fname):
        fname = self.file(fname)
        if not os.access(fname, os.R_OK):
            timestamp = 0
        else:
            timestamp = os.stat(fname)[stat.ST_MTIME]
        return datetime.datetime.fromtimestamp(timestamp)

    def timestamp(self, fname):
        fname = self.file(fname)
        if not os.access(fname, os.R_OK):
            open(fname, 'w')
        os.utime(fname, None)

    def unlink(self, fname):
        try:
            os.unlink(self.file(fname))
        except OSError:
            pass

    def has_file(self, fname):
        return os.access(self.file(fname), os.R_OK)

    def require_files(self, files):
        for file in files:
            file = self.file(file)
            if not os.access(file, os.R_OK):
                open(file, 'w')

    def open(self, *args):
        fname, other_args = args[0], args[1:]
        return open(*[self.file(fname)] + list(other_args))