def make_handler_for(node, client, parentnode=None, name=None): if parentnode: assert IDirectoryNode.providedBy(parentnode) if IFileNode.providedBy(node): return FileNodeHandler(client, node, parentnode, name) if IDirectoryNode.providedBy(node): return DirectoryNodeHandler(client, node, parentnode, name) return UnknownNodeHandler(client, node, parentnode, name)
def render_check_form(self, ctx, data): node = self.original quoted_uri = urllib.quote(node.get_uri()) target = self.get_root(ctx) + "/uri/" + quoted_uri if IDirectoryNode.providedBy(node): target += "/" check = T.form(action=target, method="post", enctype="multipart/form-data")[ T.fieldset[ T.input(type="hidden", name="t", value="check"), T.input(type="hidden", name="return_to", value="."), T.legend(class_="freeform-form-label")["Check on this object"], T.div[ "Verify every bit? (EXPENSIVE):", T.input(type="checkbox", name="verify"), ], T.div["Repair any problems?: ", T.input(type="checkbox", name="repair")], T.div["Add/renew lease on all shares?: ", T.input(type="checkbox", name="add-lease")], T.div["Emit results in JSON format?: ", T.input(type="checkbox", name="output", value="JSON")], T.input(type="submit", value="Check"), ]] return ctx.tag[check]
def _populate_row(self, keys, childnode_and_metadata): (childnode, metadata) = childnode_and_metadata values = [] isdir = bool(IDirectoryNode.providedBy(childnode)) for key in keys: if key == "size": if isdir: value = 0 else: value = childnode.get_size() or 0 elif key == "directory": value = isdir elif key == "permissions": # Twisted-14.0.2 (and earlier) expected an int, and used it # in a rendering function that did (mode & NUMBER). # Twisted-15.0.0 expects a # twisted.python.filepath.Permissions , and calls its # .shorthand() method. This provides both. value = IntishPermissions(0o600) elif key == "hardlinks": value = 1 elif key == "modified": # follow sftpd convention (i.e. linkmotime in preference to mtime) if "linkmotime" in metadata.get("tahoe", {}): value = metadata["tahoe"]["linkmotime"] else: value = metadata.get("mtime", 0) elif key == "owner": value = self.username elif key == "group": value = self.username else: value = "??" values.append(value) return values
def __init__(self, client, local_path_u, db, upload_dirnode, pending_delay, clock): QueueMixin.__init__(self, client, local_path_u, db, 'uploader', clock, delay=pending_delay) self.is_ready = False if not IDirectoryNode.providedBy(upload_dirnode): raise AssertionError("The URI in '%s' does not refer to a directory." % os.path.join('private', 'magic_folder_dircap')) if upload_dirnode.is_unknown() or upload_dirnode.is_readonly(): raise AssertionError("The URI in '%s' is not a writecap to a directory." % os.path.join('private', 'magic_folder_dircap')) self._upload_dirnode = upload_dirnode self._inotify = get_inotify_module() self._notifier = self._inotify.INotify() self._pending = set() # of unicode relpaths self._periodic_full_scan_duration = 10 * 60 # perform a full scan every 10 minutes if hasattr(self._notifier, 'set_pending_delay'): self._notifier.set_pending_delay(pending_delay) # TODO: what about IN_MOVE_SELF and IN_UNMOUNT? # self.mask = ( self._inotify.IN_CREATE | self._inotify.IN_CLOSE_WRITE | self._inotify.IN_MOVED_TO | self._inotify.IN_MOVED_FROM | self._inotify.IN_DELETE | self._inotify.IN_ONLYDIR | IN_EXCL_UNLINK ) self._notifier.watch(self._local_filepath, mask=self.mask, callbacks=[self._notify], recursive=False)#True)
def add_node(self, node, path): dirnode.DeepStats.add_node(self, node, path) d = {"path": path, "cap": node.get_uri()} if IDirectoryNode.providedBy(node): d["type"] = "directory" elif IFileNode.providedBy(node): d["type"] = "file" else: d["type"] = "unknown" v = node.get_verify_cap() if v: v = v.to_string() d["verifycap"] = v or "" r = node.get_repair_cap() if r: r = r.to_string() d["repaircap"] = r or "" si = node.get_storage_index() if si: si = base32.b2a(si) d["storage-index"] = si or "" j = json.dumps(d, ensure_ascii=True) assert "\n" not in j self.req.write(j+"\n")
def add_node(self, node, path): dirnode.DeepStats.add_node(self, node, path) data = {"path": path, "cap": node.get_uri()} if IDirectoryNode.providedBy(node): data["type"] = "directory" elif IFileNode.providedBy(node): data["type"] = "file" else: data["type"] = "unknown" v = node.get_verify_cap() if v: v = v.to_string() data["verifycap"] = v or "" r = node.get_repair_cap() if r: r = r.to_string() data["repaircap"] = r or "" si = node.get_storage_index() if si: si = base32.b2a(si) data["storage-index"] = si or "" if self.repair: d = node.check_and_repair(self.monitor, self.verify, self.add_lease) d.addCallback(self.add_check_and_repair, data) else: d = node.check(self.monitor, self.verify, self.add_lease) d.addCallback(self.add_check, data) d.addCallback(self.write_line) return d
def _made_upload_dir(n): self.failUnless(IDirectoryNode.providedBy(n)) self.upload_dirnode = n self.upload_dircap = n.get_uri() self.uploader = DropUploader(self.client, self.upload_dircap, self.local_dir.encode('utf-8'), inotify=self.inotify) return self.uploader.startService()
def modify(self, old_contents, servermap, first_time): children = self.node._unpack_contents(old_contents) now = time.time() for (namex, (child, new_metadata)) in self.entries.iteritems(): name = normalize(namex) precondition(IFilesystemNode.providedBy(child), child) # Strictly speaking this is redundant because we would raise the # error again in _pack_normalized_children. child.raise_error() metadata = None if name in children: if not self.overwrite: raise ExistingChildError("child %s already exists" % quote_output(name, encoding='utf-8')) if self.overwrite == "only-files" and IDirectoryNode.providedBy(children[name][0]): raise ExistingChildError("child %s already exists as a directory" % quote_output(name, encoding='utf-8')) metadata = children[name][1].copy() metadata = update_metadata(metadata, new_metadata, now) if self.create_readonly_node and metadata.get('no-write', False): child = self.create_readonly_node(child, name) children[name] = (child, metadata) new_contents = self.node._pack_contents(children) return new_contents
def render_directory_writecap(self, ctx, data): node = self.original if not IDirectoryNode.providedBy(node): return "" if node.is_readonly(): return "" return ctx.tag[node.get_uri()]
def got_child(self, node_or_failure, ctx, name): req = IRequest(ctx) method = req.method nonterminal = len(req.postpath) > 1 t = get_arg(req, "t", "").strip() if isinstance(node_or_failure, Failure): f = node_or_failure f.trap(NoSuchChildError) # No child by this name. What should we do about it? if nonterminal: if should_create_intermediate_directories(req): # create intermediate directories d = self.node.create_subdirectory(name) d.addCallback(make_handler_for, self.client, self.node, name) return d else: # terminal node if (method,t) in [ ("POST","mkdir"), ("PUT","mkdir"), ("POST", "mkdir-with-children"), ("POST", "mkdir-immutable") ]: # final directory kids = {} if t in ("mkdir-with-children", "mkdir-immutable"): req.content.seek(0) kids_json = req.content.read() kids = convert_children_json(self.client.nodemaker, kids_json) file_format = get_format(req, None) mutable = True mt = get_mutable_type(file_format) if t == "mkdir-immutable": mutable = False d = self.node.create_subdirectory(name, kids, mutable=mutable, mutable_version=mt) d.addCallback(make_handler_for, self.client, self.node, name) return d if (method,t) in ( ("PUT",""), ("PUT","uri"), ): # we were trying to find the leaf filenode (to put a new # file in its place), and it didn't exist. That's ok, # since that's the leaf node that we're about to create. # We make a dummy one, which will respond to the PUT # request by replacing itself. return PlaceHolderNodeHandler(self.client, self.node, name) # otherwise, we just return a no-such-child error return f node = node_or_failure if nonterminal and should_create_intermediate_directories(req): if not IDirectoryNode.providedBy(node): # we would have put a new directory here, but there was a # file in the way. raise WebError("Unable to create directory '%s': " "a file was in the way" % name, http.CONFLICT) return make_handler_for(node, self.client, self.node, name)
def render_directory_verifycap(self, ctx, data): node = self.original if not IDirectoryNode.providedBy(node): return "" verifier = node.get_verify_cap() if verifier: return ctx.tag[node.get_verify_cap().to_string()] return ""
def __init__(self, filenode, nodemaker, uploader): assert IFileNode.providedBy(filenode), filenode assert not IDirectoryNode.providedBy(filenode), filenode self._node = filenode filenode_cap = filenode.get_cap() self._uri = wrap_dirnode_cap(filenode_cap) self._nodemaker = nodemaker self._uploader = uploader
def render_file_writecap(self, ctx, data): node = self.original if IDirectoryNode.providedBy(node): node = node._node write_uri = node.get_write_uri() if not write_uri: return "" return ctx.tag[write_uri]
def render_is_mutable_file(self, ctx, data): node = self.original if IDirectoryNode.providedBy(node): return "" if (IFileNode.providedBy(node) and node.is_mutable() and not node.is_readonly()): return ctx.tag return ""
def render_file_readcap(self, ctx, data): node = self.original if IDirectoryNode.providedBy(node): node = node._node read_uri = node.get_readonly_uri() if not read_uri: return "" return ctx.tag[read_uri]
def render_raw_link(self, ctx, data): node = self.original if IDirectoryNode.providedBy(node): node = node._node elif IFileNode.providedBy(node): pass else: return "" root = self.get_root(ctx) quoted_uri = urllib.quote(node.get_uri()) text_plain_url = "%s/file/%s/@@named=/raw.txt" % (root, quoted_uri) return T.li["Raw data as ", T.a(href=text_plain_url)["text/plain"]]
def _got(children): kids = {} for name, (childnode, metadata) in children.iteritems(): assert IFilesystemNode.providedBy(childnode), childnode rw_uri = childnode.get_write_uri() ro_uri = childnode.get_readonly_uri() if IFileNode.providedBy(childnode): kiddata = ("filenode", {'size': childnode.get_size(), 'mutable': childnode.is_mutable(), }) if childnode.is_mutable(): mutable_type = childnode.get_version() assert mutable_type in (SDMF_VERSION, MDMF_VERSION) if mutable_type == MDMF_VERSION: file_format = "MDMF" else: file_format = "SDMF" else: file_format = "CHK" kiddata[1]['format'] = file_format elif IDirectoryNode.providedBy(childnode): kiddata = ("dirnode", {'mutable': childnode.is_mutable()}) else: kiddata = ("unknown", {}) kiddata[1]["metadata"] = metadata if rw_uri: kiddata[1]["rw_uri"] = rw_uri if ro_uri: kiddata[1]["ro_uri"] = ro_uri verifycap = childnode.get_verify_cap() if verifycap: kiddata[1]['verify_uri'] = verifycap.to_string() kids[name] = kiddata drw_uri = dirnode.get_write_uri() dro_uri = dirnode.get_readonly_uri() contents = { 'children': kids } if dro_uri: contents['ro_uri'] = dro_uri if drw_uri: contents['rw_uri'] = drw_uri verifycap = dirnode.get_verify_cap() if verifycap: contents['verify_uri'] = verifycap.to_string() contents['mutable'] = dirnode.is_mutable() data = ("dirnode", contents) json = simplejson.dumps(data, indent=1) + "\n" return json
def _POST_relink(self, req): charset = get_arg(req, "_charset", "utf-8") replace = parse_replace_arg(get_arg(req, "replace", "true")) from_name = get_arg(req, "from_name") if from_name is not None: from_name = from_name.strip() from_name = from_name.decode(charset) assert isinstance(from_name, unicode) else: raise WebError("from_name= is required") to_name = get_arg(req, "to_name") if to_name is not None: to_name = to_name.strip() to_name = to_name.decode(charset) assert isinstance(to_name, unicode) else: to_name = from_name # Disallow slashes in both from_name and to_name, that would only # cause confusion. if "/" in from_name: raise WebError("from_name= may not contain a slash", http.BAD_REQUEST) if "/" in to_name: raise WebError("to_name= may not contain a slash", http.BAD_REQUEST) to_dir = get_arg(req, "to_dir") if to_dir is not None and to_dir != self.node.get_write_uri(): to_dir = to_dir.strip() to_dir = to_dir.decode(charset) assert isinstance(to_dir, unicode) to_path = to_dir.split(u"/") to_root = self.client.nodemaker.create_from_cap(to_str(to_path[0])) if not IDirectoryNode.providedBy(to_root): raise WebError("to_dir is not a directory", http.BAD_REQUEST) d = to_root.get_child_at_path(to_path[1:]) else: d = defer.succeed(self.node) def _got_new_parent(new_parent): if not IDirectoryNode.providedBy(new_parent): raise WebError("to_dir is not a directory", http.BAD_REQUEST) return self.node.move_child_to(from_name, new_parent, to_name, replace) d.addCallback(_got_new_parent) d.addCallback(lambda res: "thing moved") return d
def get_type(self): node = self.original if IDirectoryNode.providedBy(node): if not node.is_mutable(): return "immutable directory" return "directory" if IFileNode.providedBy(node): si = node.get_storage_index() if si: if node.is_mutable(): return "mutable file" return "immutable file" return "immutable LIT file" return "unknown"
def __init__(self, client, local_path_u, db, collective_dirnode, upload_readonly_dircap, clock, is_upload_pending, umask): QueueMixin.__init__(self, client, local_path_u, db, 'downloader', clock, delay=self.scan_interval) if not IDirectoryNode.providedBy(collective_dirnode): raise AssertionError("The URI in '%s' does not refer to a directory." % os.path.join('private', 'collective_dircap')) if collective_dirnode.is_unknown() or not collective_dirnode.is_readonly(): raise AssertionError("The URI in '%s' is not a readonly cap to a directory." % os.path.join('private', 'collective_dircap')) self._collective_dirnode = collective_dirnode self._upload_readonly_dircap = upload_readonly_dircap self._is_upload_pending = is_upload_pending self._umask = umask
def _get_or_create_directories(self, node, path): if not IDirectoryNode.providedBy(node): # unfortunately it is too late to provide the name of the # blocking directory in the error message. raise ftp.FileExistsError("cannot create directory because there " "is a file in the way") if not path: return defer.succeed(node) d = node.get(path[0]) def _maybe_create(f): f.trap(NoSuchChildError) return node.create_subdirectory(path[0]) d.addErrback(_maybe_create) d.addCallback(self._get_or_create_directories, path[1:]) return d
def __init__(self, client, upload_dircap, local_dir_utf8, inotify=None): service.MultiService.__init__(self) try: local_dir_u = abspath_expanduser_unicode(local_dir_utf8.decode('utf-8')) if sys.platform == "win32": local_dir = local_dir_u else: local_dir = local_dir_u.encode(get_filesystem_encoding()) except (UnicodeEncodeError, UnicodeDecodeError): raise AssertionError("The '[drop_upload] local.directory' parameter %s was not valid UTF-8 or " "could not be represented in the filesystem encoding." % quote_output(local_dir_utf8)) self._client = client self._stats_provider = client.stats_provider self._convergence = client.convergence self._local_path = FilePath(local_dir) self.is_upload_ready = False if inotify is None: from twisted.internet import inotify self._inotify = inotify if not self._local_path.exists(): raise AssertionError("The '[drop_upload] local.directory' parameter was %s but there is no directory at that location." % quote_output(local_dir_u)) if not self._local_path.isdir(): raise AssertionError("The '[drop_upload] local.directory' parameter was %s but the thing at that location is not a directory." % quote_output(local_dir_u)) # TODO: allow a path rather than a cap URI. self._parent = self._client.create_node_from_uri(upload_dircap) if not IDirectoryNode.providedBy(self._parent): raise AssertionError("The URI in 'private/drop_upload_dircap' does not refer to a directory.") if self._parent.is_unknown() or self._parent.is_readonly(): raise AssertionError("The URI in 'private/drop_upload_dircap' is not a writecap to a directory.") self._uploaded_callback = lambda ign: None self._notifier = inotify.INotify() # We don't watch for IN_CREATE, because that would cause us to read and upload a # possibly-incomplete file before the application has closed it. There should always # be an IN_CLOSE_WRITE after an IN_CREATE (I think). # TODO: what about IN_MOVE_SELF or IN_UNMOUNT? mask = inotify.IN_CLOSE_WRITE | inotify.IN_MOVED_TO | inotify.IN_ONLYDIR self._notifier.watch(self._local_path, mask=mask, callbacks=[self._notify])
def modify(self, old_contents, servermap, first_time): children = self.node._unpack_contents(old_contents) if self.name not in children: if first_time and self.must_exist: raise NoSuchChildError(self.name) self.old_child = None return None self.old_child, metadata = children[self.name] # Unknown children can be removed regardless of must_be_directory or must_be_file. if self.must_be_directory and IFileNode.providedBy(self.old_child): raise ChildOfWrongTypeError("delete required a directory, not a file") if self.must_be_file and IDirectoryNode.providedBy(self.old_child): raise ChildOfWrongTypeError("delete required a file, not a directory") del children[self.name] new_contents = self.node._pack_contents(children) return new_contents
def get_type(self): node = self.original if IDirectoryNode.providedBy(node): if not node.is_mutable(): return "immutable directory" return "directory" if IFileNode.providedBy(node): si = node.get_storage_index() if si: if node.is_mutable(): ret = "mutable file" if node.get_version() == MDMF_VERSION: ret += " (mdmf)" else: ret += " (sdmf)" return ret return "immutable file" return "immutable LIT file" return "unknown"
def _deep_traverse_dirnode_children(self, children, parent, path, walker, monitor, found): monitor.raise_if_cancelled() d = defer.maybeDeferred(walker.enter_directory, parent, children) # we process file-like children first, so we can drop their FileNode # objects as quickly as possible. Tests suggest that a FileNode (held # in the client's nodecache) consumes about 2440 bytes. dirnodes (not # in the nodecache) seem to consume about 2000 bytes. dirkids = [] filekids = [] for name, (child, metadata) in sorted(children.iteritems()): childpath = path + [name] if isinstance(child, UnknownNode): walker.add_node(child, childpath) continue verifier = child.get_verify_cap() # allow LIT files (for which verifier==None) to be processed if (verifier is not None) and (verifier in found): continue found.add(verifier) if IDirectoryNode.providedBy(child): dirkids.append( (child, childpath) ) else: filekids.append( (child, childpath) ) for i, (child, childpath) in enumerate(filekids): d.addCallback(lambda ignored, child=child, childpath=childpath: walker.add_node(child, childpath)) # to work around the Deferred tail-recursion problem # (specifically the defer.succeed flavor) requires us to avoid # doing more than 158 LIT files in a row. We insert a turn break # once every 100 files (LIT or CHK) to preserve some stack space # for other code. This is a different expression of the same # Twisted problem as in #237. if i % 100 == 99: d.addCallback(lambda ignored: fireEventually()) for (child, childpath) in dirkids: d.addCallback(lambda ignored, child=child, childpath=childpath: self._deep_traverse_dirnode(child, childpath, walker, monitor, found)) return d
def _made_upload_dir(n): self.failUnless(IDirectoryNode.providedBy(n)) upload_dircap = n.get_uri() readonly_dircap = n.get_readonly_uri() self.shouldFail(AssertionError, 'invalid local.directory', 'could not be represented', DropUploader, client, upload_dircap, '\xFF', inotify=fake_inotify) self.shouldFail(AssertionError, 'nonexistent local.directory', 'there is no directory', DropUploader, client, upload_dircap, os.path.join(self.basedir, "Laputa"), inotify=fake_inotify) fp = filepath.FilePath(self.basedir).child('NOT_A_DIR') fp.touch() self.shouldFail(AssertionError, 'non-directory local.directory', 'is not a directory', DropUploader, client, upload_dircap, fp.path, inotify=fake_inotify) self.shouldFail(AssertionError, 'bad upload.dircap', 'does not refer to a directory', DropUploader, client, 'bad', errors_dir, inotify=fake_inotify) self.shouldFail(AssertionError, 'non-directory upload.dircap', 'does not refer to a directory', DropUploader, client, 'URI:LIT:foo', errors_dir, inotify=fake_inotify) self.shouldFail(AssertionError, 'readonly upload.dircap', 'is not a writecap to a directory', DropUploader, client, readonly_dircap, errors_dir, inotify=fake_inotify)
def add_node(self, node, childpath): if isinstance(node, UnknownNode): self.add("count-unknown") elif IDirectoryNode.providedBy(node): self.add("count-directories") elif IMutableFileNode.providedBy(node): self.add("count-files") self.add("count-mutable-files") # TODO: update the servermap, compute a size, add it to # size-mutable-files, max it into "largest-mutable-file" elif IImmutableFileNode.providedBy(node): # CHK and LIT self.add("count-files") size = node.get_size() self.histogram("size-files-histogram", size) theuri = from_string(node.get_uri()) if isinstance(theuri, LiteralFileURI): self.add("count-literal-files") self.add("size-literal-files", size) else: self.add("count-immutable-files") self.add("size-immutable-files", size) self.max("largest-immutable-file", size)
def _got(children): kids = {} for name, (childnode, metadata) in children.iteritems(): assert IFilesystemNode.providedBy(childnode), childnode rw_uri = childnode.get_write_uri() ro_uri = childnode.get_readonly_uri() if IFileNode.providedBy(childnode): kiddata = ("filenode", get_filenode_metadata(childnode)) elif IDirectoryNode.providedBy(childnode): kiddata = ("dirnode", {'mutable': childnode.is_mutable()}) else: kiddata = ("unknown", {}) kiddata[1]["metadata"] = metadata if rw_uri: kiddata[1]["rw_uri"] = rw_uri if ro_uri: kiddata[1]["ro_uri"] = ro_uri verifycap = childnode.get_verify_cap() if verifycap: kiddata[1]['verify_uri'] = verifycap.to_string() kids[name] = kiddata drw_uri = dirnode.get_write_uri() dro_uri = dirnode.get_readonly_uri() contents = { 'children': kids } if dro_uri: contents['ro_uri'] = dro_uri if drw_uri: contents['rw_uri'] = drw_uri verifycap = dirnode.get_verify_cap() if verifycap: contents['verify_uri'] = verifycap.to_string() contents['mutable'] = dirnode.is_mutable() data = ("dirnode", contents) json = simplejson.dumps(data, indent=1) + "\n" return json
def _list((node, metadata)): if IDirectoryNode.providedBy(node): return node.list() return {path[-1]: (node, metadata)} # need last-edge metadata
def _render((node, metadata)): assert not IDirectoryNode.providedBy(node) return self._populate_row(keys, (node, metadata))
def _got_child(child): if must_be_directory and not IDirectoryNode.providedBy(child): raise ftp.IsNotADirectoryError("rmdir called on a file") if must_be_file and IDirectoryNode.providedBy(child): raise ftp.IsADirectoryError("rmfile called on a directory") return parent.delete(childname)
def got_child(self, node_or_failure, ctx, name): DEBUG = False if DEBUG: print "GOT_CHILD", name, node_or_failure req = IRequest(ctx) method = req.method nonterminal = len(req.postpath) > 1 t = get_arg(req, "t", "").strip() if isinstance(node_or_failure, Failure): f = node_or_failure f.trap(NoSuchChildError) # No child by this name. What should we do about it? if DEBUG: print "no child", name if DEBUG: print "postpath", req.postpath if nonterminal: if DEBUG: print " intermediate" if should_create_intermediate_directories(req): # create intermediate directories if DEBUG: print " making intermediate directory" d = self.node.create_subdirectory(name) d.addCallback(make_handler_for, self.client, self.node, name) return d else: if DEBUG: print " terminal" # terminal node if (method, t) in [("POST", "mkdir"), ("PUT", "mkdir"), ("POST", "mkdir-with-children"), ("POST", "mkdir-immutable")]: if DEBUG: print " making final directory" # final directory kids = {} if t in ("mkdir-with-children", "mkdir-immutable"): req.content.seek(0) kids_json = req.content.read() kids = convert_children_json(self.client.nodemaker, kids_json) file_format = get_format(req, None) mutable = True mt = get_mutable_type(file_format) if t == "mkdir-immutable": mutable = False d = self.node.create_subdirectory(name, kids, mutable=mutable, mutable_version=mt) d.addCallback(make_handler_for, self.client, self.node, name) return d if (method, t) in ( ("PUT", ""), ("PUT", "uri"), ): if DEBUG: print " PUT, making leaf placeholder" # we were trying to find the leaf filenode (to put a new # file in its place), and it didn't exist. That's ok, # since that's the leaf node that we're about to create. # We make a dummy one, which will respond to the PUT # request by replacing itself. return PlaceHolderNodeHandler(self.client, self.node, name) if DEBUG: print " 404" # otherwise, we just return a no-such-child error return f node = node_or_failure if nonterminal and should_create_intermediate_directories(req): if not IDirectoryNode.providedBy(node): # we would have put a new directory here, but there was a # file in the way. if DEBUG: print "blocking" raise WebError( "Unable to create directory '%s': " "a file was in the way" % name, http.CONFLICT) if DEBUG: print "good child" return make_handler_for(node, self.client, self.node, name)
def render_row(self, ctx, data): name, (target, metadata) = data name = name.encode("utf-8") assert not isinstance(name, unicode) nameurl = urllib.quote(name, safe="") # encode any slashes too root = get_root(ctx) here = "%s/uri/%s/" % (root, urllib.quote(self.node.get_uri())) if self.node.is_unknown() or self.node.is_readonly(): unlink = "-" rename = "-" else: # this creates a button which will cause our _POST_unlink method # to be invoked, which unlinks the file and then redirects the # browser back to this directory unlink = T.form(action=here, method="post")[ T.input(type='hidden', name='t', value='unlink'), T.input(type='hidden', name='name', value=name), T.input(type='hidden', name='when_done', value="."), T.input(type='submit', _class='btn', value='unlink', name="unlink"), ] rename = T.form(action=here, method="get")[ T.input(type='hidden', name='t', value='rename-form'), T.input(type='hidden', name='name', value=name), T.input(type='hidden', name='when_done', value="."), T.input(type='submit', _class='btn', value='rename/relink', name="rename"), ] ctx.fillSlots("unlink", unlink) ctx.fillSlots("rename", rename) times = [] linkcrtime = metadata.get('tahoe', {}).get("linkcrtime") if linkcrtime is not None: times.append("lcr: " + render_time(linkcrtime)) else: # For backwards-compatibility with links last modified by Tahoe < 1.4.0: if "ctime" in metadata: ctime = render_time(metadata["ctime"]) times.append("c: " + ctime) linkmotime = metadata.get('tahoe', {}).get("linkmotime") if linkmotime is not None: if times: times.append(T.br()) times.append("lmo: " + render_time(linkmotime)) else: # For backwards-compatibility with links last modified by Tahoe < 1.4.0: if "mtime" in metadata: mtime = render_time(metadata["mtime"]) if times: times.append(T.br()) times.append("m: " + mtime) ctx.fillSlots("times", times) assert IFilesystemNode.providedBy(target), target target_uri = target.get_uri() or "" quoted_uri = urllib.quote(target_uri, safe="") # escape slashes too if IMutableFileNode.providedBy(target): # to prevent javascript in displayed .html files from stealing a # secret directory URI from the URL, send the browser to a URI-based # page that doesn't know about the directory at all dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl) ctx.fillSlots("filename", T.a(href=dlurl, rel="noreferrer")[name]) ctx.fillSlots("type", "SSK") ctx.fillSlots("size", "?") info_link = "%s/uri/%s?t=info" % (root, quoted_uri) elif IImmutableFileNode.providedBy(target): dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl) ctx.fillSlots("filename", T.a(href=dlurl, rel="noreferrer")[name]) ctx.fillSlots("type", "FILE") ctx.fillSlots("size", target.get_size()) info_link = "%s/uri/%s?t=info" % (root, quoted_uri) elif IDirectoryNode.providedBy(target): # directory uri_link = "%s/uri/%s/" % (root, urllib.quote(target_uri)) ctx.fillSlots("filename", T.a(href=uri_link)[name]) if not target.is_mutable(): dirtype = "DIR-IMM" elif target.is_readonly(): dirtype = "DIR-RO" else: dirtype = "DIR" ctx.fillSlots("type", dirtype) ctx.fillSlots("size", "-") info_link = "%s/uri/%s/?t=info" % (root, quoted_uri) elif isinstance(target, ProhibitedNode): ctx.fillSlots("filename", T.strike[name]) if IDirectoryNode.providedBy(target.wrapped_node): blacklisted_type = "DIR-BLACKLISTED" else: blacklisted_type = "BLACKLISTED" ctx.fillSlots("type", blacklisted_type) ctx.fillSlots("size", "-") info_link = None ctx.fillSlots("info", ["Access Prohibited:", T.br, target.reason]) else: # unknown ctx.fillSlots("filename", name) if target.get_write_uri() is not None: unknowntype = "?" elif not self.node.is_mutable() or target.is_alleged_immutable(): unknowntype = "?-IMM" else: unknowntype = "?-RO" ctx.fillSlots("type", unknowntype) ctx.fillSlots("size", "-") # use a directory-relative info link, so we can extract both the # writecap and the readcap info_link = "%s?t=info" % urllib.quote(name) if info_link: ctx.fillSlots("info", T.a(href=info_link)["More Info"]) return ctx.tag
def render_is_directory(self, ctx, data): node = self.original if IDirectoryNode.providedBy(node): return ctx.tag return ""
def test_maker(self): basedir = "client/NodeMaker/maker" fileutil.make_dirs(basedir) fileutil.write(os.path.join(basedir, "tahoe.cfg"), BASECONFIG) c = yield client.create_client(basedir) n = c.create_node_from_uri( "URI:CHK:6nmrpsubgbe57udnexlkiwzmlu:bjt7j6hshrlmadjyr7otq3dc24end5meo5xcr5xe5r663po6itmq:3:10:7277" ) self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failUnless(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failIf(n.is_mutable()) # Testing #1679. There was a bug that would occur when downloader was # downloading the same readcap more than once concurrently, so the # filenode object was cached, and there was a failure from one of the # servers in one of the download attempts. No subsequent download # attempt would attempt to use that server again, which would lead to # the file being undownloadable until the gateway was restarted. The # current fix for this (hopefully to be superceded by a better fix # eventually) is to prevent re-use of filenodes, so the NodeMaker is # hereby required *not* to cache and re-use filenodes for CHKs. other_n = c.create_node_from_uri( "URI:CHK:6nmrpsubgbe57udnexlkiwzmlu:bjt7j6hshrlmadjyr7otq3dc24end5meo5xcr5xe5r663po6itmq:3:10:7277" ) self.failIf(n is other_n, (n, other_n)) n = c.create_node_from_uri("URI:LIT:n5xgk") self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failUnless(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failIf(n.is_mutable()) n = c.create_node_from_uri( "URI:SSK:n6x24zd3seu725yluj75q5boaa:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq" ) self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failUnless(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failIf(n.is_readonly()) self.failUnless(n.is_mutable()) n = c.create_node_from_uri( "URI:SSK-RO:b7sr5qsifnicca7cbk3rhrhbvq:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq" ) self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failUnless(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failUnless(n.is_mutable()) n = c.create_node_from_uri( "URI:DIR2:n6x24zd3seu725yluj75q5boaa:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq" ) self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failUnless(IDirectoryNode.providedBy(n)) self.failIf(n.is_readonly()) self.failUnless(n.is_mutable()) n = c.create_node_from_uri( "URI:DIR2-RO:b7sr5qsifnicca7cbk3rhrhbvq:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq" ) self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failUnless(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failUnless(n.is_mutable()) unknown_rw = "lafs://from_the_future" unknown_ro = "lafs://readonly_from_the_future" n = c.create_node_from_uri(unknown_rw, unknown_ro) self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_unknown()) self.failUnlessReallyEqual(n.get_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_write_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_readonly_uri(), "ro." + unknown_ro) # Note: it isn't that we *intend* to deploy non-ASCII caps in # the future, it is that we want to make sure older Tahoe-LAFS # versions wouldn't choke on them if we were to do so. See # #1051 and wiki:NewCapDesign for details. unknown_rw = u"lafs://from_the_future_rw_\u263A".encode('utf-8') unknown_ro = u"lafs://readonly_from_the_future_ro_\u263A".encode( 'utf-8') n = c.create_node_from_uri(unknown_rw, unknown_ro) self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_unknown()) self.failUnlessReallyEqual(n.get_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_write_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_readonly_uri(), "ro." + unknown_ro)
def render_directory_readcap(self, ctx, data): node = self.original if not IDirectoryNode.providedBy(node): return "" return ctx.tag[node.get_readonly_uri()]
def directory_readcap(self, req, tag): node = self.original if not IDirectoryNode.providedBy(node): return "" return tag(node.get_readonly_uri())
def is_directory(self, req, tag): node = self.original if IDirectoryNode.providedBy(node): return tag return ""
def test_maker(self): basedir = "client/NodeMaker/maker" fileutil.make_dirs(basedir) f = open(os.path.join(basedir, "tahoe.cfg"), "w") f.write(BASECONFIG) f.close() c = client.Client(basedir) n = c.create_node_from_uri("URI:CHK:6nmrpsubgbe57udnexlkiwzmlu:bjt7j6hshrlmadjyr7otq3dc24end5meo5xcr5xe5r663po6itmq:3:10:7277") self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failUnless(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failIf(n.is_mutable()) n = c.create_node_from_uri("URI:LIT:n5xgk") self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failUnless(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failIf(n.is_mutable()) n = c.create_node_from_uri("URI:SSK:n6x24zd3seu725yluj75q5boaa:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq") self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failUnless(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failIf(n.is_readonly()) self.failUnless(n.is_mutable()) n = c.create_node_from_uri("URI:SSK-RO:b7sr5qsifnicca7cbk3rhrhbvq:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq") self.failUnless(IFilesystemNode.providedBy(n)) self.failUnless(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failUnless(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failUnless(n.is_mutable()) n = c.create_node_from_uri("URI:DIR2:n6x24zd3seu725yluj75q5boaa:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq") self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failUnless(IDirectoryNode.providedBy(n)) self.failIf(n.is_readonly()) self.failUnless(n.is_mutable()) n = c.create_node_from_uri("URI:DIR2-RO:b7sr5qsifnicca7cbk3rhrhbvq:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq") self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failUnless(IDirectoryNode.providedBy(n)) self.failUnless(n.is_readonly()) self.failUnless(n.is_mutable()) unknown_rw = "lafs://from_the_future" unknown_ro = "lafs://readonly_from_the_future" n = c.create_node_from_uri(unknown_rw, unknown_ro) self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_unknown()) self.failUnlessReallyEqual(n.get_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_write_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_readonly_uri(), "ro." + unknown_ro) # Note: it isn't that we *intend* to deploy non-ASCII caps in # the future, it is that we want to make sure older Tahoe-LAFS # versions wouldn't choke on them if we were to do so. See # #1051 and wiki:NewCapDesign for details. unknown_rw = u"lafs://from_the_future_rw_\u263A".encode('utf-8') unknown_ro = u"lafs://readonly_from_the_future_ro_\u263A".encode('utf-8') n = c.create_node_from_uri(unknown_rw, unknown_ro) self.failUnless(IFilesystemNode.providedBy(n)) self.failIf(IFileNode.providedBy(n)) self.failIf(IImmutableFileNode.providedBy(n)) self.failIf(IMutableFileNode.providedBy(n)) self.failIf(IDirectoryNode.providedBy(n)) self.failUnless(n.is_unknown()) self.failUnlessReallyEqual(n.get_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_write_uri(), unknown_rw) self.failUnlessReallyEqual(n.get_readonly_uri(), "ro." + unknown_ro)
def render_row(self, ctx, data): name, (target, metadata) = data name = name.encode("utf-8") assert not isinstance(name, unicode) nameurl = urllib.quote(name, safe="") # encode any slashes too root = get_root(ctx) here = "%s/uri/%s/" % (root, urllib.quote(self.node.get_uri())) if self.node.is_unknown() or self.node.is_readonly(): unlink = "-" rename = "-" else: # this creates a button which will cause our _POST_unlink method # to be invoked, which unlinks the file and then redirects the # browser back to this directory unlink = T.form(action=here, method="post")[ T.input(type='hidden', name='t', value='unlink'), T.input(type='hidden', name='name', value=name), T.input(type='hidden', name='when_done', value="."), T.input(type='submit', value='unlink', name="unlink"), ] rename = T.form(action=here, method="get")[ T.input(type='hidden', name='t', value='rename-form'), T.input(type='hidden', name='name', value=name), T.input(type='hidden', name='when_done', value="."), T.input(type='submit', value='rename', name="rename"), ] ctx.fillSlots("unlink", unlink) ctx.fillSlots("rename", rename) times = [] linkcrtime = metadata.get('tahoe', {}).get("linkcrtime") if linkcrtime is not None: times.append("lcr: " + time_format.iso_local(linkcrtime)) else: # For backwards-compatibility with links last modified by Tahoe < 1.4.0: if "ctime" in metadata: ctime = time_format.iso_local(metadata["ctime"]) times.append("c: " + ctime) linkmotime = metadata.get('tahoe', {}).get("linkmotime") if linkmotime is not None: if times: times.append(T.br()) times.append("lmo: " + time_format.iso_local(linkmotime)) else: # For backwards-compatibility with links last modified by Tahoe < 1.4.0: if "mtime" in metadata: mtime = time_format.iso_local(metadata["mtime"]) if times: times.append(T.br()) times.append("m: " + mtime) ctx.fillSlots("times", times) assert IFilesystemNode.providedBy(target), target target_uri = target.get_uri() or "" quoted_uri = urllib.quote(target_uri, safe="") # escape slashes too if IMutableFileNode.providedBy(target): # to prevent javascript in displayed .html files from stealing a # secret directory URI from the URL, send the browser to a URI-based # page that doesn't know about the directory at all dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl) ctx.fillSlots("filename", T.a(href=dlurl)[html.escape(name)]) ctx.fillSlots("type", "SSK") ctx.fillSlots("size", "?") info_link = "%s/uri/%s?t=info" % (root, quoted_uri) elif IImmutableFileNode.providedBy(target): dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl) ctx.fillSlots("filename", T.a(href=dlurl)[html.escape(name)]) ctx.fillSlots("type", "FILE") ctx.fillSlots("size", target.get_size()) info_link = "%s/uri/%s?t=info" % (root, quoted_uri) elif IDirectoryNode.providedBy(target): # directory uri_link = "%s/uri/%s/" % (root, urllib.quote(target_uri)) ctx.fillSlots("filename", T.a(href=uri_link)[html.escape(name)]) if not target.is_mutable(): dirtype = "DIR-IMM" elif target.is_readonly(): dirtype = "DIR-RO" else: dirtype = "DIR" ctx.fillSlots("type", dirtype) ctx.fillSlots("size", "-") info_link = "%s/uri/%s/?t=info" % (root, quoted_uri) elif isinstance(target, ProhibitedNode): ctx.fillSlots("filename", T.strike[name]) if IDirectoryNode.providedBy(target.wrapped_node): blacklisted_type = "DIR-BLACKLISTED" else: blacklisted_type = "BLACKLISTED" ctx.fillSlots("type", blacklisted_type) ctx.fillSlots("size", "-") info_link = None ctx.fillSlots("info", ["Access Prohibited:", T.br, target.reason]) else: # unknown ctx.fillSlots("filename", html.escape(name)) if target.get_write_uri() is not None: unknowntype = "?" elif not self.node.is_mutable() or target.is_alleged_immutable(): unknowntype = "?-IMM" else: unknowntype = "?-RO" ctx.fillSlots("type", unknowntype) ctx.fillSlots("size", "-") # use a directory-relative info link, so we can extract both the # writecap and the readcap info_link = "%s?t=info" % urllib.quote(name) if info_link: ctx.fillSlots("info", T.a(href=info_link)["More Info"]) return ctx.tag