2004-05-21 Dick Porter <dick@ximian.com>
authorDick Porter <dick@acm.org>
Fri, 21 May 2004 19:46:43 +0000 (19:46 -0000)
committerDick Porter <dick@acm.org>
Fri, 21 May 2004 19:46:43 +0000 (19:46 -0000)
* io.c (CreateFile): Check for existing share modes when opening
a file.

* handles.c:
* handles-private.h:
* daemon-messages.h:
* daemon.c: Maintain a hash of file share modes, keying on device
and inode (to cope with symlinks.)

svn path=/trunk/mono/; revision=27850

mono/io-layer/ChangeLog
mono/io-layer/daemon-messages.h
mono/io-layer/daemon.c
mono/io-layer/handles-private.h
mono/io-layer/handles.c
mono/io-layer/io-private.h
mono/io-layer/io.c

index 2b87f5f4a93f1337f44dafb0794302a5a104b61a..9e069d7ba7a7ec0c11dad607ecbdafadb5f6f44f 100644 (file)
@@ -1,3 +1,14 @@
+2004-05-21  Dick Porter  <dick@ximian.com>
+
+       * io.c (CreateFile): Check for existing share modes when opening
+       a file.
+
+       * handles.c: 
+       * handles-private.h: 
+       * daemon-messages.h: 
+       * daemon.c: Maintain a hash of file share modes, keying on device
+       and inode (to cope with symlinks.)
+
 2004-05-20  Lluis Sanchez Gual  <lluis@ximian.com>
 
        * daemon-messages.c: Retry if the communication with the daemon is
index 1b21f08c57d1a3831b1ac25620816f8cc32944ca..237e951b5e6abf9561d82a99e64eec4cf3090abf 100644 (file)
@@ -20,7 +20,9 @@ typedef enum {
        WapiHandleRequestType_Scratch,
        WapiHandleRequestType_ScratchFree,
        WapiHandleRequestType_ProcessFork,
-       WapiHandleRequestType_ProcessKill
+       WapiHandleRequestType_ProcessKill,
+       WapiHandleRequestType_GetOrSetShare,
+       WapiHandleRequestType_SetShare
 } WapiHandleRequestType;
 
 typedef struct 
@@ -65,6 +67,22 @@ typedef struct {
        gint32 signo;
 } WapiHandleRequest_ProcessKill;
 
+typedef struct 
+{
+       dev_t device;
+       ino_t inode;
+       guint32 new_sharemode;
+       guint32 new_access;
+} WapiHandleRequest_GetOrSetShare;
+
+typedef struct
+{
+       dev_t device;
+       ino_t inode;
+       guint32 sharemode;
+       guint32 access;
+} WapiHandleRequest_SetShare;
+
 typedef struct 
 {
        WapiHandleRequestType type;
@@ -77,6 +95,8 @@ typedef struct
                WapiHandleRequest_ScratchFree scratch_free;
                WapiHandleRequest_ProcessFork process_fork;
                WapiHandleRequest_ProcessKill process_kill;
+               WapiHandleRequest_GetOrSetShare get_or_set_share;
+               WapiHandleRequest_SetShare set_share;
        } u;
 } WapiHandleRequest;
 
@@ -88,7 +108,9 @@ typedef enum {
        WapiHandleResponseType_Scratch,
        WapiHandleResponseType_ScratchFree,
        WapiHandleResponseType_ProcessFork,
-       WapiHandleResponseType_ProcessKill
+       WapiHandleResponseType_ProcessKill,
+       WapiHandleResponseType_GetOrSetShare,
+       WapiHandleResponseType_SetShare
 } WapiHandleResponseType;
 
 typedef struct 
@@ -137,6 +159,18 @@ typedef struct
        guint32 err;
 } WapiHandleResponse_ProcessKill;
 
+typedef struct
+{
+       gboolean exists;
+       guint32 sharemode;
+       guint32 access;
+} WapiHandleResponse_GetOrSetShare;
+
+typedef struct
+{
+       guint32 dummy;
+} WapiHandleResponse_SetShare;
+
 typedef struct
 {
        WapiHandleResponseType type;
@@ -150,6 +184,8 @@ typedef struct
                WapiHandleResponse_ScratchFree scratch_free;
                WapiHandleResponse_ProcessFork process_fork;
                WapiHandleResponse_ProcessKill process_kill;
+               WapiHandleResponse_GetOrSetShare get_or_set_share;
+               WapiHandleResponse_SetShare set_share;
        } u;
 } WapiHandleResponse;
 
index 01fb5da616d789287b0b621506cc4257c30e496e..746fba49d177511d45afdceaec565001489b8a43 100644 (file)
@@ -62,9 +62,24 @@ static int main_sock;
 /* Set to TRUE by the SIGCHLD signal handler */
 static volatile gboolean check_processes=FALSE;
 
+/* The file_share_hash is used to emulate the windows file sharing mode */
+typedef struct _share_key
+{
+       dev_t device;
+       ino_t inode;
+} ShareKey;
+
+typedef struct _share_data
+{
+       guint32 sharemode;
+       guint32 access;
+} ShareData;
+
+static GHashTable *file_share_hash = NULL;
+
 static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
                             gpointer data);
-
+static void check_sharing (dev_t device, ino_t inode);
 
 /* Deletes the shared memory segment.  If we're exiting on error,
  * clients will get EPIPEs.
@@ -194,10 +209,27 @@ static void sigchld_handler (int unused)
        check_processes=TRUE;
 }
 
+static guint sharedata_hash (gconstpointer key)
+{
+       ShareKey *sharekey = (ShareKey *)key;
+       
+       return(g_int_hash (&(sharekey->inode)));
+}
+
+static gboolean sharedata_equal (gconstpointer a, gconstpointer b)
+{
+       ShareKey *share_a = (ShareKey *)a;
+       ShareKey *share_b = (ShareKey *)b;
+       
+       return(share_a->device == share_b->device &&
+              share_a->inode == share_b->inode);
+}
+
 /*
  * startup:
  *
- * Bind signals and attach to shared memory
+ * Bind signals, attach to shared memory and set up any internal data
+ * structures needed.
  */
 static void startup (void)
 {
@@ -235,6 +267,10 @@ static void startup (void)
                  "mono-handle-daemon-%d-%d-%ld", getuid (), getpid (),
                  time (NULL));
 #endif
+
+       file_share_hash = g_hash_table_new_full (sharedata_hash,
+                                                sharedata_equal, g_free,
+                                                g_free);
 }
 
 
@@ -310,6 +346,10 @@ static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
        }
        
        if(_wapi_shared_data[segment]->handles[idx].ref==0) {
+               gboolean was_file;
+               dev_t device = 0;
+               ino_t inode = 0;
+               
                if (channel_data->open_handles[handle]!=0) {
                        g_warning (G_GNUC_PRETTY_FUNCTION ": per-process open_handles mismatch, set to %d, should be 0", 
                                        channel_data->open_handles[handle]);
@@ -319,6 +359,30 @@ static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
                g_message (G_GNUC_PRETTY_FUNCTION ": Destroying handle 0x%x",
                           handle);
 #endif
+
+               /* if this was a file handle, save the device and
+                * inode numbers so we can scan the share info data
+                * later to see if the last handle to a file has been
+                * closed, and delete the data if so.
+                */
+               was_file = (_wapi_shared_data[segment]->handles[idx].type == WAPI_HANDLE_FILE);
+               if (was_file) {
+                       struct _WapiHandle_file *file_handle;
+                       gboolean ok;
+                       
+                       ok = _wapi_lookup_handle (GUINT_TO_POINTER (handle),
+                                                 WAPI_HANDLE_FILE,
+                                                 (gpointer *)&file_handle,
+                                                 NULL);
+                       if (ok == FALSE) {
+                               g_warning (G_GNUC_PRETTY_FUNCTION
+                                          ": error looking up file handle %x",
+                                          handle);
+                       } else {
+                               device = file_handle->device;
+                               inode = file_handle->inode;
+                       }
+               }
                
                _wapi_handle_ops_close_shared (GUINT_TO_POINTER (handle));
                
@@ -329,6 +393,10 @@ static gboolean unref_handle (ChannelData *channel_data, guint32 handle)
 
                memset (&_wapi_shared_data[segment]->handles[idx].u, '\0', sizeof(_wapi_shared_data[segment]->handles[idx].u));
                _wapi_shared_data[segment]->handles[idx].type=WAPI_HANDLE_UNUSED;
+
+               if (was_file) {
+                       check_sharing (device, inode);
+               }
        }
 
        if(channel_data == daemon_channel_data) {
@@ -466,6 +534,104 @@ static void rem_fd(GIOChannel *channel, ChannelData *channel_data)
        }
 }
 
+static void sharemode_set (dev_t device, ino_t inode, guint32 sharemode,
+                          guint32 access)
+{
+       ShareKey *sharekey;
+       ShareData *sharedata;
+       
+       sharekey = g_new (ShareKey, 1);
+       sharekey->device = device;
+       sharekey->inode = inode;
+
+       sharedata = g_new (ShareData, 1);
+       sharedata->sharemode = sharemode;
+       sharedata->access = access;
+       
+       /* Setting share mode to include all access bits is really
+        * removing the share info
+        */
+       if (sharemode == (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)) {
+               g_hash_table_remove (file_share_hash, sharekey);
+       } else {
+               g_hash_table_insert (file_share_hash, sharekey, sharedata);
+       }
+}
+
+static gboolean sharemode_get (dev_t device, ino_t inode, guint32 *sharemode,
+                              guint32 *access)
+{
+       ShareKey sharekey;
+       ShareData *sharedata;
+       
+       sharekey.device = device;
+       sharekey.inode = inode;
+       
+       sharedata = (ShareData *)g_hash_table_lookup (file_share_hash,
+                                                      &sharekey);
+       if (sharedata == NULL) {
+               return(FALSE);
+       }
+       
+       *sharemode = sharedata->sharemode;
+       *access = sharedata->access;
+       
+       return(TRUE);
+}
+
+static gboolean share_compare (gpointer handle, gpointer user_data)
+{
+       struct _WapiHandle_file *file_handle;
+       gboolean ok;
+       ShareKey *sharekey = (ShareKey *)user_data;
+       
+       ok = _wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
+                                 (gpointer *)&file_handle, NULL);
+       if (ok == FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up file handle %p", handle);
+               return(FALSE);
+       }
+       
+       if (file_handle->device == sharekey->device &&
+           file_handle->inode == sharekey->inode) {
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION ": found one, handle %p",
+                          handle);
+#endif
+               return(TRUE);
+       } else {
+               return(FALSE);
+       }
+}
+
+static void check_sharing (dev_t device, ino_t inode)
+{
+       ShareKey sharekey;
+       gpointer file_handle;
+       
+#ifdef DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": Checking if anything has (dev 0x%llx, inode %lld) still open", device, inode);
+#endif
+
+       sharekey.device = device;
+       sharekey.inode = inode;
+       
+       file_handle = _wapi_search_handle (WAPI_HANDLE_FILE, share_compare,
+                                          &sharekey, NULL, NULL);
+
+       if (file_handle == NULL) {
+               /* Delete this share info, as the last handle to it
+                * has been closed
+                */
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION ": Deleting share data for (dev 0x%llx inode %lld)", device, inode);
+#endif
+               
+               g_hash_table_remove (file_share_hash, &sharekey);
+       }
+}
+
 static gboolean process_compare (gpointer handle, gpointer user_data)
 {
        struct _WapiHandle_process *process_handle;
@@ -1089,6 +1255,73 @@ static void process_process_fork (GIOChannel *channel, ChannelData *channel_data
        send_reply (channel, &resp);
 }
 
+/*
+ * process_set_share:
+ * @channel: The client making the request
+ * @channel_data: The channel data
+ * @set_share: Set share data passed from the client
+ *
+ * Sets file share info
+ */
+static void process_set_share (GIOChannel *channel, ChannelData *channel_data,
+                              WapiHandleRequest_SetShare set_share)
+{
+       WapiHandleResponse resp = {0};
+
+       resp.type = WapiHandleResponseType_SetShare;
+       
+#ifdef DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": Setting share for file (dev:0x%llx, ino:%lld) mode 0x%x access 0x%x", set_share.device, set_share.inode, set_share.sharemode, set_share.access);
+#endif
+       
+       sharemode_set (set_share.device, set_share.inode, set_share.sharemode,
+                      set_share.access);
+       
+       send_reply (channel, &resp);
+}
+
+/*
+ * process_get_or_set_share:
+ * @channel: The client making the request
+ * @channel_data: The channel data
+ * @get_share: GetOrSetShare data passed from the client
+ *
+ * Gets a file share status, and sets the status if it doesn't already
+ * exist
+ */
+static void process_get_or_set_share (GIOChannel *channel,
+                                     ChannelData *channel_data,
+                                     WapiHandleRequest_GetOrSetShare get_share)
+{
+       WapiHandleResponse resp = {0};
+       
+       resp.type = WapiHandleResponseType_GetOrSetShare;
+       
+#ifdef DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION
+                  ": Getting share status for file (dev:0x%llx, ino:%lld)",
+                  get_share.device, get_share.inode);
+#endif
+
+       resp.u.get_or_set_share.exists = sharemode_get (get_share.device, get_share.inode, &resp.u.get_or_set_share.sharemode, &resp.u.get_or_set_share.access);
+       
+       if (resp.u.get_or_set_share.exists) {
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION ": Share mode: 0x%x",
+                          resp.u.get_or_set_share.sharemode);
+#endif
+       } else {
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION
+                          ": file share info not already known, setting");
+#endif
+               sharemode_set (get_share.device, get_share.inode,
+                              get_share.new_sharemode, get_share.new_access);
+       }
+       
+       send_reply (channel, &resp);
+}
+
 /*
  * read_message:
  * @channel: The client to read the request from
@@ -1150,6 +1383,13 @@ static gboolean read_message (GIOChannel *channel, ChannelData *channel_data)
        case WapiHandleRequestType_ProcessKill:
                process_process_kill (channel, req.u.process_kill);
                break;
+       case WapiHandleRequestType_SetShare:
+               process_set_share (channel, channel_data, req.u.set_share);
+               break;
+       case WapiHandleRequestType_GetOrSetShare:
+               process_get_or_set_share (channel, channel_data,
+                                         req.u.get_or_set_share);
+               break;
        case WapiHandleRequestType_Error:
                /* fall through */
        default:
index 4a6870335ef9d245528ff28b37d3f987b43a6628..674e01384b9636f531a4a6083ed7a8a41cf960c5 100644 (file)
@@ -85,6 +85,13 @@ extern gboolean _wapi_handle_process_fork (guint32 cmd, guint32 env,
 
 extern gboolean _wapi_handle_process_kill (pid_t pid, guint32 signo,
                                           gint *err);
+extern gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
+                                              guint32 new_sharemode,
+                                              guint32 new_access,
+                                              guint32 *old_sharemode,
+                                              guint32 *old_access);
+extern void _wapi_handle_set_share (dev_t device, ino_t inode,
+                                   guint32 sharemode, guint32 access);
 
 static inline struct _WapiHandleShared_list *_wapi_handle_get_shared_segment (guint32 segment)
 {
index c61f541445178c976721bed362a7ddc316bfacd7..769235fe76d89584bcd65bc2fac0881b1a63f1fa 100644 (file)
@@ -1656,3 +1656,66 @@ _wapi_handle_process_kill (pid_t process, guint32 signo, gint *errnum)
        return (result == 0);
 }
 
+gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
+                                       guint32 new_sharemode,
+                                       guint32 new_access,
+                                       guint32 *old_sharemode,
+                                       guint32 *old_access)
+{
+       WapiHandleRequest req = {0};
+       WapiHandleResponse resp = {0};
+       
+       if(shared != TRUE) {
+               /* No daemon means we don't know if a file is sharable.
+                * We're running in our own little world if this is
+                * the case, so there's no point in pretending that
+                * the file isn't sharable.
+                */
+               return(FALSE);
+       }
+       
+       req.type = WapiHandleRequestType_GetOrSetShare;
+       req.u.get_or_set_share.device = device;
+       req.u.get_or_set_share.inode = inode;
+       req.u.get_or_set_share.new_sharemode = new_sharemode;
+       req.u.get_or_set_share.new_access = new_access;
+       
+       _wapi_daemon_request_response (daemon_sock, &req, &resp);
+       if (resp.type != WapiHandleResponseType_GetOrSetShare) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": bogus daemon response, type %d", resp.type);
+               g_assert_not_reached ();
+       }
+       
+       *old_sharemode = resp.u.get_or_set_share.sharemode;
+       *old_access = resp.u.get_or_set_share.access;
+
+       return(resp.u.get_or_set_share.exists);
+}
+
+void _wapi_handle_set_share (dev_t device, ino_t inode, guint32 sharemode,
+                            guint32 access)
+{
+       WapiHandleRequest req = {0};
+       WapiHandleResponse resp = {0};
+       
+       if(shared != TRUE) {
+               /* No daemon, so there's no one else to tell about
+                * file sharing.
+                */
+               return;
+       }
+
+       req.type = WapiHandleRequestType_SetShare;
+       req.u.set_share.device = device;
+       req.u.set_share.inode = inode;
+       req.u.set_share.sharemode = sharemode;
+       req.u.set_share.access = access;
+       
+       _wapi_daemon_request_response (daemon_sock, &req, &resp);
+       if (resp.type != WapiHandleResponseType_SetShare) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": bogus daemon response, type %d", resp.type);
+               g_assert_not_reached ();
+       }
+}
index b4dbbd39901edc797673ccad708da1f186bead3b..374be0599565412f1d527bfaf0c3c4429757803e 100644 (file)
@@ -30,6 +30,8 @@ struct _WapiHandle_file
        guint32 fileaccess;
        guint32 sharemode;
        guint32 attrs;
+       dev_t device;
+       ino_t inode;
 };
 
 /* The boolean is for distinguishing between a zeroed struct being not
index f4f93f1fd09060a326f50c0c8d7df41695251483..982a60938e6d339aebd5711acb0fcdccb54b9ea1 100644 (file)
@@ -37,6 +37,7 @@
 #include <mono/io-layer/handles-private.h>
 #include <mono/io-layer/io-private.h>
 #include <mono/io-layer/timefuncs-private.h>
+#include <mono/io-layer/thread-private.h>
 #include <mono/utils/strenc.h>
 
 #undef DEBUG
@@ -1494,12 +1495,15 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        int flags=convert_flags(fileaccess, createmode);
        mode_t perms=convert_perms(sharemode);
        gchar *filename;
-       int ret;
+       int fd, ret;
        int thr_ret;
        gpointer cf_ret = INVALID_HANDLE_VALUE;
+       struct stat statbuf;
+       gboolean file_already_shared;
+       guint32 file_existing_share, file_existing_access;
        
        mono_once (&io_ops_once, io_ops_init);
-       
+
        if(name==NULL) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION ": name is NULL");
@@ -1518,7 +1522,11 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
                return(INVALID_HANDLE_VALUE);
        }
        
-       ret=open(filename, flags, perms);
+#ifdef DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": Opening %s with share 0x%x and access 0x%x", filename, sharemode, fileaccess);
+#endif
+       
+       fd = open(filename, flags, perms);
     
        /* If we were trying to open a directory with write permissions
         * (e.g. O_WRONLY or O_RDWR), this call will fail with
@@ -1528,13 +1536,13 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
         * (e.g. utime()). Hence, if we failed with the EISDIR error, try
         * to open the directory again without write permission.
         */
-       if (ret == -1 && errno == EISDIR)
+       if (fd == -1 && errno == EISDIR)
        {
                /* Try again but don't try to make it writable */
-               ret=open(filename, flags  & ~(O_RDWR|O_WRONLY), perms);
+               fd = open(filename, flags  & ~(O_RDWR|O_WRONLY), perms);
        }
        
-       if(ret==-1) {
+       if (fd == -1) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION ": Error opening file %s: %s",
                          filename, strerror(errno));
@@ -1545,12 +1553,75 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
                return(INVALID_HANDLE_VALUE);
        }
 
+       ret = fstat (fd, &statbuf);
+       if (ret == -1) {
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION ": fstat error of file %s: %s", filename, strerror (errno));
+#endif
+               _wapi_set_last_error_from_errno ();
+               g_free (filename);
+               close (fd);
+               
+               return(INVALID_HANDLE_VALUE);
+       }
+
+       file_already_shared = _wapi_handle_get_or_set_share (statbuf.st_dev, statbuf.st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access);
+       
+       if (file_already_shared) {
+               if (file_existing_share == 0) {
+                       /* Quick and easy, no possibility to share */
+#ifdef DEBUG
+                       g_message (G_GNUC_PRETTY_FUNCTION ": Share mode prevents open: requested access: 0x%x, file has sharing = NONE", fileaccess);
+#endif
+                       SetLastError (ERROR_SHARING_VIOLATION);
+                       g_free (filename);
+                       close (fd);
+               
+                       return(INVALID_HANDLE_VALUE);
+               }
+
+               if (((file_existing_share == FILE_SHARE_READ) &&
+                    (fileaccess != GENERIC_READ)) ||
+                   ((file_existing_share == FILE_SHARE_WRITE) &&
+                    (fileaccess != GENERIC_WRITE))) {
+                       /* New access mode doesn't match up */
+#ifdef DEBUG
+                       g_message (G_GNUC_PRETTY_FUNCTION ": Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", fileaccess, file_existing_share);
+#endif
+                       SetLastError (ERROR_SHARING_VIOLATION);
+                       g_free (filename);
+                       close (fd);
+               
+                       return(INVALID_HANDLE_VALUE);
+               }
+
+               if (((file_existing_access & GENERIC_READ) &&
+                    !(sharemode & FILE_SHARE_READ)) ||
+                   ((file_existing_access & GENERIC_WRITE) &&
+                    !(sharemode & FILE_SHARE_WRITE))) {
+                       /* New share mode doesn't match up */
+#ifdef DEBUG
+                       g_message (G_GNUC_PRETTY_FUNCTION ": Access mode prevents open: requested share: 0x%x, file has access: 0x%x", sharemode, file_existing_access);
+#endif
+                       SetLastError (ERROR_SHARING_VIOLATION);
+                       g_free (filename);
+                       close (fd);
+               
+                       return(INVALID_HANDLE_VALUE);
+               }
+       } else {
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION ": New file!");
+#endif
+       }
+       
        handle=_wapi_handle_new (WAPI_HANDLE_FILE);
        if(handle==_WAPI_HANDLE_INVALID) {
                g_warning (G_GNUC_PRETTY_FUNCTION
                           ": error creating file handle");
                g_free (filename);
-
+               close (fd);
+               
                return(INVALID_HANDLE_VALUE);
        }
 
@@ -1565,11 +1636,12 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        if(ok==FALSE) {
                g_warning (G_GNUC_PRETTY_FUNCTION
                           ": error looking up file handle %p", handle);
+               close (fd);
                goto cleanup;
        }
        cf_ret = handle;
 
-       file_private_handle->fd=ret;
+       file_private_handle->fd=fd;
        file_private_handle->assigned=TRUE;
        file_private_handle->async = ((attrs & FILE_FLAG_OVERLAPPED) != 0);
        file_handle->filename=_wapi_handle_scratch_store (filename,
@@ -1582,6 +1654,8 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        file_handle->fileaccess=fileaccess;
        file_handle->sharemode=sharemode;
        file_handle->attrs=attrs;
+       file_handle->device = statbuf.st_dev;
+       file_handle->inode = statbuf.st_ino;
        
 #ifdef DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION
@@ -1873,7 +1947,7 @@ static gpointer stdhandle_create (int fd, const guchar *name)
        do {
                flags=fcntl(fd, F_GETFL);
        }
-       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+       while (flags==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
 
        if(flags==-1) {
                /* Invalid fd.  Not really much point checking for EBADF