]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/write.c
xfs_db: remove unnessary checks in process_leaf_node_dir_v2_free
[thirdparty/xfsprogs-dev.git] / db / write.c
1 /*
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "libxfs.h"
20 #include <ctype.h>
21 #include <time.h>
22 #include "bit.h"
23 #include "block.h"
24 #include "command.h"
25 #include "type.h"
26 #include "faddr.h"
27 #include "fprint.h"
28 #include "field.h"
29 #include "flist.h"
30 #include "io.h"
31 #include "init.h"
32 #include "output.h"
33 #include "print.h"
34 #include "write.h"
35 #include "malloc.h"
36
37 static int write_f(int argc, char **argv);
38 static void write_help(void);
39
40 static const cmdinfo_t write_cmd =
41 { "write", NULL, write_f, 0, -1, 0, N_("[-c] [field or value]..."),
42 N_("write value to disk"), write_help };
43
44 void
45 write_init(void)
46 {
47 if (!expert_mode)
48 return;
49
50 add_command(&write_cmd);
51 srand48(clock());
52 }
53
54 static void
55 write_help(void)
56 {
57 dbprintf(_(
58 "\n"
59 " The 'write' command takes on different personalities depending on the\n"
60 " type of object being worked with.\n\n"
61 " Write has 3 modes:\n"
62 " 'struct mode' - is active anytime you're looking at a filesystem object\n"
63 " which contains individual fields (ex: an inode).\n"
64 " 'data mode' - is active anytime you set a disk address directly or set\n"
65 " the type to 'data'.\n"
66 " 'string mode' - only used for writing symlink blocks.\n"
67 "\n"
68 " Examples:\n"
69 " Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n"
70 " 'write fname \"hello\\000\"' - write superblock fname.\n"
71 " (note: in struct mode strings are not null terminated)\n"
72 " 'write fname #6669736800' - write superblock fname with hex.\n"
73 " 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n"
74 " - write superblock uuid.\n"
75 " Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n"
76 " 'write lshift 3' - shift the block 3 bytes to the left\n"
77 " 'write sequence 1 5' - write a cycle of number [1-5] through\n"
78 " the entire block.\n"
79 " String mode: 'write \"This_is_a_filename\" - write null terminated string.\n"
80 "\n"
81 " In data mode type 'write' by itself for a list of specific commands.\n\n"
82 " Specifying the -c option will allow writes of invalid (corrupt) data.\n\n"
83 ));
84
85 }
86
87 static int
88 write_f(
89 int argc,
90 char **argv)
91 {
92 pfunc_t pf;
93 extern char *progname;
94 int c;
95 int corrupt = 0; /* Allow write of corrupt data; skip verification */
96 struct xfs_buf_ops nowrite_ops;
97 const struct xfs_buf_ops *stashed_ops = NULL;
98
99 if (x.isreadonly & LIBXFS_ISREADONLY) {
100 dbprintf(_("%s started in read only mode, writing disabled\n"),
101 progname);
102 return 0;
103 }
104
105 if (cur_typ == NULL) {
106 dbprintf(_("no current type\n"));
107 return 0;
108 }
109
110 pf = cur_typ->pfunc;
111 if (pf == NULL) {
112 dbprintf(_("no handler function for type %s, write unsupported.\n"),
113 cur_typ->name);
114 return 0;
115 }
116
117 while ((c = getopt(argc, argv, "c")) != EOF) {
118 switch (c) {
119 case 'c':
120 corrupt = 1;
121 break;
122 default:
123 dbprintf(_("bad option for write command\n"));
124 return 0;
125 }
126 }
127
128 argc -= optind;
129 argv += optind;
130
131 if (iocur_top->bp->b_ops && corrupt) {
132 /* Temporarily remove write verifier to write bad data */
133 stashed_ops = iocur_top->bp->b_ops;
134 nowrite_ops.verify_read = stashed_ops->verify_read;
135 nowrite_ops.verify_write = xfs_dummy_verify;
136 iocur_top->bp->b_ops = &nowrite_ops;
137 dbprintf(_("Allowing write of corrupted data\n"));
138 }
139
140 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
141
142 if (stashed_ops)
143 iocur_top->bp->b_ops = stashed_ops;
144
145 return 0;
146 }
147
148 /* compare significant portions of commands */
149
150 static int
151 sigcmp(
152 char *s1,
153 char *s2,
154 int sig)
155 {
156 int sigcnt;
157
158 if (!s1 || !s2)
159 return 0;
160
161 for (sigcnt = 0; *s1 == *s2; s1++, s2++) {
162 sigcnt++;
163 if (*s1 == '\0')
164 return 1;
165 }
166 if (*s1 && *s2)
167 return 0;
168
169 if (sig && (sigcnt >= sig))
170 return 1;
171
172 return 0;
173 }
174
175 /* ARGSUSED */
176 static void
177 bwrite_lshift(
178 int start,
179 int len,
180 int shift,
181 int from,
182 int to)
183 {
184 char *base;
185
186 if (shift == -1)
187 shift = 1;
188 if (start == -1)
189 start = 0;
190 if (len == -1)
191 len = iocur_top->len - start;
192
193 if (len+start > iocur_top->len) {
194 dbprintf(_("length (%d) too large for data block size (%d)"),
195 len, iocur_top->len);
196 }
197
198 base = (char *)iocur_top->data + start;
199
200 memcpy(base, base+shift, len-shift);
201 memset(base+(len-shift), 0, shift);
202 }
203
204 /* ARGSUSED */
205 static void
206 bwrite_rshift(
207 int start,
208 int len,
209 int shift,
210 int from,
211 int to)
212 {
213 char *base;
214
215 if (shift == -1)
216 shift = 1;
217 if (start == -1)
218 start = 0;
219 if (len == -1)
220 len = iocur_top->len - start;
221
222 if (len+start > iocur_top->len) {
223 dbprintf(_("length (%d) too large for data block size (%d)"),
224 len, iocur_top->len);
225 }
226
227 base = (char *)iocur_top->data + start;
228
229 memcpy(base+shift, base, len-shift);
230 memset(base, 0, shift);
231 }
232
233 /* ARGSUSED */
234 static void
235 bwrite_lrot(
236 int start,
237 int len,
238 int shift,
239 int from,
240 int to)
241 {
242 char *base;
243 char *hold_region;
244
245 if (shift == -1)
246 shift = 1;
247 if (start == -1)
248 start = 0;
249 if (len == -1)
250 len = iocur_top->len - start;
251
252 if (len+start > iocur_top->len) {
253 dbprintf(_("length (%d) too large for data block size (%d)"),
254 len, iocur_top->len);
255 }
256
257 base = (char *)iocur_top->data + start;
258
259 hold_region = xmalloc(shift);
260 memcpy(hold_region, base, shift);
261 memcpy(base, base+shift, len-shift);
262 memcpy(base+(len-shift), hold_region, shift);
263 free(hold_region);
264 }
265
266 /* ARGSUSED */
267 static void
268 bwrite_rrot(
269 int start,
270 int len,
271 int shift,
272 int from,
273 int to)
274 {
275 char *base;
276 char *hold_region;
277
278 if (shift == -1)
279 shift = 1;
280 if (start == -1)
281 start = 0;
282 if (len == -1)
283 len = iocur_top->len - start;
284
285 if (len+start > iocur_top->len) {
286 dbprintf(_("length (%d) too large for data block size (%d)"),
287 len, iocur_top->len);
288 }
289
290 base = (char *)iocur_top->data + start;
291
292 hold_region = xmalloc(shift);
293 memcpy(hold_region, base+(len-shift), shift);
294 memmove(base+shift, base, len-shift);
295 memcpy(base, hold_region, shift);
296 free(hold_region);
297 }
298
299 /* ARGSUSED */
300 static void
301 bwrite_seq(
302 int start,
303 int len,
304 int step,
305 int from,
306 int to)
307 {
308 int i;
309 int tmp;
310 int base;
311 int range;
312 int top;
313 char *buf;
314
315 if (start == -1)
316 start = 0;
317
318 if (len == -1)
319 len = iocur_top->len - start;
320
321 if (len+start > iocur_top->len) {
322 dbprintf(_("length (%d) too large for data block size (%d)"),
323 len, iocur_top->len);
324 }
325
326 if (from == -1 || from > 255)
327 from = 0;
328 if (to == -1 || to > 255)
329 to = 255;
330 if (step == -1)
331 step = 1;
332
333 base = from;
334 top = to;
335 if (from > to) {
336 base = to;
337 top = from;
338 if (step > 0)
339 step = -step;
340 }
341
342 range = top - base;
343 buf = (char *)iocur_top->data + start;
344
345 tmp = 0;
346 for (i = start; i < start+len; i++) {
347 *buf++ = tmp + base;
348 tmp = (tmp + step)%(range+1);
349 }
350 }
351
352 /* ARGSUSED */
353 static void
354 bwrite_random(
355 int start,
356 int len,
357 int shift,
358 int from,
359 int to)
360 {
361 int i;
362 char *buf;
363
364 if (start == -1)
365 start = 0;
366
367 if (len == -1)
368 len = iocur_top->len - start;
369
370 if (len+start > iocur_top->len) {
371 dbprintf(_("length (%d) too large for data block size (%d)"),
372 len, iocur_top->len);
373 }
374
375 buf = (char *)iocur_top->data + start;
376
377 for (i = start; i < start+len; i++)
378 *buf++ = (char)lrand48();
379 }
380
381 /* ARGSUSED */
382 static void
383 bwrite_fill(
384 int start,
385 int len,
386 int value,
387 int from,
388 int to)
389 {
390 char *base;
391
392 if (value == -1)
393 value = 0;
394 if (start == -1)
395 start = 0;
396 if (len == -1)
397 len = iocur_top->len - start;
398
399 if (len+start > iocur_top->len) {
400 dbprintf(_("length (%d) too large for data block size (%d)"),
401 len, iocur_top->len);
402 }
403
404 base = (char *)iocur_top->data + start;
405
406 memset(base, value, len);
407 }
408
409 static struct bw_cmd {
410 void (*cmdfunc)(int,int,int,int,int);
411 char *cmdstr;
412 int sig_chars;
413 int argmin;
414 int argmax;
415 int shiftcount_arg;
416 int from_arg;
417 int to_arg;
418 int start_arg;
419 int len_arg;
420 char *usage;
421 } bw_cmdtab[] = {
422 /* cmd sig min max sh frm to start len */
423 { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3,
424 "[shiftcount] [start] [len]", },
425 { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3,
426 "[shiftcount] [start] [len]", },
427 { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3,
428 "[shiftcount] [start] [len]", },
429 { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3,
430 "[shiftcount] [start] [len]", },
431 { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4,
432 "[from] [to] [start] [len]", },
433 { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2,
434 "[start] [len]", },
435 { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3,
436 "num [start] [len]" }
437 };
438
439 #define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0]))
440
441 static int
442 convert_oct(
443 char *arg,
444 int *ret)
445 {
446 int count;
447 int i;
448 int val = 0;
449
450 /* only allow 1 case, '\' and 3 octal digits (or less) */
451
452 for (count = 0; count < 3; count++) {
453 if (arg[count] == '\0')
454 break;
455
456 if ((arg[count] < '0') && (arg[count] > '7'))
457 break;
458 }
459
460 for (i = 0; i < count; i++) {
461 val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3);
462 }
463
464 *ret = val&0xff;
465
466 return(count);
467 }
468
469 #define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
470
471 /*
472 * convert_arg allows input in the following forms:
473 *
474 * - A string ("ABTB") whose ASCII value is placed in an array in the order
475 * matching the input.
476 *
477 * - An even number of hex numbers. If the length is greater than 64 bits,
478 * then the output is an array of bytes whose top nibble is the first hex
479 * digit in the input, the lower nibble is the second hex digit in the
480 * input. UUID entries are entered in this manner.
481 *
482 * - A decimal or hexadecimal integer to be used with setbitval().
483 *
484 * Numbers that are passed to setbitval() need to be in big endian format and
485 * are adjusted in the buffer so that the first input bit is to be be written to
486 * the first bit in the output.
487 */
488 static char *
489 convert_arg(
490 char *arg,
491 int bit_length)
492 {
493 int i;
494 int alloc_size;
495 int octval;
496 int offset;
497 int ret;
498 static char *buf = NULL;
499 char *endp;
500 char *rbuf;
501 char *ostr;
502 __u64 *value;
503 __u64 val = 0;
504
505 if (bit_length <= 64)
506 alloc_size = 8;
507 else
508 alloc_size = (bit_length + 7) / 8;
509
510 buf = xrealloc(buf, alloc_size);
511 memset(buf, 0, alloc_size);
512 value = (__u64 *)buf;
513 rbuf = buf;
514
515 if (*arg == '\"') {
516 /* input a string and output ASCII array of characters */
517
518 /* zap closing quote if there is one */
519 ostr = strrchr(arg + 1, '\"');
520 if (ostr)
521 *ostr = '\0';
522
523 ostr = arg + 1;
524 for (i = 0; i < alloc_size; i++) {
525 if (!*ostr)
526 break;
527
528 /* do octal conversion */
529 if (*ostr == '\\') {
530 if (*(ostr + 1) >= '0' || *(ostr + 1) <= '7') {
531 ret = convert_oct(ostr + 1, &octval);
532 *rbuf++ = octval;
533 ostr += ret + 1;
534 continue;
535 }
536 }
537 *rbuf++ = *ostr++;
538 }
539 return buf;
540 }
541
542 if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
543 /*
544 * handle hex blocks ie
545 * #00112233445566778899aabbccddeeff
546 * and uuids ie
547 * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899
548 *
549 * (but if it starts with "-" assume it's just an integer)
550 */
551 int bytes = bit_length / NBBY;
552
553 /* is this an array of hec numbers? */
554 if (bit_length % NBBY)
555 return NULL;
556
557 /* skip leading hash */
558 if (*arg == '#')
559 arg++;
560
561 while (*arg && bytes--) {
562 /* skip hypens */
563 while (*arg == '-')
564 arg++;
565
566 /* get first nybble */
567 if (!isxdigit((int)*arg))
568 return NULL;
569 *rbuf = NYBBLE((int)*arg) << 4;
570 arg++;
571
572 /* skip more hyphens */
573 while (*arg == '-')
574 arg++;
575
576 /* get second nybble */
577 if (!isxdigit((int)*arg))
578 return NULL;
579 *rbuf++ |= NYBBLE((int)*arg);
580 arg++;
581 }
582 if (bytes < 0 && *arg)
583 return NULL;
584
585 return buf;
586 }
587
588 /* handle decimal / hexadecimal integers */
589 val = strtoll(arg, &endp, 0);
590 /* return if not a clean number */
591 if (*endp != '\0')
592 return NULL;
593
594 /* Does the value fit into the range of the destination bitfield? */
595 if (bit_length < 64 && (val >> bit_length) > 0)
596 return NULL;
597 /*
598 * If the length of the field is not a multiple of a byte, push
599 * the bits up in the field, so the most signicant field bit is
600 * the most significant bit in the byte:
601 *
602 * before:
603 * val |----|----|----|----|----|--MM|mmmm|llll|
604 * after
605 * val |----|----|----|----|----|MMmm|mmll|ll00|
606 */
607 offset = bit_length % NBBY;
608 if (offset)
609 val <<= (NBBY - offset);
610
611 /*
612 * convert to big endian and copy into the array
613 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
614 */
615 *value = cpu_to_be64(val);
616
617 /*
618 * Align the array to point to the field in the array.
619 * rbuf = |MMmm|mmll|ll00|
620 */
621 offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64));
622 rbuf += offset;
623 return rbuf;
624 }
625
626
627 /* ARGSUSED */
628 void
629 write_struct(
630 const field_t *fields,
631 int argc,
632 char **argv)
633 {
634 const ftattr_t *fa;
635 flist_t *fl;
636 flist_t *sfl;
637 int bit_length;
638 char *buf;
639 int parentoffset;
640
641 if (argc != 2) {
642 dbprintf(_("usage: write fieldname value\n"));
643 return;
644 }
645
646 fl = flist_scan(argv[0]);
647 if (!fl) {
648 dbprintf(_("unable to parse '%s'.\n"), argv[0]);
649 return;
650 }
651
652 /* if we're a root field type, go down 1 layer to get field list */
653 if (fields->name[0] == '\0') {
654 fa = &ftattrtab[fields->ftyp];
655 ASSERT(fa->ftyp == fields->ftyp);
656 fields = fa->subfld;
657 }
658
659 /* run down the field list and set offsets into the data */
660 if (!flist_parse(fields, fl, iocur_top->data, 0)) {
661 flist_free(fl);
662 dbprintf(_("parsing error\n"));
663 return;
664 }
665
666 sfl = fl;
667 parentoffset = 0;
668 while (sfl->child) {
669 parentoffset = sfl->offset;
670 sfl = sfl->child;
671 }
672
673 bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
674 bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
675
676 /* convert this to a generic conversion routine */
677 /* should be able to handle str, num, or even labels */
678
679 buf = convert_arg(argv[1], bit_length);
680 if (!buf) {
681 dbprintf(_("unable to convert value '%s'.\n"), argv[1]);
682 flist_free(fl);
683 return;
684 }
685
686 setbitval(iocur_top->data, sfl->offset, bit_length, buf);
687 write_cur();
688
689 flist_print(fl);
690 print_flist(fl);
691 flist_free(fl);
692 }
693
694 /* ARGSUSED */
695 void
696 write_string(
697 const field_t *fields,
698 int argc,
699 char **argv)
700 {
701 char *buf;
702 int i;
703
704 if (argc != 1) {
705 dbprintf(_("usage (in string mode): write \"string...\"\n"));
706 return;
707 }
708
709 buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8));
710 for (i = 0; i < iocur_top->len; i++) {
711 ((char *)iocur_top->data)[i] = *buf;
712 if (*buf++ == '\0')
713 break;
714 }
715
716 /* write back to disk */
717 write_cur();
718 }
719
720 /* ARGSUSED */
721 void
722 write_block(
723 const field_t *fields,
724 int argc,
725 char **argv)
726 {
727 int i;
728 int shiftcount = -1;
729 int start = -1;
730 int len = -1;
731 int from = -1;
732 int to = -1;
733 struct bw_cmd *cmd = NULL;
734
735 if (argc <= 1 || argc > 5)
736 goto block_usage;
737
738 for (i = 0; i < BWRITE_CMD_MAX; i++) {
739 if (sigcmp(argv[0], bw_cmdtab[i].cmdstr,
740 bw_cmdtab[i].sig_chars)) {
741 cmd = &bw_cmdtab[i];
742 break;
743 }
744 }
745
746 if (!cmd) {
747 dbprintf(_("write: invalid subcommand\n"));
748 goto block_usage;
749 }
750
751 if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) {
752 dbprintf(_("write %s: invalid number of arguments\n"),
753 cmd->cmdstr);
754 goto block_usage;
755 }
756
757 if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc))
758 shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0);
759 if (cmd->start_arg && (cmd->start_arg < argc))
760 start = (int)strtoul(argv[cmd->start_arg], NULL, 0);
761 if (cmd->len_arg && (cmd->len_arg < argc))
762 len = (int)strtoul(argv[cmd->len_arg], NULL, 0);
763 if (cmd->from_arg && (cmd->len_arg < argc))
764 from = (int)strtoul(argv[cmd->from_arg], NULL, 0);
765 if (cmd->to_arg && (cmd->len_arg < argc))
766 to = (int)strtoul(argv[cmd->to_arg], NULL, 0);
767
768 cmd->cmdfunc(start, len, shiftcount, from, to);
769
770 /* write back to disk */
771 write_cur();
772 return;
773
774 block_usage:
775
776 dbprintf(_("usage: write (in data mode)\n"));
777 for (i = 0; i < BWRITE_CMD_MAX; i++) {
778 dbprintf(" %-9.9s %s\n",
779 bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage);
780 }
781 dbprintf("\n");
782 return;
783 }