1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
4 * Michael Zucchi <notzed@ximian.com>
5 * Jeffrey Stedfast <fejj@ximian.com>
6 * Dan Winship <danw@ximian.com>
8 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
34 #include <sys/types.h>
36 #include <glib/gi18n-lib.h>
38 #include "camel-file-utils.h"
39 #include "camel-object.h"
40 #include "camel-operation.h"
41 #include "camel-url.h"
45 #define EWOULDBLOCK EAGAIN
48 #define IO_TIMEOUT (60*4)
51 * camel_file_util_encode_uint32:
52 * @out: file to output to
53 * @value: value to output
55 * Utility function to save an uint32 to a file.
57 * Returns: %0 on success, %-1 on error.
60 camel_file_util_encode_uint32 (FILE *out,
65 for (i = 28; i > 0; i -= 7) {
66 if (value >= (1 << i)) {
67 guint c = (value >> i) & 0x7f;
68 if (fputc (c, out) == -1)
72 return fputc (value | 0x80, out);
76 * camel_file_util_decode_uint32:
77 * @in: file to read from
78 * @dest: pointer to a variable to store the value in
80 * Retrieve an encoded uint32 from a file.
82 * Returns: %0 on success, %-1 on error. @*dest will contain the
86 camel_file_util_decode_uint32 (FILE *in,
92 /* until we get the last byte, keep decoding 7 bits at a time */
93 while ( ((v = fgetc (in)) & 0x80) == 0 && v != EOF) {
101 *dest = value | (v & 0x7f);
107 * camel_file_util_encode_fixed_int32:
108 * @out: file to output to
109 * @value: value to output
111 * Encode a gint32, performing no compression, but converting
114 * Returns: %0 on success, %-1 on error.
117 camel_file_util_encode_fixed_int32 (FILE *out,
122 save = g_htonl (value);
123 if (fwrite (&save, sizeof (save), 1, out) != 1)
129 * camel_file_util_decode_fixed_int32:
130 * @in: file to read from
131 * @dest: pointer to a variable to store the value in
135 * Returns: %0 on success, %-1 on error.
138 camel_file_util_decode_fixed_int32 (FILE *in,
143 if (fread (&save, sizeof (save), 1, in) == 1) {
144 *dest = g_ntohl (save);
151 #define CFU_ENCODE_T(type) \
153 camel_file_util_encode_##type (FILE *out, type value) \
157 for (i = sizeof (type) - 1; i >= 0; i--) { \
158 if (fputc ((value >> (i * 8)) & 0xff, out) == -1) \
164 #define CFU_DECODE_T(type) \
166 camel_file_util_decode_##type (FILE *in, type *dest) \
169 gint i = sizeof (type) - 1; \
172 while (i >= 0 && (v = fgetc (in)) != EOF) { \
173 save |= ((type) v) << (i * 8); \
183 * camel_file_util_encode_time_t:
184 * @out: file to output to
185 * @value: value to output
187 * Encode a time_t value to the file.
189 * Returns: %0 on success, %-1 on error.
191 CFU_ENCODE_T (time_t)
194 * camel_file_util_decode_time_t:
195 * @in: file to read from
196 * @dest: pointer to a variable to store the value in
198 * Decode a time_t value.
200 * Returns: %0 on success, %-1 on error.
202 CFU_DECODE_T (time_t)
205 * camel_file_util_encode_off_t:
206 * @out: file to output to
207 * @value: value to output
209 * Encode an off_t type.
211 * Returns: %0 on success, %-1 on error.
216 * camel_file_util_decode_off_t:
217 * @in: file to read from
218 * @dest: pointer to a variable to put the value in
220 * Decode an off_t type.
222 * Returns: %0 on success, %-1 on failure.
227 * camel_file_util_encode_gsize:
228 * @out: file to output to
229 * @value: value to output
231 * Encode an gsize type.
233 * Returns: %0 on success, %-1 on error.
238 * camel_file_util_decode_gsize:
239 * @in: file to read from
240 * @dest: pointer to a variable to put the value in
242 * Decode an gsize type.
244 * Returns: %0 on success, %-1 on failure.
249 * camel_file_util_encode_string:
250 * @out: file to output to
251 * @str: value to output
253 * Encode a normal string and save it in the output file.
255 * Returns: %0 on success, %-1 on error.
258 camel_file_util_encode_string (FILE *out,
264 return camel_file_util_encode_uint32 (out, 1);
266 if ((len = strlen (str)) > 65536)
269 if (camel_file_util_encode_uint32 (out, len + 1) == -1)
271 if (len == 0 || fwrite (str, len, 1, out) == 1)
277 * camel_file_util_decode_string:
278 * @in: file to read from
279 * @str: pointer to a variable to store the value in
281 * Decode a normal string from the input file.
283 * Returns: %0 on success, %-1 on error.
286 camel_file_util_decode_string (FILE *in,
292 if (camel_file_util_decode_uint32 (in, &len) == -1) {
303 ret = g_malloc (len + 1);
304 if (len > 0 && fread (ret, len, 1, in) != 1) {
316 * camel_file_util_encode_fixed_string:
317 * @out: file to output to
318 * @str: value to output
319 * @len: total-len of str to store
321 * Encode a normal string and save it in the output file.
322 * Unlike @camel_file_util_encode_string, it pads the
323 * @str with "NULL" bytes, if @len is > strlen(str)
325 * Returns: %0 on success, %-1 on error.
328 camel_file_util_encode_fixed_string (FILE *out,
334 /* Max size is 64K */
338 /* Don't allow empty strings to be written. */
342 buf = g_malloc0 (len);
343 g_strlcpy (buf, str, len);
345 if (fwrite (buf, len, 1, out) == len)
355 * camel_file_util_decode_fixed_string:
356 * @in: file to read from
357 * @str: pointer to a variable to store the value in
358 * @len: total-len to decode.
360 * Decode a normal string from the input file.
362 * Returns: %0 on success, %-1 on error.
365 camel_file_util_decode_fixed_string (FILE *in,
376 ret = g_malloc (len + 1);
377 if (len > 0 && fread (ret, len, 1, in) != 1) {
389 * camel_file_util_safe_filename:
390 * @name: string to 'flattened' into a safe filename
392 * 'Flattens' @name into a safe filename string by hex encoding any
393 * chars that may cause problems on the filesystem.
395 * Returns: a safe filename string.
398 camel_file_util_safe_filename (const gchar *name)
401 const gchar *unsafe_chars = "/?()'*<>:\"\\|";
403 const gchar *unsafe_chars = "/?()'*";
409 return camel_url_encode (name, unsafe_chars);
412 /* FIXME: poll() might be more efficient and more portable? */
416 * @fd: file descriptor
417 * @buf: buffer to fill
418 * @n: number of bytes to read into @buf
419 * @cancellable: optional #GCancellable object, or %NULL
420 * @error: return location for a #GError, or %NULL
422 * Cancellable libc read() replacement.
424 * Code that intends to be portable to Win32 should call this function
425 * only on file descriptors returned from open(), not on sockets.
427 * Returns: number of bytes read or -1 on fail. On failure, errno will
428 * be set appropriately.
434 GCancellable *cancellable,
440 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
445 cancel_fd = g_cancellable_get_fd (cancellable);
447 if (cancel_fd == -1) {
449 nread = read (fd, buf, n);
450 } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
453 gint errnosav, flags, fdmax;
456 flags = fcntl (fd, F_GETFL);
457 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
465 FD_SET (cancel_fd, &rdset);
466 fdmax = MAX (fd, cancel_fd) + 1;
467 tv.tv_sec = IO_TIMEOUT;
471 res = select (fdmax, &rdset, 0, 0, &tv);
476 else if (FD_ISSET (cancel_fd, &rdset)) {
481 nread = read (fd, buf, n);
482 } while (nread == -1 && errno == EINTR);
484 } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
487 fcntl (fd, F_SETFL, flags);
492 g_cancellable_release_fd (cancellable);
494 if (g_cancellable_set_error_if_cancelled (cancellable, error))
500 g_io_error_from_errno (errno),
501 "%s", g_strerror (errno));
508 * @fd: file descriptor
509 * @buf: buffer to write
510 * @n: number of bytes of @buf to write
511 * @cancellable: optional #GCancellable object, or %NULL
512 * @error: return location for a #GError, or %NULL
514 * Cancellable libc write() replacement.
516 * Code that intends to be portable to Win32 should call this function
517 * only on file descriptors returned from open(), not on sockets.
519 * Returns: number of bytes written or -1 on fail. On failure, errno will
520 * be set appropriately.
523 camel_write (gint fd,
526 GCancellable *cancellable,
529 gssize w, written = 0;
532 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
537 cancel_fd = g_cancellable_get_fd (cancellable);
539 if (cancel_fd == -1) {
542 w = write (fd, buf + written, n - written);
543 } while (w == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
546 } while (w != -1 && written < n);
549 gint errnosav, flags, fdmax;
552 flags = fcntl (fd, F_GETFL);
553 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
555 fdmax = MAX (fd, cancel_fd) + 1;
563 FD_SET (cancel_fd, &rdset);
564 tv.tv_sec = IO_TIMEOUT;
568 res = select (fdmax, &rdset, &wrset, 0, &tv);
574 else if (FD_ISSET (cancel_fd, &rdset))
578 w = write (fd, buf + written, n - written);
579 } while (w == -1 && errno == EINTR);
582 if (errno == EAGAIN || errno == EWOULDBLOCK)
587 } while (w != -1 && written < n);
590 fcntl (fd, F_SETFL, flags);
595 g_cancellable_release_fd (cancellable);
597 if (g_cancellable_set_error_if_cancelled (cancellable, error))
603 g_io_error_from_errno (errno),
604 "%s", g_strerror (errno));
614 * @buf: buffer to fill
615 * @n: number of bytes to read into @buf
616 * @cancellable: optional #GCancellable object, or %NULL
617 * @error: return location for a #GError, or %NULL
619 * Cancellable read() replacement for sockets. Code that intends to be
620 * portable to Win32 should call this function only on sockets
621 * returned from socket(), or accept().
623 * Returns: number of bytes read or -1 on fail. On failure, errno will
624 * be set appropriately. If the socket is nonblocking
625 * camel_read_socket() will retry the read until it gets something.
628 camel_read_socket (gint fd,
631 GCancellable *cancellable,
635 return camel_read (fd, buf, n, cancellable, error);
640 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
645 cancel_fd = g_cancellable_get_fd (cancellable);
647 if (cancel_fd == -1) {
649 nread = recv (fd, buf, n, 0);
650 } while (nread == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK);
656 ioctlsocket (fd, FIONBIO, &yes);
657 fdmax = MAX (fd, cancel_fd) + 1;
664 FD_SET (cancel_fd, &rdset);
665 tv.tv_sec = IO_TIMEOUT;
669 res = select (fdmax, &rdset, 0, 0, &tv);
674 else if (FD_ISSET (cancel_fd, &rdset)) {
678 nread = recv (fd, buf, n, 0);
680 } while (nread == -1 && WSAGetLastError () == WSAEWOULDBLOCK);
685 g_cancellable_release_fd (cancellable);
687 if (g_cancellable_set_error_if_cancelled (cancellable, error))
693 g_io_error_from_errno (errno),
694 "%s", g_strerror (errno));
701 * camel_write_socket:
702 * @fd: file descriptor
703 * @buf: buffer to write
704 * @n: number of bytes of @buf to write
705 * @error: return location for a #GError, or %NULL
707 * Cancellable write() replacement for sockets. Code that intends to
708 * be portable to Win32 should call this function only on sockets
709 * returned from socket() or accept().
711 * Returns: number of bytes written or -1 on fail. On failure, errno will
712 * be set appropriately.
715 camel_write_socket (gint fd,
718 GCancellable *cancellable,
722 return camel_write (fd, buf, n, cancellable, error);
724 gssize w, written = 0;
727 if (g_cancellable_is_cancelled (cancellable)) {
731 G_IO_ERROR_CANCELLED,
736 cancel_fd = g_cancellable_get_fd (cancellable);
738 if (cancel_fd == -1) {
741 w = send (fd, buf + written, n - written, 0);
742 } while (w == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK);
745 } while (w != -1 && written < n);
751 ioctlsocket (fd, FIONBIO, &arg);
752 fdmax = MAX (fd, cancel_fd) + 1;
760 FD_SET (cancel_fd, &rdset);
761 tv.tv_sec = IO_TIMEOUT;
765 res = select (fdmax, &rdset, &wrset, 0, &tv);
766 if (res == SOCKET_ERROR) {
767 /* w still being -1 will catch this */
770 else if (FD_ISSET (cancel_fd, &rdset))
773 w = send (fd, buf + written, n - written, 0);
774 if (w == SOCKET_ERROR) {
775 if (WSAGetLastError () == WSAEWOULDBLOCK)
780 } while (w != -1 && written < n);
782 ioctlsocket (fd, FIONBIO, &arg);
785 g_cancellable_release_fd (cancellable);
787 if (g_cancellable_set_error_if_cancelled (cancellable, error))
793 g_io_error_from_errno (errno),
794 "%s", g_strerror (errno));
803 * camel_file_util_savename:
804 * @filename: a pathname
806 * Builds a pathname where the basename is of the form ".#" + the
807 * basename of @filename, for instance used in a two-stage commit file
810 * Returns: The new pathname. It must be free'd with g_free().
813 camel_file_util_savename (const gchar *filename)
815 gchar *dirname, *retval;
817 dirname = g_path_get_dirname (filename);
819 if (strcmp (dirname, ".") == 0) {
820 retval = g_strconcat (".#", filename, NULL);
822 gchar *basename = g_path_get_basename (filename);
823 gchar *newbasename = g_strconcat (".#", basename, NULL);
825 retval = g_build_filename (dirname, newbasename, NULL);
827 g_free (newbasename);