~ubuntu-branches/ubuntu/breezy/fl-cow/breezy

« back to all changes in this revision

Viewing changes to fl-cow/fl-cow.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Collins
  • Date: 2005-05-28 17:27:21 UTC
  • Revision ID: james.westby@ubuntu.com-20050528172721-jj5vkjr77mx2awg7
Tags: upstream-0.4
ImportĀ upstreamĀ versionĀ 0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  FL-COW by Davide Libenzi ( File Links Copy On Write )
 
3
 *  Copyright (C) 2003  Davide Libenzi
 
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 2 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
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 *  Davide Libenzi <davidel@xmailserver.org>
 
20
 *
 
21
 */
 
22
 
 
23
#include <stdarg.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <unistd.h>
 
27
#include <fcntl.h>
 
28
#include <sys/types.h>
 
29
#include <sys/time.h>
 
30
#include <sys/stat.h>
 
31
#include <sys/uio.h>
 
32
#include <sys/mman.h>
 
33
#include <sys/file.h>
 
34
#include <sys/ioctl.h>
 
35
#include <stdio.h>
 
36
#include <time.h>
 
37
#include <errno.h>
 
38
#include <dlfcn.h>
 
39
 
 
40
 
 
41
#ifdef HAVE_CONFIG_H
 
42
#include "config.h"
 
43
#endif
 
44
 
 
45
 
 
46
#ifdef ENABLE_DEBUG
 
47
#define DPRINTF(format, args...) fprintf(stderr, format, ## args)
 
48
#else
 
49
#define DPRINTF(format, args...)
 
50
#endif
 
51
 
 
52
 
 
53
#ifndef RTLD_NEXT
 
54
#define RTLD_NEXT ((void *) -1L)
 
55
#endif
 
56
 
 
57
#define REAL_LIBC RTLD_NEXT
 
58
 
 
59
#define FLCLOW_MAXPATH 512
 
60
 
 
61
 
 
62
 
 
63
int open(const char *name, int flags, ...) __attribute__ ((weak, alias("__libc_open")));
 
64
int __open(const char *name, int flags, ...) __attribute__ ((weak, alias("__libc_open")));
 
65
int open64(const char *name, int flags, ...) __attribute__ ((weak, alias("__libc_open64")));
 
66
int __open64(const char *name, int flags, ...) __attribute__ ((weak, alias("__libc_open64")));
 
67
 
 
68
 
 
69
 
 
70
 
 
71
static int cow_name(const char *name) {
 
72
        int nlen, len;
 
73
        char const *home, *excld, *next;
 
74
        char fpath[FLCLOW_MAXPATH];
 
75
 
 
76
        nlen = strlen(name);
 
77
        if (*name != '/' && nlen < sizeof(fpath) - 1) {
 
78
                if (name[0] == '~' && name[1] == '/') {
 
79
                        if ((home = getenv("HOME")) != NULL) {
 
80
                                strncpy(fpath, home, sizeof(fpath) - 1);
 
81
                                name += 2;
 
82
                                nlen -= 2;
 
83
                        } else
 
84
                                fpath[0] = '\0';
 
85
                } else {
 
86
                        if (!getcwd(fpath, sizeof(fpath) - 1 - nlen))
 
87
                                fpath[0] = '\0';
 
88
                }
 
89
                if ((len = strlen(fpath)) + nlen + 2 < sizeof(fpath)) {
 
90
                        if (len && fpath[len - 1] != '/')
 
91
                                fpath[len++] = '/';
 
92
                        memcpy(fpath + len, name, nlen + 1);
 
93
                        name = fpath;
 
94
                        nlen += len;
 
95
                }
 
96
        }
 
97
        for (excld = getenv("FLCOW_PATH"); excld;) {
 
98
                if (!(next = strchr(excld, ':')))
 
99
                        len = strlen(excld);
 
100
                else
 
101
                        len = next - excld;
 
102
                if (len && !strncmp(excld, name, len))
 
103
                        return 1;
 
104
                excld = next ? next + 1: NULL;
 
105
        }
 
106
        return 0;
 
107
}
 
108
 
 
109
 
 
110
static int do_cow_name(const char *name, int (*open_proc)(const char *, int, mode_t)) {
 
111
        int nfd, sfd;
 
112
        void *addr;
 
113
        struct stat stb;
 
114
        char fpath[FLCLOW_MAXPATH];
 
115
 
 
116
        if ((sfd = open_proc(name, O_RDONLY, 0)) == -1)
 
117
                return -1;
 
118
        if (fstat(sfd, &stb)) {
 
119
                close(sfd);
 
120
                return -1;
 
121
        }
 
122
        snprintf(fpath, sizeof(fpath) - 1, "%s,,+++", name);
 
123
        if ((nfd = open_proc(fpath, O_CREAT | O_EXCL | O_WRONLY, stb.st_mode)) == -1) {
 
124
                close(sfd);
 
125
                return -1;
 
126
        }
 
127
        if ((addr = mmap(NULL, stb.st_size, PROT_READ, MAP_PRIVATE,
 
128
                         sfd, 0)) == MAP_FAILED) {
 
129
                close(nfd);
 
130
                unlink(fpath);
 
131
                close(sfd);
 
132
                return -1;
 
133
        }
 
134
        if (write(nfd, addr, stb.st_size) != stb.st_size) {
 
135
                munmap(addr, stb.st_size);
 
136
                close(nfd);
 
137
                unlink(fpath);
 
138
                close(sfd);
 
139
                return -1;
 
140
        }
 
141
        munmap(addr, stb.st_size);
 
142
        close(sfd);
 
143
        fchown(nfd, stb.st_uid, stb.st_gid);
 
144
        close(nfd);
 
145
 
 
146
        if (unlink(name)) {
 
147
                unlink(fpath);
 
148
                return -1;
 
149
        }
 
150
 
 
151
        rename(fpath, name);
 
152
 
 
153
        return 0;
 
154
}
 
155
 
 
156
 
 
157
static int do_generic_open(const char *name, int flags, mode_t mode,
 
158
                           int (*open_proc)(const char *, int, mode_t)) {
 
159
        struct stat stb;
 
160
 
 
161
        if ((flags & O_RDWR || flags & O_WRONLY) && cow_name(name) &&
 
162
            !stat(name, &stb) && S_ISREG(stb.st_mode) && stb.st_nlink > 1) {
 
163
                DPRINTF("COWing %s\n", name);
 
164
                if (do_cow_name(name, open_proc) < 0) {
 
165
                        DPRINTF("COWing %s failed !\n", name);
 
166
                } else {
 
167
                        DPRINTF("COWing %s succeed\n", name);
 
168
                }
 
169
        }
 
170
 
 
171
        return open_proc(name, flags, mode);
 
172
}
 
173
 
 
174
 
 
175
int __libc_open64(const char *name, int flags, ...) {
 
176
        static int (*func_open)(const char *, int, mode_t) = NULL;
 
177
        va_list args;
 
178
        mode_t mode;
 
179
 
 
180
        if (!func_open)
 
181
                func_open = (int (*)(const char *, int, mode_t)) dlsym(REAL_LIBC, "__libc_open64");
 
182
 
 
183
        va_start(args, flags);
 
184
        mode = va_arg(args, mode_t);
 
185
        va_end(args);
 
186
 
 
187
        DPRINTF("open64(%s, 0x%x, 0x%x)\n", name, flags, mode);
 
188
 
 
189
        return do_generic_open(name, flags, mode, func_open);
 
190
}
 
191
 
 
192
 
 
193
int __libc_open(const char *name, int flags, ...) {
 
194
        static int (*func_open)(const char *, int, mode_t) = NULL;
 
195
        va_list args;
 
196
        mode_t mode;
 
197
 
 
198
        if (!func_open)
 
199
                func_open = (int (*)(const char *, int, mode_t)) dlsym(REAL_LIBC, "__libc_open");
 
200
 
 
201
        va_start(args, flags);
 
202
        mode = va_arg(args, mode_t);
 
203
        va_end(args);
 
204
 
 
205
        DPRINTF("open(%s, 0x%x, 0x%x)\n", name, flags, mode);
 
206
 
 
207
        return do_generic_open(name, flags, mode, func_open);
 
208
}
 
209