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) 2000, 2003 Ximian, Inc.
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
35 #include <sys/types.h>
41 #define EWOULDBLOCK EAGAIN
44 #include <libedataserver/e-data-server-util.h>
46 #include "camel-file-utils.h"
47 #include "camel-operation.h"
48 #include "camel-url.h"
50 #define IO_TIMEOUT (60*4)
53 * camel_file_util_encode_uint32:
54 * @out: file to output to
55 * @value: value to output
57 * Utility function to save an uint32 to a file.
59 * Return value: 0 on success, -1 on error.
62 camel_file_util_encode_uint32 (FILE *out, guint32 value)
66 for (i = 28; i > 0; i -= 7) {
67 if (value >= (1 << i)) {
68 unsigned int c = (value >> i) & 0x7f;
69 if (fputc (c, out) == -1)
73 return fputc (value | 0x80, out);
78 * camel_file_util_decode_uint32:
79 * @in: file to read from
80 * @dest: pointer to a variable to store the value in
82 * Retrieve an encoded uint32 from a file.
84 * Return value: 0 on success, -1 on error. @*dest will contain the
88 camel_file_util_decode_uint32 (FILE *in, guint32 *dest)
93 /* until we get the last byte, keep decoding 7 bits at a time */
94 while ( ((v = fgetc (in)) & 0x80) == 0 && v!=EOF) {
102 *dest = value | (v & 0x7f);
109 * camel_file_util_encode_fixed_int32:
110 * @out: file to output to
111 * @value: value to output
113 * Encode a gint32, performing no compression, but converting
116 * Return value: 0 on success, -1 on error.
119 camel_file_util_encode_fixed_int32 (FILE *out, gint32 value)
123 save = g_htonl (value);
124 if (fwrite (&save, sizeof (save), 1, out) != 1)
131 * camel_file_util_decode_fixed_int32:
132 * @in: file to read from
133 * @dest: pointer to a variable to store the value in
137 * Return value: 0 on success, -1 on error.
140 camel_file_util_decode_fixed_int32 (FILE *in, gint32 *dest)
144 if (fread (&save, sizeof (save), 1, in) == 1) {
145 *dest = g_ntohl (save);
152 #define CFU_ENCODE_T(type) \
154 camel_file_util_encode_##type(FILE *out, type value) \
158 for (i = sizeof (type) - 1; i >= 0; i--) { \
159 if (fputc((value >> (i * 8)) & 0xff, out) == -1) \
165 #define CFU_DECODE_T(type) \
167 camel_file_util_decode_##type(FILE *in, type *dest) \
170 int i = sizeof(type) - 1; \
173 while (i >= 0 && (v = fgetc (in)) != EOF) { \
174 save |= ((type)v) << (i * 8); \
185 * camel_file_util_encode_time_t:
186 * @out: file to output to
187 * @value: value to output
189 * Encode a time_t value to the file.
191 * Return value: 0 on success, -1 on error.
196 * camel_file_util_decode_time_t:
197 * @in: file to read from
198 * @dest: pointer to a variable to store the value in
200 * Decode a time_t value.
202 * Return value: 0 on success, -1 on error.
207 * camel_file_util_encode_off_t:
208 * @out: file to output to
209 * @value: value to output
211 * Encode an off_t type.
213 * Return value: 0 on success, -1 on error.
219 * camel_file_util_decode_off_t:
220 * @in: file to read from
221 * @dest: pointer to a variable to put the value in
223 * Decode an off_t type.
225 * Return value: 0 on success, -1 on failure.
230 * camel_file_util_encode_size_t:
231 * @out: file to output to
232 * @value: value to output
234 * Encode an size_t type.
236 * Return value: 0 on success, -1 on error.
242 * camel_file_util_decode_size_t:
243 * @in: file to read from
244 * @dest: pointer to a variable to put the value in
246 * Decode an size_t type.
248 * Return value: 0 on success, -1 on failure.
254 * camel_file_util_encode_string:
255 * @out: file to output to
256 * @str: value to output
258 * Encode a normal string and save it in the output file.
260 * Return value: 0 on success, -1 on error.
263 camel_file_util_encode_string (FILE *out, const char *str)
268 return camel_file_util_encode_uint32 (out, 1);
270 if ((len = strlen (str)) > 65536)
273 if (camel_file_util_encode_uint32 (out, len+1) == -1)
275 if (len == 0 || fwrite (str, len, 1, out) == 1)
282 * camel_file_util_decode_string:
283 * @in: file to read from
284 * @str: pointer to a variable to store the value in
286 * Decode a normal string from the input file.
288 * Return value: 0 on success, -1 on error.
291 camel_file_util_decode_string (FILE *in, char **str)
296 if (camel_file_util_decode_uint32 (in, &len) == -1) {
307 ret = g_malloc (len+1);
308 if (len > 0 && fread (ret, len, 1, in) != 1) {
320 * camel_file_util_encode_fixed_string:
321 * @out: file to output to
322 * @str: value to output
323 * @len: total-len of str to store
325 * Encode a normal string and save it in the output file.
326 * Unlike @camel_file_util_encode_string, it pads the
327 * @str with "NULL" bytes, if @len is > strlen(str)
329 * Return value: 0 on success, -1 on error.
332 camel_file_util_encode_fixed_string (FILE *out, const char *str, size_t len)
336 /* Don't allow empty strings to be written */
340 /* Max size is 64K */
344 memset(buf, 0x00, len);
345 g_strlcpy(buf, str, len);
347 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 * Return value: 0 on success, -1 on error.
365 camel_file_util_decode_fixed_string (FILE *in, char **str, size_t len)
374 ret = g_malloc (len+1);
375 if (len > 0 && fread (ret, len, 1, in) != 1) {
387 * camel_file_util_safe_filename:
388 * @name: string to 'flattened' into a safe filename
390 * 'Flattens' @name into a safe filename string by hex encoding any
391 * chars that may cause problems on the filesystem.
393 * Returns a safe filename string.
396 camel_file_util_safe_filename (const char *name)
399 const char *unsafe_chars = "/?()'*<>:\"\\|";
401 const char *unsafe_chars = "/?()'*";
407 return camel_url_encode(name, unsafe_chars);
411 /* FIXME: poll() might be more efficient and more portable? */
415 * @fd: file descriptor
416 * @buf: buffer to fill
417 * @n: number of bytes to read into @buf
419 * Cancellable libc read() replacement.
421 * Code that intends to be portable to Win32 should call this function
422 * only on file descriptors returned from open(), not on sockets.
424 * Returns number of bytes read or -1 on fail. On failure, errno will
425 * be set appropriately.
428 camel_read (int fd, char *buf, size_t n)
433 if (camel_operation_cancel_check (NULL)) {
438 cancel_fd = camel_operation_cancel_fd (NULL);
442 if (cancel_fd == -1) {
444 nread = read (fd, buf, n);
445 } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
448 int errnosav, flags, fdmax;
451 flags = fcntl (fd, F_GETFL);
452 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
460 FD_SET (cancel_fd, &rdset);
461 fdmax = MAX (fd, cancel_fd) + 1;
462 tv.tv_sec = IO_TIMEOUT;
466 res = select(fdmax, &rdset, 0, 0, &tv);
471 else if (FD_ISSET (cancel_fd, &rdset)) {
476 nread = read (fd, buf, n);
477 } while (nread == -1 && errno == EINTR);
479 } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
482 fcntl (fd, F_SETFL, flags);
493 * @fd: file descriptor
494 * @buf: buffer to write
495 * @n: number of bytes of @buf to write
497 * Cancellable libc write() replacement.
499 * Code that intends to be portable to Win32 should call this function
500 * only on file descriptors returned from open(), not on sockets.
502 * Returns number of bytes written or -1 on fail. On failure, errno will
503 * be set appropriately.
506 camel_write (int fd, const char *buf, size_t n)
508 ssize_t w, written = 0;
511 if (camel_operation_cancel_check (NULL)) {
516 cancel_fd = camel_operation_cancel_fd (NULL);
520 if (cancel_fd == -1) {
523 w = write (fd, buf + written, n - written);
524 } while (w == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
527 } while (w != -1 && written < n);
530 int errnosav, flags, fdmax;
533 flags = fcntl (fd, F_GETFL);
534 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
536 fdmax = MAX (fd, cancel_fd) + 1;
544 FD_SET (cancel_fd, &rdset);
545 tv.tv_sec = IO_TIMEOUT;
549 res = select (fdmax, &rdset, &wrset, 0, &tv);
555 else if (FD_ISSET (cancel_fd, &rdset))
559 w = write (fd, buf + written, n - written);
560 } while (w == -1 && errno == EINTR);
563 if (errno == EAGAIN || errno == EWOULDBLOCK)
568 } while (w != -1 && written < n);
571 fcntl (fd, F_SETFL, flags);
585 * @buf: buffer to fill
586 * @n: number of bytes to read into @buf
588 * Cancellable read() replacement for sockets. Code that intends to be
589 * portable to Win32 should call this function only on sockets
590 * returned from socket(), or accept().
592 * Returns number of bytes read or -1 on fail. On failure, errno will
593 * be set appropriately. If the socket is nonblocking
594 * camel_read_socket() will retry the read until it gets something.
597 camel_read_socket (int fd, char *buf, size_t n)
600 return camel_read (fd, buf, n);
605 if (camel_operation_cancel_check (NULL)) {
609 cancel_fd = camel_operation_cancel_fd (NULL);
611 if (cancel_fd == -1) {
613 nread = recv (fd, buf, n, 0);
614 } while (nread == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK);
620 ioctlsocket (fd, FIONBIO, &yes);
621 fdmax = MAX (fd, cancel_fd) + 1;
628 FD_SET (cancel_fd, &rdset);
629 tv.tv_sec = IO_TIMEOUT;
633 res = select(fdmax, &rdset, 0, 0, &tv);
638 else if (FD_ISSET (cancel_fd, &rdset)) {
642 nread = recv (fd, buf, n, 0);
644 } while (nread == -1 && WSAGetLastError () == WSAEWOULDBLOCK);
654 * camel_write_socket:
655 * @fd: file descriptor
656 * @buf: buffer to write
657 * @n: number of bytes of @buf to write
659 * Cancellable write() replacement for sockets. Code that intends to
660 * be portable to Win32 should call this function only on sockets
661 * returned from socket() or accept().
663 * Returns number of bytes written or -1 on fail. On failure, errno will
664 * be set appropriately.
667 camel_write_socket (int fd, const char *buf, size_t n)
670 return camel_write (fd, buf, n);
672 ssize_t w, written = 0;
675 if (camel_operation_cancel_check (NULL)) {
680 cancel_fd = camel_operation_cancel_fd (NULL);
681 if (cancel_fd == -1) {
684 w = send (fd, buf + written, n - written, 0);
685 } while (w == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK);
688 } while (w != -1 && written < n);
694 ioctlsocket (fd, FIONBIO, &arg);
695 fdmax = MAX (fd, cancel_fd) + 1;
703 FD_SET (cancel_fd, &rdset);
704 tv.tv_sec = IO_TIMEOUT;
708 res = select (fdmax, &rdset, &wrset, 0, &tv);
709 if (res == SOCKET_ERROR) {
710 /* w still being -1 will catch this */
713 else if (FD_ISSET (cancel_fd, &rdset))
716 w = send (fd, buf + written, n - written, 0);
717 if (w == SOCKET_ERROR) {
718 if (WSAGetLastError () == WSAEWOULDBLOCK)
723 } while (w != -1 && written < n);
725 ioctlsocket (fd, FIONBIO, &arg);
737 * camel_file_util_savename:
738 * @filename: a pathname
740 * Builds a pathname where the basename is of the form ".#" + the
741 * basename of @filename, for instance used in a two-stage commit file
744 * Return value: The new pathname. It must be free'd with g_free().
747 camel_file_util_savename(const char *filename)
749 char *dirname, *retval;
751 dirname = g_path_get_dirname(filename);
753 if (strcmp (dirname, ".") == 0) {
754 retval = g_strconcat (".#", filename, NULL);
756 char *basename = g_path_get_basename(filename);
757 char *newbasename = g_strconcat (".#", basename, NULL);
759 retval = g_build_filename (dirname, newbasename, NULL);
761 g_free (newbasename);