1 /*
2 * AFFLIB(tm)
3 *
4 * AFF and AFFLIB is a trademark of Simson Garfinkel and Basis Technology Corp.
5 *
6 * Distributed under the Berkeley 4-part license
7 */
8 #include "affconfig.h"
9 #include "afflib.h"
10 #include "afflib_i.h"
11 #include "vnode_split_raw.h"
12
13 #ifdef HAVE_CTYPE_H
14 #include <ctype.h>
15 #endif
16
17 #ifndef HAVE_ISDIGIT
isdigit(char ch)18 static int isdigit(char ch)
19 {
20 return ch>='0' && ch<='9';
21 }
22 #endif
23
24
25
26 /* split raw file implementation with optional metadata support */
27 struct split_raw_private {
28 u_int num_raw_files; // number of raw files
29 int *fds; // array of file descriptors for each open raw file
30 uint64_t *pos; // where we are in each file
31 char *first_raw_fname; /* The filename of the first raw file. */
32 char *next_raw_fname; /* The filename of the next raw file, or 0
33 when one big file is used. */
34 int64_t cur_page; // current page number, used for split_raw_get_next_seg
35 };
36
SPLIT_RAW_PRIVATE(AFFILE * af)37 static inline struct split_raw_private *SPLIT_RAW_PRIVATE(AFFILE *af)
38 {
39 assert(af->v == &vnode_split_raw);
40 return (struct split_raw_private *)(af->vnodeprivate);
41 }
42
43 /* Return 1 if a file is the first of a split-raw series*/
split_raw_identify_file(const char * filename,int exists)44 static int split_raw_identify_file(const char *filename,int exists)
45 {
46 if(exists && access(filename,R_OK)!=0) return 0; // needs to exist and it doesn't
47 return af_ext_is(filename,"000") || af_ext_is(filename,"001") ||
48 af_ext_is(filename,"aaa") || af_ext_is(filename,"AAA");
49 }
50
51 /* split_raw_close:
52 * Close each of the split files.
53 */
54
split_raw_close(AFFILE * af)55 static int split_raw_close(AFFILE *af)
56 {
57 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
58
59 for (uint64_t i = 0; i < srp->num_raw_files; i++){
60 if(srp->fds[i]){
61 close(srp->fds[i]);
62 srp->fds[i] = 0;
63 }
64 }
65 if (srp->fds) free (srp->fds);
66 if (srp->pos) free (srp->pos);
67 if (srp->first_raw_fname) free (srp->first_raw_fname);
68 if (srp->next_raw_fname) free (srp->next_raw_fname);
69 free(srp);
70 af->vnodeprivate = 0;
71 return 0;
72 }
73
74
75 /**
76 * increment_fname(filename):
77 * "filename.000" => "filename.001"
78 * "filename.123" => "filename.124"
79 * "filename.999" => "filename.AAA"
80 * "filename.AZZ" => "filename.BAA"
81 * "filename.aaa" => "filename.aab" (legacy support)
82 * fn must be at least 4 characters long and must have a 3-character extension
83 *
84 * @param fn filename to increment (modified in place)
85 * @return 0 if successful.
86 * -1 for invalid filename or no more namespace.
87 */
88 /** increase the character and return true if carry */
incval(char & ch,int base)89 static bool incval(char &ch,int base)
90 {
91 if(base==10){
92 if(ch=='9'){
93 ch='0';
94 return true;
95 }
96 ch++;
97 return false;
98 }
99
100 /* Assume base 36 */
101 switch(ch){
102 case 'Z':
103 ch='0'; // go back to 0
104 return true; // and carry
105 case '9':
106 ch='A';
107 return false;
108 default:
109 ch++; // normal increment
110 return false;
111 }
112 }
113
split_raw_increment_fname(char * fn)114 int split_raw_increment_fname (char *fn)
115 {
116 size_t len = strlen(fn);
117 if(len<4 || fn[len-4]!='.') return -1;
118 char *ext = fn+len-3;
119
120 /* See if it is a number */
121 if(isdigit(ext[0]) && isdigit(ext[1]) && isdigit(ext[2])){
122 int num = atoi(ext);
123 if(num==999){
124 strcpy(ext,"A00");
125 return 0;
126 }
127 snprintf(ext,4,"%03d",num+1);
128 return 0;
129 }
130
131 /* First digit goes A-Z, second and third go 0-9A-Z */
132
133 /* Get the case */
134 int lower = islower(ext[0]);
135
136 /* Convert to all uppercase */
137 for(int i=0;i<3;i++){
138 if(isalpha(ext[i])) ext[i] = toupper(ext[i]);
139 }
140
141 /* Increment */
142 if(incval(ext[2],10)){
143 if(incval(ext[1],36)){
144 if(incval(ext[0],36)){
145 return EINVAL;
146 }
147 }
148 }
149
150 /* Convert back to lowercase if necessary */
151 for(int i=0;i<3;i++){
152 if(isalpha(ext[i]) && lower) ext[i] = tolower(ext[i]);
153 }
154 return 0;
155 }
156
157
srp_validate(AFFILE * af)158 void srp_validate(AFFILE *af)
159 {
160 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
161 for(uint32_t i=0;i<srp->num_raw_files;i++){
162 assert(srp->fds[i]!=0);
163 }
164 }
165
166 /** Debugging routine.
167 */
srp_dump(AFFILE * af)168 void srp_dump(AFFILE *af)
169 {
170 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
171 for(uint32_t i=0;i<srp->num_raw_files;i++){
172 fprintf(stderr," fds[%d]=%d pos[%d]=%" I64d "\n",i,srp->fds[i],i,srp->pos[i]);
173 }
174 srp_validate(af);
175 fprintf(stderr,"===================\n");
176 }
177
srp_add_fd(AFFILE * af,int fd)178 static void srp_add_fd(AFFILE *af,int fd)
179 {
180 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
181 srp->num_raw_files++;
182 srp->fds = (int *)realloc (srp->fds, sizeof (int) * (srp->num_raw_files));
183 srp->fds[srp->num_raw_files - 1] = fd;
184 srp->pos = (uint64_t *)realloc (srp->pos, sizeof (uint64_t) * (srp->num_raw_files));
185 srp->pos[srp->num_raw_files - 1] = 0;
186 }
187
188
split_raw_open_internal(AFFILE * af,uint64_t * image_size)189 static int split_raw_open_internal(AFFILE *af, uint64_t *image_size)
190 {
191 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
192 int fd;
193 struct stat sb;
194
195 fd = open(srp->first_raw_fname, af->openflags|O_BINARY, af->openmode);
196 if (fd < 0) {
197 (*af->error_reporter)("split_raw_open_internal: open(%s): ",af->fname);
198 return -1;
199 }
200
201 srp->num_raw_files = 1;
202 srp->fds = (int *)malloc (sizeof (int));
203 srp->fds[0] = fd;
204 srp->pos = (uint64_t *)malloc (sizeof (uint64_t));
205 if (fstat (fd, &sb) != 0) {
206 (*af->error_reporter)("split_raw_open_internal: fstat(%s): ",af->fname);
207 close (fd);
208 return -1;
209 }
210
211 af->maxsize = 0;
212
213 /* If there's a next_raw_fname set by the caller of this function, we
214 * have a split file; otherwise we have one big file.
215 */
216 if (srp->next_raw_fname==0) {
217 (*image_size) = sb.st_size;
218 return 0;
219 }
220
221 /* This gets set to 1 the first time we find a file whose size doesn't
222 match the size of the first file. If we successfully open a file
223 when this flag is already 1, then our sanity checks fail. */
224 int current_file_must_be_last = 0;
225
226 do {
227 if (split_raw_increment_fname (srp->next_raw_fname) != 0) {
228 (*af->error_reporter)("split_raw_open_internal: too many files\n");
229 errno = EINVAL;
230 return -1;
231 }
232 fd = open(srp->next_raw_fname,
233 af->openflags & O_RDWR ? (O_RDWR|O_BINARY) : (O_RDONLY|O_BINARY));
234
235 if (fd < 0) {
236 if (errno != ENOENT) {
237 (af->error_reporter)("split_raw_open_internal errno=%d",errno);
238 return -1;
239 }
240 (*image_size) = sb.st_size + af->maxsize * (srp->num_raw_files - 1);
241 errno = 0; // reset errno
242 return 0; // end of files
243 }
244 srp_add_fd(af,fd);
245 if (current_file_must_be_last) {
246 (*af->error_reporter)("split_raw_open_internal: %s exists, "
247 "but previous file didn't match expected file size\n",af->fname);
248 return -1;
249 }
250 /* Set af->maxsize to the size of the first file, but only
251 if a second file exists. If no second file exists, then we want
252 to use af->maxsize, which cannot be set until after
253 af_open returns. */
254 if (!af->maxsize)
255 af->maxsize = sb.st_size;
256 if (fstat (fd, &sb) != 0) {
257 (*af->error_reporter)("split_raw_open_internal: fstat(%s): ",af->fname);
258 return -1;
259 }
260 if ((uint64_t)sb.st_size != af->maxsize){
261 current_file_must_be_last = 1;
262 }
263 } while (1);
264 return -1;
265 }
266
split_raw_open(AFFILE * af)267 static int split_raw_open(AFFILE *af)
268 {
269 int ret;
270
271 af->vnodeprivate = (void *)calloc(sizeof(struct split_raw_private),1);
272 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
273
274 srp->first_raw_fname = strdup (af->fname);
275 srp->next_raw_fname = strdup (af->fname);
276 ret = split_raw_open_internal (af, &(af->image_size));
277
278 if (ret != 0) {
279 split_raw_close (af);
280 return ret;
281 }
282
283 /* Adaptively find the largest pagesize we can use that fits within maxsize */
284 af->image_pagesize = 512;
285 while ((af->image_pagesize < (16 * 1024 * 1024))
286 && !(af->maxsize % (af->image_pagesize * 2)))
287 af->image_pagesize *= 2;
288
289 if ((ret == 0) && (af->maxsize % af->image_pagesize!=0)) {
290 (*af->error_reporter)("split_raw_open: %s: raw_file_size (%" I64d " not a multiple of pagesize %lu\n",
291 af->fname, af->maxsize,af->image_pagesize);
292 split_raw_close (af);
293 return -1;
294 }
295
296 return 0;
297 }
298
split_raw_vstat(AFFILE * af,struct af_vnode_info * vni)299 static int split_raw_vstat(AFFILE *af,struct af_vnode_info *vni)
300 {
301 memset(vni,0,sizeof(*vni)); // clear it
302 vni->imagesize = af->image_size;
303 vni->pagesize = af->image_pagesize;
304 vni->supports_compression = 0;
305 vni->supports_metadata = 0;
306 vni->is_raw = 1;
307 vni->changable_pagesize = 1; // change it at any time
308 vni->changable_sectorsize = 1; // change it at any time
309 return 0;
310 }
311
split_raw_read(AFFILE * af,unsigned char * buf,uint64_t pos,size_t count)312 static int split_raw_read(AFFILE *af, unsigned char *buf, uint64_t pos,size_t count)
313 {
314 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
315 off_t c3;
316 int ret = 0; // how many bytes read
317
318 if ((af->image_size - pos) < (unsigned)count){
319 count = (off_t)(af->image_size - pos);
320 }
321
322 while (count > 0) {
323 int filenum = -1;
324 off_t file_offset = 0;
325
326 if (af->maxsize) { // if we do file segments
327 filenum = (int)(pos / af->maxsize);
328 file_offset = (off_t)(pos % af->maxsize);
329 } else {
330 filenum = 0;
331 file_offset = (off_t)pos;
332 }
333 if (file_offset != (off_t) srp->pos[filenum]) {
334 off_t c2 = lseek (srp->fds[filenum], file_offset, SEEK_SET);
335 if (file_offset != c2) { // seek failed; return work to date
336 if (ret) return ret; // some bytes were read; return that
337 else return -1; // no bytes read; return error
338 }
339 srp->pos[filenum] = c2; // this file starts here
340 }
341 if (af->maxsize && ((af->maxsize - file_offset) < (unsigned) count))
342 c3 = (off_t)(af->maxsize - file_offset);
343 else
344 c3 = count;
345 off_t c4 = read (srp->fds[filenum], buf, c3);
346 if (c4 <= 0) { // got an error
347 if (ret) return ret; // return how many bytes we read
348 else return -1; // otherwise, return -1
349 }
350 buf += c4;
351 count -= c4;
352 ret += c4;
353 pos += c4;
354 srp->pos[filenum] += c4; // position of this file pointer
355 if (c3 != c4) return ret; // incomplete?
356 }
357 return ret;
358 }
359
360 /*
361 * split_raw_write_internal2:
362 * If buf==0, assume we are writing zeros to the end of the file,
363 * and just seek to the last character and write a single NUL.
364 */
365
split_raw_write_internal2(AFFILE * af,unsigned char * buf,uint64_t pos,size_t count)366 int split_raw_write_internal2(AFFILE *af, unsigned char *buf, uint64_t pos,size_t count)
367 {
368 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
369 off_t c1, c3;
370 int i;
371 int ret = 0;
372 struct affcallback_info acbi;
373
374 /* Setup the callback structure */
375 memset(&acbi,0,sizeof(acbi));
376 acbi.info_version = 1;
377 acbi.af = af->parent ? af->parent : af;
378 acbi.pagenum = af->image_pagesize ? pos / af->image_pagesize : 0;
379 acbi.bytes_to_write = count;
380
381 while (count > 0) {
382 if (af->maxsize) { // do we need to possibly split into multiple file writes?
383 /* Figure out which file number we will need to write to... */
384 if (pos >= (af->maxsize * srp->num_raw_files)) {
385 int fd = open(srp->next_raw_fname, O_RDWR | O_CREAT | O_EXCL | O_BINARY, af->openmode);
386 if (fd < 0) {
387 (*af->error_reporter)("split_raw_write: open(%s): ",af->fname);
388 if (ret) return ret;
389 else return -1;
390 }
391 srp_add_fd(af,fd);
392 if (split_raw_increment_fname (srp->next_raw_fname) != 0) {
393 (*af->error_reporter)("split_raw_write: too many files\n");
394 if (ret)
395 return ret;
396 else
397 return -1;
398 }
399 }
400 i = (int)(pos / af->maxsize);
401 c1 = (off_t)(pos % af->maxsize);
402 } else {
403 i = 0;
404 c1 = (off_t)pos;
405 }
406 if (c1 != (off_t)srp->pos[i]) { // do we need to seek this file?
407 off_t c2 = lseek (srp->fds[i], c1, SEEK_SET); // try to seek
408 if (c1 != c2) { // hm. Ended up in the wrong place. That's an error
409 if (ret>0) { // return how many bytes we got
410 return ret;
411 }
412 else {
413 return -1;
414 }
415 }
416 srp->pos[i] = c2;
417 }
418 if (af->maxsize && ((af->maxsize - c1) < (unsigned)count))
419 c3 = (off_t)(af->maxsize - c1);
420 else
421 c3 = count;
422 if(af->w_callback) {acbi.phase = 3;(*af->w_callback)(&acbi);}
423
424 /* WRITE THE DATA! */
425 off_t c4 = 0;
426
427 if(buf){
428 c4 = write (srp->fds[i], buf, c3);
429 }
430 else {
431 /* Extend with lseek() and write a single byte */
432 char z = 0;
433
434 lseek(srp->fds[i],c3-1,SEEK_CUR);
435 if(write(srp->fds[i],&z,1)!=1) return -1; // failure
436 c4 = c3;
437 }
438
439 /* DONE! */
440
441 acbi.bytes_written = c4;
442 if(af->w_callback) {acbi.phase = 4;(*af->w_callback)(&acbi);}
443 if (c4 <= 0) { // some error writing?
444 if (ret)
445 return ret;
446 else
447 return -1;
448 }
449 buf += c4;
450 count -= c4;
451 ret += c4;
452 pos += c4;
453 srp->pos[i] += c4;
454 if (af->image_size < pos) af->image_size = pos; // image was extended
455 if (c3 != c4){ // amount written doesn't equal request; return
456 return ret;
457 }
458 }
459 return ret;
460 }
461
split_raw_write(AFFILE * af,unsigned char * buf,uint64_t pos,size_t count)462 int split_raw_write(AFFILE *af, unsigned char *buf, uint64_t pos,size_t count)
463 {
464 /* If we are being asked to start writing beyond the end of the file
465 * pad out the file (and possibly create one or more new image files.)
466 */
467
468 if (af->maxsize) {
469 if (pos > af->image_size) { // writing beyond the end...
470 while(pos > af->image_size){
471
472 /* repeat until file is as big as where we should be writing */
473 int64_t bytes_left = pos - af->image_size;
474 int bytes_to_write = (int)(af->maxsize - (af->image_size % af->maxsize));
475 if(bytes_to_write > bytes_left) bytes_to_write = (int)bytes_left;
476 int bytes_written = split_raw_write_internal2(af,0,af->image_size,bytes_to_write);
477 if(bytes_to_write != bytes_written){
478 return -1; // some kind of internal error
479 }
480 }
481 }
482 }
483
484 return split_raw_write_internal2 (af, buf, pos,count);
485 }
486
487
488
489 /* Get a segment; if a data page is being asked for, then fake it.
490 * Otherwise, return an error.
491 */
492
split_raw_get_seg(AFFILE * af,const char * name,uint32_t * arg,unsigned char * data,size_t * datalen)493 static int split_raw_get_seg(AFFILE *af,const char *name,uint32_t *arg,unsigned char *data,
494 size_t *datalen)
495 {
496 int64_t page_num = af_segname_page_number(name);
497 if(page_num<0){
498 /* See if PAGESIZE or IMAGESIZE is being requested; we can fake those */
499 if(strcmp(name,AF_PAGESIZE)==0){
500 if(arg) *arg = af->image_pagesize;
501 if(datalen) *datalen = 0;
502 return 0;
503 }
504 if(strcmp(name,AF_IMAGESIZE)==0){
505 struct aff_quad q;
506 if(data && *datalen>=8){
507 q.low = htonl((uint32_t)(af->image_size & 0xffffffff));
508 q.high = htonl((uint32_t)(af->image_size >> 32));
509 memcpy(data,&q,8);
510 *datalen = 8;
511 }
512 return 0;
513 }
514 if(strcmp(name,AF_SECTORSIZE)==0){
515 if(arg) *arg = af->image_sectorsize;
516 if(datalen) *datalen = 0;
517 return 0;
518 }
519 if(strcmp(name,AF_DEVICE_SECTORS)==0){
520 int64_t devicesectors = af->image_size / af->image_sectorsize;
521 struct aff_quad q;
522 if(data && *datalen>=8){
523 q.low = htonl((uint32_t)(devicesectors & 0xffffffff));
524 q.high = htonl((uint32_t)(devicesectors >> 32));
525 memcpy(data,&q,8);
526 *datalen = 8;
527 }
528 return 0;
529 }
530 errno = ENOTSUP; // sorry! We don't store metadata
531 return -1;
532 }
533
534 uint64_t pos = page_num * af->image_pagesize; // where we are to start reading
535 uint64_t bytes_left = af->image_size - pos; // how many bytes left in the file
536
537 uint32_t bytes_to_read = af->image_pagesize; // copy this many bytes, unless
538 if(bytes_to_read > bytes_left) bytes_to_read = (uint32_t)bytes_left; // only this much is left
539
540 if(arg) *arg = 0; // arg is always 0
541 if(datalen){
542 if(data==0){ // asked for 0 bytes, so give the actual size
543 *datalen = bytes_to_read;
544 return 0;
545 }
546 if(*datalen < (unsigned)bytes_to_read){
547 *datalen = bytes_to_read;
548 return AF_ERROR_DATASMALL;
549 }
550 }
551 if(data){
552 int bytes_read = split_raw_read(af,data,pos,bytes_to_read);
553 if(bytes_read>=0){
554 if(datalen) *datalen = bytes_read;
555 return 0;
556 }
557 return -1; // some kind of EOF?
558 }
559 return 0; // no problems!
560 }
561
562 /*
563 * split_raw_get_next_seg:
564 * Try get_next_seg on the AFF file first. If that fails,
565 * create the next virtual segment
566 */
567
split_raw_get_next_seg(AFFILE * af,char * segname,size_t segname_len,uint32_t * arg,unsigned char * data,size_t * datalen_)568 static int split_raw_get_next_seg(AFFILE *af,char *segname,size_t segname_len,uint32_t *arg,
569 unsigned char *data,size_t *datalen_)
570 {
571 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
572
573 int64_t total_pages = (af->image_size + af->image_pagesize - 1) / af->image_pagesize;
574 if(srp->cur_page >= total_pages) return -1; // that's all there are
575
576 /* Make the segment name */
577 char pagename[AF_MAX_NAME_LEN];
578 memset(pagename,0,sizeof(pagename));
579 snprintf(pagename,sizeof(pagename),AF_PAGE,srp->cur_page++);
580
581 /* Get the segment, if we can */
582 int r = split_raw_get_seg(af,pagename,arg,data,datalen_);
583
584 /* If r==0 and there is room for copying in the segment name, return it */
585 if(r==0){
586 if(strlen(pagename)+1 < segname_len){
587 strcpy(segname,pagename);
588 return 0;
589 }
590 /* segname wasn't big enough */
591 return -2;
592 }
593 return r; // some other error
594 }
595
596
597 /* Rewind all of the segments */
split_raw_rewind_seg(AFFILE * af)598 static int split_raw_rewind_seg(AFFILE *af)
599 {
600 struct split_raw_private *srp = SPLIT_RAW_PRIVATE(af);
601 srp->cur_page = 0;
602 return 0;
603 }
604
split_raw_update_seg(AFFILE * af,const char * name,uint32_t,const u_char * value,uint32_t vallen)605 static int split_raw_update_seg(AFFILE *af, const char *name,
606 uint32_t /*arg*/,const u_char *value,uint32_t vallen)
607
608 {
609 int64_t page_num = af_segname_page_number(name);
610 if(page_num<0){
611 errno = ENOTSUP; // sorry! We don't store metadata
612 return -1;
613 }
614
615 uint64_t pos = page_num * af->image_pagesize; // where we are to start reading
616 int written = split_raw_write(af, (unsigned char *)value, pos,vallen);
617 if(written==(int)vallen) return 0; // success
618 return -1;
619 }
620
621
622 struct af_vnode vnode_split_raw = {
623 AF_IDENTIFY_SPLIT_RAW,
624 AF_VNODE_TYPE_COMPOUND|AF_VNODE_TYPE_RELIABLE|AF_VNODE_MAXSIZE_MULTIPLE|AF_VNODE_NO_SIGNING|AF_VNODE_NO_SEALING,
625 "Split Raw",
626 split_raw_identify_file,
627 split_raw_open,
628 split_raw_close,
629 split_raw_vstat,
630 split_raw_get_seg, // get seg
631 split_raw_get_next_seg, // get_next_seg
632 split_raw_rewind_seg, // rewind_seg
633 split_raw_update_seg, // update_seg
634 0, // del_seg
635 split_raw_read, // read
636 split_raw_write // write
637 };
638
639
640