Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-file-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Authors:
4  *   Michael Zucchi <notzed@ximian.com>
5  *   Jeffrey Stedfast <fejj@ximian.com>
6  *   Dan Winship <danw@ximian.com>
7  *
8  * Copyright (C) 2000, 2003 Ximian, Inc.
9  *
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.
13  *
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.
18  *
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
22  * USA
23  */
24
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include <glib.h>
38
39 #ifdef G_OS_WIN32
40 #include <winsock2.h>
41 #define EWOULDBLOCK EAGAIN
42 #endif
43
44 #include <libedataserver/e-data-server-util.h>
45
46 #include "camel-file-utils.h"
47 #include "camel-operation.h"
48 #include "camel-url.h"
49
50 #define IO_TIMEOUT (60*4)
51
52 /**
53  * camel_file_util_encode_uint32:
54  * @out: file to output to
55  * @value: value to output
56  * 
57  * Utility function to save an uint32 to a file.
58  * 
59  * Return value: 0 on success, -1 on error.
60  **/
61 int
62 camel_file_util_encode_uint32 (FILE *out, guint32 value)
63 {
64         int i;
65
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)
70                                 return -1;
71                 }
72         }
73         return fputc (value | 0x80, out);
74 }
75
76
77 /**
78  * camel_file_util_decode_uint32:
79  * @in: file to read from
80  * @dest: pointer to a variable to store the value in
81  * 
82  * Retrieve an encoded uint32 from a file.
83  * 
84  * Return value: 0 on success, -1 on error.  @*dest will contain the
85  * decoded value.
86  **/
87 int
88 camel_file_util_decode_uint32 (FILE *in, guint32 *dest)
89 {
90         guint32 value = 0;
91         int v;
92
93         /* until we get the last byte, keep decoding 7 bits at a time */
94         while ( ((v = fgetc (in)) & 0x80) == 0 && v!=EOF) {
95                 value |= v;
96                 value <<= 7;
97         }
98         if (v == EOF) {
99                 *dest = value >> 7;
100                 return -1;
101         }
102         *dest = value | (v & 0x7f);
103
104         return 0;
105 }
106
107
108 /**
109  * camel_file_util_encode_fixed_int32:
110  * @out: file to output to
111  * @value: value to output
112  * 
113  * Encode a gint32, performing no compression, but converting
114  * to network order.
115  * 
116  * Return value: 0 on success, -1 on error.
117  **/
118 int
119 camel_file_util_encode_fixed_int32 (FILE *out, gint32 value)
120 {
121         guint32 save;
122
123         save = g_htonl (value);
124         if (fwrite (&save, sizeof (save), 1, out) != 1)
125                 return -1;
126         return 0;
127 }
128
129
130 /**
131  * camel_file_util_decode_fixed_int32:
132  * @in: file to read from
133  * @dest: pointer to a variable to store the value in
134  * 
135  * Retrieve a gint32.
136  * 
137  * Return value: 0 on success, -1 on error.
138  **/
139 int
140 camel_file_util_decode_fixed_int32 (FILE *in, gint32 *dest)
141 {
142         guint32 save;
143
144         if (fread (&save, sizeof (save), 1, in) == 1) {
145                 *dest = g_ntohl (save);
146                 return 0;
147         } else {
148                 return -1;
149         }
150 }
151
152 #define CFU_ENCODE_T(type)                                              \
153 int                                                                     \
154 camel_file_util_encode_##type(FILE *out, type value)                    \
155 {                                                                       \
156         int i;                                                          \
157                                                                         \
158         for (i = sizeof (type) - 1; i >= 0; i--) {                      \
159                 if (fputc((value >> (i * 8)) & 0xff, out) == -1)        \
160                         return -1;                                      \
161         }                                                               \
162         return 0;                                                       \
163 }
164
165 #define CFU_DECODE_T(type)                              \
166 int                                                     \
167 camel_file_util_decode_##type(FILE *in, type *dest)     \
168 {                                                       \
169         type save = 0;                                  \
170         int i = sizeof(type) - 1;                       \
171         int v = EOF;                                    \
172                                                         \
173         while (i >= 0 && (v = fgetc (in)) != EOF) {     \
174                 save |= ((type)v) << (i * 8);           \
175                 i--;                                    \
176         }                                               \
177         *dest = save;                                   \
178         if (v == EOF)                                   \
179                 return -1;                              \
180         return 0;                                       \
181 }
182
183
184 /**
185  * camel_file_util_encode_time_t:
186  * @out: file to output to
187  * @value: value to output
188  * 
189  * Encode a time_t value to the file.
190  * 
191  * Return value: 0 on success, -1 on error.
192  **/
193 CFU_ENCODE_T(time_t)
194
195 /**
196  * camel_file_util_decode_time_t:
197  * @in: file to read from
198  * @dest: pointer to a variable to store the value in
199  * 
200  * Decode a time_t value.
201  * 
202  * Return value: 0 on success, -1 on error.
203  **/
204 CFU_DECODE_T(time_t)
205
206 /**
207  * camel_file_util_encode_off_t:
208  * @out: file to output to
209  * @value: value to output
210  * 
211  * Encode an off_t type.
212  * 
213  * Return value: 0 on success, -1 on error.
214  **/
215 CFU_ENCODE_T(off_t)
216
217
218 /**
219  * camel_file_util_decode_off_t:
220  * @in: file to read from
221  * @dest: pointer to a variable to put the value in
222  * 
223  * Decode an off_t type.
224  * 
225  * Return value: 0 on success, -1 on failure.
226  **/
227 CFU_DECODE_T(off_t)
228
229 /**
230  * camel_file_util_encode_size_t:
231  * @out: file to output to
232  * @value: value to output
233  * 
234  * Encode an size_t type.
235  * 
236  * Return value: 0 on success, -1 on error.
237  **/
238 CFU_ENCODE_T(size_t)
239
240
241 /**
242  * camel_file_util_decode_size_t:
243  * @in: file to read from
244  * @dest: pointer to a variable to put the value in
245  * 
246  * Decode an size_t type.
247  * 
248  * Return value: 0 on success, -1 on failure.
249  **/
250 CFU_DECODE_T(size_t)
251
252
253 /**
254  * camel_file_util_encode_string:
255  * @out: file to output to
256  * @str: value to output
257  * 
258  * Encode a normal string and save it in the output file.
259  * 
260  * Return value: 0 on success, -1 on error.
261  **/
262 int
263 camel_file_util_encode_string (FILE *out, const char *str)
264 {
265         register int len;
266
267         if (str == NULL)
268                 return camel_file_util_encode_uint32 (out, 1);
269         
270         if ((len = strlen (str)) > 65536)
271                 len = 65536;
272         
273         if (camel_file_util_encode_uint32 (out, len+1) == -1)
274                 return -1;
275         if (len == 0 || fwrite (str, len, 1, out) == 1)
276                 return 0;
277         return -1;
278 }
279
280
281 /**
282  * camel_file_util_decode_string:
283  * @in: file to read from
284  * @str: pointer to a variable to store the value in
285  * 
286  * Decode a normal string from the input file.
287  * 
288  * Return value: 0 on success, -1 on error.
289  **/
290 int
291 camel_file_util_decode_string (FILE *in, char **str)
292 {
293         guint32 len;
294         register char *ret;
295
296         if (camel_file_util_decode_uint32 (in, &len) == -1) {
297                 *str = NULL;
298                 return -1;
299         }
300
301         len--;
302         if (len > 65536) {
303                 *str = NULL;
304                 return -1;
305         }
306
307         ret = g_malloc (len+1);
308         if (len > 0 && fread (ret, len, 1, in) != 1) {
309                 g_free (ret);
310                 *str = NULL;
311                 return -1;
312         }
313
314         ret[len] = 0;
315         *str = ret;
316         return 0;
317 }
318
319 /**
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
324  * 
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)
328  * 
329  * Return value: 0 on success, -1 on error.
330  **/
331 int
332 camel_file_util_encode_fixed_string (FILE *out, const char *str, size_t len)
333 {
334         char buf[len];
335
336         /* Don't allow empty strings to be written */
337         if (len < 1)
338                 return -1;
339
340         /* Max size is 64K */
341         if (len > 65536)
342                 len = 65536;
343                 
344         memset(buf, 0x00, len);
345         g_strlcpy(buf, str, len);
346
347         if (fwrite (buf, len, 1, out) == len)
348                 return 0;
349
350         return -1;
351 }
352
353
354 /**
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.  
359  * 
360  * Decode a normal string from the input file.
361  * 
362  * Return value: 0 on success, -1 on error.
363  **/
364 int
365 camel_file_util_decode_fixed_string (FILE *in, char **str, size_t len)
366 {
367         register char *ret;
368
369         if (len > 65536) {
370                 *str = NULL;
371                 return -1;
372         }
373
374         ret = g_malloc (len+1);
375         if (len > 0 && fread (ret, len, 1, in) != 1) {
376                 g_free (ret);
377                 *str = NULL;
378                 return -1;
379         }
380
381         ret[len] = 0;
382         *str = ret;
383         return 0;
384 }
385
386 /**
387  * camel_file_util_safe_filename:
388  * @name: string to 'flattened' into a safe filename
389  *
390  * 'Flattens' @name into a safe filename string by hex encoding any
391  * chars that may cause problems on the filesystem.
392  *
393  * Returns a safe filename string.
394  **/
395 char *
396 camel_file_util_safe_filename (const char *name)
397 {
398 #ifdef G_OS_WIN32
399         const char *unsafe_chars = "/?()'*<>:\"\\|";
400 #else
401         const char *unsafe_chars = "/?()'*";
402 #endif
403
404         if (name == NULL)
405                 return NULL;
406         
407         return camel_url_encode(name, unsafe_chars);
408 }
409
410
411 /* FIXME: poll() might be more efficient and more portable? */
412
413 /**
414  * camel_read:
415  * @fd: file descriptor
416  * @buf: buffer to fill
417  * @n: number of bytes to read into @buf
418  *
419  * Cancellable libc read() replacement.
420  *
421  * Code that intends to be portable to Win32 should call this function
422  * only on file descriptors returned from open(), not on sockets.
423  *
424  * Returns number of bytes read or -1 on fail. On failure, errno will
425  * be set appropriately.
426  **/
427 ssize_t
428 camel_read (int fd, char *buf, size_t n)
429 {
430         ssize_t nread;
431         int cancel_fd;
432         
433         if (camel_operation_cancel_check (NULL)) {
434                 errno = EINTR;
435                 return -1;
436         }
437 #ifndef G_OS_WIN32
438         cancel_fd = camel_operation_cancel_fd (NULL);
439 #else
440         cancel_fd = -1;
441 #endif
442         if (cancel_fd == -1) {
443                 do {
444                         nread = read (fd, buf, n);
445                 } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
446         } else {
447 #ifndef G_OS_WIN32
448                 int errnosav, flags, fdmax;
449                 fd_set rdset;
450                 
451                 flags = fcntl (fd, F_GETFL);
452                 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
453                 
454                 do {
455                         struct timeval tv;
456                         int res;
457
458                         FD_ZERO (&rdset);
459                         FD_SET (fd, &rdset);
460                         FD_SET (cancel_fd, &rdset);
461                         fdmax = MAX (fd, cancel_fd) + 1;
462                         tv.tv_sec = IO_TIMEOUT;
463                         tv.tv_usec = 0;
464                         nread = -1;
465
466                         res = select(fdmax, &rdset, 0, 0, &tv);
467                         if (res == -1)
468                                 ;
469                         else if (res == 0)
470                                 errno = ETIMEDOUT;
471                         else if (FD_ISSET (cancel_fd, &rdset)) {
472                                 errno = EINTR;
473                                 goto failed;
474                         } else {                                
475                                 do {
476                                         nread = read (fd, buf, n);
477                                 } while (nread == -1 && errno == EINTR);
478                         }
479                 } while (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
480         failed:
481                 errnosav = errno;
482                 fcntl (fd, F_SETFL, flags);
483                 errno = errnosav;
484 #endif
485         }
486         
487         return nread;
488 }
489
490
491 /**
492  * camel_write:
493  * @fd: file descriptor
494  * @buf: buffer to write
495  * @n: number of bytes of @buf to write
496  *
497  * Cancellable libc write() replacement.
498  *
499  * Code that intends to be portable to Win32 should call this function
500  * only on file descriptors returned from open(), not on sockets.
501  *
502  * Returns number of bytes written or -1 on fail. On failure, errno will
503  * be set appropriately.
504  **/
505 ssize_t
506 camel_write (int fd, const char *buf, size_t n)
507 {
508         ssize_t w, written = 0;
509         int cancel_fd;
510         
511         if (camel_operation_cancel_check (NULL)) {
512                 errno = EINTR;
513                 return -1;
514         }
515 #ifndef G_OS_WIN32
516         cancel_fd = camel_operation_cancel_fd (NULL);
517 #else
518         cancel_fd = -1;
519 #endif
520         if (cancel_fd == -1) {
521                 do {
522                         do {
523                                 w = write (fd, buf + written, n - written);
524                         } while (w == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
525                         if (w > 0)
526                                 written += w;
527                 } while (w != -1 && written < n);
528         } else {
529 #ifndef G_OS_WIN32
530                 int errnosav, flags, fdmax;
531                 fd_set rdset, wrset;
532                 
533                 flags = fcntl (fd, F_GETFL);
534                 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
535                 
536                 fdmax = MAX (fd, cancel_fd) + 1;
537                 do {
538                         struct timeval tv;
539                         int res;
540
541                         FD_ZERO (&rdset);
542                         FD_ZERO (&wrset);
543                         FD_SET (fd, &wrset);
544                         FD_SET (cancel_fd, &rdset);
545                         tv.tv_sec = IO_TIMEOUT;
546                         tv.tv_usec = 0;                 
547                         w = -1;
548
549                         res = select (fdmax, &rdset, &wrset, 0, &tv);
550                         if (res == -1) {
551                                 if (errno == EINTR)
552                                         w = 0;
553                         } else if (res == 0)
554                                 errno = ETIMEDOUT;
555                         else if (FD_ISSET (cancel_fd, &rdset))
556                                 errno = EINTR;
557                         else {
558                                 do {
559                                         w = write (fd, buf + written, n - written);
560                                 } while (w == -1 && errno == EINTR);
561                                 
562                                 if (w == -1) {
563                                         if (errno == EAGAIN || errno == EWOULDBLOCK)
564                                                 w = 0;
565                                 } else
566                                         written += w;
567                         }
568                 } while (w != -1 && written < n);
569                 
570                 errnosav = errno;
571                 fcntl (fd, F_SETFL, flags);
572                 errno = errnosav;
573 #endif
574         }
575         
576         if (w == -1)
577                 return -1;
578         
579         return written;
580 }
581
582 /**
583  * camel_read_socket:
584  * @fd: a socket
585  * @buf: buffer to fill
586  * @n: number of bytes to read into @buf
587  *
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().
591  *
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.
595  **/
596 ssize_t
597 camel_read_socket (int fd, char *buf, size_t n)
598 {
599 #ifndef G_OS_WIN32
600         return camel_read (fd, buf, n);
601 #else
602         ssize_t nread;
603         int cancel_fd;
604         
605         if (camel_operation_cancel_check (NULL)) {
606                 errno = EINTR;
607                 return -1;
608         }
609         cancel_fd = camel_operation_cancel_fd (NULL);
610
611         if (cancel_fd == -1) {
612                 do {
613                         nread = recv (fd, buf, n, 0);
614                 } while (nread == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK);
615         } else {
616                 int fdmax;
617                 fd_set rdset;
618                 u_long yes = 1;
619
620                 ioctlsocket (fd, FIONBIO, &yes);
621                 fdmax = MAX (fd, cancel_fd) + 1;
622                 do {
623                         struct timeval tv;
624                         int res;
625
626                         FD_ZERO (&rdset);
627                         FD_SET (fd, &rdset);
628                         FD_SET (cancel_fd, &rdset);
629                         tv.tv_sec = IO_TIMEOUT;
630                         tv.tv_usec = 0;
631                         nread = -1;
632
633                         res = select(fdmax, &rdset, 0, 0, &tv);
634                         if (res == -1)
635                                 ;
636                         else if (res == 0)
637                                 errno = ETIMEDOUT;
638                         else if (FD_ISSET (cancel_fd, &rdset)) {
639                                 errno = EINTR;
640                                 goto failed;
641                         } else {                                
642                                 nread = recv (fd, buf, n, 0);
643                         }
644                 } while (nread == -1 && WSAGetLastError () == WSAEWOULDBLOCK);
645         failed:
646                 ;
647         }
648         
649         return nread;
650 #endif
651 }
652
653 /**
654  * camel_write_socket:
655  * @fd: file descriptor
656  * @buf: buffer to write
657  * @n: number of bytes of @buf to write
658  *
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().
662  *
663  * Returns number of bytes written or -1 on fail. On failure, errno will
664  * be set appropriately.
665  **/
666 ssize_t
667 camel_write_socket (int fd, const char *buf, size_t n)
668 {
669 #ifndef G_OS_WIN32
670         return camel_write (fd, buf, n);
671 #else
672         ssize_t w, written = 0;
673         int cancel_fd;
674         
675         if (camel_operation_cancel_check (NULL)) {
676                 errno = EINTR;
677                 return -1;
678         }
679
680         cancel_fd = camel_operation_cancel_fd (NULL);
681         if (cancel_fd == -1) {
682                 do {
683                         do {
684                                 w = send (fd, buf + written, n - written, 0);
685                         } while (w == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK);
686                         if (w > 0)
687                                 written += w;
688                 } while (w != -1 && written < n);
689         } else {
690                 int fdmax;
691                 fd_set rdset, wrset;
692                 u_long arg = 1;
693
694                 ioctlsocket (fd, FIONBIO, &arg);
695                 fdmax = MAX (fd, cancel_fd) + 1;
696                 do {
697                         struct timeval tv;
698                         int res;
699
700                         FD_ZERO (&rdset);
701                         FD_ZERO (&wrset);
702                         FD_SET (fd, &wrset);
703                         FD_SET (cancel_fd, &rdset);
704                         tv.tv_sec = IO_TIMEOUT;
705                         tv.tv_usec = 0;                 
706                         w = -1;
707
708                         res = select (fdmax, &rdset, &wrset, 0, &tv);
709                         if (res == SOCKET_ERROR) {
710                                 /* w still being -1 will catch this */
711                         } else if (res == 0)
712                                 errno = ETIMEDOUT;
713                         else if (FD_ISSET (cancel_fd, &rdset))
714                                 errno = EINTR;
715                         else {
716                                 w = send (fd, buf + written, n - written, 0);
717                                 if (w == SOCKET_ERROR) {
718                                         if (WSAGetLastError () == WSAEWOULDBLOCK)
719                                                 w = 0;
720                                 } else
721                                         written += w;
722                         }
723                 } while (w != -1 && written < n);
724                 arg = 0;
725                 ioctlsocket (fd, FIONBIO, &arg);
726         }
727         
728         if (w == -1)
729                 return -1;
730         
731         return written;
732 #endif
733 }
734
735
736 /**
737  * camel_file_util_savename:
738  * @filename: a pathname
739  * 
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
742  * write.
743  * 
744  * Return value: The new pathname.  It must be free'd with g_free().
745  **/
746 char *
747 camel_file_util_savename(const char *filename)
748 {
749         char *dirname, *retval;
750
751         dirname = g_path_get_dirname(filename);
752
753         if (strcmp (dirname, ".") == 0) {
754                 retval = g_strconcat (".#", filename, NULL);
755         } else {
756                 char *basename = g_path_get_basename(filename);
757                 char *newbasename = g_strconcat (".#", basename, NULL);
758
759                 retval = g_build_filename (dirname, newbasename, NULL);
760
761                 g_free (newbasename);
762                 g_free (basename);
763         }
764         g_free (dirname);
765
766         return retval;
767 }