Moved FILE_DELETE_ON_CLOSE support to the inode object so that we
really wait for the last close.
Added FILE_SHARE_DELETE support.

diff --git a/server/fd.c b/server/fd.c
index f9491c3..6848a2e 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -53,8 +53,9 @@
 /* closed_fd is used to keep track of the unix fd belonging to a closed fd object */
 struct closed_fd
 {
-    struct closed_fd *next;   /* next fd in close list */
-    int               fd;     /* the unix file descriptor */
+    struct list entry;       /* entry in inode closed list */
+    int         fd;          /* the unix file descriptor */
+    char        unlink[1];   /* name to unlink on close (if any) */
 };
 
 struct fd
@@ -99,7 +100,7 @@
     ino_t               ino;        /* inode number */
     struct list         open;       /* list of open file descriptors */
     struct list         locks;      /* list of file locks */
-    struct closed_fd   *closed;     /* list of file descriptors to close at destroy time */
+    struct list         closed;     /* list of file descriptors to close at destroy time */
 };
 
 static void inode_dump( struct object *obj, int verbose );
@@ -362,12 +363,24 @@
 /* close all pending file descriptors in the closed list */
 static void inode_close_pending( struct inode *inode )
 {
-    while (inode->closed)
+    struct list *ptr = list_head( &inode->closed );
+
+    while (ptr)
     {
-        struct closed_fd *fd = inode->closed;
-        inode->closed = fd->next;
-        close( fd->fd );
-        free( fd );
+        struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
+        struct list *next = list_next( &inode->closed, ptr );
+
+        if (fd->fd != -1)
+        {
+            close( fd->fd );
+            fd->fd = -1;
+        }
+        if (!fd->unlink)  /* get rid of it unless there's an unlink pending on that file */
+        {
+            list_remove( ptr );
+            free( fd );
+        }
+        ptr = next;
     }
 }
 
@@ -385,12 +398,27 @@
 static void inode_destroy( struct object *obj )
 {
     struct inode *inode = (struct inode *)obj;
+    struct list *ptr;
 
     assert( list_empty(&inode->open) );
     assert( list_empty(&inode->locks) );
 
     list_remove( &inode->entry );
-    inode_close_pending( inode );
+
+    while ((ptr = list_head( &inode->closed )))
+    {
+        struct closed_fd *fd = LIST_ENTRY( ptr, struct closed_fd, entry );
+        list_remove( ptr );
+        if (fd->fd != -1) close( fd->fd );
+        if (fd->unlink[0])
+        {
+            /* make sure it is still the same file */
+            struct stat st;
+            if (!stat( fd->unlink, &st ) && st.st_dev == inode->dev && st.st_ino == inode->ino)
+                unlink( fd->unlink );
+        }
+        free( fd );
+    }
 }
 
 /* retrieve the inode object for a given fd, creating it if needed */
@@ -417,9 +445,9 @@
         inode->hash   = hash;
         inode->dev    = dev;
         inode->ino    = ino;
-        inode->closed = NULL;
         list_init( &inode->open );
         list_init( &inode->locks );
+        list_init( &inode->closed );
         list_add_head( &inode_hash[hash], &inode->entry );
     }
     return inode;
@@ -430,10 +458,15 @@
 {
     if (!list_empty( &inode->locks ))
     {
-        fd->next = inode->closed;
-        inode->closed = fd;
+        list_add_head( &inode->closed, &fd->entry );
     }
-    else  /* no locks on this inode, we can close the fd right away */
+    else if (fd->unlink[0])  /* close the fd but keep the structure around for unlink */
+    {
+        close( fd->fd );
+        fd->fd = -1;
+        list_add_head( &inode->closed, &fd->entry );
+    }
+    else  /* no locks on this inode and no unlink, get rid of the fd */
     {
         close( fd->fd );
         free( fd );
@@ -769,7 +802,8 @@
 static void fd_dump( struct object *obj, int verbose )
 {
     struct fd *fd = (struct fd *)obj;
-    fprintf( stderr, "Fd unix_fd=%d user=%p\n", fd->unix_fd, fd->user );
+    fprintf( stderr, "Fd unix_fd=%d user=%p unlink='%s'\n",
+             fd->unix_fd, fd->user, fd->closed->unlink );
 }
 
 static void fd_destroy( struct object *obj )
@@ -839,12 +873,13 @@
 /* the sharing mode of other opens of the same file */
 static int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing )
 {
-    unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
+    unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
     unsigned int existing_access = 0;
+    int unlink = 0;
     struct list *ptr;
 
     /* if access mode is 0, sharing mode is ignored */
-    if (!access) sharing = FILE_SHARE_READ|FILE_SHARE_WRITE;
+    if (!access) sharing = existing_sharing;
     fd->access = access;
     fd->sharing = sharing;
 
@@ -855,6 +890,7 @@
         {
             existing_sharing &= fd_ptr->sharing;
             existing_access  |= fd_ptr->access;
+            if (fd_ptr->closed->unlink[0]) unlink = 1;
         }
     }
 
@@ -862,6 +898,8 @@
     if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
     if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) return 0;
     if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
+    if (fd->closed->unlink[0] && !(existing_sharing & FILE_SHARE_DELETE)) return 0;
+    if (unlink && !(sharing & FILE_SHARE_DELETE)) return 0;
     return 1;
 }
 
@@ -869,14 +907,14 @@
 /* the fd must have been created with alloc_fd */
 /* on error the fd object is released */
 struct fd *open_fd( struct fd *fd, const char *name, int flags, mode_t *mode,
-                    unsigned int access, unsigned int sharing )
+                    unsigned int access, unsigned int sharing, const char *unlink_name )
 {
     struct stat st;
     struct closed_fd *closed_fd;
 
     assert( fd->unix_fd == -1 );
 
-    if (!(closed_fd = mem_alloc( sizeof(*closed_fd) )))
+    if (!(closed_fd = mem_alloc( sizeof(*closed_fd) + strlen(unlink_name) )))
     {
         release_object( fd );
         return NULL;
@@ -889,6 +927,7 @@
         return NULL;
     }
     closed_fd->fd = fd->unix_fd;
+    closed_fd->unlink[0] = 0;
     fstat( fd->unix_fd, &st );
     *mode = st.st_mode;
 
@@ -914,10 +953,17 @@
             set_error( STATUS_SHARING_VIOLATION );
             return NULL;
         }
+        strcpy( closed_fd->unlink, unlink_name );
     }
     else
     {
         free( closed_fd );
+        if (unlink_name[0])  /* we can't unlink special files */
+        {
+            release_object( fd );
+            set_error( STATUS_INVALID_PARAMETER );
+            return NULL;
+        }
     }
     return fd;
 }