Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "stdinc.h"
2
#include <ctype.h>
3
#include "dat.h"
4
#include "fns.h"
5
 
6
u32int	maxblocksize;
7
int	readonly;
8
 
9
static int
10
strtoullsuf(char *p, char **pp, int rad, u64int *u)
11
{
12
	u64int v;
13
 
14
	if(!isdigit((uchar)*p))
15
		return -1;
16
	v = strtoull(p, &p, rad);
17
	switch(*p){
18
	case 'k':
19
	case 'K':
20
		v *= 1024;
21
		p++;
22
		break;
23
	case 'm':
24
	case 'M':
25
		v *= 1024*1024;
26
		p++;
27
		break;
28
	case 'g':
29
	case 'G':
30
		v *= 1024*1024*1024;
31
		p++;
32
		break;
33
	case 't':
34
	case 'T':
35
		v *= 1024*1024;
36
		v *= 1024*1024;
37
		p++;
38
		break;
39
	}
40
	*pp = p;
41
	*u = v;
42
	return 0;
43
}
44
 
45
static int
46
parsepart(char *name, char **file, u64int *lo, u64int *hi)
47
{
48
	char *p;
49
 
50
	*file = estrdup(name);
51
	if((p = strrchr(*file, ':')) == nil){
52
		*lo = 0;
53
		*hi = 0;
54
		return 0;
55
	}
56
	*p++ = 0;
57
	if(*p == '-')
58
		*lo = 0;
59
	else{
60
		if(strtoullsuf(p, &p, 0, lo) < 0){
61
			free(*file);
62
			return -1;
63
		}
64
	}
65
	if(*p == '-')
66
		p++;
67
	if(*p == 0){
68
		*hi = 0;
69
		return 0;
70
	}
71
	if(strtoullsuf(p, &p, 0, hi) < 0 || *p != 0){
72
		free(*file);
73
		return -1;
74
	}
75
	return 0;
76
}
77
 
78
Part*
79
initpart(char *name, int mode)
80
{
81
	Part *part;
82
	Dir *dir;
83
	char *file;
84
	u64int lo, hi;
85
 
86
	if(parsepart(name, &file, &lo, &hi) < 0)
87
		return nil;
88
	trace(TraceDisk, "initpart %s file %s lo 0x%llx hi 0x%llx", name, file, lo, hi);
89
	part = MKZ(Part);
90
	part->name = estrdup(name);
91
	part->filename = estrdup(file);
92
	if(readonly){
93
		mode &= ~(OREAD|OWRITE|ORDWR);
94
		mode |= OREAD;
95
	}
96
	part->fd = open(file, mode);
97
	if(part->fd < 0){
98
		if((mode&(OREAD|OWRITE|ORDWR)) == ORDWR)
99
			part->fd = open(file, (mode&~ORDWR)|OREAD);
100
		if(part->fd < 0){
101
			freepart(part);
102
			fprint(2, "can't open partition='%s': %r\n", file);
103
			seterr(EOk, "can't open partition='%s': %r", file);
104
			fprint(2, "%r\n");
105
			free(file);
106
			return nil;
107
		}
108
		fprint(2, "warning: %s opened for reading only\n", name);
109
	}
110
	part->offset = lo;
111
	dir = dirfstat(part->fd);
112
	if(dir == nil){
113
		freepart(part);
114
		seterr(EOk, "can't stat partition='%s': %r", file);
115
		free(file);
116
		return nil;
117
	}
118
	if(dir->length == 0){
119
		free(dir);
120
		freepart(part);
121
		seterr(EOk, "can't determine size of partition %s", file);
122
		free(file);
123
		return nil;
124
	}
125
	if(dir->length < hi || dir->length < lo){
126
		freepart(part);
127
		seterr(EOk, "partition '%s': bounds out of range (max %lld)", name, dir->length);
128
		free(dir);
129
		free(file);
130
		return nil;
131
	}
132
	if(hi == 0)
133
		hi = dir->length;
134
	part->size = hi - part->offset;
135
	free(dir);
136
	return part;
137
}
138
 
139
int
140
flushpart(Part *part)
141
{
142
	USED(part);
143
	return 0;
144
}
145
 
146
void
147
freepart(Part *part)
148
{
149
	if(part == nil)
150
		return;
151
	if(part->fd >= 0)
152
		close(part->fd);
153
	free(part->name);
154
	free(part);
155
}
156
 
157
void
158
partblocksize(Part *part, u32int blocksize)
159
{
160
	if(part->blocksize)
161
		sysfatal("resetting partition=%s's block size", part->name);
162
	part->blocksize = blocksize;
163
	if(blocksize > maxblocksize)
164
		maxblocksize = blocksize;
165
}
166
 
167
enum {
168
	Maxxfer = 64*1024,	/* for NCR SCSI controllers; was 128K */
169
};
170
 
171
static int reopen(Part*);
172
 
173
int
174
rwpart(Part *part, int isread, u64int offset0, u8int *buf0, u32int count0)
175
{
176
	u32int count, opsize;
177
	int n;
178
	u8int *buf;
179
	u64int offset;
180
 
181
	trace(TraceDisk, "%s %s %ud at 0x%llx", 
182
		isread ? "read" : "write", part->name, count0, offset0);
183
	if(offset0 >= part->size || offset0+count0 > part->size){
184
		seterr(EStrange, "out of bounds %s offset 0x%llux count %ud to partition %s size 0x%llux",
185
			isread ? "read" : "write", offset0, count0, part->name,
186
			part->size);
187
		return -1;
188
	}
189
 
190
	buf = buf0;
191
	count = count0;
192
	offset = offset0;
193
	while(count > 0){
194
		opsize = count;
195
		if(opsize > Maxxfer)
196
			opsize = Maxxfer;
197
		if(isread)
198
			n = pread(part->fd, buf, opsize, offset);
199
		else
200
			n = pwrite(part->fd, buf, opsize, offset);
201
		if(n <= 0){
202
			seterr(EAdmin, "%s %s offset 0x%llux count %ud buf %p returned %d: %r",
203
				isread ? "read" : "write", part->filename, offset, opsize, buf, n);
204
			return -1;
205
		}
206
		offset += n;
207
		count -= n;
208
		buf += n;
209
	}
210
 
211
	return count0;
212
}
213
 
214
int
215
readpart(Part *part, u64int offset, u8int *buf, u32int count)
216
{
217
	return rwpart(part, 1, offset, buf, count);
218
}
219
 
220
int
221
writepart(Part *part, u64int offset, u8int *buf, u32int count)
222
{
223
	return rwpart(part, 0, offset, buf, count);
224
}
225
 
226
ZBlock*
227
readfile(char *name)
228
{
229
	Part *p;
230
	ZBlock *b;
231
 
232
	p = initpart(name, OREAD);
233
	if(p == nil)
234
		return nil;
235
	b = alloczblock(p->size, 0, p->blocksize);
236
	if(b == nil){
237
		seterr(EOk, "can't alloc %s: %r", name);
238
		freepart(p);
239
		return nil;
240
	}
241
	if(readpart(p, 0, b->data, p->size) < 0){
242
		seterr(EOk, "can't read %s: %r", name);
243
		freepart(p);
244
		freezblock(b);
245
		return nil;
246
	}
247
	freepart(p);
248
	return b;
249
}