Fixed yet another bloody implementation of getpwuid_r. This time for AIX.
[platform/upstream/glib.git] / gutils.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* 
28  * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include "glibconfig.h"
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <errno.h>
45 #ifdef HAVE_PWD_H
46 #include <pwd.h>
47 #endif
48 #include <sys/types.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
51 #endif
52
53 #ifdef NATIVE_WIN32
54 #  define STRICT                        /* Strict typing, please */
55 #  include <windows.h>
56 #  include <direct.h>
57 #  include <errno.h>
58 #  include <ctype.h>
59 #  ifdef _MSC_VER
60 #    include <io.h>
61 #  endif /* _MSC_VER */
62 #endif /* NATIVE_WIN32 */
63
64 /* implement Glib's inline functions
65  */
66 #define G_INLINE_FUNC extern
67 #define G_CAN_INLINE 1
68 #include "glib.h"
69
70 #ifdef  MAXPATHLEN
71 #define G_PATH_LENGTH   (MAXPATHLEN + 1)
72 #elif   defined (PATH_MAX)
73 #define G_PATH_LENGTH   (PATH_MAX + 1)
74 #else   /* !MAXPATHLEN */
75 #define G_PATH_LENGTH   (2048 + 1)
76 #endif  /* !MAXPATHLEN && !PATH_MAX */
77
78 const guint glib_major_version = GLIB_MAJOR_VERSION;
79 const guint glib_minor_version = GLIB_MINOR_VERSION;
80 const guint glib_micro_version = GLIB_MICRO_VERSION;
81 const guint glib_interface_age = GLIB_INTERFACE_AGE;
82 const guint glib_binary_age = GLIB_BINARY_AGE;
83
84 #if defined (NATIVE_WIN32) && defined (__LCC__)
85 int __stdcall 
86 LibMain (void         *hinstDll,
87          unsigned long dwReason,
88          void         *reserved)
89 {
90   return 1;
91 }
92 #endif /* NATIVE_WIN32 && __LCC__ */
93
94 void
95 g_atexit (GVoidFunc func)
96 {
97   gint result;
98   gchar *error = NULL;
99
100   /* keep this in sync with glib.h */
101
102 #ifdef  G_NATIVE_ATEXIT
103   result = ATEXIT (func);
104   if (result)
105     error = g_strerror (errno);
106 #elif defined (HAVE_ATEXIT)
107 #  ifdef NeXT /* @#%@! NeXTStep */
108   result = !atexit ((void (*)(void)) func);
109   if (result)
110     error = g_strerror (errno);
111 #  else
112   result = atexit ((void (*)(void)) func);
113   if (result)
114     error = g_strerror (errno);
115 #  endif /* NeXT */
116 #elif defined (HAVE_ON_EXIT)
117   result = on_exit ((void (*)(int, void *)) func, NULL);
118   if (result)
119     error = g_strerror (errno);
120 #else
121   result = 0;
122   error = "no implementation";
123 #endif /* G_NATIVE_ATEXIT */
124
125   if (error)
126     g_error ("Could not register atexit() function: %s", error);
127 }
128
129 gint
130 g_snprintf (gchar       *str,
131             gulong       n,
132             gchar const *fmt,
133             ...)
134 {
135 #ifdef  HAVE_VSNPRINTF
136   va_list args;
137   gint retval;
138   
139   va_start (args, fmt);
140   retval = vsnprintf (str, n, fmt, args);
141   va_end (args);
142   
143   return retval;
144 #else   /* !HAVE_VSNPRINTF */
145   gchar *printed;
146   va_list args;
147   
148   va_start (args, fmt);
149   printed = g_strdup_vprintf (fmt, args);
150   va_end (args);
151   
152   strncpy (str, printed, n);
153   str[n-1] = '\0';
154
155   g_free (printed);
156   
157   return strlen (str);
158 #endif  /* !HAVE_VSNPRINTF */
159 }
160
161 gint
162 g_vsnprintf (gchar       *str,
163              gulong       n,
164              gchar const *fmt,
165              va_list      args)
166 {
167 #ifdef  HAVE_VSNPRINTF
168   gint retval;
169   
170   retval = vsnprintf (str, n, fmt, args);
171   
172   return retval;
173 #else   /* !HAVE_VSNPRINTF */
174   gchar *printed;
175   
176   printed = g_strdup_vprintf (fmt, args);
177   strncpy (str, printed, n);
178   str[n-1] = '\0';
179
180   g_free (printed);
181   
182   return strlen (str);
183 #endif /* !HAVE_VSNPRINTF */
184 }
185
186 guint        
187 g_parse_debug_string  (const gchar *string, 
188                        GDebugKey   *keys, 
189                        guint        nkeys)
190 {
191   guint i;
192   guint result = 0;
193   
194   g_return_val_if_fail (string != NULL, 0);
195   
196   if (!g_strcasecmp (string, "all"))
197     {
198       for (i=0; i<nkeys; i++)
199         result |= keys[i].value;
200     }
201   else
202     {
203       gchar *str = g_strdup (string);
204       gchar *p = str;
205       gchar *q;
206       gboolean done = FALSE;
207       
208       while (*p && !done)
209         {
210           q = strchr (p, ':');
211           if (!q)
212             {
213               q = p + strlen(p);
214               done = TRUE;
215             }
216           
217           *q = 0;
218           
219           for (i=0; i<nkeys; i++)
220             if (!g_strcasecmp(keys[i].key, p))
221               result |= keys[i].value;
222           
223           p = q+1;
224         }
225       
226       g_free (str);
227     }
228   
229   return result;
230 }
231
232 gchar*
233 g_basename (const gchar    *file_name)
234 {
235   register gchar *base;
236   
237   g_return_val_if_fail (file_name != NULL, NULL);
238   
239   base = strrchr (file_name, G_DIR_SEPARATOR);
240   if (base)
241     return base + 1;
242
243 #ifdef NATIVE_WIN32
244   if (isalpha (file_name[0]) && file_name[1] == ':')
245     return (gchar*) file_name + 2;
246 #endif /* NATIVE_WIN32 */
247   
248   return (gchar*) file_name;
249 }
250
251 gboolean
252 g_path_is_absolute (const gchar *file_name)
253 {
254   g_return_val_if_fail (file_name != NULL, FALSE);
255   
256   if (file_name[0] == G_DIR_SEPARATOR)
257     return TRUE;
258
259 #ifdef NATIVE_WIN32
260   if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
261     return TRUE;
262 #endif
263
264   return FALSE;
265 }
266
267 gchar*
268 g_path_skip_root (gchar *file_name)
269 {
270   g_return_val_if_fail (file_name != NULL, NULL);
271   
272   if (file_name[0] == G_DIR_SEPARATOR)
273     return file_name + 1;
274
275 #ifdef NATIVE_WIN32
276   if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
277     return file_name + 3;
278 #endif
279
280   return NULL;
281 }
282
283 gchar*
284 g_dirname (const gchar     *file_name)
285 {
286   register gchar *base;
287   register guint len;
288   
289   g_return_val_if_fail (file_name != NULL, NULL);
290   
291   base = strrchr (file_name, G_DIR_SEPARATOR);
292   if (!base)
293     return g_strdup (".");
294   while (base > file_name && *base == G_DIR_SEPARATOR)
295     base--;
296   len = (guint) 1 + base - file_name;
297   
298   base = g_new (gchar, len + 1);
299   g_memmove (base, file_name, len);
300   base[len] = 0;
301   
302   return base;
303 }
304
305 gchar*
306 g_get_current_dir (void)
307 {
308   gchar *buffer;
309   gchar *dir;
310
311   buffer = g_new (gchar, G_PATH_LENGTH);
312   *buffer = 0;
313   
314   /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
315    * and, if that wasn't bad enough, hangs in doing so.
316    */
317 #if     defined (sun) && !defined (__SVR4)
318   dir = getwd (buffer);
319 #else   /* !sun */
320   dir = getcwd (buffer, G_PATH_LENGTH - 1);
321 #endif  /* !sun */
322   
323   if (!dir || !*buffer)
324     {
325       /* hm, should we g_error() out here?
326        * this can happen if e.g. "./" has mode \0000
327        */
328       buffer[0] = G_DIR_SEPARATOR;
329       buffer[1] = 0;
330     }
331
332   dir = g_strdup (buffer);
333   g_free (buffer);
334   
335   return dir;
336 }
337
338 gchar*
339 g_getenv (const gchar *variable)
340 {
341 #ifndef NATIVE_WIN32
342   g_return_val_if_fail (variable != NULL, NULL);
343
344   return getenv (variable);
345 #else
346   gchar *v;
347   guint k;
348   static gchar *p = NULL;
349   static gint l;
350   gchar dummy[2];
351
352   g_return_val_if_fail (variable != NULL, NULL);
353   
354   v = getenv (variable);
355   if (!v)
356     return NULL;
357   
358   /* On Windows NT, it is relatively typical that environment variables
359    * contain references to other environment variables. Handle that by
360    * calling ExpandEnvironmentStrings.
361    */
362
363   /* First check how much space we need */
364   k = ExpandEnvironmentStrings (v, dummy, 2);
365   /* Then allocate that much, and actualy do the expansion */
366   if (p == NULL)
367     {
368       p = g_malloc (k);
369       l = k;
370     }
371   else if (k > l)
372     {
373       p = g_realloc (p, k);
374       l = k;
375     }
376   ExpandEnvironmentStrings (v, p, k);
377   return p;
378 #endif
379 }
380
381
382 G_LOCK_DEFINE_STATIC (g_utils_global);
383
384 static  gchar   *g_tmp_dir = NULL;
385 static  gchar   *g_user_name = NULL;
386 static  gchar   *g_real_name = NULL;
387 static  gchar   *g_home_dir = NULL;
388
389 /* HOLDS: g_utils_global_lock */
390 static void
391 g_get_any_init (void)
392 {
393   if (!g_tmp_dir)
394     {
395       g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
396       if (!g_tmp_dir)
397         g_tmp_dir = g_strdup (g_getenv ("TMP"));
398       if (!g_tmp_dir)
399         g_tmp_dir = g_strdup (g_getenv ("TEMP"));
400       
401 #ifdef P_tmpdir
402       if (!g_tmp_dir)
403         {
404           int k;
405           g_tmp_dir = g_strdup (P_tmpdir);
406           k = strlen (g_tmp_dir);
407           if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
408             g_tmp_dir[k-1] = '\0';
409         }
410 #endif
411       
412       if (!g_tmp_dir)
413         {
414 #ifndef NATIVE_WIN32
415           g_tmp_dir = g_strdup ("/tmp");
416 #else /* NATIVE_WIN32 */
417           g_tmp_dir = g_strdup ("C:\\");
418 #endif /* NATIVE_WIN32 */
419         }
420       
421       if (!g_home_dir)
422         g_home_dir = g_strdup (g_getenv ("HOME"));
423       
424 #ifdef NATIVE_WIN32
425       if (!g_home_dir)
426         {
427           /* The official way to specify a home directory on NT is
428            * the HOMEDRIVE and HOMEPATH environment variables.
429            *
430            * This is inside #ifdef NATIVE_WIN32 because with the cygwin dll,
431            * HOME should be a POSIX style pathname.
432            */
433           
434           if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
435             {
436               gchar *homedrive, *homepath;
437               
438               homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
439               homepath = g_strdup (g_getenv ("HOMEPATH"));
440               
441               g_home_dir = g_strconcat (homedrive, homepath, NULL);
442               g_free (homedrive);
443               g_free (homepath);
444             }
445         }
446 #endif /* !NATIVE_WIN32 */
447       
448 #ifdef HAVE_PWD_H
449       {
450         struct passwd *pw = NULL;
451         gpointer buffer = NULL;
452         
453 #  ifdef HAVE_GETPWUID_R
454         struct passwd pwd;
455         guint bufsize = 64;
456         gint error;
457         
458         do
459           {
460             g_free (buffer);
461             buffer = g_malloc (bufsize);
462             errno = 0;
463             
464 #    ifdef HAVE_GETPWUID_R_POSIX
465             error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
466             error = error < 0 ? errno : error;
467 #    else /* !HAVE_GETPWUID_R_POSIX */
468 #      ifdef _AIX
469             error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
470             pw = error == 0 ? &pwd : NULL;
471 #      else /* !_AIX */
472             pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
473             error = pw ? 0 : errno;
474 #      endif /* !_AIX */            
475 #    endif /* !HAVE_GETPWUID_R_POSIX */
476             
477             if (!pw)
478               {
479                 /* we bail out prematurely if the user id can't be found
480                  * (should be pretty rare case actually), or if the buffer
481                  * should be sufficiently big and lookups are still not
482                  * successfull.
483                  */
484                 if (error == 0 || error == ENOENT)
485                   {
486                     g_warning ("getpwuid_r(): failed due to: No such user %d.",
487                                getuid ());
488                     break;
489                   }
490                 if (bufsize > 32 * 1024)
491                   {
492                     g_warning ("getpwuid_r(): failed due to: %s.",
493                                g_strerror (error));
494                     break;
495                   }
496                 
497                 bufsize *= 2;
498               }
499           }
500         while (!pw);
501 #  endif /* !HAVE_GETPWUID_R */
502         
503         if (!pw)
504           {
505             setpwent ();
506             pw = getpwuid (getuid ());
507             endpwent ();
508           }
509         if (pw)
510           {
511             g_user_name = g_strdup (pw->pw_name);
512             g_real_name = g_strdup (pw->pw_gecos);
513             if (!g_home_dir)
514               g_home_dir = g_strdup (pw->pw_dir);
515           }
516         g_free (buffer);
517       }
518       
519 #else /* !HAVE_PWD_H */
520       
521 #  ifdef NATIVE_WIN32
522       {
523         guint len = 17;
524         gchar buffer[17];
525         
526         if (GetUserName (buffer, &len))
527           {
528             g_user_name = g_strdup (buffer);
529             g_real_name = g_strdup (buffer);
530           }
531       }
532 #  endif /* NATIVE_WIN32 */
533       
534 #endif /* !HAVE_PWD_H */
535       
536       if (!g_user_name)
537         g_user_name = g_strdup ("somebody");
538       if (!g_real_name)
539         g_real_name = g_strdup ("Unknown");
540       else
541         {
542           gchar *p;
543
544           for (p = g_real_name; *p; p++)
545             if (*p == ',')
546               {
547                 *p = 0;
548                 p = g_strdup (g_real_name);
549                 g_free (g_real_name);
550                 g_real_name = p;
551                 break;
552               }
553         }
554     }
555 }
556
557 gchar*
558 g_get_user_name (void)
559 {
560   G_LOCK (g_utils_global);
561   if (!g_tmp_dir)
562     g_get_any_init ();
563   G_UNLOCK (g_utils_global);
564   
565   return g_user_name;
566 }
567
568 gchar*
569 g_get_real_name (void)
570 {
571   G_LOCK (g_utils_global);
572   if (!g_tmp_dir)
573     g_get_any_init ();
574   G_UNLOCK (g_utils_global);
575  
576   return g_real_name;
577 }
578
579 /* Return the home directory of the user. If there is a HOME
580  * environment variable, its value is returned, otherwise use some
581  * system-dependent way of finding it out. If no home directory can be
582  * deduced, return NULL.
583  */
584
585 gchar*
586 g_get_home_dir (void)
587 {
588   G_LOCK (g_utils_global);
589   if (!g_tmp_dir)
590     g_get_any_init ();
591   G_UNLOCK (g_utils_global);
592   
593   return g_home_dir;
594 }
595
596 /* Return a directory to be used to store temporary files. This is the
597  * value of the TMPDIR, TMP or TEMP environment variables (they are
598  * checked in that order). If none of those exist, use P_tmpdir from
599  * stdio.h.  If that isn't defined, return "/tmp" on POSIXly systems,
600  * and C:\ on Windows.
601  */
602
603 gchar*
604 g_get_tmp_dir (void)
605 {
606   G_LOCK (g_utils_global);
607   if (!g_tmp_dir)
608     g_get_any_init ();
609   G_UNLOCK (g_utils_global);
610   
611   return g_tmp_dir;
612 }
613
614 static gchar *g_prgname = NULL;
615
616 gchar*
617 g_get_prgname (void)
618 {
619   gchar* retval;
620
621   G_LOCK (g_utils_global);
622   retval = g_prgname;
623   G_UNLOCK (g_utils_global);
624
625   return retval;
626 }
627
628 void
629 g_set_prgname (const gchar *prgname)
630 {
631   gchar *c;
632     
633   G_LOCK (g_utils_global);
634   c = g_prgname;
635   g_prgname = g_strdup (prgname);
636   g_free (c);
637   G_UNLOCK (g_utils_global);
638 }
639
640 guint
641 g_direct_hash (gconstpointer v)
642 {
643   return GPOINTER_TO_UINT (v);
644 }
645
646 gint
647 g_direct_equal (gconstpointer v1,
648                 gconstpointer v2)
649 {
650   return v1 == v2;
651 }
652
653 gint
654 g_int_equal (gconstpointer v1,
655              gconstpointer v2)
656 {
657   return *((const gint*) v1) == *((const gint*) v2);
658 }
659
660 guint
661 g_int_hash (gconstpointer v)
662 {
663   return *(const gint*) v;
664 }
665
666 #if 0 /* Old IO Channels */
667
668 GIOChannel*
669 g_iochannel_new (gint fd)
670 {
671   GIOChannel *channel = g_new (GIOChannel, 1);
672
673   channel->fd = fd;
674
675 #ifdef NATIVE_WIN32
676   channel->peer = 0;
677   channel->peer_fd = 0;
678   channel->offset = 0;
679   channel->need_wakeups = 0;
680 #endif /* NATIVE_WIN32 */
681
682   return channel;
683 }
684
685 void
686 g_iochannel_free (GIOChannel *channel)
687 {
688   g_return_if_fail (channel != NULL);
689
690   g_free (channel);
691 }
692
693 void
694 g_iochannel_close_and_free (GIOChannel *channel)
695 {
696   g_return_if_fail (channel != NULL);
697
698   close (channel->fd);
699
700   g_iochannel_free (channel);
701 }
702
703 #undef g_iochannel_wakeup_peer
704
705 void
706 g_iochannel_wakeup_peer (GIOChannel *channel)
707 {
708 #ifdef NATIVE_WIN32
709   static guint message = 0;
710 #endif
711
712   g_return_if_fail (channel != NULL);
713
714 #ifdef NATIVE_WIN32
715   if (message == 0)
716     message = RegisterWindowMessage ("gdk-pipe-readable");
717
718 #  if 0
719   g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
720            channel->peer, message, channel->peer_fd, channel->offset);
721 #  endif
722   PostThreadMessage (channel->peer, message,
723                      channel->peer_fd, channel->offset);
724 #endif /* NATIVE_WIN32 */
725 }
726
727 #endif /* Old IO Channels */
728
729 #ifdef NATIVE_WIN32
730 #ifdef _MSC_VER
731
732 int
733 gwin_ftruncate (gint  fd,
734                 guint size)
735 {
736   HANDLE hfile;
737   guint curpos;
738
739   g_return_val_if_fail (fd >= 0, -1);
740   
741   hfile = (HANDLE) _get_osfhandle (fd);
742   curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
743   if (curpos == 0xFFFFFFFF
744       || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
745       || !SetEndOfFile (hfile))
746     {
747       gint error = GetLastError ();
748
749       switch (error)
750         {
751         case ERROR_INVALID_HANDLE:
752           errno = EBADF;
753           break;
754         default:
755           errno = EIO;
756           break;
757         }
758
759       return -1;
760     }
761
762   return 0;
763 }
764
765 DIR*
766 gwin_opendir (const char *dirname)
767 {
768   DIR *result;
769   gchar *mask;
770   guint k;
771
772   g_return_val_if_fail (dirname != NULL, NULL);
773
774   result = g_new0 (DIR, 1);
775   result->find_file_data = g_new0 (WIN32_FIND_DATA, 1);
776   result->dir_name = g_strdup (dirname);
777   
778   k = strlen (result->dir_name);
779   if (k && result->dir_name[k - 1] == '\\')
780     {
781       result->dir_name[k - 1] = '\0';
782       k--;
783     }
784   mask = g_strdup_printf ("%s\\*", result->dir_name);
785
786   result->find_file_handle = (guint) FindFirstFile (mask,
787                                              (LPWIN32_FIND_DATA) result->find_file_data);
788   g_free (mask);
789
790   if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE)
791     {
792       int error = GetLastError ();
793
794       g_free (result->dir_name);
795       g_free (result->find_file_data);
796       g_free (result);
797       switch (error)
798         {
799         default:
800           errno = EIO;
801           return NULL;
802         }
803     }
804   result->just_opened = TRUE;
805
806   return result;
807 }
808
809 struct dirent*
810 gwin_readdir (DIR *dir)
811 {
812   static struct dirent result;
813
814   g_return_val_if_fail (dir != NULL, NULL);
815
816   if (dir->just_opened)
817     dir->just_opened = FALSE;
818   else
819     {
820       if (!FindNextFile ((HANDLE) dir->find_file_handle,
821                          (LPWIN32_FIND_DATA) dir->find_file_data))
822         {
823           int error = GetLastError ();
824
825           switch (error)
826             {
827             case ERROR_NO_MORE_FILES:
828               return NULL;
829             default:
830               errno = EIO;
831               return NULL;
832             }
833         }
834     }
835   strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName));
836       
837   return &result;
838 }
839
840 void
841 gwin_rewinddir (DIR *dir)
842 {
843   gchar *mask;
844
845   g_return_if_fail (dir != NULL);
846
847   if (!FindClose ((HANDLE) dir->find_file_handle))
848     g_warning ("gwin_rewinddir(): FindClose() failed\n");
849
850   mask = g_strdup_printf ("%s\\*", dir->dir_name);
851   dir->find_file_handle = (guint) FindFirstFile (mask,
852                                           (LPWIN32_FIND_DATA) dir->find_file_data);
853   g_free (mask);
854
855   if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE)
856     {
857       int error = GetLastError ();
858
859       switch (error)
860         {
861         default:
862           errno = EIO;
863           return;
864         }
865     }
866   dir->just_opened = TRUE;
867 }  
868
869 gint
870 gwin_closedir (DIR *dir)
871 {
872   g_return_val_if_fail (dir != NULL, -1);
873
874   if (!FindClose ((HANDLE) dir->find_file_handle))
875     {
876       int error = GetLastError ();
877
878       switch (error)
879         {
880         default:
881           errno = EIO; return -1;
882         }
883     }
884
885   g_free (dir->dir_name);
886   g_free (dir->find_file_data);
887   g_free (dir);
888
889   return 0;
890 }
891
892 #endif /* _MSC_VER */
893
894 #endif /* NATIVE_WIN32 */