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