Mon Aug 20 12:41:09 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / eglib / src / gfile.c
1 /*
2  * File utility functions.
3  *
4  * Author:
5  *   Gonzalo Paniagua Javier (gonzalo@novell.com)
6  *
7  * (C) 2006 Novell, Inc.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28 #include <config.h>
29 #include <glib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36
37 #ifdef G_OS_WIN32
38 #include <io.h>
39 #define open _open
40 #define S_ISREG(x) ((x &  _S_IFMT) == _S_IFREG)
41 #define S_ISDIR(x) ((x &  _S_IFMT) == _S_IFDIR)
42 #endif
43
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47
48 GFileError
49 g_file_error_from_errno (gint err_no)
50 {
51         switch (err_no) {
52         case EEXIST:
53                 return G_FILE_ERROR_EXIST;
54         case EISDIR:
55                 return G_FILE_ERROR_ISDIR;
56         case EACCES:
57                 return G_FILE_ERROR_ACCES;
58         case ENAMETOOLONG:
59                 return G_FILE_ERROR_NAMETOOLONG;
60         case ENOENT:
61                 return G_FILE_ERROR_NOENT;
62         case ENOTDIR:
63                 return G_FILE_ERROR_NOTDIR;
64         case ENXIO:
65                 return G_FILE_ERROR_NXIO;
66         case ENODEV:
67                 return G_FILE_ERROR_NODEV;
68         case EROFS:
69                 return G_FILE_ERROR_ROFS;
70 #ifdef ETXTBSY
71         case ETXTBSY:
72                 return G_FILE_ERROR_TXTBSY;
73 #endif
74         case EFAULT:
75                 return G_FILE_ERROR_FAULT;
76 #ifdef ELOOP
77         case ELOOP:
78                 return G_FILE_ERROR_LOOP;
79 #endif
80         case ENOSPC:
81                 return G_FILE_ERROR_NOSPC;
82         case ENOMEM:
83                 return G_FILE_ERROR_NOMEM;
84         case EMFILE:
85                 return G_FILE_ERROR_MFILE;
86         case ENFILE:
87                 return G_FILE_ERROR_NFILE;
88         case EBADF:
89                 return G_FILE_ERROR_BADF;
90         case EINVAL:
91                 return G_FILE_ERROR_INVAL;
92         case EPIPE:
93                 return G_FILE_ERROR_PIPE;
94         case EAGAIN:
95                 return G_FILE_ERROR_AGAIN;
96         case EINTR:
97                 return G_FILE_ERROR_INTR;
98         case EIO:
99                 return G_FILE_ERROR_IO;
100         case EPERM:
101                 return G_FILE_ERROR_PERM;
102         case ENOSYS:
103                 return G_FILE_ERROR_NOSYS;
104         default:
105                 return G_FILE_ERROR_FAILED;
106         }
107 }
108
109 #ifndef O_LARGEFILE
110 #define OPEN_FLAGS (O_RDONLY)
111 #else
112 #define OPEN_FLAGS (O_RDONLY | O_LARGEFILE)
113 #endif
114 gboolean
115 g_file_get_contents (const gchar *filename, gchar **contents, gsize *length, GError **error)
116 {
117         gchar *str;
118         int fd;
119         struct stat st;
120         long offset;
121         int nread;
122
123         g_return_val_if_fail (filename != NULL, FALSE);
124         g_return_val_if_fail (contents != NULL, FALSE);
125         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
126
127         *contents = NULL;
128         if (length)
129                 *length = 0;
130
131         fd = open (filename, OPEN_FLAGS);
132         if (fd == -1) {
133                 if (error != NULL) {
134                         int err = errno;
135                         *error = g_error_new (G_LOG_DOMAIN, g_file_error_from_errno (err), "Error opening file");
136                 }
137                 return FALSE;
138         }
139
140         if (fstat (fd, &st) != 0) {
141                 if (error != NULL) {
142                         int err = errno;
143                         *error = g_error_new (G_LOG_DOMAIN, g_file_error_from_errno (err), "Error in fstat()");
144                 }
145                 close (fd);
146                 return FALSE;
147         }
148
149         str = g_malloc (st.st_size + 1);
150         offset = 0;
151         do {
152                 nread = read (fd, str + offset, st.st_size - offset);
153                 if (nread > 0) {
154                         offset += nread;
155                 }
156         } while ((nread > 0 && offset < st.st_size) || (nread == -1 && errno == EINTR));
157
158         close (fd);
159         str [st.st_size] = '\0';
160         if (length) {
161                 *length = st.st_size;
162         }
163         *contents = str;
164         return TRUE;
165 }
166
167 #ifdef _MSC_VER
168 int mkstemp (char *tmp_template)
169 {
170         int fd;
171         gunichar2* utf16_template;
172
173         utf16_template  = u8to16 (tmp_template);
174
175         fd = -1;
176         utf16_template = _wmktemp( utf16_template);
177         if (utf16_template && *utf16_template) {
178                 /* FIXME: _O_TEMPORARY causes file to disappear on close causing a test to fail */
179                 fd = _wopen( utf16_template, _O_BINARY | _O_CREAT /*| _O_TEMPORARY*/ | _O_EXCL, _S_IREAD | _S_IWRITE);
180         }
181
182         sprintf (tmp_template + strlen (tmp_template) - 6, "%S", utf16_template + wcslen (utf16_template) - 6);
183
184         g_free (utf16_template);
185         return fd;
186 }
187 #endif
188
189 gint
190 g_file_open_tmp (const gchar *tmpl, gchar **name_used, GError **error)
191 {
192         const static gchar *default_tmpl = ".XXXXXX";
193         gchar *t;
194         gint fd;
195         size_t len;
196
197         g_return_val_if_fail (error == NULL || *error == NULL, -1);
198
199         if (tmpl == NULL)
200                 tmpl = default_tmpl;
201
202         if (strchr (tmpl, G_DIR_SEPARATOR) != NULL) {
203                 if (error) {
204                         *error = g_error_new (G_LOG_DOMAIN, 24, "Template should not have any " G_DIR_SEPARATOR_S);
205                 }
206                 return -1;
207         }
208
209         len = strlen (tmpl);
210         if (len < 6 || strcmp (tmpl + len - 6, "XXXXXX")) {
211                 if (error) {
212                         *error = g_error_new (G_LOG_DOMAIN, 24, "Template should end with XXXXXX");
213                 }
214                 return -1;
215         }
216
217         t = g_build_filename (g_get_tmp_dir (), tmpl, NULL);
218
219         fd = mkstemp (t);
220
221         if (fd == -1) {
222                 if (error) {
223                         int err = errno;
224                         *error = g_error_new (G_LOG_DOMAIN, g_file_error_from_errno (err), "Error in mkstemp()");
225                 }
226                 g_free (t);
227                 return -1;
228         }
229
230         if (name_used) {
231                 *name_used = t;
232         } else {
233                 g_free (t);
234         }
235         return fd;
236 }
237
238 #ifdef _MSC_VER
239 #pragma warning(disable:4701)
240 #endif
241
242 gboolean
243 g_file_test (const gchar *filename, GFileTest test)
244 {
245 #ifdef G_OS_WIN32
246         struct _stat64 stat;
247         int ret = 0;
248         gunichar2* utf16_filename = NULL;
249
250         if (filename == NULL || test == 0)
251                 return FALSE;
252
253         utf16_filename = u8to16 (filename);
254         ret = _wstati64 (utf16_filename, &stat);
255         g_free (utf16_filename);
256
257         if ((test & G_FILE_TEST_EXISTS) != 0) {
258                 if (ret == 0)
259                         return TRUE;
260         }
261
262         if (ret != 0)
263                 return FALSE;
264
265         if ((test & G_FILE_TEST_IS_EXECUTABLE) != 0) {
266                 if (stat.st_mode & _S_IEXEC)
267                         return TRUE;
268         }
269
270         if ((test & G_FILE_TEST_IS_REGULAR) != 0) {
271                 if (stat.st_mode & _S_IFREG)
272                         return TRUE;
273         }
274
275         if ((test & G_FILE_TEST_IS_DIR) != 0) {
276                 if (stat.st_mode & _S_IFDIR)
277                         return TRUE;
278         }
279
280         /* make this last in case it is OR'd with something else */
281         if ((test & G_FILE_TEST_IS_SYMLINK) != 0) {
282                 return FALSE;
283         }
284
285         return FALSE;
286 #else
287         struct stat st;
288         gboolean have_stat;
289
290         if (filename == NULL || test == 0)
291                 return FALSE;
292
293         have_stat = FALSE;
294
295         if ((test & G_FILE_TEST_EXISTS) != 0) {
296                 if (access (filename, F_OK) == 0)
297                         return TRUE;
298         }
299
300         if ((test & G_FILE_TEST_IS_EXECUTABLE) != 0) {
301                 if (access (filename, X_OK) == 0)
302                         return TRUE;
303         }
304         if ((test & G_FILE_TEST_IS_SYMLINK) != 0) {
305                 have_stat = (lstat (filename, &st) == 0);
306                 if (have_stat && S_ISLNK (st.st_mode))
307                         return TRUE;
308         }
309
310         if ((test & G_FILE_TEST_IS_REGULAR) != 0) {
311                 if (!have_stat)
312                         have_stat = (stat (filename, &st) == 0);
313                 if (have_stat && S_ISREG (st.st_mode))
314                         return TRUE;
315         }
316         if ((test & G_FILE_TEST_IS_DIR) != 0) {
317                 if (!have_stat)
318                         have_stat = (stat (filename, &st) == 0);
319                 if (have_stat && S_ISDIR (st.st_mode))
320                         return TRUE;
321         }
322         return FALSE;
323 #endif
324 }
325
326