1 /* Distributed under the 4-part Berkeley License */
2 
3 /*
4  * afflib_db.cpp:
5  *
6  * Functions for the manipulation of the AFF database.
7  */
8 
9 
10 #include "affconfig.h"
11 #include "afflib.h"
12 #include "afflib_i.h"
13 #include "aff_db.h"
14 
15 
16 /****************************************************************
17  *** Low-level functions
18  ****************************************************************/
19 
20 /****************************************************************
21  *** Probe Functions
22  ****************************************************************/
23 
af_probe_next_seg(AFFILE * af,char * segname,size_t segname_len,uint32_t * arg_,size_t * datasize_,size_t * segsize_,int do_rewind)24 int af_probe_next_seg(AFFILE *af,
25 		       char *segname,
26 		       size_t segname_len,
27 		       uint32_t *arg_, // optional arg
28 		       size_t *datasize_, // optional get datasize
29 		       size_t *segsize_, // optional get size of entire segment
30 		       int do_rewind) // optional rewind af->aseg, otherwise leave at start of segment data
31 {
32     if(!af->aseg)(*af->error_reporter)("af_probe_next_segment only works with aff files");
33 
34     struct af_segment_head segh;
35     memset(&segh,0,sizeof(segh));
36 
37     uint64_t start = ftello(af->aseg);
38 #ifdef __BORLANDC__
39     fseeko(af->aseg, start, SEEK_SET) ;    // Windows is dumb :-(
40 #endif
41 
42     if(fread(&segh,sizeof(segh),1,af->aseg)!=1){
43 	return AF_ERROR_EOF;
44     }
45     if(strcmp(segh.magic,AF_SEGHEAD)!=0){
46 	snprintf(af->error_str,sizeof(af->error_str),"afflib: segh is corrupt at %" PRIu64,start);
47 	return AF_ERROR_SEGH;
48     }
49 
50     uint32_t name_len = ntohl(segh.name_len);
51     uint32_t datasize = ntohl(segh.data_len);
52     if(name_len>AF_MAX_NAME_LEN){
53 	snprintf(af->error_str,sizeof(af->error_str),"afflib: name_len=%" PRIu32 " (an outrageous value)",name_len);
54 	return AF_ERROR_NAME;
55     }
56 
57     if(name_len+1 > segname_len){
58 	fseeko(af->aseg,start,SEEK_SET); // rewind to start
59 	return -2;
60     }
61 
62     if(fread(segname,1,name_len,af->aseg)!=name_len){
63 	fseeko(af->aseg,start,SEEK_SET); // rewind
64 	return -1;
65     }
66     segname[name_len] = 0;
67 
68     if(do_rewind) fseeko(af->aseg,start,SEEK_SET); // rewind
69 
70     uint32_t segsize = sizeof(struct af_segment_head)
71 	+ sizeof(struct af_segment_tail)
72 	+ name_len + datasize;
73 
74     if(arg_)      *arg_      = ntohl(segh.flag);
75     if(datasize_) *datasize_ = datasize;
76     if(segsize_)  *segsize_ = segsize;
77 
78 #ifdef DEBUG
79     fprintf(stderr,"af_probe_next_seg(segname=%s datasize=%d segsize=%d) do_rewind=%d\n",
80 	    segname,datasize,segsize,do_rewind);
81 #endif
82     return 0;
83 }
84 
85 /* af_backspace:
86  * moves back one segment in the aff file.
87  * Returns 0 if success, -1 if we can't back up further.
88  */
af_backspace(AFFILE * af)89 int af_backspace(AFFILE *af)
90 {
91     struct af_segment_tail segt;
92 
93     uint64_t start = ftello(af->aseg);
94 
95     if(start==sizeof(AF_HEADER) || start<sizeof(segt)) return -1; // can't backspace further
96 
97     uint64_t pos_tail = start - sizeof(segt); // backspace to read the tail
98     fseeko(af->aseg,pos_tail,SEEK_SET);
99     if(fread(&segt,sizeof(segt),1,af->aseg)!=1){
100 	fseeko(af->aseg,start,SEEK_SET); // put it back
101 	return -1;			// can't read segt?
102     }
103     /* Verify that this is a segment tail. if it isn't, put the file pointer back and return */
104     if(memcmp(segt.magic,AF_SEGTAIL,sizeof(AF_SEGTAIL))!=0){
105 	fseeko(af->aseg,start,SEEK_SET);
106 	return -1;
107     }
108 
109     /* Now I know how long the segment was. Compute where it started */
110     uint64_t seg_start = start - ntohl(segt.segment_len);
111     fseeko(af->aseg,seg_start,SEEK_SET);
112     return 0;
113 }
114 
115 
116 
117 /* find the given segment and return 0 if found.
118  * Leave the file pointer positioned at the start of the segment.
119  * Return -1 if segment is not found, and leave pointer at the end
120  */
aff_find_seg(AFFILE * af,const char * segname,uint32_t * arg,size_t * datasize,size_t * segsize)121 int	aff_find_seg(AFFILE *af,const char *segname,
122 		    uint32_t *arg,
123 		    size_t *datasize,
124 		    size_t *segsize)
125 {
126     char   next_segment_name[AF_MAX_NAME_LEN];
127     size_t next_segsize = 0;
128     size_t next_datasize = 0;
129     uint32_t next_arg;
130 
131     /* Try to use the TOC to find the segment in question */
132     struct aff_toc_mem *adm = aff_toc(af,segname);
133     if(adm){
134 	if(datasize==0 && segsize==0 && arg==0){
135 	    /* User was just probing to see if it was present. And it is! */
136 	    return 0;
137 	}
138 	fseeko(af->aseg,adm->offset,SEEK_SET);
139     }
140     else {
141 	af_rewind_seg(af);
142     }
143     while(af_probe_next_seg(af,next_segment_name,sizeof(next_segment_name),
144 			    &next_arg,&next_datasize,&next_segsize,1)==0){
145 	if(strcmp(next_segment_name,segname)==0){	// found the segment!
146 	    if(datasize) *datasize = next_datasize;
147 	    if(segsize)  *segsize  = next_segsize;
148 	    if(arg)      *arg      = next_arg;
149 	    return 0;			// return the info
150 	}
151 	fseeko(af->aseg,next_segsize,SEEK_CUR);	// skip the segment
152     }
153     return -1;				// couldn't find segment
154 }
155 
af_get_segq(AFFILE * af,const char * name,int64_t * aff_quad)156 int af_get_segq(AFFILE *af,const char *name,int64_t *aff_quad)
157 {
158     unsigned char buf[8];
159     size_t  bufsize = sizeof(buf);
160 
161     if(af_get_seg(af,name,0,(unsigned char *)&buf,&bufsize)){
162 	return -1;			// couldn't get it...
163     }
164     if(bufsize!=sizeof(struct aff_quad)){		// make sure size is good.
165 	return -1;
166     }
167 
168     *aff_quad = af_decode_q(buf);
169     return 0;
170 }
171 
172 
173 /* af_update_segq:
174  * Update the named aff_quad-byte value.
175  */
176 
177 
af_update_segq(AFFILE * af,const char * name,int64_t value)178 int af_update_segq(AFFILE *af, const char *name, int64_t value)
179 {
180     struct aff_quad  q;
181     q.low  = htonl((uint32_t)(value & 0xffffffff));
182     q.high = htonl((uint32_t)(value >> 32));
183     return af_update_seg(af,name,AF_SEG_QUADWORD,(const u_char *)&q,8);
184 }
185 
186 
187