Index: /branches/neb_distrib_20081210/Nebulous/Build.PL
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/Build.PL	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/Build.PL	(revision 23536)
@@ -11,39 +11,36 @@
 my $pkg_dir = "./nebclient";
 
-sub ACTION_code {
-    my $self = shift;
-
-    $self->SUPER::ACTION_code(@_);
-
-    my $old_pwd = getcwd();
-    chdir $pkg_dir;
-
-    unless (-e "configure") {
-        system("./autogen.sh") == 0 or die "install failed: $?";
-    }
-
-    chdir $old_pwd;
-}
-
-sub ACTION_build {
-    my $self = shift;
-
-    $self->SUPER::ACTION_build(@_);
-
-    my $old_pwd = getcwd();
-    chdir $pkg_dir;
-
-    unless (-e "Makefile") {
-        system("sh ./configure") == 0 or die "build failed: $?";
-    }
-
-    system("make") == 0 or die "build failed: $?";
-
-    chdir $old_pwd;
-}
-
-# Do not attempt to install nebclient.  It is bundled in this package for
-# testing only.
-#
+# sub ACTION_code {
+#     my $self = shift;
+# 
+#     $self->SUPER::ACTION_code(@_);
+# 
+#     my $old_pwd = getcwd();
+#     chdir $pkg_dir;
+# 
+#     unless (-e "configure") {
+#         system("./autogen.sh") == 0 or die "install failed: $?";
+#     }
+# 
+#     chdir $old_pwd;
+# }
+# 
+# sub ACTION_build {
+#     my $self = shift;
+# 
+#     $self->SUPER::ACTION_build(@_);
+# 
+#     my $old_pwd = getcwd();
+#     chdir $pkg_dir;
+# 
+#     unless (-e "Makefile") {
+#         system("sh ./configure") == 0 or die "build failed: $?";
+#     }
+# 
+#     system("make") == 0 or die "build failed: $?";
+# 
+#     chdir $old_pwd;
+# }
+# 
 # sub ACTION_install {
 #     my $self = shift;
@@ -58,17 +55,17 @@
 #     chdir $old_pwd;
 # }
-
-sub ACTION_clean {
-    my $self = shift;
-
-    $self->SUPER::ACTION_clean(@_);
-
-    my $old_pwd = getcwd();
-    chdir $pkg_dir;
-
-    system("make clean") == 0 or die "install failed: $?";
-
-    chdir $old_pwd;
-}
+# 
+# sub ACTION_clean {
+#     my $self = shift;
+# 
+#     $self->SUPER::ACTION_clean(@_);
+# 
+#     my $old_pwd = getcwd();
+#     chdir $pkg_dir;
+# 
+#     system("make clean") == 0 or die "install failed: $?";
+# 
+#     chdir $old_pwd;
+# }
 EOF
 
Index: /branches/neb_distrib_20081210/Nebulous/MANIFEST
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/MANIFEST	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/MANIFEST	(revision 23536)
@@ -20,10 +20,4 @@
 bin/neb-touch
 bin/neb-xattr
-docs/c_api.h
-docs/database_setup.txt
-docs/design.txt
-docs/requirements.txt
-docs/setup.txt
-docs/tmp.txt
 examples/Makefile
 examples/nebexample.c
Index: /branches/neb_distrib_20081210/Nebulous/lib/Nebulous/Client.pm
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/lib/Nebulous/Client.pm	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/lib/Nebulous/Client.pm	(revision 23536)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004-2008  Joshua Hoblitt
 #
-# $Id: Client.pm,v 1.62.6.1 2008-12-14 22:03:08 eugene Exp $
+# $Id: Client.pm,v 1.64 2008-12-14 22:48:35 eugene Exp $
 
 package Nebulous::Client;
Index: /branches/neb_distrib_20081210/Nebulous/nebclient/Doxyfile.in
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/nebclient/Doxyfile.in	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/nebclient/Doxyfile.in	(revision 23536)
@@ -1,3 +1,3 @@
-# Doxyfile 1.4.2
+# Doxyfile 1.5.4
 
 # This file describes the settings to be used by the documentation system
@@ -15,8 +15,16 @@
 #---------------------------------------------------------------------------
 
+# This tag specifies the encoding used for all characters in the config file that 
+# follow. The default is UTF-8 which is also the encoding used for all text before 
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
 # by quotes) that should identify the project.
 
-PROJECT_NAME           = @PACKAGE_NAME@
+PROJECT_NAME           = nebclient
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
@@ -24,5 +32,5 @@
 # if some version control system is used.
 
-PROJECT_NUMBER         = @PACKAGE_VERSION@
+PROJECT_NUMBER         = 0.08
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
@@ -31,6 +39,5 @@
 # where doxygen was started. If left blank the current directory will be used.
 
-# @top_builddir@ doesn't work for some reason
-OUTPUT_DIRECTORY       = @builddir@/docs
+OUTPUT_DIRECTORY       = ./docs
 
 # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
@@ -47,21 +54,11 @@
 # information to generate all constant output in the proper language. 
 # The default language is English, other supported languages are: 
-# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
-# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
-# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
-# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
-# Swedish, and Ukrainian.
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
 
 OUTPUT_LANGUAGE        = English
-
-# This tag can be used to specify the encoding used in the generated output. 
-# The encoding is not always determined by the language that is chosen, 
-# but also whether or not the output is meant for Windows or non-Windows users. 
-# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
-# forces the Windows encoding (this is the default for the Windows binary), 
-# whereas setting the tag to NO uses a Unix-style encoding (the default for 
-# all platforms other than Windows).
-
-USE_WINDOWS_ENCODING   = NO
 
 # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
@@ -137,8 +134,16 @@
 # will interpret the first line (until the first dot) of a JavaDoc-style 
 # comment as the brief description. If set to NO, the JavaDoc 
-# comments will behave just like the Qt-style comments (thus requiring an 
-# explicit @brief command for a brief description.
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
 
 JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
 
 # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
@@ -162,11 +167,4 @@
 
 INHERIT_DOCS           = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
-# tag is set to YES, then doxygen will reuse the documentation of the first 
-# member in the group (if any) for the other members of the group. By default 
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC   = NO
 
 # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
@@ -197,10 +195,37 @@
 OPTIMIZE_OUTPUT_FOR_C  = NO
 
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
-# only. Doxygen will then generate output that is more tailored for Java. 
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for Java. 
 # For instance, namespaces will be presented as packages, qualified scopes 
 # will look different, etc.
 
 OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
 
 # Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
@@ -212,4 +237,14 @@
 SUBGROUPING            = YES
 
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is 
+# documented as struct with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code where the coding convention is that all structs are 
+# typedef'ed and only the typedef is referenced never the struct's name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
 #---------------------------------------------------------------------------
 # Build related configuration options
@@ -245,4 +280,11 @@
 
 EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted 
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}', 
+# where file will be replaced with the base name of the file that contains the anonymous 
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
 
 # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
@@ -378,5 +420,5 @@
 # If the sources in your project are distributed over multiple directories 
 # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
-# in the documentation.
+# in the documentation. The default is NO.
 
 SHOW_DIRECTORIES       = YES
@@ -387,5 +429,5 @@
 # popen()) the command <command> <input-file>, where <command> is the value of 
 # the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
-# provided by doxygen. Whatever the progam writes to standard output 
+# provided by doxygen. Whatever the program writes to standard output 
 # is used as the file version. See the manual for examples.
 
@@ -435,5 +477,5 @@
 # be obtained via FILE_VERSION_FILTER)
 
-WARN_FORMAT            = "$file:$line: $text"
+WARN_FORMAT            = "$file:$line: $text "
 
 # The WARN_LOGFILE tag can be used to specify a file to which warning 
@@ -452,5 +494,12 @@
 # with spaces.
 
-INPUT                  = @top_srcdir@/src
+INPUT                  = ./src
+
+# This tag can be used to specify the character encoding of the source files that 
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
 
 # If the value of the INPUT tag contains directories, you can use the 
@@ -459,5 +508,5 @@
 # blank the following patterns are tested: 
 # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
 
 FILE_PATTERNS          = *.h
@@ -483,7 +532,16 @@
 # If the value of the INPUT tag contains directories, you can use the 
 # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
-# certain files from those directories.
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
 
 EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the output. 
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
 
 # The EXAMPLE_PATH tag can be used to specify one or more files or 
@@ -545,5 +603,7 @@
 # be generated. Documented entities will be cross-referenced with these sources. 
 # Note: To get rid of all source code in the generated output, make sure also 
-# VERBATIM_HEADERS is set to NO.
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH 
+# then you must also enable this option. If you don't then doxygen will produce 
+# a warning and turn it on anyway
 
 SOURCE_BROWSER         = NO
@@ -571,4 +631,19 @@
 
 REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
 
 # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
@@ -656,4 +731,12 @@
 GENERATE_HTMLHELP      = NO
 
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
 # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
 # be used to specify the file name of the resulting .chm file. You 
@@ -958,5 +1041,5 @@
 # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
 # then the macro expansion is limited to the macros specified with the 
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+# PREDEFINED and EXPAND_AS_DEFINED tags.
 
 EXPAND_ONLY_PREDEF     = NO
@@ -1046,5 +1129,5 @@
 # interpreter (i.e. the result of `which perl').
 
-PERL_PATH              = @PERL@
+PERL_PATH              = /usr/bin/perl
 
 #---------------------------------------------------------------------------
@@ -1061,4 +1144,12 @@
 CLASS_DIAGRAMS         = YES
 
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
+# be found in the default search path.
+
+MSCGEN_PATH            = 
+
 # If set to YES, the inheritance and collaboration graphs will hide 
 # inheritance and usage relations if the target is undocumented 
@@ -1118,5 +1209,5 @@
 INCLUDED_BY_GRAPH      = YES
 
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
 # generate a call dependency graph for every global function or class method. 
 # Note that enabling this option will significantly increase the time of a run. 
@@ -1126,4 +1217,12 @@
 CALL_GRAPH             = NO
 
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable caller graphs for selected 
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
 # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
 # will graphical hierarchy of all classes instead of a textual one.
@@ -1155,19 +1254,13 @@
 DOTFILE_DIRS           = 
 
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
-# this value, doxygen will try to truncate the graph, so that it fits within 
-# the specified constraint. Beware that most browsers cannot cope with very 
-# large images.
-
-MAX_DOT_GRAPH_WIDTH    = 1024
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
-# this value, doxygen will try to truncate the graph, so that it fits within 
-# the specified constraint. Beware that most browsers cannot cope with very 
-# large images.
-
-MAX_DOT_GRAPH_HEIGHT   = 1024
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the number 
+# of direct children of the root node in a graph is already larger than 
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
 
 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
@@ -1176,8 +1269,6 @@
 # that lay further from the root node will be omitted. Note that setting this 
 # option to 1 or 2 may greatly reduce the computation time needed for large 
-# code bases. Also note that a graph may be further truncated if the graph's 
-# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH 
-# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), 
-# the graph is not depth-constrained.
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
 
 MAX_DOT_GRAPH_DEPTH    = 0
Index: /branches/neb_distrib_20081210/Nebulous/nebclient/src/nebclient.c
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/nebclient/src/nebclient.c	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/nebclient/src/nebclient.c	(revision 23536)
@@ -4,5 +4,5 @@
  * Copyright (C) 2005  Joshua Hoblitt
  *
- * $Id: nebclient.c,v 1.54.6.1 2008-12-14 22:03:08 eugene Exp $
+ * $Id: nebclient.c,v 1.57 2009-02-13 02:45:47 jhoblitt Exp $
  */
 
@@ -336,5 +336,4 @@
 bool nebSetXattr(nebServer *server, const char *key, const char *name, const char *value, nebCR flag)
 {
-
     REQUIRE_SERVER;
 
@@ -363,4 +362,99 @@
     if (!response) {
         nebSetErr(server, "can not set xattr");
+        return false;
+    }
+
+    return true;
+}
+
+
+char *nebGetXattr(nebServer *server, const char *key, const char *name) 
+{
+    REQUIRE_SERVER;
+
+    if (!key) {
+        nebSetErr(server, "parameter 'key' may not be NULL");
+        return false;
+    }
+    if (!name) {
+        nebSetErr(server, "parameter 'name' may not be NULL");
+        return false;
+    }
+
+    struct ns1__getxattr_USCOREobjectResponse response;
+    if (soap_call_ns1__getxattr_USCOREobject(server->soap, server->endpoint,
+        NULL, (char *)key, (char *)name, (char **)&response) != SOAP_OK) {
+        nebSetServerErr(server);
+        return false;
+    }
+
+    if (!(char *)response.result) {
+        nebSetErr(server, "server returned no result");
+        return NULL;
+    }
+
+    char *value = xmalloc(strlen((char *)response.result) + 1);
+    strcpy(value, (char *)response.result);
+
+    return value;
+}
+
+
+int nebListXattr(nebServer *server, const char *key, char ***xattrs)
+{
+    REQUIRE_SERVER;
+
+    if (!key) {
+        nebSetErr(server, "parameter 'key' may not be NULL");
+        return false;
+    }
+
+    struct ns1__listxattr_USCOREobjectResponse response;
+    if (soap_call_ns1__listxattr_USCOREobject(server->soap, server->endpoint,
+        NULL, (char *)key, &response) != SOAP_OK) {
+        nebSetServerErr(server);
+        return false;
+    }
+
+    int resultElements = response.result->__size;
+
+    if (xattrs) {
+        char **resultArray = response.result->__ptr;
+        *xattrs = xmalloc(resultElements * sizeof(char *));
+        if (resultElements) {
+            for (int i = 0; i < resultElements; i++) {
+                *xattrs[i] = xmalloc(strlen(resultArray[i]) + 1);
+                strcpy(*xattrs[i], resultArray[i]);
+            }
+
+        }
+    }
+
+    return resultElements;
+}
+
+
+bool nebRemoveXattr(nebServer *server, const char *key, const char *name)
+{
+    REQUIRE_SERVER;
+
+    if (!key) {
+        nebSetErr(server, "parameter 'key' may not be NULL");
+        return false;
+    }
+    if (!name) {
+        nebSetErr(server, "parameter 'name' may not be NULL");
+        return false;
+    }
+
+    int response;
+    if (soap_call_ns1__removexattr_USCOREobject(server->soap, server->endpoint,
+        NULL, (char *)key, (char *)name, &response) != SOAP_OK) {
+        nebSetServerErr(server);
+        return false;
+    }
+
+    if (!response) {
+        nebSetErr(server, "can not remove xattr");
         return false;
     }
@@ -539,5 +633,5 @@
 
     for (int i = 0; i < locations->n; i++) {
-        if (!nebDeleteInstance(server, key, locations->URI[i])) {
+      if (!nebDeleteInstance(server, key, locations->URI[i])) {
             nebSetErr(server, "can not delete instance");
             nebObjectInstancesFree(locations);
@@ -676,5 +770,5 @@
 
     if (soap_call_ns1__delete_USCOREinstance(server->soap, server->endpoint,
-            NULL, (char *)key, (char *)URI, &response) != SOAP_OK) {
+        NULL, (char *)key, (char *)URI, &response) != SOAP_OK) {
         nebFree(filename);
 
Index: /branches/neb_distrib_20081210/Nebulous/nebclient/src/nebclient.h
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/nebclient/src/nebclient.h	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/nebclient/src/nebclient.h	(revision 23536)
@@ -4,5 +4,5 @@
  * Copyright (C) 2005  Joshua Hoblitt
  *
- * $Id: nebclient.h,v 1.36.6.1 2008-12-14 22:03:08 eugene Exp $
+ * $Id: nebclient.h,v 1.40 2009-02-13 02:49:00 jhoblitt Exp $
  */
 
@@ -155,4 +155,38 @@
 );
 
+/** Get an Xattr on a storage object
+ *
+ * @return true on success
+ */
+char *nebGetXattr(
+    nebServer *server,                  ///< nebServer object
+    const char *key,                    ///< storage object key (name)
+    const char *name                    ///< xattr name
+);
+
+/** List all Xattrs on a storage object
+ *
+ * This function returns the count of Xattrs on an object and the actual names
+ * are returned in the (char **) pointed to by the xattrs param.  The xattrs
+ * param may be NULL.
+ *
+ * @return int
+ */
+int nebListXattr(
+    nebServer *server,                  ///< nebServer object
+    const char *key,                    ///< storage object key (name)
+    char ***xattrs                      ///< array of xattr names to return
+);
+
+/** Remove an Xattr from a storage object
+ *
+ * @return true on success
+ */
+bool nebRemoveXattr(
+    nebServer *server,                  ///< nebServer object
+    const char *key,                    ///< storage object key (name)
+    const char *name                    ///< xattr name
+);
+
 /** Lists all instances of a storage object
  *
Index: /branches/neb_distrib_20081210/Nebulous/nebclient/tests/tests.c
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/nebclient/tests/tests.c	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/nebclient/tests/tests.c	(revision 23536)
@@ -2,4 +2,5 @@
 #include <stdlib.h>
 #include <unistd.h>
+#include <string.h>
 #include <stdbool.h>
 
@@ -19,5 +20,5 @@
     char            *key = "foobarbaz";
 
-    plan_tests(24);
+    plan_tests(28);
 
     if (getenv("NEB_SERVER")) {
@@ -96,4 +97,13 @@
     neb_ok(server, nebSetXattr(server, key, "user.copies", "2",  NEB_CREATE), "set user.copies xattr");
 
+    char *copies = nebGetXattr(server, key, "user.copies");
+    neb_ok(server, strcmp(copies, "2") == 0, "get user.copies xattr");
+    char **xattrs = NULL;
+    int n_xattrs = nebListXattr(server, key, &xattrs);
+    printf("# %s\n\n", xattrs[0]);
+    neb_ok(server, n_xattrs == 1, "count of xattrs");
+    neb_ok(server, strcmp(xattrs[0], "user.copies") == 0, "user.copies xattr exists");
+    neb_ok(server, nebRemoveXattr(server, key, "user.copies"), "remove user.copies xattr");
+
     {
         nebObjectInstances *locations = NULL;
Index: /branches/neb_distrib_20081210/Nebulous/scripts/old_ptest.pl
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/scripts/old_ptest.pl	(revision 23536)
+++ /branches/neb_distrib_20081210/Nebulous/scripts/old_ptest.pl	(revision 23536)
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Benchmark qw( timethese );
+use PS::IPP::IData::Client;
+
+my $idata = PS::IPP::IData::Client->new(
+    proxy   => 'http://localhost:80/idata'
+);
+
+my $key = shift || 'foobar';
+
+timethese( -10,
+    {
+        'create/delete' => sub {
+            my $fh = $idata->create( $key );
+            close $fh;
+            $idata->delete( $key );
+        },
+    }
+);
Index: /branches/neb_distrib_20081210/Nebulous/scripts/ptest.pl
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/scripts/ptest.pl	(revision 23535)
+++ /branches/neb_distrib_20081210/Nebulous/scripts/ptest.pl	(revision 23536)
@@ -5,27 +5,92 @@
 
 use lib "./lib";
+package main;
 
-use Nebulous::Client;
+#use Nebulous::Client;
+use IO::Select;
+use IO::Socket;
+use POSIX qw(:DEFAULT :sys_wait_h);
+use Hook::LexWrap;
+use Sys::Hostname;
 
-my $neb = Nebulous::Client->new(
-    proxy   => 'http://localhost:80/nebulous'
-);
+my $print_stdout = undef;
+
+$| = 1;
 
 my $key = shift || 'foobar';
 my $kids = shift || 1;
 
+$key = "/tmp/" . $key;
+
+#my $s = IO::Select->new();
+
 foreach my $id ( 1..$kids ) {
+#    my ($sock_parent, $sock_child) = IO::Socket->socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
+#    $s->add($sock_parent);
+
     my $pid = fork;
 
     unless ( $pid )  {
-        my $fname = "${key}_$id";
-        my $fh = $neb->open_create( $fname );
-        die "can't create file $fname" unless $fh;
+        # child
+        my $sock_child = \*STDOUT;
+        child($sock_child, $id);
+        shutdown($sock_child, 2);
+        exit 0;
+    }
+    # parent
+}
 
-        print $fh "fooby\n";
+$SIG{CHLD} = \&REAPER;
 
+sub REAPER {
+    while ((my $pid = waitpid(-1,WNOHANG)) > 0) {
+        $kids--;
+#        delete $children{$pid};
+    }
+    $SIG{CHLD} = \&REAPER;
+}
+
+
+while ($kids) {
+#    foreach my $child ($s->can_read(0)) {
+#        my $string = do { local $/; <$child>};
+#        my @events = split(/\n/, $string) if $string;
+#        print join("\n", @events), "\n" if scalar @events;
+#    }
+}
+
+sub child
+{
+    my ($sock, $id) = @_;
+
+    unless ($print_stdout) {
+        my $filename = hostname() . "." . $$ . ".txt";
+        open my $fh, ">$filename" or die "can't open $filename: $!";
+
+        open STDOUT, ">&", $fh or die "can't reopen STDOUT: $!";
+        autoflush STDOUT 1;
+    }
+
+#    select $sock;
+#    $| = 1;
+
+    # child
+    my $fname = "${key}_$id";
+
+    my $neb = Nebulous::Client::Bench->new(
+#    proxy   => 'http://localhost:80/nebulous'
+        proxy   => 'http://alala:80/nebulous',
+#        sock    => \*STDOUT,
+    );
+
+
+    while (1) {
+#    print $sock "$$ : i'm a little tea pot using key: $fname\n";
+        my $fh = $neb->open_create( $fname )
+            or child_die($sock, "can't create file $fname");
         close $fh;
 
-        $fh = $neb->open( $fname, 'read' ) or die "can't open file";
+        $fh = $neb->open( $fname, 'read' )
+            or child_die("can't open file");
         close $fh;
 
@@ -40,10 +105,73 @@
         $neb->delete( $fname . "_move" );
 
-        exit 0;
+#    print $sock "$$ : all done!\n";
     }
+
+    return 1;
 }
 
-while ( $kids ) {
-    wait();
-    $kids --;
+sub child_die
+{
+    my $sock = shift;
+    print $sock @_;
+    shutdown($sock, 2);
+    exit 1;
 }
+
+package Nebulous::Client::Bench;
+
+use base qw( Nebulous::Client );
+
+#sub new
+#{
+#    my $class = shift;
+#    my %p = @_;
+#
+#    my $sock = delete $p{sock};
+#    my $self = $class->SUPER::new(%p);
+#    $self->{sock} = $sock;
+#
+#    return $self;
+#}
+
+BEGIN {
+sub make_wrapper
+{
+    my $method = shift;
+
+eval "sub $method {"
+.'    my $self = shift;'
+.'    my $smark = Time::HiRes::time();'
+.'    my $ret = $self->SUPER::' . "$method" .'(@_);'
+.'    my $emark = Time::HiRes::time();'
+.'    printf "%-17s %-17s %s\n", $emark, " ' . "$method" . ' ", ($emark - $smark), "\n";'
+.'    return $ret;'
+.'}';
+
+}
+
+make_wrapper("create");
+make_wrapper("open_create");
+make_wrapper("replicate");
+make_wrapper("cull");
+make_wrapper("lock");
+make_wrapper("unlock");
+make_wrapper("setxattr");
+make_wrapper("getxattr");
+make_wrapper("listxattr");
+make_wrapper("removexattr");
+make_wrapper("find_objects");
+make_wrapper("find_instances");
+#make_wrapper("find");
+#make_wrapper("open");
+#make_wrapper("delete");
+#make_wrapper("copy");
+make_wrapper("move");
+make_wrapper("swap");
+make_wrapper("delete_instance");
+make_wrapper("stat");
+make_wrapper("mounts");
+
+}
+
+1;
Index: /branches/neb_distrib_20081210/Nebulous/scripts/stats.pl
===================================================================
--- /branches/neb_distrib_20081210/Nebulous/scripts/stats.pl	(revision 23536)
+++ /branches/neb_distrib_20081210/Nebulous/scripts/stats.pl	(revision 23536)
@@ -0,0 +1,51 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Statistics::Descriptive;
+
+#my $filename = shift or die "Usage: stats.pl <filename>";
+my $filename = shift || "-";
+
+open(my $fh, "$filename") or die "can't open file $filename: $!";
+
+my $data = do {local $/; <$fh>};
+
+my %methods;
+
+foreach my $line (split(/\n/, $data)) {
+    my ($time, $method, $duration) = split(/\s+/, $line);
+
+    push @{$methods{$method}->{time}}, $time;
+    push @{$methods{$method}->{duration}}, $duration;
+}
+
+close($fh) or die "can't close file $filename: $!";
+
+use Data::Dumper;
+
+my $total_stat = Statistics::Descriptive::Sparse->new();
+#print Dumper \%methods;
+foreach my $method (keys %methods) {
+    {
+        my $duration    = $methods{$method}->{duration};
+        my $stat = Statistics::Descriptive::Sparse->new();
+        $stat->add_data(@$duration);
+        printf("%-40s : %f\n", "$method - mean duration", $stat->mean());
+    }
+    {
+        my $times       = $methods{$method}->{time};
+        my $stat = Statistics::Descriptive::Sparse->new();
+        $stat->add_data(@$times);
+        $total_stat->add_data(@$times);
+        printf("%-40s : %f\n","$method - calls/s", $stat->count / ($stat->max - $stat->min));
+    }
+}
+
+print "\n";
+printf("%-40s : %f\n", "first timestamp", $total_stat->min);
+printf("%-40s : %f\n", "last timestamp", $total_stat->max);
+printf("%-40s : %f\n", "total wallclock seconds", ($total_stat->max - $total_stat->min));
+printf("%-40s : %f\n", "total call count", $total_stat->count);
+printf("%-40s : %f\n", "total calls/s:", $total_stat->count / ($total_stat->max - $total_stat->min));
