xref: /plan9/sys/src/cmd/venti/srv/part.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
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
strtoullsuf(char * p,char ** pp,int rad,u64int * u)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
parsepart(char * name,char ** file,u64int * lo,u64int * hi)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*
initpart(char * name,int mode)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
flushpart(Part * part)140 flushpart(Part *part)
141 {
142 	USED(part);
143 	return 0;
144 }
145 
146 void
freepart(Part * part)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
partblocksize(Part * part,u32int blocksize)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
rwpart(Part * part,int isread,u64int offset0,u8int * buf0,u32int count0)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
readpart(Part * part,u64int offset,u8int * buf,u32int count)215 readpart(Part *part, u64int offset, u8int *buf, u32int count)
216 {
217 	return rwpart(part, 1, offset, buf, count);
218 }
219 
220 int
writepart(Part * part,u64int offset,u8int * buf,u32int count)221 writepart(Part *part, u64int offset, u8int *buf, u32int count)
222 {
223 	return rwpart(part, 0, offset, buf, count);
224 }
225 
226 ZBlock*
readfile(char * name)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 }
250