gio on win32 (was Re: Announce: gio merged)



On 03.12.2007 10:07, Alexander Larsson wrote:
> On Fri, 2007-11-30 at 15:01 +0100, Hans Breuer wrote: 
[...]

>>>> g_io_modules_ensure_loaded (GIO_MODULE_DIR);
>>>> It would be nice if this function would take no parameter to allow
>>>> implementation of dynamic DLL placement resolvement in one place.
>>> Hmm. This is also used by gvfs to load its modules. It then passes a
>>> different location to the function ($(libdir)/gvfs/modules). Can you
>>> describe in more detail what you want it to do?
>>>
>> On windows the location of DLLs is deduce at runtime. It depends on where a
>> setup installed the DLLs, rather than fixed at compiled time.
>> Thus we have established a pattern to resolve module placement from the DLL
>> loading them. See for example gtk/gtkmodules.c.
>> My first idea was taht the parameter to g_io_modules_ensure_loaded() was
>> always the same. Thus it would have been possible to do the dynamic path
>> calcualtion in just this one function. Of course GIO_MODULE_DIR can be
>> defined to a function call on win32, to keep the other code like it is.
>> _gio_win32_module_dir() will have to return a static string than.
> 
> Thats a way it can be made to work with the current use in libgio, but
> it makes the API sort of weird for win32. How exactly is the dynamic
> path calculated? Maybe its possible to make the API work in some
> relative way? That way some other library on could also use
> g_io_modules_ensure_loaded() to load its modules relative to its dll.
> 
The thing needed than would be the DLL name or the HANDLE of the DLL to
resolve the relative path against. I'm not sure though how the
responsibilities need to be split for loading some gio-modules.
Is an application supposed to deliver it's own extension modules for gio?

>>>> glocalfile.c needs some more porting to GLib APIs, e.g. g_file_test
>>> g_file_test is pretty lame though. It does a new stat each time you call it and there are no ways to get more than a single piece of info for each call. This will just slaughter i/o performance. 
>>>
>>> What exactly is it that you need it to do that g_file_test does? We need to move that into glocalfile.c instead.
>>>
>> The first thing is the undefined statfs_buffer for !USE_STATFS and
>> !USE_STATVFS in g_local_file_query_filesystem_info. I need to understand
>> the unknown API first to propose how to port it.
>> On a quick glance the missing definition for S_ISDIR led me to propose
>> g_file_test(). But of course this can be resolved differntly.
> 
> Maybe we should have a full alternative implementation of
> g_local_file_query_info() using GetFileAttributes and similar calls. 
> 
I've started something of this, but not commited yet. (I'm getting too old
for all these ifdefs ;)) See attahed patch.

> I think we can make the posix version mostly work for win32, but a
> native implementation can get more information, like fat attributes
> (hidden, archive, system) and NT ACLs.
> 
> I think the interesting parts for a native win32 implementation is (for
> local files, i.e. in glocalfile.c):
> 
> g_file_query_info() - This returns information about a file, like size,
> type, icon, last changed, etc. The return type is a GFileInfo which is a
> key-value container where the keys are namespaced strings like
> "std:type" or "unix:uid". 
> 
This sounds like the application again must be unix/win32 specific. Or who
is supposed to interpret the unix:uid key? Could some of this be abstracted
away?

> g_file_query_filesystem_info() - Similar to the above, but gets
> information about the filesystem the file is on. i.e. total diskspace,
> diskspace left, type of filesystem.
> 
Again I alread started a win32 specific implementation, not commited yet
but attached for review.

> g_file_enumerate_children() - This is readdir() + stat of each file
> combined into one. I think Win32 has a better fit to this, where
> FindNextFile actually returns stat info. On posix you need to make a
> separate stat call for each filename readdir() returns. So, a native
> win32 implementation of GFileEnumerator would be more efficient.
> 
> None of this is strictly necessary of course, so it all depends on how
> much time the win32 developers want to spend on it.
> 
At the moment I'm concentrating on getting gio to work at all. At some
points there still is working implmentation missing. My current unresolved
externals (i.e. some of the stuff that compiles still requires functions
not compiled) :

glocalfile.obj : error LNK2001: unresolved external symbol _g_unix_mount_free
glocalfile.obj : error LNK2001: unresolved external symbol
_g_unix_mount_is_readonly
glocalfile.obj : error LNK2001: unresolved external symbol _g_get_unix_mount_at
glocalfile.obj : error LNK2001: unresolved external symbol
_g_unix_mounts_changed_since
glocalfile.obj : error LNK2001: unresolved external symbol _localtime_r
glocalfile.obj : error LNK2001: unresolved external symbol
__g_local_directory_monitor_new
glocalfileinfo.obj : error LNK2001: unresolved external symbol
_get_groupname_from_gid
glocalfileinfo.obj : error LNK2001: unresolved external symbol
_get_realname_from_uid
glocalfileinfo.obj : error LNK2001: unresolved external symbol
_get_username_from_uid

>>>> Finally gio.symbols should be added to make exporting of symbols (and what
>>>> not;) as easy as for glib/gobject and gtk+
>>> It also needs to set up the aliases work for unix... I'll take a look at it.
>>>
>>>> Do you want me to commit the uncritical pieces?
>>> Everything but the gcontenttype.c part (that should not build on win32)
>>> looks good to me.
>>>
>> Ok, revert that thing and just moved the #include <dirent.h> stuff into the
>> !G_OS_WIN32 #else.
> 
> Did you commit your stuff? 
> 
Only things not too questionable. To give you an impression f the currently
needed changes an updated patch is attached.

>> In the first chunck I was also completely missing the gwin32appinfo.c
>> thing. Now it is giving me a hard time by using somewhat unusual API - not
>> available in my current Platform SDK installation. There are people
>> claiming shlwapi.h to be "one of the worst designed libraries to come out
>> of the Windows team"
>> [http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=203814&SiteID=1]
>> So at least now I know why it was not installed on my computer :-)
> 
> Hmm. When I wrote the stuff I was just using MinGW. It had most of this
> stuff, but lacked some and actually had some values wrong. Thats why
> there are defines like ASSOCF_INIT_BYEXENAME and REAL_ASSOCSTR_COMMAND
> at the top of the file.
> 
AssocQueryStringW is not available with the original SDK delivered with
msvc6. With more recent SDKs it seems to be part of some "Internet Explorer
SDK". I'll try to look into replacing with some less critical API.


-------- Hans "at" Breuer "dot" Org -----------
Tell me what you need, and I'll tell you how to
get along without it.                -- Dilbert
Index: glocalfile.c
===================================================================
--- glocalfile.c	(revision 6027)
+++ glocalfile.c	(working copy)
@@ -27,7 +27,9 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
 #if HAVE_SYS_STATFS_H
 #include <sys/statfs.h>
@@ -77,6 +79,19 @@
 #include <glib/gstdio.h>
 #include "glibintl.h"
 
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <io.h>
+#include <direct.h>
+
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#endif
+#ifndef S_ISLNK
+#define S_ISLNK(m) (0)
+#endif
+#endif
+
 #include "gioalias.h"
 
 static void g_local_file_file_iface_init (GFileIface       *iface);
@@ -683,7 +698,7 @@
   GUnixMount *mount;
   guint64 cache_time;
 
-  if (lstat (path, &buf) != 0)
+  if (g_lstat (path, &buf) != 0)
     return;
 
   G_LOCK (mount_info_hash);
@@ -797,11 +812,36 @@
   
   if (g_file_attribute_matcher_matches (attribute_matcher,
 					G_FILE_ATTRIBUTE_FS_FREE))
-    g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_FREE, block_size * statfs_buffer.f_bavail);
+    {
+#ifdef G_OS_WIN32
+      gchar *localdir = g_path_get_dirname (local->filename);
+      wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL);
+      ULARGE_INTEGER li;
+      
+      g_free (localdir);
+      if (GetDiskFreeSpaceExW (wdirname, &li, NULL, NULL))
+        g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_FREE, (guint64)li.QuadPart);
+      g_free (wdirname);
+#else
+      g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_FREE, block_size * statfs_buffer.f_bavail);
+#endif
+    }
   if (g_file_attribute_matcher_matches (attribute_matcher,
 					G_FILE_ATTRIBUTE_FS_SIZE))
-    g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_SIZE, block_size * statfs_buffer.f_blocks);
-
+    {
+#ifdef G_OS_WIN32
+      gchar *localdir = g_path_get_dirname (local->filename);
+      wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL);
+      ULARGE_INTEGER li;
+      
+      g_free (localdir);
+      if (GetDiskFreeSpaceExW (wdirname, NULL, &li, NULL))
+        g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_SIZE,  (guint64)li.QuadPart);
+      g_free (wdirname);
+#else
+      g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_SIZE, block_size * statfs_buffer.f_blocks);
+#endif
+    }
 #ifdef USE_STATFS
   fstype = get_fs_type (statfs_buffer.f_type);
   if (fstype &&
@@ -831,7 +871,7 @@
   char *mountpoint;
   GVolume *volume;
 
-  if (lstat (local->filename, &buf) != 0)
+  if (g_lstat (local->filename, &buf) != 0)
     {
       g_set_error (error, G_IO_ERROR,
 		   G_IO_ERROR_NOT_FOUND,
@@ -1114,12 +1154,19 @@
 {
   char *resolved, *canonical, *parent, *link2;
   char symlink_value[4096];
+#ifdef G_OS_WIN32
+#else
   ssize_t res;
+#endif
   
+#ifdef G_OS_WIN32
+#else
   res = readlink (link, symlink_value, sizeof (symlink_value) - 1);
+  
   if (res == -1)
     return g_strdup (link);
   symlink_value[res] = 0;
+#endif
   
   if (g_path_is_absolute (symlink_value))
     return canonicalize_filename (symlink_value);
@@ -1355,8 +1402,6 @@
   char *trashdir, *globaldir, *topdir, *infodir, *filesdir;
   char *basename, *trashname, *trashfile, *infoname, *infofile;
   char *original_name, *original_name_escaped;
-  uid_t uid;
-  char uid_str[32];
   int i;
   char *data;
   gboolean is_homedir_trash;
@@ -1403,6 +1448,12 @@
     }
   else
     {
+#ifdef G_OS_WIN32
+      g_warning ("Recycle bin not implemented");
+#else
+      uid_t uid;
+      char uid_str[32];
+
       uid = geteuid ();
       g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid);
       
@@ -1464,6 +1515,7 @@
 	      trashdir = NULL;
 	    }
 	}
+#endif
 
       if (trashdir == NULL)
 	{
Index: glocalfileinfo.c
===================================================================
--- glocalfileinfo.c	(revision 6027)
+++ glocalfileinfo.c	(working copy)
@@ -22,11 +22,15 @@
 
 #include <config.h>
 
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <fcntl.h>
 #include <errno.h>
 #ifdef HAVE_GRP_H
@@ -54,6 +58,28 @@
 #include <glib/gstdio.h>
 #include "glibintl.h"
 
+#ifdef G_OS_WIN32
+#include <io.h>
+#ifndef W_OK
+#define W_OK 2
+#endif
+#ifndef R_OK
+#define R_OK 4
+#endif
+#ifndef X_OK
+#define X_OK 0 /* not really */
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR _S_IEXEC
+#endif
+#endif
+
 #include "glocalfileinfo.h"
 #include "gioerror.h"
 #include "gthemedicon.h"
@@ -67,12 +93,12 @@
 	guint32 bits[2];
 	unsigned char in[64];
 };
-
+#ifndef G_OS_WIN32
 typedef struct {
   char *user_name;
   char *real_name;
 } UidData;
-
+#endif
 G_LOCK_DEFINE_STATIC (uid_cache);
 static GHashTable *uid_cache = NULL;
 
@@ -769,7 +795,11 @@
        */
       if (res == 0)
 	{
+#ifdef S_ISVTX
 	  parent_info->is_sticky = (statbuf.st_mode & S_ISVTX) != 0;
+#else
+	  parent_info->is_sticky = FALSE;
+#endif
 	  parent_info->owner = statbuf.st_uid;
 	  parent_info->device = statbuf.st_dev;
 	}
@@ -808,11 +838,13 @@
 	{
 	  if (parent_info->is_sticky)
 	    {
+#ifndef G_OS_WIN32
 	      uid_t uid = geteuid ();
 
 	      if (uid == statbuf->st_uid ||
 		  uid == parent_info->owner ||
 		  uid == 0)
+#endif
 		writable = TRUE;
 	    }
 	  else
@@ -847,6 +879,7 @@
     file_type = G_FILE_TYPE_REGULAR;
   else if (S_ISDIR (statbuf->st_mode))
     file_type = G_FILE_TYPE_DIRECTORY;
+#ifndef G_OS_WIN32
   else if (S_ISCHR (statbuf->st_mode) ||
 	   S_ISBLK (statbuf->st_mode) ||
 	   S_ISFIFO (statbuf->st_mode)
@@ -855,6 +888,7 @@
 #endif
 	   )
     file_type = G_FILE_TYPE_SPECIAL;
+#endif
 #ifdef S_ISLNK
   else if (S_ISLNK (statbuf->st_mode))
     file_type = G_FILE_TYPE_SYMBOLIC_LINK;
@@ -977,7 +1011,7 @@
   
   return utf8_string;
 }
-
+#ifndef G_OS_WIN32
 static void
 uid_data_free (UidData *data)
 {
@@ -1075,7 +1109,6 @@
   return res;
 }
 
-
 /* called with lock held */
 static char *
 lookup_gid_name (gid_t gid)
@@ -1125,6 +1158,7 @@
   G_UNLOCK (gid_cache);
   return res;
 }
+#endif /* !G_OS_WIN32 */
 
 static char *
 get_content_type (const char          *basename,
@@ -1140,12 +1174,14 @@
     return g_strdup  ("inode/symlink");
   else if (S_ISDIR(statbuf->st_mode))
     return g_strdup ("inode/directory");
+#ifndef G_OS_WIN32
   else if (S_ISCHR(statbuf->st_mode))
     return g_strdup ("inode/chardevice");
   else if (S_ISBLK(statbuf->st_mode))
     return g_strdup ("inode/blockdevice");
   else if (S_ISFIFO(statbuf->st_mode))
     return g_strdup ("inode/fifo");
+#endif
 #ifdef S_ISSOCK
   else if (S_ISSOCK(statbuf->st_mode))
     return g_strdup ("inode/socket");
Index: gwin32appinfo.c
===================================================================
--- gwin32appinfo.c	(revision 6027)
+++ gwin32appinfo.c	(working copy)
@@ -97,7 +97,9 @@
 g_desktop_app_info_new_from_id (wchar_t *id /* takes ownership */,
 				gboolean id_is_exename)
 {
+#ifdef AssocQueryStringW
   ASSOCF flags;
+#endif
   wchar_t buffer[1024];
   DWORD buffer_size;
   GWin32AppInfo *info;
@@ -108,6 +110,7 @@
   info->id_utf8 = g_utf16_to_utf8 (id, -1, NULL, NULL, NULL);  
   info->id_is_exename = id_is_exename;
 
+#ifdef AssocQueryStringW  
   flags = 0;
   if (id_is_exename)
     flags |= ASSOCF_INIT_BYEXENAME;
@@ -129,6 +132,7 @@
 			buffer,
 			&buffer_size) == S_OK)
     info->name = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
+#endif
 
   if (info->name == NULL)
     {
@@ -139,6 +143,7 @@
 	info->name = g_strdup (info->id_utf8);
     }
 
+#ifdef AssocQueryStringW
   if (AssocQueryKeyW(flags,
 		     ASSOCKEY_APP,
 		     info->id,
@@ -150,6 +155,7 @@
 	info->no_open_with = TRUE;
       RegCloseKey (app_key);
     }
+#endif
   
   return G_APP_INFO (info);
 }
@@ -245,13 +251,15 @@
 			 GError            **error)
 {
   GWin32AppInfo *info = G_WIN32_APP_INFO (appinfo);
+#ifdef AssocQueryStringW
   ASSOCF flags;
+#endif
   HKEY class_key;
   SHELLEXECUTEINFOW exec_info = {0};
   GList *l;
 
   /* TODO:  What might startup_id mean on win32? */
-  
+#ifdef AssocQueryStringW  
   flags = 0;
   if (info->id_is_exename)
     flags |= ASSOCF_INIT_BYEXENAME;
@@ -265,8 +273,9 @@
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Can't find application"));
       return FALSE;
     }
+#endif
 
-  for (l = file; l != NULL; l = l->next)
+  for (l = files; l != NULL; l = l->next)
     {
       char *path = g_file_get_path (l->data);
       wchar_t *wfilename = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
@@ -593,6 +602,7 @@
   wtype = g_utf8_to_utf16 (content_type, -1, NULL, NULL, NULL);
 
   /* Verify that we have some sort of app registered for this type */
+#ifdef AssocQueryStringW
   buffer_size = 1024;
   if (AssocQueryStringW (0,
 		  	 REAL_ASSOCSTR_COMMAND,
@@ -602,6 +612,7 @@
 			 &buffer_size) == S_OK)
     /* Takes ownership of wtype */
     return g_desktop_app_info_new_from_id (wtype, FALSE);
+#endif
 
   g_free (wtype);
   return NULL;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]