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