123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- #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;
- }
|