1 /*
2 * utility functions used by AFFLIB.
3 * These functions do not actually read or write data into the AFF File.
4 * Distributed under the Berkeley 4-part license.
5 */
6
7 #include "affconfig.h"
8 #include "afflib.h"
9 #include "afflib_i.h"
10
11 #ifndef HAVE_ERR
12 #include <stdarg.h>
err(int eval,const char * fmt,...)13 void err(int eval,const char *fmt,...)
14 {
15 va_list ap;
16 va_start(ap,fmt);
17 vfprintf(stderr,fmt,ap);
18 va_end(ap);
19 fprintf(stderr,": %s\n",strerror(errno));
20 exit(eval);
21 }
22 #endif
23
af_err(int eval,const char * fmt,...)24 void af_err(int eval,const char *fmt,...)
25 {
26 va_list ap;
27 va_start(ap,fmt);
28 vfprintf(stderr,fmt,ap);
29 va_end(ap);
30 if(af_error_str[0]) fprintf(stderr,": %s",af_error_str);
31 if(errno) fprintf(stderr,": %s",strerror(errno));
32 fputc('\n',stderr);
33 exit(eval);
34 }
35
36
37 #ifndef HAVE_ERRX
38 #include <stdarg.h>
errx(int eval,const char * fmt,...)39 void errx(int eval,const char *fmt,...)
40 {
41 va_list ap;
42 va_start(ap,fmt);
43 vfprintf(stderr,fmt,ap);
44 fprintf(stderr,"%s\n",strerror(errno));
45 va_end(ap);
46 exit(eval);
47 }
48 #endif
49
50 #ifndef HAVE_WARN
51 #include <stdarg.h>
warn(const char * fmt,...)52 void warn(const char *fmt, ...)
53 {
54 va_list args;
55 va_start(args,fmt);
56 vfprintf(stderr,fmt, args);
57 fprintf(stderr,": %s",strerror(errno));
58 }
59 #endif
60
61 #ifndef HAVE_WARNX
62 #include <stdarg.h>
warnx(const char * fmt,...)63 void warnx(const char *fmt,...)
64 {
65 va_list ap;
66 va_start(ap,fmt);
67 vfprintf(stderr,fmt,ap);
68 va_end(ap);
69 }
70 #endif
71
72
73
74
75 /*
76 * af_hexbuf:
77 * Turn a binay string into a hex string, optionally with spaces.
78 */
79
af_hexbuf(char * dst,int dst_len,const unsigned char * bin,int bytes,int flag)80 const char *af_hexbuf(char *dst,int dst_len,const unsigned char *bin,int bytes,int flag)
81 {
82 int charcount = 0;
83 const char *start = dst; // remember where the start of the string is
84 const char *fmt = (flag & AF_HEXBUF_UPPERCASE) ? "%02X" : "%02x";
85
86 *dst = 0; // begin with null termination
87 while(bytes>0 && dst_len > 3){
88 sprintf(dst,fmt,*bin); // convert the next byte
89 dst += 2;
90 bin += 1;
91 dst_len -= 2;
92 bytes--;
93 charcount++; // how many characters
94
95 if((flag & AF_HEXBUF_SPACE4) && charcount%2==0){
96 *dst++ = ' ';
97 *dst = '\000';
98 dst_len -= 1;
99 }
100 }
101 return start; // return the start
102 }
103
104
105 /* Add commas
106 */
af_commas(char buf[64],int64_t val)107 const char *af_commas(char buf[64],int64_t val)
108 {
109 char tmp[64];
110 char t2[64];
111 int negative = 0;
112
113 buf[0] = 0;
114 if(val==0){
115 strcpy(buf,"0");
116 }
117 if(val<0){
118 negative = 1;
119 val = -val;
120 }
121
122 while(val>0){
123 int digits = val % 1000; // get the residue
124 val = val / 1000; // and shift what's over
125
126 if(val>0){ // we will still have more to do
127 sprintf(tmp,",%03d",digits); // so pad it with zeros and a comma
128 }
129 else {
130 sprintf(tmp,"%d",digits); // otherwise just get the value
131 }
132 strcpy(t2,buf); // copy out the buffer
133 strcpy(buf,tmp); // copy in what we just did
134 strcat(buf,t2); // and put back what was there
135 }
136 if(negative){
137 strcpy(t2,buf);
138 strcpy(buf,"-");
139 strcat(buf,t2);
140 }
141 return buf;
142 }
143
af_decode_q(unsigned char buf[8])144 uint64_t af_decode_q(unsigned char buf[8])
145 {
146 struct aff_quad *q = (struct aff_quad *)buf; // point q to buf.
147
148 assert(sizeof(*q)==8); // be sure!
149 return (((uint64_t)ntohl(q->high)) << 32) + ((uint64_t)ntohl(q->low));
150 }
151
152 /* parse the segment number.
153 * The extra %c picks up characters that might be after the number,
154 * so that page5_hash doesn't match for page5.
155 */
af_segname_page_number(const char * name)156 int64_t af_segname_page_number(const char *name)
157 {
158 #ifdef KERNEL_LIBRARY
159 #define PAGE_NAME "page"
160 if(_strnicmp(name,PAGE_NAME,strlen(PAGE_NAME))==0)
161 {
162 int64_t pagenum;
163 for (int i=strlen(PAGE_NAME);i<strlen(name);i++)
164 if (!isdigit(name[i])) return -1;
165
166 pagenum = _atoi64(name+strlen(PAGE_NAME));
167 return pagenum;
168 }
169 #define SEG_NAME "seg"
170 if(_strnicmp(name,SEG_NAME,strlen(SEG_NAME))==0)
171 {
172 int64_t pagenum;
173 for (int i=strlen(SEG_NAME);i<strlen(name);i++)
174 if (!isdigit(name[i])) return -1;
175
176 pagenum = _atoi64(name+strlen(SEG_NAME));
177 return pagenum;
178 }
179 return -1;
180 #else
181 int64_t pagenum;
182 char ch;
183 if(sscanf(name,AF_PAGE"%c",&pagenum,&ch)==1){
184 return pagenum; // new-style page number
185 }
186 if(sscanf(name,AF_SEG_D"%c",&pagenum,&ch)==1){
187 return pagenum; // old-style page number
188 }
189 return -1;
190 #endif
191 }
192
af_segname_hash_page_number(const char * name,char * hash,int hashlen)193 int64_t af_segname_hash_page_number(const char *name,char *hash,int hashlen)
194 {
195 char copy[AF_MAX_NAME_LEN];
196 const char *cc = strchr((char *)name,'_');
197 if(!cc) return -1; // not possibly correct
198 strlcpy(copy,name,sizeof(copy));
199 char *dd = strchr(copy,'_');
200 if(!dd) return -1; // really weird; shouldn't happen
201 *dd++ = '\000'; // terminate at _
202 if(strcmp(dd,"md5")!=0) return -1; // not a valid hash
203 int64_t page = af_segname_page_number(copy);
204 if(page<0) return -1; // wasn't what we wanted
205 strlcpy(hash,dd,hashlen);
206 return page;
207 }
208
af_hasmeta(const char * infile)209 int af_hasmeta(const char *infile)
210 {
211 /* return 1 if the string has shell metacharacters */
212 for(const char *cc = infile;*cc;cc++){
213 switch(*cc){
214 case '?': return 1;
215 case '*': return 1;
216 case '&': return 1;
217 case '`': return 1;
218 case '(': return 1;
219 case ')': return 1;
220 }
221 }
222 return 0;
223 }
224
225 /* It is a filestream if the filename begins file:// or has no "://" in it */
af_is_filestream(const char * filename)226 int af_is_filestream(const char *filename)
227 {
228 if(strncmp(filename,"file://",7)==0) return 1;
229 if(strstr(filename,"://")==0) return 1;
230 return 0;
231 }
232
233
234
235
236
237
238 #ifndef HAVE_STRLCPY
strlcpy(char * dest,const char * src,size_t dest_size)239 size_t strlcpy(char *dest,const char *src,size_t dest_size)
240 {
241 strncpy(dest,src,dest_size);
242 dest[dest_size-1] = '\000';
243 return strlen(dest);
244 }
245 #endif
246
247 #ifndef HAVE_STRLCAT
strlcat(char * dest,const char * src,size_t dest_size)248 size_t strlcat(char *dest,const char *src,size_t dest_size)
249 {
250 int dest_len = strlen(dest);
251 int src_len = strlen(src);
252 int room = dest_size - (dest_len +src_len+1);
253 if(room>0){
254 /* There is room; just copy over what we have and return */
255 strcat(dest,src);
256 return strlen(dest);
257 }
258 /* Not room; figure out how many bytes we can copy... */
259 int left = dest_size - (dest_len+1);
260 strncpy(dest+dest_len,src,left);
261 dest[dest_len-1] = '\000';
262 return strlen(dest);
263 }
264 #endif
265
266 /* Parse a URL. Allocate the parts if requested. Default protocol is "file", of course*/
af_parse_url(const char * url,char ** protocol,char ** hostname,char ** username,char ** password,int * port,char ** path)267 void af_parse_url(const char *url,char **protocol,char **hostname,char **username,char **password,
268 int *port,char **path)
269 {
270 const char *p1 = strstr(url,"://");
271 if(!p1){
272 if(protocol) *protocol = strdup("file");
273 if(path) *path = strdup(url);
274 return;
275 }
276 if(protocol){
277 int len = p1-url;
278 *protocol = (char *)malloc(len+1);
279 strncpy(*protocol,url,len);
280 }
281 url = p1+3; // move past ://
282
283 const char *at = strchr(url,'@');
284 if(at){ // we may have a username and/or password
285 char *scratch = (char *)malloc(at-url+1);
286 strncpy(scratch,url,at-url);
287 scratch[at-url]='\000';
288 char *colon = strchr(scratch,':');
289 if(colon){
290 *colon = '\000';
291 }
292 if(username) *username = strdup(scratch);
293 if(colon){
294 if(password) *password = strdup(colon+1);
295 }
296 free(scratch);
297 url = at+1;
298 }
299
300 /* Process hostname if it exists */
301 const char *slash = strchr(url,'/');
302 if(slash){
303 char *scratch = (char *)malloc(slash-url+1);
304 strncpy(scratch,url,slash-url);
305 scratch[slash-url]='\000';
306 char *colon = strchr(scratch,':');
307 if(colon){
308 *colon = '\000';
309 }
310 if(hostname) *hostname = strdup(scratch);
311 if(colon){
312 if(port) *port = atoi(colon+1);
313 }
314 free(scratch);
315 url = slash+1;
316 }
317 if(path) *path = strdup(url); // remember file name
318 }
319