1 /* radare - LGPL - Copyright 2007-2020 - pancake */
2 
3 #include "r_types.h"
4 #include "r_util.h"
5 #include <stdio.h>
6 #include <time.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <r_lib.h>
11 #if __UNIX__
12 #include <sys/time.h>
13 #include <sys/mman.h>
14 #include <limits.h>
15 #endif
16 #if __APPLE__ && __MAC_10_5
17 #define HAVE_COPYFILE_H 1
18 #else
19 #define HAVE_COPYFILE_H 0
20 #endif
21 #if HAVE_COPYFILE_H
22 #include <copyfile.h>
23 #endif
24 #if _MSC_VER
25 #include <process.h>
26 #endif
27 
28 #define BS 1024
29 
file_stat(const char * file,struct stat * const pStat)30 static int file_stat(const char *file, struct stat* const pStat) {
31 	r_return_val_if_fail (file && pStat, -1);
32 #if __WINDOWS__
33 	wchar_t *wfile = r_utf8_to_utf16 (file);
34 	if (!wfile) {
35 		return -1;
36 	}
37 	int ret = _wstat (wfile, pStat);
38 	free (wfile);
39 	return ret;
40 #else // __WINDOWS__
41 	return stat (file, pStat);
42 #endif // __WINDOWS__
43 }
44 
45 // r_file_new("", "bin", NULL) -> /bin
46 // r_file_new(".", "bin", NULL) -> ./bin
47 // r_file_new("/", "bin", NULL) -> //bin # shall we be stricts?
r_file_new(const char * root,...)48 R_API char *r_file_new(const char *root, ...) {
49 	va_list ap;
50 	va_start (ap, root);
51 	RStrBuf *sb = r_strbuf_new ("");
52 	char *home = r_str_home (NULL);
53 	const char *arg = va_arg (ap, char *);
54 	r_strbuf_append (sb, arg);
55 	arg = va_arg (ap, char *);
56 	while (arg) {
57 		if (!strcmp (arg, "~")) {
58 			arg = home;
59 		}
60 		r_strbuf_append (sb, R_SYS_DIR);
61 		r_strbuf_append (sb, arg);
62 		arg = va_arg (ap, char *);
63 	}
64 	va_end (ap);
65 	free (home);
66 	char *path = r_strbuf_drain (sb);
67 	char *abs = r_file_abspath (path);
68 	free (path);
69 	return abs;
70 }
71 
r_file_truncate(const char * filename,ut64 newsize)72 R_API bool r_file_truncate(const char *filename, ut64 newsize) {
73 	r_return_val_if_fail (filename, false);
74 	int fd;
75 	if (r_file_is_directory (filename)) {
76 		return false;
77 	}
78 	if (!r_file_exists (filename) || !r_file_is_regular (filename)) {
79 		return false;
80 	}
81 #if __WINDOWS__
82 	fd = r_sandbox_open (filename, O_RDWR, 0644);
83 #else
84 	fd = r_sandbox_open (filename, O_RDWR | O_SYNC, 0644);
85 #endif
86 	if (fd == -1) {
87 		return false;
88 	}
89 #ifdef _MSC_VER
90 	int r = _chsize (fd, newsize);
91 #else
92 	int r = ftruncate (fd, newsize);
93 #endif
94 	if (r != 0) {
95 		eprintf ("Could not resize %s file\n", filename);
96 		close (fd);
97 		return false;
98 	}
99 	close (fd);
100 	return true;
101 }
102 
103 /*
104 Example:
105 	str = r_file_basename ("home/inisider/Downloads/user32.dll");
106 	// str == user32.dll
107 */
r_file_basename(const char * path)108 R_API const char *r_file_basename(const char *path) {
109 	r_return_val_if_fail (path, NULL);
110 	const char *ptr = r_str_rchr (path, NULL, '/');
111 	if (ptr) {
112 		path = ptr + 1;
113 	} else {
114 		if ((ptr = r_str_rchr (path, NULL, '\\'))) {
115 			path = ptr + 1;
116 		}
117 	}
118 	return path;
119 }
120 
121 /*
122 Example:
123 	str = r_file_basename ("home/inisider/Downloads");
124 	// str == "home/inisider/Downloads"
125 	free (str);
126 */
r_file_dirname(const char * path)127 R_API char *r_file_dirname(const char *path) {
128 	r_return_val_if_fail (path, NULL);
129 	char *newpath = strdup (path);
130 	char *ptr = (char*)r_str_rchr (newpath, NULL, '/');
131 	if (ptr) {
132 		*ptr = 0;
133 	} else {
134 		ptr = (char*)r_str_rchr (newpath, NULL, '\\');
135 		if (ptr) {
136 			*ptr = 0;
137 		}
138 	}
139 	return newpath;
140 }
141 
r_file_is_c(const char * file)142 R_API bool r_file_is_c(const char *file) {
143 	r_return_val_if_fail (file, false);
144 	const char *ext = r_str_lchr (file, '.'); // TODO: add api in r_file_extension or r_str_ext for this
145 	if (ext) {
146 		ext++;
147 		if (!strcmp (ext, "cparse")
148 		||  !strcmp (ext, "c")
149 		||  !strcmp (ext, "h")) {
150 			return true;
151 		}
152 	}
153 	return false;
154 }
155 
r_file_is_regular(const char * str)156 R_API bool r_file_is_regular(const char *str) {
157 	struct stat buf = {0};
158 	if (!str || !*str || file_stat (str, &buf) == -1) {
159 		return false;
160 	}
161 	return ((S_IFREG & buf.st_mode) == S_IFREG);
162 }
163 
r_file_is_directory(const char * str)164 R_API bool r_file_is_directory(const char *str) {
165 	struct stat buf = {0};
166 	r_return_val_if_fail (!R_STR_ISEMPTY (str), false);
167 	if (file_stat (str, &buf) == -1) {
168 		return false;
169 	}
170 #ifdef S_IFBLK
171 	if ((S_IFBLK & buf.st_mode) == S_IFBLK) {
172 		return false;
173 	}
174 #endif
175 	return S_IFDIR == (S_IFDIR & buf.st_mode);
176 }
177 
r_file_fexists(const char * fmt,...)178 R_API bool r_file_fexists(const char *fmt, ...) {
179 	int ret;
180 	char string[BS];
181 	va_list ap;
182 	va_start (ap, fmt);
183 	vsnprintf (string, sizeof (string), fmt, ap);
184 	ret = r_file_exists (string);
185 	va_end (ap);
186 	return ret;
187 }
188 
r_file_exists(const char * str)189 R_API bool r_file_exists(const char *str) {
190 	char *absfile = r_file_abspath (str);
191 	struct stat buf = {0};
192 	r_return_val_if_fail (!R_STR_ISEMPTY (str), false);
193 	if (file_stat (absfile, &buf) == -1) {
194 		free (absfile);
195 		return false;
196 	}
197 	free (absfile);
198 	return S_IFREG == (S_IFREG & buf.st_mode);
199 }
200 
r_file_size(const char * str)201 R_API ut64 r_file_size(const char *str) {
202 	r_return_val_if_fail (!R_STR_ISEMPTY (str), 0);
203 	struct stat buf = {0};
204 	if (file_stat (str, &buf) == -1) {
205 		return 0;
206 	}
207 	return (ut64)buf.st_size;
208 }
209 
r_file_is_abspath(const char * file)210 R_API bool r_file_is_abspath(const char *file) {
211 	r_return_val_if_fail (!R_STR_ISEMPTY (file), 0);
212 	return ((*file && file[1]==':') || *file == '/');
213 }
214 
r_file_abspath_rel(const char * cwd,const char * file)215 R_API char *r_file_abspath_rel(const char *cwd, const char *file) {
216 	char *ret = NULL;
217 	if (!file || !strcmp (file, ".") || !strcmp (file, "./")) {
218 		return r_sys_getdir ();
219 	}
220 	if (strstr (file, "://")) {
221 		return strdup (file);
222 	}
223 	if (!strncmp (file, "~/", 2) || !strncmp (file, "~\\", 2)) {
224 		ret = r_str_home (file + 2);
225 	} else {
226 #if __UNIX__
227 		if (cwd && *file != '/') {
228 			ret = r_str_newf ("%s" R_SYS_DIR "%s", cwd, file);
229 		}
230 #elif __WINDOWS__
231 		// Network path
232 		if (!strncmp (file, "\\\\", 2)) {
233 			return strdup (file);
234 		}
235 		if (!strchr (file, ':')) {
236 			PTCHAR abspath = malloc (MAX_PATH * sizeof (TCHAR));
237 			if (abspath) {
238 				PTCHAR f = r_sys_conv_utf8_to_win (file);
239 				int s = GetFullPathName (f, MAX_PATH, abspath, NULL);
240 				if (s > MAX_PATH) {
241 					R_LOG_ERROR ("r_file_abspath/GetFullPathName: Path to file too long.\n");
242 				} else if (!s) {
243 					r_sys_perror ("r_file_abspath/GetFullPathName");
244 				} else {
245 					ret = r_sys_conv_win_to_utf8 (abspath);
246 				}
247 				free (abspath);
248 				free (f);
249 			}
250 		}
251 #endif
252 	}
253 	if (!ret) {
254 		ret = strdup (file);
255 	}
256 #if __UNIX__
257 	char *abspath = realpath (ret, NULL);
258 	if (abspath) {
259 		free (ret);
260 		ret = abspath;
261 	}
262 #endif
263 	return ret;
264 }
265 
r_file_abspath(const char * file)266 R_API char *r_file_abspath(const char *file) {
267 	r_return_val_if_fail (file, NULL);
268 	char *cwd = r_sys_getdir ();
269 	if (cwd) {
270 		char *ret = r_file_abspath_rel (cwd, file);
271 		free (cwd);
272 		return ret;
273 	}
274 	return NULL;
275 }
276 
r_file_path(const char * bin)277 R_API char *r_file_path(const char *bin) {
278 	r_return_val_if_fail (bin, NULL);
279 	char *file = NULL;
280 	char *path = NULL;
281 	char *str, *ptr;
282 	const char *extension = "";
283 	if (!strncmp (bin, "./", 2)) {
284 		return r_file_exists (bin)
285 			? r_file_abspath (bin): NULL;
286 	}
287 	char *path_env = (char *)r_sys_getenv ("PATH");
288 #if __WINDOWS__
289 	if (!r_str_endswith (bin, ".exe")) {
290 		extension = ".exe";
291 	}
292 #endif
293 	if (path_env) {
294 		str = path = strdup (path_env);
295 		do {
296 			ptr = strchr (str, R_SYS_ENVSEP[0]);
297 			if (ptr) {
298 				*ptr = '\0';
299 				file = r_str_newf (R_JOIN_2_PATHS ("%s", "%s%s"), str, bin, extension);
300 				if (r_file_exists (file)) {
301 					free (path);
302 					free (path_env);
303 					return file;
304 				}
305 				str = ptr + 1;
306 				free (file);
307 			}
308 		} while (ptr);
309 	}
310 	free (path_env);
311 	free (path);
312 	return strdup (bin);
313 }
314 
r_stdin_slurp(int * sz)315 R_API char *r_stdin_slurp (int *sz) {
316 #if __UNIX__ || __WINDOWS__
317 	int i, ret, newfd;
318 	if ((newfd = dup (0)) < 0) {
319 		return NULL;
320 	}
321 	char *buf = malloc (BS);
322 	if (!buf) {
323 		close (newfd);
324 		return NULL;
325 	}
326 	for (i = ret = 0; i >= 0; i += ret) {
327 		char *new = realloc (buf, i + BS);
328 		if (!new) {
329 			eprintf ("Cannot realloc to %d\n", i+BS);
330 			free (buf);
331 			return NULL;
332 		}
333 		buf = new;
334 		ret = read (0, buf + i, BS);
335 		if (ret < 1) {
336 			break;
337 		}
338 	}
339 	if (i < 1) {
340 		i = 0;
341 		R_FREE (buf);
342 	} else {
343 		buf[i] = 0;
344 		dup2 (newfd, 0);
345 		close (newfd);
346 	}
347 	if (sz) {
348 		*sz = i;
349 	}
350 	if (!i) {
351 		R_FREE (buf);
352 	}
353 	return buf;
354 #else
355 #warning TODO r_stdin_slurp
356 	return NULL;
357 #endif
358 }
359 
r_file_slurp(const char * str,R_NULLABLE size_t * usz)360 R_API char *r_file_slurp(const char *str, R_NULLABLE size_t *usz) {
361 	r_return_val_if_fail (str, NULL);
362 	if (usz) {
363 		*usz = 0;
364 	}
365 	if (!r_file_exists (str)) {
366 		return NULL;
367 	}
368 	FILE *fd = r_sandbox_fopen (str, "rb");
369 	if (!fd) {
370 		return NULL;
371 	}
372 	if (fseek (fd, 0, SEEK_END) == -1) {
373 		// cannot determine the size of the file
374 	}
375 	long sz = ftell (fd);
376 	if (sz < 0) {
377 		fclose (fd);
378 		return NULL;
379 	}
380 	if (!sz) {
381 		if (r_file_is_regular (str)) {
382 			char *buf = NULL;
383 			long size = 0;
384 			(void)fseek (fd, 0, SEEK_SET);
385 			do {
386 				char *nbuf = realloc (buf, size + BS);
387 				if (!nbuf) {
388 					break;
389 				}
390 				buf = nbuf;
391 				size_t r = fread (buf + size, 1, BS, fd);
392 				if (ferror (fd)) {
393 					R_FREE (buf);
394 					goto regular_err;
395 				}
396 				size += r;
397 			} while (!feof (fd));
398 			char *nbuf = realloc (buf, size + 1);
399 			if (!nbuf) {
400 				free (buf);
401 				return NULL;
402 			}
403 			buf = nbuf;
404 			buf[size] = '\0';
405 			if (usz) {
406 				*usz = size;
407 			}
408 		regular_err:
409 			fclose (fd);
410 			return buf;
411 		}
412 		// try to read 64K
413 		sz = UT16_MAX;
414 	}
415 	rewind (fd);
416 	char *ret = (char *)malloc (sz + 1);
417 	if (!ret) {
418 		fclose (fd);
419 		return NULL;
420 	}
421 	size_t rsz = fread (ret, 1, sz, fd);
422 	if (rsz != sz) {
423 		eprintf ("Warning: r_file_slurp: fread: truncated read\n");
424 		sz = rsz;
425 	}
426 	fclose (fd);
427 	ret[sz] = '\0';
428 	if (usz) {
429 		*usz = sz;
430 	}
431 	return ret;
432 }
433 
r_file_gzslurp(const char * str,int * outlen,int origonfail)434 R_API ut8 *r_file_gzslurp(const char *str, int *outlen, int origonfail) {
435 	r_return_val_if_fail (str, NULL);
436 	if (outlen) {
437 		*outlen = 0;
438 	}
439 	size_t sz;
440 	ut8 *in = (ut8*)r_file_slurp (str, &sz);
441 	if (!in) {
442 		return NULL;
443 	}
444 	ut8 *out = r_inflate (in, (int)sz, NULL, outlen);
445 	if (!out && origonfail) {
446 		// if uncompression fails, return orig buffer ?
447 		if (outlen) {
448 			*outlen = (int)sz;
449 		}
450 		in[sz] = 0;
451 		return in;
452 	}
453 	free (in);
454 	return out;
455 }
456 
r_file_slurp_hexpairs(const char * str,int * usz)457 R_API ut8 *r_file_slurp_hexpairs(const char *str, int *usz) {
458 	r_return_val_if_fail (str, NULL);
459 	if (usz) {
460 		*usz = 0;
461 	}
462 	ut8 *ret;
463 	long sz;
464 	int c, bytes = 0;
465 	FILE *fd = r_sandbox_fopen (str, "rb");
466 	if (!fd) {
467 		return NULL;
468 	}
469 	(void) fseek (fd, 0, SEEK_END);
470 	sz = ftell (fd);
471 	(void) fseek (fd, 0, SEEK_SET);
472 	ret = (ut8*)malloc ((sz>>1)+1);
473 	if (!ret) {
474 		fclose (fd);
475 		return NULL;
476 	}
477 	for (;;) {
478 		if (fscanf (fd, " #%*[^\n]") == 1)  {
479 			continue;
480 		}
481 		if (fscanf (fd, "%02x", &c) == 1) {
482 			ret[bytes++] = c;
483 			continue;
484 		}
485 		if (feof (fd)) {
486 			break;
487 		}
488 		free (ret);
489 		fclose (fd);
490 		return NULL;
491 	}
492 	ret[bytes] = '\0';
493 	fclose (fd);
494 	if (usz) {
495 		*usz = bytes;
496 	}
497 	return ret;
498 }
499 
r_file_slurp_range(const char * str,ut64 off,int sz,int * osz)500 R_API char *r_file_slurp_range(const char *str, ut64 off, int sz, int *osz) {
501 	char *ret;
502 	size_t read_items;
503 	FILE *fd = r_sandbox_fopen (str, "rb");
504 	if (!fd) {
505 		return NULL;
506 	}
507 	// XXX handle out of bound reads (eof)
508 	if (fseek (fd, off, SEEK_SET) < 0) {
509 		fclose (fd);
510 		return NULL;
511 	}
512 	ret = (char *) malloc (sz + 1);
513 	if (ret) {
514 		if (osz) {
515 			*osz = (int)(size_t) fread (ret, 1, sz, fd);
516 		} else {
517 			read_items = fread (ret, 1, sz, fd);
518 			if (!read_items) {
519 				fclose (fd);
520 				return ret;
521 			}
522 		}
523 		ret[sz] = '\0';
524 	}
525 	fclose (fd);
526 	return ret;
527 }
528 
r_file_slurp_random_line(const char * file)529 R_API char *r_file_slurp_random_line(const char *file) {
530 	r_return_val_if_fail (file, NULL);
531 	int i = 0;
532 	return r_file_slurp_random_line_count (file, &i);
533 }
534 
r_file_slurp_random_line_count(const char * file,int * line)535 R_API char *r_file_slurp_random_line_count(const char *file, int *line) {
536 	r_return_val_if_fail (file && line, NULL);
537 	/* Reservoir Sampling */
538 	char *ptr = NULL, *str;
539 	size_t i, lines, selection = -1;
540 	int start = *line;
541 	if ((str = r_file_slurp (file, NULL))) {
542 		r_num_irand ();
543 		for (i = 0; str[i]; i++) {
544 			if (str[i] == '\n') {
545 				//here rand doesn't have any security implication
546 				// https://www.securecoding.cert.org/confluence/display/c/MSC30-C.+Do+not+use+the+rand()+function+for+generating+pseudorandom+numbers
547 				if (!(r_num_rand ((++(*line))))) {
548 					selection = (*line - 1);  /* The line we want. */
549 				}
550 			}
551 		}
552 		if ((selection < start) || (selection == -1)) {
553 			free (str);
554 			return NULL;
555 		} else {
556 			lines = selection - start;
557 		}
558 		if (lines > 0) {
559 			for (i = 0; str[i] && lines; i++) {
560 				if (str[i] == '\n') {
561 					lines--;
562 				}
563 			}
564 			ptr = str + i;
565 			for (i = 0; ptr[i]; i++) {
566 				if (ptr[i] == '\n') {
567 					ptr[i] = '\0';
568 					break;
569 				}
570 			}
571 			ptr = strdup (ptr);
572 		}
573 		free (str);
574 	}
575 	return ptr;
576 }
577 
r_file_slurp_line(const char * file,int line,int context)578 R_API char *r_file_slurp_line(const char *file, int line, int context) {
579 	r_return_val_if_fail (file, NULL);
580 	int i, lines = 0;
581 	size_t sz;
582 	char *ptr = NULL, *str = r_file_slurp (file, &sz);
583 	// TODO: Implement context
584 	if (str) {
585 		for (i = 0; str[i]; i++) {
586 			if (str[i] == '\n') {
587 				lines++;
588 			}
589 		}
590 		if (line > lines) {
591 			free (str);
592 			return NULL;
593 		}
594 		lines = line - 1;
595 		for (i = 0; str[i]&&lines; i++) {
596 			if (str[i] == '\n') {
597 				lines--;
598 			}
599 		}
600 		ptr = str+i;
601 		for (i = 0; ptr[i]; i++) {
602 			if (ptr[i] == '\n') {
603 				ptr[i] = '\0';
604 				break;
605 			}
606 		}
607 		ptr = strdup (ptr);
608 		free (str);
609 	}
610 	return ptr;
611 }
612 
r_file_slurp_lines_from_bottom(const char * file,int line)613 R_API char *r_file_slurp_lines_from_bottom(const char *file, int line) {
614 	r_return_val_if_fail (file, NULL);
615 	int i, lines = 0;
616 	size_t sz;
617 	char *ptr = NULL, *str = r_file_slurp (file, &sz);
618 	// TODO: Implement context
619 	if (str) {
620 		for (i = 0; str[i]; i++) {
621 			if (str[i] == '\n') {
622 				lines++;
623 			}
624 		}
625 		if (line > lines) {
626 			return strdup (str);	// number of lines requested in more than present, return all
627 		}
628 		i--;
629 		for (; str[i] && line; i--) {
630 			if (str[i] == '\n') {
631 				line--;
632 			}
633 		}
634 		ptr = str+i;
635 		ptr = strdup (ptr);
636 		free (str);
637 	}
638 	return ptr;
639 }
640 
r_file_slurp_lines(const char * file,int line,int count)641 R_API char *r_file_slurp_lines(const char *file, int line, int count) {
642 	r_return_val_if_fail (file, NULL);
643 	int i, lines = 0;
644 	size_t sz;
645 	char *ptr = NULL, *str = r_file_slurp (file, &sz);
646 	// TODO: Implement context
647 	if (str) {
648 		for (i = 0; str[i]; i++) {
649 			if (str[i] == '\n') {
650 				lines++;
651 			}
652 		}
653 		if (line > lines) {
654 			free (str);
655 			return NULL;
656 		}
657 		lines = line - 1;
658 		for (i = 0; str[i]&&lines; i++) {
659 			if (str[i] == '\n') {
660 				lines--;
661 			}
662 		}
663 		ptr = str+i;
664 		for (i = 0; ptr[i]; i++) {
665 			if (ptr[i] == '\n') {
666 				if (count) {
667 					count--;
668 				} else {
669 					ptr[i] = '\0';
670 					break;
671 				}
672 			}
673 		}
674 		ptr = strdup (ptr);
675 		free (str);
676 	}
677 	return ptr;
678 }
679 
r_file_root(const char * root,const char * path)680 R_API char *r_file_root(const char *root, const char *path) {
681 	r_return_val_if_fail (root && path, NULL);
682 	char *ret, *s = r_str_replace (strdup (path), "..", "", 1);
683 	// XXX ugly hack
684 	while (strstr (s, "..")) {
685 		s = r_str_replace (s, "..", "", 1);
686 	}
687 	while (strstr (s, "./")) {
688 		s = r_str_replace (s, "./", "", 1);
689 	}
690 	while (strstr (s, "//")) {
691 		s = r_str_replace (s, "//", "", 1);
692 	}
693 	ret = r_str_append (strdup (root), R_SYS_DIR);
694 	ret = r_str_append (ret, s);
695 	free (s);
696 	return ret;
697 }
698 
r_file_hexdump(const char * file,const ut8 * buf,int len,int append)699 R_API bool r_file_hexdump(const char *file, const ut8 *buf, int len, int append) {
700 	FILE *fd;
701 	int i,j;
702 	if (!file || !*file || !buf || len < 0) {
703 		eprintf ("r_file_hexdump file: %s buf: %p\n", file, buf);
704 		return false;
705 	}
706 	if (append) {
707 		fd = r_sandbox_fopen (file, "ab");
708 	} else {
709 		r_sys_truncate (file, 0);
710 		fd = r_sandbox_fopen (file, "wb");
711 	}
712 	if (!fd) {
713 		eprintf ("Cannot open '%s' for writing\n", file);
714 		return false;
715 	}
716 	for (i = 0; i < len; i += 16) {
717 		int l = R_MIN (16, len - i);
718 		fprintf (fd, "0x%08"PFMT64x"  ", (ut64)i);
719 		for (j = 0; j + 2 <= l; j += 2) {
720 			fprintf (fd, "%02x%02x ", buf[i +j], buf[i+j+1]);
721 		}
722 		if (j < l) {
723 			fprintf (fd, "%02x   ", buf[i + j]);
724 			j += 2;
725 		}
726 		if (j < 16) {
727 			fprintf (fd, "%*s ", (16 - j) / 2 * 5, "");
728 		}
729 		for (j = 0; j < 16; j++) {
730 			fprintf (fd, "%c", j < l && IS_PRINTABLE (buf[i + j])? buf[i+j]: '.');
731 		}
732 		fprintf (fd, "\n");
733 	}
734 	fclose (fd);
735 	return true;
736 }
737 
r_file_touch(const char * file)738 R_API bool r_file_touch(const char *file) {
739 	r_return_val_if_fail (file, false);
740 	return r_file_dump (file, NULL, 0, true);
741 }
742 
r_file_dump(const char * file,const ut8 * buf,int len,bool append)743 R_API bool r_file_dump(const char *file, const ut8 *buf, int len, bool append) {
744 	r_return_val_if_fail (!R_STR_ISEMPTY (file), false);
745 	FILE *fd;
746 	if (append) {
747 		fd = r_sandbox_fopen (file, "ab");
748 	} else {
749 		r_sys_truncate (file, 0);
750 		fd = r_sandbox_fopen (file, "wb");
751 	}
752 	if (!fd) {
753 		eprintf ("Cannot open '%s' for writing\n", file);
754 		return false;
755 	}
756 	if (buf) {
757 		if (len < 0) {
758 			len = strlen ((const char *)buf);
759 		}
760 		if (len > 0 && fwrite (buf, len, 1, fd) != 1) {
761 			r_sys_perror ("r_file_dump: fwrite: error\n");
762 			fclose (fd);
763 			return false;
764 		}
765 	}
766 	fclose (fd);
767 	return true;
768 }
769 
r_file_move(const char * src,const char * dst)770 R_API bool r_file_move(const char *src, const char *dst) {
771 	r_return_val_if_fail (!R_STR_ISEMPTY (src) && !R_STR_ISEMPTY (dst), false);
772 	if (r_sandbox_enable (0)) {
773 		return false;
774 	}
775 	// rename fails when files are in different mountpoints
776 	// in this situation it needs to be copied and removed
777 	if (rename (src, dst) != 0) {
778 		char *a = r_str_escape (src);
779 		char *b = r_str_escape (dst);
780 		char *input = r_str_newf ("\"%s\" \"%s\"", a, b);
781 #if __WINDOWS__
782 		int rc = r_sys_cmdf ("move %s", input);
783 #else
784 		int rc = r_sys_cmdf ("mv %s", input);
785 #endif
786 		free (a);
787 		free (b);
788 		return rc == 0;
789 	}
790 	return true;
791 }
792 
r_file_rm(const char * file)793 R_API bool r_file_rm(const char *file) {
794 	r_return_val_if_fail (!R_STR_ISEMPTY (file), false);
795 	if (r_sandbox_enable (0)) {
796 		return false;
797 	}
798 	if (r_file_is_directory (file)) {
799 #if __WINDOWS__
800 		LPTSTR file_ = r_sys_conv_utf8_to_win (file);
801 		bool ret = RemoveDirectory (file_);
802 
803 		free (file_);
804 		return !ret;
805 #else
806 		return !rmdir (file);
807 #endif
808 	} else {
809 #if __WINDOWS__
810 		LPTSTR file_ = r_sys_conv_utf8_to_win (file);
811 		bool ret = DeleteFile (file_);
812 
813 		free (file_);
814 		return !ret;
815 #else
816 		return !unlink (file);
817 #endif
818 	}
819 }
820 
r_file_readlink(const char * path)821 R_API char *r_file_readlink(const char *path) {
822 	r_return_val_if_fail (!R_STR_ISEMPTY (path), false);
823 	if (!r_sandbox_enable (0)) {
824 #if __UNIX__
825 		int ret;
826 		char pathbuf[4096] = {0};
827 		strncpy (pathbuf, path, sizeof (pathbuf) - 1);
828 		repeat:
829 		ret = readlink (path, pathbuf, sizeof (pathbuf)-1);
830 		if (ret != -1) {
831 			pathbuf[ret] = 0;
832 			path = pathbuf;
833 			goto repeat;
834 		}
835 		return strdup (pathbuf);
836 #endif
837 	}
838 	return NULL;
839 }
840 
r_file_mmap_write(const char * file,ut64 addr,const ut8 * buf,int len)841 R_API int r_file_mmap_write(const char *file, ut64 addr, const ut8 *buf, int len) {
842 #if __WINDOWS__
843 	HANDLE fh = INVALID_HANDLE_VALUE;
844 	DWORD written = 0;
845 	LPTSTR file_ = NULL;
846 	int ret = -1;
847 
848 	if (r_sandbox_enable (0)) {
849 		return -1;
850 	}
851 	file_ = r_sys_conv_utf8_to_win (file);
852 	fh = CreateFile (file_, GENERIC_READ|GENERIC_WRITE,
853 		FILE_SHARE_READ | FILE_SHARE_WRITE,
854 		NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
855 	if (fh == INVALID_HANDLE_VALUE) {
856 		r_sys_perror ("r_file_mmap_write/CreateFile");
857 		goto err_r_file_mmap_write;
858 	}
859 	SetFilePointer (fh, addr, NULL, FILE_BEGIN);
860 	if (!WriteFile (fh, buf, (DWORD)len,  &written, NULL)) {
861 		r_sys_perror ("r_file_mmap_write/WriteFile");
862 		goto err_r_file_mmap_write;
863 	}
864 	ret = len;
865 err_r_file_mmap_write:
866 	free (file_);
867 	if (fh != INVALID_HANDLE_VALUE) {
868 		CloseHandle (fh);
869 	}
870 	return ret;
871 #elif __UNIX__
872 	int fd = r_sandbox_open (file, O_RDWR|O_SYNC, 0644);
873 	const int pagesize = getpagesize ();
874 	int mmlen = len + pagesize;
875 	int rest = addr % pagesize;
876         ut8 *mmap_buf;
877 	if (fd == -1) {
878 		return -1;
879 	}
880 	if ((st64)addr < 0) {
881 		return -1;
882 	}
883 	mmap_buf = mmap (NULL, mmlen*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)addr - rest);
884 	if (((int)(size_t)mmap_buf) == -1) {
885 		return -1;
886 	}
887 	memcpy (mmap_buf+rest, buf, len);
888 	msync (mmap_buf+rest, len, MS_INVALIDATE);
889 	munmap (mmap_buf, mmlen*2);
890 	close (fd);
891 	return len;
892 #else
893 	return -1;
894 #endif
895 }
896 
r_file_mmap_read(const char * file,ut64 addr,ut8 * buf,int len)897 R_API int r_file_mmap_read (const char *file, ut64 addr, ut8 *buf, int len) {
898 #if __WINDOWS__
899 	HANDLE fm = NULL, fh = INVALID_HANDLE_VALUE;
900 	LPTSTR file_ = NULL;
901 	int ret = -1;
902 	if (r_sandbox_enable (0)) {
903 		return -1;
904 	}
905 	file_ = r_sys_conv_utf8_to_win (file);
906 	fh = CreateFile (file_, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
907 	if (fh == INVALID_HANDLE_VALUE) {
908 		r_sys_perror ("r_file_mmap_read/CreateFile");
909 		goto err_r_file_mmap_read;
910 	}
911 	fm = CreateFileMapping (fh, NULL, PAGE_READONLY, 0, 0, NULL);
912 	if (!fm) {
913 		r_sys_perror ("CreateFileMapping");
914 		goto err_r_file_mmap_read;
915 	}
916 	ut8 *obuf = MapViewOfFile (fm, FILE_MAP_READ, 0, 0, len);
917 	if (!obuf) {
918 		goto err_r_file_mmap_read;
919 	}
920 	memcpy (obuf, buf, len);
921 	UnmapViewOfFile (obuf);
922 	ret = len;
923 err_r_file_mmap_read:
924 	if (fh != INVALID_HANDLE_VALUE) {
925 		CloseHandle (fh);
926 	}
927 	if (fm) {
928 		CloseHandle (fm);
929 	}
930 	free (file_);
931 	return ret;
932 #elif __UNIX__
933 	int fd = r_sandbox_open (file, O_RDONLY, 0644);
934 	const int pagesize = 4096;
935 	int mmlen = len+pagesize;
936 	int rest = addr%pagesize;
937 	ut8 *mmap_buf;
938 	if (fd == -1) {
939 		return -1;
940 	}
941 	mmap_buf = mmap (NULL, mmlen*2, PROT_READ, MAP_SHARED, fd, (off_t)addr-rest);
942 	if (((int)(size_t)mmap_buf) == -1) {
943 		return -1;
944 	}
945 	memcpy (buf, mmap_buf+rest, len);
946 	munmap (mmap_buf, mmlen*2);
947 	close (fd);
948 	return len;
949 #endif
950 	return 0;
951 }
952 
953 #if __UNIX__
r_file_mmap_unix(RMmap * m,int fd)954 static RMmap *r_file_mmap_unix (RMmap *m, int fd) {
955 	ut8 empty = m->len == 0;
956 	m->buf = mmap (NULL, (empty?BS:m->len) ,
957 		m->rw?PROT_READ|PROT_WRITE:PROT_READ,
958 		MAP_SHARED, fd, (off_t)m->base);
959 	if (m->buf == MAP_FAILED) {
960 		m->buf = NULL;
961 	}
962 	return m;
963 }
964 #elif __WINDOWS__
r_file_mmap_windows(RMmap * m,const char * file)965 static RMmap *r_file_mmap_windows(RMmap *m, const char *file) {
966 	LPTSTR file_ = r_sys_conv_utf8_to_win (file);
967 	bool success = false;
968 
969 	m->fh = CreateFile (file_, GENERIC_READ | (m->rw ? GENERIC_WRITE : 0),
970 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
971 		OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
972 	if (m->fh == INVALID_HANDLE_VALUE) {
973 		r_sys_perror ("CreateFile");
974 		goto err_r_file_mmap_windows;
975 	}
976 	m->fm = CreateFileMapping (m->fh, NULL, PAGE_READONLY, 0, 0, NULL);
977 		//m->rw?PAGE_READWRITE:PAGE_READONLY, 0, 0, NULL);
978 	if (!m->fm) {
979 		r_sys_perror ("CreateFileMapping");
980 		goto err_r_file_mmap_windows;
981 
982 	}
983 	m->buf = MapViewOfFile (m->fm,
984 		// m->rw?(FILE_MAP_READ|FILE_MAP_WRITE):FILE_MAP_READ,
985 		FILE_MAP_COPY,
986 		UT32_HI (m->base), UT32_LO (m->base), 0);
987 	success = true;
988 err_r_file_mmap_windows:
989 	if (!success) {
990 		if (m->fh != INVALID_HANDLE_VALUE) {
991 			CloseHandle (m->fh);
992 		}
993 		R_FREE (m);
994 	}
995 	free (file_);
996 	return m;
997 }
998 #else
file_mmap_other(RMmap * m)999 static RMmap *file_mmap_other (RMmap *m) {
1000 	ut8 empty = m->len == 0;
1001 	m->buf = malloc ((empty? BS: m->len));
1002 	if (!empty && m->buf) {
1003 		lseek (m->fd, (off_t)0, SEEK_SET);
1004 		read (m->fd, m->buf, m->len);
1005 	} else {
1006 		R_FREE (m);
1007 	}
1008 	return m;
1009 }
1010 #endif
1011 
r_file_mmap_arch(RMmap * mmap,const char * filename,int fd)1012 R_API RMmap *r_file_mmap_arch(RMmap *mmap, const char *filename, int fd) {
1013 #if __WINDOWS__
1014 	(void)fd;
1015 	return r_file_mmap_windows (mmap, filename);
1016 #elif __UNIX__
1017 	(void)filename;
1018 	return r_file_mmap_unix (mmap, fd);
1019 #else
1020 	(void)filename;
1021 	(void)fd;
1022 	return file_mmap_other (mmap);
1023 #endif
1024 }
1025 
1026 // TODO: add rwx support?
r_file_mmap(const char * file,bool rw,ut64 base)1027 R_API RMmap *r_file_mmap(const char *file, bool rw, ut64 base) {
1028 	RMmap *m = NULL;
1029 	int fd = -1;
1030 	if (!rw && !r_file_exists (file)) {
1031 		return m;
1032 	}
1033 	fd = r_sandbox_open (file, rw? O_RDWR: O_RDONLY, 0644);
1034 	if (fd == -1 && !rw) {
1035 		eprintf ("r_file_mmap: file does not exis.\n");
1036 		//m->buf = malloc (m->len);
1037 		return m;
1038 	}
1039 	m = R_NEW (RMmap);
1040 	if (!m) {
1041 		if (fd != -1) {
1042 			close (fd);
1043 		}
1044 		return NULL;
1045 	}
1046 	m->base = base;
1047 	m->rw = rw;
1048 	m->fd = fd;
1049 	m->len = fd != -1? lseek (fd, (off_t)0, SEEK_END) : 0;
1050 	m->filename = strdup (file);
1051 
1052 	if (m->fd == -1) {
1053 		return m;
1054 	}
1055 
1056 	if (m->len == (off_t)-1) {
1057 		close (fd);
1058 		R_FREE (m);
1059 		return NULL;
1060 	}
1061 #if __UNIX__
1062 	return r_file_mmap_unix (m, fd);
1063 #elif __WINDOWS__
1064 	close (fd);
1065 	m->fd = -1;
1066 	return r_file_mmap_windows (m, file);
1067 #else
1068 	return file_mmap_other (m);
1069 #endif
1070 }
1071 
r_file_mmap_free(RMmap * m)1072 R_API void r_file_mmap_free(RMmap *m) {
1073 	if (!m) {
1074 		return;
1075 	}
1076 #if __WINDOWS__
1077 	if (m->fm != INVALID_HANDLE_VALUE) {
1078 		CloseHandle (m->fm);
1079 	}
1080 	if (m->fh != INVALID_HANDLE_VALUE) {
1081 		CloseHandle (m->fh);
1082 	}
1083 	if (m->buf) {
1084 		UnmapViewOfFile (m->buf);
1085 	}
1086 #endif
1087 	if (m->fd == -1) {
1088 		free (m);
1089 		return;
1090 	}
1091 	free (m->filename);
1092 #if __UNIX__
1093 	munmap (m->buf, m->len);
1094 #endif
1095 	close (m->fd);
1096 	free (m);
1097 }
1098 
r_file_temp(const char * prefix)1099 R_API char *r_file_temp(const char *prefix) {
1100 	if (!prefix) {
1101 		prefix = "";
1102 	}
1103 	char *path = r_file_tmpdir ();
1104 	char *res = r_str_newf ("%s/%s.%"PFMT64x, path, prefix, r_time_now ());
1105 	free (path);
1106 	return res;
1107 }
1108 
r_file_mkstemp(R_NULLABLE const char * prefix,char ** oname)1109 R_API int r_file_mkstemp(R_NULLABLE const char *prefix, char **oname) {
1110 	int h = -1;
1111 	char *path = r_file_tmpdir ();
1112 	if (!prefix) {
1113 		prefix = "r2";
1114 	}
1115 #if __WINDOWS__
1116 	LPTSTR name = NULL;
1117 	LPTSTR path_ = r_sys_conv_utf8_to_win (path);
1118 	LPTSTR prefix_ = r_sys_conv_utf8_to_win (prefix);
1119 
1120 	name = (LPTSTR)malloc (sizeof (TCHAR) * (MAX_PATH + 1));
1121 	if (!name) {
1122 		goto err_r_file_mkstemp;
1123 	}
1124 	if (GetTempFileName (path_, prefix_, 0, name)) {
1125 		char *name_ = r_sys_conv_win_to_utf8 (name);
1126 		h = r_sandbox_open (name_, O_RDWR|O_EXCL|O_BINARY, 0644);
1127 		if (oname) {
1128 			if (h != -1) {
1129 				*oname = name_;
1130 			} else {
1131 				*oname = NULL;
1132 				free (name_);
1133 			}
1134 		} else {
1135 			free (name_);
1136 		}
1137 	}
1138 err_r_file_mkstemp:
1139 	free (name);
1140 	free (path_);
1141 	free (prefix_);
1142 #else
1143 	char pfxx[1024];
1144 	const char *suffix = strchr (prefix, '*');
1145 
1146 	if (suffix) {
1147 		suffix++;
1148 		r_str_ncpy (pfxx, prefix, (size_t)(suffix - prefix));
1149 		prefix = pfxx;
1150 	} else {
1151 		suffix = "";
1152 	}
1153 
1154 	char *name = r_str_newf ("%s/r2.%s.XXXXXX%s", path, prefix, suffix);
1155 	mode_t mask = umask (S_IWGRP | S_IWOTH);
1156 	if (suffix && *suffix) {
1157 #if defined(__GLIBC__) && defined(__GLIBC_MINOR__) && 2 <= __GLIBC__ && 19 <= __GLIBC__MINOR__
1158 		h = mkstemps (name, strlen (suffix));
1159 #else
1160 		char *const xpos = strrchr (name, 'X');
1161 		const char c = (char)(NULL != xpos ? *(xpos + 1) : 0);
1162 		if (0 != c) {
1163 			xpos[1] = 0;
1164 			h = mkstemp (name);
1165 			xpos[1] = c;
1166 		} else {
1167 			h = -1;
1168 		}
1169 #endif
1170 	} else {
1171 		h = mkstemp (name);
1172 	}
1173 	umask (mask);
1174 	if (oname) {
1175 		*oname = (h!=-1)? strdup (name): NULL;
1176 	}
1177 	free (name);
1178 #endif
1179 	free (path);
1180 	return h;
1181 }
1182 
r_file_tmpdir(void)1183 R_API char *r_file_tmpdir(void) {
1184 #if __WINDOWS__
1185 	LPTSTR tmpdir;
1186 	char *path = NULL;
1187 	DWORD len = 0;
1188 
1189 	tmpdir = (LPTSTR)calloc (1, sizeof (TCHAR) * (MAX_PATH + 1));
1190 	if (!tmpdir) {
1191 		return NULL;
1192 	}
1193 	if ((len = GetTempPath (MAX_PATH + 1, tmpdir)) == 0) {
1194 		path = r_sys_getenv ("TEMP");
1195 		if (!path) {
1196 			path = strdup ("C:\\WINDOWS\\Temp\\");
1197 		}
1198 	} else {
1199 		tmpdir[len] = 0;
1200 		DWORD (WINAPI *glpn)(LPCTSTR, LPCTSTR, DWORD) = r_lib_dl_sym (GetModuleHandle (TEXT ("kernel32.dll")), W32_TCALL("GetLongPathName"));
1201 		if (glpn) {
1202 			// Windows XP sometimes returns short path name
1203 			glpn (tmpdir, tmpdir, MAX_PATH + 1);
1204 		}
1205 		path = r_sys_conv_win_to_utf8 (tmpdir);
1206 	}
1207 	free (tmpdir);
1208 	// Windows 7, stat() function fail if tmpdir ends with '\\'
1209 	if (path) {
1210 		size_t path_len = strlen (path);
1211 		if (path_len > 0 && path[path_len - 1] == '\\') {
1212 			path[path_len - 1] = '\0';
1213 		}
1214 	}
1215 #else
1216 	char *path = r_sys_getenv ("TMPDIR");
1217 	if (path && !*path) {
1218 		R_FREE (path);
1219 	}
1220 	if (!path) {
1221 #if __ANDROID__
1222 		path = strdup ("/data/data/org.radare.radare2installer/radare2/tmp");
1223 #else
1224 		path = strdup ("/tmp");
1225 #endif
1226 	}
1227 #endif
1228 	if (!r_file_is_directory (path)) {
1229 		eprintf ("Cannot find temporary directory '%s'\n", path);
1230 	}
1231 	return path;
1232 }
1233 
r_file_copy(const char * src,const char * dst)1234 R_API bool r_file_copy(const char *src, const char *dst) {
1235 	/* TODO: implement in C */
1236 	/* TODO: Use NO_CACHE for iOS dyldcache copying */
1237 #if HAVE_COPYFILE_H
1238 	return copyfile (src, dst, 0, COPYFILE_DATA | COPYFILE_XATTR) != -1;
1239 #elif __WINDOWS__
1240 	PTCHAR s = r_sys_conv_utf8_to_win (src);
1241 	PTCHAR d = r_sys_conv_utf8_to_win (dst);
1242 	if (!s || !d) {
1243 		R_LOG_ERROR ("r_file_copy: Failed to allocate memory\n");
1244 		free (s);
1245 		free (d);
1246 		return false;
1247 	}
1248 	bool ret = CopyFile (s, d, 0);
1249 	if (!ret) {
1250 		r_sys_perror ("r_file_copy");
1251 	}
1252 	free (s);
1253 	free (d);
1254 	return ret;
1255 #else
1256 	char *src2 = r_str_replace (strdup (src), "'", "\\'", 1);
1257 	char *dst2 = r_str_replace (strdup (dst), "'", "\\'", 1);
1258 	int rc = r_sys_cmdf ("cp -f '%s' '%s'", src2, dst2);
1259 	free (src2);
1260 	free (dst2);
1261 	return rc == 0;
1262 #endif
1263 }
1264 
recursive_search_glob(const char * path,const char * glob,RList * list,int depth)1265 static void recursive_search_glob(const char *path, const char *glob, RList* list, int depth) {
1266 	if (depth < 1) {
1267 		return;
1268 	}
1269 	char* file;
1270 	RListIter *iter;
1271 	RList *dir = r_sys_dir (path);
1272 	r_list_foreach (dir, iter, file) {
1273 		if (!strcmp (file, ".") || !strcmp (file, "..")) {
1274 			continue;
1275 		}
1276 		char *filename = malloc (strlen (path) + strlen (file) + 2);
1277 		strcpy (filename, path);
1278 		strcat (filename, file);
1279 		if (r_file_is_directory (filename)) {
1280 			strcat (filename, R_SYS_DIR);
1281 			recursive_search_glob (filename, glob, list, depth - 1);
1282 			free (filename);
1283 		} else if (r_str_glob (file, glob)) {
1284 			r_list_append (list, filename);
1285 		} else {
1286 			free (filename);
1287 		}
1288 	}
1289 	r_list_free (dir);
1290 }
1291 
r_file_globsearch(const char * _globbed_path,int maxdepth)1292 R_API RList* r_file_globsearch(const char *_globbed_path, int maxdepth) {
1293 	char *globbed_path = strdup (_globbed_path);
1294 	RList *files = r_list_newf (free);
1295 	char *glob = strchr (globbed_path, '*');
1296 	if (!glob) {
1297 		r_list_append (files, strdup (globbed_path));
1298 	} else {
1299 		*glob = '\0';
1300 		char *last_slash = (char *)r_str_last (globbed_path, R_SYS_DIR);
1301 		*glob = '*';
1302 		char *path, *glob_ptr;
1303 		if (last_slash) {
1304 			glob_ptr = last_slash + 1;
1305 			if (globbed_path[0] == '~') {
1306 				char *rpath = r_str_newlen (globbed_path + 2, last_slash - globbed_path - 1);
1307 				path = r_str_home (r_str_get (rpath));
1308 				free (rpath);
1309 			} else {
1310 				path = r_str_newlen (globbed_path, last_slash - globbed_path + 1);
1311 			}
1312 		} else {
1313 			glob_ptr = globbed_path;
1314 			path = r_str_newf (".%s", R_SYS_DIR);
1315 		}
1316 
1317 		if (!path) {
1318 			r_list_free (files);
1319 			free (globbed_path);
1320 			return NULL;
1321 		}
1322 
1323 		if (*(glob + 1) == '*') {  // "**"
1324 			recursive_search_glob (path, glob_ptr, files, maxdepth);
1325 		} else {                   // "*"
1326 			recursive_search_glob (path, glob_ptr, files, 1);
1327 		}
1328 		free (path);
1329 	}
1330 	free (globbed_path);
1331 	return files;
1332 }
1333