Moving A Child
----------------
-``POST /uri/$DIRCAP/[SUBDIRS../]?t=rename&from_name=OLD&to_dir=TARGET[&to_name=NEW]``
+``POST /uri/$DIRCAP/[SUBDIRS../]?t=move&from_name=OLD&to_dir=TARGET``
This instructs the node to move a child of the given directory to a
- different directory, both of which must be mutable. The child can also be
- renamed in the process. The to_dir parameter can be either the name of a
- subdirectory of the dircap from which the child is being moved (multiple
- levels of descent are supported) or the writecap of an unrelated directory.
-
- This operation will replace any existing child of the new name, making it
- behave like the UNIX "``mv -f``" command. The original child is not
+ different directory, both of which must be mutable. The child can also
+ be renamed in the process. The to_dir parameter should contain the name
+ of a subdirectory of the dircap from which the child is being moved
+ (multiple levels of descent are supported), unless the file is to be
+ moved to an unrelated directory. In the latter case, this can be
+ specified by passing a target_type=uri argument and the target URI in
+ to_dir=. If the target is the name of a subdirectory, this can be
+ signified by passing target_type=name. A new name for the child can
+ also be specified using the to_name= parameter.
+
+ This operation will replace any existing child of the new name, making
+ it behave like the UNIX "``mv -f``" command. The original child is not
unlinked until it is linked into the target directory.
Other Utilities
return d
def test_POST_move_file(self):
- """"""
d = self.POST(self.public_url + "/foo", t="move",
from_name="bar.txt", to_dir="sub")
d.addCallback(lambda res:
d.addCallback(self.failUnlessIsBazDotTxt)
return d
+ def test_POST_move_file_bad_target_type(self):
+ d = self.POST(self.public_url + "/foo", t="move", target_type="*D",
+ from_name="bar.txt", to_dir="sub")
+ d.addBoth(self.shouldFail, error.Error,
+ "test_POST_rename_file_slash_fail",
+ "400 Bad Request",
+ "invalid target_type parameter",
+ )
+ return d
+
def test_POST_move_file_multi_level(self):
d = self.POST(self.public_url + "/foo/sub/level2?t=mkdir", "")
d.addCallback(lambda res: self.POST(self.public_url + "/foo", t="move",
return d
def test_POST_move_file_to_uri(self):
- d = self.POST(self.public_url + "/foo", t="move",
+ d = self.POST(self.public_url + "/foo", t="move", target_type="uri",
from_name="bar.txt", to_dir=self._sub_uri)
d.addCallback(lambda res:
self.failIfNodeHasChild(self._foo_node, u"bar.txt"))
return d
def test_POST_move_file_to_bad_uri(self):
- d = self.POST(self.public_url + "/foo", t="move", from_name="bar.txt",
+ d = self.POST(self.public_url + "/foo", t="move",
+ from_name="bar.txt", target_type="uri",
to_dir="URI:DIR2:mn5jlyjnrjeuydyswlzyui72i:rmneifcj6k6sycjljjhj3f6majsq2zqffydnnul5hfa4j577arma")
d.addBoth(self.shouldFail, error.Error,
"POST_move_file_to_bad_uri",
s.startswith(ALLEGED_READONLY_PREFIX + 'URI:LIT:') or
s.startswith(ALLEGED_IMMUTABLE_PREFIX + 'URI:LIT:'))
-def is_writeable_directory_uri(s):
- if not isinstance(s, str):
- return False
- return (s.startswith('URI:DIR2:') or
- s.startswith(ALLEGED_READONLY_PREFIX + 'URI:DIR2:') or
- s.startswith(ALLEGED_IMMUTABLE_PREFIX + 'URI:DIR2:'))
-
def has_uri_prefix(s):
if not isinstance(s, str):
return False
from foolscap.api import fireEventually
from allmydata.util import base32, time_format
-from allmydata.uri import from_string_dirnode, is_writeable_directory_uri
+from allmydata.uri import from_string_dirnode
from allmydata.interfaces import IDirectoryNode, IFileNode, IFilesystemNode, \
IImmutableFileNode, IMutableFileNode, ExistingChildError, \
NoSuchChildError, EmptyPathnameComponentError, SDMF_VERSION, MDMF_VERSION
if not from_name or not to_dir:
raise WebError("move requires from_name and to_dir")
replace = boolean_of_arg(get_arg(req, "replace", "true"))
+ target_type = get_arg(req, "target_type", "name")
+ if not target_type in ["name", "uri"]:
+ raise WebError("invalid target_type parameter",
+ http.BAD_REQUEST)
# allow from_name to contain slashes, so they can fix names that
# were accidentally created with them. But disallow them in to_name
# (if it's specified), to discourage the practice.
if to_name and "/" in to_name:
- raise WebError("to_name= may not contain a slash", http.BAD_REQUEST)
+ raise WebError("to_name= may not contain a slash",
+ http.BAD_REQUEST)
- d = self.node.has_child(to_dir.split('/')[0])
- def get_target_node(isname):
- if isname or not is_writeable_directory_uri(str(to_dir)):
+ d = defer.Deferred()
+ def get_target_node(target_type):
+ if target_type == "name":
return self.node.get_child_at_path(to_dir)
- else:
+ elif target_type == "uri":
return self.client.create_node_from_uri(str(to_dir))
d.addCallback(get_target_node)
+ d.callback(target_type)
def is_target_node_usable(target_node):
if not IDirectoryNode.providedBy(target_node):
- raise WebError("to_dir is not a usable directory", http.GONE)
+ raise WebError("to_dir is not a usable directory",
+ http.GONE)
return target_node
d.addCallback(is_target_node_usable)
d.addCallback(lambda new_parent: self.node.move_child_to(
<input n:render="when_done" />
Move child:
- <input type="text" name="from_name" readonly="true" n:render="get_name" />
+ <input type="text" name="from_name" readonly="true"
+ n:render="get_name" /><br />
to
<input type="text" name="to_dir" /><br />
+ <input checked="checked" type="radio" id="tt-name"
+ value="name" name="target_type" />
+ <label for="tt-name"> Subdirectory</label>
+ <input type="radio" id="tt-uri" value="uri" name="target_type"/>
+ <label for="tt-uri"> URI</label> <br /><br />
New name?
<input type="text" name="to_name" />
- <input type="submit" value="move" />
+ <input type="submit" value="move" /><br />
</fieldset>
</form>
</div>