~ubuntu-branches/ubuntu/edgy/dovecot/edgy-security

« back to all changes in this revision

Viewing changes to src/lib/file-copy.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2006-06-30 15:13:37 UTC
  • mfrom: (1.10.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060630151337-l772crcoe5hfd4hw
Tags: 1.0.rc1-1ubuntu1
Merge from debian unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2006 Timo Sirainen */
 
2
 
 
3
#include "lib.h"
 
4
#include "istream.h"
 
5
#include "ostream.h"
 
6
#include "file-copy.h"
 
7
 
 
8
#include <stdio.h>
 
9
#include <unistd.h>
 
10
#include <fcntl.h>
 
11
 
 
12
static int file_copy_to_tmp(const char *srcpath, const char *tmppath,
 
13
                            bool try_hardlink)
 
14
{
 
15
        struct istream *input;
 
16
        struct ostream *output;
 
17
        int fd_in, fd_out;
 
18
        off_t ret;
 
19
 
 
20
        if (try_hardlink) {
 
21
                /* see if hardlinking works */
 
22
                if (link(srcpath, tmppath) == 0)
 
23
                        return 1;
 
24
                if (errno == EEXIST) {
 
25
                        if (unlink(tmppath) < 0 && errno != ENOENT) {
 
26
                                i_error("unlink(%s) failed: %m", tmppath);
 
27
                                return -1;
 
28
                        }
 
29
                        if (link(srcpath, tmppath) == 0)
 
30
                                return 1;
 
31
                }
 
32
                if (errno == ENOENT)
 
33
                        return 0;
 
34
                if (!ECANTLINK(errno)) {
 
35
                        i_error("link(%s, %s) failed: %m", srcpath, tmppath);
 
36
                        return -1;
 
37
                }
 
38
 
 
39
                /* fallback to manual copying */
 
40
        }
 
41
 
 
42
        fd_in = open(srcpath, O_RDONLY);
 
43
        if (fd_in == -1) {
 
44
                if (errno == ENOENT)
 
45
                        return 0;
 
46
                i_error("open(%s) failed: %m", srcpath);
 
47
                return -1;
 
48
        }
 
49
 
 
50
        fd_out = open(tmppath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 
51
        if (fd_out == -1) {
 
52
                i_error("open(%s, O_CREAT) failed: %m", tmppath);
 
53
                (void)close(fd_in);
 
54
                return -1;
 
55
        }
 
56
        input = i_stream_create_file(fd_in, default_pool, 0, FALSE);
 
57
        output = o_stream_create_file(fd_out, default_pool, 0, FALSE);
 
58
 
 
59
        while ((ret = o_stream_send_istream(output, input)) > 0) ;
 
60
 
 
61
        i_stream_destroy(&input);
 
62
        o_stream_destroy(&output);
 
63
 
 
64
        if (close(fd_in) < 0) {
 
65
                i_error("close(%s) failed: %m", srcpath);
 
66
                ret = -1;
 
67
        }
 
68
        if (close(fd_out) < 0) {
 
69
                i_error("close(%s) failed: %m", tmppath);
 
70
                ret = -1;
 
71
        }
 
72
        return ret < 0 ? -1 : 1;
 
73
}
 
74
 
 
75
int file_copy(const char *srcpath, const char *destpath, bool try_hardlink)
 
76
{
 
77
        const char *tmppath;
 
78
        int ret;
 
79
 
 
80
        t_push();
 
81
        tmppath = t_strconcat(destpath, ".tmp", NULL);
 
82
 
 
83
        ret = file_copy_to_tmp(srcpath, tmppath, try_hardlink);
 
84
        if (ret > 0) {
 
85
                if (rename(tmppath, destpath) < 0) {
 
86
                        i_error("rename(%s, %s) failed: %m", tmppath, destpath);
 
87
                        ret = -1;
 
88
                }
 
89
        }
 
90
        if (ret < 0)
 
91
                (void)unlink(tmppath);
 
92
 
 
93
        t_pop();
 
94
        return ret;
 
95
}