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 } 250