gopherfs.c (3330B)
1 /* 2 * Copy me if you can. 3 * by 20h 4 */ 5 6 #define FUSE_USE_VERSION 26 7 8 #include <fuse.h> 9 #include <unistd.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <stdlib.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <time.h> 16 #include "ind.h" 17 #include "arg.h" 18 #include "sdb.h" 19 #include "proto.h" 20 #include "download.h" 21 22 sdb *db; 23 char *argv0; 24 25 static int 26 gopendir(const char *path, struct fuse_file_info *fi) 27 { 28 sdbe *e; 29 30 e = getelem(db, (char *)path, nil); 31 if(e == nil) 32 return ~ENOENT; 33 34 return 0; 35 } 36 37 38 static int 39 ggetattr(const char *path, struct stat *stbuf) 40 { 41 int res; 42 sdbe *e; 43 44 res = 0; 45 46 memset(stbuf, 0, sizeof(struct stat)); 47 if(!strcmp(path, "/")) { 48 stbuf->st_mode = S_IFDIR | 0755; 49 stbuf->st_nlink = 1; 50 stbuf->st_size = 1; 51 } else { 52 e = getelem(db, (char *)path, nil); 53 if(e == nil) 54 return ~ENOENT; 55 if(e->v[0] == '1') { 56 stbuf->st_mode = S_IFDIR | 0444; 57 stbuf->st_nlink = 2; 58 } else { 59 stbuf->st_mode = S_IFREG | 0444; 60 stbuf->st_nlink = 1; 61 stbuf->st_size = 1; 62 } 63 } 64 65 return res; 66 } 67 68 static int 69 greaddir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, 70 struct fuse_file_info *fi) 71 { 72 sdbe *e; 73 char *v, *d; 74 75 e = nil; 76 77 filler(buf, ".", 0, 0); 78 filler(buf, "..", 0, 0); 79 80 e = getelem(db, (char *)path, e); 81 if(e == nil) 82 return 0; 83 84 if(checkcache(db, e->k) == 1) 85 if(rnpggopher(e->v + sizeof(char) + sizeof(time_t), db, e->k, 86 -1) < 0) 87 return 0; 88 89 for(; e != nil; e = getelem(db, (char *)path, e)) { 90 if(!strcmp(e->k, (char *)path)) 91 continue; 92 if(strchr(e->k + strlen(path) + 1, '/')) 93 continue; 94 v = gmemdup(e->k, strlen(e->k) + 1); 95 d = strrchr(v, '/'); 96 if(d == nil) 97 continue; 98 *d++ = '\0'; 99 filler(buf, d, 0, 0); 100 free(v); 101 } 102 103 return 0; 104 } 105 106 static int 107 gopen(const char *path, struct fuse_file_info *fi) 108 { 109 110 if(checkqueue(db, (char *)path) < 0) 111 if(downloadfile(db, (char *)path) < 0) 112 return ~ENOENT; 113 114 fi->direct_io = 1; 115 116 return 0; 117 } 118 119 static int 120 gread(const char *path, char *buf, size_t size, off_t offset, 121 struct fuse_file_info *fi) 122 { 123 124 return getbytes(db, (char *)path, buf, size, offset); 125 } 126 127 static struct fuse_operations goper = { 128 .getattr = ggetattr, 129 .readdir = greaddir, 130 .opendir = gopendir, 131 .open = gopen, 132 .read = gread, 133 }; 134 135 void 136 usage(void) 137 { 138 139 tprintf(2, "usage: %s [-h] URI mntpnt [-o option[,...]]\n", argv0); 140 exit(1); 141 } 142 143 int 144 main(int argc, char *argv[]) 145 { 146 char *server, *port, *path, type; 147 char *p, *b, *c, *d; 148 int res; 149 150 db = createdb(); 151 path = ""; 152 type = '1'; 153 c = nil; 154 res = 1; 155 156 ARGBEGIN { 157 case 'h': 158 default: 159 usage(); 160 } ARGEND; 161 162 if(argc == 0) 163 usage(); 164 165 if(argc > 0 && argv[0] != nil) { 166 c = gmemdup(argv[0], strlen(argv[0]) + 1); 167 p = strstr(c, "gopher://"); 168 if(p == nil) { 169 tprintf(2, "Wrong URI Syntax\n"); 170 goto badending; 171 } 172 p += 9; 173 server = p; 174 175 b = strchr(p, ':'); 176 d = strchr(p, '/'); 177 if(b > d) 178 b = nil; 179 if(b != nil) { 180 *b++ = '\0'; 181 port = b; 182 } else 183 port = "70"; 184 if(d != nil) { 185 *d++ = '\0'; 186 type = *d; 187 p = strchr(d, '/'); 188 if(p != nil) { 189 *p++ = '\0'; 190 path = p; 191 } 192 } 193 194 adddbentry(db, type, "", path, "", server, port); 195 free(c); 196 } 197 198 res = fuse_main(argc, argv, &goper, nil); 199 200 badending: 201 destroydb(db); 202 203 return res; 204 } 205