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