Author: aum
Date: 2006-06-07 04:11:34 +0000 (Wed, 07 Jun 2006)
New Revision: 9063

Modified:
   trunk/apps/pyFreenet/CHANGELOG
   trunk/apps/pyFreenet/code.leo
   trunk/apps/pyFreenet/fcp/freenetfs.py
   trunk/apps/pyFreenet/fcp/node.py
   trunk/apps/pyFreenet/freedisk.py
   trunk/apps/pyFreenet/freesitemgr
   trunk/apps/pyFreenet/freesitemgr.py
Log:
Changed freesitemgr, now allows inserts from across a LAN if '-s' option used.


Modified: trunk/apps/pyFreenet/CHANGELOG
===================================================================
--- trunk/apps/pyFreenet/CHANGELOG      2006-06-07 01:40:15 UTC (rev 9062)
+++ trunk/apps/pyFreenet/CHANGELOG      2006-06-07 04:11:34 UTC (rev 9063)
@@ -1,6 +1,11 @@

 Revision history for PyFCP

+- Version 0.1.5
+
+    - added global queue and persistence support for fcpget/fcpput
+    - added 'nowait' option to fcpput
+
 - Version 0.1.4

     - added manpages for console programs

Modified: trunk/apps/pyFreenet/code.leo
===================================================================
--- trunk/apps/pyFreenet/code.leo       2006-06-07 01:40:15 UTC (rev 9062)
+++ trunk/apps/pyFreenet/code.leo       2006-06-07 04:11:34 UTC (rev 9063)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <leo_file>
 <leo_header file_format="2" tnodes="0" max_tnode_index="57" clone_windows="0"/>
-<globals body_outline_ratio="0.347234042553">
-       <global_window_position top="30" left="18" height="716" width="1175"/>
+<globals body_outline_ratio="0.267906976744">
+       <global_window_position top="70" left="86" height="636" width="1075"/>
        <global_log_window_position top="0" left="0" height="0" width="0"/>
 </globals>
 <preferences/>
@@ -29,18 +29,19 @@
 </v>
 <v t="aum.20060513073239" a="E"><vh>Package 'fcp'</vh>
 <v t="aum.20060516141235" tnodeList="aum.20060516141235"><vh>@nosent 
__init__.py</vh></v>
-<v t="aum.20060506215707" a="E" 
tnodeList="aum.20060506215707,aum.20060506215707.1,aum.20060506220237,aum.20060506215707.2,aum.20060506215707.3,aum.20060506220237.1,aum.20060506220237.2,aum.20060514223716,aum.20060506231352.1,aum.20060506231352,aum.20060507003931,aum.20060511001853,aum.20060521180804,aum.20060506224238,aum.20060514224855,aum.20060514224919,aum.20060514225725,aum.20060514223936,aum.20060514223822,aum.20060514223845,aum.20060514224020,aum.20060514124642,aum.20060514191601,aum.20060511205201,aum.20060506232639,aum.20060506232639.1,aum.20060511222538,aum.20060512101715,aum.20060511205201.1,aum.20060511205201.2,aum.20060506223545,aum.20060506224238.1,aum.20060506231352.2,aum.20060506220856,aum.20060506222005,aum.20060507124316,aum.20060511103841,aum.20060511103841.1,aum.20060511103952,aum.20060511103952.1,aum.20060604204143,aum.20060514134235,aum.20060512181209,aum.20060514162944,aum.20060514124934,aum.20060512102840,aum.20060514164052,aum.20060509184020.1,aum.20060509184020.2,aum.20060509224119,aum.20060509224221,aum.20060603170554,aum.20060603231840,aum.20060603231840.1,aum.20060603231840.2"><vh>@nosent
 node.py</vh>
+<v t="aum.20060506215707" a="E" 
tnodeList="aum.20060506215707,aum.20060506215707.1,aum.20060506220237,aum.20060506215707.2,aum.20060506215707.3,aum.20060607085345,aum.20060506220237.1,aum.20060506220237.2,aum.20060514223716,aum.20060506231352.1,aum.20060506231352,aum.20060507003931,aum.20060511001853,aum.20060521180804,aum.20060506224238,aum.20060514224855,aum.20060514224919,aum.20060514225725,aum.20060514223936,aum.20060514223822,aum.20060514223845,aum.20060514224020,aum.20060514124642,aum.20060514191601,aum.20060511205201,aum.20060506232639,aum.20060506232639.1,aum.20060511222538,aum.20060512101715,aum.20060511205201.1,aum.20060511205201.2,aum.20060506223545,aum.20060506224238.1,aum.20060506231352.2,aum.20060506220856,aum.20060506222005,aum.20060507124316,aum.20060511103841,aum.20060511103841.1,aum.20060511103952,aum.20060511103952.1,aum.20060604204143,aum.20060514134235,aum.20060512181209,aum.20060514162944,aum.20060514124934,aum.20060512102840,aum.20060514164052,aum.20060509184020.1,aum.20060509184020.2,aum.20060509224119,aum.20060509224221,aum.20060603170554,aum.20060603231840,aum.20060603231840.1,aum.20060603231840.2"><vh>@nosent
 node.py</vh>
 <v t="aum.20060506215707.1"><vh>imports</vh></v>
 <v t="aum.20060506220237"><vh>exceptions</vh></v>
 <v t="aum.20060506215707.2"><vh>globals</vh></v>
 <v t="aum.20060506215707.3" a="E"><vh>class FCPNodeConnection</vh>
+<v t="aum.20060607085345"><vh>attribs</vh></v>
 <v t="aum.20060506220237.1"><vh>__init__</vh></v>
 <v t="aum.20060506220237.2"><vh>__del__</vh></v>
 <v t="aum.20060514223716" a="E"><vh>FCP Primitives</vh>
 <v t="aum.20060506231352.1"><vh>genkey</vh></v>
 <v t="aum.20060506231352"><vh>get</vh></v>
 <v t="aum.20060507003931"><vh>put</vh></v>
-<v t="aum.20060511001853"><vh>putdir</vh></v>
+<v t="aum.20060511001853" a="V"><vh>putdir</vh></v>
 <v t="aum.20060521180804"><vh>invertprivate</vh></v>
 </v>
 <v t="aum.20060506224238" a="E"><vh>Other High Level Methods</vh>
@@ -136,7 +137,7 @@
 <v t="aum.20060507195029.1"><vh>main</vh></v>
 <v t="aum.20060506224545"><vh>mainline</vh></v>
 </v>
-<v t="aum.20060528175118" a="E" 
tnodeList="aum.20060528175118,aum.20060528175118.1,aum.20060528175118.2,aum.20060528175118.3,aum.20060528175118.4,aum.20060528175118.5,aum.20060528175118.6,aum.20060528175118.7,aum.20060528175118.8,aum.20060528175118.9,aum.20060528175118.10,aum.20060528175118.11,aum.20060528175118.12,aum.20060528175118.13,aum.20060528175118.14,aum.20060528175118.15,aum.20060528175118.16,aum.20060528175118.17,aum.20060528175118.18,aum.20060528175118.19,aum.20060528175118.20,aum.20060603153411,aum.20060603160206,aum.20060528175118.21,aum.20060528175118.22,aum.20060528175118.23,aum.20060528175118.24"><vh>@file
 xmlobject.py</vh>
+<v t="aum.20060528175118" 
tnodeList="aum.20060528175118,aum.20060528175118.1,aum.20060528175118.2,aum.20060528175118.3,aum.20060528175118.4,aum.20060528175118.5,aum.20060528175118.6,aum.20060528175118.7,aum.20060528175118.8,aum.20060528175118.9,aum.20060528175118.10,aum.20060528175118.11,aum.20060528175118.12,aum.20060528175118.13,aum.20060528175118.14,aum.20060528175118.15,aum.20060528175118.16,aum.20060528175118.17,aum.20060528175118.18,aum.20060528175118.19,aum.20060528175118.20,aum.20060603153411,aum.20060603160206,aum.20060528175118.21,aum.20060528175118.22,aum.20060528175118.23,aum.20060528175118.24"><vh>@file
 xmlobject.py</vh>
 <v t="aum.20060528175118.1"><vh>imports</vh></v>
 <v t="aum.20060528175118.2"><vh>globals</vh></v>
 <v t="aum.20060528175118.3"><vh>exceptions</vh></v>
@@ -166,21 +167,21 @@
 <v t="aum.20060528175118.24"><vh>_toxml</vh></v>
 </v>
 </v>
-<v t="aum.20060521163823" a="E" 
tnodeList="aum.20060521163823,aum.20060521163823.1,aum.20060521175433,aum.20060521175052,aum.20060521163823.2,aum.20060521163823.5,aum.20060521163823.3,aum.20060521175052.6,aum.20060521175052.4,aum.20060521175052.5,aum.20060521191057,aum.20060526071442,aum.20060526112020,aum.20060521232922,aum.20060521163823.4,aum.20060521185642,aum.20060521163823.14,aum.20060521163823.15,aum.20060521163823.25,aum.20060521163823.6,aum.20060527195652,aum.20060526163608,aum.20060604143559,aum.20060521163823.8,aum.20060521163823.13,aum.20060521163823.18,aum.20060521163823.17,aum.20060521163823.20,aum.20060521163823.21,aum.20060521163823.7,aum.20060521163823.23,aum.20060528214253,aum.20060528214707,aum.20060521163823.12,aum.20060521163823.10,aum.20060521163823.24,aum.20060521163823.11,aum.20060521163823.16,aum.20060521163823.9,aum.20060521163823.19,aum.20060521163823.22,aum.20060528221744,aum.20060530234330,aum.20060528221744.1,aum.20060530151504,aum.20060528221758,aum.20060530151453.1,aum.20060530151453,aum.20060530234330.1,aum.20060530234330.2,aum.20060521185946,aum.20060527114534,aum.20060527114743,aum.20060525194744,aum.20060522231936,aum.20060522225626,aum.20060521190048,aum.20060521190048.1,aum.20060525225133,aum.20060601233442,aum.20060525225133.1,aum.20060525225603,aum.20060525225713,aum.20060527140140.2,aum.20060526072230,aum.20060527114053,aum.20060530202714,aum.20060530202714.1,aum.20060530202714.2,aum.20060530202714.3,aum.20060525193858,aum.20060525194744.1,aum.20060529184826,aum.20060529123536,aum.20060521163823.26"><vh>@file
 freenetfs.py</vh>
+<v t="aum.20060521163823" a="E" 
tnodeList="aum.20060521163823,aum.20060521163823.1,aum.20060521175433,aum.20060521175052,aum.20060521163823.2,aum.20060521163823.5,aum.20060521163823.3,aum.20060604212311,aum.20060604210617,aum.20060604212311.1,aum.20060604213643,aum.20060604223923,aum.20060604223923.1,aum.20060604223923.2,aum.20060521185642,aum.20060521163823.14,aum.20060521163823.15,aum.20060521163823.25,aum.20060521163823.6,aum.20060527195652,aum.20060526163608,aum.20060604143559,aum.20060521163823.8,aum.20060521163823.13,aum.20060521163823.18,aum.20060521163823.17,aum.20060521163823.20,aum.20060521163823.21,aum.20060521163823.7,aum.20060521163823.23,aum.20060528214253,aum.20060528214707,aum.20060521163823.12,aum.20060521163823.10,aum.20060521163823.24,aum.20060521163823.11,aum.20060521163823.16,aum.20060521163823.9,aum.20060521163823.19,aum.20060521163823.22,aum.20060528221744,aum.20060530234330,aum.20060530151504,aum.20060528221758,aum.20060530151453.1,aum.20060530151453,aum.20060530234330.1,aum.20060530234330.2,aum.20060606204304,aum.20060526071442,aum.20060526112020,aum.20060521163823.4,aum.20060521185946,aum.20060527114534,aum.20060527114743,aum.20060522231936,aum.20060522225626,aum.20060521190048,aum.20060521190048.1,aum.20060521232922,aum.20060606204304.1,aum.20060525194744,aum.20060521191057,aum.20060604212812,aum.20060604212812.1,aum.20060606204304.2,aum.20060606204304.3,aum.20060521175052.6,aum.20060521175052.4,aum.20060521175052.5,aum.20060606232825,aum.20060525225133,aum.20060601233442,aum.20060525225133.1,aum.20060525225603,aum.20060525225713,aum.20060527140140.2,aum.20060526072230,aum.20060527114053,aum.20060530202714,aum.20060530202714.1,aum.20060530202714.2,aum.20060530202714.3,aum.20060525193858,aum.20060525194744.1,aum.20060529184826,aum.20060529123536,aum.20060521163823.26"><vh>@file
 freenetfs.py</vh>
 <v t="aum.20060521163823.1"><vh>imports</vh></v>
 <v t="aum.20060521175433"><vh>globals</vh></v>
 <v t="aum.20060521175052"><vh>class ErrnoWrapper</vh></v>
-<v t="aum.20060521163823.2" a="E"><vh>class FreenetFS</vh>
+<v t="aum.20060521163823.2" a="E"><vh>class FreenetBaseFS</vh>
 <v t="aum.20060521163823.5"><vh>attribs</vh></v>
 <v t="aum.20060521163823.3"><vh>__init__</vh></v>
-<v t="aum.20060521175052.6"><vh>run</vh></v>
-<v t="aum.20060521175052.4"><vh>GetContent</vh></v>
-<v t="aum.20060521175052.5"><vh>Invalidate</vh></v>
-<v t="aum.20060521191057"><vh>_loadConfig</vh></v>
-<v t="aum.20060526071442"><vh>setupFiles</vh></v>
-<v t="aum.20060526112020"><vh>connectToNode</vh></v>
-<v t="aum.20060521232922"><vh>log</vh></v>
-<v t="aum.20060521163823.4"><vh>mythread</vh></v>
+<v t="aum.20060604212311" a="E"><vh>command handlers</vh>
+<v t="aum.20060604210617"><vh>executeCommand</vh></v>
+<v t="aum.20060604212311.1"><vh>cmd_hello</vh></v>
+<v t="aum.20060604213643"><vh>cmd_mount</vh></v>
+<v t="aum.20060604223923"><vh>cmd_umount</vh></v>
+<v t="aum.20060604223923.1"><vh>cmd_update</vh></v>
+<v t="aum.20060604223923.2"><vh>cmd_commit</vh></v>
+</v>
 <v t="aum.20060521185642" a="E"><vh>fs primitives</vh>
 <v t="aum.20060521163823.14"><vh>chmod</vh></v>
 <v t="aum.20060521163823.15"><vh>chown</vh></v>
@@ -212,7 +213,6 @@
 </v>
 <v t="aum.20060528221744" a="E"><vh>freedisk methods</vh>
 <v t="aum.20060530234330"><vh>setupFreedisks</vh></v>
-<v t="aum.20060528221744.1"><vh>newDisk</vh></v>
 <v t="aum.20060530151504"><vh>addDisk</vh></v>
 <v t="aum.20060528221758"><vh>delDisk</vh></v>
 <v t="aum.20060530151453.1"><vh>commitDisk</vh></v>
@@ -220,15 +220,34 @@
 <v t="aum.20060530234330.1"><vh>getManifest</vh></v>
 <v t="aum.20060530234330.2"><vh>putManifest</vh></v>
 </v>
+<v t="aum.20060606204304" a="E"><vh>util methods</vh>
+<v t="aum.20060526071442"><vh>setupFiles</vh></v>
+<v t="aum.20060526112020"><vh>connectToNode</vh></v>
+<v t="aum.20060521163823.4"><vh>mythread</vh></v>
 <v t="aum.20060521185946"><vh>hashpath</vh></v>
 <v t="aum.20060527114534"><vh>addToCache</vh></v>
 <v t="aum.20060527114743"><vh>delFromCache</vh></v>
-<v t="aum.20060525194744"><vh>__getDirStat</vh></v>
 <v t="aum.20060522231936"><vh>statFromKw</vh></v>
 <v t="aum.20060522225626"><vh>statToDict</vh></v>
 <v t="aum.20060521190048"><vh>getReadURI</vh></v>
 <v t="aum.20060521190048.1"><vh>getWriteURI</vh></v>
+<v t="aum.20060521232922"><vh>log</vh></v>
 </v>
+<v t="aum.20060606204304.1"><vh>deprecated methods</vh>
+<v t="aum.20060525194744"><vh>__getDirStat</vh></v>
+<v t="aum.20060521191057"><vh>_loadConfig</vh></v>
+</v>
+</v>
+<v t="aum.20060604212812" a="E"><vh>class Freedisk</vh>
+<v t="aum.20060604212812.1"><vh>__init__</vh></v>
+</v>
+<v t="aum.20060606204304.2" a="E"><vh>class FreenetFuseFS</vh>
+<v t="aum.20060606204304.3"><vh>attribs</vh></v>
+<v t="aum.20060521175052.6"><vh>run</vh></v>
+<v t="aum.20060521175052.4"><vh>GetContent</vh></v>
+<v t="aum.20060521175052.5"><vh>Invalidate</vh></v>
+<v t="aum.20060606232825"><vh>tickThread</vh></v>
+</v>
 <v t="aum.20060525225133" a="E"><vh>class FileRecord</vh>
 <v t="aum.20060601233442"><vh>attribs</vh></v>
 <v t="aum.20060525225133.1"><vh>__init__</vh></v>
@@ -238,7 +257,7 @@
 <v t="aum.20060526072230"><vh>addChild</vh></v>
 <v t="aum.20060527114053"><vh>delChild</vh></v>
 </v>
-<v t="aum.20060530202714" a="E"><vh>class FreediskMgr</vh>
+<v t="aum.20060530202714"><vh>class FreediskMgr</vh>
 <v t="aum.20060530202714.1"><vh>__init__</vh></v>
 <v t="aum.20060530202714.2"><vh>update</vh></v>
 <v t="aum.20060530202714.3"><vh>commit</vh></v>
@@ -251,7 +270,7 @@
 </v>
 </v>
 <v t="aum.20060521111625" a="E"><vh>Client Apps</vh>
-<v t="aum.20060513073239.2"><vh>freesitemgr</vh>
+<v t="aum.20060513073239.2" a="E"><vh>freesitemgr</vh>
 <v t="aum.20060516145032" a="E" 
tnodeList="aum.20060516145032,aum.20060516145032.1,aum.20060514132715,aum.20060514132715.1,aum.20060516150511,aum.20060516184736.1,aum.20060516193650,aum.20060516153119,aum.20060516143534.1,aum.20060516144850,aum.20060516143534.2,aum.20060514132715.2,aum.20060514132715.3"><vh>@nosent
 freesitemgr.py</vh>
 <v t="aum.20060516145032.1" a="E"><vh>freesitemgr-script</vh>
 <v t="aum.20060514132715"><vh>imports</vh></v>
@@ -293,7 +312,7 @@
 <v t="aum.20060515200029"><vh>mainline</vh></v>
 </v>
 </v>
-<v t="aum.20060521111625.1" a="E"><vh>get/put/genkey</vh>
+<v t="aum.20060521111625.1"><vh>get/put/genkey</vh>
 <v t="aum.20060521133455" a="E"><vh>fcpget</vh>
 <v t="aum.20060521133455.1" a="E" 
tnodeList="aum.20060521133455.1,aum.20060521133455.2,aum.20060521111727.1,aum.20060521131205,aum.20060521131205.1,aum.20060521131205.2,aum.20060521111727.2,aum.20060521111727.3"><vh>@nosent
 fcpget</vh>
 <v t="aum.20060521133455.2" a="E"><vh>fcpget code</vh>
@@ -323,7 +342,7 @@
 <v t="aum.20060521134737.2"><vh>globals</vh></v>
 <v t="aum.20060521134737.3"><vh>usage</vh></v>
 <v t="aum.20060521134737.4"><vh>help</vh></v>
-<v t="aum.20060521134737.5" a="V"><vh>main</vh></v>
+<v t="aum.20060521134737.5"><vh>main</vh></v>
 <v t="aum.20060521134737.6"><vh>mainline</vh></v>
 </v>
 </v>
@@ -364,7 +383,7 @@
 <v t="aum.20060521163241" a="E"><vh>freedisk</vh>
 <v t="aum.20060529191729" tnodeList="aum.20060529191729"><vh>@file 
mount.freenetfs</vh></v>
 <v t="aum.20060602094531" a="E"><vh>Front ends</vh>
-<v t="aum.20060530170840" a="E" 
tnodeList="aum.20060530170840,aum.20060529123536.1,aum.20060529163723,aum.20060529163723.1,aum.20060603114446,aum.20060604194409,aum.20060604194834,aum.20060603114247,aum.20060530143459.3,aum.20060530143459.4,aum.20060530143459.5,aum.20060530143459.6,aum.20060530143459.7,aum.20060530143459.8,aum.20060530143459.9,aum.20060603164555,aum.20060604144241,aum.20060603121718,aum.20060603125105,aum.20060603121718.1,aum.20060603121848,aum.20060603122324,aum.20060603125848,aum.20060603132557,aum.20060603131227,aum.20060603154804,aum.20060603155318,aum.20060603162815,aum.20060603155642,aum.20060603125405,aum.20060603125405.1,aum.20060529164147,aum.20060529164147.1,aum.20060530160322,aum.20060531160838,aum.20060603100604,aum.20060603100604.1,aum.20060603100604.2,aum.20060604143852,aum.20060603125812,aum.20060603132247,aum.20060529163723.2,aum.20060530142805.1,aum.20060530143459,aum.20060604200719,aum.20060529163723.4"><vh>@file
 freedisk.py</vh>
+<v t="aum.20060530170840" a="E" 
tnodeList="aum.20060530170840,aum.20060529123536.1,aum.20060529163723,aum.20060529163723.1,aum.20060603114446,aum.20060604194409,aum.20060604194834,aum.20060603114247,aum.20060530143459.3,aum.20060607092808,aum.20060530143459.4,aum.20060530143459.5,aum.20060530143459.6,aum.20060530143459.7,aum.20060530143459.8,aum.20060530143459.9,aum.20060603164555,aum.20060604144241,aum.20060604143852,aum.20060603121718,aum.20060603125105,aum.20060603121718.1,aum.20060603121848,aum.20060603122324,aum.20060603125848,aum.20060603132557,aum.20060603131227,aum.20060603154804,aum.20060603155318,aum.20060603162815,aum.20060603155642,aum.20060603125405,aum.20060603125405.1,aum.20060529164147,aum.20060529164147.1,aum.20060530160322,aum.20060531160838,aum.20060603100604,aum.20060603100604.1,aum.20060603100604.2,aum.20060603125812,aum.20060603132247,aum.20060529163723.2,aum.20060530142805.1,aum.20060530143459,aum.20060604200719,aum.20060529163723.4"><vh>@file
 freedisk.py</vh>
 <v t="aum.20060529123536.1" a="E"><vh>freedisk app</vh>
 <v t="aum.20060529163723"><vh>imports</vh></v>
 <v t="aum.20060529163723.1"><vh>globals</vh></v>
@@ -373,6 +392,7 @@
 <v t="aum.20060604194834"><vh>run</vh></v>
 <v t="aum.20060603114247"><vh>cmd_init</vh></v>
 <v t="aum.20060530143459.3"><vh>cmd_start</vh></v>
+<v t="aum.20060607092808"><vh>cmd_run</vh></v>
 <v t="aum.20060530143459.4"><vh>cmd_stop</vh></v>
 <v t="aum.20060530143459.5"><vh>cmd_new</vh></v>
 <v t="aum.20060530143459.6"><vh>cmd_add</vh></v>
@@ -381,8 +401,9 @@
 <v t="aum.20060530143459.9"><vh>cmd_commit</vh></v>
 <v t="aum.20060603164555"><vh>cmd_list</vh></v>
 <v t="aum.20060604144241"><vh>cmd_cmd</vh></v>
+<v t="aum.20060604143852"><vh>doFsCommand</vh></v>
 </v>
-<v t="aum.20060603121718"><vh>class FreediskConfig</vh>
+<v t="aum.20060603121718" a="E"><vh>class FreediskConfig</vh>
 <v t="aum.20060603125105"><vh>attribs</vh></v>
 <v t="aum.20060603121718.1"><vh>__init__</vh></v>
 <v t="aum.20060603121848"><vh>load</vh></v>
@@ -404,7 +425,6 @@
 <v t="aum.20060603100604"><vh>encrypt</vh></v>
 <v t="aum.20060603100604.1"><vh>decrypt</vh></v>
 <v t="aum.20060603100604.2"><vh>getpasswd</vh></v>
-<v t="aum.20060604143852"><vh>doFsCommand</vh></v>
 <v t="aum.20060603125812"><vh>ipython</vh></v>
 <v t="aum.20060603132247"><vh>getyesno</vh></v>
 <v t="aum.20060529163723.2" a="E"><vh>main</vh>
@@ -415,7 +435,7 @@
 <v t="aum.20060529163723.4"><vh>mainline</vh></v>
 </v>
 </v>
-<v t="aum.20060530170840.1" 
tnodeList="aum.20060530170840.1,aum.20060529123536.1,aum.20060529163723,aum.20060529163723.1,aum.20060603114446,aum.20060604194409,aum.20060604194834,aum.20060603114247,aum.20060530143459.3,aum.20060530143459.4,aum.20060530143459.5,aum.20060530143459.6,aum.20060530143459.7,aum.20060530143459.8,aum.20060530143459.9,aum.20060603164555,aum.20060604144241,aum.20060603121718,aum.20060603125105,aum.20060603121718.1,aum.20060603121848,aum.20060603122324,aum.20060603125848,aum.20060603132557,aum.20060603131227,aum.20060603154804,aum.20060603155318,aum.20060603162815,aum.20060603155642,aum.20060603125405,aum.20060603125405.1,aum.20060529164147,aum.20060529164147.1,aum.20060530160322,aum.20060531160838,aum.20060603100604,aum.20060603100604.1,aum.20060603100604.2,aum.20060604143852,aum.20060603125812,aum.20060603132247,aum.20060529163723.2,aum.20060530142805.1,aum.20060530143459,aum.20060604200719,aum.20060529163723.4"><vh>@file
 freedisk</vh>
+<v t="aum.20060530170840.1" 
tnodeList="aum.20060530170840.1,aum.20060529123536.1,aum.20060529163723,aum.20060529163723.1,aum.20060603114446,aum.20060604194409,aum.20060604194834,aum.20060603114247,aum.20060530143459.3,aum.20060607092808,aum.20060530143459.4,aum.20060530143459.5,aum.20060530143459.6,aum.20060530143459.7,aum.20060530143459.8,aum.20060530143459.9,aum.20060603164555,aum.20060604144241,aum.20060604143852,aum.20060603121718,aum.20060603125105,aum.20060603121718.1,aum.20060603121848,aum.20060603122324,aum.20060603125848,aum.20060603132557,aum.20060603131227,aum.20060603154804,aum.20060603155318,aum.20060603162815,aum.20060603155642,aum.20060603125405,aum.20060603125405.1,aum.20060529164147,aum.20060529164147.1,aum.20060530160322,aum.20060531160838,aum.20060603100604,aum.20060603100604.1,aum.20060603100604.2,aum.20060603125812,aum.20060603132247,aum.20060529163723.2,aum.20060530142805.1,aum.20060530143459,aum.20060604200719,aum.20060529163723.4"><vh>@file
 freedisk</vh>
 <v t="aum.20060529123536.1" a="E"><vh>freedisk app</vh>
 <v t="aum.20060529163723"><vh>imports</vh></v>
 <v t="aum.20060529163723.1"><vh>globals</vh></v>
@@ -424,6 +444,7 @@
 <v t="aum.20060604194834"><vh>run</vh></v>
 <v t="aum.20060603114247"><vh>cmd_init</vh></v>
 <v t="aum.20060530143459.3"><vh>cmd_start</vh></v>
+<v t="aum.20060607092808"><vh>cmd_run</vh></v>
 <v t="aum.20060530143459.4"><vh>cmd_stop</vh></v>
 <v t="aum.20060530143459.5"><vh>cmd_new</vh></v>
 <v t="aum.20060530143459.6"><vh>cmd_add</vh></v>
@@ -432,8 +453,9 @@
 <v t="aum.20060530143459.9"><vh>cmd_commit</vh></v>
 <v t="aum.20060603164555"><vh>cmd_list</vh></v>
 <v t="aum.20060604144241"><vh>cmd_cmd</vh></v>
+<v t="aum.20060604143852"><vh>doFsCommand</vh></v>
 </v>
-<v t="aum.20060603121718"><vh>class FreediskConfig</vh>
+<v t="aum.20060603121718" a="E"><vh>class FreediskConfig</vh>
 <v t="aum.20060603125105"><vh>attribs</vh></v>
 <v t="aum.20060603121718.1"><vh>__init__</vh></v>
 <v t="aum.20060603121848"><vh>load</vh></v>
@@ -455,7 +477,6 @@
 <v t="aum.20060603100604"><vh>encrypt</vh></v>
 <v t="aum.20060603100604.1"><vh>decrypt</vh></v>
 <v t="aum.20060603100604.2"><vh>getpasswd</vh></v>
-<v t="aum.20060604143852"><vh>doFsCommand</vh></v>
 <v t="aum.20060603125812"><vh>ipython</vh></v>
 <v t="aum.20060603132247"><vh>getyesno</vh></v>
 <v t="aum.20060529163723.2" a="E"><vh>main</vh>
@@ -1144,6 +1165,8 @@
     client commands and incoming node responses
     """
     log = self._log
+
+    log(DETAIL, "FCPNode: manager thread starting")
     try:
         while self.running:

@@ -6650,7 +6673,8 @@

         - filebyfile - default False - if True, manually inserts
           each constituent file, then performs the ClientPutComplexDir
-          as a manifest full of redirects
+          as a manifest full of redirects. You *must* use this mode
+          if inserting from across a LAN

         - maxretries - maximum number of retries, default 3
         - priority - default 1
@@ -6725,8 +6749,9 @@

             log(INFO, "Launching insert of %s" % relpath)

+            raw = file(fullpath, "rb").read()
             job = self.put("CHK@",
-                           file=fullpath,
+                           data=raw,
                            mimetype=mimetype,
                            async=1,
                            verbosity=verbosity,
@@ -6909,8 +6934,10 @@
     """
     Waits forever (or for a given timeout) for a job to complete
     """
-    self.lock.acquire()
+    while not self.lock.acquire(False):
+        time.sleep(0.1)
     self.lock.release()
+
     return self.getResult()
 </t>
 <t tx="aum.20060511113333"># standard lib imports
@@ -7231,8 +7258,9 @@

     # shut down FCP connection
     if hasattr(self, 'socket'):
-        self.socket.close()
-        del self.socket
+        if not self.noCloseSocket:
+            self.socket.close()
+            del self.socket

     # and close the logfile
     if self.logfile not in [sys.stdout, sys.stderr]:
@@ -7497,6 +7525,7 @@
     elif async:
         return job
     else:
+        self._log(DETAIL, "Waiting on job")
         return job.wait()

 </t>
@@ -7791,6 +7820,11 @@

 Revision history for PyFCP

+- Version 0.1.5
+
+    - added global queue and persistence support for fcpget/fcpput
+    - added 'nowait' option to fcpput
+
 - Version 0.1.4

     - added manpages for console programs
@@ -7853,7 +7887,7 @@
     "fcpput.py", "fcpput",
     "fcpgenkey.py", "fcpgenkey",
     "manpages",
-    "freedisk.py", "freedisk.conf",
+    "freedisk.py", "freedisk", "freedisk.conf",
     "html",
     ]

@@ -8466,7 +8500,10 @@
     print "  -s, --single-files"
     print "          - insert one file at a time as CHKs, then insert"
     print "            a manifest which redirects to these, useful"
-    print "            for debugging"
+    print "            for debugging. Also, you MUST use this mode if"
+    print "            inserting a freesite from across a LAN (ie, if"
+    print "            the FCP service is on a different machine to"
+    print "            the machine running freesitemgr"
     print
     print "Available Commands:"
     print "  setup          - create/edit freesite config file interactively"
@@ -9252,17 +9289,16 @@
 except:
     pass

-import _fuse
 import sys
 from errno import *

 import fcp

 from fcp.xmlobject import XMLFile
-from fcp.node import guessMimetype, base64encode, base64decode
+from fcp.node import guessMimetype, base64encode, base64decode, uriIsPrivate

 </t>
-<t tx="aum.20060521163823.2">class FreenetFS:
+<t tx="aum.20060521163823.2">class FreenetBaseFS:

        @others

@@ -9284,7 +9320,7 @@
         - debug - whether to run in debug mode, default False
     """

-    #self.log("init: args=%s kw=%s" % (args, kw))
+    self.log("FreenetBaseFS.__init__: args=%s kw=%s" % (args, kw))

     for k in ['multithreaded',
               'fcpHost',
@@ -9321,6 +9357,13 @@
         self.log("xmp.py:Xmp:unnamed mount options: %s" % self.optlist)
         self.log("xmp.py:Xmp:named mount options: %s" % self.optdict)

+    try:
+        self.node = None
+        self.connectToNode()
+    except:
+        raise
+        pass
+
 </t>
 <t tx="aum.20060521163823.4">def mythread(self):

@@ -9334,12 +9377,7 @@
     #    print "mythread: ticking"

 </t>
-<t tx="aum.20060521163823.5">_attrs = ['getattr', 'readlink', 'getdir', 
'mknod', 'mkdir',
-      'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
-      'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
-      'statfs', 'fsync']
-
-multithreaded = 0
+<t tx="aum.20060521163823.5">multithreaded = 0
 flags = 1
 debug = False
 fcpHost = fcpHost
@@ -9544,7 +9582,15 @@
 </t>
 <t tx="aum.20060521163823.12">def rename(self, path, path1):

-       ret = os.rename(path, path1)
+    rec = self.files.get(path, None)
+    if not rec:
+        raise IOError(errno.ENOENT, path)
+
+    del self.files[path]
+    self.files[path1] = rec
+    rec.haschanged = True
+    ret = 0
+
     self.log("rename: path=%s path1=%s\n  =&gt; %s" % (path, path1, ret))
        return ret

@@ -9639,7 +9685,7 @@

         # create the record
         rec = self.addToCache(path=path, isreg=True, perm=0644,
-                              iswriting=True)
+                              iswriting=True, haschanged=True)
         ret = 0

         # fall back on host os
@@ -9734,6 +9780,7 @@
         if flags &amp; flag:
             self.log("open: setting iswriting for %s" % path)
             rec.iswriting = True
+            rec.haschanged = True

     self.log("open: open of %s succeeded" % path)

@@ -9799,7 +9846,7 @@

     # ditch any encoded command files
     if path.startswith("/cmds/"):
-        print "got file %s" % path
+        #print "got file %s" % path
         rec = self.files.get(path, None)
         if rec:
             self.delFromCache(rec)
@@ -9888,17 +9935,14 @@
 </t>
 <t tx="aum.20060521175052.6">def run(self):

-    try:
-        self.node = None
-        self.connectToNode()
-    except:
-        #raise
-        pass
+    import _fuse

     d = {'mountpoint': self.mountpoint,
          'multithreaded': self.multithreaded,
          }

+    #print "run: d=%s" % str(d)
+
     if self.debug:
         d['lopts'] = 'debug'

@@ -9913,6 +9957,8 @@
         if hasattr(self,a):
             d[a] = ErrnoWrapper(getattr(self, a))

+    #thread.start_new_thread(self.tickThread, ())
+
     _fuse.main(**d)

 </t>
@@ -10560,6 +10606,9 @@
     # finally, parent constructor, now that we have a complete stat list
     list.__init__(self, statrec)

+    if self.isdir:
+        self.size = 2
+
 </t>
 <t tx="aum.20060525225603">def __getattr__(self, attr):
     """
@@ -10736,6 +10785,7 @@
         # create permissions field
         if isDir:
             perm |= 0755
+            size = 2
         else:
             perm |= 0444

@@ -10759,6 +10809,8 @@
     self.children.append(rec)
     self.size += 1

+    #print "addChild: path=%s size=%s" % (self.path, self.size)
+
 </t>
 <t tx="aum.20060526112020">def connectToNode(self):
     """
@@ -10767,8 +10819,10 @@
     if self.node:
         return

-    self.verbosity = fcp.DETAIL
+    #self.verbosity = fcp.DETAIL

+    self.log("connectToNode: verbosity=%s" % self.verbosity)
+
     try:
         self.node = fcp.FCPNode(host=self.fcpHost,
                                 port=self.fcpPort,
@@ -10852,6 +10906,8 @@
     else:
         print "eh? trying to remove %s from %s" % (rec.path, self.path)

+    #print "delChild: path=%s size=%s" % (self.path, self.size)
+
 </t>
 <t tx="aum.20060527114534">def addToCache(self, rec=None, **kw):
     """
@@ -10890,11 +10946,22 @@
     """
     Tries to remove file/dir record from cache
     """
-    path = rec.path
+    if isinstance(rec, str):
+        path = rec
+        rec = self.files.get(path, None)
+        if not rec:
+            print "delFromCache: no such path %s" % path
+            return
+    else:
+        path = rec.path
+
     parentPath = os.path.split(path)[0]

     if self.files.has_key(path):
+        rec = self.files[path]
         del self.files[path]
+        for child in rec.children:
+            self.delFromCache(child)

     parentRec = self.files.get(parentPath, None)
     if parentRec:
@@ -11665,17 +11732,6 @@
 @others

 </t>
-<t tx="aum.20060528221744.1">def newDisk(self, name, uri=None):
-    """
-    Adds (mounts) a freedisk within freenetfs
-    
-    Arguments:
-        - name - name of disk - will be mounted in as /usr/&lt;name&gt;
-        - uri - a private SSK key URI. If not given, one will be
-          randomly generated
-    """
-
-</t>
 <t tx="aum.20060528221758">def delDisk(self, name):
     """
     drops a freedisk mount
@@ -11683,6 +11739,9 @@
     Arguments:
         - name - the name of the disk
     """
+    diskPath = "/usr/" + name
+    rec = self.freedisks.pop(diskPath)
+    self.delFromCache(rec)

 </t>
 <t tx="aum.20060529123536">def main():
@@ -11702,13 +11761,16 @@
         except:
             args.append(o)

-    #kw['multithreaded'] = True
-    kw['multithreaded'] = False
+    kw['multithreaded'] = True
+    #kw['multithreaded'] = False
+    print "main: kw=%s" % str(kw)
+    

     if os.fork() == 0:
-        server = FreenetFS(mountpoint, *args, **kw)
+        server = FreenetFuseFS(mountpoint, *args, **kw)
         server.run()

+
 </t>
 <t tx="aum.20060529123536.1">"""
 freedisk is a command-line utility for creating,
@@ -11876,41 +11938,36 @@
     conf = self.conf
     kw = self.kw

-    print "starting freedisk service..."
-    fs = freenetfs.FreenetFS(
-            conf.mountpoint,
-            fcpHost=conf.fcpHost,
-            fcpPort=conf.fcpPort,
-            verbosity=conf.fcpVerbosity,
-            debug=kw['debug'],
-            multithreaded=kw['multithreaded'],
-            )
+    # spawn the child
+    print "Spawning freenetfs filesystem process..."
+    os.system("freedisk run &amp;")

-    # spawn a process to run it
-    if os.fork() == 0:
-        print "Mounting freenet fs at %s" % conf.mountpoint
-        fs.run()
+    # wait for child to bring up the fs, via a very crude test
+    keyDir = os.path.join(conf.mountpoint, "keys")
+    print "Waiting for disk to come up..."
+    while not os.path.isdir(keyDir):
+        time.sleep(1)
+    disks = conf.getDisks()
+
+    if disks:
+        print "Freenetfs now mounted, adding existing disks..."
     else:
-        # parent process
-        keyDir = os.path.join(conf.mountpoint, "keys")
-        print "Waiting for disk to come up..."
-        while not os.path.isdir(keyDir):
-            time.sleep(1)
-        disks = conf.getDisks()
-    
-        if disks:
-            print "Freenetfs now mounted, adding existing disks..."
-        else:
-            print "Freenetfs now mounted, no freedisks at present"
-    
-        for disk in disks:
-    
-            diskPath = os.path.join(conf.mountpoint, "usr", disk.name)
-    
-            # barf if a freedisk of that name is already mounted
-            if os.path.exists(diskPath):
-                usage("Freedisk %s seems to be already mounted" % disk.name)
-            
+        print "Freenetfs now mounted, no freedisks at present"
+
+    for disk in disks:
+
+        #break
+
+        diskPath = os.path.join(conf.mountpoint, "usr", disk.name)
+
+        # barf if a freedisk of that name is already mounted
+        if os.path.exists(diskPath):
+            usage("Freedisk %s seems to be already mounted" % disk.name)
+
+        self.doFsCommand("mount %s|%s|%s" % (
+            disk.name, disk.uri, disk.passwd))
+
+        if 0:
             # mkdir to create the freedisk dir
             os.mkdir(diskPath)

@@ -11927,6 +11984,9 @@
             file(privKeyPath, "w").write(disk.privUri)
             file(passwdPath, "w").write(disk.passwd)

+    #while True:
+    #    time.sleep(1)
+
 </t>
 <t tx="aum.20060530143459.4">def cmd_stop(self, *args):
     """
@@ -11962,30 +12022,41 @@

     keys = file(keyPath).read().strip().split("\n")
     pubKey, privKey = [k.split("/")[0].split("freenet:")[-1] for k in keys]
-    
-    # mkdir to create the freedisk dir
-    os.mkdir(diskPath)
-    
-    # wait for the pseudo-files to come into existence
-    while not os.path.isfile(privKeyPath):
-        time.sleep(0.1)
-    
-    #status("About to write to %s" % privKeyPath)
-    
-    file(self.pubKeyPath, "w").write(pubKey)
-    file(self.privKeyPath, "w").write(privKey)
-    file(self.passwdPath, "w").write(passwd)
-    
+
+    print self.doFsCommand("mount %s|%s|%s" % (diskname, privKey, passwd))
+
     # and, of course, update config
-    conf.addDisk(diskname, pubKey, privKey, passwd)
-    
-    </t>
+    conf.addDisk(diskname, privKey, passwd)
+
+    return
+
+
+    # deprecated
+
+    if 0:
+        # mkdir to create the freedisk dir
+        os.mkdir(diskPath)
+        
+        # wait for the pseudo-files to come into existence
+        while not os.path.isfile(privKeyPath):
+            time.sleep(0.1)
+        
+        #status("About to write to %s" % privKeyPath)
+        
+        file(self.pubKeyPath, "w").write(pubKey)
+        file(self.privKeyPath, "w").write(privKey)
+        file(self.passwdPath, "w").write(passwd)
+
+</t>
 <t tx="aum.20060530143459.6">def cmd_add(self, *args):

     nargs = len(args)

+    diskname = self.diskname
+    conf = self.conf
+
     # get uri
-    if nargs &lt; 3:
+    if nargs &lt; 2:
         usage("add: Missing URI")
     uri = args[1]

@@ -11994,25 +12065,38 @@
     # barf if a freedisk of that name is already mounted
     if os.path.exists(self.diskPath):
         usage("Freedisk %s seems to be already mounted" % diskname)
+
+    # get a password if desired
+    passwd = getpasswd("Disk's password", True)
+
+    print self.doFsCommand("mount %s|%s|%s" % (diskname, uri, passwd))
+
+    # and, of course, update config
+    conf.addDisk(diskname, uri, passwd)
+
+    return
+
+    # deprecated
+
+    if 0:    
+        # mkdir to create the freedisk dir
+        os.mkdir(self.diskPath)
+        
+        # wait for the pseudo-files to come into existence
+        while not os.path.isfile(self.privKeyPath):
+            time.sleep(0.1)
+        
+        # set the keys
+        
+        if fcp.node.uriIsPrivate(uri):
+            path = privKeyPath
+        else:
+            path = pubKeyPath
+        f = file(path, "w")
+        f.write(uri)
+        f.flush()
+        f.close()

-    # mkdir to create the freedisk dir
-    os.mkdir(self.diskPath)
-    
-    # wait for the pseudo-files to come into existence
-    while not os.path.isfile(self.privKeyPath):
-        time.sleep(0.1)
-    
-    # set the keys
-    
-    if fcp.node.uriIsPrivate(uri):
-        path = privKeyPath
-    else:
-        path = pubKeyPath
-    f = file(path, "w")
-    f.write(uri)
-    f.flush()
-    f.close()
-    
     </t>
 <t tx="aum.20060530143459.7">def cmd_del(self, *args):
     """
@@ -12025,9 +12109,15 @@

     if not isinstance(disk, XMLNode):
         usage("No such disk '%s'" % diskname)
+
+    self.doFsCommand("umount %s" % diskname)

     conf.delDisk(diskname)

+    return
+
+    # deprecated
+
     path = os.path.join(conf.mountpoint, "usr", diskname)
     os.rmdir(path)

@@ -12036,6 +12126,20 @@
     """
     Updates a freedisk *from* freenet
     """
+    conf = self.conf
+    diskname = self.diskname
+
+    disk = conf.getDisk(diskname)
+    
+    if not isinstance(disk, XMLNode):
+        usage("No such disk '%s'" % diskname)
+
+    self.doFsCommand("update %s" % diskname)
+    
+    return
+
+    # deprecated
+
     cmdPath = self.cmdPath
     diskname = self.diskname

@@ -12051,6 +12155,20 @@
     """
     commits a freedisk *to* freenet
     """
+    conf = self.conf
+    diskname = self.diskname
+
+    disk = conf.getDisk(diskname)
+    
+    if not isinstance(disk, XMLNode):
+        usage("No such disk '%s'" % diskname)
+
+    res = self.doFsCommand("commit %s" % diskname)
+    
+    return res
+
+    # deprecated
+
     cmdPath = self.cmdPath
     diskname = self.diskname

@@ -12118,32 +12236,29 @@
     rootPath = os.path.join("/usr", name)

     # get the freedisk root's record, barf if nonexistent
-    rootRec = self.files.get(rootPath, None)
-    if not rootRec:
-        self.log("commitDisk: no disk '%s' mounted!" % name)
-        return
+    diskRec = self.freedisks.get(name, None)
+    if not diskRec:
+        self.log("commitDisk: no such disk '%s'" % name)
+        return "No such disk '%s'" % name
+    
+    rootRec = diskRec.root

-    # determine pseudo-file paths
-    statusFile = self.files[os.path.join(rootPath, ".status")]
-    privKeyFile = self.files[os.path.join(rootPath, ".privatekey")]
-    pubKeyFile = self.files[os.path.join(rootPath, ".publickey")]
+    # get private key, if any
+    privKey = diskRec.privKey
+    if not privKey:
+        # no private key - disk was mounted readonly with only a pubkey
+        raise IOError(errno.EIO, "Disk %s is read-only" % name)

-    # and get the private key, sans 'freenet:'
-    privKey = privKeyFile.data.split("freenet:")[-1]
-
-    # process further
+    # process the private key to needed format
+    privKey = privKey.split("freenet:")[-1]
     privKey = privKey.replace("SSK@", "USK@").split("/")[0] + "/" + name + "/0"

     self.log("commit: privKey=%s" % privKey)

-    if privKey.startswith("SSK@"):
-        # convert to USK
-        privKey = "USK" + privKey[3:] + "/0"
-    
     self.log("commitDisk: checking files in %s" % rootPath)

     # update status
-    statusFile.data = "committing\nAnalysing files\n"
+    #statusFile.data = "committing\nAnalysing files\n"

     # get list of records of files within this freedisk
     fileRecs = []
@@ -12161,8 +12276,6 @@
     # now sort them
     fileRecs.sort(lambda r1, r2: cmp(r1.path, r2.path))

-    statusFile.data = "committing\nConnecting to Freenet\n"
-
     # make sure we have a node to talk to
     self.connectToNode()
     node = self.node
@@ -12182,8 +12295,6 @@
             chkonly=True,
             mimetype=rec.mimetype)

-    statusFile.data = "committing\nInserting Files\n"
-
     # now, create the manifest
     manifest = XMLFile(root="freedisk")
     root = manifest.root
@@ -12216,9 +12327,6 @@
         nRunning = len(jobsRunning)
         self.log("commit: %s waiting, %s running" % (nWaiting,nRunning))

-        statusFile.data = "committing\n%s files queued, %s inserting\n" % (
-                            nWaiting, nRunning)
-
         # launch jobs, if available, and if spare slots
         while len(jobsRunning) &lt; maxJobs and jobsWaiting:

@@ -12259,19 +12367,20 @@
         else:
             time.sleep(1)

-    statusFile.data = "idle"
+    manifestUri = manifestJob.wait()
+    self.log("commitDisk: done, manifestUri=%s" % manifestUri)

-    self.log("commitDisk: done, manifestUri=%s" % manifestJob.uri)
+    #pubKeyFile.data = manifestJob.uri

-    pubKeyFile.data = manifestJob.uri
-
     endTime = time.time()
     commitTime = endTime - startTime

     self.log("commitDisk: commit completed in %s seconds" % commitTime)

+    return manifestUri
+
 </t>
-<t tx="aum.20060530151504">def addDisk(self, name, uri):
+<t tx="aum.20060530151504">def addDisk(self, name, uri, passwd):
     """
     Adds (mounts) a freedisk within freenetfs

@@ -12281,8 +12390,28 @@
           reveal whether it's public or private. If public, the freedisk
           will be mounted read-only. If private, the freedisk will be
           mounted read/write
+        - passwd - the encryption password for the disk, or empty string
+          if the disk is to be unencrypted
     """
+    print "addDisk: name=%s uri=%s passwd=%s" % (name, uri, passwd)

+    diskPath = "/usr/" + name
+    rec = self.addToCache(path=diskPath, isdir=True, perm=0755, canwrite=True)
+    disk = Freedisk(rec)
+    self.freedisks[name] = disk
+
+    if uriIsPrivate(uri):
+        privKey = uri
+        pubKey = None
+    else:
+        privKey = None
+        pubKey = uri
+    
+    disk.privKey = privKey
+    disk.pubKey = pubKey
+
+    #print "addDisk: done"
+
 </t>
 <t tx="aum.20060530160322">def removeDirAndContents(path):

@@ -12690,7 +12819,7 @@
     return item

 </t>
-<t tx="aum.20060603154804">def addDisk(self, name, uri, privUri, passwd):
+<t tx="aum.20060603154804">def addDisk(self, name, uri, passwd):

     d = self.getDisk(name)
     if isinstance(d, XMLNode):
@@ -12699,7 +12828,6 @@
     diskNode = self.root._addNode("disk")
     diskNode.name = name
     diskNode.uri = uri
-    diskNode.privUri = privUri
     diskNode.passwd = passwd

     self.save()
@@ -12841,35 +12969,32 @@
 </t>
 <t tx="aum.20060604143559"># a command has been encoded via base64

-print "base64 command encoded into %s" % path
-
 cmdBase64 = path.split("/cmds/", 1)[-1]

-print "cmdBase64=%s" % cmdBase64
-
 cmd = base64decode(cmdBase64)

-print "cmd=%s" % cmd
+result = self.executeCommand(cmd)

-result = cmd + "\n" + "done\n"
-
 rec = self.addToCache(path=path, isreg=True, data=result, perm=0644)

 </t>
-<t tx="aum.20060604143852">def doFsCommand(cmd):
+<t tx="aum.20060604143852">def doFsCommand(self, cmd):
     """
     Executes a command via base64-encoded file
     """
     cmdBase64 = fcp.node.base64encode(cmd)
-    path = conf.mountpoint + "/cmds/" + cmdBase64
+    if len(cmdBase64) &gt; 254:
+        raise Exception("Command too long")
+
+    path = self.conf.mountpoint + "/cmds/" + cmdBase64
     return file(path).read()

 </t>
 <t tx="aum.20060604144241">def cmd_cmd(self, *args):

     # arbitrary command, for testing
-    cmd = " ".join(args)
-    print repr(doFsCommand(cmd))
+    cmd = args[0] + "|".join(args[1:])
+    print repr(self.doFsCommand(cmd))

 </t>
 <t tx="aum.20060604194409">def __init__(self, *args, **kw):
@@ -12912,7 +13037,7 @@
     self.cmd_setup = self.cmd_init
     self.cmd_mount = self.cmd_start
     self.cmd_unmoutn = self.cmd_umount = self.cmd_stop
-    
+
 </t>
 <t tx="aum.20060604194834">def run(self):
     """
@@ -12923,12 +13048,14 @@
     if not method:
         usage("Unrecognised command '%s'" % cmd)

-    return method(*self.args[1:])
+    result = method(*self.args[1:]) or ""

+    return result
+
 </t>
 <t tx="aum.20060604200719">mgr = FreediskMgr(*args, **opts)

-mgr.run()
+print mgr.run()

 </t>
 <t tx="aum.20060604204143">def waitTillReqSent(self):
@@ -12938,5 +13065,191 @@
     self.reqSentLock.acquire()

 </t>
+<t tx="aum.20060604210617">def executeCommand(self, cmd):
+    """
+    Executes a single-line command that was submitted as
+    a base64-encoded filename in /cmds/
+    """
+    self.log("executeCommand:cmd=%s" % repr(cmd))
+
+    try:
+        cmd, args = cmd.split(" ", 1)
+        args = args.split("|")
+    except:
+        return "error\nInvalid command %s" % repr(cmd)
+
+    method = getattr(self, "cmd_"+cmd, None)
+    if method:
+        return method(*args)
+    else:
+        return "error\nUnrecognised command %s" % repr(cmd)
+
+</t>
+<t tx="aum.20060604212311"># methods which handle filesystem commands
+
+ at others
+
+</t>
+<t tx="aum.20060604212311.1">def cmd_hello(self, *args):
+    
+    return "ok\nhello: args=%s" % repr(args)
+
+</t>
+<t tx="aum.20060604212812">class Freedisk:
+    """
+    Encapsulates a freedisk
+    """
+    @others
+
+</t>
+<t tx="aum.20060604212812.1">def __init__(self, rootrec):
+    
+    self.root = rootrec
+
+</t>
+<t tx="aum.20060604213643">def cmd_mount(self, *args):
+    """
+    tries to mount a freedisk
+    
+    arguments:
+        - diskname
+        - uri (may be public or private)
+        - password
+    """
+    #print "mount: args=%s" % repr(args)
+
+    try:
+        name, uri, passwd = args
+    except:
+        return "error\nmount: invalid arguments %s" % repr(args)
+
+    try:
+        self.addDisk(name, uri, passwd)
+    except:
+        return "error\nmount: failed to mount disk %s" % name
+
+    return "ok\nmount: successfully mounted disk %s" % name
+
+</t>
+<t tx="aum.20060604223923">def cmd_umount(self, *args):
+    """
+    tries to unmount a freedisk
+    
+    arguments:
+        - diskname
+    """
+    #print "mount: args=%s" % repr(args)
+
+    try:
+        name = args[0]
+    except:
+        return "error\numount: invalid arguments %s" % repr(args)
+
+    try:
+        self.delDisk(name)
+    except:
+        traceback.print_exc()
+        return "error\numount: failed to unmount freedisk '%s'" % name
+    
+    return "ok\numount: successfully unmounted freedisk %s" % name
+
+</t>
+<t tx="aum.20060604223923.1">def cmd_update(self, *args):
+    """
+    Does an update of a freedisk from freenet
+    """
+    #print "update: args=%s" % repr(args)
+
+    try:
+        name = args[0]
+    except:
+        return "error\nupdate: invalid arguments %s" % repr(args)
+
+    try:
+        self.updateDisk(name)
+    except:
+        traceback.print_exc()
+        return "error\nupdate: failed to update freedisk '%s'" % name
+    
+    return "ok\nupdate: successfully updated freedisk '%s'" % name
+
+</t>
+<t tx="aum.20060604223923.2">def cmd_commit(self, *args):
+    """
+    Does an commit of a freedisk into freenet
+    """
+    try:
+        name = args[0]
+    except:
+        return "error\ninvalid arguments %s" % repr(args)
+
+    try:
+        uri = self.commitDisk(name)
+    except:
+        traceback.print_exc()
+        return "error\nfailed to commit freedisk '%s'" % name
+    
+    return "ok\n%s" % uri
+
+</t>
+<t tx="aum.20060606204304"># utility methods
+
+ at others
+
+</t>
+<t tx="aum.20060606204304.1"># deprecated methods
+
+ at others
+
+</t>
+<t tx="aum.20060606204304.2">class FreenetFuseFS(FreenetBaseFS):
+    """
+    Interfaces with FUSE
+    """
+    @others
+</t>
+<t tx="aum.20060606204304.3">_attrs = ['getattr', 'readlink', 'getdir', 
'mknod', 'mkdir',
+      'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
+      'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
+      'statfs', 'fsync']
+
+</t>
+<t tx="aum.20060606232825">def tickThread(self, *args, **kw):
+    
+    print "tickThread: starting"
+    i = 0
+    while True:
+        print "tickThread: n=%s" % i
+        time.sleep(10)
+        i += 1
+
+</t>
+<t tx="aum.20060607085345">noCloseSocket = True
+
+</t>
+<t tx="aum.20060607092808">def cmd_run(self, *args):
+    """
+    become the foreground FUSE process.
+    
+    This is launched by 'freedisk start'
+    """
+    conf = self.conf
+    kw = self.kw
+
+    print "Creating freenetfs filesystem..."
+    fs = freenetfs.FreenetFuseFS(
+            conf.mountpoint,
+            fcpHost=conf.fcpHost,
+            fcpPort=conf.fcpPort,
+            verbosity=conf.fcpVerbosity,
+            debug=kw['debug'],
+            multithreaded=kw['multithreaded'],
+            )
+
+    # never returns, until fs is unmounted
+    print "Freenetfs filesystem now alive..."
+    fs.run()
+
+</t>
 </tnodes>
 </leo_file>

Modified: trunk/apps/pyFreenet/fcp/freenetfs.py
===================================================================
--- trunk/apps/pyFreenet/fcp/freenetfs.py       2006-06-07 01:40:15 UTC (rev 
9062)
+++ trunk/apps/pyFreenet/fcp/freenetfs.py       2006-06-07 04:11:34 UTC (rev 
9063)
@@ -40,14 +40,13 @@
 except:
     pass

-import _fuse
 import sys
 from errno import *

 import fcp

 from fcp.xmlobject import XMLFile
-from fcp.node import guessMimetype, base64encode, base64decode
+from fcp.node import guessMimetype, base64encode, base64decode, uriIsPrivate

 #@-node:imports
 #@+node:globals
@@ -97,16 +96,11 @@


 #@-node:class ErrnoWrapper
-#@+node:class FreenetFS
-class FreenetFS:
+#@+node:class FreenetBaseFS
+class FreenetBaseFS:

     #@ @+others
     #@+node:attribs
-    _attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
-          'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
-          'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
-          'statfs', 'fsync']
-    
     multithreaded = 0
     flags = 1
     debug = False
@@ -151,7 +145,7 @@
             - debug - whether to run in debug mode, default False
         """

-        #self.log("init: args=%s kw=%s" % (args, kw))
+        self.log("FreenetBaseFS.__init__: args=%s kw=%s" % (args, kw))

         for k in ['multithreaded',
                   'fcpHost',
@@ -188,192 +182,137 @@
             self.log("xmp.py:Xmp:unnamed mount options: %s" % self.optlist)
             self.log("xmp.py:Xmp:named mount options: %s" % self.optdict)

-    #@-node:__init__
-    #@+node:run
-    def run(self):
-    
         try:
             self.node = None
             self.connectToNode()
         except:
-            #raise
+            raise
             pass

-        d = {'mountpoint': self.mountpoint,
-             'multithreaded': self.multithreaded,
-             }
+    #@-node:__init__
+    #@+node:command handlers
+    # methods which handle filesystem commands

-        if self.debug:
-            d['lopts'] = 'debug'
+    #@+others
+    #@+node:executeCommand
+    def executeCommand(self, cmd):
+        """
+        Executes a single-line command that was submitted as
+        a base64-encoded filename in /cmds/
+        """
+        self.log("executeCommand:cmd=%s" % repr(cmd))

-        k=[]
-        for opt in ['allow_other', 'kernel_cache']:
-            if getattr(self, opt):
-                k.append(opt)
-        if k:
-            d['kopts'] = ",".join(k)
+        try:
+            cmd, args = cmd.split(" ", 1)
+            args = args.split("|")
+        except:
+            return "error\nInvalid command %s" % repr(cmd)

-        for a in self._attrs:
-            if hasattr(self,a):
-                d[a] = ErrnoWrapper(getattr(self, a))
+        method = getattr(self, "cmd_"+cmd, None)
+        if method:
+            return method(*args)
+        else:
+            return "error\nUnrecognised command %s" % repr(cmd)

-        _fuse.main(**d)
+    #@-node:executeCommand
+    #@+node:cmd_hello
+    def cmd_hello(self, *args):
+        
+        return "ok\nhello: args=%s" % repr(args)

-    #@-node:run
-    #@+node:GetContent
-    def GetContext(self):
-        print "GetContext: called"
-        return _fuse.FuseGetContext(self)
-    
-    #@-node:GetContent
-    #@+node:Invalidate
-    def Invalidate(self, path):
-        print "Invalidate: called"
-        return _fuse.FuseInvalidate(self, path)
-    
-    #@-node:Invalidate
-    #@+node:_loadConfig
-    def _loadConfig(self):
+    #@-node:cmd_hello
+    #@+node:cmd_mount
+    def cmd_mount(self, *args):
         """
-        The 'physical device' argument to mount should be the pathname
-        of a configuration file, with 'name=val' lines, including the
-        following items:
-            - publickey=<freenet public key URI>
-            - privatekey=<freenet private key URI> (optional, without which we
-              will have the fs mounted readonly
+        tries to mount a freedisk
+        
+        arguments:
+            - diskname
+            - uri (may be public or private)
+            - password
         """
-        opts = {}
+        #print "mount: args=%s" % repr(args)

-        # build a dict of all the 'name=value' pairs in config file
-        for line in [l.strip() for l in file(self.config).readlines()]:
-            if line == '' or line.startswith("#"):
-                continue
-            try:
-                name, val = line.split("=", 1)
-                opts[name.strip()] = val.strip()
-            except:
-                pass
+        try:
+            name, uri, passwd = args
+        except:
+            return "error\nmount: invalid arguments %s" % repr(args)

-        # mandate a pubkey
         try:
-            self.pubkey = opts['pubkey'].replace("SSK@", "USK@").split("/")[0] 
+ "/"
+            self.addDisk(name, uri, passwd)
         except:
-            raise Exception("Config file %s: missing or invalid publickey" \
-                            % self.configfile)
+            return "error\nmount: failed to mount disk %s" % name

-        # accept optional privkey
-        if opts.has_key("privkey"):
+        return "ok\nmount: successfully mounted disk %s" % name

-            try:
-                self.privkey = opts['privkey'].replace("SSK@",
-                                                     "USK@").split("/")[0] + 
"/"
-            except:
-                raise Exception("Config file %s: invalid privkey" \
-                                % self.configfile)
+    #@-node:cmd_mount
+    #@+node:cmd_umount
+    def cmd_umount(self, *args):
+        """
+        tries to unmount a freedisk
+        
+        arguments:
+            - diskname
+        """
+        #print "mount: args=%s" % repr(args)

-        # mandate cachepath
         try:
-            self.cachedir = opts['cachedir']
-            if not os.path.isdir(self.cachedir):
-                self.log("Creating cache directory %s" % self.cachedir)
-                os.makedirs(self.cachedir)
-                #raise hell
+            name = args[0]
         except:
-            raise Exception("config file %s: missing or invalid cache 
directory" \
-                            % self.configfile)
+            return "error\numount: invalid arguments %s" % repr(args)

-    #@-node:_loadConfig
-    #@+node:setupFiles
-    def setupFiles(self):
+        try:
+            self.delDisk(name)
+        except:
+            traceback.print_exc()
+            return "error\numount: failed to unmount freedisk '%s'" % name
+        
+        return "ok\numount: successfully unmounted freedisk %s" % name
+    
+    #@-node:cmd_umount
+    #@+node:cmd_update
+    def cmd_update(self, *args):
         """
-        Create initial file/directory layout, according
-        to attributes 'initialFiles' and 'chrFiles'
+        Does an update of a freedisk from freenet
         """
-        # easy map of files
-        self.files = {}
+        #print "update: args=%s" % repr(args)

-        # now create records for initial files
-        for path in self.initialFiles:
+        try:
+            name = args[0]
+        except:
+            return "error\nupdate: invalid arguments %s" % repr(args)

-            # initial attribs
-            isReg = isDir = isChr = isSock = isFifo = False
-            perm = size = 0
+        try:
+            self.updateDisk(name)
+        except:
+            traceback.print_exc()
+            return "error\nupdate: failed to update freedisk '%s'" % name
+        
+        return "ok\nupdate: successfully updated freedisk '%s'" % name

-            # determine file type
-            if path.endswith("/"):
-                isDir = True
-                path = path[:-1]
-                if not path:
-                    path = "/"
-            elif path in self.chrFiles:
-                # it's a char file
-                #isChr = True
-                isReg = True
-                perm |= 0666
-                size = 1024
-            else:
-                # by default, it's a regular file
-                isReg = True
-    
-            # create permissions field
-            if isDir:
-                perm |= 0755
-            else:
-                perm |= 0444
-    
-            # create record for this path
-            self.addToCache(
-                path=path,
-                perm=perm,
-                size=size,
-                isdir=isDir, isreg=isReg, ischr=isChr,
-                issock=isSock, isfifo=isFifo,
-                )
-    
-    #@-node:setupFiles
-    #@+node:connectToNode
-    def connectToNode(self):
+    #@-node:cmd_update
+    #@+node:cmd_commit
+    def cmd_commit(self, *args):
         """
-        Attempts a connection to an fcp node
+        Does an commit of a freedisk into freenet
         """
-        if self.node:
-            return
-        
-        self.verbosity = fcp.DETAIL
+        try:
+            name = args[0]
+        except:
+            return "error\ninvalid arguments %s" % repr(args)

         try:
-            self.node = fcp.FCPNode(host=self.fcpHost,
-                                    port=self.fcpPort,
-                                    verbosity=self.verbosity)
+            uri = self.commitDisk(name)
         except:
-            raise IOError(errno.EIO, "Failed to reach FCP service at %s:%s" % (
-                            self.fcpHost, self.fcpPort))
+            traceback.print_exc()
+            return "error\nfailed to commit freedisk '%s'" % name
+        
+        return "ok\n%s" % uri

-        #self.log("pubkey=%s" % self.pubkey)
-        #self.log("privkey=%s" % self.privkey)
-        #self.log("cachedir=%s" % self.cachedir)
+    #@-node:cmd_commit
+    #@-others

-    #@-node:connectToNode
-    #@+node:log
-    def log(self, msg):
-        #if not quiet:
-        #    print "freedisk:"+msg
-        file("/tmp/freedisk.log", "a").write(msg+"\n")
-    
-    #@-node:log
-    #@+node:mythread
-    def mythread(self):
-    
-        """
-        The beauty of the FUSE python implementation is that with the python 
interp
-        running in foreground, you can have threads
-        """    
-        self.log("mythread: started")
-        #while 1:
-        #    time.sleep(120)
-        #    print "mythread: ticking"
-    
-    #@-node:mythread
+    #@-node:command handlers
     #@+node:fs primitives
     # primitives required for actual fs operations

@@ -457,18 +396,12 @@
                 #@+node:<<base64 command>>
                 # a command has been encoded via base64

-                print "base64 command encoded into %s" % path
-                
                 cmdBase64 = path.split("/cmds/", 1)[-1]

-                print "cmdBase64=%s" % cmdBase64
-                
                 cmd = base64decode(cmdBase64)

-                print "cmd=%s" % cmd
+                result = self.executeCommand(cmd)

-                result = cmd + "\n" + "done\n"
-                
                 rec = self.addToCache(path=path, isreg=True, data=result, 
perm=0644)

                 #@-node:<<base64 command>>
@@ -613,7 +546,7 @@

             # create the record
             rec = self.addToCache(path=path, isreg=True, perm=0644,
-                                  iswriting=True)
+                                  iswriting=True, haschanged=True)
             ret = 0

             # fall back on host os
@@ -653,6 +586,7 @@
             if flags & flag:
                 self.log("open: setting iswriting for %s" % path)
                 rec.iswriting = True
+                rec.haschanged = True

         self.log("open: open of %s succeeded" % path)

@@ -706,7 +640,7 @@

         # ditch any encoded command files
         if path.startswith("/cmds/"):
-            print "got file %s" % path
+            #print "got file %s" % path
             rec = self.files.get(path, None)
             if rec:
                 self.delFromCache(rec)
@@ -843,7 +777,15 @@
     #@+node:rename
     def rename(self, path, path1):

-       ret = os.rename(path, path1)
+        rec = self.files.get(path, None)
+        if not rec:
+            raise IOError(errno.ENOENT, path)
+    
+        del self.files[path]
+        self.files[path1] = rec
+        rec.haschanged = True
+        ret = 0
+    
         self.log("rename: path=%s path1=%s\n  => %s" % (path, path1, ret))
        return ret

@@ -1067,20 +1009,8 @@
         self.freedisks = {}

     #@-node:setupFreedisks
-    #@+node:newDisk
-    def newDisk(self, name, uri=None):
-        """
-        Adds (mounts) a freedisk within freenetfs
-        
-        Arguments:
-            - name - name of disk - will be mounted in as /usr/<name>
-            - uri - a private SSK key URI. If not given, one will be
-              randomly generated
-        """
-    
-    #@-node:newDisk
     #@+node:addDisk
-    def addDisk(self, name, uri):
+    def addDisk(self, name, uri, passwd):
         """
         Adds (mounts) a freedisk within freenetfs

@@ -1090,8 +1020,28 @@
               reveal whether it's public or private. If public, the freedisk
               will be mounted read-only. If private, the freedisk will be
               mounted read/write
+            - passwd - the encryption password for the disk, or empty string
+              if the disk is to be unencrypted
         """
+        print "addDisk: name=%s uri=%s passwd=%s" % (name, uri, passwd)

+        diskPath = "/usr/" + name
+        rec = self.addToCache(path=diskPath, isdir=True, perm=0755, 
canwrite=True)
+        disk = Freedisk(rec)
+        self.freedisks[name] = disk
+    
+        if uriIsPrivate(uri):
+            privKey = uri
+            pubKey = None
+        else:
+            privKey = None
+            pubKey = uri
+        
+        disk.privKey = privKey
+        disk.pubKey = pubKey
+    
+        #print "addDisk: done"
+    
     #@-node:addDisk
     #@+node:delDisk
     def delDisk(self, name):
@@ -1101,6 +1051,9 @@
         Arguments:
             - name - the name of the disk
         """
+        diskPath = "/usr/" + name
+        rec = self.freedisks.pop(diskPath)
+        self.delFromCache(rec)

     #@-node:delDisk
     #@+node:commitDisk
@@ -1119,32 +1072,29 @@
         rootPath = os.path.join("/usr", name)

         # get the freedisk root's record, barf if nonexistent
-        rootRec = self.files.get(rootPath, None)
-        if not rootRec:
-            self.log("commitDisk: no disk '%s' mounted!" % name)
-            return
+        diskRec = self.freedisks.get(name, None)
+        if not diskRec:
+            self.log("commitDisk: no such disk '%s'" % name)
+            return "No such disk '%s'" % name
+        
+        rootRec = diskRec.root

-        # determine pseudo-file paths
-        statusFile = self.files[os.path.join(rootPath, ".status")]
-        privKeyFile = self.files[os.path.join(rootPath, ".privatekey")]
-        pubKeyFile = self.files[os.path.join(rootPath, ".publickey")]
+        # get private key, if any
+        privKey = diskRec.privKey
+        if not privKey:
+            # no private key - disk was mounted readonly with only a pubkey
+            raise IOError(errno.EIO, "Disk %s is read-only" % name)

-        # and get the private key, sans 'freenet:'
-        privKey = privKeyFile.data.split("freenet:")[-1]
-    
-        # process further
+        # process the private key to needed format
+        privKey = privKey.split("freenet:")[-1]
         privKey = privKey.replace("SSK@", "USK@").split("/")[0] + "/" + name + 
"/0"

         self.log("commit: privKey=%s" % privKey)

-        if privKey.startswith("SSK@"):
-            # convert to USK
-            privKey = "USK" + privKey[3:] + "/0"
-        
         self.log("commitDisk: checking files in %s" % rootPath)

         # update status
-        statusFile.data = "committing\nAnalysing files\n"
+        #statusFile.data = "committing\nAnalysing files\n"

         # get list of records of files within this freedisk
         fileRecs = []
@@ -1162,8 +1112,6 @@
         # now sort them
         fileRecs.sort(lambda r1, r2: cmp(r1.path, r2.path))

-        statusFile.data = "committing\nConnecting to Freenet\n"
-    
         # make sure we have a node to talk to
         self.connectToNode()
         node = self.node
@@ -1183,8 +1131,6 @@
                 chkonly=True,
                 mimetype=rec.mimetype)

-        statusFile.data = "committing\nInserting Files\n"
-    
         # now, create the manifest
         manifest = XMLFile(root="freedisk")
         root = manifest.root
@@ -1217,9 +1163,6 @@
             nRunning = len(jobsRunning)
             self.log("commit: %s waiting, %s running" % (nWaiting,nRunning))

-            statusFile.data = "committing\n%s files queued, %s inserting\n" % (
-                                nWaiting, nRunning)
-    
             # launch jobs, if available, and if spare slots
             while len(jobsRunning) < maxJobs and jobsWaiting:

@@ -1260,17 +1203,18 @@
             else:
                 time.sleep(1)

-        statusFile.data = "idle"
+        manifestUri = manifestJob.wait()
+        self.log("commitDisk: done, manifestUri=%s" % manifestUri)

-        self.log("commitDisk: done, manifestUri=%s" % manifestJob.uri)
+        #pubKeyFile.data = manifestJob.uri

-        pubKeyFile.data = manifestJob.uri
-    
         endTime = time.time()
         commitTime = endTime - startTime

         self.log("commitDisk: commit completed in %s seconds" % commitTime)

+        return manifestUri
+    
     #@-node:commitDisk
     #@+node:updateDisk
     def updateDisk(self, name):
@@ -1329,6 +1273,97 @@
     #@-others

     #@-node:freedisk methods
+    #@+node:util methods
+    # utility methods
+    
+    #@+others
+    #@+node:setupFiles
+    def setupFiles(self):
+        """
+        Create initial file/directory layout, according
+        to attributes 'initialFiles' and 'chrFiles'
+        """
+        # easy map of files
+        self.files = {}
+    
+        # now create records for initial files
+        for path in self.initialFiles:
+    
+            # initial attribs
+            isReg = isDir = isChr = isSock = isFifo = False
+            perm = size = 0
+    
+            # determine file type
+            if path.endswith("/"):
+                isDir = True
+                path = path[:-1]
+                if not path:
+                    path = "/"
+            elif path in self.chrFiles:
+                # it's a char file
+                #isChr = True
+                isReg = True
+                perm |= 0666
+                size = 1024
+            else:
+                # by default, it's a regular file
+                isReg = True
+    
+            # create permissions field
+            if isDir:
+                perm |= 0755
+                size = 2
+            else:
+                perm |= 0444
+    
+            # create record for this path
+            self.addToCache(
+                path=path,
+                perm=perm,
+                size=size,
+                isdir=isDir, isreg=isReg, ischr=isChr,
+                issock=isSock, isfifo=isFifo,
+                )
+    
+    #@-node:setupFiles
+    #@+node:connectToNode
+    def connectToNode(self):
+        """
+        Attempts a connection to an fcp node
+        """
+        if self.node:
+            return
+        
+        #self.verbosity = fcp.DETAIL
+    
+        self.log("connectToNode: verbosity=%s" % self.verbosity)
+    
+        try:
+            self.node = fcp.FCPNode(host=self.fcpHost,
+                                    port=self.fcpPort,
+                                    verbosity=self.verbosity)
+        except:
+            raise IOError(errno.EIO, "Failed to reach FCP service at %s:%s" % (
+                            self.fcpHost, self.fcpPort))
+    
+        #self.log("pubkey=%s" % self.pubkey)
+        #self.log("privkey=%s" % self.privkey)
+        #self.log("cachedir=%s" % self.cachedir)
+    
+    #@-node:connectToNode
+    #@+node:mythread
+    def mythread(self):
+    
+        """
+        The beauty of the FUSE python implementation is that with the python 
interp
+        running in foreground, you can have threads
+        """    
+        self.log("mythread: started")
+        #while 1:
+        #    time.sleep(120)
+        #    print "mythread: ticking"
+    
+    #@-node:mythread
     #@+node:hashpath
     def hashpath(self, path):

@@ -1374,25 +1409,28 @@
         """
         Tries to remove file/dir record from cache
         """
-        path = rec.path
+        if isinstance(rec, str):
+            path = rec
+            rec = self.files.get(path, None)
+            if not rec:
+                print "delFromCache: no such path %s" % path
+                return
+        else:
+            path = rec.path
+    
         parentPath = os.path.split(path)[0]

         if self.files.has_key(path):
+            rec = self.files[path]
             del self.files[path]
+            for child in rec.children:
+                self.delFromCache(child)

         parentRec = self.files.get(parentPath, None)
         if parentRec:
             parentRec.delChild(rec)

     #@-node:delFromCache
-    #@+node:__getDirStat
-    def __getDirStat(self, path):
-        """
-        returns a stat tuple for given path
-        """
-        return FileRecord(mode=0700, path=path, isdir=True)
-    
-    #@-node:__getDirStat
     #@+node:statFromKw
     def statFromKw(self, **kw):
         """
@@ -1506,9 +1544,168 @@
         return self.privkey + self.hashpath(path) + "/0"

     #@-node:getWriteURI
+    #@+node:log
+    def log(self, msg):
+        #if not quiet:
+        #    print "freedisk:"+msg
+        file("/tmp/freedisk.log", "a").write(msg+"\n")
+    
+    #@-node:log
     #@-others
+    
+    #@-node:util methods
+    #@+node:deprecated methods
+    # deprecated methods
+    
+    #@+others
+    #@+node:__getDirStat
+    def __getDirStat(self, path):
+        """
+        returns a stat tuple for given path
+        """
+        return FileRecord(mode=0700, path=path, isdir=True)
+    
+    #@-node:__getDirStat
+    #@+node:_loadConfig
+    def _loadConfig(self):
+        """
+        The 'physical device' argument to mount should be the pathname
+        of a configuration file, with 'name=val' lines, including the
+        following items:
+            - publickey=<freenet public key URI>
+            - privatekey=<freenet private key URI> (optional, without which we
+              will have the fs mounted readonly
+        """
+        opts = {}
+    
+        # build a dict of all the 'name=value' pairs in config file
+        for line in [l.strip() for l in file(self.config).readlines()]:
+            if line == '' or line.startswith("#"):
+                continue
+            try:
+                name, val = line.split("=", 1)
+                opts[name.strip()] = val.strip()
+            except:
+                pass
+    
+        # mandate a pubkey
+        try:
+            self.pubkey = opts['pubkey'].replace("SSK@", "USK@").split("/")[0] 
+ "/"
+        except:
+            raise Exception("Config file %s: missing or invalid publickey" \
+                            % self.configfile)
+    
+        # accept optional privkey
+        if opts.has_key("privkey"):
+    
+            try:
+                self.privkey = opts['privkey'].replace("SSK@",
+                                                     "USK@").split("/")[0] + 
"/"
+            except:
+                raise Exception("Config file %s: invalid privkey" \
+                                % self.configfile)
+    
+        # mandate cachepath
+        try:
+            self.cachedir = opts['cachedir']
+            if not os.path.isdir(self.cachedir):
+                self.log("Creating cache directory %s" % self.cachedir)
+                os.makedirs(self.cachedir)
+                #raise hell
+        except:
+            raise Exception("config file %s: missing or invalid cache 
directory" \
+                            % self.configfile)
+    
+    #@-node:_loadConfig
+    #@-others
+    
+    #@-node:deprecated methods
+    #@-others

-#@-node:class FreenetFS
+#@-node:class FreenetBaseFS
+#@+node:class Freedisk
+class Freedisk:
+    """
+    Encapsulates a freedisk
+    """
+    #@    @+others
+    #@+node:__init__
+    def __init__(self, rootrec):
+        
+        self.root = rootrec
+    
+    #@-node:__init__
+    #@-others
+
+#@-node:class Freedisk
+#@+node:class FreenetFuseFS
+class FreenetFuseFS(FreenetBaseFS):
+    """
+    Interfaces with FUSE
+    """
+    #@    @+others
+    #@+node:attribs
+    _attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
+          'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
+          'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
+          'statfs', 'fsync']
+    
+    #@-node:attribs
+    #@+node:run
+    def run(self):
+    
+        import _fuse
+    
+        d = {'mountpoint': self.mountpoint,
+             'multithreaded': self.multithreaded,
+             }
+    
+        #print "run: d=%s" % str(d)
+    
+        if self.debug:
+            d['lopts'] = 'debug'
+    
+        k=[]
+        for opt in ['allow_other', 'kernel_cache']:
+            if getattr(self, opt):
+                k.append(opt)
+        if k:
+            d['kopts'] = ",".join(k)
+    
+        for a in self._attrs:
+            if hasattr(self,a):
+                d[a] = ErrnoWrapper(getattr(self, a))
+    
+        #thread.start_new_thread(self.tickThread, ())
+    
+        _fuse.main(**d)
+    
+    #@-node:run
+    #@+node:GetContent
+    def GetContext(self):
+        print "GetContext: called"
+        return _fuse.FuseGetContext(self)
+    
+    #@-node:GetContent
+    #@+node:Invalidate
+    def Invalidate(self, path):
+        print "Invalidate: called"
+        return _fuse.FuseInvalidate(self, path)
+    
+    #@-node:Invalidate
+    #@+node:tickThread
+    def tickThread(self, *args, **kw):
+        
+        print "tickThread: starting"
+        i = 0
+        while True:
+            print "tickThread: n=%s" % i
+            time.sleep(10)
+            i += 1
+    
+    #@-node:tickThread
+    #@-others
+#@-node:class FreenetFuseFS
 #@+node:class FileRecord
 class FileRecord(list):
     """
@@ -1630,6 +1827,9 @@
         # finally, parent constructor, now that we have a complete stat list
         list.__init__(self, statrec)

+        if self.isdir:
+            self.size = 2
+    
     #@-node:__init__
     #@+node:__getattr__
     def __getattr__(self, attr):
@@ -1792,6 +1992,8 @@
         self.children.append(rec)
         self.size += 1

+        #print "addChild: path=%s size=%s" % (self.path, self.size)
+    
     #@-node:addChild
     #@+node:delChild
     def delChild(self, rec):
@@ -1805,6 +2007,8 @@
         else:
             print "eh? trying to remove %s from %s" % (rec.path, self.path)

+        #print "delChild: path=%s size=%s" % (self.path, self.size)
+    
     #@-node:delChild
     #@-others

@@ -1903,13 +2107,16 @@
         except:
             args.append(o)

-    #kw['multithreaded'] = True
-    kw['multithreaded'] = False
+    kw['multithreaded'] = True
+    #kw['multithreaded'] = False
+    print "main: kw=%s" % str(kw)
+    

     if os.fork() == 0:
-        server = FreenetFS(mountpoint, *args, **kw)
+        server = FreenetFuseFS(mountpoint, *args, **kw)
         server.run()

+
 #@-node:main
 #@+node:mainline
 if __name__ == '__main__':

Modified: trunk/apps/pyFreenet/fcp/node.py
===================================================================
--- trunk/apps/pyFreenet/fcp/node.py    2006-06-07 01:40:15 UTC (rev 9062)
+++ trunk/apps/pyFreenet/fcp/node.py    2006-06-07 04:11:34 UTC (rev 9063)
@@ -127,6 +127,8 @@
           calling modes.

     """
+    noCloseSocket = True
+    
     def __init__(self, **kw):
         """
         Create a connection object
@@ -483,7 +485,8 @@

             - filebyfile - default False - if True, manually inserts
               each constituent file, then performs the ClientPutComplexDir
-              as a manifest full of redirects
+              as a manifest full of redirects. You *must* use this mode
+              if inserting from across a LAN

             - maxretries - maximum number of retries, default 3
             - priority - default 1
@@ -558,8 +561,9 @@

                 log(INFO, "Launching insert of %s" % relpath)

+                raw = file(fullpath, "rb").read()
                 job = self.put("CHK@",
-                               file=fullpath,
+                               data=raw,
                                mimetype=mimetype,
                                async=1,
                                verbosity=verbosity,
@@ -763,8 +767,9 @@

         # shut down FCP connection
         if hasattr(self, 'socket'):
-            self.socket.close()
-            del self.socket
+            if not self.noCloseSocket:
+                self.socket.close()
+                del self.socket

         # and close the logfile
         if self.logfile not in [sys.stdout, sys.stderr]:
@@ -781,6 +786,8 @@
         client commands and incoming node responses
         """
         log = self._log
+    
+        log(DETAIL, "FCPNode: manager thread starting")
         try:
             while self.running:

@@ -862,6 +869,7 @@
         elif async:
             return job
         else:
+            self._log(DETAIL, "Waiting on job")
             return job.wait()

     def _on_rxMsg(self, msg):
@@ -1309,8 +1317,10 @@
         """
         Waits forever (or for a given timeout) for a job to complete
         """
-        self.lock.acquire()
+        while not self.lock.acquire(False):
+            time.sleep(0.1)
         self.lock.release()
+    
         return self.getResult()
     def waitTillReqSent(self):
         """

Modified: trunk/apps/pyFreenet/freedisk.py
===================================================================
--- trunk/apps/pyFreenet/freedisk.py    2006-06-07 01:40:15 UTC (rev 9062)
+++ trunk/apps/pyFreenet/freedisk.py    2006-06-07 04:11:34 UTC (rev 9063)
@@ -99,7 +99,7 @@
         self.cmd_setup = self.cmd_init
         self.cmd_mount = self.cmd_start
         self.cmd_unmoutn = self.cmd_umount = self.cmd_stop
-        
+    
     #@-node:__init__
     #@+node:run
     def run(self):
@@ -111,8 +111,10 @@
         if not method:
             usage("Unrecognised command '%s'" % cmd)

-        return method(*self.args[1:])
+        result = method(*self.args[1:]) or ""

+        return result
+    
     #@-node:run
     #@+node:cmd_init
     def cmd_init(self, *args):
@@ -176,41 +178,36 @@
         conf = self.conf
         kw = self.kw

-        print "starting freedisk service..."
-        fs = freenetfs.FreenetFS(
-                conf.mountpoint,
-                fcpHost=conf.fcpHost,
-                fcpPort=conf.fcpPort,
-                verbosity=conf.fcpVerbosity,
-                debug=kw['debug'],
-                multithreaded=kw['multithreaded'],
-                )
+        # spawn the child
+        print "Spawning freenetfs filesystem process..."
+        os.system("freedisk run &")

-        # spawn a process to run it
-        if os.fork() == 0:
-            print "Mounting freenet fs at %s" % conf.mountpoint
-            fs.run()
+        # wait for child to bring up the fs, via a very crude test
+        keyDir = os.path.join(conf.mountpoint, "keys")
+        print "Waiting for disk to come up..."
+        while not os.path.isdir(keyDir):
+            time.sleep(1)
+        disks = conf.getDisks()
+    
+        if disks:
+            print "Freenetfs now mounted, adding existing disks..."
         else:
-            # parent process
-            keyDir = os.path.join(conf.mountpoint, "keys")
-            print "Waiting for disk to come up..."
-            while not os.path.isdir(keyDir):
-                time.sleep(1)
-            disks = conf.getDisks()
-        
-            if disks:
-                print "Freenetfs now mounted, adding existing disks..."
-            else:
-                print "Freenetfs now mounted, no freedisks at present"
-        
-            for disk in disks:
-        
-                diskPath = os.path.join(conf.mountpoint, "usr", disk.name)
-        
-                # barf if a freedisk of that name is already mounted
-                if os.path.exists(diskPath):
-                    usage("Freedisk %s seems to be already mounted" % 
disk.name)
-                
+            print "Freenetfs now mounted, no freedisks at present"
+    
+        for disk in disks:
+    
+            #break
+    
+            diskPath = os.path.join(conf.mountpoint, "usr", disk.name)
+    
+            # barf if a freedisk of that name is already mounted
+            if os.path.exists(diskPath):
+                usage("Freedisk %s seems to be already mounted" % disk.name)
+    
+            self.doFsCommand("mount %s|%s|%s" % (
+                disk.name, disk.uri, disk.passwd))
+    
+            if 0:
                 # mkdir to create the freedisk dir
                 os.mkdir(diskPath)

@@ -227,7 +224,35 @@
                 file(privKeyPath, "w").write(disk.privUri)
                 file(passwdPath, "w").write(disk.passwd)

+        #while True:
+        #    time.sleep(1)
+    
     #@-node:cmd_start
+    #@+node:cmd_run
+    def cmd_run(self, *args):
+        """
+        become the foreground FUSE process.
+        
+        This is launched by 'freedisk start'
+        """
+        conf = self.conf
+        kw = self.kw
+    
+        print "Creating freenetfs filesystem..."
+        fs = freenetfs.FreenetFuseFS(
+                conf.mountpoint,
+                fcpHost=conf.fcpHost,
+                fcpPort=conf.fcpPort,
+                verbosity=conf.fcpVerbosity,
+                debug=kw['debug'],
+                multithreaded=kw['multithreaded'],
+                )
+    
+        # never returns, until fs is unmounted
+        print "Freenetfs filesystem now alive..."
+        fs.run()
+    
+    #@-node:cmd_run
     #@+node:cmd_stop
     def cmd_stop(self, *args):
         """
@@ -264,33 +289,42 @@

         keys = file(keyPath).read().strip().split("\n")
         pubKey, privKey = [k.split("/")[0].split("freenet:")[-1] for k in keys]
-        
-        # mkdir to create the freedisk dir
-        os.mkdir(diskPath)
-        
-        # wait for the pseudo-files to come into existence
-        while not os.path.isfile(privKeyPath):
-            time.sleep(0.1)
-        
-        #status("About to write to %s" % privKeyPath)
-        
-        file(self.pubKeyPath, "w").write(pubKey)
-        file(self.privKeyPath, "w").write(privKey)
-        file(self.passwdPath, "w").write(passwd)
-        
+    
+        print self.doFsCommand("mount %s|%s|%s" % (diskname, privKey, passwd))
+    
         # and, of course, update config
-        conf.addDisk(diskname, pubKey, privKey, passwd)
-        
-        
-    #@nonl
+        conf.addDisk(diskname, privKey, passwd)
+    
+        return
+    
+    
+        # deprecated
+    
+        if 0:
+            # mkdir to create the freedisk dir
+            os.mkdir(diskPath)
+            
+            # wait for the pseudo-files to come into existence
+            while not os.path.isfile(privKeyPath):
+                time.sleep(0.1)
+            
+            #status("About to write to %s" % privKeyPath)
+            
+            file(self.pubKeyPath, "w").write(pubKey)
+            file(self.privKeyPath, "w").write(privKey)
+            file(self.passwdPath, "w").write(passwd)
+    
     #@-node:cmd_new
     #@+node:cmd_add
     def cmd_add(self, *args):

         nargs = len(args)

+        diskname = self.diskname
+        conf = self.conf
+    
         # get uri
-        if nargs < 3:
+        if nargs < 2:
             usage("add: Missing URI")
         uri = args[1]

@@ -299,26 +333,39 @@
         # barf if a freedisk of that name is already mounted
         if os.path.exists(self.diskPath):
             usage("Freedisk %s seems to be already mounted" % diskname)
+    
+        # get a password if desired
+        passwd = getpasswd("Disk's password", True)
+    
+        print self.doFsCommand("mount %s|%s|%s" % (diskname, uri, passwd))
+    
+        # and, of course, update config
+        conf.addDisk(diskname, uri, passwd)
+    
+        return
+    
+        # deprecated
+    
+        if 0:    
+            # mkdir to create the freedisk dir
+            os.mkdir(self.diskPath)
+            
+            # wait for the pseudo-files to come into existence
+            while not os.path.isfile(self.privKeyPath):
+                time.sleep(0.1)
+            
+            # set the keys
+            
+            if fcp.node.uriIsPrivate(uri):
+                path = privKeyPath
+            else:
+                path = pubKeyPath
+            f = file(path, "w")
+            f.write(uri)
+            f.flush()
+            f.close()

-        # mkdir to create the freedisk dir
-        os.mkdir(self.diskPath)

-        # wait for the pseudo-files to come into existence
-        while not os.path.isfile(self.privKeyPath):
-            time.sleep(0.1)
-        
-        # set the keys
-        
-        if fcp.node.uriIsPrivate(uri):
-            path = privKeyPath
-        else:
-            path = pubKeyPath
-        f = file(path, "w")
-        f.write(uri)
-        f.flush()
-        f.close()
-        
-        
     #@nonl
     #@-node:cmd_add
     #@+node:cmd_del
@@ -333,9 +380,15 @@

         if not isinstance(disk, XMLNode):
             usage("No such disk '%s'" % diskname)
+    
+        self.doFsCommand("umount %s" % diskname)

         conf.delDisk(diskname)

+        return
+    
+        # deprecated
+    
         path = os.path.join(conf.mountpoint, "usr", diskname)
         os.rmdir(path)

@@ -345,6 +398,20 @@
         """
         Updates a freedisk *from* freenet
         """
+        conf = self.conf
+        diskname = self.diskname
+    
+        disk = conf.getDisk(diskname)
+        
+        if not isinstance(disk, XMLNode):
+            usage("No such disk '%s'" % diskname)
+    
+        self.doFsCommand("update %s" % diskname)
+        
+        return
+    
+        # deprecated
+    
         cmdPath = self.cmdPath
         diskname = self.diskname

@@ -361,6 +428,20 @@
         """
         commits a freedisk *to* freenet
         """
+        conf = self.conf
+        diskname = self.diskname
+    
+        disk = conf.getDisk(diskname)
+        
+        if not isinstance(disk, XMLNode):
+            usage("No such disk '%s'" % diskname)
+    
+        res = self.doFsCommand("commit %s" % diskname)
+        
+        return res
+    
+        # deprecated
+    
         cmdPath = self.cmdPath
         diskname = self.diskname

@@ -395,10 +476,23 @@
     def cmd_cmd(self, *args):

         # arbitrary command, for testing
-        cmd = " ".join(args)
-        print repr(doFsCommand(cmd))
+        cmd = args[0] + "|".join(args[1:])
+        print repr(self.doFsCommand(cmd))

     #@-node:cmd_cmd
+    #@+node:doFsCommand
+    def doFsCommand(self, cmd):
+        """
+        Executes a command via base64-encoded file
+        """
+        cmdBase64 = fcp.node.base64encode(cmd)
+        if len(cmdBase64) > 254:
+            raise Exception("Command too long")
+    
+        path = self.conf.mountpoint + "/cmds/" + cmdBase64
+        return file(path).read()
+    
+    #@-node:doFsCommand
     #@-others

 #@-node:class FreediskMgr
@@ -513,7 +607,7 @@

     #@-node:setPassword
     #@+node:addDisk
-    def addDisk(self, name, uri, privUri, passwd):
+    def addDisk(self, name, uri, passwd):

         d = self.getDisk(name)
         if isinstance(d, XMLNode):
@@ -522,7 +616,6 @@
         diskNode = self.root._addNode("disk")
         diskNode.name = name
         diskNode.uri = uri
-        diskNode.privUri = privUri
         diskNode.passwd = passwd

         self.save()
@@ -707,16 +800,6 @@
     return passwd

 #@-node:getpasswd
-#@+node:doFsCommand
-def doFsCommand(cmd):
-    """
-    Executes a command via base64-encoded file
-    """
-    cmdBase64 = fcp.node.base64encode(cmd)
-    path = conf.mountpoint + "/cmds/" + cmdBase64
-    return file(path).read()
-
-#@-node:doFsCommand
 #@+node:ipython
 def ipython(o=None):

@@ -807,7 +890,7 @@
     #@+node:<<execute command>>
     mgr = FreediskMgr(*args, **opts)

-    mgr.run()
+    print mgr.run()

     #@-node:<<execute command>>
     #@nl

Modified: trunk/apps/pyFreenet/freesitemgr
===================================================================
--- trunk/apps/pyFreenet/freesitemgr    2006-06-07 01:40:15 UTC (rev 9062)
+++ trunk/apps/pyFreenet/freesitemgr    2006-06-07 04:11:34 UTC (rev 9063)
@@ -162,7 +162,10 @@
     print "  -s, --single-files"
     print "          - insert one file at a time as CHKs, then insert"
     print "            a manifest which redirects to these, useful"
-    print "            for debugging"
+    print "            for debugging. Also, you MUST use this mode if"
+    print "            inserting a freesite from across a LAN (ie, if"
+    print "            the FCP service is on a different machine to"
+    print "            the machine running freesitemgr"
     print
     print "Available Commands:"
     print "  setup          - create/edit freesite config file interactively"

Modified: trunk/apps/pyFreenet/freesitemgr.py
===================================================================
--- trunk/apps/pyFreenet/freesitemgr.py 2006-06-07 01:40:15 UTC (rev 9062)
+++ trunk/apps/pyFreenet/freesitemgr.py 2006-06-07 04:11:34 UTC (rev 9063)
@@ -162,7 +162,10 @@
     print "  -s, --single-files"
     print "          - insert one file at a time as CHKs, then insert"
     print "            a manifest which redirects to these, useful"
-    print "            for debugging"
+    print "            for debugging. Also, you MUST use this mode if"
+    print "            inserting a freesite from across a LAN (ie, if"
+    print "            the FCP service is on a different machine to"
+    print "            the machine running freesitemgr"
     print
     print "Available Commands:"
     print "  setup          - create/edit freesite config file interactively"


Reply via email to