#!/usr/bin/env python # # This requires the python FUSE bindings, and the FUSE module loaded in your kernel. # # Linux: modprobe fuse # FreeBSD: kldload fuse # # This is not a 100% implementation of all fuse functions. Only writing and # creating new files is supported. # # Author: jls@semicomplete.com import os, stat, errno import fuse import urllib import libxml2 import time import base64 class tastystat(fuse.Stat): def __init__(self): self.st_mode = 0 self.st_ino = 0 self.st_dev = 0 self.st_nlink = 0 self.st_uid = 0 self.st_gid = 0 self.st_size = 0 self.st_atime = 0 self.st_mtime = 0 self.st_ctime = 0 class delicious(object): user = "YOUR_DELICIOUS_USER" password = "YOUR PASSWORD" _instance = None def __init__(self): self.myfiles = None self.lastupdate = 0 self.cachethreshold = 10 def singleton(self): if not self._instance: self._instance = delicious() return self._instance singleton = classmethod(singleton) def getfiles(self): if time.time() - self.lastupdate < self.cachethreshold and self.myfiles: return self.myfiles fd = urllib.urlopen("https://%s:%s@api.del.icio.us/v1/posts/all?tag=tastydrive" % (self.user, self.password)) data = fd.read() doc = libxml2.parseMemory(data, len(data)) files = {} for post in doc.xpathEval("/posts/post"): url = [x for x in post.xpathEval("@href")][0].content filename = [x for x in post.xpathEval("@description")][0].content files.update({ "%s" % filename: url}) self.myfiles = files.copy() self.lastupdate = time.time() return files def savefile(self, file, data): #url = urllib.quote("data:application/octet-stream;base64,%s" % b64) #url = "data:application/octet-stream;base64,%s" % b64 #url = "data:text/plain;base64,%s" % b64 types = { "png": "image/png", "jpg": "image/jpeg", "doc": "application/msword", "ppt": "application/vnd.ms-powerpoint", "html": "text/html", "mp3": "audio/mpeg", } if '.' in file: ext = file.split(".")[-1] else: ext = "" redir = "http://wzus.ask.com/r?t=p&url=&u=" #url = urllib.quote("data:%s;base64,%s" % (types.get(ext, "text/plain"), b64)) print "Saving data: %s (%d bytes)" % (file, len(data)) shard = 0 b64data = urllib.quote(base64.b64encode(data)) print "b64 len: %d" % len(b64data) while len(b64data) > 0: print "b64 len: %d" % len(b64data) #length = len(data) > 60000 and 60000 or len(data) length = 60000 piece = b64data[:length] #b64 = urllib.quote(base64.b64encode(piece)) #url = "http://%s?%s" % (types.get(ext, "text/plain"), b64) url = "http://chunk/%s" % (piece) args = { "description": "%d:%s" % (shard, file), "tags": "tastydrive:%s" % (file), "url": url, } print " %s: Saving shard %d" % (file, shard) fd = urllib.urlopen("https://%s:%s@api.del.icio.us/v1/posts/add" % (self.user, self.password), urllib.urlencode(args)) fd.read() fd.close() b64data = b64data[len(piece):] shard += 1 # Write bootstrap shard ctype = types.get(ext, "text/plain") bootstrap = """ """ % ({ "file": file, "ctype": ctype }) b64strap = urllib.quote(base64.b64encode(bootstrap)) #ctype = types.get(ext, "text/plain") url = "data:text/html;base64,%s" % (b64strap) redir = "http://wzus.ask.com/r?t=p&url=&u=%s" % url print "Redir url size: %d" % len(redir) args = { "description": "%s" % (file), "tags": "tastydrive", "url": redir, } fd = urllib.urlopen("https://%s:%s@api.del.icio.us/v1/posts/add" % (self.user, self.password), urllib.urlencode(args)) fd.read() fd.close() def addfile(self, file): self.myfiles[file] = "" self.savefile(file, "") class TastyDriveFS(fuse.Fuse): openfiles = {} lastcheck = 0 def getattr(self, path): st = tastystat() d = delicious.singleton() files = d.getfiles() print "path: %s" % path if path == '/': st.st_mode = stat.S_IFDIR | 0755 st.st_nlink = 2 elif path[1:] in files: # ... check path here for delicious name description st.st_mode = stat.S_IFREG | 0644 st.st_nlink = 1 st.st_size = len(files[path[1:]]) else: return -errno.ENOENT return st def readdir(self, path, offset): contents = ['.', '..'] contents.extend([x for x in delicious.singleton().getfiles()]) for r in contents: yield fuse.Direntry(r) def open(self, path, flags): path = path[1:] d = delicious.singleton() files = d.getfiles() if path not in files: return -errno.ENOENT if flags & (os.O_WRONLY | os.O_RDWR | os.O_CREAT): # I am *far* too lazy to implement any kind of multiaccessness for writes. if path in self.openfiles: return -errno.EBUSY self.openfiles[path] = files.get(path, "") def read(self, path, size, offset): path = path[1:] d = delicious.singleton() files = d.getfiles() print "Path (read): %s" % path if path not in files: return -errno.ENOENT slen = len(files[path]) if offset < slen: if offset + size > slen: size = slen - offset buf = files[path][offset:offset+size] else: buf = '' return buf def truncate(self, path, size): print "Truncated %s" % path self.openfiles[path[1:]] = "" def release(self, path, flags): # Save to delicious path = path[1:] if path in self.openfiles: delicious.singleton().savefile(path, self.openfiles[path]) del self.openfiles[path] def write(self, path, buf, offset): path = path[1:] data = self.openfiles[path] if offset < len(data): # do something? pass else: data = "%s%s%s" % (data, "X" * (offset - len(data)), buf) self.openfiles[path] = data return len(buf) #return -errno.ENOSYS def mknod ( self, path, mode, dev ): print "mknod" delicious.singleton().addfile(path[1:]) def main(): usage=""" Userspace hello example """ + fuse.Fuse.fusage server = TastyDriveFS(version="%prog " + fuse.__version__, usage=usage, dash_s_do='setsingle') server.parse(errex=1) server.main() if __name__ == '__main__': main()