mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-19 21:17:54 +00:00
dirnode.py: fix a bug in the no-write change for Adder, and improve test coverage. Add a 'metadata' argument to create_subdirectory, with documentation. Also update some comments in test_dirnode.py made stale by the ctime/mtime change.
This commit is contained in:
parent
db394671e9
commit
29a06457d2
@ -415,9 +415,11 @@ POST /uri?t=mkdir-with-children
|
||||
it is acceptable to set "rw_uri" to that cap and omit "ro_uri". The
|
||||
client must not put a write cap into a "ro_uri" field.
|
||||
|
||||
A file may have a "no-write" metadata field that affects how writes to
|
||||
it are handled via the SFTP frontend; see docs/frontends/FTP-and-SFTP.txt
|
||||
for details.
|
||||
The metadata may have a "no-write" field. If this is set to true in the
|
||||
metadata of a link, it will not be possible to open that link for writing
|
||||
via the SFTP frontend; see docs/frontends/FTP-and-SFTP.txt for details.
|
||||
Also, if the "no-write" field is set to true in the metadata of a link to
|
||||
a mutable child, it will cause the link to be diminished to read-only.
|
||||
|
||||
Note that the webapi-using client application must not provide the
|
||||
"Content-Type: multipart/form-data" header that usually accompanies HTML
|
||||
@ -669,7 +671,9 @@ GET /uri/$DIRCAP/[SUBDIRS../]FILENAME?t=json
|
||||
|
||||
In Tahoe earlier than v1.4.0, only the 'mtime'/'ctime' keys were populated.
|
||||
Starting in Tahoe v1.4.0, the 'linkmotime'/'linkcrtime' keys in the 'tahoe'
|
||||
sub-dict are also populated.
|
||||
sub-dict are also populated. However, prior to v1.7.0, a bug caused the
|
||||
'tahoe' sub-dict to be deleted by webapi requests in which new metadata
|
||||
is specified, and not to be added to existing child links that lack it.
|
||||
|
||||
The reason we added the new values in Tahoe v1.4.0 is that there is a
|
||||
"set_children" API (described below) which you can use to overwrite the
|
||||
|
@ -122,9 +122,10 @@ class MetadataSetter:
|
||||
raise NoSuchChildError(name)
|
||||
|
||||
now = time.time()
|
||||
metadata = update_metadata(children[name][1].copy(), self.metadata, now)
|
||||
child = children[name][0]
|
||||
if self.create_readonly_node and metadata and metadata.get('no-write', False):
|
||||
|
||||
metadata = update_metadata(children[name][1].copy(), self.metadata, now)
|
||||
if self.create_readonly_node and metadata.get('no-write', False):
|
||||
child = self.create_readonly_node(child, name)
|
||||
|
||||
children[name] = (child, metadata)
|
||||
@ -167,10 +168,11 @@ class Adder:
|
||||
raise ExistingChildError("child '%s' already exists" % name)
|
||||
metadata = children[name][1].copy()
|
||||
|
||||
if self.create_readonly_node and metadata and metadata.get('no-write', False):
|
||||
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, update_metadata(metadata, new_metadata, now))
|
||||
children[name] = (child, metadata)
|
||||
new_contents = self.node._pack_contents(children)
|
||||
return new_contents
|
||||
|
||||
@ -591,7 +593,7 @@ class DirectoryNode:
|
||||
return d
|
||||
|
||||
def create_subdirectory(self, name, initial_children={}, overwrite=True,
|
||||
mutable=True):
|
||||
mutable=True, metadata=None):
|
||||
assert isinstance(name, unicode)
|
||||
if self.is_readonly():
|
||||
return defer.fail(NotWriteableError())
|
||||
@ -600,7 +602,7 @@ class DirectoryNode:
|
||||
else:
|
||||
d = self._nodemaker.create_immutable_directory(initial_children)
|
||||
def _created(child):
|
||||
entries = {name: (child, None)}
|
||||
entries = {name: (child, metadata)}
|
||||
a = Adder(self, entries, overwrite=overwrite,
|
||||
create_readonly_node=self._create_readonly_node)
|
||||
d = self._node.modify(a.modify)
|
||||
|
@ -985,7 +985,7 @@ class IDirectoryNode(IFilesystemNode):
|
||||
is a file, or if must_be_file is True and the child is a directory,
|
||||
I raise ChildOfWrongTypeError."""
|
||||
|
||||
def create_subdirectory(name, initial_children={}, overwrite=True):
|
||||
def create_subdirectory(name, initial_children={}, overwrite=True, metadata=None):
|
||||
"""I create and attach a directory at the given name. The new
|
||||
directory can be empty, or it can be populated with children
|
||||
according to 'initial_children', which takes a dictionary in the same
|
||||
|
@ -775,8 +775,7 @@ class Dirnode(GridTestMixin, unittest.TestCase,
|
||||
d.addCallback(lambda metadata:
|
||||
self.failUnlessEqual(set(metadata.keys()), set(["tahoe", "ctime", "mtime"])))
|
||||
|
||||
# or we can add specific metadata at set_uri() time, which
|
||||
# overrides the timestamps
|
||||
# we can also add specific metadata at set_uri() time
|
||||
d.addCallback(lambda res: n.set_uri(u"c4",
|
||||
fake_file_uri, fake_file_uri,
|
||||
{"key": "value"}))
|
||||
@ -790,7 +789,7 @@ class Dirnode(GridTestMixin, unittest.TestCase,
|
||||
d.addCallback(lambda res: n.delete(u"c4"))
|
||||
|
||||
# set_node + metadata
|
||||
# it should be possible to add a child without any metadata
|
||||
# it should be possible to add a child without any metadata except for timestamps
|
||||
d.addCallback(lambda res: n.set_node(u"d2", n, {}))
|
||||
d.addCallback(lambda res: c.create_dirnode())
|
||||
d.addCallback(lambda n2:
|
||||
@ -808,8 +807,7 @@ class Dirnode(GridTestMixin, unittest.TestCase,
|
||||
d.addCallback(lambda metadata:
|
||||
self.failUnlessEqual(set(metadata.keys()), set(["tahoe", "ctime", "mtime"])))
|
||||
|
||||
# or we can add specific metadata at set_node() time, which
|
||||
# overrides the timestamps
|
||||
# we can also add specific metadata at set_node() time
|
||||
d.addCallback(lambda res: n.set_node(u"d4", n,
|
||||
{"key": "value"}))
|
||||
d.addCallback(lambda res: n.get_metadata_for(u"d4"))
|
||||
@ -899,6 +897,11 @@ class Dirnode(GridTestMixin, unittest.TestCase,
|
||||
metadata["tags"] == ["web2.0-compatible"] and
|
||||
"bad" not in metadata["tahoe"], metadata))
|
||||
|
||||
d.addCallback(lambda res:
|
||||
self.shouldFail(NoSuchChildError, "set_metadata_for-nosuch", "",
|
||||
n.set_metadata_for, u"nosuch", {}))
|
||||
|
||||
|
||||
def _start(res):
|
||||
self._start_timestamp = time.time()
|
||||
d.addCallback(_start)
|
||||
@ -1047,6 +1050,35 @@ class Dirnode(GridTestMixin, unittest.TestCase,
|
||||
self.failUnlessEqual(child.get_uri(),
|
||||
other_file_uri))
|
||||
|
||||
|
||||
# Setting the no-write field should diminish a mutable cap to read-only
|
||||
# (for both files and directories).
|
||||
|
||||
d.addCallback(lambda ign: n.set_uri(u"mutable", other_file_uri, other_file_uri))
|
||||
d.addCallback(lambda ign: n.get(u"mutable"))
|
||||
d.addCallback(lambda mutable: self.failIf(mutable.is_readonly(), mutable))
|
||||
d.addCallback(lambda ign: n.set_metadata_for(u"mutable", {"no-write": True}))
|
||||
d.addCallback(lambda ign: n.get(u"mutable"))
|
||||
d.addCallback(lambda mutable: self.failUnless(mutable.is_readonly(), mutable))
|
||||
d.addCallback(lambda ign: n.set_metadata_for(u"mutable", {"no-write": True}))
|
||||
d.addCallback(lambda ign: n.get(u"mutable"))
|
||||
d.addCallback(lambda mutable: self.failUnless(mutable.is_readonly(), mutable))
|
||||
|
||||
d.addCallback(lambda ign: n.get(u"subdir2"))
|
||||
d.addCallback(lambda subdir2: self.failIf(subdir2.is_readonly()))
|
||||
d.addCallback(lambda ign: n.set_metadata_for(u"subdir2", {"no-write": True}))
|
||||
d.addCallback(lambda ign: n.get(u"subdir2"))
|
||||
d.addCallback(lambda subdir2: self.failUnless(subdir2.is_readonly(), subdir2))
|
||||
|
||||
d.addCallback(lambda ign: n.set_uri(u"mutable_ro", other_file_uri, other_file_uri,
|
||||
metadata={"no-write": True}))
|
||||
d.addCallback(lambda ign: n.get(u"mutable_ro"))
|
||||
d.addCallback(lambda mutable_ro: self.failUnless(mutable_ro.is_readonly(), mutable_ro))
|
||||
|
||||
d.addCallback(lambda ign: n.create_subdirectory(u"subdir_ro", metadata={"no-write": True}))
|
||||
d.addCallback(lambda ign: n.get(u"subdir_ro"))
|
||||
d.addCallback(lambda subdir_ro: self.failUnless(subdir_ro.is_readonly(), subdir_ro))
|
||||
|
||||
return d
|
||||
|
||||
d.addCallback(_then)
|
||||
|
Loading…
Reference in New Issue
Block a user