diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ip/ftpfs/file.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ip/ftpfs/file.c')
-rwxr-xr-x | sys/src/cmd/ip/ftpfs/file.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/sys/src/cmd/ip/ftpfs/file.c b/sys/src/cmd/ip/ftpfs/file.c new file mode 100755 index 000000000..ff5bfeca0 --- /dev/null +++ b/sys/src/cmd/ip/ftpfs/file.c @@ -0,0 +1,257 @@ +#include <u.h> +#include <libc.h> +#include <String.h> +#include "ftpfs.h" + +enum +{ + Chunk= 1024, /* chunk size for buffered data */ + Nfile= 128, /* maximum number of cached files */ +}; + +/* a file (with cached data) */ +struct File +{ + char *mem; /* part of file cached in memory */ + ulong len; /* length of cached data */ + long off; /* current offset into tpath */ + short fd; /* fd to cache file */ + char inuse; + char dirty; + ulong atime; /* time of last access */ + Node *node; + char *template; +}; + +static File files[Nfile]; +static ulong now; +static int ntmp; + +/* + * lookup a file, create one if not found. if there are no + * free files, free the last oldest clean one. + */ +static File* +fileget(Node *node) +{ + File *fp; + File *oldest; + + fp = node->fp; + if(fp) + return fp; + + oldest = 0; + for(fp = files; fp < &files[Nfile]; fp++){ + if(fp->inuse == 0) + break; + if(fp->dirty == 0 && (oldest == 0 || oldest->atime > fp->atime)) + oldest = fp; + } + + if(fp == &files[Nfile]){ + uncache(oldest->node); + fp = oldest; + } + node->fp = fp; + fp->node = node; + fp->atime = now++; + fp->inuse = 1; + fp->fd = -1; + if(fp->mem){ + free(fp->mem); + fp->mem = nil; + } + return fp; +} + +/* + * free a cached file + */ +void +filefree(Node *node) +{ + File *fp; + + fp = node->fp; + if(fp == 0) + return; + + if(fp->fd > 0){ + ntmp--; + close(fp->fd); + remove(fp->template); + free(fp->template); + fp->template = 0; + } + fp->fd = -1; + if(fp->mem){ + free(fp->mem); + fp->mem = nil; + } + fp->len = 0; + fp->inuse = 0; + fp->dirty = 0; + + node->fp = 0; +} + +/* + * satisfy read first from in memory chunk and then from temporary + * file. It's up to the caller to make sure that the file is valid. + */ +int +fileread(Node *node, char *a, long off, int n) +{ + int sofar; + int i; + File *fp; + + fp = node->fp; + if(fp == 0) + fatal("fileread"); + + if(off + n > fp->len) + n = fp->len - off; + + for(sofar = 0; sofar < n; sofar += i, off += i, a += i){ + if(off >= fp->len) + return sofar; + if(off < Chunk){ + i = n; + if(off + i > Chunk) + i = Chunk - off; + memmove(a, fp->mem + off, i); + continue; + } + if(fp->off != off) + if(seek(fp->fd, off, 0) < 0){ + fp->off = -1; + return -1; + } + i = read(fp->fd, a, n-sofar); + if(i < 0){ + fp->off = -1; + return -1; + } + if(i == 0) + break; + fp->off = off + i; + } + return sofar; +} + +void +uncachedir(Node *parent, Node *child) +{ + Node *sp; + + if(parent == 0 || parent == child) + return; + for(sp = parent->children; sp; sp = sp->sibs) + if(sp->opens == 0) + if(sp != child) + if(sp->fp != nil) + if(sp->fp->dirty == 0) + if(sp->fp->fd >= 0){ + filefree(sp); + UNCACHED(sp); + } +} + +static int +createtmp(File *fp) +{ + char template[32]; + + strcpy(template, "/tmp/ftpXXXXXXXXXXX"); + mktemp(template); + if(strcmp(template, "/") == 0){ + fprint(2, "ftpfs can't create tmp file %s: %r\n", template); + return -1; + } + if(ntmp >= 16) + uncachedir(fp->node->parent, fp->node); + + fp->fd = create(template, ORDWR|ORCLOSE, 0600); + fp->template = strdup(template); + fp->off = 0; + ntmp++; + return fp->fd; +} + +/* + * write cached data (first Chunk bytes stay in memory) + */ +int +filewrite(Node *node, char *a, long off, int n) +{ + int i, sofar; + File *fp; + + fp = fileget(node); + + if(fp->mem == nil){ + fp->mem = malloc(Chunk); + if(fp->mem == nil) + return seterr("out of memory"); + } + + for(sofar = 0; sofar < n; sofar += i, off += i, a += i){ + if(off < Chunk){ + i = n; + if(off + i > Chunk) + i = Chunk - off; + memmove(fp->mem + off, a, i); + continue; + } + if(fp->fd < 0) + if(createtmp(fp) < 0) + return seterr("can't create temp file"); + if(fp->off != off) + if(seek(fp->fd, off, 0) < 0){ + fp->off = -1; + return seterr("can't seek temp file"); + } + i = write(fp->fd, a, n-sofar); + if(i <= 0){ + fp->off = -1; + return seterr("can't write temp file"); + } + fp->off = off + i; + } + + if(off > fp->len) + fp->len = off; + if(off > node->d->length) + node->d->length = off; + return sofar; +} + +/* + * mark a file as dirty + */ +void +filedirty(Node *node) +{ + File *fp; + + fp = fileget(node); + fp->dirty = 1; +} + +/* + * mark a file as clean + */ +void +fileclean(Node *node) +{ + if(node->fp) + node->fp->dirty = 0; +} + +int +fileisdirty(Node *node) +{ + return node->fp && node->fp->dirty; +} |