Browse Source

Import the stock source of filejoinfs-1.0.

Initial import.
Georgi Chorbadzhiyski 13 years ago
commit
0fe5c26bfd
11 changed files with 356 additions and 0 deletions
  1. 6
    0
      Makefile
  2. 291
    0
      filejoinfs.c
  3. 11
    0
      fusefile_valgrind
  4. 4
    0
      mount.sh
  5. 29
    0
      readme.txt
  6. 7
    0
      test.sh
  7. 3
    0
      test.txt
  8. 1
    0
      test1
  9. 1
    0
      test2
  10. 1
    0
      test3
  11. 2
    0
      umount.sh

+ 6
- 0
Makefile View File

@@ -0,0 +1,6 @@
1
+CFLAGS = -ggdb -Wall -Wextra -Wshadow -Wformat-security -O2
2
+all: filejoinfs
3
+filejoinfs: filejoinfs.c
4
+	${CC} ${CFLAGS} `pkg-config fuse --cflags --libs` filejoinfs.c -lfuse -o $@
5
+clean:
6
+	rm filejoinfs

+ 291
- 0
filejoinfs.c View File

@@ -0,0 +1,291 @@
1
+/*
2
+# filejoinfs v1.0
3
+# Quick'n'dirty FUSE module implementing joining of different files as one
4
+#
5
+# Copyright (c) 2010 Georgi Chorbadzhiyski (georgi@unixsol.org)
6
+# All rights reserved.
7
+#
8
+# Redistribution and use of this script, with or without modification, is
9
+# permitted provided that the following conditions are met:
10
+#
11
+# 1. Redistributions of this script must retain the above copyright
12
+#    notice, this list of conditions and the following disclaimer.
13
+#
14
+#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
17
+#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
+#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20
+#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21
+#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22
+#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23
+#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+#
25
+#  To compile the program run:
26
+#         gcc -Wall -Wextra `pkg-config fuse --cflags --libs` filejoinfs.c -lfuse -o filejoinfs
27
+#
28
+#  To use it:
29
+#       1. Install fuse module
30
+#             sudo modprobe fuse
31
+#
32
+#       2. Create file list
33
+#             echo /etc/group >> filelist.txt
34
+#             echo /etc/issue >> filelist.txt
35
+#             echo /etc/passwd >> filelist.txt
36
+#
37
+#       3. Create an empty file over which the files in the list will be joined
38
+#             touch joined.txt
39
+#
40
+#       4. Mount filejoinfs
41
+#             ./filejoinfs filelist.txt joined.txt
42
+#
43
+#       5. Check the result with
44
+#             cat joined.txt
45
+#
46
+#          You will see the contents of files listed in filelist.txt
47
+#
48
+#       6. Unmount the fs
49
+#             fusermount -u joined.txt
50
+#
51
+ */
52
+
53
+#define FUSE_USE_VERSION 26
54
+#define _XOPEN_SOURCE 500 // for "pread"
55
+#define _GNU_SOURCE 1 // for "getline"
56
+
57
+#include <stdio.h>
58
+#include <stdlib.h>
59
+#include <error.h>
60
+#include <string.h>
61
+#include <errno.h>
62
+#include <unistd.h>
63
+#include <sys/types.h>
64
+#include <fuse.h>
65
+
66
+/* Handle list of files */
67
+struct fileinfo {
68
+	int		fd;
69
+	char	*name;
70
+	off_t	size;
71
+};
72
+
73
+struct files {
74
+	int		num_files;
75
+	off_t	total_size;
76
+	int		alloc_files;
77
+	struct fileinfo **data;
78
+};
79
+
80
+struct files *filelist;
81
+
82
+struct files *files_alloc() {
83
+	struct files *f = calloc(1, sizeof(struct files));
84
+	f->alloc_files = 64;
85
+	f->data = calloc(f->alloc_files, sizeof(struct fileinfo *));
86
+	return f;
87
+}
88
+
89
+void files_free(struct files **pfiles) {
90
+	struct files *files = *pfiles;
91
+	struct fileinfo *file;
92
+	int i;
93
+	if (files) {
94
+		for (i=0; i<files->num_files; i++) {
95
+			file = files->data[i];
96
+			close(file->fd);
97
+			free(file->name);
98
+			free(file);
99
+		}
100
+		free(files->data);
101
+		free(*pfiles);
102
+		*pfiles = NULL;
103
+	}
104
+}
105
+
106
+void files_dump(struct files *files) {
107
+	int i;
108
+	fprintf(stdout,"num_files:%d\n", files->num_files);
109
+	fprintf(stdout,"alloc_files:%d\n", files->alloc_files);
110
+	fprintf(stdout,"total_sizes:%lld\n", files->total_size);
111
+	for (i=0; i<files->num_files; i++) {
112
+		struct fileinfo *f = files->data[i];
113
+		fprintf(stdout,"file[%d]->fd=%d\n", i, f->fd);
114
+		fprintf(stdout,"file[%d]->name=%s\n", i, f->name);
115
+		fprintf(stdout,"file[%d]->size=%llu\n", i, f->size);
116
+	}
117
+}
118
+
119
+int files_add_file(struct files *files, char *filename) {
120
+	int ret = 0;
121
+	struct stat sb;
122
+	if (stat(filename, &sb) != -1) {
123
+		struct fileinfo *file;
124
+
125
+		int fd = open(filename, O_RDONLY);
126
+		if (fd == -1) {
127
+			fprintf(stderr, "open(%s) error : %s\n", filename, strerror(errno));
128
+			return ret;
129
+		}
130
+
131
+		file = calloc(1, sizeof(struct fileinfo));
132
+		file->name = strdup(filename);
133
+		file->size = sb.st_size;
134
+		file->fd   = fd;
135
+
136
+		files->total_size += file->size;
137
+
138
+		files->data[files->num_files] = file;
139
+		files->num_files++;
140
+		if (files->num_files >= files->alloc_files-1) {
141
+			files->alloc_files *= 2;
142
+			files->data = realloc(files->data, files->alloc_files * sizeof(struct fileinfo *));
143
+		}
144
+
145
+		ret = 1;
146
+	} else {
147
+		fprintf(stderr, "stat(%s) error : %s\n", filename, strerror(errno));
148
+	}
149
+	return ret;
150
+}
151
+
152
+int files_load_filelist(struct files *files, char *filename) {
153
+	size_t len;
154
+	ssize_t readed;
155
+	int ret = 0;
156
+	char *line = NULL;
157
+
158
+	FILE *file = fopen(filename, "r");
159
+	if (!file) {
160
+		fprintf(stderr, "Can't open %s : %s\n", filename, strerror(errno));
161
+		return ret;
162
+	}
163
+
164
+	while ((readed = getline(&line, &len, file)) != -1) {
165
+		line[readed-1] = '\0';
166
+		ret += files_add_file(files, line);
167
+	}
168
+	free(line);
169
+	fclose(file);
170
+
171
+	return ret;
172
+}
173
+
174
+static int fuse_getattr(const char *path, struct stat *stbuf) {
175
+	if (strcmp(path, "/") != 0)
176
+		return -ENOENT;
177
+
178
+	if (fstat(filelist->data[0]->fd, stbuf) == -1)
179
+		return -errno;
180
+
181
+	stbuf->st_size = filelist->total_size;
182
+
183
+    return 0;
184
+}
185
+
186
+static int fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
187
+	(void)fi; // prevent warning
188
+	int i;
189
+	struct fileinfo *file = filelist->data[0];
190
+	ssize_t readen, totreaden = 0;
191
+	off_t fileofs = offset, passed = 0;
192
+	int filenum = 0;
193
+
194
+	if (strcmp(path, "/") != 0)
195
+		return -ENOENT;
196
+
197
+	if (offset >= filelist->total_size) // Hmm :)
198
+		return 0;
199
+
200
+	if (offset + size > filelist->total_size) { // Asking for too much
201
+		if (filelist->total_size < offset) // Prevent overflow
202
+			return 0;
203
+		size = filelist->total_size - offset;
204
+	}
205
+
206
+	if (offset > file->size) { // After the first file
207
+		// Find the file that corresponds to the required offset
208
+		// Can be slow with lots of files, but do it simple for now
209
+		for (i=0; i<filelist->num_files; i++) {
210
+			struct fileinfo *f = filelist->data[i];
211
+			passed += f->size;
212
+			if (passed >= offset) {
213
+				file = f;
214
+				filenum = i;
215
+				fileofs = file->size - (passed - offset);
216
+				break;
217
+			}
218
+		}
219
+	}
220
+
221
+	// Read all data
222
+	do {
223
+		readen = pread(file->fd, buf, size, fileofs);
224
+		if (readen == -1) // Error reading
225
+			return -errno;
226
+		totreaden += readen;
227
+		fileofs += readen;
228
+		buf += readen;
229
+		size -= readen;
230
+		if (fileofs >= file->size) {
231
+			fileofs = 0;
232
+			filenum++;
233
+			if (filenum >= filelist->num_files) {
234
+				break;
235
+			}
236
+			file = filelist->data[filenum];
237
+		}
238
+	} while(size > 0);
239
+
240
+	return totreaden;
241
+}
242
+
243
+static struct fuse_operations concatfs_op = {
244
+	.getattr	= fuse_getattr,
245
+	.read		= fuse_read,
246
+};
247
+
248
+int main(int argc, char *argv[]) {
249
+	int ret;
250
+	char *filenames;
251
+	char *mountpoint_file;
252
+	struct stat sb;
253
+
254
+	if (argc < 3) {
255
+		fprintf(stderr, "Usage: filejoinfs filelist.txt mount-point-file\n");
256
+		exit(EXIT_FAILURE);
257
+	}
258
+
259
+	filenames = argv[1];
260
+	mountpoint_file = argv[2];
261
+
262
+	if (stat(mountpoint_file, &sb) == -1) {
263
+		fprintf(stderr, "Can't mount on %s : %s\n", mountpoint_file, strerror(errno));
264
+		exit(EXIT_FAILURE);
265
+	} else {
266
+		if (!S_ISREG(sb.st_mode)) {
267
+			fprintf(stderr, "%s is not a file!\n", mountpoint_file);
268
+			exit(EXIT_FAILURE);
269
+		}
270
+	}
271
+
272
+	filelist = files_alloc();
273
+	if (!files_load_filelist(filelist, filenames)) {
274
+		fprintf(stderr, "Error no files loaded from %s.\n", argv[1]);
275
+		files_free(&filelist);
276
+		exit(EXIT_FAILURE);
277
+	}
278
+
279
+	char *fuse_argv[5];
280
+	fuse_argv[0] = argv[0];
281
+	fuse_argv[1] = mountpoint_file;
282
+	fuse_argv[2] = "-o";
283
+	fuse_argv[3] = "nonempty,allow_user,direct_io";
284
+	fuse_argv[4]  = 0;
285
+
286
+	ret = fuse_main(4, fuse_argv, &concatfs_op, NULL);
287
+
288
+	files_free(&filelist);
289
+
290
+	return ret;
291
+}

+ 11
- 0
fusefile_valgrind View File

@@ -0,0 +1,11 @@
1
+ulimit -c unlimited
2
+valgrind \
3
+	--log-file=filejoinfs-$(date +%F-%H:%M:%S).log \
4
+	--leak-check=full \
5
+	--show-reachable=yes \
6
+	--undef-value-errors=no \
7
+	--trace-children=yes \
8
+	--run-libc-freeres=yes \
9
+	--time-stamp=yes \
10
+		-- \
11
+	./filejoinfs test.txt

+ 4
- 0
mount.sh View File

@@ -0,0 +1,4 @@
1
+ulimit -c unlimited
2
+touch testmnt.txt
3
+./filejoinfs test.txt testmnt.txt
4
+

+ 29
- 0
readme.txt View File

@@ -0,0 +1,29 @@
1
+filejoinfs v1.0
2
+
3
+filejoinfs is fuse module that allows joining several files as one.
4
+
5
+To compile the program run:
6
+       gcc -Wall -Wextra `pkg-config fuse --cflags --libs` filejoinfs.c -lfuse -o filejoinfs
7
+
8
+To use it:
9
+     1. Install fuse module
10
+           sudo modprobe fuse
11
+
12
+     2. Create file list
13
+           echo /etc/group >> filelist.txt
14
+           echo /etc/issue >> filelist.txt
15
+           echo /etc/passwd >> filelist.txt
16
+
17
+     3. Create an empty file over which the files in the list will be joined
18
+           touch joined.txt
19
+
20
+     4. Mount filejoinfs
21
+           ./filejoinfs filelist.txt joined.txt
22
+
23
+     5. Check the result with
24
+           cat joined.txt
25
+
26
+        You will see the contents of files listed in filelist.txt
27
+
28
+     6. Unmount the fs
29
+           fusermount -u joined.txt

+ 7
- 0
test.sh View File

@@ -0,0 +1,7 @@
1
+./mount.sh
2
+cat testmnt.txt
3
+head -c 20 testmnt.txt
4
+tail -c 20 testmnt.txt
5
+head -c 160 testmnt.txt | tail -n 1
6
+echo
7
+./umount.sh

+ 3
- 0
test.txt View File

@@ -0,0 +1,3 @@
1
+test1
2
+test2
3
+test3

+ 1
- 0
test1 View File

@@ -0,0 +1 @@
1
+12345678901234567890123456789012345678901234567890123456789012345678901234567890

+ 1
- 0
test2 View File

@@ -0,0 +1 @@
1
+abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij

+ 1
- 0
test3 View File

@@ -0,0 +1 @@
1
+09876543210987654321098765432109876543210987654321098765432109876543210987654321

+ 2
- 0
umount.sh View File

@@ -0,0 +1,2 @@
1
+fusermount -u testmnt.txt
2
+rm testmnt.txt

Loading…
Cancel
Save