2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
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.
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
44 wrap_main (int ac, char *av[], struct wrap_ccb *wccb)
48 rc = wrap_process_args (ac, av, wccb);
52 rc = wrap_main_start_index_file (wccb);
56 rc = wrap_main_start_image_file (wccb);
65 wrap_main_start_index_file (struct wrap_ccb *wccb)
67 char * filename = wccb->I_index_file_name;
73 if (filename[0] == '#') {
74 int fd = atoi (filename+1);
76 if (fd < 2 || fd > 100) {
78 strcpy (wccb->errmsg, "bad -I#N");
81 fp = fdopen (fd, "w");
83 sprintf (wccb->errmsg, "failed fdopen %s", filename);
87 fp = fopen (filename, "w");
89 sprintf (wccb->errmsg, "failed open %s", filename);
100 wrap_main_start_image_file (struct wrap_ccb *wccb)
102 char * filename = wccb->f_file_name;
106 case WRAP_CCB_OP_BACKUP:
107 o_mode = O_CREAT | O_WRONLY;
110 case WRAP_CCB_OP_RECOVER:
111 case WRAP_CCB_OP_RECOVER_FILEHIST:
123 if (strcmp (filename, "-") == 0) {
124 if (wccb->op == WRAP_CCB_OP_BACKUP) {
129 } else if (filename[0] == '#') {
130 fd = atoi (filename+1);
132 if (fd < 2 || fd > 100) {
134 strcpy (wccb->errmsg, "bad -f#N");
138 fd = open (filename, o_mode, 0666);
140 sprintf (wccb->errmsg, "failed open %s", filename);
145 wccb->data_conn_fd = fd;
151 wrap_log (struct wrap_ccb *wccb, char *fmt, ...)
156 if (!wccb->index_fp && wccb->d_debug < 1)
159 sprintf (buf, "%04d ", ++wccb->log_seq_num);
162 vsnprintf (buf+5, sizeof(buf)-5, fmt, ap);
166 wrap_send_log_message (wccb->index_fp, buf);
168 if (wccb->d_debug > 0)
169 fprintf (stderr, "LOG: %s\n", buf);
173 wrap_set_error (struct wrap_ccb *wccb, int error)
184 wrap_set_errno (struct wrap_ccb *wccb)
186 return wrap_set_error (wccb, errno);
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 ...]
199 wrap_process_args (int argc, char *argv[], struct wrap_ccb *wccb)
205 NDMOS_MACRO_ZEROFILL (wccb);
207 wccb->progname = argv[0];
210 strcpy (wccb->errmsg, "too few arguments");
214 while ((c = getopt (argc, argv, "cxtB:d:I:E:f:o:")) != EOF) {
217 op = WRAP_CCB_OP_BACKUP;
221 op = WRAP_CCB_OP_RECOVER_FILEHIST;
225 op = WRAP_CCB_OP_RECOVER;
229 if (wccb->op != WRAP_CCB_OP_NONE) {
230 strcpy (wccb->errmsg, "only one of -c, -x, -t");
237 if (wccb->B_butype) {
238 strcpy (wccb->errmsg, "only one -B allowed");
241 wccb->B_butype = optarg;
245 wccb->d_debug = atoi(optarg);
249 if (wccb->n_env >= WRAP_MAX_ENV) {
250 strcpy (wccb->errmsg, "-E overflow");
253 p = strchr (optarg, '=');
259 wccb->env[wccb->n_env].name = optarg;
260 wccb->env[wccb->n_env].value = p;
265 if (wccb->f_file_name) {
266 strcpy (wccb->errmsg, "only one -f allowed");
269 wccb->f_file_name = optarg;
273 if (wccb->I_index_file_name) {
274 strcpy (wccb->errmsg, "only one -I allowed");
277 wccb->I_index_file_name = optarg;
281 if (wccb->n_o_option >= WRAP_MAX_O_OPTION) {
282 strcpy (wccb->errmsg, "-o overflow");
285 wccb->o_option[wccb->n_o_option] = optarg;
290 strcpy (wccb->errmsg, "unknown option");
297 abort(); /* just can't happen */
299 case WRAP_CCB_OP_NONE:
300 strcpy (wccb->errmsg, "one of -c, -x, or -t required");
303 case WRAP_CCB_OP_BACKUP:
305 strcpy (wccb->errmsg, "extra args not allowed for -c");
310 case WRAP_CCB_OP_RECOVER:
311 case WRAP_CCB_OP_RECOVER_FILEHIST:
315 for (c = optind; c+2 < argc; c += 3) {
319 sprintf (wccb->errmsg, "malformed fhinfo %s", p);
323 if (wccb->n_file >= WRAP_MAX_FILE) {
324 strcpy (wccb->errmsg, "file table overflow");
328 if (strcmp (p, "@-") == 0) {
329 wccb->file[wccb->n_file].fhinfo = WRAP_INVALID_FHINFO;
331 wccb->file[wccb->n_file].fhinfo =
332 NDMOS_API_STRTOLL (p+1, &p, 0);
334 sprintf(wccb->errmsg,"malformed fhinfo %s",p);
339 wccb->file[wccb->n_file].original_name = argv[c];
340 wccb->file[wccb->n_file].save_to_name = argv[c+2];
346 strcpy (wccb->errmsg, "superfluous args at end");
350 p = wrap_find_env (wccb, "HIST");
354 p = wrap_find_env (wccb, "HIST_TYPE");
363 wccb->hist_enable = 'y';
367 wccb->hist_enable = 'd';
371 wccb->hist_enable = 'f';
380 p = wrap_find_env (wccb, "DIRECT");
383 wccb->direct_enable = 1;
387 p = wrap_find_env (wccb, "FILESYSTEM");
389 p = wrap_find_env (wccb, "PREFIX");
393 wccb->backup_root = p;
399 wrap_find_env (struct wrap_ccb *wccb, char *name)
403 for (i = 0; i < wccb->n_env; i++) {
404 if (strcmp (wccb->env[i].name, name) == 0)
405 return wccb->env[i].value;
418 wrap_cmd_add_with_escapes (char *cmd, char *word, char *special)
420 char * cmd_lim = &cmd[WRAP_MAX_COMMAND-3];
426 if (p != cmd) *p++ = ' ';
428 while ((c = *word++) != 0) {
430 return -1; /* overflow */
431 if (c == '\\' || strchr (special, c))
441 wrap_cmd_add_with_sh_escapes (char *cmd, char *word)
443 return wrap_cmd_add_with_escapes (cmd, word, " \t`'\"*?[]$");
447 wrap_cmd_add_allow_file_wildcards (char *cmd, char *word)
449 return wrap_cmd_add_with_escapes (cmd, word, " \t`'\"$");
455 wrap_pipe_fork_exec (char *cmd, int fdmap[3])
463 for (i = 0; i < 3; i++) {
469 for (i = 0; i < 3; i++) {
471 child_fdmap[i] = fdmap[i];
475 case WRAP_FDMAP_DEV_NULL:
477 nullfd = open ("/dev/null", 2);
482 child_fdmap[i] = nullfd;
485 case WRAP_FDMAP_INPUT_PIPE:
486 rc = pipe (pipes[i]);
490 child_fdmap[i] = pipes[i][0];
493 case WRAP_FDMAP_OUTPUT_PIPE:
494 rc = pipe (pipes[i]);
498 child_fdmap[i] = pipes[i][1];
513 dup2 (child_fdmap[2], 2);
514 dup2 (child_fdmap[1], 1);
515 dup2 (child_fdmap[0], 0);
517 for (rc = 3; rc < 100; rc++) close(rc);
519 execl ("/bin/sh", "sh", "-c", cmd, NULL);
521 fprintf (stderr, "EXEC FAILED %s\n", cmd);
528 for (i = 0; i < 3; i++) {
533 case WRAP_FDMAP_DEV_NULL:
536 case WRAP_FDMAP_INPUT_PIPE:
538 fdmap[i] = pipes[i][1];
541 case WRAP_FDMAP_OUTPUT_PIPE:
543 fdmap[i] = pipes[i][0];
557 for (i = 0; i < 3; i++) {
558 if (pipes[i][0] >= 0)
560 if (pipes[i][1] >= 0)
571 wrap_parse_msg (char *buf, struct wrap_msg_buf *wmsg)
582 if (c1 == 'L' && c2 == 'x') { /* log_message */
583 return wrap_parse_log_message_msg (buf, wmsg);
586 if (c1 == 'H' && c2 == 'F') { /* add_file */
587 return wrap_parse_add_file_msg (buf, wmsg);
590 if (c1 == 'H' && c2 == 'D') { /* add_dirent */
591 return wrap_parse_add_dirent_msg (buf, wmsg);
594 if (c1 == 'H' && c2 == 'N') { /* add_node */
595 return wrap_parse_add_node_msg (buf, wmsg);
598 if (c1 == 'D' && c2 == 'E') { /* add_env */
599 return wrap_parse_add_env_msg (buf, wmsg);
602 if (c1 == 'D' && c2 == 'R') { /* data_read */
603 return wrap_parse_data_read_msg (buf, wmsg);
610 wrap_parse_log_message_msg (char *buf, struct wrap_msg_buf *wmsg)
612 struct wrap_log_message *res = &wmsg->body.log_message;
616 wmsg->msg_type = WRAP_MSGTYPE_LOG_MESSAGE;
618 while (*scan && *scan == ' ')
621 rc = wrap_cstr_to_str (scan, res->message, sizeof res->message);
622 if (rc < 0) return -2;
628 wrap_send_log_message (FILE *fp, char *message)
630 struct wrap_msg_buf wmsg;
631 struct wrap_log_message *res = &wmsg.body.log_message;
635 wrap_cstr_from_str (message, res->message, sizeof res->message);
636 fprintf (fp, "Lx %s\n", res->message);
642 wrap_parse_add_file_msg (char *buf, struct wrap_msg_buf *wmsg)
644 struct wrap_add_file * res = &wmsg->body.add_file;
649 wmsg->msg_type = WRAP_MSGTYPE_ADD_FILE;
651 res->fstat.valid = 0;
652 res->fhinfo = WRAP_INVALID_FHINFO;
654 while (*scan && *scan == ' ')
660 while (*scan && *scan != ' ')
665 rc = wrap_cstr_to_str (p, res->path, sizeof res->path);
668 rc = wrap_cstr_to_str (p, res->path, sizeof res->path);
670 if (rc < 0) return -2;
680 res->fhinfo = NDMOS_API_STRTOLL (p, &scan, 0);
684 rc = wrap_parse_fstat_subr(&scan, &res->fstat);
690 if (*scan != ' ' && *scan != 0) {
700 wrap_send_add_file (FILE *fp, char *path, unsigned long long fhinfo,
701 struct wrap_fstat *fstat)
703 struct wrap_msg_buf wmsg;
704 struct wrap_add_file * res = &wmsg.body.add_file;
708 wrap_cstr_from_str (path, res->path, sizeof res->path);
709 fprintf (fp, "HF %s", res->path);
711 if (fhinfo != WRAP_INVALID_FHINFO)
712 fprintf (fp, " @%llu", fhinfo);
714 wrap_send_fstat_subr (fp, fstat);
722 wrap_parse_add_dirent_msg (char *buf, struct wrap_msg_buf *wmsg)
724 struct wrap_add_dirent *res = &wmsg->body.add_dirent;
729 wmsg->msg_type = WRAP_MSGTYPE_ADD_DIRENT;
731 res->fhinfo = WRAP_INVALID_FHINFO;
733 while (*scan && *scan == ' ')
738 res->dir_fileno = NDMOS_API_STRTOLL (scan, &scan, 0);
742 while (*scan == ' ') scan++;
748 while (*scan && *scan != ' ')
753 rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
756 rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
758 if (rc < 0) return -2;
760 res->fileno = NDMOS_API_STRTOLL (scan, &scan, 0);
761 if (*scan != ' ' && *scan != 0)
764 while (*scan == ' ') scan++;
767 res->fhinfo = NDMOS_API_STRTOLL(scan+1, &scan, 0);
770 if (*scan != ' ' && *scan != 0)
773 while (*scan == ' ') scan++;
782 wrap_send_add_dirent (FILE *fp, char *name, unsigned long long fhinfo,
783 unsigned long long dir_fileno, unsigned long long fileno)
785 struct wrap_msg_buf wmsg;
786 struct wrap_add_dirent *res = &wmsg.body.add_dirent;
790 wrap_cstr_from_str (name, res->name, sizeof res->name);
791 fprintf (fp, "HD %llu %s %llu", dir_fileno, res->name, fileno);
793 if (fhinfo != WRAP_INVALID_FHINFO)
794 fprintf (fp, " @%llu", fhinfo);
803 wrap_parse_add_node_msg (char *buf, struct wrap_msg_buf *wmsg)
805 struct wrap_add_node * res = &wmsg->body.add_node;
810 wmsg->msg_type = WRAP_MSGTYPE_ADD_NODE;
812 res->fstat.valid = 0;
813 res->fhinfo = WRAP_INVALID_FHINFO;
815 while (*scan && *scan == ' ')
820 res->fstat.fileno = NDMOS_API_STRTOLL (scan, &scan, 0);
821 if (*scan != ' ' && *scan != 0)
824 res->fstat.valid |= WRAP_FSTAT_VALID_FILENO;
834 res->fhinfo = NDMOS_API_STRTOLL (p, &scan, 0);
838 rc = wrap_parse_fstat_subr(&scan, &res->fstat);
844 if (*scan != ' ' && *scan != 0) {
850 if ( (res->fstat.valid & WRAP_FSTAT_VALID_FILENO) == 0)
857 wrap_send_add_node (FILE *fp, unsigned long long fhinfo,
858 struct wrap_fstat *fstat)
860 unsigned long save_valid;
864 if (fstat->valid & WRAP_FSTAT_VALID_FILENO) {
865 fprintf (fp, "HN %llu", fstat->fileno);
867 fprintf (fp, "HN 0000000000");
870 if (fhinfo != WRAP_INVALID_FHINFO)
871 fprintf (fp, " @%llu", fhinfo);
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;
886 wrap_parse_fstat_subr (char **scanp, struct wrap_fstat *fstat)
888 char * scan = *scanp;
890 unsigned long valid = 0;
895 valid = WRAP_FSTAT_VALID_SIZE;
896 fstat->size = NDMOS_API_STRTOLL (p, &scan, 0);
899 case 'i': /* fileno (inum) */
900 valid = WRAP_FSTAT_VALID_FILENO;
901 fstat->fileno = NDMOS_API_STRTOLL (p, &scan, 0);
904 case 'm': /* mode low twelve bits */
905 valid = WRAP_FSTAT_VALID_MODE;
906 fstat->mode = strtol (p, &scan, 8);
909 case 'l': /* link count */
910 valid = WRAP_FSTAT_VALID_LINKS;
911 fstat->links = strtol (p, &scan, 0);
915 valid = WRAP_FSTAT_VALID_UID;
916 fstat->uid = strtol (p, &scan, 0);
920 valid = WRAP_FSTAT_VALID_GID;
921 fstat->gid = strtol (p, &scan, 0);
924 case 't': /* one of the times */
927 case 'm': /* mtime */
928 valid = WRAP_FSTAT_VALID_MTIME;
929 fstat->mtime = strtol (p, &scan, 0);
932 case 'a': /* atime */
933 valid = WRAP_FSTAT_VALID_ATIME;
934 fstat->atime = strtol (p, &scan, 0);
937 case 'c': /* ctime */
938 valid = WRAP_FSTAT_VALID_CTIME;
939 fstat->ctime = strtol (p, &scan, 0);
947 case 'f': /* ftype (file type) */
948 valid = WRAP_FSTAT_VALID_FTYPE;
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;
960 fstat->ftype = WRAP_FTYPE_INVALID;
970 if (*scan != ' ' && *scan != 0)
973 fstat->valid |= valid;
980 wrap_send_fstat_subr (FILE *fp, struct wrap_fstat *fstat)
984 if (fstat->valid & WRAP_FSTAT_VALID_FTYPE) {
987 switch (fstat->ftype) {
989 case WRAP_FTYPE_INVALID:
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;
1004 fprintf (fp, " f%c", c);
1010 if (fstat->valid & WRAP_FSTAT_VALID_MODE) {
1011 fprintf (fp, " m%04o", fstat->mode);
1014 if (fstat->valid & WRAP_FSTAT_VALID_LINKS) {
1015 fprintf (fp, " l%lu", fstat->links);
1018 if (fstat->valid & WRAP_FSTAT_VALID_SIZE) {
1019 fprintf (fp, " s%llu", fstat->size);
1022 if (fstat->valid & WRAP_FSTAT_VALID_UID) {
1023 fprintf (fp, " u%lu", fstat->uid);
1026 if (fstat->valid & WRAP_FSTAT_VALID_GID) {
1027 fprintf (fp, " g%lu", fstat->gid);
1030 if (fstat->valid & WRAP_FSTAT_VALID_ATIME) {
1031 fprintf (fp, " ta%lu", fstat->atime);
1034 if (fstat->valid & WRAP_FSTAT_VALID_MTIME) {
1035 fprintf (fp, " tm%lu", fstat->mtime);
1038 if (fstat->valid & WRAP_FSTAT_VALID_CTIME) {
1039 fprintf (fp, " tc%lu", fstat->ctime);
1042 if (fstat->valid & WRAP_FSTAT_VALID_FILENO) {
1043 fprintf (fp, " i%llu", fstat->fileno);
1050 wrap_parse_add_env_msg (char *buf, struct wrap_msg_buf *wmsg)
1052 struct wrap_add_env * res = &wmsg->body.add_env;
1053 char * scan = buf+3;
1057 wmsg->msg_type = WRAP_MSGTYPE_ADD_ENV;
1059 while (*scan && *scan == ' ')
1065 while (*scan && *scan != ' ')
1070 rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
1073 rc = wrap_cstr_to_str (p, res->name, sizeof res->name);
1075 if (rc < 0) return -2;
1077 while (*scan && *scan == ' ')
1081 while (*scan && *scan != ' ')
1086 rc = wrap_cstr_to_str (p, res->value, sizeof res->value);
1089 rc = wrap_cstr_to_str (p, res->value, sizeof res->value);
1091 if (rc < 0) return -2;
1097 wrap_send_add_env (FILE *fp, char *name, char *value)
1099 struct wrap_msg_buf wmsg;
1100 struct wrap_add_env * res = &wmsg.body.add_env;
1104 wrap_cstr_from_str (name, res->name, sizeof res->name);
1105 wrap_cstr_from_str (value, res->value, sizeof res->value);
1107 fprintf (fp, "DE %s %s\n", res->name, res->value);
1113 wrap_parse_data_read_msg (char *buf, struct wrap_msg_buf *wmsg)
1115 struct wrap_data_read * res = &wmsg->body.data_read;
1116 char * scan = buf+3;
1118 wmsg->msg_type = WRAP_MSGTYPE_DATA_READ;
1120 while (*scan && *scan == ' ')
1125 res->offset = NDMOS_API_STRTOLL (scan, &scan, 0);
1129 while (*scan && *scan != ' ')
1135 res->length = NDMOS_API_STRTOLL (scan, &scan, 0);
1137 /* tolerate trailing white */
1138 while (*scan && *scan != ' ')
1148 wrap_send_data_read (FILE *fp,
1149 unsigned long long offset, unsigned long long length)
1154 fprintf (fp, "DR %lld %lld\n", (long long) offset, (long long)length);
1161 wrap_parse_data_stats_msg (char *buf, struct wrap_msg_buf *wmsg)
1164 struct wrap_data_stats *res = &wmsg->body.data_stats;
1165 char * scan = buf+3;
1167 wmsg->msg_type = WRAP_MSGTYPE_DATA_STATS;
1173 wrap_send_data_stats (FILE *fp)
1177 fprintf (fp, "DS ...\n");
1188 ****************************************************************
1192 wrap_reco_align_to_wanted (struct wrap_ccb *wccb)
1194 unsigned long long distance;
1195 unsigned long unwanted_length;
1199 * If there is an error, we're toast.
1205 * If we're aligned, we're done.
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);
1216 * If we have a portion we don't want, consume it now
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) {
1223 * We have some of what we want.
1224 * Consume (discard) unwanted part.
1226 unwanted_length = distance;
1228 unwanted_length = wccb->have_length;
1231 unwanted_length = wccb->have_length;
1233 wrap_reco_consume (wccb, unwanted_length);
1237 if (wccb->expect_length > 0) {
1238 /* Incoming, but we don't have it yet. */
1239 wrap_reco_receive (wccb);
1244 * We don't have anything. We don't expect anything.
1245 * Time to issue an NDMP_DATA_NOTIFY_READ via this wrapper.
1248 wrap_reco_issue_read (wccb);
1254 wrap_reco_receive (struct wrap_ccb *wccb)
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;
1264 if (wccb->have_length == 0) {
1265 wccb->have = wccb->iobuf;
1266 have_end = wccb->have + wccb->have_length;
1269 if (n_read < 512 && wccb->have != wccb->iobuf) {
1270 /* Not much room at have_end. Front of iobuf available. */
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;
1278 if (n_read > wccb->reading_length)
1279 n_read = wccb->reading_length;
1287 rc = read (wccb->data_conn_fd, have_end, n_read);
1289 wccb->have_length += rc;
1290 wccb->reading_offset += rc;
1291 wccb->reading_length -= rc;
1295 strcpy (wccb->errmsg, "EOF on data connection");
1296 wrap_set_error (wccb, -1);
1298 sprintf (wccb->errmsg, "errno %d on data connection",
1300 wrap_set_errno (wccb);
1308 wrap_reco_consume (struct wrap_ccb *wccb, unsigned long length)
1310 assert (wccb->have_length >= length);
1312 wccb->have_offset += length;
1313 wccb->have_length -= length;
1314 wccb->expect_offset += length;
1315 wccb->expect_length -= length;
1316 wccb->have += length;
1318 if (wccb->expect_length == 0) {
1319 assert (wccb->have_length == 0);
1320 wccb->expect_offset = -1ull;
1327 wrap_reco_must_have (struct wrap_ccb *wccb, unsigned long length)
1329 if (wccb->want_length < length)
1330 wccb->want_length = length;
1332 wrap_reco_align_to_wanted (wccb);
1334 while (wccb->have_length < length && !wccb->error) {
1335 wrap_reco_align_to_wanted (wccb); /* triggers issue_read() */
1336 wrap_reco_receive (wccb);
1339 if (wccb->have_length >= 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)
1354 wccb->want_offset = want_offset;
1355 wccb->want_length = want_length;
1357 return wrap_reco_must_have (wccb, must_have_length);
1361 wrap_reco_pass (struct wrap_ccb *wccb, int write_fd,
1362 unsigned long long length, unsigned write_bsize)
1367 while (length > 0) {
1375 if (wccb->have_length < cnt) {
1376 wrap_reco_must_have (wccb, cnt);
1379 rc = write (write_fd, wccb->have, cnt);
1382 wrap_reco_consume (wccb, cnt);
1389 wrap_reco_issue_read (struct wrap_ccb *wccb)
1391 unsigned long long off;
1392 unsigned long long len;
1394 assert (wccb->reading_length == 0);
1396 if (wccb->data_conn_mode == 0) {
1400 rc = fstat (wccb->data_conn_fd, &st);
1402 sprintf (wccb->errmsg, "Can't fstat() data conn rc=%d",
1404 return wrap_set_errno (wccb);
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);
1413 } else if (S_ISREG(st.st_mode)) {
1414 wccb->data_conn_mode = 'f';
1416 sprintf (wccb->errmsg, "Unsupported data_conn type %o",
1418 return wrap_set_error (wccb, -3);
1422 off = wccb->want_offset;
1423 len = wccb->want_length;
1425 off += wccb->have_length;
1426 len -= wccb->have_length;
1432 wccb->last_read_offset = off;
1433 wccb->last_read_length = len;
1435 switch (wccb->data_conn_mode) {
1441 lseek (wccb->data_conn_fd, off, 0);
1445 wrap_send_data_read (wccb->index_fp, off, len);
1449 wccb->reading_offset = wccb->last_read_offset;
1450 wccb->reading_length = wccb->last_read_length;
1452 if (wccb->have_length == 0) {
1453 wccb->expect_offset = wccb->reading_offset;
1454 wccb->expect_length = wccb->reading_length;
1456 wccb->expect_length += len;
1466 * (Note: this is hoisted from ndml_cstr.c)
1469 * Convert strings to/from a canonical strings (CSTR).
1471 * The main reason for this is to eliminate spaces
1472 * in strings thus making multiple strings easily
1473 * delimited by white space.
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.
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.
1486 wrap_cstr_from_str (char *src, char *dst, unsigned dst_max)
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;
1494 while ((c = *p++) != 0) {
1495 if (c <= ' ' || c > 0x7E || c == NDMCSTR_WARN) {
1498 *q++ = NDMCSTR_WARN;
1499 *q++ = cstr_to_hex[(c>>4)&0xF];
1500 *q++ = cstr_to_hex[c&0xF];
1509 return q - (unsigned char *)dst;
1513 wrap_cstr_to_str (char *src, char *dst, unsigned dst_max)
1515 unsigned char * p = (unsigned char *)src;
1516 unsigned char * q = (unsigned char *)dst;
1517 unsigned char * q_end = q + dst_max - 1;
1520 while ((c = *p++) != 0) {
1523 if (c != NDMCSTR_WARN) {
1527 c1 = wrap_cstr_from_hex (p[0]);
1528 c2 = wrap_cstr_from_hex (p[1]);
1530 if (c1 < 0 || c2 < 0) {
1531 /* busted conversion */
1541 return q - (unsigned char *)dst;
1545 wrap_cstr_from_hex (int c)
1547 if ('0' <= c && c <= '9')
1549 if ('a' <= c && c <= 'f')
1550 return (c - 'a') + 10;
1551 if ('A' <= c && c <= 'F')
1552 return (c - 'A') + 10;