From 3e35959e9b9130a45a83765f7dd79fab4cf0b443 Mon Sep 17 00:00:00 2001
From: david-sarah <david-sarah@jacaranda.org>
Date: Thu, 28 Jan 2010 19:14:24 -0800
Subject: [PATCH] Add mutable field to t=json output for unknown nodes, when
 mutability is known

---
 docs/frontends/webapi.txt      | 39 +++++++++++++++++++++++++++++-----
 src/allmydata/unknown.py       |  3 +++
 src/allmydata/web/directory.py | 22 +++++++++++++------
 3 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/docs/frontends/webapi.txt b/docs/frontends/webapi.txt
index 6e698990..30a11be1 100644
--- a/docs/frontends/webapi.txt
+++ b/docs/frontends/webapi.txt
@@ -556,7 +556,7 @@ GET /uri/$DIRCAP/[SUBDIRS../]FILENAME?t=json
       "ro_uri": file_uri,
       "verify_uri": verify_uri,
       "size": bytes,
-      "mutable": false,
+      "mutable": false
       } ]
 
   If it is a capability to a directory followed by a path from that directory
@@ -575,7 +575,7 @@ GET /uri/$DIRCAP/[SUBDIRS../]FILENAME?t=json
         "mtime": 1202777696.7564139,
         "tahoe": {
           "linkcrtime": 1202777696.7564139,
-          "linkmotime": 1202777696.7564139,
+          "linkmotime": 1202777696.7564139
           } } } ]
 
   If it is a directory, then it includes information about the children of
@@ -602,7 +602,7 @@ GET /uri/$DIRCAP/[SUBDIRS../]FILENAME?t=json
               "mtime": 1202777696.7564139,
               "tahoe": {
                 "linkcrtime": 1202777696.7564139,
-                "linkmotime": 1202777696.7564139,
+                "linkmotime": 1202777696.7564139
                 } } } ],
         "subdir":  [ "dirnode", {
             "rw_uri": rwuri,
@@ -612,7 +612,7 @@ GET /uri/$DIRCAP/[SUBDIRS../]FILENAME?t=json
               "mtime": 1202778111.2160511,
               "tahoe": {
                 "linkcrtime": 1202777696.7564139,
-                "linkmotime": 1202777696.7564139,
+                "linkmotime": 1202777696.7564139
               } } } ]
       } } ]
 
@@ -623,10 +623,39 @@ GET /uri/$DIRCAP/[SUBDIRS../]FILENAME?t=json
   entry of the child is omitted, and the directory view includes the metadata
   that is stored on the directory edge).
 
-  Then the rw_uri field will be present in the information about a directory
+  The rw_uri field will be present in the information about a directory
   if and only if you have read-write access to that directory. The verify_uri
   field will be present if and only if the object has a verify-cap
   (non-distributed LIT files do not have verify-caps).
+  
+  If the cap is of an unknown format, then the file size and verify_uri will
+  not be available:
+
+   GET /uri/$UNKNOWNCAP?t=json :
+
+    [ "unknown", {
+      "rw_uri": unknown_write_uri,
+      "ro_uri": unknown_read_uri
+      } ]
+
+   GET /uri/$DIRCAP/[SUBDIRS../]UNKNOWNCHILDNAME?t=json :
+
+    [ "unknown", {
+      "rw_uri": unknown_write_uri,
+      "ro_uri": unknown_read_uri,
+      "mutable": true,
+      "metadata": {
+        "ctime": 1202777696.7564139,
+        "mtime": 1202777696.7564139,
+        "tahoe": {
+          "linkcrtime": 1202777696.7564139,
+          "linkmotime": 1202777696.7564139
+          } } } ]
+
+  As in the case of file nodes, the metadata will only be present when the
+  capability is to a directory followed by a path. The "mutable" field is also
+  not always present; when it is absent, the mutability of the object is not
+  known.
 
 ==== About the metadata ====
 
diff --git a/src/allmydata/unknown.py b/src/allmydata/unknown.py
index 6b37b146..a8b108ee 100644
--- a/src/allmydata/unknown.py
+++ b/src/allmydata/unknown.py
@@ -146,6 +146,9 @@ class UnknownNode:
         # immutable (or even read-only), provided that no error was detected.
         return not self.error and not self.rw_uri
 
+    def is_alleged_immutable(self):
+        return not self.error and not self.rw_uri and (not self.ro_uri or self.ro_uri.startswith(ALLEGED_IMMUTABLE_PREFIX))
+
     def raise_error(self):
         if self.error is not None:
             raise self.error
diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py
index f046c7fc..4edb2496 100644
--- a/src/allmydata/web/directory.py
+++ b/src/allmydata/web/directory.py
@@ -13,7 +13,7 @@ from nevow.inevow import IRequest
 from foolscap.api import fireEventually
 
 from allmydata.util import base32, time_format
-from allmydata.uri import from_string_dirnode, ALLEGED_IMMUTABLE_PREFIX
+from allmydata.uri import from_string_dirnode
 from allmydata.interfaces import IDirectoryNode, IFileNode, IFilesystemNode, \
      IImmutableFileNode, IMutableFileNode, ExistingChildError, \
      NoSuchChildError, EmptyPathnameComponentError
@@ -739,7 +739,7 @@ class DirectoryAsHTML(rend.Page):
             ctx.fillSlots("filename", html.escape(name))
             if target.get_write_uri() is not None:
                 unknowntype = "?"
-            elif not self.node.is_mutable() or target.get_readonly_uri().startswith(ALLEGED_IMMUTABLE_PREFIX):
+            elif not self.node.is_mutable() or target.is_alleged_immutable():
                 unknowntype = "?-IMM"
             else:
                 unknowntype = "?-RO"
@@ -1096,8 +1096,10 @@ class DeepCheckStreamer(dirnode.DeepStats):
 
         if IDirectoryNode.providedBy(node):
             data["type"] = "directory"
-        else:
+        elif IFileNode.providedBy(node):
             data["type"] = "file"
+        else:
+            data["type"] = "unknown"
 
         v = node.get_verify_cap()
         if v:
@@ -1161,24 +1163,30 @@ class UnknownNodeHandler(RenderMixin, rend.Page):
         if t == "info":
             return MoreInfo(self.node)
         if t == "json":
+            is_parent_known_immutable = self.parentnode and not self.parentnode.is_mutable()
             if self.parentnode and self.name:
                 d = self.parentnode.get_metadata_for(self.name)
             else:
                 d = defer.succeed(None)
-            d.addCallback(lambda md: UnknownJSONMetadata(ctx, self.node, md))
+            d.addCallback(lambda md: UnknownJSONMetadata(ctx, self.node, md, is_parent_known_immutable))
             return d
         raise WebError("GET unknown URI type: can only do t=info and t=json, not t=%s.\n"
                        "Using a webapi server that supports a later version of Tahoe "
                        "may help." % t)
 
-def UnknownJSONMetadata(ctx, filenode, edge_metadata):
-    rw_uri = filenode.get_write_uri()
-    ro_uri = filenode.get_readonly_uri()
+def UnknownJSONMetadata(ctx, node, edge_metadata, is_parent_known_immutable):
+    rw_uri = node.get_write_uri()
+    ro_uri = node.get_readonly_uri()
     data = ("unknown", {})
     if ro_uri:
         data[1]['ro_uri'] = ro_uri
     if rw_uri:
         data[1]['rw_uri'] = rw_uri
+        data[1]['mutable'] = True
+    elif is_parent_known_immutable or node.is_alleged_immutable():
+        data[1]['mutable'] = False
+    # else we don't know whether it is mutable.
+
     if edge_metadata is not None:
         data[1]['metadata'] = edge_metadata
     return text_plain(simplejson.dumps(data, indent=1) + "\n", ctx)
-- 
2.45.2