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