2
* FL-COW by Davide Libenzi ( File Links Copy On Write )
3
* Copyright (C) 2003 Davide Libenzi
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.
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.
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
19
* Davide Libenzi <davidel@xmailserver.org>
28
#include <sys/types.h>
34
#include <sys/ioctl.h>
47
#define DPRINTF(format, args...) fprintf(stderr, format, ## args)
49
#define DPRINTF(format, args...)
54
#define RTLD_NEXT ((void *) -1L)
57
#define REAL_LIBC RTLD_NEXT
59
#define FLCLOW_MAXPATH 512
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")));
71
static int cow_name(const char *name) {
73
char const *home, *excld, *next;
74
char fpath[FLCLOW_MAXPATH];
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);
86
if (!getcwd(fpath, sizeof(fpath) - 1 - nlen))
89
if ((len = strlen(fpath)) + nlen + 2 < sizeof(fpath)) {
90
if (len && fpath[len - 1] != '/')
92
memcpy(fpath + len, name, nlen + 1);
97
for (excld = getenv("FLCOW_PATH"); excld;) {
98
if (!(next = strchr(excld, ':')))
102
if (len && !strncmp(excld, name, len))
104
excld = next ? next + 1: NULL;
110
static int do_cow_name(const char *name, int (*open_proc)(const char *, int, mode_t)) {
114
char fpath[FLCLOW_MAXPATH];
116
if ((sfd = open_proc(name, O_RDONLY, 0)) == -1)
118
if (fstat(sfd, &stb)) {
122
snprintf(fpath, sizeof(fpath) - 1, "%s,,+++", name);
123
if ((nfd = open_proc(fpath, O_CREAT | O_EXCL | O_WRONLY, stb.st_mode)) == -1) {
127
if ((addr = mmap(NULL, stb.st_size, PROT_READ, MAP_PRIVATE,
128
sfd, 0)) == MAP_FAILED) {
134
if (write(nfd, addr, stb.st_size) != stb.st_size) {
135
munmap(addr, stb.st_size);
141
munmap(addr, stb.st_size);
143
fchown(nfd, stb.st_uid, stb.st_gid);
157
static int do_generic_open(const char *name, int flags, mode_t mode,
158
int (*open_proc)(const char *, int, mode_t)) {
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);
167
DPRINTF("COWing %s succeed\n", name);
171
return open_proc(name, flags, mode);
175
int __libc_open64(const char *name, int flags, ...) {
176
static int (*func_open)(const char *, int, mode_t) = NULL;
181
func_open = (int (*)(const char *, int, mode_t)) dlsym(REAL_LIBC, "__libc_open64");
183
va_start(args, flags);
184
mode = va_arg(args, mode_t);
187
DPRINTF("open64(%s, 0x%x, 0x%x)\n", name, flags, mode);
189
return do_generic_open(name, flags, mode, func_open);
193
int __libc_open(const char *name, int flags, ...) {
194
static int (*func_open)(const char *, int, mode_t) = NULL;
199
func_open = (int (*)(const char *, int, mode_t)) dlsym(REAL_LIBC, "__libc_open");
201
va_start(args, flags);
202
mode = va_arg(args, mode_t);
205
DPRINTF("open(%s, 0x%x, 0x%x)\n", name, flags, mode);
207
return do_generic_open(name, flags, mode, func_open);