root/tarfs/tarfs.c

Revision 25, 5.9 kB (checked in by nlawren2, 10 months ago)

Wrote some more code, did some homework, and got TarFS to accept command line arguments

Line 
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 #include <errno.h>
5 #include <fcntl.h>
6
7 #include <string.h>
8 #include <unistd.h>
9 #include <ctype.h>
10
11 #include <fuse.h>
12
13 #include "tar.h"
14
15 #define BLOCK_SIZE  512
16 #define HEADER_SIZE 500
17 #define NAME_SIZE   100
18 #define true        1
19 #define false       0
20 #define eprintf(...) fprintf(stderr, __VA_ARGS__)
21
22 FILE *error_log;
23
24 typedef struct posix_header posix_header;
25 typedef char bool;
26
27 typedef struct inode inode;
28
29 struct inode{
30         inode *next;
31         inode *subdir; // null if not a directory
32
33         char file_name[NAME_SIZE];
34        
35         unsigned long block_offset;
36
37         int block_length;
38         int file_length;
39
40         bool special; // if . or ..
41 };
42
43 FILE  *tar_file;
44 inode *file_tree;
45
46 inode *create_dir(inode *parent){
47         inode *me=malloc(sizeof(inode));
48         inode *up=malloc(sizeof(inode));
49         me->special=true;
50         me->file_name[0]='.';
51         me->file_name[1]='\0';
52         me->subdir=me;
53         me->next=up;
54
55         up->special=true;
56         up->file_name[0]='.';
57         up->file_name[1]='.';
58         up->file_name[2]='\0';
59         up->subdir=parent;
60         up->next=NULL;
61
62         return me;
63 }
64
65 static int tarfs_open(const char *file_path, struct fuse_file_info *fi)
66 {
67         if((fi->flags & 3) != O_RDONLY )
68         {
69                 return -EACCES;
70         }
71         return 0;
72 }
73
74 static int tarfs_readdir(const char *file_path, void *buffer, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi){
75         char *result;
76         char delims[]="/";
77         inode *i=file_tree, *node;
78
79         /* Traverse the file tree */
80         result=strtok(++file_path, delims);
81         while( result != NULL ){
82                 while(i){
83                         if(!strcmp(result, i->file_name)){
84                                 if(i->subdir){
85                                         i=i->subdir;
86                                         break;
87                                 }
88                                 else{
89                                         return -ENOENT;
90                                 }
91                         }
92                         i=i->next;
93                 }
94                 result=strtok(NULL, delims);
95         }
96
97         while(i){
98                 filler(buffer,i->file_name,NULL,0);
99                 i=i->next;
100         }
101        
102         return 0;
103 }
104
105 static int tarfs_getattr(const char *file_path, struct stat *stbuf)
106 {
107         char *result;
108         char delims[]="/";
109         inode *i=file_tree, *node;
110         int res = 0;
111         memset(stbuf, 0, sizeof(struct stat));
112         stbuf->st_nlink = 1;
113
114         result=strtok(++file_path, delims);
115         while( result != NULL ){
116                 while(i){
117                         if(!strcmp(result, i->file_name)){
118                                 if(i->subdir){
119                                         i=i->subdir;
120                                         break;
121                                 }
122                                 else{
123                                         node=i;
124                                         goto is_file;
125                                 }
126                         }
127                         i=i->next;
128                 }
129                 if(!i) return -ENOENT;
130                 result=strtok(NULL, delims);
131         }
132        
133         stbuf->st_mode = S_IFDIR | 0555;
134         stbuf->st_size = BLOCK_SIZE;
135         return res;
136
137 is_file:
138         stbuf->st_mode = S_IFREG | 0555;
139         stbuf->st_size = i->file_length;
140         return res;
141 }
142
143 static int tarfs_read(const char *file_path, char *buffer, size_t size, off_t offset, struct fuse_file_info *fi){
144         char *result;
145         char delims[]="/";
146         inode *i=file_tree, *node;
147         size_t len;
148
149         /* Traverse the file tree */
150         result=strtok(++file_path, delims);
151         while( result != NULL ){
152                 while(i){
153                         if(!strcmp(result, i->file_name)){
154                                 if(i->subdir){
155                                         i=i->subdir;
156                                         break;
157                                 }
158                                 else{
159                                         node=i;
160                                         goto read;
161                                 }
162                         }
163                         i=i->next;
164                 }
165                 result=strtok(NULL, delims);
166         }
167
168         return -ENOENT;
169
170 read:
171         /* Get the file length */
172         len=node->file_length;
173         if (offset > len) return 0;
174
175
176         fseek(tar_file, node->block_offset + offset, SEEK_SET);
177                
178         if( size + offset > len ) size=len-offset;
179        
180         size = fread(buffer, sizeof(char), size, tar_file);
181                
182         fflush(tar_file);
183
184         return size;
185 }
186
187 inode *tarfs_init(FILE *file){
188         char buffer[BLOCK_SIZE];
189         char *result;
190         char delims[]="/";
191         posix_header header;
192         inode *i, *last_i, *new;
193
194         /* Create a root directory of the tree */
195         file_tree=create_dir(NULL);
196
197         while(true){
198                 fread(buffer, sizeof(char), BLOCK_SIZE, file);
199                 memcpy(&header, buffer, HEADER_SIZE);
200
201
202                 /* Check that the header is valid */
203                 if(!memcmp(header.magic,"\0\0\0\0\0",5)) break;
204
205                 if(memcmp(header.magic,"ustar",5)) return NULL;
206
207                 /* Create the next inode */
208                 new=malloc(sizeof(inode));     
209                
210                 /* Traverse the file tree */
211                 result=strtok(header.name, delims);
212                 i=file_tree;
213                 while( result != NULL ){
214                        
215                         while(i){
216                                 if(i->subdir){
217                                         if(!strcmp(i->file_name,result)){
218                                                 i=i->subdir;
219                                                 break;
220                                         }
221                                 }
222                                 last_i=i;
223                                 i=i->next;
224                         }
225                         if(!i){
226                                 last_i->next=new;
227                                 break;
228                         }
229                         result=strtok(NULL, delims);
230                 }
231
232                 if( !result )
233                         if( header.typeflag == '5' )
234                                 continue;
235                         else
236                                 return NULL;
237         /* Add inode attributes */ int name_size=strlen(result); memmove(new->file_name, result, name_size); new->file_name[name_size]='\0';
238                
239                 switch(header.typeflag){
240                 case '\0':
241                 case '0':
242                         new->subdir=NULL;
243                         break;
244                 case '5':
245                         new->subdir=create_dir(new);
246                         break;
247                 default:
248                         return NULL;
249                 }
250                
251                 /* Read in the file's data */
252                 sscanf(header.size,"%o",&new->file_length);
253                 new->block_length=(new->file_length + 511 ) & ~511;
254                 new->next=NULL;
255                 new->block_offset=ftell(file);
256                
257                 /* Jump to the next header */   
258                 fseek(file, new->block_length, SEEK_CUR);
259
260         }
261         fflush(file);
262         return file_tree;
263 }
264
265 void tarfs_destroy_internal(inode *_file_tree){
266         inode *i=_file_tree, *j;
267
268         while(i){
269                 if(i->subdir && !i->special )
270                         tarfs_destroy_internal(i->subdir);
271                 j=i;
272                 i=i->next;
273                 free(j);
274         }
275         fflush(stdout);
276 }
277
278 void tarfs_destroy(){
279         tarfs_destroy_internal(file_tree);
280 }
281
282 void tarfs_print(inode *file_tree, int tab){
283         inode *i=file_tree;
284
285         int temp=tab;
286         char *tabs=malloc(temp+1);
287         tabs[temp]='\0';
288         while(temp--) tabs[temp]=' ';
289        
290         while(i){
291                 printf("%s%s (offset=%i, length=%i)\n",tabs,i->file_name,i->block_offset,i->file_length);
292                 if( i->subdir && !i->special )
293                         tarfs_print(i->subdir, tab+3);
294                 i=i->next;
295         }
296         free(tabs);
297 }
298
299 static struct fuse_operations tarfs_oper = {
300         .getattr =  tarfs_getattr,
301         .read = tarfs_read,
302         .open = tarfs_open,
303         .readdir = tarfs_readdir,
304         .destroy = tarfs_destroy
305 };
306
307 int main(int argc, char **argv){
308         /* Parse filepath and initialize the file tree */
309         if( argc != 3 ){
310                 eprintf("Use: %s directory filepath\n", argv[0]);
311                 return 1;
312         }
313
314         tar_file = fopen(argv[2], "r");
315         if( !tar_file ){
316                 eprintf("Invalid filename: %s\n", argv[2]);
317                 return 1;
318         }
319        
320         file_tree=tarfs_init(tar_file);
321         if( !file_tree ){
322                 eprintf("Invalid filetype: %s\n", argv[2]);
323                 return 1;
324         }
325        
326         return fuse_main(argc-1, argv, &tarfs_oper);
327 }
Note: See TracBrowser for help on using the browser.