Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/ip/ftpfs/file.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <String.h>
4
#include "ftpfs.h"
5
 
6
enum
7
{
8
	Chunk=		1024,		/* chunk size for buffered data */
9
	Nfile=		128,		/* maximum number of cached files */
10
};
11
 
12
/* a file (with cached data) */
13
struct File
14
{
15
	char	*mem;		/* part of file cached in memory */
16
	ulong	len;		/* length of cached data */
17
	long	off;		/* current offset into tpath */
18
	short	fd;		/* fd to cache file */
19
	char	inuse;
20
	char	dirty;
21
	ulong	atime;		/* time of last access */
22
	Node	*node;
23
	char 	*template;
24
};
25
 
26
static File	files[Nfile];
27
static ulong	now;
28
static int	ntmp;
29
 
30
/*
31
 *  lookup a file, create one if not found.  if there are no
32
 *  free files, free the last oldest clean one.
33
 */
34
static File*
35
fileget(Node *node)
36
{
37
	File *fp;
38
	File *oldest;
39
 
40
	fp = node->fp;
41
	if(fp)
42
		return fp;
43
 
44
	oldest = 0;
45
	for(fp = files; fp < &files[Nfile]; fp++){
46
		if(fp->inuse == 0)
47
			break;
48
		if(fp->dirty == 0 && (oldest == 0 || oldest->atime > fp->atime))
49
			oldest = fp;
50
	}
51
 
52
	if(fp == &files[Nfile]){
53
		uncache(oldest->node);
54
		fp = oldest;
55
	}
56
	node->fp = fp;
57
	fp->node = node;
58
	fp->atime = now++;
59
	fp->inuse = 1;
60
	fp->fd = -1;
61
	if(fp->mem){
62
		free(fp->mem);
63
		fp->mem = nil;
64
	}
65
	return fp;
66
}
67
 
68
/*
69
 *  free a cached file
70
 */
71
void
72
filefree(Node *node)
73
{
74
	File *fp;
75
 
76
	fp = node->fp;
77
	if(fp == 0)
78
		return;
79
 
80
	if(fp->fd > 0){
81
		ntmp--;
82
		close(fp->fd);
83
		remove(fp->template);
84
		free(fp->template);
85
		fp->template = 0;
86
	}
87
	fp->fd = -1;
88
	if(fp->mem){
89
		free(fp->mem);
90
		fp->mem = nil;
91
	}
92
	fp->len = 0;
93
	fp->inuse = 0;
94
	fp->dirty = 0;
95
 
96
	node->fp = 0;
97
}
98
 
99
/*
100
 *  satisfy read first from in memory chunk and then from temporary
101
 *  file.  It's up to the caller to make sure that the file is valid.
102
 */
103
int
104
fileread(Node *node, char *a, long off, int n)
105
{
106
	int sofar;
107
	int i;
108
	File *fp;
109
 
110
	fp = node->fp;
111
	if(fp == 0)
112
		fatal("fileread");
113
 
114
	if(off + n > fp->len)
115
		n = fp->len - off;
116
 
117
	for(sofar = 0; sofar < n; sofar += i, off += i, a += i){
118
		if(off >= fp->len)
119
			return sofar;
120
		if(off < Chunk){
121
			i = n;
122
			if(off + i > Chunk)
123
				i = Chunk - off;
124
			memmove(a, fp->mem + off, i);
125
			continue;
126
		}
127
		if(fp->off != off)
128
			if(seek(fp->fd, off, 0) < 0){
129
				fp->off = -1;
130
				return -1;
131
			}
132
		i = read(fp->fd, a, n-sofar);
133
		if(i < 0){
134
			fp->off = -1;
135
			return -1;
136
		}
137
		if(i == 0)
138
			break;
139
		fp->off = off + i;
140
	}
141
	return sofar;
142
}
143
 
144
void
145
uncachedir(Node *parent, Node *child)
146
{
147
	Node *sp;
148
 
149
	if(parent == 0 || parent == child)
150
		return;
151
	for(sp = parent->children; sp; sp = sp->sibs)
152
		if(sp->opens == 0)
153
		if(sp != child)
154
		if(sp->fp != nil)
155
		if(sp->fp->dirty == 0)
156
		if(sp->fp->fd >= 0){
157
			filefree(sp);
158
			UNCACHED(sp);
159
		}
160
}
161
 
162
static int
163
createtmp(File *fp)
164
{
165
	char template[32];
166
 
167
	strcpy(template, "/tmp/ftpXXXXXXXXXXX");
168
	mktemp(template);
169
	if(strcmp(template, "/") == 0){
170
		fprint(2, "ftpfs can't create tmp file %s: %r\n", template);
171
		return -1;
172
	}
173
	if(ntmp >= 16)
174
		uncachedir(fp->node->parent, fp->node);
175
 
176
	fp->fd = create(template, ORDWR|ORCLOSE, 0600);
177
	fp->template = strdup(template);
178
	fp->off = 0;
179
	ntmp++;
180
	return fp->fd;
181
}
182
 
183
/*
184
 *  write cached data (first Chunk bytes stay in memory)
185
 */
186
int
187
filewrite(Node *node, char *a, long off, int n)
188
{
189
	int i, sofar;
190
	File *fp;
191
 
192
	fp = fileget(node);
193
 
194
	if(fp->mem == nil){
195
		fp->mem = malloc(Chunk);
196
		if(fp->mem == nil)
197
			return seterr("out of memory");
198
	}
199
 
200
	for(sofar = 0; sofar < n; sofar += i, off += i, a += i){
201
		if(off < Chunk){
202
			i = n;
203
			if(off + i > Chunk)
204
				i = Chunk - off;
205
			memmove(fp->mem + off, a, i);
206
			continue;
207
		}
208
		if(fp->fd < 0)
209
			if(createtmp(fp) < 0)
210
				return seterr("can't create temp file");
211
		if(fp->off != off)
212
			if(seek(fp->fd, off, 0) < 0){
213
				fp->off = -1;
214
				return seterr("can't seek temp file");
215
			}
216
		i = write(fp->fd, a, n-sofar);
217
		if(i <= 0){
218
			fp->off = -1;
219
			return seterr("can't write temp file");
220
		}
221
		fp->off = off + i;
222
	}
223
 
224
	if(off > fp->len)
225
		fp->len = off;
226
	if(off > node->d->length)
227
		node->d->length = off;
228
	return sofar;
229
}
230
 
231
/*
232
 *  mark a file as dirty
233
 */
234
void
235
filedirty(Node *node)
236
{
237
	File *fp;
238
 
239
	fp = fileget(node);
240
	fp->dirty = 1;
241
}
242
 
243
/*
244
 *  mark a file as clean
245
 */
246
void
247
fileclean(Node *node)
248
{
249
	if(node->fp)
250
		node->fp->dirty = 0;
251
}
252
 
253
int
254
fileisdirty(Node *node)
255
{
256
	return node->fp && node->fp->dirty;
257
}