1
2 /*
3 FUNIONFS: UNIONFS over FUSE Usermode filesystem
4 Copyright (C) 2005-2006 Stephane APIOU <stephane.apiou@free.fr>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 */
21
22 #include <fuse.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <sys/mman.h>
31 #include <dirent.h>
32
33 #include "funionfs.h"
34
35 extern f_opt_t f_opt;
36 extern FILE *log_fd;
37
38 extern struct unionfs_desc *unionfs_list;
39
40 extern char initial_working_dir[PATH_MAX + 1];
41
42 f_cbuf_t f_cbuf = { "", 0, 0 };
43
44 int
funionfs_relist(void)45 funionfs_relist(void)
46 {
47 int ret;
48
49 if (*f_opt.firstdir != '\0')
50 {
51 if (strcmp(f_opt.firstdir, "NONE")
52 && strcmp(f_opt.firstdir, "none")
53 && strcmp(f_opt.firstdir, "None"))
54 {
55 int fd;
56 char *s, *firstdir;
57 struct unionfs_desc *walk;
58
59 if (*f_opt.firstdir == '/')
60 firstdir = strdup(f_opt.firstdir);
61 else
62 firstdir =
63 rel2abspath(f_opt.firstdir,
64 initial_working_dir);
65 DEBUG_PRINTF("firstdir=%s\n", firstdir);
66 s = (char *) malloc(strlen(firstdir) +
67 strlen(CONTROL_FILE) + 2);
68 strcpy(s, firstdir);
69 strcat(s, "/");
70 strcat(s, CONTROL_FILE);
71 DEBUG_PRINTF("s=%s\n", s);
72 free(firstdir);
73 if (!s)
74 return -ENOMEM;
75 ret = unlink(s);
76 if ((ret < 0) && (errno != ENOENT))
77 {
78 free(s);
79 return -errno;
80 }
81 fd = open(s, O_CREAT | O_EXCL | O_WRONLY, 0600);
82 free(s);
83 if (fd < 0)
84 return -errno;
85 DEBUG_PRINTF("Starting to walk list...\n");
86 walk = unionfs_list;
87 while (walk)
88 {
89 ret = write(fd, walk->path, strlen(walk->path));
90 if (ret < 0)
91 return -errno;
92 if (walk->ro)
93 ret = write(fd, "=ro", 3);
94 else
95 ret = write(fd, "=rw", 3);
96 if (ret < 0)
97 return -errno;
98 ret = write(fd, "\n", 1);
99 if (ret < 0)
100 return -errno;
101 walk = walk->pnext;
102 }
103 close(fd);
104 }
105 }
106 return 0;
107
108 }
109
110 static int
command_is(const char * text,const char * word)111 command_is(const char *text, const char *word)
112 {
113 int l;
114
115 l = strlen(word);
116 return !strncmp(text, word, l) && (isspace(text[l]) || !text[l]);
117 }
118
119 static int
funionfs_execute(const char * command)120 funionfs_execute(const char *command)
121 {
122 int ret;
123
124 if (!*command)
125 return 0;
126
127 LOG("execute %s\n", command);
128
129 if (command_is(command, "relist"))
130 return funionfs_relist();
131
132 if (command_is(command, "umount"))
133 {
134 if (!fuse_get_context()->uid
135 || (fuse_get_context()->uid == getuid())
136 || (fuse_get_context()->uid == geteuid()))
137 {
138 if (*f_opt.mountpoint == '/')
139 fuse_unmount(f_opt.mountpoint);
140 else
141 fuse_unmount(rel2abspath
142 (f_opt.mountpoint,
143 initial_working_dir));
144 }
145 return -1;
146 }
147 if (command_is(command, "add_ro") && command[6])
148 {
149 ret = funionfs_addpath(command + 7, 1);
150 if (ret != 1)
151 return ret;
152 return funionfs_relist();
153 }
154 if (command_is(command, "add_rw") && command[6])
155 {
156 ret = funionfs_addpath(command + 7, 0);
157 if (ret != 1)
158 return ret;
159 return funionfs_relist();
160 }
161 if (command_is(command, "make_ro") && command[7])
162 {
163 struct unionfs_desc *walk;
164
165 if (command[8] != '/')
166 return -ENOENT;
167
168 walk = unionfs_list;
169 while (walk)
170 {
171 if (!strcmp(command + 8, walk->path))
172 walk->ro = 1;
173 walk = walk->pnext;
174 }
175 return funionfs_relist();
176 }
177 return 0;
178 }
179
180 int
add_to_control_buffer(f_cbuf_t * to,const char * buf,size_t size)181 add_to_control_buffer(f_cbuf_t * to, const char *buf, size_t size)
182 {
183 LOG("add_to_control_buf:\n");
184 if (to->length + size >= CONTROL_BUFFER_SIZE)
185 return -ENOSPC;
186 {
187 unsigned i, j;
188
189 for (i = 0; i < size; i++)
190 {
191 j = (to->start + to->length + i) % CONTROL_BUFFER_SIZE;
192 to->data[j] = buf[i];
193 LOG("%c", buf[i]);
194 }
195 j = (to->start + to->length + size) % CONTROL_BUFFER_SIZE;
196 to->data[j] = 0;
197 LOG("\nend add_to_control_buf\n");
198 }
199 to->length += size;
200 return 0;
201 }
202
203 void
flush_control_buffer(f_cbuf_t * what)204 flush_control_buffer(f_cbuf_t * what)
205 {
206 what->start = 0;
207 what->length = 0;
208 what->data[0] = 0;
209 }
210
211 char *
take_control_buffer_line(f_cbuf_t * from)212 take_control_buffer_line(f_cbuf_t * from)
213 {
214 char *head, *tail;
215 long n;
216
217 n = 0;
218 head = from->data + from->start;
219 tail = head;
220 while (*tail != 0 && *tail != 10)
221 {
222 tail++;
223 n++;
224 if (tail - from->data >= CONTROL_BUFFER_SIZE)
225 tail = from->data;
226 }
227 *tail = 0;
228 from->length -= n + 1;
229 if (from->length < 0)
230 {
231 from->length = 0;
232 from->data[from->start] = 0;
233 }
234 from->start = (from->start + n + 1) % CONTROL_BUFFER_SIZE;
235 return strdup(head);
236 }
237
238 static int
is_control_buffer_line(f_cbuf_t * from)239 is_control_buffer_line(f_cbuf_t * from)
240 {
241 int n;
242
243 n = 0;
244 while ((from->data[(from->start + n) % CONTROL_BUFFER_SIZE] != 10)
245 && (from->data[(from->start + n) % CONTROL_BUFFER_SIZE] != 10)
246 && (n < CONTROL_BUFFER_SIZE))
247 n++;
248 return (from->data[(from->start + n) % CONTROL_BUFFER_SIZE] == 10);
249 }
250
251
252 int
funionfs_control_write(const char * buf,size_t size)253 funionfs_control_write(const char *buf, size_t size)
254 {
255 int ret;
256 char *s;
257
258 ret = add_to_control_buffer(&f_cbuf, buf, size);
259 if (ret)
260 return ret;
261 while (is_control_buffer_line(&f_cbuf))
262 {
263 s = take_control_buffer_line(&f_cbuf);
264 funionfs_execute(s);
265 free(s);
266 }
267 return size;
268 }
269