gopherfs

A FUSE gopher file system.
git clone git://r-36.net/gopherfs
Log | Files | Refs | README | LICENSE

proto.c (4717B)


      1 /*
      2  * Copy me if you can.
      3  * by 20h
      4  */
      5 
      6 #include <unistd.h>
      7 #include <stdarg.h>
      8 #include <stdio.h>
      9 #include <netdb.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <sys/types.h>
     13 #include <sys/socket.h>
     14 #include <netinet/in.h>
     15 #include <arpa/inet.h>
     16 #include <time.h>
     17 #include "ind.h"
     18 #include "sdb.h"
     19 
     20 void
     21 tprintf(int sock, char *fmt, ...)
     22 {
     23         va_list fmtargs;
     24 	int fd2;
     25 	FILE *fp;
     26 
     27 	fd2 = dup(sock);
     28 	fp = fdopen(fd2, "w");
     29 	if(fp == nil) {
     30 		perror("fdopen");
     31 		return;
     32 	}
     33 
     34         va_start(fmtargs, fmt);
     35         vfprintf(fp, fmt, fmtargs);
     36         va_end(fmtargs);
     37 
     38 	fclose(fp);
     39 
     40         return;
     41 }
     42 
     43 char *
     44 readln(int fd)
     45 {
     46         char *ret;
     47         int len, st;
     48 
     49         len = 1;
     50 
     51         ret = greallocz(nil, 2, 2);
     52         while((st = read(fd, &ret[len - 1], 1)) > 0 && ret[len - 1] != '\n')
     53                 ret = greallocz(ret, ++len + 1, 0);
     54 	if(st < 0) {
     55 		free(ret);
     56 		return nil;
     57 	}
     58 
     59         if(ret[len - 1] != '\n') {
     60                 free(ret);
     61                 return nil;
     62         }
     63         ret[len - 1] = '\0';
     64 	if(ret[len - 2] == '\r')
     65 		ret[len - 2] = '\0';
     66 
     67         return ret;
     68 }
     69 
     70 int
     71 connecttcp(char *host, char *service)
     72 {
     73         int sock;
     74 	struct addrinfo *ai, *a;
     75 
     76 	sock = -1;
     77 
     78 	if(getaddrinfo(host, service, nil, &ai) < 0) {
     79 		perror("getaddrinfo");
     80 		return -1;
     81 	}
     82 
     83 	for(a = ai; a; a = a->ai_next) {
     84 		sock = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
     85 		if(sock < 0) {
     86 			perror("socket");
     87 			sock = -1;
     88 			break;
     89 		}
     90 
     91 		if(connect(sock, a->ai_addr, a->ai_addrlen) < 0) {
     92 			perror("connect");
     93 			sock = -1;
     94 			break;
     95 		} else
     96 			break;
     97 	}
     98 
     99 	freeaddrinfo(ai);
    100 
    101         return sock;
    102 }
    103 
    104 int
    105 sendgopherreq(char *server, char *port, char *str)
    106 {
    107 	int sock;
    108 
    109 	sock = connecttcp(server, port);
    110 	if(sock < 0)
    111 		return -1;
    112 
    113 	tprintf(sock, "%s\r\n", str);
    114 
    115 	return sock;
    116 }
    117 
    118 void
    119 adddbentry(sdb *db, char type, char *dpath, char *path, char *name,
    120 		char *server, char *port)
    121 {
    122 	char *uri, *more;
    123 	char *rdp;
    124 	int mlen;
    125 	time_t tim;
    126 	sdbe *e;
    127 
    128 	if(dpath[strlen(dpath) - 1] == '/')
    129 		rdp = "";
    130 	else
    131 		rdp = "/";
    132 	uri = greallocz(nil, strlen(dpath) + strlen(rdp) + strlen(name) + 1, 2);
    133         sprintf(uri, "%s%s%s", dpath, rdp, name);
    134 
    135 	mlen = sizeof(char) + sizeof(time_t) + strlen(server) + strlen(port) +
    136 		strlen(path) + 3;
    137 	more = greallocz(nil, mlen, 2); 
    138         tim = time(nil);
    139         more[0] = type;
    140         memcpy(more + sizeof(char), &tim, sizeof(tim));
    141         sprintf(more + sizeof(char) + sizeof(time_t), "%s:%s/%s", server,
    142 			port, path); 
    143 
    144         e = getelem(db, uri, nil);
    145         if(e != nil) {
    146 		free(e->v);
    147                 e->v = gmemdup(more, mlen);
    148                 e->l = mlen;
    149         } else
    150                 addelem(db, uri, more, mlen);
    151 
    152 	free(more);
    153 	free(uri);
    154 
    155 	return;
    156 }
    157 
    158 int
    159 parsegopher(int sock, sdb *db, char *dpath)
    160 {
    161 	char *ln, type, *name, *path, *server, *port, *end;
    162 
    163 	while((ln = readln(sock)) != nil) {
    164 		type = ln[0];
    165 		name = ln + 1;
    166 		path = strchr(name, '\t');
    167 		if(path == nil) {
    168 			free(ln);
    169 			continue;
    170 		}
    171 		*path++ = '\0';
    172 		server = strchr(path, '\t');
    173 		if(server == nil) {
    174 			free(ln);
    175 			continue;
    176 		}
    177 		*server++ = '\0';
    178 		port = strchr(server, '\t');
    179 		if(port == nil) {
    180 			free(ln);
    181 			continue;
    182 		}
    183 		*port++ = '\0';
    184 		end = strchr(port, '\t');
    185 		if(end != nil)
    186 			*end = '\0';
    187 		end = strchr(port, '\r');
    188 		if(end != nil)
    189 			*end = '\0';
    190 
    191 		if(name[0] == '.') {
    192 			if(name[1] == '\0') {
    193 				free(ln);
    194 				continue;
    195 			}
    196 			if(name[1] == '.' && name[2] == '\0') {
    197 				free(ln);
    198 				continue;
    199 			}
    200 		}
    201 
    202 		adddbentry(db, type, dpath, path, name, server, port);
    203 		free(ln);
    204 	}
    205 
    206 	return 0;
    207 }
    208 
    209 void
    210 writetofile(int sock, int fd)
    211 {
    212 	char buf[8192];
    213 	int l;
    214 
    215 	for(;;) {
    216 		l = read(sock, buf, sizeof(buf));
    217 		if(l <= 0)
    218 			return;
    219 		write(fd, buf, l);
    220 	}
    221 
    222 	return;
    223 }
    224 
    225 int
    226 rnpggopher(char *srv, sdb *db, char *dpath, int fd)
    227 {
    228 	char *server, *port, *path;
    229 	int sock, res;
    230 
    231 	res = 0;
    232 
    233 	server = gmemdup(srv, strlen(srv) + 1);
    234 	port = strchr(server, ':');
    235 	path = strchr(server, '/');
    236 	if(port == nil)
    237 		port = "70";
    238 	else
    239 		*port++ = '\0';
    240 	if(path == nil)
    241 		path = "";
    242 	else
    243 		*path++ = '\0';
    244 
    245 	sock = sendgopherreq(server, port, path);
    246 	if(sock < 0) {
    247 		perror("sendgopherreq");
    248 		res = -1;
    249 	} else {
    250 		if(fd < 0)
    251 			parsegopher(sock, db, dpath);
    252 		else
    253 			writetofile(sock, fd);
    254 	}
    255 
    256 	free(server);
    257 	close(sock);
    258 
    259 	return res;
    260 }
    261 
    262 int
    263 checkcache(sdb *db, char *path)
    264 {
    265 	sdbe *e;
    266 	time_t tim;
    267 	int i;
    268 
    269 	e = getelem(db, path, nil);
    270 	for(i = 0; e != nil; e = getelem(db, path, e), i++) {
    271 		if(!strcmp(e->k, (char *)path))
    272 			continue;
    273 		if(strchr(e->k + strlen(path) + 1, '/'))
    274 			continue;
    275 
    276 		memmove(&tim, e->v + sizeof(char), sizeof(time_t));
    277 		if(time(nil) - tim > ECACHE)
    278 			return 1;
    279 	}
    280 
    281 	if(i < 2)
    282 		return 1;
    283 
    284 	return 0;
    285 }
    286