r3507: - added deferred replies on sharing violation in pvfs open. The
authorAndrew Tridgell <tridge@samba.org>
Wed, 3 Nov 2004 10:09:48 +0000 (10:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:05:23 +0000 (13:05 -0500)
  deferred reply is short-circuited immediately when the file is
  closed by another user, allowing it to be opened by the waiting user.

- added a sane set of timeval manipulation routines

- converted all the events code and code that uses it to use struct
  timeval instead of time_t, which allows for microsecond resolution
  instead of 1 second resolution. This was needed for doing the pvfs
  deferred open code, and is why the patch is so big.
(This used to be commit 0d51511d408d91eb5f68a35e980e0875299b1831)

36 files changed:
source4/include/events.h
source4/include/messages.h
source4/ldap_server/ldap_server.c
source4/lib/basic.mk
source4/lib/events.c
source4/lib/messaging/messaging.c
source4/lib/time.c
source4/lib/unix_privs.c [new file with mode: 0644]
source4/libcli/raw/clitransport.c
source4/libcli/raw/libcliraw.h
source4/librpc/rpc/dcerpc_sock.c
source4/ntvfs/cifs/vfs_cifs.c
source4/ntvfs/common/brlock.c
source4/ntvfs/common/opendb.c
source4/ntvfs/posix/pvfs_lock.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_wait.c
source4/ntvfs/posix/vfs_posix.h
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_sock.c
source4/smb_server/smb_server.c
source4/smbd/process_model.h
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/smbd/service.c
source4/smbd/service.h
source4/torture/basic/dir.c
source4/torture/gentest.c
source4/torture/local/messaging.c
source4/torture/local/talloc.c
source4/torture/nbench/nbench.c
source4/torture/nbench/nbio.c
source4/torture/raw/mux.c
source4/torture/raw/open.c
source4/torture/torture.c
source4/torture/torture_util.c

index c44acc77aee7010978883a1d3328c68a3f005348..36fedc6e8b4a22f8a98f7e02f02272b7f0d31830 100644 (file)
@@ -28,7 +28,8 @@ struct event_context {
                struct fd_event *next, *prev;
                int fd;
                uint16_t flags; /* see EVENT_FD_* flags */
-               void (*handler)(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags);
+               void (*handler)(struct event_context *ev, struct fd_event *fde, 
+                               struct timeval t, uint16_t flags);
                void *private;
                int ref_count;
        } *fd_events;
@@ -36,8 +37,9 @@ struct event_context {
        /* list of timed events */
        struct timed_event {
                struct timed_event *next, *prev;
-               time_t next_event;
-               void (*handler)(struct event_context *ev, struct timed_event *te, time_t t);
+               struct timeval next_event;
+               void (*handler)(struct event_context *ev, struct timed_event *te, 
+                               struct timeval t);
                void *private;
                int ref_count;
        } *timed_events;
@@ -45,7 +47,8 @@ struct event_context {
        /* list of loop events - called on each select() */
        struct loop_event {
                struct loop_event *next, *prev;
-               void (*handler)(struct event_context *ev, struct loop_event *le, time_t t);
+               void (*handler)(struct event_context *ev, struct loop_event *le, 
+                               struct timeval t);
                void *private;
                int ref_count;
        } *loop_events;
index 96c1e81a313aa683cd0747e179b66bd989d3654a..48376efa037d3296442634e0ccdc7afaa8da0460 100644 (file)
@@ -29,5 +29,6 @@ struct messaging_context;
 #define MSG_PING               2
 #define MSG_PONG               3
 #define MSG_BRL_RETRY          4
+#define MSG_PVFS_RETRY_OPEN    5
 
 #endif
index 3b4ccb6b73cc6c7fb917680286eb1dbecd2f72cf..9338baa165f8597fc76be44c62676587445fc3d8 100644 (file)
@@ -440,7 +440,7 @@ NTSTATUS ldapsrv_flush_responses(struct ldapsrv_connection *conn)
 /*
   called when a LDAP socket becomes readable
 */
-static void ldapsrv_recv(struct server_connection *conn, time_t t,
+static void ldapsrv_recv(struct server_connection *conn, struct timeval t,
                         uint16_t flags)
 {
        struct ldapsrv_connection *ldap_conn = conn->private_data;
@@ -536,7 +536,7 @@ static void ldapsrv_recv(struct server_connection *conn, time_t t,
 /*
   called when a LDAP socket becomes writable
 */
-static void ldapsrv_send(struct server_connection *conn, time_t t,
+static void ldapsrv_send(struct server_connection *conn, struct timeval t,
                         uint16_t flags)
 {
        struct ldapsrv_connection *ldap_conn = conn->private_data;
@@ -558,7 +558,7 @@ static void ldapsrv_send(struct server_connection *conn, time_t t,
 /*
   called when connection is idle
 */
-static void ldapsrv_idle(struct server_connection *conn, time_t t)
+static void ldapsrv_idle(struct server_connection *conn, struct timeval t)
 {
        DEBUG(10,("ldapsrv_idle: not implemented!\n"));
        return;
index e7d710eec6b72c086c11e3b92fbafb0d9c01e121..827aa0a57ca318cfd076d8a912babc0ba3602835 100644 (file)
@@ -72,7 +72,8 @@ ADD_OBJ_FILES = \
                lib/events.o \
                lib/db_wrap.o \
                lib/server_mutex.o \
-               lib/idtree.o
+               lib/idtree.o \
+               lib/unix_privs.o
 REQUIRED_SUBSYSTEMS = \
                LIBTDB CHARSET LIBREPLACE LIBNETIF LIBCRYPTO
 # End SUBSYSTEM LIBBASIC
index f53a244c6da2bc1fe6734bc6ee700e14871d6971..0ca6b665986d9726b76d6512c985b715e5580dd2 100644 (file)
@@ -285,15 +285,14 @@ void event_loop_exit(struct event_context *ev, int code)
 */
 int event_loop_once(struct event_context *ev)
 {
-       time_t t;
        fd_set r_fds, w_fds;
        struct fd_event *fe;
        struct loop_event *le;
        struct timed_event *te;
        int selrtn;
-       struct timeval tval;
+       struct timeval tval, t;
 
-       t = time(NULL);
+       t = timeval_current();
 
        /* the loop events are called on each loop. Be careful to allow the 
           event to remove itself */
@@ -310,7 +309,6 @@ int event_loop_once(struct event_context *ev)
                le = next;
        }
 
-       ZERO_STRUCT(tval);
        FD_ZERO(&r_fds);
        FD_ZERO(&w_fds);
 
@@ -336,17 +334,12 @@ int event_loop_once(struct event_context *ev)
 
        /* start with a reasonable max timeout */
        tval.tv_sec = 600;
+       tval.tv_usec = 0;
                
        /* work out the right timeout for all timed events */
        for (te=ev->timed_events;te;te=te->next) {
-               int timeout = te->next_event - t;
-               if (timeout < 0) {
-                       timeout = 0;
-               }
-               if (te->ref_count &&
-                   timeout < tval.tv_sec) {
-                       tval.tv_sec = timeout;
-               }
+               struct timeval tv = timeval_diff(&te->next_event, &t);
+               tval = timeval_min(&tv, &tval);
        }
 
        /* only do a select() if there're fd_events
@@ -368,7 +361,7 @@ int event_loop_once(struct event_context *ev)
                 */
                selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval);
                
-               t = time(NULL);
+               t = timeval_current();
                
                if (selrtn == -1 && errno == EBADF) {
                        /* the socket is dead! this should never
@@ -404,11 +397,11 @@ int event_loop_once(struct event_context *ev)
                if (te->ref_count == 0) {
                        DLIST_REMOVE(ev->timed_events, te);
                        talloc_free(te);
-               } else if (te->next_event <= t) {
+               } else if (timeval_compare(&te->next_event, &t) >= 0) {
                        te->ref_count++;
                        te->handler(ev, te, t);
                        te->ref_count--;
-                       if (te->next_event <= t) {
+                       if (timeval_compare(&te->next_event, &t) >= 0) {
                                /* the handler didn't set a time for the 
                                   next event - remove the event */
                                event_remove_timed(ev, te);
index f862b2d5053eb38d58d2fae8e82c316749dd9949..041554a7c04a52a68add8745e89164242427a84a 100644 (file)
@@ -29,6 +29,9 @@
 /* change the message version with any incompatible changes in the protocol */
 #define MESSAGING_VERSION 1
 
+/* the number of microseconds to backoff in retrying to send a message */
+#define MESSAGING_BACKOFF 250000
+
 struct messaging_context {
        servid_t server_id;
        struct socket_context *sock;
@@ -119,7 +122,7 @@ static void messaging_dispatch(struct messaging_context *msg, struct messaging_r
   handle IO for a single message
 */
 static void messaging_recv_handler(struct event_context *ev, struct fd_event *fde, 
-                                time_t t, uint16_t flags)
+                                  struct timeval t, uint16_t flags)
 {
        struct messaging_rec *rec = fde->private;
        struct messaging_context *msg = rec->msg;
@@ -200,7 +203,7 @@ static int rec_destructor(void *ptr)
   handle a new incoming connection
 */
 static void messaging_listen_handler(struct event_context *ev, struct fd_event *fde, 
-                                    time_t t, uint16_t flags)
+                                    struct timeval t, uint16_t flags)
 {
        struct messaging_context *msg = fde->private;
        struct messaging_rec *rec;
@@ -272,7 +275,7 @@ void messaging_deregister(struct messaging_context *msg, uint32_t msg_type, void
   handle IO for sending a message
 */
 static void messaging_send_handler(struct event_context *ev, struct fd_event *fde, 
-                                  time_t t, uint16_t flags)
+                                  struct timeval t, uint16_t flags)
 {
        struct messaging_rec *rec = fde->private;
        NTSTATUS status;
@@ -323,20 +326,34 @@ static void messaging_send_handler(struct event_context *ev, struct fd_event *fd
 }
 
 
+/*
+  wrapper around socket_connect with raised privileges
+*/
+static NTSTATUS try_connect(struct messaging_rec *rec)
+{
+       NTSTATUS status;
+       void *priv = root_privileges();
+       status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0);
+       talloc_free(priv);
+       return status;
+}
+
+
 /*
   when the servers listen queue is full we use this to backoff the message
 */
-static void messaging_backoff_handler(struct event_context *ev, struct timed_event *te, time_t t)
+static void messaging_backoff_handler(struct event_context *ev, struct timed_event *te, 
+                                     struct timeval t)
 {
        struct messaging_rec *rec = te->private;
        struct messaging_context *msg = rec->msg;
        NTSTATUS status;
        struct fd_event fde;
 
-       status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0);
+       status = try_connect(rec);
        if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
                /* backoff again */
-               te->next_event = t+1;
+               te->next_event = timeval_add(&t, 0, MESSAGING_BACKOFF);
                return;
        }
 
@@ -356,7 +373,7 @@ static void messaging_backoff_handler(struct event_context *ev, struct timed_eve
 
        talloc_set_destructor(rec, rec_destructor);
 
-       messaging_send_handler(msg->event.ev, rec->fde, 0, EVENT_FD_WRITE);
+       messaging_send_handler(msg->event.ev, rec->fde, timeval_zero(), EVENT_FD_WRITE);
 }
 
 
@@ -396,11 +413,11 @@ NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t
 
        rec->path = messaging_path(rec, server);
 
-       status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0);
+       status = try_connect(rec);
        if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
                /* backoff on this message - the servers listen queue is full */
                struct timed_event te;
-               te.next_event = time(NULL)+1;
+               te.next_event = timeval_current_ofs(0, MESSAGING_BACKOFF);
                te.handler = messaging_backoff_handler;
                te.private = rec;
                event_add_timed(msg->event.ev, &te);
@@ -421,11 +438,25 @@ NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t
 
        talloc_set_destructor(rec, rec_destructor);
 
-       messaging_send_handler(msg->event.ev, rec->fde, 0, EVENT_FD_WRITE);
+       messaging_send_handler(msg->event.ev, rec->fde, timeval_zero(), EVENT_FD_WRITE);
 
        return NT_STATUS_OK;
 }
 
+/*
+  Send a message to a particular server, with the message containing a single pointer
+*/
+NTSTATUS messaging_send_ptr(struct messaging_context *msg, servid_t server, 
+                           uint32_t msg_type, void *ptr)
+{
+       DATA_BLOB blob;
+
+       blob.data = (void *)&ptr;
+       blob.length = sizeof(void *);
+
+       return messaging_send(msg, server, msg_type, &blob);
+}
+
 
 /*
   destroy the messaging context
index cfceebf9cb71624eccee79caa4ca5059a2e202b6..9e6da2cfa696b0e0c92a122ecc0ab5c8581cffe0 100644 (file)
@@ -386,9 +386,144 @@ NTTIME nttime_from_string(const char *s)
        return strtoull(s, NULL, 0);
 }
 
-int64_t usec_time_diff(struct timeval *larget, struct timeval *smallt)
+/*
+  return (tv1 - tv2) in microseconds
+*/
+int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2)
+{
+       int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
+       return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
+}
+
+
+/*
+  return a zero timeval
+*/
+struct timeval timeval_zero(void)
 {
-       int64_t sec_diff = larget->tv_sec - smallt->tv_sec;
-       return (sec_diff * 1000000) + (int64_t)(larget->tv_usec - smallt->tv_usec);
+       struct timeval tv;
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       return tv;
 }
 
+/*
+  return a timeval for the current time
+*/
+struct timeval timeval_current(void)
+{
+       struct timeval tv;
+       GetTimeOfDay(&tv);
+       return tv;
+}
+
+/*
+  return a timeval struct with the given elements
+*/
+struct timeval timeval_set(uint32_t secs, uint32_t usecs)
+{
+       struct timeval tv;
+       tv.tv_sec = secs;
+       tv.tv_usec = usecs;
+       return tv;
+}
+
+
+/*
+  return a timeval ofs microseconds after tv
+*/
+struct timeval timeval_add(struct timeval *tv, uint32_t secs, uint32_t usecs)
+{
+       struct timeval tv2 = *tv;
+       const uint_t million = 1000000;
+       tv2.tv_sec += secs;
+       tv2.tv_usec += usecs;
+       tv2.tv_sec += tv2.tv_usec / million;
+       tv2.tv_usec = tv2.tv_usec % million;
+       return tv2;
+}
+
+/*
+  return the sum of two timeval structures
+*/
+struct timeval timeval_sum(struct timeval *tv1, struct timeval *tv2)
+{
+       return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
+}
+
+/*
+  return a timeval secs/usecs into the future
+*/
+struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
+{
+       struct timeval tv = timeval_current();
+       return timeval_add(&tv, secs, usecs);
+}
+
+/*
+  compare two timeval structures. 
+  Return 1 if tv2 > tv1
+  Return 0 if tv2 == tv1
+  Return -1 if tv2 < tv1
+*/
+int timeval_compare(struct timeval *tv1, struct timeval *tv2)
+{
+       if (tv2->tv_sec  > tv1->tv_sec)  return 1;
+       if (tv2->tv_sec  < tv1->tv_sec)  return -1;
+       if (tv2->tv_usec > tv1->tv_usec) return 1;
+       if (tv2->tv_usec < tv1->tv_usec) return -1;
+       return 0;
+}
+
+/*
+  return True if a timer is in the past
+*/
+BOOL timeval_expired(struct timeval *tv)
+{
+       struct timeval tv2 = timeval_current();
+       if (tv2.tv_sec > tv->tv_sec) return True;
+       if (tv2.tv_sec < tv->tv_sec) return False;
+       return (tv2.tv_usec >= tv->tv_usec);
+}
+
+/*
+  return the number of seconds elapsed since a given time
+*/
+double timeval_elapsed(struct timeval *tv)
+{
+       struct timeval tv2 = timeval_current();
+       return (tv2.tv_sec - tv->tv_sec) + 
+              (tv2.tv_usec - tv->tv_usec)*1.0e-6;
+}
+
+/*
+  return the lesser of two timevals
+*/
+struct timeval timeval_min(struct timeval *tv1, struct timeval *tv2)
+{
+       if (tv1->tv_sec < tv2->tv_sec) return *tv1;
+       if (tv1->tv_sec > tv2->tv_sec) return *tv2;
+       if (tv1->tv_usec < tv2->tv_usec) return *tv1;
+       return *tv2;
+}
+
+/*
+  return the difference between two timevals as a timeval
+  if tv2 comes after tv1, then return a zero timeval
+  (this is *tv1 - *tv2)
+*/
+struct timeval timeval_diff(struct timeval *tv1, struct timeval *tv2)
+{
+       struct timeval t;
+       if (timeval_compare(tv1, tv2) >= 0) {
+               return timeval_zero();
+       }
+       t.tv_sec = tv1->tv_sec - tv2->tv_sec;
+       if (tv2->tv_usec > tv1->tv_usec) {
+               t.tv_sec--;
+               t.tv_usec = 1000000 - (tv2->tv_usec - tv1->tv_usec);
+       } else {
+               t.tv_usec = tv1->tv_usec - tv2->tv_usec;
+       }
+       return t;
+}
diff --git a/source4/lib/unix_privs.c b/source4/lib/unix_privs.c
new file mode 100644 (file)
index 0000000..c65f490
--- /dev/null
@@ -0,0 +1,69 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   gain/lose root privileges
+
+   Copyright (C) Andrew Tridgell 2004
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "system/passwd.h"
+
+/*
+  there are times when smbd needs to temporarily gain root privileges
+  to do some operation. To do this you call root_privileges(), which
+  returns a talloc handle. To restore your previous privileges
+  talloc_free() this pointer.
+
+  Note that this call is considered successful even if it does not
+  manage to gain too privileges, but it will call smb_abort() if it
+  fails to restore the privileges afterwards. The logic is that
+  failing to gain root access can be caught by whatever operation
+  needs to be run as root failing, but failing to lose the root
+  privileges is dangerous.
+
+  This also means that this code is safe to be called from completely
+  unprivileged processes.
+*/
+
+struct saved_state {
+       uid_t uid;
+};
+
+static int privileges_destructor(void *ptr)
+{
+       struct saved_state *s = ptr;
+       if (geteuid() != s->uid &&
+           seteuid(s->uid) != 0) {
+               smb_panic("Failed to restore privileges");
+       }
+       return 0;
+}
+
+void *root_privileges(void)
+{
+       struct saved_state *s;
+       s = talloc_p(NULL, struct saved_state);
+       if (!s) return NULL;
+       s->uid = geteuid();
+       if (s->uid != 0) {
+               seteuid(0);
+       }
+       talloc_set_destructor(s, privileges_destructor);
+       return s;
+}
+
index 00e52f3a1418776319a4f21375be99b70c6c477d..52cb4d8beb50ea26f2aeed28472db29723ea0446 100644 (file)
@@ -33,7 +33,7 @@ static void smbcli_transport_process_send(struct smbcli_transport *transport);
   an event has happened on the socket
 */
 static void smbcli_transport_event_handler(struct event_context *ev, struct fd_event *fde, 
-                                       time_t t, uint16_t flags)
+                                          struct timeval t, uint16_t flags)
 {
        struct smbcli_transport *transport = fde->private;
 
@@ -233,21 +233,21 @@ again:
 }
 
 static void idle_handler(struct event_context *ev, 
-                        struct timed_event *te, time_t t)
+                        struct timed_event *te, struct timeval t)
 {
        struct smbcli_transport *transport = te->private;
-       te->next_event = t + transport->idle.period;
+       te->next_event = timeval_add(&te->next_event, 0, transport->idle.period);
        transport->idle.func(transport, transport->idle.private);
 }
 
 /*
   setup the idle handler for a transport
-  the period is in seconds
+  the period is in microseconds
 */
 void smbcli_transport_idle_handler(struct smbcli_transport *transport, 
-                               void (*idle_func)(struct smbcli_transport *, void *),
-                               uint_t period,
-                               void *private)
+                                  void (*idle_func)(struct smbcli_transport *, void *),
+                                  uint64_t period,
+                                  void *private)
 {
        struct timed_event te;
        transport->idle.func = idle_func;
@@ -258,7 +258,7 @@ void smbcli_transport_idle_handler(struct smbcli_transport *transport,
                event_remove_timed(transport->event.ctx, transport->event.te);
        }
 
-       te.next_event = time(NULL) + period;
+       te.next_event = timeval_current_ofs(0, period);
        te.handler = idle_handler;
        te.private = transport;
        transport->event.te = event_add_timed(transport->event.ctx, &te);
index 9b03ab713b78611fbce396185e5d1af536a5fa2d..b00af846b77a13319ff7ded12550cee55f1f7dc9 100644 (file)
@@ -114,7 +114,7 @@ struct smbcli_transport {
        uint_t readbraw_pending:1;
        
        /* an idle function - if this is defined then it will be
-          called once every period seconds while we are waiting
+          called once every period microseconds while we are waiting
           for a packet */
        struct {
                void (*func)(struct smbcli_transport *, void *);
index 41fde60ea0c6d0d3b5346d15b34924591b17b75f..26464884bc976adab437f9e9c8efb78f9d840e41 100644 (file)
@@ -190,7 +190,7 @@ static void sock_process_recv(struct dcerpc_pipe *p)
   called when a IO is triggered by the events system
 */
 static void sock_io_handler(struct event_context *ev, struct fd_event *fde, 
-                          time_t t, uint16_t flags)
+                           struct timeval t, uint16_t flags)
 {
        struct dcerpc_pipe *p = fde->private;
        struct sock_private *sock = p->transport.private;
index 4fd5650f9b90e7adeb001625e92ea015c07c515c..3e9899cb8ca691864f8f27317394d451b1a41730 100644 (file)
@@ -78,7 +78,8 @@ static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin
  /*
   a handler for read events on a connection to a backend server
 */
-static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
+static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, 
+                               struct timeval t, uint16_t flags)
 {
        struct cvfs_private *private = fde->private;
        struct smbsrv_tcon *tcon = private->tcon;
@@ -149,7 +150,7 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
        
        /* we need to receive oplock break requests from the server */
        smbcli_oplock_handler(private->transport, oplock_handler, private);
-       smbcli_transport_idle_handler(private->transport, idle_func, 1, private);
+       smbcli_transport_idle_handler(private->transport, idle_func, 50000, private);
 
        private->transport->event.fde->handler = cifs_socket_handler;
        private->transport->event.fde->private = private;
index d1df0413ce8e6baed0c405a1dfbd7ccfc8818a39..6fae7c6e4cf106558074929e8ac2441c64007fbb 100644 (file)
@@ -333,17 +333,14 @@ static void brl_notify_unlock(struct brl_context *brl,
        for (i=0;i<count;i++) {
                if (locks[i].lock_type >= PENDING_READ_LOCK &&
                    brl_overlap(&locks[i], removed_lock)) {
-                       DATA_BLOB data;
-
                        if (last_notice != -1 && brl_overlap(&locks[i], &locks[last_notice])) {
                                continue;
                        }
                        if (locks[i].lock_type == PENDING_WRITE_LOCK) {
                                last_notice = i;
                        }
-                       data.data = (void *)&locks[i].notify_ptr;
-                       data.length = sizeof(void *);
-                       messaging_send(brl->messaging_ctx, locks[i].context.server, MSG_BRL_RETRY, &data);
+                       messaging_send_ptr(brl->messaging_ctx, locks[i].context.server, 
+                                          MSG_BRL_RETRY, locks[i].notify_ptr);
                }
        }
 }
index 5dc68e538282fb75ffae0c57ded16a8a2a40dbb4..39d4f37ec2e144d96aefa6760e2bd89866e614ec 100644 (file)
@@ -39,6 +39,7 @@
 */
 
 #include "includes.h"
+#include "messages.h"
 
 struct odb_context {
        struct tdb_wrap *w;
@@ -58,6 +59,8 @@ struct odb_entry {
        uint32_t share_access;
        uint32_t create_options;
        uint32_t access_mask;
+       void     *notify_ptr;
+       BOOL     pending;
 };
 
 
@@ -152,6 +155,8 @@ static BOOL share_conflict(struct odb_entry *e1, struct odb_entry *e2)
 {
 #define CHECK_MASK(am, sa, right, share) if (((am) & (right)) && !((sa) & (share))) return True
 
+       if (e1->pending || e2->pending) return False;
+
        /* if either open involves no read.write or delete access then
           it can't conflict */
        if (!(e1->access_mask & (SA_RIGHT_FILE_WRITE_APPEND | 
@@ -219,6 +224,8 @@ NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum,
        e.share_access   = share_access;
        e.create_options = create_options;
        e.access_mask    = access_mask;
+       e.notify_ptr     = NULL;
+       e.pending        = False;
 
        /* check the existing file opens to see if they
           conflict */
@@ -254,6 +261,56 @@ NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum,
 }
 
 
+/*
+  register a pending open file in the open files database
+*/
+NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private)
+{
+       struct odb_context *odb = lck->odb;
+       TDB_DATA dbuf;
+       struct odb_entry e;
+       char *tp;
+       struct odb_entry *elist;
+       int count;
+               
+       dbuf = tdb_fetch(odb->w->tdb, lck->key);
+
+       e.server         = odb->server;
+       e.tid            = odb->tid;
+       e.fnum           = 0;
+       e.share_access   = 0;
+       e.create_options = 0;
+       e.access_mask    = 0;
+       e.notify_ptr     = private;
+       e.pending        = True;
+
+       /* check the existing file opens to see if they
+          conflict */
+       elist = (struct odb_entry *)dbuf.dptr;
+       count = dbuf.dsize / sizeof(struct odb_entry);
+
+       tp = Realloc(dbuf.dptr, (count+1) * sizeof(struct odb_entry));
+       if (tp == NULL) {
+               if (dbuf.dptr) free(dbuf.dptr);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       dbuf.dptr = tp;
+       dbuf.dsize = (count+1) * sizeof(struct odb_entry);
+
+       memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
+              &e, sizeof(struct odb_entry));
+
+       if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
+               free(dbuf.dptr);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       free(dbuf.dptr);
+       return NT_STATUS_OK;
+}
+
+
 /*
   remove a opendb entry
 */
@@ -274,6 +331,15 @@ NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum)
        elist = (struct odb_entry *)dbuf.dptr;
        count = dbuf.dsize / sizeof(struct odb_entry);
 
+       /* send any pending notifications */
+       for (i=0;i<count;i++) {
+               if (elist[i].pending) {
+                       messaging_send_ptr(odb->messaging_ctx, elist[i].server, 
+                                          MSG_PVFS_RETRY_OPEN, elist[i].notify_ptr);
+                       
+               }
+       }
+
        /* find the entry, and delete it */
        for (i=0;i<count;i++) {
                if (fnum == elist[i].fnum &&
@@ -308,6 +374,60 @@ NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum)
 }
 
 
+/*
+  remove a pending opendb entry
+*/
+NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private)
+{
+       struct odb_context *odb = lck->odb;
+       TDB_DATA dbuf;
+       struct odb_entry *elist;
+       int i, count;
+       NTSTATUS status;
+
+       dbuf = tdb_fetch(odb->w->tdb, lck->key);
+
+       if (dbuf.dptr == NULL) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       elist = (struct odb_entry *)dbuf.dptr;
+       count = dbuf.dsize / sizeof(struct odb_entry);
+
+       /* find the entry, and delete it */
+       for (i=0;i<count;i++) {
+               if (private == elist[i].notify_ptr &&
+                   odb->server == elist[i].server &&
+                   odb->tid == elist[i].tid) {
+                       if (i < count-1) {
+                               memmove(elist+i, elist+i+1, 
+                                       (count - (i+1)) * sizeof(struct odb_entry));
+                       }
+                       break;
+               }
+       }
+
+       status = NT_STATUS_OK;
+
+       if (i == count) {
+               status = NT_STATUS_UNSUCCESSFUL;
+       } else if (count == 1) {
+               if (tdb_delete(odb->w->tdb, lck->key) != 0) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       } else {
+               dbuf.dsize = (count-1) * sizeof(struct odb_entry);
+               if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       }
+
+       free(dbuf.dptr);
+
+       return status;
+}
+
+
 /*
   update create options on an open file
 */
@@ -386,6 +506,8 @@ NTSTATUS odb_can_open(struct odb_context *odb, DATA_BLOB *key,
        e.share_access   = share_access;
        e.create_options = create_options;
        e.access_mask    = access_mask;
+       e.notify_ptr     = NULL;
+       e.pending        = False;
 
        for (i=0;i<count;i++) {
                if (share_conflict(elist+i, &e)) {
index 2668eec00484c435462e980bbf24707606fd3582..82ac9ebad574adb240f151274b8ace4eb56c9f85 100644 (file)
@@ -56,7 +56,7 @@ struct pvfs_pending_lock {
        struct smbsrv_request *req;
        int pending_lock;
        void *wait_handle;
-       time_t end_time;
+       struct timeval end_time;
 };
 
 /*
@@ -301,8 +301,9 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                pending->f = f;
                pending->req = req;
 
-               /* round up to the nearest second */
-               pending->end_time = time(NULL) + ((lck->lockx.in.timeout+999)/1000);
+               pending->end_time = 
+                       timeval_current_ofs(lck->lockx.in.timeout/1000,
+                                           1000*(lck->lockx.in.timeout%1000));
        }
 
        if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) {
index f3ef72f4ed546536db7b9af386fe9a83294b59b0..8ad6ad0389d08daa36421f1560237121cdfdcf5b 100644 (file)
@@ -25,6 +25,7 @@
 #include "system/time.h"
 #include "system/filesys.h"
 #include "dlinklist.h"
+#include "messages.h"
 
 /*
   create file handles with convenient numbers for sniffers
@@ -33,6 +34,8 @@
 #define PVFS_MIN_NEW_FNUM  0x200
 #define PVFS_MIN_DIR_FNUM  0x300
 
+#define SHARING_VIOLATION_DELAY 1000000
+
 /*
   find open file handle given fnum
 */
@@ -125,7 +128,6 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
 
        fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_DIR_FNUM, UINT16_MAX);
        if (fnum == -1) {
-               talloc_free(f);
                return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
 
@@ -228,10 +230,12 @@ static int pvfs_fd_destructor(void *p)
                return 0;
        }
 
-       status = odb_close_file(lck, f->fnum);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
-                        f->name->full_name, nt_errstr(status)));
+       if (f->have_opendb_entry) {
+               status = odb_close_file(lck, f->fnum);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
+                                f->name->full_name, nt_errstr(status)));
+               }
        }
 
        talloc_free(lck);
@@ -370,6 +374,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->access_mask = access_mask;
        f->seek_offset = 0;
        f->position = 0;
+       f->have_opendb_entry = True;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -398,6 +403,166 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
 }
 
 
+/*
+  open am existing file - called from both the open retry code
+  and the main open code
+*/
+NTSTATUS pvfs_open_existing(struct pvfs_file *f,
+                           union smb_open *io,
+                           int open_flags)
+{
+       int fd;
+       NTSTATUS status;
+
+       /* do the actual open */
+       fd = open(f->name->full_name, open_flags);
+       if (fd == -1) {
+               return pvfs_map_errno(f->pvfs, errno);
+       }
+
+       f->fd = fd;
+
+       /* re-resolve the open fd */
+       status = pvfs_resolve_name_fd(f->pvfs, fd, f->name);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       io->generic.out.oplock_level  = NO_OPLOCK;
+       io->generic.out.fnum          = f->fnum;
+       io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
+       io->generic.out.create_time   = f->name->dos.create_time;
+       io->generic.out.access_time   = f->name->dos.access_time;
+       io->generic.out.write_time    = f->name->dos.write_time;
+       io->generic.out.change_time   = f->name->dos.change_time;
+       io->generic.out.attrib        = f->name->dos.attrib;
+       io->generic.out.alloc_size    = f->name->dos.alloc_size;
+       io->generic.out.size          = f->name->st.st_size;
+       io->generic.out.file_type     = FILE_TYPE_DISK;
+       io->generic.out.ipc_state     = 0;
+       io->generic.out.is_directory  = 0;
+
+       /* success - keep the file handle */
+       talloc_steal(f->pvfs, f);
+
+       return NT_STATUS_OK;
+}
+
+/*
+  state of a pending open retry
+*/
+struct pvfs_open_retry {
+       union smb_open *io;
+       struct pvfs_file *f;
+       struct smbsrv_request *req;
+       void *wait_handle;
+       struct timeval end_time;
+       int open_flags;
+};
+
+/* destroy a pending open request */
+static int pvfs_retry_destructor(void *ptr)
+{
+       struct pvfs_open_retry *r = ptr;
+       struct odb_lock *lck;
+       lck = odb_lock(r->req, r->f->pvfs->odb_context, &r->f->locking_key);
+       if (lck != NULL) {
+               odb_remove_pending(lck, r);
+       }
+       return 0;
+}
+
+/*
+  retry an open
+*/
+static void pvfs_open_retry(void *private, BOOL timed_out)
+{
+       struct pvfs_open_retry *r = private;
+       struct odb_lock *lck;
+       struct pvfs_file *f = r->f;
+       struct smbsrv_request *req = r->req;
+       NTSTATUS status;
+       
+       lck = odb_lock(req, f->pvfs->odb_context, &f->locking_key);
+       if (lck == NULL) {
+               req->async_states->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               req->async_states->send_fn(req);
+               return;
+       }
+
+       /* see if we are allowed to open at the same time as existing opens */
+       status = odb_open_file(lck, f->fnum, f->share_access, 
+                              f->create_options, f->access_mask);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) && !timed_out) {
+               talloc_free(lck);
+               return;
+       }
+
+       talloc_free(r->wait_handle);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               req->async_states->status = status;
+               req->async_states->send_fn(req);
+               return;
+       }
+
+       f->have_opendb_entry = True;
+
+       /* do the rest of the open work */
+       status = pvfs_open_existing(f, r->io, r->open_flags);
+
+       if (NT_STATUS_IS_OK(status)) {
+               talloc_steal(f->pvfs, f);
+       }
+
+       req->async_states->status = status;
+       req->async_states->send_fn(req);
+}
+
+/*
+  setup for a open retry after a sharing violation
+*/
+static NTSTATUS pvfs_open_setup_retry(struct smbsrv_request *req, 
+                                     union smb_open *io,
+                                     struct pvfs_file *f, 
+                                     struct odb_lock *lck,
+                                     int open_flags)
+{
+       struct pvfs_open_retry *r;
+       struct pvfs_state *pvfs = f->pvfs;
+       NTSTATUS status;
+
+       r = talloc_p(req, struct pvfs_open_retry);
+       if (r == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       r->io = io;
+       r->f = f;
+       r->req = req;
+       r->end_time = timeval_current_ofs(0, SHARING_VIOLATION_DELAY);
+       r->open_flags = open_flags;
+
+       /* setup a pending lock */
+       status = odb_open_file_pending(lck, r);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, r->end_time, 
+                                          pvfs_open_retry, r);
+       if (r->wait_handle == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       talloc_free(lck);
+       talloc_steal(pvfs, req);
+
+       talloc_set_destructor(r, pvfs_retry_destructor);
+
+       return NT_STATUS_OK;
+}
+
 /*
   open a file
 */
@@ -405,7 +570,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                   struct smbsrv_request *req, union smb_open *io)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
-       int fd, flags;
+       int flags;
        struct pvfs_filename *name;
        struct pvfs_file *f;
        NTSTATUS status;
@@ -539,11 +704,26 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
 
+       f->fnum = fnum;
+       f->fd = -1;
+       f->name = talloc_steal(f, name);
+       f->session = req->session;
+       f->smbpid = req->smbpid;
+       f->pvfs = pvfs;
+       f->pending_list = NULL;
+       f->lock_count = 0;
+       f->create_options = io->generic.in.create_options;
+       f->share_access = io->generic.in.share_access;
+       f->access_mask = access_mask;
+       f->seek_offset = 0;
+       f->position = 0;
+       f->have_opendb_entry = False;
+
        /* form the lock context used for byte range locking and
           opendb locking */
        status = pvfs_locking_key(name, f, &f->locking_key);
        if (!NT_STATUS_IS_OK(status)) {
-               idr_remove(pvfs->idtree_fnum, fnum);
+               idr_remove(pvfs->idtree_fnum, f->fnum);
                return status;
        }
 
@@ -558,65 +738,31 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       /* see if we are allowed to open at the same time as existing opens */
-       status = odb_open_file(lck, fnum, share_access, create_options, access_mask);
-       if (!NT_STATUS_IS_OK(status)) {
-               idr_remove(pvfs->idtree_fnum, fnum);
-               return status;
-       }
-
-       f->fnum = fnum;
-       f->fd = -1;
-       f->name = talloc_steal(f, name);
-       f->session = req->session;
-       f->smbpid = req->smbpid;
-       f->pvfs = pvfs;
-       f->pending_list = NULL;
-       f->lock_count = 0;
-       f->create_options = io->generic.in.create_options;
-       f->share_access = io->generic.in.share_access;
-       f->access_mask = access_mask;
-       f->seek_offset = 0;
-       f->position = 0;
-
        DLIST_ADD(pvfs->open_files, f);
 
        /* setup a destructor to avoid file descriptor leaks on
           abnormal termination */
        talloc_set_destructor(f, pvfs_fd_destructor);
 
-       /* do the actual open */
-       fd = open(name->full_name, flags);
-       if (fd == -1) {
-               return pvfs_map_errno(pvfs, errno);
-       }
 
-       f->fd = fd;
+       /* see if we are allowed to open at the same time as existing opens */
+       status = odb_open_file(lck, f->fnum, share_access, create_options, access_mask);
+
+       /* on a sharing violation we need to retry when the file is closed by 
+          the other user, or after 1 second */
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
+           (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+               return pvfs_open_setup_retry(req, io, f, lck, flags);
+       }
 
-       /* re-resolve the open fd */
-       status = pvfs_resolve_name_fd(pvfs, fd, name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       io->generic.out.oplock_level  = NO_OPLOCK;
-       io->generic.out.fnum          = f->fnum;
-       io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
-       io->generic.out.create_time   = name->dos.create_time;
-       io->generic.out.access_time   = name->dos.access_time;
-       io->generic.out.write_time    = name->dos.write_time;
-       io->generic.out.change_time   = name->dos.change_time;
-       io->generic.out.attrib        = name->dos.attrib;
-       io->generic.out.alloc_size    = name->dos.alloc_size;
-       io->generic.out.size          = name->st.st_size;
-       io->generic.out.file_type     = FILE_TYPE_DISK;
-       io->generic.out.ipc_state     = 0;
-       io->generic.out.is_directory  = 0;
-
-       /* success - keep the file handle */
-       talloc_steal(pvfs, f);
+       f->have_opendb_entry = True;
 
-       return NT_STATUS_OK;
+       /* do the rest of the open work */
+       return pvfs_open_existing(f, io, flags);
 }
 
 
@@ -677,7 +823,6 @@ NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
        for (f=pvfs->open_files;f;f=next) {
                next = f->next;
                if (f->session == req->session) {
-                       DLIST_REMOVE(pvfs->open_files, f);
                        talloc_free(f);
                }
        }
@@ -698,7 +843,6 @@ NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
        for (f=pvfs->open_files;f;f=next) {
                next = f->next;
                if (f->smbpid == req->smbpid) {
-                       DLIST_REMOVE(pvfs->open_files, f);
                        talloc_free(f);
                }
        }
index f01bd0ea189a5b1c514af8f2a8a747d14b0f426f..0faab8ef555f2803cf41de6b135b598f8876f518 100644 (file)
@@ -58,10 +58,9 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin
        struct pvfs_wait *pwait = private;
        struct smbsrv_request *req;
 
-       /* we need to check that this one is for us. This sender sends
-          the private pointer as the body of the message. This might
-          seem a little unusual, but as the pointer is guaranteed
-          unique for this server, it is a good token */
+       /* we need to check that this one is for us. See
+          messaging_send_ptr() for the other side of this.
+        */
        if (data->length != sizeof(void *) ||
            *(void **)data->data != pwait->private) {
                return;
@@ -82,7 +81,8 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin
 /*
   receive a timeout on a message wait
 */
-static void pvfs_wait_timeout(struct event_context *ev, struct timed_event *te, time_t t)
+static void pvfs_wait_timeout(struct event_context *ev, 
+                             struct timed_event *te, struct timeval t)
 {
        struct pvfs_wait *pwait = te->private;
        struct smbsrv_request *req = pwait->req;
@@ -116,7 +116,7 @@ static int pvfs_wait_destructor(void *ptr)
 void *pvfs_wait_message(struct pvfs_state *pvfs, 
                        struct smbsrv_request *req, 
                        int msg_type, 
-                       time_t end_time,
+                       struct timeval end_time,
                        void (*fn)(void *, BOOL),
                        void *private)
 {
index 530a2deae3d734842064cca3778bc97e90307072..265649f5a38004f3e2b90314fa31b64966dda2ac 100644 (file)
@@ -112,6 +112,8 @@ struct pvfs_file {
        /* yes, we need 2 independent positions ... */
        uint64_t seek_offset;
        uint64_t position;
+
+       BOOL have_opendb_entry;
 };
 
 
index f9e2d8d28e154f3d949e75b721b8e19312604fc0..3aeb7033d1bf538f5a1d11e80a62db375b479883 100644 (file)
@@ -1057,21 +1057,18 @@ static void dcesrv_accept(struct server_connection *srv_conn)
        dcesrv_sock_accept(srv_conn);
 }
 
-static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
+static void dcesrv_recv(struct server_connection *srv_conn, 
+                       struct timeval t, uint16_t flags)
 {
        dcesrv_sock_recv(srv_conn, t, flags);
 }
 
-static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
+static void dcesrv_send(struct server_connection *srv_conn, 
+                       struct timeval t, uint16_t flags)
 {
        dcesrv_sock_send(srv_conn, t, flags);
 }
 
-static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
-{
-       dcesrv_sock_idle(srv_conn, t);
-}
-
 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
 {
        dcesrv_sock_close(srv_conn, reason);
@@ -1190,7 +1187,7 @@ static const struct server_service_ops dcesrv_ops = {
        .accept_connection      = dcesrv_accept,
        .recv_handler           = dcesrv_recv,
        .send_handler           = dcesrv_send,
-       .idle_handler           = dcesrv_idle,
+       .idle_handler           = NULL,
        .close_connection       = dcesrv_close,
        .service_exit           = dcesrv_exit,  
 };
index 544082471ee6fcd285d0835cc8913dd716f70dba..f8d0bbfc6dde71d59e94550d640da33e717bb842 100644 (file)
@@ -248,7 +248,7 @@ void dcesrv_sock_accept(struct server_connection *conn)
        return; 
 }
 
-void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
+void dcesrv_sock_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
 {
        NTSTATUS status;
        struct dcesrv_connection *dce_conn = conn->private_data;
@@ -288,7 +288,7 @@ void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
        return; 
 }
 
-void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
+void dcesrv_sock_send(struct server_connection *conn, struct timeval t, uint16_t flags)
 {
        struct dcesrv_connection *dce_conn = conn->private_data;
        NTSTATUS status;
@@ -308,14 +308,6 @@ void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
        return;
 }
 
-void dcesrv_sock_idle(struct server_connection *conn, time_t t)
-{
-       DEBUG(10,("dcesrv_sock_idle\n"));
-       conn->event.idle->next_event = t + 5;
-
-       return; 
-}
-
 void dcesrv_sock_close(struct server_connection *conn, const char *reason)
 {
        struct dcesrv_connection *dce_conn = conn->private_data;
index e1eb4e3179a47e8118bc8a511d63274c0b0129d4..861186a8d7bc981ae837f3e6a9b20ec26ebb745f 100644 (file)
@@ -723,7 +723,7 @@ static void smbsrv_init(struct server_service *service, const struct model_ops *
 /*
   called when a SMB socket becomes readable
 */
-static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
+static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
 {
        struct smbsrv_connection *smb_conn = conn->private_data;
        NTSTATUS status;
@@ -744,7 +744,7 @@ static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags
 /*
   called when a SMB socket becomes writable
 */
-static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
+static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
 {
        struct smbsrv_connection *smb_conn = conn->private_data;
 
@@ -787,11 +787,10 @@ static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags
 /*
   called when connection is idle
 */
-static void smbsrv_idle(struct server_connection *conn, time_t t)
+static void smbsrv_idle(struct server_connection *conn, struct timeval t)
 {
        DEBUG(10,("smbsrv_idle: not implemented!\n"));
-       conn->event.idle->next_event = t + 5;
-
+       conn->event.idle->next_event = timeval_add(&t, 5, 0);
        return;
 }
 
index 79373d8a39d7f7a148d252ec7fe1451362e3d35b..92d92a70ad81f3b372397cb168271c90aff290f1 100644 (file)
@@ -40,10 +40,12 @@ struct model_ops {
        void (*model_startup)(void);
 
        /* function to accept new connection */
-       void (*accept_connection)(struct event_context *, struct fd_event *, time_t, uint16_t);
+       void (*accept_connection)(struct event_context *, struct fd_event *, 
+                                 struct timeval t, uint16_t);
                        
        /* function to terminate a connection */
-       void (*terminate_connection)(struct server_connection *srv_conn, const char *reason);
+       void (*terminate_connection)(struct server_connection *srv_conn, 
+                                    const char *reason);
 
        /* function to exit server */
        void (*exit_server)(struct server_context *srv_ctx, const char *reason);
index 6ce0479b0c6c99f54be07af6c2254b7de313f991..66074d166d61ec99453039ee4e3296e873fe4b98 100644 (file)
@@ -38,7 +38,8 @@ static void single_start_server(void)
 /*
   called when a listening socket becomes readable
 */
-static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags)
+static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde, 
+                                    struct timeval t, uint16_t flags)
 {
        NTSTATUS status;
        struct socket_context *sock;
@@ -55,7 +56,7 @@ static void single_accept_connection(struct event_context *ev, struct fd_event *
 
        conn = server_setup_connection(ev, server_socket, sock, t, socket_get_fd(sock));
        if (!conn) {
-               DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
+               DEBUG(0,("server_setup_connection failed\n"));
                return;
        }
 
index 3741ce1b46fe3ea6772fff1599f581a7f1e0ab14..c794605dc58e690159774f16f384e56f82b123f9 100644 (file)
@@ -39,7 +39,7 @@ static void standard_model_startup(void)
   called when a listening socket becomes readable
 */
 static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
-                                      time_t t, uint16_t flags)
+                                      struct timeval t, uint16_t flags)
 {
        NTSTATUS status;
        struct socket_context *sock;
index 6d2f9a814967388e212771d3cb4d3b8133f113b7..767d310e2bfca254cf3493beee6ee723a81eab63 100644 (file)
@@ -205,7 +205,7 @@ static int server_destructor(void *ptr)
 struct server_connection *server_setup_connection(struct event_context *ev, 
                                                  struct server_socket *server_socket, 
                                                  struct socket_context *sock, 
-                                                 time_t t,
+                                                 struct timeval t,
                                                  servid_t server_id)
 {
        struct fd_event fde;
@@ -226,13 +226,13 @@ struct server_connection *server_setup_connection(struct event_context *ev,
        fde.handler     = server_io_handler;
 
        idle.private    = srv_conn;
-       idle.next_event = t + SERVER_DEFAULT_IDLE_TIME;
+       idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0);
        idle.handler    = server_idle_handler;
 
        srv_conn->event.ctx             = ev;
        srv_conn->event.fde             = &fde;
        srv_conn->event.idle            = &idle;
-       srv_conn->event.idle_time       = SERVER_DEFAULT_IDLE_TIME;
+       srv_conn->event.idle_time       = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
 
        srv_conn->server_socket         = server_socket;
        srv_conn->service               = server_socket->service;
@@ -269,11 +269,12 @@ void server_terminate_connection(struct server_connection *srv_conn, const char
        srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
 }
 
-void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
+void server_io_handler(struct event_context *ev, struct fd_event *fde, 
+                      struct timeval t, uint16_t flags)
 {
        struct server_connection *conn = fde->private;
 
-       conn->event.idle->next_event = t + conn->event.idle_time;
+       conn->event.idle->next_event = timeval_sum(&t,  &conn->event.idle_time);
 
        if (flags & EVENT_FD_WRITE) {
                conn->service->ops->send_handler(conn, t, flags);
@@ -286,13 +287,14 @@ void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t,
 
 }
 
-void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t)
+void server_idle_handler(struct event_context *ev, struct timed_event *idle, 
+                        struct timeval t)
 {
        struct server_connection *conn = idle->private;
 
-       conn->event.idle->next_event = t + conn->event.idle_time;
+       conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
 
-       conn->service->ops->idle_handler(conn,t);
+       conn->service->ops->idle_handler(conn, t);
 }
 /*
   return the operations structure for a named backend of the specified type
index 2ac1988f3d096f0fbd72b4b8ac69ded20e1b165d..5bb43a74fa58893a19a09c7806fb7a4886f962a3 100644 (file)
@@ -48,13 +48,13 @@ struct server_service_ops {
        void (*accept_connection)(struct server_connection *);
 
        /* function to accept new connection */
-       void (*recv_handler)(struct server_connection *, time_t, uint16_t);
+       void (*recv_handler)(struct server_connection *, struct timeval, uint16_t);
 
        /* function to accept new connection */
-       void (*send_handler)(struct server_connection *, time_t, uint16_t);
+       void (*send_handler)(struct server_connection *, struct timeval, uint16_t);
 
        /* function to accept new connection */
-       void (*idle_handler)(struct server_connection *, time_t);
+       void (*idle_handler)(struct server_connection *, struct timeval);
 
        /* function to close a connection */
        void (*close_connection)(struct server_connection *, const char *reason);
@@ -114,7 +114,7 @@ struct server_connection {
                struct event_context *ctx;
                struct fd_event *fde;
                struct timed_event *idle;
-               time_t idle_time;
+               struct timeval idle_time;
        } event;
 
        servid_t server_id;
index 5d3ac8d1de3d8e8b54b9914e9f72d2a7a70bb78d..7921b3eb0334aa952d8396d181baf5b0739214c0 100644 (file)
@@ -35,9 +35,9 @@ BOOL torture_dirtest1(void)
        int i;
        struct smbcli_state *cli;
        int fnum;
-       double t1;
        BOOL correct = True;
        extern int torture_numops;
+       struct timeval tv;
 
        printf("starting dirtest1\n");
 
@@ -48,6 +48,7 @@ BOOL torture_dirtest1(void)
        printf("Creating %d random filenames\n", torture_numops);
 
        srandom(0);
+       tv = timeval_current();
        for (i=0;i<torture_numops;i++) {
                char *fname;
                asprintf(&fname, "\\%x", (int)random());
@@ -61,13 +62,11 @@ BOOL torture_dirtest1(void)
                free(fname);
        }
 
-       t1 = end_timer();
-
        printf("Matched %d\n", smbcli_list(cli->tree, "a*.*", 0, list_fn, NULL));
        printf("Matched %d\n", smbcli_list(cli->tree, "b*.*", 0, list_fn, NULL));
        printf("Matched %d\n", smbcli_list(cli->tree, "xyzabc", 0, list_fn, NULL));
 
-       printf("dirtest core %g seconds\n", end_timer() - t1);
+       printf("dirtest core %g seconds\n", timeval_elapsed(&tv));
 
        srandom(0);
        for (i=0;i<torture_numops;i++) {
index 07ad0929dec16bdcaf74be3e363a7f3a6fb9dea2..310dec1bc745316f2d476c721786c67ed68ef634 100644 (file)
@@ -189,7 +189,7 @@ static BOOL connect_servers(void)
                        }
 
                        smbcli_oplock_handler(servers[i].cli[j]->transport, oplock_handler, NULL);
-                       smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 1, NULL);
+                       smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 50000, NULL);
                }
        }
 
index c0dab06ccabcab6368a5eb29496aaf41cdeb5aa4..303ffa8fe98e4197f70c341714caaf6675e1352b 100644 (file)
@@ -58,6 +58,7 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
        int ping_count = 0;
        int pong_count = 0;
        BOOL ret = True;
+       struct timeval tv;
 
        if (fork() == 0) {
                struct messaging_context *msg_ctx2 = messaging_init(mem_ctx, 1, ev);
@@ -83,10 +84,10 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
 
        messaging_register(msg_ctx, &pong_count, MY_PONG, pong_message);
 
-       start_timer();
+       tv = timeval_current();
 
        printf("Sending pings for 10 seconds\n");
-       while (end_timer() < 10.0) {
+       while (timeval_elapsed(&tv) < 10.0) {
                DATA_BLOB data;
                NTSTATUS status1, status2;
 
@@ -113,7 +114,7 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
 
        printf("waiting for %d remaining replies (done %d)\n", 
               ping_count - pong_count, pong_count);
-       while (end_timer() < 30 && pong_count < ping_count) {
+       while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
                event_loop_once(ev);
        }
 
@@ -125,7 +126,8 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
                ret = False;
        }
 
-       printf("ping rate of %.0f messages/sec\n", (ping_count+pong_count)/end_timer());
+       printf("ping rate of %.0f messages/sec\n", 
+              (ping_count+pong_count)/timeval_elapsed(&tv));
 
        talloc_free(msg_ctx);
 
index 332312200a217fc791e9e514a15804eb26b6c7bd..348b037753adb200557659ada5a38e5faf3f4366 100644 (file)
 #ifdef _STANDALONE_
 typedef enum {False=0,True=1} BOOL;
 
-static struct timeval tp1,tp2;
-
-static void start_timer(void)
+static struct timeval current_time(void)
 {
-       gettimeofday(&tp1,NULL);
+       struct timeval tv;
+       GetTimeOfDay(&tv);
+       return tv;
 }
 
-static double end_timer(void)
+static double elapsed_time(struct timeval *tv)
 {
-       gettimeofday(&tp2,NULL);
-       return((tp2.tv_sec - tp1.tv_sec) + 
-              (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+       struct timeval tv2 = current_time();
+       return (tv2.tv_sec - tv->tv_sec) + 
+              (tv2.tv_usec - tv->tv_usec)*1.0e-6;
 }
 #endif /* _STANDALONE_ */
 
@@ -642,10 +642,11 @@ static BOOL test_speed(void)
 {
        void *ctx = talloc(NULL, 0);
        unsigned count;
+       struct timeval tv;
 
        printf("MEASURING TALLOC VS MALLOC SPEED\n");
 
-       start_timer();
+       tv = timeval_current();
        count = 0;
        do {
                void *p1, *p2, *p3;
@@ -654,13 +655,13 @@ static BOOL test_speed(void)
                p3 = talloc(p1, 300);
                talloc_free(p1);
                count += 3;
-       } while (end_timer() < 5.0);
+       } while (timeval_elapsed(&tv) < 5.0);
 
-       printf("talloc: %.0f ops/sec\n", count/end_timer());
+       printf("talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
 
        talloc_free(ctx);
 
-       start_timer();
+       tv = timeval_current();
        count = 0;
        do {
                void *p1, *p2, *p3;
@@ -671,9 +672,9 @@ static BOOL test_speed(void)
                free(p2);
                free(p3);
                count += 3;
-       } while (end_timer() < 5.0);
+       } while (timeval_elapsed(&tv) < 5.0);
 
-       printf("malloc: %.0f ops/sec\n", count/end_timer());
+       printf("malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
 
        return True;    
 }
index 0b4bf4bbf1da2f82fdfaa1bd4a8a76f8481e52d5..1c90658f49cf4f27e89438da349f3a4edfed2a28 100644 (file)
@@ -37,6 +37,9 @@ static BOOL run_netbench(struct smbcli_state *cli, int client)
        fstring params[20];
        const char *p;
        BOOL correct = True;
+       struct timeval tv;
+
+       tv = timeval_current();
 
        nb_setup(cli, client, warmup);
 
@@ -52,15 +55,15 @@ static BOOL run_netbench(struct smbcli_state *cli, int client)
 again:
        while (fgets(line, sizeof(line)-1, f)) {
                NTSTATUS status;
-               double t = end_timer();
 
-               if (warmup && t >= warmup) {
+               if (warmup && 
+                   timeval_elapsed(&tv) >= warmup) {
                        warmup = 0;
                        nb_warmup_done();
-                       start_timer();
+                       tv = timeval_current();
                }
 
-               if (end_timer() >= timelimit) {
+               if (timeval_elapsed(&tv) >= timelimit) {
                        goto done;
                }
 
index 98b1c08c976d6c58d7f0b5532537d35360d6f00b..98967f252330e2fd1a31c47b510b58160fc3909b 100644 (file)
@@ -31,6 +31,7 @@ static int nbio_id;
 static int nprocs;
 static BOOL bypass_io;
 static int warmup;
+static struct timeval tv;
 
 struct ftable {
        struct ftable *next, *prev;
@@ -76,7 +77,7 @@ void nb_alarm(int sig)
                if (!children[i].done) num_clients++;
        }
 
-       t = end_timer();
+       t = timeval_elapsed(&tv);
 
        if (warmup) {
                printf("%4d  %8d  %.2f MB/sec  warmup %.0f sec   \n", 
@@ -91,7 +92,7 @@ void nb_alarm(int sig)
        }
 
        if (warmup && t >= warmup) {
-               start_timer();
+               tv = timeval_current();
                warmup = 0;
        }
 
@@ -156,7 +157,7 @@ void nb_setup(struct smbcli_state *cli, int id, int warmupt)
        warmup = warmupt;
        nbio_id = id;
        c = cli;
-       start_timer();
+       tv = timeval_current();
        if (children) {
                children[nbio_id].done = 0;
        }
index c184fb79a7adfe596e07620cdf0eb611240796f7..c02045817e71523bc6947bb059627e599f79321d 100644 (file)
@@ -42,6 +42,8 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        int fnum;
        BOOL ret = True;
        struct smbcli_request *req;
+       struct timeval tv;
+       double d;
 
        printf("testing multiplexed open/open/close\n");
 
@@ -64,14 +66,25 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.fnum;
 
+       tv = timeval_current();
+
        /* send an open that will conflict */
        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
 
+       d = timeval_elapsed(&tv);
+       if (d < 0.5 || d > 1.5) {
+               printf("bad timeout for conflict - %.2f should be 1.0\n", d);
+               ret = False;
+       } else {
+               printf("open delay %.2f\n", d);
+       }
+
        /*
          same request, but async
        */
+       tv = timeval_current();
        req = smb_raw_open_send(cli->tree, &io);
        
        /* and close the file */
@@ -81,6 +94,14 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_open_recv(req, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
 
+       d = timeval_elapsed(&tv);
+       if (d > 0.25) {
+               printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
+               ret = False;
+       } else {
+               printf("async open delay %.2f\n", d);
+       }
+
        smbcli_close(cli->tree, io.ntcreatex.out.fnum);
 
 done:
index 81681bbd743a70ba80a60f959f999d93ff174bd1..c81098490019e66e69aa4cec200651feeebe2a57 100644 (file)
@@ -266,6 +266,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        int fnum = -1, fnum2;
        BOOL ret = True;
        int i;
+       struct timeval tv;
        struct {
                uint16_t open_func;
                BOOL with_file;
@@ -398,13 +399,13 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = io.openx.out.fnum;
 
        io.openx.in.timeout = 20000;
-       start_timer();
+       tv = timeval_current();
        io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_NONE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
-       if (end_timer() > 3) {
-               printf("(%s) Incorrect timing in openx with timeout - waited %d seconds\n",
-                      __location__, (int)end_timer());
+       if (timeval_elapsed(&tv) > 3.0) {
+               printf("(%s) Incorrect timing in openx with timeout - waited %.2f seconds\n",
+                      __location__, timeval_elapsed(&tv));
                ret = False;
        }
        smbcli_close(cli->tree, fnum);
index 656607d93448246c0605500299f1306aaf4566b6..19dc311dd95cf7545c31c352fa86127fa371bc03 100644 (file)
@@ -937,22 +937,19 @@ static BOOL run_deferopen(struct smbcli_state *cli, int dummy)
                int fnum = -1;
 
                do {
-                       struct timeval tv_start, tv_end;
-                       GetTimeOfDay(&tv_start);
+                       struct timeval tv;
+                       tv = timeval_current();
                        fnum = smbcli_nt_create_full(cli->tree, fname, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
                                FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
                                NTCREATEX_DISP_OPEN_IF, 0, 0);
                        if (fnum != -1) {
                                break;
                        }
-                       GetTimeOfDay(&tv_end);
                        if (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION)) {
-                               /* Sharing violation errors need to be 1 second apart. */
-                               int64_t tdif = usec_time_diff(&tv_end, &tv_start);
-                               if (tdif < 500000 || tdif > 1500000) {
-                                       fprintf(stderr,"Timing incorrect %lld.%lld for share violation\n",
-                                               tdif / (int64_t)1000000, 
-                                               tdif % (int64_t)1000000);
+                               double e = timeval_elapsed(&tv);
+                               if (e < 0.5 || e > 1.5) {
+                                       fprintf(stderr,"Timing incorrect %.2f violation\n",
+                                               e);
                                }
                        }
                } while (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION));
@@ -2269,6 +2266,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
        char **unc_list = NULL;
        const char *p;
        int num_unc_names = 0;
+       struct timeval tv;
 
        synccount = 0;
 
@@ -2300,7 +2298,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                child_status_out[i] = True;
        }
 
-       start_timer();
+       tv = timeval_current();
 
        for (i=0;i<torture_nprocs;i++) {
                procnum = i;
@@ -2364,18 +2362,18 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                }
                if (synccount == torture_nprocs) break;
                msleep(100);
-       } while (end_timer() < start_time_limit);
+       } while (timeval_elapsed(&tv) < start_time_limit);
 
        if (synccount != torture_nprocs) {
                printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
                *result = False;
-               return end_timer();
+               return timeval_elapsed(&tv);
        }
 
        printf("Starting %d clients\n", torture_nprocs);
 
        /* start the client load */
-       start_timer();
+       tv = timeval_current();
        for (i=0;i<torture_nprocs;i++) {
                child_status[i] = 0;
        }
@@ -2398,7 +2396,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
                        *result = False;
                }
        }
-       return end_timer();
+       return timeval_elapsed(&tv);
 }
 
 #define FLAG_MULTIPROC 1
@@ -2557,12 +2555,12 @@ static BOOL run_test(const char *name)
                                }
                                         
                        } else {
-                               start_timer();
+                               struct timeval tv = timeval_current();
                                if (!torture_ops[i].fn()) {
                                        ret = False;
                                        printf("TEST %s FAILED!\n", torture_ops[i].name);
                                }
-                               t = end_timer();
+                               t = timeval_elapsed(&tv);
                        }
                        printf("%s took %g secs\n\n", torture_ops[i].name, t);
                }
index 0c0464507d063997892c8a8b1ef9377e9138a306..22aa9ffedd39e7a2ae35a1d06f1a1cf0e076c5df 100644 (file)
 #include "system/time.h"
 
 
-static struct timeval tp1,tp2;
-
-void start_timer(void)
-{
-       gettimeofday(&tp1,NULL);
-}
-
-double end_timer(void)
-{
-       gettimeofday(&tp2,NULL);
-       return((tp2.tv_sec - tp1.tv_sec) + 
-              (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
-}
-
-
 /*
   create a directory, returning a handle to it
 */