1 /*
2  * Copyright (c) 1998,1999,2000
3  *	Traakan, Inc., Los Altos, CA
4  *	All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  */
36 
37 #include "ndmos.h"
38 #include "wraplib.h"
39 
40 
41 
42 
43 int
wrap_main(int ac,char * av[],struct wrap_ccb * wccb)44 wrap_main (int ac, char *av[], struct wrap_ccb *wccb)
45 {
46 	int		rc;
47 
48 	rc = wrap_process_args (ac, av, wccb);
49 	if (rc)
50 		return rc;
51 
52 	rc = wrap_main_start_index_file (wccb);
53 	if (rc)
54 		return rc;
55 
56 	rc = wrap_main_start_image_file (wccb);
57 	if (rc)
58 		return rc;
59 
60 
61 	return 0;
62 }
63 
64 int
wrap_main_start_index_file(struct wrap_ccb * wccb)65 wrap_main_start_index_file (struct wrap_ccb *wccb)
66 {
67 	char *		filename = wccb->I_index_file_name;
68 	FILE *		fp;
69 
70 	if (!filename)
71 		return 0;
72 
73 	if (filename[0] == '#') {
74 		int	fd = atoi (filename+1);
75 
76 		if (fd < 2 || fd > 100) {
77 			/* huey! */
78 			strcpy (wccb->errmsg, "bad -I#N");
79 			return -1;
80 		}
81 		fp = fdopen (fd, "w");
82 		if (!fp) {
83 			sprintf (wccb->errmsg, "failed fdopen %s", filename);
84 			return -1;
85 		}
86 	} else {
87 		fp = fopen (filename, "w");
88 		if (!fp) {
89 			sprintf (wccb->errmsg, "failed open %s", filename);
90 			return -1;
91 		}
92 	}
93 
94 	wccb->index_fp = fp;
95 
96 	return 0;
97 }
98 
99 int
wrap_main_start_image_file(struct wrap_ccb * wccb)100 wrap_main_start_image_file (struct wrap_ccb *wccb)
101 {
102 	char *		filename = wccb->f_file_name;
103 	int		fd, o_mode;
104 
105 	switch (wccb->op) {
106 	case WRAP_CCB_OP_BACKUP:
107 		o_mode = O_CREAT | O_WRONLY;
108 		break;
109 
110 	case WRAP_CCB_OP_RECOVER:
111 	case WRAP_CCB_OP_RECOVER_FILEHIST:
112 		o_mode = O_RDONLY;
113 		break;
114 
115 	default:
116 		abort();
117 		return -1;
118 	}
119 
120 	if (!filename)
121 		filename = "-";
122 
123 	if (strcmp (filename, "-") == 0) {
124 		if (wccb->op == WRAP_CCB_OP_BACKUP) {
125 			fd = 1;
126 		} else {
127 			fd = 0;
128 		}
129 	} else if (filename[0] == '#') {
130 		fd = atoi (filename+1);
131 
132 		if (fd < 2 || fd > 100) {
133 			/* huey! */
134 			strcpy (wccb->errmsg, "bad -f#N");
135 			return -1;
136 		}
137 	} else {
138 		fd = open (filename, o_mode, 0666);
139 		if (fd < 0) {
140 			sprintf (wccb->errmsg, "failed open %s", filename);
141 			return -1;
142 		}
143 	}
144 
145 	wccb->data_conn_fd = fd;
146 
147 	return 0;
148 }
149 
150 void
wrap_log(struct wrap_ccb * wccb,char * fmt,...)151 wrap_log (struct wrap_ccb *wccb, char *fmt, ...)
152 {
153 	va_list		ap;
154 	char		buf[4096];
155 
156 	if (!wccb->index_fp && wccb->d_debug < 1)
157 		return;
158 
159 	sprintf (buf, "%04d ", ++wccb->log_seq_num);
160 
161 	va_start (ap, fmt);
162 	vsnprintf (buf+5, sizeof(buf)-5, fmt, ap);
163 	va_end (ap);
164 
165 	if (wccb->index_fp)
166 		wrap_send_log_message (wccb->index_fp, buf);
167 
168 	if (wccb->d_debug > 0)
169 		fprintf (stderr, "LOG: %s\n", buf);
170 }
171 
172 int
wrap_set_error(struct wrap_ccb * wccb,int error)173 wrap_set_error (struct wrap_ccb *wccb, int error)
174 {
175 	if (error == 0)
176 		error = -3;
177 
178 	wccb->error = error;
179 
180 	return wccb->error;
181 }
182 
183 int
wrap_set_errno(struct wrap_ccb * wccb)184 wrap_set_errno (struct wrap_ccb *wccb)
185 {
186 	return wrap_set_error (wccb, errno);
187 }
188 
189 
190 /*
191  * wrap -c [-B TYPE] [-d N] [-I FILE] [-E NAME=VALUE ...]
192  * wrap -x [-B TYPE] [-d N] [-I FILE] [-E NAME=VALUE ...]
193  *		ORIGINAL_NAME @pos NEW_NAME ...
194  * wrap -t [-B TYPE] [-d N] [-I FILE] [-E NAME=VALUE ...]
195  *		ORIGINAL_NAME @pos
196  */
197 
198 int
wrap_process_args(int argc,char * argv[],struct wrap_ccb * wccb)199 wrap_process_args (int argc, char *argv[], struct wrap_ccb *wccb)
200 {
201 	int			c;
202 	enum wrap_ccb_op	op;
203 	char *			p;
204 
205 	NDMOS_MACRO_ZEROFILL (wccb);
206 
207 	wccb->progname = argv[0];
208 
209 	if (argc < 2) {
210 		strcpy (wccb->errmsg, "too few arguments");
211 		return -1;
212 	}
213 
214 	while ((c = getopt (argc, argv, "cxtB:d:I:E:f:o:")) != EOF) {
215 	    switch (c) {
216 	    case 'c':
217 		op = WRAP_CCB_OP_BACKUP;
218 		goto set_op;
219 
220 	    case 't':
221 		op = WRAP_CCB_OP_RECOVER_FILEHIST;
222 		goto set_op;
223 
224 	    case 'x':
225 		op = WRAP_CCB_OP_RECOVER;
226 		goto set_op;
227 
228 	    set_op:
229 		if (wccb->op != WRAP_CCB_OP_NONE) {
230 			strcpy (wccb->errmsg, "only one of -c, -x, -t");
231 			return -1;
232 		}
233 		wccb->op = op;
234 		break;
235 
236 	    case 'B':
237 		if (wccb->B_butype) {
238 			strcpy (wccb->errmsg, "only one -B allowed");
239 			return -1;
240 		}
241 		wccb->B_butype = optarg;
242 		break;
243 
244 	    case 'd':
245 		wccb->d_debug = atoi(optarg);
246 		break;
247 
248 	    case 'E':
249 		if (wccb->n_env >= WRAP_MAX_ENV) {
250 			strcpy (wccb->errmsg, "-E overflow");
251 			return -1;
252 		}
253 		p = strchr (optarg, '=');
254 		if (p) {
255 			*p++ = 0;
256 		} else {
257 			p = "";
258 		}
259 		wccb->env[wccb->n_env].name = optarg;
260 		wccb->env[wccb->n_env].value = p;
261 		wccb->n_env++;
262 		break;
263 
264 	    case 'f':
265 		if (wccb->f_file_name) {
266 			strcpy (wccb->errmsg, "only one -f allowed");
267 			return -1;
268 		}
269 		wccb->f_file_name = optarg;
270 		break;
271 
272 	    case 'I':
273 		if (wccb->I_index_file_name) {
274 			strcpy (wccb->errmsg, "only one -I allowed");
275 			return -1;
276 		}
277 		wccb->I_index_file_name = optarg;
278 		break;
279 
280 	    case 'o':
281 		if (wccb->n_o_option >= WRAP_MAX_O_OPTION) {
282 			strcpy (wccb->errmsg, "-o overflow");
283 			return -1;
284 		}
285 		wccb->o_option[wccb->n_o_option] = optarg;
286 		wccb->n_o_option++;
287 		break;
288 
289 	    default:
290 		strcpy (wccb->errmsg, "unknown option");
291 		return -1;
292 	    }
293 	}
294 
295 	switch (wccb->op) {
296 	default:
297 		abort();	/* just can't happen */
298 
299 	case WRAP_CCB_OP_NONE:
300 		strcpy (wccb->errmsg, "one of -c, -x, or -t required");
301 		return -1;
302 
303 	case WRAP_CCB_OP_BACKUP:
304 		if (optind < argc) {
305 			strcpy (wccb->errmsg, "extra args not allowed for -c");
306 			return -1;
307 		}
308 		break;
309 
310 	case WRAP_CCB_OP_RECOVER:
311 	case WRAP_CCB_OP_RECOVER_FILEHIST:
312 		break;
313 	}
314 
315 	for (c = optind; c+2 < argc; c += 3) {
316 		p = argv[c+1];
317 
318 		if (p[0] != '@') {
319 			sprintf (wccb->errmsg, "malformed fhinfo %s", p);
320 			return -1;
321 		}
322 
323 		if (wccb->n_file >= WRAP_MAX_FILE) {
324 			strcpy (wccb->errmsg, "file table overflow");
325 			return -1;
326 		}
327 
328 		if (strcmp (p, "@-") == 0) {
329 			wccb->file[wccb->n_file].fhinfo = WRAP_INVALID_FHINFO;
330 		} else {
331 			wccb->file[wccb->n_file].fhinfo =
332 					NDMOS_API_STRTOLL (p+1, &p, 0);
333 			if (*p != 0) {
334 				sprintf(wccb->errmsg,"malformed fhinfo %s",p);
335 				return -1;
336 			}
337 		}
338 
339 		wccb->file[wccb->n_file].original_name = argv[c];
340 		wccb->file[wccb->n_file].save_to_name = argv[c+2];
341 
342 		wccb->n_file++;
343 	}
344 
345 	if (c < argc) {
346 		strcpy (wccb->errmsg, "superfluous args at end");
347 		return -1;
348 	}
349 
350 	p = wrap_find_env (wccb, "HIST");
351 	if (p) {
352 		switch (*p) {
353 		case 'y': case 'Y':
354 			p = wrap_find_env (wccb, "HIST_TYPE");
355 			if (!p) {
356 				p = "y";
357 			}
358 			break;
359 		}
360 
361 		switch (*p) {
362 		case 'y': case 'Y':
363 			wccb->hist_enable = 'y';
364 			break;
365 
366 		case 'd': case 'D':
367 			wccb->hist_enable = 'd';
368 			break;
369 
370 		case 'f': case 'F':
371 			wccb->hist_enable = 'f';
372 			break;
373 
374 		default:
375 			/* gripe? */
376 			break;
377 		}
378 	}
379 
380 	p = wrap_find_env (wccb, "DIRECT");
381 	if (p) {
382 		if (*p == 'y') {
383 			wccb->direct_enable = 1;
384 		}
385 	}
386 
387 	p = wrap_find_env (wccb, "FILESYSTEM");
388 	if (!p)
389 		p = wrap_find_env (wccb, "PREFIX");
390 	if (!p)
391 		p = "/";
392 
393 	wccb->backup_root = p;
394 
395 	return 0;
396 }
397 
398 char *
wrap_find_env(struct wrap_ccb * wccb,char * name)399 wrap_find_env (struct wrap_ccb *wccb, char *name)
400 {
401 	int		i;
402 
403 	for (i = 0; i < wccb->n_env; i++) {
404 		if (strcmp (wccb->env[i].name, name) == 0)
405 			return wccb->env[i].value;
406 	}
407 
408 	return 0;
409 }
410 
411 
412 
413 
414 
415 
416 
417 int
wrap_cmd_add_with_escapes(char * cmd,char * word,char * special)418 wrap_cmd_add_with_escapes (char *cmd, char *word, char *special)
419 {
420 	char *		cmd_lim = &cmd[WRAP_MAX_COMMAND-3];
421 	char *		p;
422 	int		c;
423 
424 	p = cmd;
425 	while (*p) p++;
426 	if (p != cmd) *p++ = ' ';
427 
428 	while ((c = *word++) != 0) {
429 		if (p >= cmd_lim)
430 			return -1;	/* overflow */
431 		if (c == '\\' || strchr (special, c))
432 			*p++ = '\\';
433 		*p++ = c;
434 	}
435 	*p = 0;
436 
437 	return 0;
438 }
439 
440 int
wrap_cmd_add_with_sh_escapes(char * cmd,char * word)441 wrap_cmd_add_with_sh_escapes (char *cmd, char *word)
442 {
443 	return wrap_cmd_add_with_escapes (cmd, word, " \t`'\"*?[]$");
444 }
445 
446 int
wrap_cmd_add_allow_file_wildcards(char * cmd,char * word)447 wrap_cmd_add_allow_file_wildcards (char *cmd, char *word)
448 {
449 	return wrap_cmd_add_with_escapes (cmd, word, " \t`'\"$");
450 }
451 
452 
453 
454 int
wrap_pipe_fork_exec(char * cmd,int fdmap[3])455 wrap_pipe_fork_exec (char *cmd, int fdmap[3])
456 {
457 	int			pipes[3][2];
458 	int			child_fdmap[3];
459 	int			nullfd = -1;
460 	int			i;
461 	int			rc = -1;
462 
463 	for (i = 0; i < 3; i++) {
464 		pipes[i][0] = -1;
465 		pipes[i][1] = -1;
466 		child_fdmap[i] = -1;
467 	}
468 
469 	for (i = 0; i < 3; i++) {
470 		if (fdmap[i] >= 0) {
471 			child_fdmap[i] = fdmap[i];
472 			continue;
473 		}
474 		switch (fdmap[i]) {
475 		case WRAP_FDMAP_DEV_NULL:
476 			if (nullfd < 0) {
477 				nullfd = open ("/dev/null", 2);
478 				if (nullfd < 0) {
479 					goto bail_out;
480 				}
481 			}
482 			child_fdmap[i] = nullfd;
483 			break;
484 
485 		case WRAP_FDMAP_INPUT_PIPE:
486 			rc = pipe (pipes[i]);
487 			if (rc != 0) {
488 				goto bail_out;
489 			}
490 			child_fdmap[i] = pipes[i][0];
491 			break;
492 
493 		case WRAP_FDMAP_OUTPUT_PIPE:
494 			rc = pipe (pipes[i]);
495 			if (rc != 0) {
496 				goto bail_out;
497 			}
498 			child_fdmap[i] = pipes[i][1];
499 			break;
500 
501 		default:
502 			goto bail_out;
503 		}
504 	}
505 
506 	rc = fork();
507 	if (rc < 0) {
508 		goto bail_out;
509 	}
510 
511 	if (rc == 0) {
512 		/* child */
513 		dup2 (child_fdmap[2], 2);
514 		dup2 (child_fdmap[1], 1);
515 		dup2 (child_fdmap[0], 0);
516 
517 		for (rc = 3; rc < 100; rc++) close(rc);
518 
519 		execl ("/bin/sh", "sh", "-c", cmd, NULL);
520 
521 		fprintf (stderr, "EXEC FAILED %s\n", cmd);
522 		exit(127);
523 	}
524 
525 	if (nullfd >= 0)
526 		close (nullfd);
527 
528 	for (i = 0; i < 3; i++) {
529 		if (fdmap[i] >= 0) {
530 			continue;
531 		}
532 		switch (fdmap[i]) {
533 		case WRAP_FDMAP_DEV_NULL:
534 			break;
535 
536 		case WRAP_FDMAP_INPUT_PIPE:
537 			close (pipes[i][0]);
538 			fdmap[i] = pipes[i][1];
539 			break;
540 
541 		case WRAP_FDMAP_OUTPUT_PIPE:
542 			close (pipes[i][1]);
543 			fdmap[i] = pipes[i][0];
544 			break;
545 
546 		default:
547 			abort();
548 		}
549 	}
550 
551 	return rc;	/* PID */
552 
553   bail_out:
554 	if (nullfd >= 0)
555 		close (nullfd);
556 
557 	for (i = 0; i < 3; i++) {
558 		if (pipes[i][0] >= 0)
559 			close (pipes[i][0]);
560 		if (pipes[i][1] >= 0)
561 			close (pipes[i][1]);
562 	}
563 
564 	return -1;
565 }
566 
567 
568 
569 
570 int
wrap_parse_msg(char * buf,struct wrap_msg_buf * wmsg)571 wrap_parse_msg (char *buf, struct wrap_msg_buf *wmsg)
572 {
573 	int		c1, c2;
574 
575 	c1 = buf[0];
576 	c2 = buf[1];
577 
578 	if (buf[2] != ' ') {
579 		return -1;
580 	}
581 
582 	if (c1 == 'L' && c2 == 'x') {		/* log_message */
583 		return wrap_parse_log_message_msg (buf, wmsg);
584 	}
585 
586 	if (c1 == 'H' && c2 == 'F') {		/* add_file */
587 		return wrap_parse_add_file_msg (buf, wmsg);
588 	}
589 
590 	if (c1 == 'H' && c2 == 'D') {		/* add_dirent */
591 		return wrap_parse_add_dirent_msg (buf, wmsg);
592 	}
593 
594 	if (c1 == 'H' && c2 == 'N') {		/* add_node */
595 		return wrap_parse_add_node_msg (buf, wmsg);
596 	}
597 
598 	if (c1 == 'D' && c2 == 'E') {		/* add_env */
599 		return wrap_parse_add_env_msg (buf, wmsg);
600 	}
601 
602 	if (c1 == 'D' && c2 == 'R') {		/* data_read */
603 		return wrap_parse_data_read_msg (buf, wmsg);
604 	}
605 
606 	return -1;
607 }
608 
609 int
wrap_parse_log_message_msg(char * buf,struct wrap_msg_buf * wmsg)610 wrap_parse_log_message_msg (char *buf, struct wrap_msg_buf *wmsg)
611 {
612 	struct wrap_log_message *res = &wmsg->body.log_message;
613 	char *			scan = buf+3;
614 	int			rc;
615 
616 	wmsg->msg_type = WRAP_MSGTYPE_LOG_MESSAGE;
617 
618 	while (*scan && *scan == ' ')
619 		scan++;
620 
621 	rc = wrap_cstr_to_str (scan, res->message, sizeof res->message);
622 	if (rc < 0) return -2;
623 
624 	return 0;
625 }
626 
627 int
wrap_send_log_message(FILE * fp,char * message)628 wrap_send_log_message (FILE *fp, char *message)
629 {
630 	struct wrap_msg_buf	wmsg;
631 	struct wrap_log_message *res = &wmsg.body.log_message;
632 
633 	if (!fp) return -1;
634 
635 	wrap_cstr_from_str (message, res->message, sizeof res->message);
636 	fprintf (fp, "Lx %s\n", res->message);
637 
638 	return 0;
639 }
640 
641 int
wrap_parse_add_file_msg(char * buf,struct wrap_msg_buf * wmsg)642 wrap_parse_add_file_msg (char *buf, struct wrap_msg_buf *wmsg)
643 {
644 	struct wrap_add_file *	res = &wmsg->body.add_file;
645 	char *			scan = buf+3;
646 	char *			p;
647 	int			rc;
648 
649 	wmsg->msg_type = WRAP_MSGTYPE_ADD_FILE;
650 
651 	res->fstat.valid = 0;
652 	res->fhinfo = WRAP_INVALID_FHINFO;
653 
654 	while (*scan && *scan == ' ')
655 		scan++;
656 	if (*scan == 0)
657 		return -1;
658 
659 	p = scan;
660 	while (*scan && *scan != ' ')
661 		scan++;
662 
663 	if (*scan) {
664 		*scan = 0;
665 		rc = wrap_cstr_to_str (p, res->path, sizeof res->path);
666 		*scan++ = ' ';
667 	} else {
668 		rc = wrap_cstr_to_str (p, res->path, sizeof res->path);
669 	}
670 	if (rc < 0) return -2;
671 
672 	while (*scan) {
673 		p = scan+1;
674 		switch (*scan) {
675 		case ' ':
676 			scan++;
677 			continue;
678 
679 		case '@':
680 			res->fhinfo = NDMOS_API_STRTOLL (p, &scan, 0);
681 			break;
682 
683 		default:
684 			rc = wrap_parse_fstat_subr(&scan, &res->fstat);
685 			if (rc < 0)
686 				return rc;
687 			break;
688 		}
689 
690 		if (*scan != ' ' && *scan != 0) {
691 			/* bogus */
692 			return -1;
693 		}
694 	}
695 
696 	return 0;
697 }
698 
699 int
wrap_send_add_file(FILE * fp,char * path,unsigned long long fhinfo,struct wrap_fstat * fstat)700 wrap_send_add_file (FILE *fp, char *path, unsigned long long fhinfo,
701   struct wrap_fstat *fstat)
702 {
703 	struct wrap_msg_buf	wmsg;
704 	struct wrap_add_file *	res = &wmsg.body.add_file;
705 
706 	if (!fp) return -1;
707 
708 	wrap_cstr_from_str (path, res->path, sizeof res->path);
709 	fprintf (fp, "HF %s", res->path);
710 
711 	if (fhinfo != WRAP_INVALID_FHINFO)
712 		fprintf (fp, " @%llu", fhinfo);
713 
714 	wrap_send_fstat_subr (fp, fstat);
715 
716 	fprintf (fp, "\n");
717 
718 	return 0;
719 }
720 
721 int
wrap_parse_add_dirent_msg(char * buf,struct wrap_msg_buf * wmsg)722 wrap_parse_add_dirent_msg (char *buf, struct wrap_msg_buf *wmsg)
723 {
724 	struct wrap_add_dirent *res = &wmsg->body.add_dirent;
725 	char *			scan = buf+3;
726 	char *			p;
727 	int			rc;
728 
729 	wmsg->msg_type = WRAP_MSGTYPE_ADD_DIRENT;
730 
731 	res->fhinfo = WRAP_INVALID_FHINFO;
732 
733 	while (*scan && *scan == ' ')
734 		scan++;
735 	if (*scan == 0)
736 		return -1;
737 
738 	res->dir_fileno = NDMOS_API_STRTOLL (scan, &scan, 0);
739 	if (*scan != ' ')
740 		return -1;
741 
742 	while (*scan == ' ') scan++;
743 
744 	if (*scan == 0)
745 		return -1;
746 
747 	p = scan;
748 	while (*scan && *scan != ' ')
749 		scan++;
750 
751 	if (*scan) {
752 		*scan = 0;
753 		rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
754 		*scan++ = ' ';
755 	} else {
756 		rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
757 	}
758 	if (rc < 0) return -2;
759 
760 	res->fileno = NDMOS_API_STRTOLL (scan, &scan, 0);
761 	if (*scan != ' ' && *scan != 0)
762 		return -1;
763 
764 	while (*scan == ' ') scan++;
765 
766 	if (*scan == '@') {
767 		res->fhinfo = NDMOS_API_STRTOLL(scan+1, &scan, 0);
768 	}
769 
770 	if (*scan != ' ' && *scan != 0)
771 		return -1;
772 
773 	while (*scan == ' ') scan++;
774 
775 	if (*scan)
776 		return -1;
777 
778 	return 0;
779 }
780 
781 int
wrap_send_add_dirent(FILE * fp,char * name,unsigned long long fhinfo,unsigned long long dir_fileno,unsigned long long fileno)782 wrap_send_add_dirent (FILE *fp, char *name, unsigned long long fhinfo,
783   unsigned long long dir_fileno, unsigned long long fileno)
784 {
785 	struct wrap_msg_buf	wmsg;
786 	struct wrap_add_dirent *res = &wmsg.body.add_dirent;
787 
788 	if (!fp) return -1;
789 
790 	wrap_cstr_from_str (name, res->name, sizeof res->name);
791 	fprintf (fp, "HD %llu %s %llu", dir_fileno, res->name, fileno);
792 
793 	if (fhinfo != WRAP_INVALID_FHINFO)
794 		fprintf (fp, " @%llu", fhinfo);
795 
796 	fprintf (fp, "\n");
797 
798 	return 0;
799 }
800 
801 
802 int
wrap_parse_add_node_msg(char * buf,struct wrap_msg_buf * wmsg)803 wrap_parse_add_node_msg (char *buf, struct wrap_msg_buf *wmsg)
804 {
805 	struct wrap_add_node *	res = &wmsg->body.add_node;
806 	char *			scan = buf+3;
807 	char *			p;
808 	int			rc;
809 
810 	wmsg->msg_type = WRAP_MSGTYPE_ADD_NODE;
811 
812 	res->fstat.valid = 0;
813 	res->fhinfo = WRAP_INVALID_FHINFO;
814 
815 	while (*scan && *scan == ' ')
816 		scan++;
817 	if (*scan == 0)
818 		return -1;
819 
820 	res->fstat.fileno = NDMOS_API_STRTOLL (scan, &scan, 0);
821 	if (*scan != ' ' && *scan != 0)
822 		return -1;
823 
824 	res->fstat.valid |= WRAP_FSTAT_VALID_FILENO;
825 
826 	while (*scan) {
827 		p = scan+1;
828 		switch (*scan) {
829 		case ' ':
830 			scan++;
831 			continue;
832 
833 		case '@':
834 			res->fhinfo = NDMOS_API_STRTOLL (p, &scan, 0);
835 			break;
836 
837 		default:
838 			rc = wrap_parse_fstat_subr(&scan, &res->fstat);
839 			if (rc < 0)
840 				return rc;
841 			break;
842 		}
843 
844 		if (*scan != ' ' && *scan != 0) {
845 			/* bogus */
846 			return -1;
847 		}
848 	}
849 
850 	if ( (res->fstat.valid & WRAP_FSTAT_VALID_FILENO) == 0)
851 		return -5;
852 
853 	return 0;
854 }
855 
856 int
wrap_send_add_node(FILE * fp,unsigned long long fhinfo,struct wrap_fstat * fstat)857 wrap_send_add_node (FILE *fp, unsigned long long fhinfo,
858   struct wrap_fstat *fstat)
859 {
860 	unsigned long		save_valid;
861 
862 	if (!fp) return -1;
863 
864 	if (fstat->valid & WRAP_FSTAT_VALID_FILENO) {
865 		fprintf (fp, "HN %llu", fstat->fileno);
866 	} else {
867 		fprintf (fp, "HN 0000000000");
868 	}
869 
870 	if (fhinfo != WRAP_INVALID_FHINFO)
871 		fprintf (fp, " @%llu", fhinfo);
872 
873 	/* suppress iFILENO */
874 	save_valid = fstat->valid;
875 	fstat->valid &= ~WRAP_FSTAT_VALID_FILENO;
876 	wrap_send_fstat_subr (fp, fstat);
877 	fstat->valid = save_valid;
878 
879 	fprintf (fp, "\n");
880 
881 	return 0;
882 }
883 
884 
885 int
wrap_parse_fstat_subr(char ** scanp,struct wrap_fstat * fstat)886 wrap_parse_fstat_subr (char **scanp, struct wrap_fstat *fstat)
887 {
888 	char *		scan = *scanp;
889 	char *		p = scan+1;
890 	unsigned long	valid = 0;
891 
892 	valid = 0;
893 	switch (*scan) {
894 	case 's':	/* size */
895 		valid = WRAP_FSTAT_VALID_SIZE;
896 		fstat->size = NDMOS_API_STRTOLL (p, &scan, 0);
897 		break;
898 
899 	case 'i':	/* fileno (inum) */
900 		valid = WRAP_FSTAT_VALID_FILENO;
901 		fstat->fileno = NDMOS_API_STRTOLL (p, &scan, 0);
902 		break;
903 
904 	case 'm':	/* mode low twelve bits */
905 		valid = WRAP_FSTAT_VALID_MODE;
906 		fstat->mode = strtol (p, &scan, 8);
907 		break;
908 
909 	case 'l':	/* link count */
910 		valid = WRAP_FSTAT_VALID_LINKS;
911 		fstat->links = strtol (p, &scan, 0);
912 		break;
913 
914 	case 'u':	/* uid */
915 		valid = WRAP_FSTAT_VALID_UID;
916 		fstat->uid = strtol (p, &scan, 0);
917 		break;
918 
919 	case 'g':	/* gid */
920 		valid = WRAP_FSTAT_VALID_GID;
921 		fstat->gid = strtol (p, &scan, 0);
922 		break;
923 
924 	case 't':		/* one of the times */
925 		p = scan+2;
926 		switch (scan[1]) {
927 		case 'm':	/* mtime */
928 			valid = WRAP_FSTAT_VALID_MTIME;
929 			fstat->mtime = strtol (p, &scan, 0);
930 			break;
931 
932 		case 'a':	/* atime */
933 			valid = WRAP_FSTAT_VALID_ATIME;
934 			fstat->atime = strtol (p, &scan, 0);
935 			break;
936 
937 		case 'c':	/* ctime */
938 			valid = WRAP_FSTAT_VALID_CTIME;
939 			fstat->ctime = strtol (p, &scan, 0);
940 			break;
941 
942 		default:
943 			return -3;
944 		}
945 		break;
946 
947 	case 'f':	/* ftype (file type) */
948 		valid = WRAP_FSTAT_VALID_FTYPE;
949 		switch (scan[1]) {
950 		case 'd':	fstat->ftype = WRAP_FTYPE_DIR; break;
951 		case 'p':	fstat->ftype = WRAP_FTYPE_FIFO; break;
952 		case 'c':	fstat->ftype = WRAP_FTYPE_CSPEC; break;
953 		case 'b':	fstat->ftype = WRAP_FTYPE_BSPEC; break;
954 		case '-':	fstat->ftype = WRAP_FTYPE_REG; break;
955 		case 'l':	fstat->ftype = WRAP_FTYPE_SLINK; break;
956 		case 's':	fstat->ftype = WRAP_FTYPE_SOCK; break;
957 		case 'R':	fstat->ftype = WRAP_FTYPE_REGISTRY; break;
958 		case 'o':	fstat->ftype = WRAP_FTYPE_OTHER; break;
959 		default:
960 			fstat->ftype = WRAP_FTYPE_INVALID;
961 			return -5;
962 		}
963 		scan += 2;
964 		break;
965 
966 	default:
967 		return -3;
968 	}
969 
970 	if (*scan != ' ' && *scan != 0)
971 		return -1;
972 
973 	fstat->valid |= valid;
974 	*scanp = scan;
975 
976 	return 0;
977 }
978 
979 int
wrap_send_fstat_subr(FILE * fp,struct wrap_fstat * fstat)980 wrap_send_fstat_subr (FILE *fp, struct wrap_fstat *fstat)
981 {
982 	if (!fp) return -1;
983 
984 	if (fstat->valid & WRAP_FSTAT_VALID_FTYPE) {
985 		int		c = 0;
986 
987 		switch (fstat->ftype) {
988 		default:
989 		case WRAP_FTYPE_INVALID:
990 			c = 0;
991 			break;
992 		case WRAP_FTYPE_DIR:		c = 'd'; break;
993 		case WRAP_FTYPE_FIFO:		c = 'p'; break;
994 		case WRAP_FTYPE_CSPEC:		c = 'c'; break;
995 		case WRAP_FTYPE_BSPEC:		c = 'b'; break;
996 		case WRAP_FTYPE_REG:		c = '-'; break;
997 		case WRAP_FTYPE_SLINK:		c = 'l'; break;
998 		case WRAP_FTYPE_SOCK:		c = 's'; break;
999 		case WRAP_FTYPE_REGISTRY:	c = 'R'; break;
1000 		case WRAP_FTYPE_OTHER:		c = 'o'; break;
1001 		}
1002 
1003 		if (c) {
1004 			fprintf (fp, " f%c", c);
1005 		} else {
1006 			return -1;
1007 		}
1008 	}
1009 
1010 	if (fstat->valid & WRAP_FSTAT_VALID_MODE) {
1011 		fprintf (fp, " m%04o", fstat->mode);
1012 	}
1013 
1014 	if (fstat->valid & WRAP_FSTAT_VALID_LINKS) {
1015 		fprintf (fp, " l%lu", fstat->links);
1016 	}
1017 
1018 	if (fstat->valid & WRAP_FSTAT_VALID_SIZE) {
1019 		fprintf (fp, " s%llu", fstat->size);
1020 	}
1021 
1022 	if (fstat->valid & WRAP_FSTAT_VALID_UID) {
1023 		fprintf (fp, " u%lu", fstat->uid);
1024 	}
1025 
1026 	if (fstat->valid & WRAP_FSTAT_VALID_GID) {
1027 		fprintf (fp, " g%lu", fstat->gid);
1028 	}
1029 
1030 	if (fstat->valid & WRAP_FSTAT_VALID_ATIME) {
1031 		fprintf (fp, " ta%lu", fstat->atime);
1032 	}
1033 
1034 	if (fstat->valid & WRAP_FSTAT_VALID_MTIME) {
1035 		fprintf (fp, " tm%lu", fstat->mtime);
1036 	}
1037 
1038 	if (fstat->valid & WRAP_FSTAT_VALID_CTIME) {
1039 		fprintf (fp, " tc%lu", fstat->ctime);
1040 	}
1041 
1042 	if (fstat->valid & WRAP_FSTAT_VALID_FILENO) {
1043 		fprintf (fp, " i%llu", fstat->fileno);
1044 	}
1045 
1046 	return 0;
1047 }
1048 
1049 int
wrap_parse_add_env_msg(char * buf,struct wrap_msg_buf * wmsg)1050 wrap_parse_add_env_msg (char *buf, struct wrap_msg_buf *wmsg)
1051 {
1052 	struct wrap_add_env *	res = &wmsg->body.add_env;
1053 	char *			scan = buf+3;
1054 	char *			p;
1055 	int			rc;
1056 
1057 	wmsg->msg_type = WRAP_MSGTYPE_ADD_ENV;
1058 
1059 	while (*scan && *scan == ' ')
1060 		scan++;
1061 	if (*scan == 0)
1062 		return -1;
1063 
1064 	p = scan;
1065 	while (*scan && *scan != ' ')
1066 		scan++;
1067 
1068 	if (*scan) {
1069 		*scan = 0;
1070 		rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
1071 		*scan++ = ' ';
1072 	} else {
1073 		rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
1074 	}
1075 	if (rc < 0) return -2;
1076 
1077 	while (*scan && *scan == ' ')
1078 		scan++;
1079 
1080 	p = scan;
1081 	while (*scan && *scan != ' ')
1082 		scan++;
1083 
1084 	if (*scan) {
1085 		*scan = 0;
1086 		rc = wrap_cstr_to_str (p, res->value, sizeof res->value);
1087 		*scan++ = ' ';
1088 	} else {
1089 		rc = wrap_cstr_to_str (p, res->value, sizeof res->value);
1090 	}
1091 	if (rc < 0) return -2;
1092 
1093 	return 0;
1094 }
1095 
1096 int
wrap_send_add_env(FILE * fp,char * name,char * value)1097 wrap_send_add_env (FILE *fp, char *name, char *value)
1098 {
1099 	struct wrap_msg_buf	wmsg;
1100 	struct wrap_add_env *	res = &wmsg.body.add_env;
1101 
1102 	if (!fp) return -1;
1103 
1104 	wrap_cstr_from_str (name, res->name, sizeof res->name);
1105 	wrap_cstr_from_str (value, res->value, sizeof res->value);
1106 
1107 	fprintf (fp, "DE %s %s\n", res->name, res->value);
1108 
1109 	return 0;
1110 }
1111 
1112 int
wrap_parse_data_read_msg(char * buf,struct wrap_msg_buf * wmsg)1113 wrap_parse_data_read_msg (char *buf, struct wrap_msg_buf *wmsg)
1114 {
1115 	struct wrap_data_read *	res = &wmsg->body.data_read;
1116 	char *			scan = buf+3;
1117 
1118 	wmsg->msg_type = WRAP_MSGTYPE_DATA_READ;
1119 
1120 	while (*scan && *scan == ' ')
1121 		scan++;
1122 	if (*scan == 0)
1123 		return -1;
1124 
1125 	res->offset = NDMOS_API_STRTOLL (scan, &scan, 0);
1126 	if (*scan != ' ')
1127 		return -1;
1128 
1129 	while (*scan && *scan != ' ')
1130 		scan++;
1131 
1132 	if (*scan == 0)
1133 		return -1;
1134 
1135 	res->length = NDMOS_API_STRTOLL (scan, &scan, 0);
1136 
1137 	/* tolerate trailing white */
1138 	while (*scan && *scan != ' ')
1139 		scan++;
1140 
1141 	if (*scan != 0)
1142 		return -1;
1143 
1144 	return 0;
1145 }
1146 
1147 int
wrap_send_data_read(FILE * fp,unsigned long long offset,unsigned long long length)1148 wrap_send_data_read (FILE *fp,
1149   unsigned long long offset, unsigned long long length)
1150 {
1151 
1152 	if (!fp) return -1;
1153 
1154 	fprintf (fp, "DR %lld %lld\n", (long long) offset, (long long)length);
1155 	fflush (fp);
1156 
1157 	return 0;
1158 }
1159 
1160 int
wrap_parse_data_stats_msg(char * buf,struct wrap_msg_buf * wmsg)1161 wrap_parse_data_stats_msg (char *buf, struct wrap_msg_buf *wmsg)
1162 {
1163 #if 0
1164 	struct wrap_data_stats *res = &wmsg->body.data_stats;
1165 	char *			scan = buf+3;
1166 
1167 	wmsg->msg_type = WRAP_MSGTYPE_DATA_STATS;
1168 #endif
1169 	return -1;
1170 }
1171 
1172 int
wrap_send_data_stats(FILE * fp)1173 wrap_send_data_stats (FILE *fp)
1174 {
1175 	if (!fp) return -1;
1176 
1177 	fprintf (fp, "DS ...\n");
1178 	fflush (fp);
1179 
1180 	return 0;
1181 }
1182 
1183 
1184 
1185 
1186 /*
1187  * Recovery helpers
1188  ****************************************************************
1189  */
1190 
1191 int
wrap_reco_align_to_wanted(struct wrap_ccb * wccb)1192 wrap_reco_align_to_wanted (struct wrap_ccb *wccb)
1193 {
1194 	unsigned long long	distance;
1195 	unsigned long		unwanted_length;
1196 
1197    top:
1198 	/*
1199 	 * If there is an error, we're toast.
1200 	 */
1201 	if (wccb->error)
1202 		return wccb->error;
1203 
1204 	/*
1205 	 * If we're aligned, we're done.
1206 	 */
1207 	if (wccb->expect_offset == wccb->want_offset) {
1208 		if (wccb->expect_length < wccb->want_length
1209 		 && wccb->reading_length == 0) {
1210 			wrap_reco_issue_read (wccb);
1211 		}
1212 		return wccb->error;
1213 	}
1214 
1215 	/*
1216 	 * If we have a portion we don't want, consume it now
1217 	 */
1218 	if (wccb->have_length > 0) {
1219 		if (wccb->have_offset < wccb->want_offset) {
1220 			distance = wccb->want_offset - wccb->have_offset;
1221 			if (distance < wccb->have_length) {
1222 				/*
1223 				 * We have some of what we want.
1224 				 * Consume (discard) unwanted part.
1225 				 */
1226 				unwanted_length = distance;
1227 			} else {
1228 				unwanted_length = wccb->have_length;
1229 			}
1230 		} else {
1231 			unwanted_length = wccb->have_length;
1232 		}
1233 		wrap_reco_consume (wccb, unwanted_length);
1234 		goto top;
1235 	}
1236 
1237 	if (wccb->expect_length > 0) {
1238 		/* Incoming, but we don't have it yet. */
1239 		wrap_reco_receive (wccb);
1240 		goto top;
1241 	}
1242 
1243 	/*
1244 	 * We don't have anything. We don't expect anything.
1245 	 * Time to issue an NDMP_DATA_NOTIFY_READ via this wrapper.
1246 	 */
1247 
1248 	wrap_reco_issue_read (wccb);
1249 
1250 	goto top;
1251 }
1252 
1253 int
wrap_reco_receive(struct wrap_ccb * wccb)1254 wrap_reco_receive (struct wrap_ccb *wccb)
1255 {
1256 	char *		iobuf_end = &wccb->iobuf[wccb->n_iobuf];
1257 	char *		have_end = wccb->have + wccb->have_length;
1258 	unsigned	n_read = iobuf_end - have_end;
1259 	int		rc;
1260 
1261 	if (wccb->error)
1262 		return wccb->error;
1263 
1264 	if (wccb->have_length == 0) {
1265 		wccb->have = wccb->iobuf;
1266 		have_end = wccb->have + wccb->have_length;
1267 	}
1268 
1269 	if (n_read < 512 && wccb->have != wccb->iobuf) {
1270 		/* Not much room at have_end. Front of iobuf available. */
1271 		/* Compress */
1272 		NDMOS_API_BCOPY (wccb->have, wccb->iobuf, wccb->have_length);
1273 		wccb->have = wccb->iobuf;
1274 		have_end = wccb->have + wccb->have_length;
1275 		n_read = iobuf_end - have_end;
1276 	}
1277 
1278 	if (n_read > wccb->reading_length)
1279 		n_read = wccb->reading_length;
1280 
1281 	if (n_read == 0) {
1282 		/* Hmmm. */
1283 		abort ();
1284 		return -1;
1285 	}
1286 
1287 	rc = read (wccb->data_conn_fd, have_end, n_read);
1288 	if (rc > 0) {
1289 		wccb->have_length += rc;
1290 		wccb->reading_offset += rc;
1291 		wccb->reading_length -= rc;
1292 	} else {
1293 		/* EOF or error */
1294 		if (rc == 0) {
1295 			strcpy (wccb->errmsg, "EOF on data connection");
1296 			wrap_set_error (wccb, -1);
1297 		} else {
1298 			sprintf (wccb->errmsg, "errno %d on data connection",
1299 					errno);
1300 			wrap_set_errno (wccb);
1301 		}
1302 	}
1303 
1304 	return wccb->error;
1305 }
1306 
1307 int
wrap_reco_consume(struct wrap_ccb * wccb,unsigned long length)1308 wrap_reco_consume (struct wrap_ccb *wccb, unsigned long length)
1309 {
1310 	assert (wccb->have_length >= length);
1311 
1312 	wccb->have_offset += length;
1313 	wccb->have_length -= length;
1314 	wccb->expect_offset += length;
1315 	wccb->expect_length -= length;
1316 	wccb->have += length;
1317 
1318 	if (wccb->expect_length == 0) {
1319 		assert (wccb->have_length == 0);
1320 		wccb->expect_offset = -1ull;
1321 	}
1322 
1323 	return wccb->error;
1324 }
1325 
1326 int
wrap_reco_must_have(struct wrap_ccb * wccb,unsigned long length)1327 wrap_reco_must_have (struct wrap_ccb *wccb, unsigned long length)
1328 {
1329 	if (wccb->want_length < length)
1330 		wccb->want_length = length;
1331 
1332 	wrap_reco_align_to_wanted (wccb);
1333 
1334 	while (wccb->have_length < length && !wccb->error) {
1335 		wrap_reco_align_to_wanted (wccb); /* triggers issue_read() */
1336 		wrap_reco_receive (wccb);
1337 	}
1338 
1339 	if (wccb->have_length >= length)
1340 		return 0;
1341 
1342 	return wccb->error;
1343 }
1344 
1345 int
wrap_reco_seek(struct wrap_ccb * wccb,unsigned long long want_offset,unsigned long long want_length,unsigned long must_have_length)1346 wrap_reco_seek (struct wrap_ccb *wccb,
1347  unsigned long long want_offset,
1348  unsigned long long want_length,
1349  unsigned long must_have_length)
1350 {
1351 	if (wccb->error)
1352 		return wccb->error;
1353 
1354 	wccb->want_offset = want_offset;
1355 	wccb->want_length = want_length;
1356 
1357 	return wrap_reco_must_have (wccb, must_have_length);
1358 }
1359 
1360 int
wrap_reco_pass(struct wrap_ccb * wccb,int write_fd,unsigned long long length,unsigned write_bsize)1361 wrap_reco_pass (struct wrap_ccb *wccb, int write_fd,
1362   unsigned long long length, unsigned write_bsize)
1363 {
1364 	unsigned		cnt;
1365 	int			rc;
1366 
1367 	while (length > 0) {
1368 		if (wccb->error)
1369 			break;
1370 
1371 		cnt = write_bsize;
1372 		if (cnt > length)
1373 			cnt = length;
1374 
1375 		if (wccb->have_length < cnt) {
1376 			wrap_reco_must_have (wccb, cnt);
1377 		}
1378 
1379 		rc = write (write_fd, wccb->have, cnt);
1380 
1381 		length -= cnt;
1382 		wrap_reco_consume (wccb, cnt);
1383 	}
1384 
1385 	return wccb->error;
1386 }
1387 
1388 int
wrap_reco_issue_read(struct wrap_ccb * wccb)1389 wrap_reco_issue_read (struct wrap_ccb *wccb)
1390 {
1391 	unsigned long long		off;
1392 	unsigned long long		len;
1393 
1394 	assert (wccb->reading_length == 0);
1395 
1396 	if (wccb->data_conn_mode == 0) {
1397 		struct stat	st;
1398 		int		rc;
1399 
1400 		rc = fstat (wccb->data_conn_fd, &st);
1401 		if (rc != 0) {
1402 			sprintf (wccb->errmsg, "Can't fstat() data conn rc=%d",
1403 				rc);
1404 			return wrap_set_errno (wccb);
1405 		}
1406 		if (S_ISFIFO(st.st_mode)) {
1407 			wccb->data_conn_mode = 'p';
1408 			if (!wccb->index_fp) {
1409 				strcpy (wccb->errmsg,
1410 					"data_conn is pipe but no -I");
1411 				return wrap_set_error (wccb, -3);
1412 			}
1413 		} else if (S_ISREG(st.st_mode)) {
1414 			wccb->data_conn_mode = 'f';
1415 		} else {
1416 			sprintf (wccb->errmsg, "Unsupported data_conn type %o",
1417 				st.st_mode);
1418 			return wrap_set_error (wccb, -3);
1419 		}
1420 	}
1421 
1422 	off = wccb->want_offset;
1423 	len = wccb->want_length;
1424 
1425 	off += wccb->have_length;
1426 	len -= wccb->have_length;
1427 
1428 	if (len == 0) {
1429 		abort();
1430 	}
1431 
1432 	wccb->last_read_offset = off;
1433 	wccb->last_read_length = len;
1434 
1435 	switch (wccb->data_conn_mode) {
1436 	default:
1437 		abort();
1438 		return -1;
1439 
1440 	case 'f':
1441 		lseek (wccb->data_conn_fd, off, 0);
1442 		break;
1443 
1444 	case 'p':
1445 		wrap_send_data_read (wccb->index_fp, off, len);
1446 		break;
1447 	}
1448 
1449 	wccb->reading_offset = wccb->last_read_offset;
1450 	wccb->reading_length = wccb->last_read_length;
1451 
1452 	if (wccb->have_length == 0) {
1453 		wccb->expect_offset = wccb->reading_offset;
1454 		wccb->expect_length = wccb->reading_length;
1455 	} else {
1456 		wccb->expect_length += len;
1457 	}
1458 
1459 	return wccb->error;
1460 }
1461 
1462 
1463 
1464 
1465 /*
1466  * (Note: this is hoisted from ndml_cstr.c)
1467  *
1468  * Description:
1469  *	Convert strings to/from a canonical strings (CSTR).
1470  *
1471  *	The main reason for this is to eliminate spaces
1472  *	in strings thus making multiple strings easily
1473  *	delimited by white space.
1474  *
1475  *	Canonical strings use the HTTP convention of
1476  *	percent sign followed by two hex digits (%xx).
1477  *	Characters outside the printable ASCII range,
1478  *	space, and percent sign are so converted.
1479  *
1480  *	Both interfaces return the length of the resulting
1481  *	string, -1 if there is an overflow, or -2
1482  *	there is a conversion error.
1483  */
1484 
1485 int
wrap_cstr_from_str(char * src,char * dst,unsigned dst_max)1486 wrap_cstr_from_str (char *src, char *dst, unsigned dst_max)
1487 {
1488 	static char		cstr_to_hex[] = "0123456789ABCDEF";
1489 	unsigned char *		p = (unsigned char *)src;
1490 	unsigned char *		q = (unsigned char *)dst;
1491 	unsigned char *		q_end = q + dst_max - 1;
1492 	int			c;
1493 
1494 	while ((c = *p++) != 0) {
1495 		if (c <= ' ' || c > 0x7E || c == NDMCSTR_WARN) {
1496 			if (q+3 > q_end)
1497 				return -1;
1498 			*q++ = NDMCSTR_WARN;
1499 			*q++ = cstr_to_hex[(c>>4)&0xF];
1500 			*q++ = cstr_to_hex[c&0xF];
1501 		} else {
1502 			if (q+1 > q_end)
1503 				return -1;
1504 			*q++ = c;
1505 		}
1506 	}
1507 	*q = 0;
1508 
1509 	return q - (unsigned char *)dst;
1510 }
1511 
1512 int
wrap_cstr_to_str(char * src,char * dst,unsigned dst_max)1513 wrap_cstr_to_str (char *src, char *dst, unsigned dst_max)
1514 {
1515 	unsigned char *		p = (unsigned char *)src;
1516 	unsigned char *		q = (unsigned char *)dst;
1517 	unsigned char *		q_end = q + dst_max - 1;
1518 	int			c, c1, c2;
1519 
1520 	while ((c = *p++) != 0) {
1521 		if (q+1 > q_end)
1522 			return -1;
1523 		if (c != NDMCSTR_WARN) {
1524 			*q++ = c;
1525 			continue;
1526 		}
1527 		c1 = wrap_cstr_from_hex (p[0]);
1528 		c2 = wrap_cstr_from_hex (p[1]);
1529 
1530 		if (c1 < 0 || c2 < 0) {
1531 			/* busted conversion */
1532 			return -2;
1533 		}
1534 
1535 		c = (c1<<4) + c2;
1536 		*q++ = c;
1537 		p += 2;
1538 	}
1539 	*q = 0;
1540 
1541 	return q - (unsigned char *)dst;
1542 }
1543 
1544 int
wrap_cstr_from_hex(int c)1545 wrap_cstr_from_hex (int c)
1546 {
1547 	if ('0' <= c && c <= '9')
1548 		return c - '0';
1549 	if ('a' <= c && c <= 'f')
1550 		return (c - 'a') + 10;
1551 	if ('A' <= c && c <= 'F')
1552 		return (c - 'A') + 10;
1553 	return -1;
1554 }
1555