src/mn-vfs.c (9395B) - raw
1 /*
2 * Mail Notification
3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <string.h>
21 #include <glib/gi18n.h>
22 #include "mn-vfs.h"
23
24 #ifndef MN_REGRESSION_TEST
25 #define READ_LINE_BLOCK_SIZE 16384
26 #endif
27
28 struct _MNVFSReadLineContext
29 {
30 GnomeVFSHandle *handle;
31 GString *buf;
32 char *terminator;
33 GnomeVFSResult last_result;
34 gboolean eof;
35 };
36
37 /* FIXME: must also handle \r and \r\n terminators */
38 GnomeVFSResult
39 mn_vfs_read_line (MNVFSReadLineContext **context,
40 GnomeVFSHandle *handle,
41 const char **line)
42 {
43 GnomeVFSResult result;
44 gboolean first_pass = TRUE;
45
46 g_return_val_if_fail(context != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
47 g_return_val_if_fail(handle != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
48 g_return_val_if_fail(line != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
49
50 if (*context)
51 {
52 g_return_val_if_fail((*context)->handle == handle, GNOME_VFS_ERROR_BAD_PARAMETERS);
53 if ((*context)->terminator)
54 {
55 g_string_erase((*context)->buf, 0, (*context)->terminator - (*context)->buf->str + 1);
56 (*context)->terminator = NULL;
57 }
58 else if ((*context)->eof)
59 return GNOME_VFS_ERROR_EOF; /* we're done */
60 }
61 else
62 {
63 *context = g_new0(MNVFSReadLineContext, 1);
64 (*context)->handle = handle;
65 (*context)->buf = g_string_new(NULL);
66 }
67
68 while (TRUE)
69 {
70 if (! (*context)->buf->str[0] || ! first_pass)
71 {
72 char buf[READ_LINE_BLOCK_SIZE];
73 GnomeVFSFileSize bytes_read;
74
75 result = (*context)->last_result = gnome_vfs_read(handle, buf, sizeof(buf), &bytes_read);
76 if (result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_EOF)
77 g_string_append_len((*context)->buf, buf, bytes_read);
78 else
79 break; /* error */
80 }
81
82 (*context)->terminator = strchr((*context)->buf->str, '\n');
83 if ((*context)->terminator || (*context)->last_result == GNOME_VFS_ERROR_EOF)
84 {
85 result = (*context)->last_result;
86 if ((*context)->terminator || (*context)->buf->str[0])
87 {
88 *line = (*context)->buf->str;
89 if (result == GNOME_VFS_ERROR_EOF)
90 result = GNOME_VFS_OK;
91 }
92 if ((*context)->terminator)
93 (*context)->terminator[0] = 0;
94 else if ((*context)->last_result == GNOME_VFS_ERROR_EOF)
95 (*context)->eof = TRUE;
96
97 break; /* line found, or last line */
98 }
99
100 first_pass = FALSE;
101 }
102
103 return result;
104 }
105
106 void
107 mn_vfs_read_line_context_free (MNVFSReadLineContext *context)
108 {
109 g_return_if_fail(context != NULL);
110
111 g_string_free(context->buf, TRUE);
112 g_free(context);
113 }
114
115 gboolean
116 mn_vfs_test (GnomeVFSURI *uri, GFileTest test)
117 {
118 GnomeVFSFileInfoOptions options;
119 GnomeVFSFileInfo *file_info;
120 gboolean status = FALSE;
121
122 g_return_val_if_fail(uri != NULL, FALSE);
123
124 options = GNOME_VFS_FILE_INFO_DEFAULT;
125 if (! (test & G_FILE_TEST_IS_SYMLINK))
126 options |= GNOME_VFS_FILE_INFO_FOLLOW_LINKS;
127 if (test & G_FILE_TEST_IS_EXECUTABLE)
128 options |= GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS;
129
130 file_info = gnome_vfs_file_info_new();
131 if (gnome_vfs_get_file_info_uri(uri, file_info, options) == GNOME_VFS_OK)
132 {
133 if (file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE)
134 {
135 if (test & G_FILE_TEST_IS_REGULAR)
136 status = file_info->type == GNOME_VFS_FILE_TYPE_REGULAR;
137 if (! status && test & G_FILE_TEST_IS_SYMLINK)
138 status = file_info->type == GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK;
139 if (! status && test & G_FILE_TEST_IS_DIR)
140 status = file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY;
141 }
142 if (file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS)
143 {
144 if (! status && test & G_FILE_TEST_IS_EXECUTABLE)
145 status = file_info->permissions & GNOME_VFS_PERM_ACCESS_EXECUTABLE;
146 }
147 if (! status && test & G_FILE_TEST_EXISTS)
148 status = TRUE; /* gnome_vfs_get_file_info() succeeded, so the file exists */
149 }
150 gnome_vfs_file_info_unref(file_info);
151
152 return status;
153 }
154
155 GnomeVFSResult
156 mn_vfs_read_entire_file_uri (GnomeVFSURI *uri,
157 int *file_size,
158 char **file_contents)
159 {
160 char *text_uri;
161 GnomeVFSResult result;
162
163 g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
164
165 text_uri = gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE);
166 result = gnome_vfs_read_entire_file(text_uri, file_size, file_contents);
167 g_free(text_uri);
168
169 return result;
170 }
171
172 GnomeVFSResult
173 mn_vfs_write_entire_file_uri (GnomeVFSURI *uri,
174 gsize file_size,
175 const char *file_contents,
176 gboolean exclusive,
177 unsigned int perms)
178 {
179 GnomeVFSHandle *handle;
180 GnomeVFSResult result;
181 GnomeVFSFileSize bytes_written = 0;
182
183 result = gnome_vfs_create_uri(&handle, uri, GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_TRUNCATE, exclusive, perms);
184 if (result != GNOME_VFS_OK)
185 return result;
186
187 while (bytes_written < file_size)
188 {
189 GnomeVFSFileSize this_bytes_written;
190
191 result = gnome_vfs_write(handle, file_contents + bytes_written, file_size - bytes_written, &this_bytes_written);
192 if (result != GNOME_VFS_OK)
193 {
194 gnome_vfs_close(handle);
195 return result;
196 }
197
198 bytes_written += this_bytes_written;
199 }
200
201 return gnome_vfs_close(handle);
202 }
203
204 gboolean
205 mn_vfs_write_entire_file_uri_safe (GnomeVFSURI *uri,
206 gsize file_size,
207 const char *file_contents,
208 unsigned int perms,
209 GError **err)
210 {
211 GnomeVFSResult result;
212 char *text_uri;
213 GnomeVFSURI *tmp_uri;
214 char *tmp_text_uri;
215 GnomeVFSURI *old_uri;
216 char *old_text_uri;
217 gboolean status = FALSE;
218 gboolean old_exists;
219
220 g_return_val_if_fail(uri != NULL, FALSE);
221
222 text_uri = gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_PASSWORD);
223 tmp_uri = mn_vfs_uri_append_file_suffix(uri, ".tmp");
224 tmp_text_uri = gnome_vfs_uri_to_string(tmp_uri, GNOME_VFS_URI_HIDE_PASSWORD);
225 old_uri = mn_vfs_uri_append_file_suffix(uri, ".old");
226 old_text_uri = gnome_vfs_uri_to_string(old_uri, GNOME_VFS_URI_HIDE_PASSWORD);
227
228 if (mn_vfs_test(tmp_uri, G_FILE_TEST_EXISTS))
229 {
230 result = gnome_vfs_unlink_from_uri(tmp_uri);
231 if (result != GNOME_VFS_OK)
232 {
233 g_set_error(err, 0, 0, _("Unable to remove %s: %s."), tmp_text_uri, gnome_vfs_result_to_string(result));
234 goto end;
235 }
236 }
237
238 result = mn_vfs_write_entire_file_uri(tmp_uri, file_size, file_contents, TRUE, perms);
239 if (result != GNOME_VFS_OK)
240 {
241 g_set_error(err, 0, 0, _("Unable to write %s: %s."), tmp_text_uri, gnome_vfs_result_to_string(result));
242 goto end;
243 }
244
245 old_exists = mn_vfs_test(uri, G_FILE_TEST_EXISTS);
246 if (old_exists)
247 {
248 result = gnome_vfs_move_uri(uri, old_uri, TRUE);
249 if (result != GNOME_VFS_OK)
250 {
251 g_set_error(err, 0, 0, _("Unable to rename %s to %s: %s."), text_uri, old_text_uri, gnome_vfs_result_to_string(result));
252 goto end;
253 }
254 }
255
256 result = gnome_vfs_move_uri(tmp_uri, uri, TRUE);
257 if (result != GNOME_VFS_OK)
258 {
259 g_set_error(err, 0, 0, _("Unable to rename %s to %s: %s."), tmp_text_uri, text_uri, gnome_vfs_result_to_string(result));
260 goto end;
261 }
262
263 if (old_exists)
264 {
265 GnomeVFSResult this_result;
266
267 this_result = gnome_vfs_unlink_from_uri(old_uri);
268 if (this_result != GNOME_VFS_OK) /* non fatal */
269 g_warning(_("unable to delete %s: %s"), old_text_uri, gnome_vfs_result_to_string(this_result));
270 }
271
272 status = TRUE; /* success */
273
274 end:
275 g_free(text_uri);
276 gnome_vfs_uri_unref(tmp_uri);
277 g_free(tmp_text_uri);
278 gnome_vfs_uri_unref(old_uri);
279 g_free(old_text_uri);
280
281 return status;
282 }
283
284 GnomeVFSURI *
285 mn_vfs_uri_append_file_suffix (GnomeVFSURI *uri, const char *suffix)
286 {
287 GnomeVFSURI *result;
288
289 g_return_val_if_fail(uri != NULL, NULL);
290 g_return_val_if_fail(suffix != NULL, NULL);
291
292 result = gnome_vfs_uri_dup(uri);
293 if (result->text)
294 {
295 char *new_text;
296
297 new_text = g_strconcat(result->text, suffix, NULL);
298 g_free(result->text);
299 result->text = new_text;
300 }
301 else
302 result->text = g_strdup(suffix);
303
304 return result;
305 }
306
307 char *
308 mn_vfs_uri_extract_short_name (const char *text_uri)
309 {
310 GnomeVFSURI *uri;
311 char *name;
312
313 g_return_val_if_fail(text_uri != NULL, NULL);
314
315 uri = gnome_vfs_uri_new(text_uri);
316 if (! uri)
317 return NULL;
318
319 name = gnome_vfs_uri_extract_short_name(uri);
320 gnome_vfs_uri_unref(uri);
321
322 return name;
323 }
324
325 char *
326 mn_vfs_get_local_path (GnomeVFSURI *uri)
327 {
328 char *text_uri;
329 char *path;
330
331 g_return_val_if_fail(uri != NULL, NULL);
332
333 text_uri = gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE);
334 path = gnome_vfs_get_local_path_from_uri(text_uri);
335 g_free(text_uri);
336
337 return path;
338 }
339
340 gboolean
341 mn_vfs_result_to_g_error (GnomeVFSResult result, GError **err)
342 {
343 if (result == GNOME_VFS_OK)
344 return TRUE;
345
346 g_set_error(err, 0, 0, "%s", gnome_vfs_result_to_string(result));
347 return FALSE;
348 }