]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/write.c
xfs_db: pass the inode cluster offset when copying inodes
[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 with\n"
83 " an invalid CRC. Specifying the -d option will allow writes of invalid data,\n"
84 " but still recalculate the CRC so we are forced to check and detect the\n"
85 " invalid data appropriately.\n\n"
86 ));
87
88 }
89
90 static int
91 write_f(
92 int argc,
93 char **argv)
94 {
95 pfunc_t pf;
96 extern char *progname;
97 int c;
98 bool corrupt = false; /* Allow write of bad data w/ invalid CRC */
99 bool invalid_data = false; /* Allow write of bad data w/ valid CRC */
100 struct xfs_buf_ops local_ops;
101 const struct xfs_buf_ops *stashed_ops = NULL;
102
103 if (x.isreadonly & LIBXFS_ISREADONLY) {
104 dbprintf(_("%s started in read only mode, writing disabled\n"),
105 progname);
106 return 0;
107 }
108
109 if (cur_typ == NULL) {
110 dbprintf(_("no current type\n"));
111 return 0;
112 }
113
114 pf = cur_typ->pfunc;
115 if (pf == NULL) {
116 dbprintf(_("no handler function for type %s, write unsupported.\n"),
117 cur_typ->name);
118 return 0;
119 }
120
121 while ((c = getopt(argc, argv, "cd")) != EOF) {
122 switch (c) {
123 case 'c':
124 corrupt = true;
125 break;
126 case 'd':
127 invalid_data = true;
128 break;
129 default:
130 dbprintf(_("bad option for write command\n"));
131 return 0;
132 }
133 }
134
135 if (corrupt && invalid_data) {
136 dbprintf(_("Cannot specify both -c and -d options\n"));
137 return 0;
138 }
139
140 if (invalid_data && iocur_top->typ->crc_off == TYP_F_NO_CRC_OFF) {
141 dbprintf(_("Cannot recalculate CRCs on this type of object\n"));
142 return 0;
143 }
144
145 argc -= optind;
146 argv += optind;
147
148 /*
149 * If the buffer has no verifier or we are using standard verifier
150 * paths, then just write it out and return
151 */
152 if (!iocur_top->bp->b_ops ||
153 !(corrupt || invalid_data)) {
154 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
155 return 0;
156 }
157
158
159 /* Temporarily remove write verifier to write bad data */
160 stashed_ops = iocur_top->bp->b_ops;
161 local_ops.verify_read = stashed_ops->verify_read;
162 iocur_top->bp->b_ops = &local_ops;
163
164 if (corrupt) {
165 local_ops.verify_write = xfs_dummy_verify;
166 dbprintf(_("Allowing write of corrupted data and bad CRC\n"));
167 } else { /* invalid data */
168 local_ops.verify_write = xfs_verify_recalc_crc;
169 dbprintf(_("Allowing write of corrupted data with good CRC\n"));
170 }
171
172 (*pf)(DB_WRITE, cur_typ->fields, argc, argv);
173
174 iocur_top->bp->b_ops = stashed_ops;
175
176 return 0;
177 }
178
179 /* compare significant portions of commands */
180
181 static int
182 sigcmp(
183 char *s1,
184 char *s2,
185 int sig)
186 {
187 int sigcnt;
188
189 if (!s1 || !s2)
190 return 0;
191
192 for (sigcnt = 0; *s1 == *s2; s1++, s2++) {
193 sigcnt++;
194 if (*s1 == '\0')
195 return 1;
196 }
197 if (*s1 && *s2)
198 return 0;
199
200 if (sig && (sigcnt >= sig))
201 return 1;
202
203 return 0;
204 }
205
206 /* ARGSUSED */
207 static void
208 bwrite_lshift(
209 int start,
210 int len,
211 int shift,
212 int from,
213 int to)
214 {
215 char *base;
216
217 if (shift == -1)
218 shift = 1;
219 if (start == -1)
220 start = 0;
221 if (len == -1)
222 len = iocur_top->len - start;
223
224 if (len+start > iocur_top->len) {
225 dbprintf(_("length (%d) too large for data block size (%d)"),
226 len, iocur_top->len);
227 }
228
229 base = (char *)iocur_top->data + start;
230
231 memcpy(base, base+shift, len-shift);
232 memset(base+(len-shift), 0, shift);
233 }
234
235 /* ARGSUSED */
236 static void
237 bwrite_rshift(
238 int start,
239 int len,
240 int shift,
241 int from,
242 int to)
243 {
244 char *base;
245
246 if (shift == -1)
247 shift = 1;
248 if (start == -1)
249 start = 0;
250 if (len == -1)
251 len = iocur_top->len - start;
252
253 if (len+start > iocur_top->len) {
254 dbprintf(_("length (%d) too large for data block size (%d)"),
255 len, iocur_top->len);
256 }
257
258 base = (char *)iocur_top->data + start;
259
260 memcpy(base+shift, base, len-shift);
261 memset(base, 0, shift);
262 }
263
264 /* ARGSUSED */
265 static void
266 bwrite_lrot(
267 int start,
268 int len,
269 int shift,
270 int from,
271 int to)
272 {
273 char *base;
274 char *hold_region;
275
276 if (shift == -1)
277 shift = 1;
278 if (start == -1)
279 start = 0;
280 if (len == -1)
281 len = iocur_top->len - start;
282
283 if (len+start > iocur_top->len) {
284 dbprintf(_("length (%d) too large for data block size (%d)"),
285 len, iocur_top->len);
286 }
287
288 base = (char *)iocur_top->data + start;
289
290 hold_region = xmalloc(shift);
291 memcpy(hold_region, base, shift);
292 memcpy(base, base+shift, len-shift);
293 memcpy(base+(len-shift), hold_region, shift);
294 free(hold_region);
295 }
296
297 /* ARGSUSED */
298 static void
299 bwrite_rrot(
300 int start,
301 int len,
302 int shift,
303 int from,
304 int to)
305 {
306 char *base;
307 char *hold_region;
308
309 if (shift == -1)
310 shift = 1;
311 if (start == -1)
312 start = 0;
313 if (len == -1)
314 len = iocur_top->len - start;
315
316 if (len+start > iocur_top->len) {
317 dbprintf(_("length (%d) too large for data block size (%d)"),
318 len, iocur_top->len);
319 }
320
321 base = (char *)iocur_top->data + start;
322
323 hold_region = xmalloc(shift);
324 memcpy(hold_region, base+(len-shift), shift);
325 memmove(base+shift, base, len-shift);
326 memcpy(base, hold_region, shift);
327 free(hold_region);
328 }
329
330 /* ARGSUSED */
331 static void
332 bwrite_seq(
333 int start,
334 int len,
335 int step,
336 int from,
337 int to)
338 {
339 int i;
340 int tmp;
341 int base;
342 int range;
343 int top;
344 char *buf;
345
346 if (start == -1)
347 start = 0;
348
349 if (len == -1)
350 len = iocur_top->len - start;
351
352 if (len+start > iocur_top->len) {
353 dbprintf(_("length (%d) too large for data block size (%d)"),
354 len, iocur_top->len);
355 }
356
357 if (from == -1 || from > 255)
358 from = 0;
359 if (to == -1 || to > 255)
360 to = 255;
361 if (step == -1)
362 step = 1;
363
364 base = from;
365 top = to;
366 if (from > to) {
367 base = to;
368 top = from;
369 if (step > 0)
370 step = -step;
371 }
372
373 range = top - base;
374 buf = (char *)iocur_top->data + start;
375
376 tmp = 0;
377 for (i = start; i < start+len; i++) {
378 *buf++ = tmp + base;
379 tmp = (tmp + step)%(range+1);
380 }
381 }
382
383 /* ARGSUSED */
384 static void
385 bwrite_random(
386 int start,
387 int len,
388 int shift,
389 int from,
390 int to)
391 {
392 int i;
393 char *buf;
394
395 if (start == -1)
396 start = 0;
397
398 if (len == -1)
399 len = iocur_top->len - start;
400
401 if (len+start > iocur_top->len) {
402 dbprintf(_("length (%d) too large for data block size (%d)"),
403 len, iocur_top->len);
404 }
405
406 buf = (char *)iocur_top->data + start;
407
408 for (i = start; i < start+len; i++)
409 *buf++ = (char)lrand48();
410 }
411
412 /* ARGSUSED */
413 static void
414 bwrite_fill(
415 int start,
416 int len,
417 int value,
418 int from,
419 int to)
420 {
421 char *base;
422
423 if (value == -1)
424 value = 0;
425 if (start == -1)
426 start = 0;
427 if (len == -1)
428 len = iocur_top->len - start;
429
430 if (len+start > iocur_top->len) {
431 dbprintf(_("length (%d) too large for data block size (%d)"),
432 len, iocur_top->len);
433 }
434
435 base = (char *)iocur_top->data + start;
436
437 memset(base, value, len);
438 }
439
440 static struct bw_cmd {
441 void (*cmdfunc)(int,int,int,int,int);
442 char *cmdstr;
443 int sig_chars;
444 int argmin;
445 int argmax;
446 int shiftcount_arg;
447 int from_arg;
448 int to_arg;
449 int start_arg;
450 int len_arg;
451 char *usage;
452 } bw_cmdtab[] = {
453 /* cmd sig min max sh frm to start len */
454 { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3,
455 "[shiftcount] [start] [len]", },
456 { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3,
457 "[shiftcount] [start] [len]", },
458 { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3,
459 "[shiftcount] [start] [len]", },
460 { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3,
461 "[shiftcount] [start] [len]", },
462 { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4,
463 "[from] [to] [start] [len]", },
464 { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2,
465 "[start] [len]", },
466 { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3,
467 "num [start] [len]" }
468 };
469
470 #define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0]))
471
472 static int
473 convert_oct(
474 char *arg,
475 int *ret)
476 {
477 int count;
478 int i;
479 int val = 0;
480
481 /* only allow 1 case, '\' and 3 octal digits (or less) */
482
483 for (count = 0; count < 3; count++) {
484 if (arg[count] == '\0')
485 break;
486
487 if ((arg[count] < '0') && (arg[count] > '7'))
488 break;
489 }
490
491 for (i = 0; i < count; i++) {
492 val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3);
493 }
494
495 *ret = val&0xff;
496
497 return(count);
498 }
499
500 #define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa))
501
502 /*
503 * convert_arg allows input in the following forms:
504 *
505 * - A string ("ABTB") whose ASCII value is placed in an array in the order
506 * matching the input.
507 *
508 * - An even number of hex numbers. If the length is greater than 64 bits,
509 * then the output is an array of bytes whose top nibble is the first hex
510 * digit in the input, the lower nibble is the second hex digit in the
511 * input. UUID entries are entered in this manner.
512 *
513 * - A decimal or hexadecimal integer to be used with setbitval().
514 *
515 * Numbers that are passed to setbitval() need to be in big endian format and
516 * are adjusted in the buffer so that the first input bit is to be be written to
517 * the first bit in the output.
518 */
519 static char *
520 convert_arg(
521 char *arg,
522 int bit_length)
523 {
524 int i;
525 int alloc_size;
526 int octval;
527 int offset;
528 int ret;
529 static char *buf = NULL;
530 char *endp;
531 char *rbuf;
532 char *ostr;
533 __u64 *value;
534 __u64 val = 0;
535
536 if (bit_length <= 64)
537 alloc_size = 8;
538 else
539 alloc_size = (bit_length + 7) / 8;
540
541 buf = xrealloc(buf, alloc_size);
542 memset(buf, 0, alloc_size);
543 value = (__u64 *)buf;
544 rbuf = buf;
545
546 if (*arg == '\"') {
547 /* input a string and output ASCII array of characters */
548
549 /* zap closing quote if there is one */
550 ostr = strrchr(arg + 1, '\"');
551 if (ostr)
552 *ostr = '\0';
553
554 ostr = arg + 1;
555 for (i = 0; i < alloc_size; i++) {
556 if (!*ostr)
557 break;
558
559 /* do octal conversion */
560 if (*ostr == '\\') {
561 if (*(ostr + 1) >= '0' || *(ostr + 1) <= '7') {
562 ret = convert_oct(ostr + 1, &octval);
563 *rbuf++ = octval;
564 ostr += ret + 1;
565 continue;
566 }
567 }
568 *rbuf++ = *ostr++;
569 }
570 return buf;
571 }
572
573 if (arg[0] == '#' || ((arg[0] != '-') && strchr(arg,'-'))) {
574 /*
575 * handle hex blocks ie
576 * #00112233445566778899aabbccddeeff
577 * and uuids ie
578 * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899
579 *
580 * (but if it starts with "-" assume it's just an integer)
581 */
582 int bytes = bit_length / NBBY;
583
584 /* is this an array of hec numbers? */
585 if (bit_length % NBBY)
586 return NULL;
587
588 /* skip leading hash */
589 if (*arg == '#')
590 arg++;
591
592 while (*arg && bytes--) {
593 /* skip hypens */
594 while (*arg == '-')
595 arg++;
596
597 /* get first nybble */
598 if (!isxdigit((int)*arg))
599 return NULL;
600 *rbuf = NYBBLE((int)*arg) << 4;
601 arg++;
602
603 /* skip more hyphens */
604 while (*arg == '-')
605 arg++;
606
607 /* get second nybble */
608 if (!isxdigit((int)*arg))
609 return NULL;
610 *rbuf++ |= NYBBLE((int)*arg);
611 arg++;
612 }
613 if (bytes < 0 && *arg)
614 return NULL;
615
616 return buf;
617 }
618
619 /* handle decimal / hexadecimal integers */
620 val = strtoll(arg, &endp, 0);
621 /* return if not a clean number */
622 if (*endp != '\0')
623 return NULL;
624
625 /* Does the value fit into the range of the destination bitfield? */
626 if (bit_length < 64 && (val >> bit_length) > 0)
627 return NULL;
628 /*
629 * If the length of the field is not a multiple of a byte, push
630 * the bits up in the field, so the most signicant field bit is
631 * the most significant bit in the byte:
632 *
633 * before:
634 * val |----|----|----|----|----|--MM|mmmm|llll|
635 * after
636 * val |----|----|----|----|----|MMmm|mmll|ll00|
637 */
638 offset = bit_length % NBBY;
639 if (offset)
640 val <<= (NBBY - offset);
641
642 /*
643 * convert to big endian and copy into the array
644 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
645 */
646 *value = cpu_to_be64(val);
647
648 /*
649 * Align the array to point to the field in the array.
650 * rbuf = |MMmm|mmll|ll00|
651 */
652 offset = sizeof(__be64) - 1 - ((bit_length - 1) / sizeof(__be64));
653 rbuf += offset;
654 return rbuf;
655 }
656
657
658 /* ARGSUSED */
659 void
660 write_struct(
661 const field_t *fields,
662 int argc,
663 char **argv)
664 {
665 const ftattr_t *fa;
666 flist_t *fl;
667 flist_t *sfl;
668 int bit_length;
669 char *buf;
670 int parentoffset;
671
672 if (argc != 2) {
673 dbprintf(_("usage: write fieldname value\n"));
674 return;
675 }
676
677 fl = flist_scan(argv[0]);
678 if (!fl) {
679 dbprintf(_("unable to parse '%s'.\n"), argv[0]);
680 return;
681 }
682
683 /* if we're a root field type, go down 1 layer to get field list */
684 if (fields->name[0] == '\0') {
685 fa = &ftattrtab[fields->ftyp];
686 ASSERT(fa->ftyp == fields->ftyp);
687 fields = fa->subfld;
688 }
689
690 /* run down the field list and set offsets into the data */
691 if (!flist_parse(fields, fl, iocur_top->data, 0)) {
692 flist_free(fl);
693 dbprintf(_("parsing error\n"));
694 return;
695 }
696
697 sfl = fl;
698 parentoffset = 0;
699 while (sfl->child) {
700 parentoffset = sfl->offset;
701 sfl = sfl->child;
702 }
703
704 /*
705 * For structures, fsize * fcount tells us the size of the region we are
706 * modifying, which is usually a single structure member and is pointed
707 * to by the last child in the list.
708 *
709 * However, if the base structure is an array and we have a direct index
710 * into the array (e.g. write bno[5]) then we are returned a single
711 * flist object with the offset pointing directly at the location we
712 * need to modify. The length of the object we are modifying is then
713 * determined by the size of the individual array entry (fsize) and the
714 * indexes defined in the object, not the overall size of the array
715 * (which is what fcount returns).
716 */
717 bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
718 if (sfl->fld->flags & FLD_ARRAY)
719 bit_length *= sfl->high - sfl->low + 1;
720 else
721 bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
722
723 /* convert this to a generic conversion routine */
724 /* should be able to handle str, num, or even labels */
725
726 buf = convert_arg(argv[1], bit_length);
727 if (!buf) {
728 dbprintf(_("unable to convert value '%s'.\n"), argv[1]);
729 flist_free(fl);
730 return;
731 }
732
733 setbitval(iocur_top->data, sfl->offset, bit_length, buf);
734 write_cur();
735
736 flist_print(fl);
737 print_flist(fl);
738 flist_free(fl);
739 }
740
741 /* ARGSUSED */
742 void
743 write_string(
744 const field_t *fields,
745 int argc,
746 char **argv)
747 {
748 char *buf;
749 int i;
750
751 if (argc != 1) {
752 dbprintf(_("usage (in string mode): write \"string...\"\n"));
753 return;
754 }
755
756 buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8));
757 for (i = 0; i < iocur_top->len; i++) {
758 ((char *)iocur_top->data)[i] = *buf;
759 if (*buf++ == '\0')
760 break;
761 }
762
763 /* write back to disk */
764 write_cur();
765 }
766
767 /* ARGSUSED */
768 void
769 write_block(
770 const field_t *fields,
771 int argc,
772 char **argv)
773 {
774 int i;
775 int shiftcount = -1;
776 int start = -1;
777 int len = -1;
778 int from = -1;
779 int to = -1;
780 struct bw_cmd *cmd = NULL;
781
782 if (argc <= 1 || argc > 5)
783 goto block_usage;
784
785 for (i = 0; i < BWRITE_CMD_MAX; i++) {
786 if (sigcmp(argv[0], bw_cmdtab[i].cmdstr,
787 bw_cmdtab[i].sig_chars)) {
788 cmd = &bw_cmdtab[i];
789 break;
790 }
791 }
792
793 if (!cmd) {
794 dbprintf(_("write: invalid subcommand\n"));
795 goto block_usage;
796 }
797
798 if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) {
799 dbprintf(_("write %s: invalid number of arguments\n"),
800 cmd->cmdstr);
801 goto block_usage;
802 }
803
804 if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc))
805 shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0);
806 if (cmd->start_arg && (cmd->start_arg < argc))
807 start = (int)strtoul(argv[cmd->start_arg], NULL, 0);
808 if (cmd->len_arg && (cmd->len_arg < argc))
809 len = (int)strtoul(argv[cmd->len_arg], NULL, 0);
810 if (cmd->from_arg && (cmd->len_arg < argc))
811 from = (int)strtoul(argv[cmd->from_arg], NULL, 0);
812 if (cmd->to_arg && (cmd->len_arg < argc))
813 to = (int)strtoul(argv[cmd->to_arg], NULL, 0);
814
815 cmd->cmdfunc(start, len, shiftcount, from, to);
816
817 /* write back to disk */
818 write_cur();
819 return;
820
821 block_usage:
822
823 dbprintf(_("usage: write (in data mode)\n"));
824 for (i = 0; i < BWRITE_CMD_MAX; i++) {
825 dbprintf(" %-9.9s %s\n",
826 bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage);
827 }
828 dbprintf("\n");
829 return;
830 }