This repository has been archived by the owner on Apr 10, 2023. It is now read-only.
forked from MaaSTaaR/SSFS
-
Notifications
You must be signed in to change notification settings - Fork 1
/
catfs.c
222 lines (203 loc) · 6.1 KB
/
catfs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#define FUSE_USE_VERSION 30
#include <fuse.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <linux/limits.h>
#include <errno.h>
struct entry {
char *name;
off_t start;
off_t size;
};
struct entry *entries;
int entries_len;
// fd cache
int fd=-1;
int fd_i=-1;
// fs block size-1
//off_t block_size_1=511;
//pwd where the catfs was started from
char *pwd;
// properties of the file in fake FS
char *filename;
off_t filelen;
struct stat filestat;
static int do_getattr( const char *path, struct stat *st )
{
//printf("getattr [%s]\n", path);
st->st_uid = getuid(); // The owner of the file/directory is the user who mounted the filesystem
st->st_gid = getgid(); // The group of the file/directory is the same as the group of the user who mounted the filesystem
st->st_atime = time( NULL ); // The last "a"ccess of the file/directory is right now
st->st_mtime = time( NULL ); // The last "m"odification of the file/directory is right now
if ( strcmp( path, "/" ) == 0 )
{
st->st_mode = S_IFDIR | 0755;
st->st_nlink = 2; // Why "two" hardlinks instead of "one"? The answer is here: http://unix.stackexchange.com/a/101536
}
else
{
st->st_mode = S_IFREG | 0444;
st->st_nlink = 1;
st->st_size = filelen;
}
return 0;
}
static int do_readdir( const char *path, void *buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi )
{
filler( buffer, ".", NULL, 0 ); // Current Directory
filler( buffer, "..", NULL, 0 ); // Parent Directory
if ( strcmp( path, "/" ) == 0 ) // If the user is trying to show the files/directories of the root directory show the following
{
filler( buffer, "archive.cat", NULL, 0 );
}
return 0;
}
int BinarySearch(struct entry *array, int number_of_elements, off_t key) {
int low = 0, high = number_of_elements-1, mid;
int iter =0;
while(low < high) {
iter++;
mid = (low + high)/2;
if(mid==low) mid++;
if(array[mid].start < key) low = mid;
else if(array[mid].start > key) high = mid-1;
//printf("%d %d %d\n", iter, low, high);
if(iter==number_of_elements) return mid;
}
return low;
}
off_t min(off_t a, off_t b) {
if(a<b) return a;
return b;
}
static int do_read( const char *path, char *buffer, size_t size, off_t offset, struct fuse_file_info *fi )
{
memset(buffer, 0, size);
//printf( "--> Trying to read %s, %u, %u\n", path, offset, size );
off_t bytes_written=0;
off_t bytes_left=size;
if(offset>filelen) offset=filelen;
if(bytes_left+offset>filelen) bytes_left=filelen-offset;
//printf( "--> Trying to read %s, %u, %u\n", path, offset, bytes_left );
int i=BinarySearch(entries, entries_len, offset);
//printf( "start entry %d\n", i);
while(bytes_left>0 && i<entries_len) {
off_t pos_in_file=offset-entries[i].start;
//printf( "entry %d, %d, %s\n", i, pos_in_file, entries[i].name);
if(fd_i!=i) {
if (fd != -1) close(fd);
//printf("opening\n");
fd = open(entries[i].name, O_RDONLY);
//if (fd==-1) printf("errno=%d\n",errno);
fd_i=i;
}
if (fd != -1) {
//printf( "reading %u bytes starting at %u to %u \n", bytes_left, pos_in_file, bytes_written);
int res=pread(fd, buffer+bytes_written, bytes_left, pos_in_file);
//printf( "read %u bytes\n", res);
// NOTE: even if we didn't actually read the file,
// we still consider it "ok" result
// (relevant part in buffer will be zero-filled)
}
off_t this_result = min(entries[i].size-pos_in_file, bytes_left);
bytes_written += this_result;
offset += this_result;
bytes_left -= this_result;
//printf( "%u bytes written, offset=%u, %u bytes left\n", bytes_written, offset, bytes_left);
//printf( "uoutput: [%s]\n", buffer);
i++;
}
return bytes_written;
}
static struct fuse_operations operations = {
.getattr = do_getattr,
.readdir = do_readdir,
.read = do_read,
};
void usage(char *name) {
printf("usage: %s {list file} {mount point} [FUSE parameters]\n"
"\n"
"{list file} - file generated by this command:\n"
"\n"
" find . -type f -printf \"%s \\%P\\n\" >{list file}\n"
"\n"
"{mount point} - empty directory to mount catfs\n"
"\n"
,name, "%s");
}
//from rofs-filtered
static char* concat_path(const char* p1, const char* p2) {
size_t p1len = strlen(p1);
size_t p2len = strlen(p2);
// Need room for path separator and null terminator
char *path = malloc(p1len + p2len + 2);
if (!path) return NULL;
strcpy(path, p1);
if ((path[p1len - 1] != '/') && (p2[0] != '/')) {
// Add a "/" if neither p1 nor p2 has it.
strcat(path, "/");
} else if (path[p1len - 1] == '/') {
// If p1 ends in '/', we don't need it from p2
while (p2[0] == '/') p2++;
}
strcat(path, p2);
return path;
}
int main( int argc, char *argv[] ) {
if(argc<2) {
usage(argv[0]);
return;
}
char line[PATH_MAX];
pwd=get_current_dir_name();
//printf("Current working dir: %s\n", pwd);
FILE *fr = fopen (argv[1], "rt");
if(fr == NULL) {
usage(argv[0]);
return;
}
int i=0;
while(fgets(line, PATH_MAX, fr) != NULL) {
i++;
}
entries_len = i;
entries = malloc(sizeof(struct entry) * entries_len);
rewind(fr);
i=0;
off_t filepos=0;
while(fgets(line, sizeof line, fr) != NULL) {
size_t len = strlen(line);
if (len > 0 && line[len-1] == '\n') {
line[--len] = '\0';
}
sscanf (line, "%" SCNd64, &(entries[i].size));
// round up to x*512
// http://stackoverflow.com/questions/2022179/c-quick-calculation-of-next-multiple-of-4
//off_t old=entries[i].size;
//entries[i].size = (entries[i].size + block_size_1) & ~block_size_1;
//int blk=entries[i].size/512;
//printf("old [%" PRId64 "], new [%" PRId64 "], blk [%d], new [%d]\n", old, entries[i].size, blk, blk*512);
entries[i].start=filepos;
filepos=entries[i].start+entries[i].size;
char *name = line;
while (*name != ' ') name++;
name++;
if(name[0]=='/') {
entries[i].name = malloc(strlen(name)+1);
strcpy(entries[i].name, name);
//printf("direct copy absolute filename: [%s]\n", entries[i].name);
} else {
entries[i].name = concat_path(pwd, name);
//printf("relative filename: [%s]\n", entries[i].name);
}
i++;
}
filelen=filepos;
fclose(fr);
return fuse_main( argc-1, argv+1, &operations, NULL );
}