1 /* radare - LGPL - Copyright 2009-2019 // pancake */
2
3 static const char *help_msg_m[] = {
4 "Usage:", "m[-?*dgy] [...] ", "Mountpoints management",
5 "m", " /mnt ext2 0", "Mount ext2 fs at /mnt with delta 0 on IO",
6 "m", " /mnt", "Mount fs at /mnt with autodetect fs and current offset",
7 "m", "", "List all mountpoints in human readable format",
8 "m*", "", "Same as above, but in r2 commands",
9 "m-/", "", "Umount given path (/)",
10 "mL", "", "List filesystem plugins (Same as Lm)",
11 "mc", " [file]", "Cat: Show the contents of the given file",
12 "md", " /", "List directory contents for path",
13 "mf", "[?] [o|n]", "Search files for given filename or for offset",
14 "mg", " /foo [offset size]", "Get fs file/dir and dump it to disk",
15 "mi", " /foo/bar", "Get offset and size of given file",
16 "mj", "", "List mounted filesystems in JSON",
17 "mo", " /foo/bar", "Open given file into a malloc://",
18 "mp", " msdos 0", "Show partitions in msdos format at offset 0",
19 "mp", "", "List all supported partition types",
20 "ms", " /mnt", "Open filesystem prompt at /mnt",
21 "mw", " [file] [data]", "Write data into file", // TODO: add mwf
22 "my", "", "Yank contents of file into clipboard",
23 //"TODO: support multiple mountpoints and RFile IO's (need io+core refactorn",
24 NULL
25 };
26
cmd_mount_init(RCore * core,RCmdDesc * parent)27 static void cmd_mount_init(RCore *core, RCmdDesc *parent) {
28 DEFINE_CMD_DESCRIPTOR (core, m);
29 }
30
cmd_mkdir(void * data,const char * input)31 static int cmd_mkdir(void *data, const char *input) {
32 char *res = r_syscmd_mkdir (input);
33 if (res) {
34 r_cons_print (res);
35 free (res);
36 }
37 return 0;
38 }
39
cmd_mv(void * data,const char * input)40 static int cmd_mv(void *data, const char *input) {
41 return r_syscmd_mv (input)? 1: 0;
42 }
43
44 static char *cwd = NULL;
45 #define av_max 1024
46
t2s(const char ch)47 static const char *t2s(const char ch) {
48 switch (ch) {
49 case 'f': return "file";
50 case 'd': return "directory";
51 case 'm': return "mountpoint";
52 }
53 return "unknown";
54 }
55
cmd_mount_ls(RCore * core,const char * input)56 static void cmd_mount_ls (RCore *core, const char *input) {
57 bool isJSON = *input == 'j';
58 RListIter *iter;
59 RFSFile *file;
60 RFSRoot *root;
61 input = r_str_trim_head_ro (input + isJSON);
62 RList *list = r_fs_dir (core->fs, input);
63 PJ *pj = NULL;
64 if (isJSON) {
65 pj = pj_new ();
66 pj_a (pj);
67 }
68 if (list) {
69 r_list_foreach (list, iter, file) {
70 if (isJSON) {
71 pj_o (pj);
72 pj_ks (pj, "type", t2s(file->type));
73 pj_ks (pj, "name", file->name);
74 pj_end (pj);
75 } else {
76 r_cons_printf ("%c %s\n", file->type, file->name);
77 }
78 }
79 r_list_free (list);
80 }
81 const char *path = *input ? input : "/";
82 r_list_foreach (core->fs->roots, iter, root) {
83 // TODO: adjust contents between //
84 if (!strncmp (path, root->path, strlen (path))) {
85 char *base = strdup (root->path);
86 char *ls = (char *)r_str_lchr (base, '/');
87 if (ls) {
88 ls++;
89 *ls = 0;
90 }
91 // TODO: adjust contents between //
92 if (!strcmp (path, base)) {
93 if (isJSON) {
94 pj_o (pj);
95 pj_ks (pj, "path", root->path);
96 pj_ks (pj, "type", "mountpoint");
97 pj_end (pj);
98 } else {
99 r_cons_printf ("m %s\n", root->path); // (root->path && root->path[0]) ? root->path + 1: "");
100 }
101 }
102 free (base);
103 }
104 }
105 if (isJSON) {
106 pj_end (pj);
107 r_cons_printf ("%s\n", pj_string (pj));
108 pj_free (pj);
109 }
110 }
111
cmd_mount(void * data,const char * _input)112 static int cmd_mount(void *data, const char *_input) {
113 ut64 off = 0;
114 char *input, *oinput, *ptr, *ptr2;
115 RList *list;
116 RListIter *iter;
117 RFSFile *file;
118 RFSRoot *root;
119 RFSPlugin *plug;
120 RFSPartition *part;
121 RCore *core = (RCore *)data;
122
123 if (!strncmp ("kdir", _input, 4)) {
124 return cmd_mkdir (data, _input);
125 }
126 if (!strncmp ("v", _input, 1)) {
127 return cmd_mv (data, _input);
128 }
129 input = oinput = strdup (_input);
130
131 switch (*input) {
132 case ' ':
133 input = (char *)r_str_trim_head_ro (input + 1);
134 ptr = strchr (input, ' ');
135 if (ptr) {
136 *ptr = 0;
137 ptr = (char *)r_str_trim_head_ro (ptr + 1);
138 ptr2 = strchr (ptr, ' ');
139 if (ptr2) {
140 *ptr2 = 0;
141 off = r_num_math (core->num, ptr2+1);
142 }
143 input = (char *)r_str_trim_head_ro (input);
144 ptr = (char*)r_str_trim_head_ro (ptr);
145
146 const char *mountp = input;
147 const char *fstype = ptr;
148 if (*mountp != '/') {
149 if (*fstype != '/') {
150 eprintf ("Invalid mountpoint\n");
151 return 0;
152 }
153 mountp = ptr;
154 fstype = input;
155 }
156
157 if (!r_fs_mount (core->fs, fstype, mountp, off)) {
158 eprintf ("Cannot mount %s\n", input);
159 }
160 } else {
161 if (!(ptr = r_fs_name (core->fs, core->offset))) {
162 eprintf ("Unknown filesystem type\n");
163 }
164 if (!r_fs_mount (core->fs, ptr, input, core->offset)) {
165 eprintf ("Cannot mount %s\n", input);
166 }
167 free (ptr);
168 }
169 break;
170 case '-':
171 r_fs_umount (core->fs, input+1);
172 break;
173 case 'j':
174 {
175 PJ *pj = pj_new ();
176 pj_o (pj);
177 pj_k (pj, "mountpoints");
178 pj_a (pj);
179 r_list_foreach (core->fs->roots, iter, root) {
180 pj_o (pj);
181 pj_ks (pj, "path", root->path);
182 pj_ks (pj, "plugin", root->p->name);
183 pj_kn (pj, "offset", root->delta);
184 pj_end (pj);
185 }
186 pj_end (pj);
187 pj_k (pj, "plugins");
188 pj_a (pj);
189 r_list_foreach (core->fs->plugins, iter, plug) {
190 pj_o (pj);
191 pj_ks (pj, "name", plug->name);
192 pj_ks (pj, "description", plug->desc);
193 pj_end (pj);
194 }
195
196 pj_end (pj);
197 pj_end (pj);
198 r_cons_printf ("%s\n", pj_string (pj));
199 pj_free (pj);
200 }
201 break;
202 case '*':
203 r_list_foreach (core->fs->roots, iter, root) {
204 r_cons_printf ("m %s %s 0x%"PFMT64x"\n",
205 root-> path, root->p->name, root->delta);
206 }
207 break;
208 case '\0':
209 r_list_foreach (core->fs->roots, iter, root) {
210 r_cons_printf ("%s\t0x%"PFMT64x"\t%s\n",
211 root->p->name, root->delta, root->path);
212 }
213 break;
214 case 'L': // "mL" list of plugins
215 r_list_foreach (core->fs->plugins, iter, plug) {
216 r_cons_printf ("%10s %s\n", plug->name, plug->desc);
217 }
218 break;
219 case 'l': // "ml"
220 case 'd': // "md"
221 cmd_mount_ls (core, input + 1);
222 break;
223 case 'p':
224 input++;
225 if (*input == ' ') {
226 input++;
227 }
228 ptr = strchr (input, ' ');
229 if (ptr) {
230 *ptr = 0;
231 off = r_num_math (core->num, ptr+1);
232 }
233 list = r_fs_partitions (core->fs, input, off);
234 if (list) {
235 r_list_foreach (list, iter, part) {
236 r_cons_printf ("%d %02x 0x%010"PFMT64x" 0x%010"PFMT64x"\n",
237 part->number, part->type,
238 part->start, part->start+part->length);
239 }
240 r_list_free (list);
241 } else {
242 eprintf ("Cannot read partition\n");
243 }
244 break;
245 case 'o': //"mo"
246 input++;
247 if (input[0]==' ') {
248 input++;
249 }
250 file = r_fs_open (core->fs, input, false);
251 if (file) {
252 r_fs_read (core->fs, file, 0, file->size);
253 char *uri = r_str_newf ("malloc://%d", file->size);
254 RIODesc *fd = r_io_open (core->io, uri, R_PERM_RW, 0);
255 if (fd) {
256 r_io_desc_write (fd, file->data, file->size);
257 }
258 } else {
259 eprintf ("Cannot open file\n");
260 }
261 break;
262 case 'i':
263 input++;
264 if (input[0]==' ') {
265 input++;
266 }
267 file = r_fs_open (core->fs, input, false);
268 if (file) {
269 // XXX: dump to file or just pipe?
270 r_fs_read (core->fs, file, 0, file->size);
271 r_cons_printf ("f file %d 0x%08"PFMT64x"\n", file->size, file->off);
272 r_fs_close (core->fs, file);
273 } else {
274 eprintf ("Cannot open file\n");
275 }
276 break;
277 case 'c': // "mc"
278 input++;
279 if (*input == ' ') {
280 input++;
281 }
282 ptr = strchr (input, ' ');
283 if (ptr) {
284 *ptr++ = 0;
285 } else {
286 ptr = "./";
287 }
288 file = r_fs_open (core->fs, input, false);
289 if (file) {
290 r_fs_read (core->fs, file, 0, file->size);
291 r_cons_memcat ((const char *)file->data, file->size);
292 r_fs_close (core->fs, file);
293 r_cons_memcat ("\n", 1);
294 } else if (!r_fs_dir_dump (core->fs, input, ptr)) {
295 eprintf ("Cannot open file\n");
296 }
297 break;
298 case 'g': // "mg"
299 input++;
300 int offset = 0;
301 int size = 0;
302 if (*input == ' ') {
303 input++;
304 }
305 ptr = strchr (input, ' ');
306 if (ptr) {
307 *ptr++ = 0;
308 char *input2 = strdup (ptr++);
309 const char *args = r_str_trim_head_ro (input2);
310 if (args) {
311 ptr = strchr (args, ' ');
312 if (ptr) {
313 *ptr++ = 0;
314 size = r_num_math (core->num, ptr);
315 }
316 offset = r_num_math (core->num, args);
317 }
318 } else {
319 ptr = "./";
320 }
321 const char *filename = r_str_trim_head_ro (input);
322
323 file = r_fs_open (core->fs, filename, false);
324 if (file) {
325 char *localFile = strdup (filename);
326 char *slash = (char *)r_str_rchr (localFile, NULL, '/');
327 if (slash) {
328 memmove (localFile, slash + 1, strlen (slash));
329 }
330 size_t ptr = offset;
331 int total_bytes_read = 0;
332 int blocksize = file->size < core->blocksize ? file->size : core->blocksize;
333 size = size > 0 ? size : file->size;
334 if (r_file_exists (localFile) && !r_sys_truncate (localFile, 0)) {
335 eprintf ("Cannot create file %s\n", localFile);
336 break;
337 }
338 while (total_bytes_read < size && ptr < file->size) {
339 int bytes_read = 0;
340 if (size - total_bytes_read < blocksize) {
341 bytes_read = r_fs_read (core->fs, file, ptr, size - total_bytes_read);
342 } else {
343 bytes_read = r_fs_read (core->fs, file, ptr, blocksize);
344 }
345 if (bytes_read > 0) {
346 r_file_dump (localFile, file->data, bytes_read, true);
347 }
348 ptr += bytes_read;
349 total_bytes_read += bytes_read;
350 }
351 r_fs_close (core->fs, file);
352 if (offset) {
353 eprintf ("File '%s' created. (offset: 0x%"PFMT64x" size: %d bytes)\n", localFile, (ut64) offset, size);
354 } else {
355 eprintf ("File '%s' created. (size: %d bytes)\n", localFile, size);
356 }
357 free (localFile);
358 } else if (!r_fs_dir_dump (core->fs, filename, ptr)) {
359 eprintf ("Cannot open file\n");
360 }
361 break;
362 case 'f':
363 input++;
364 switch (*input) {
365 case '?':
366 r_cons_printf (
367 "Usage: mf[no] [...]\n"
368 " mfn /foo *.c ; search files by name in /foo path\n"
369 " mfo /foo 0x5e91 ; search files by offset in /foo path\n"
370 );
371 break;
372 case 'n':
373 input++;
374 if (*input == ' ')
375 input++;
376 ptr = strchr (input, ' ');
377 if (ptr) {
378 *ptr++ = 0;
379 list = r_fs_find_name (core->fs, input, ptr);
380 r_list_foreach (list, iter, ptr) {
381 r_str_trim_path (ptr);
382 printf ("%s\n", ptr);
383 }
384 //XXX: r_list_purge (list);
385 } else eprintf ("Unknown store path\n");
386 break;
387 case 'o':
388 input++;
389 if (*input == ' ')
390 input++;
391 ptr = strchr (input, ' ');
392 if (ptr) {
393 *ptr++ = 0;
394 ut64 off = r_num_math (core->num, ptr);
395 list = r_fs_find_off (core->fs, input, off);
396 r_list_foreach (list, iter, ptr) {
397 r_str_trim_path (ptr);
398 printf ("%s\n", ptr);
399 }
400 //XXX: r_list_purge (list);
401 } else eprintf ("Unknown store path\n");
402 break;
403 }
404 break;
405 case 's': // "ms"
406 if (core->http_up) {
407 free (oinput);
408 return false;
409 }
410 input++;
411 if (input[0] == ' ') {
412 input++;
413 }
414 r_cons_set_raw (false);
415 {
416 RFSShell shell = {
417 .cwd = &cwd,
418 .set_prompt = r_line_set_prompt,
419 .readline = r_line_readline,
420 .hist_add = r_line_hist_add
421 };
422 core->rfs = &shell;
423 core->autocomplete_type = AUTOCOMPLETE_MS;
424 r_core_autocomplete_reload (core);
425 r_fs_shell_prompt (&shell, core->fs, input);
426 core->autocomplete_type = AUTOCOMPLETE_DEFAULT;
427 r_core_autocomplete_reload (core);
428 R_FREE (cwd);
429 }
430 break;
431 case 'w':
432 if (input[1] == ' ') {
433 char *args = r_str_trim_dup (input + 1);
434 char *arg = strchr (args, ' ');
435 if (arg) {
436 data = arg + 1;
437 } else {
438 data = "";
439 // touch and truncate
440 }
441 RFSFile *f = r_fs_open (core->fs, args, true);
442 if (f) {
443 r_fs_write (core->fs, f, 0, (const ut8 *)data, strlen (data));
444 r_fs_close (core->fs, f);
445 r_fs_file_free (f);
446 }
447 free (args);
448 } else {
449 eprintf ("Usage: mw [file] ([data])\n");
450 }
451 break;
452 case 'y':
453 eprintf ("TODO\n");
454 break;
455 case '?':
456 r_core_cmd_help (core, help_msg_m);
457 break;
458 }
459 free (oinput);
460 return 0;
461 }
462