73 if (log_file != NULL) 74 err_set_log(log_file); 75 76 if (argc <= 1) 77 { 78 if (piece_dir != NULL) 79 status = read_piece(NULL); 80 } 81 else 82 { 83 while (*++argv != NULL) 84 status |= read_piece(*argv); 85 } 86 87 if (base_dir != NULL) 88 apply_complete(); 89 90 return status; 91 } 92 93 94/* 95 * Construct the file name of a piece of a delta. 96 */ 97#define mk_piece_name(fn,d,p,n) \ 98 sprintf((fn), "%s/%s+%d-%d", piece_dir, (d), (p), (n)) 99 100/* 101 * Construct the file name of an assembled delta. 102 */ 103#define mk_delta_name(fn,d) \ 104 sprintf((fn), "%s/%s", delta_dir, (d)) 105 106/* 107 * If the next required delta is now present, let ctm lunch on it and any 108 * contiguous deltas. 109 */ 110void 111apply_complete() 112 { 113 int i, dn; 114 FILE *fp, *ctm; 115 struct stat sb; 116 char class[20]; 117 char delta[30]; 118 char fname[1000]; 119 char buf[2000]; 120 char junk[2]; 121 char here[1000]; 122 123 sprintf(fname, "%s/%s", base_dir, CTM_STATUS); 124 if ((fp = fopen(fname, "r")) == NULL) 125 return; 126 127 i = fscanf(fp, "%s %d %c", class, &dn, junk); 128 fclose(fp); 129 if (i != 2) 130 return; 131 132 /* 133 * We might need to convert the delta filename to an absolute pathname. 134 */ 135 here[0] = '\0'; 136 if (delta_dir[0] != '/') 137 { 138 getcwd(here, sizeof(here)-1); 139 i = strlen(here) - 1; 140 if (i >= 0 && here[i] != '/') 141 { 142 here[++i] = '/'; 143 here[++i] = '\0'; 144 } 145 } 146 147 /* 148 * Keep applying deltas until we run out or something bad happens. 149 */ 150 for (;;) 151 { 152 sprintf(delta, "%s.%04d.gz", class, ++dn); 153 mk_delta_name(fname, delta); 154 155 if (stat(fname, &sb) < 0) 156 return; 157 158 sprintf(buf, "(cd %s && ctm %s%s) 2>&1", base_dir, here, fname); 159 if ((ctm = popen(buf, "r")) == NULL) 160 { 161 err("ctm failed to apply %s", delta); 162 return; 163 } 164 165 while (fgets(buf, sizeof(buf), ctm) != NULL) 166 { 167 i = strlen(buf) - 1; 168 if (i >= 0 && buf[i] == '\n') 169 buf[i] = '\0'; 170 err("ctm: %s", buf); 171 } 172 173 if (pclose(ctm) != 0) 174 { 175 err("ctm failed to apply %s", delta); 176 return; 177 } 178 179 if (delete_after) 180 unlink(fname); 181 182 err("%s applied%s", delta, delete_after ? " and deleted" : ""); 183 } 184 } 185 186 187/* 188 * This cheap plastic checksum effectively rotates our checksum-so-far 189 * left one, then adds the character. We only want 16 bits of it, and 190 * don't care what happens to the rest. It ain't much, but it's small. 191 */ 192#define add_ck(sum,x) \ 193 ((sum) += ((x)&0xff) + (sum) + (((sum)&0x8000) ? 1 : 0)) 194 195 196/* 197 * Decode the data between BEGIN and END, and stash it in the staging area. 198 * Multiple pieces can be present in a single file, bracketed by BEGIN/END. 199 * If we have all pieces of a delta, combine them. Returns 0 on success, 200 * and 1 for any sort of failure. 201 */ 202int 203read_piece(char *input_file) 204 { 205 int status = 0;
|
254 continue; 255 } 256 257 /* 258 * We are decoding. Stop if we see the end flag. 259 */ 260 if (sscanf(line, "CTM_MAIL END %d %c", &claimed_cksum, junk) == 1) 261 { 262 int e; 263 264 decoding = 0; 265 266 fflush(ofp); 267 e = ferror(ofp); 268 fclose(ofp); 269 270 if (e) 271 err("error writing %s", pname); 272 273 if (cksum != claimed_cksum) 274 err("checksum: read %d, calculated %d", claimed_cksum, cksum); 275 276 if (e || cksum != claimed_cksum) 277 { 278 err("%s %d/%d discarded", delta, pce, npieces); 279 unlink(pname); 280 status++; 281 continue; 282 } 283 284 err("%s %d/%d stored", delta, pce, npieces); 285 286 if (!combine_if_complete(delta, pce, npieces)) 287 status++; 288 continue; 289 } 290 291 /* 292 * Must be a line of encoded data. Decode it, sum it, and save it. 293 */ 294 n = decode_line(line, out_buf); 295 if (n < 0) 296 { 297 err("line %d: illegal character: '%c'", line_no, line[-n]); 298 err("%s %d/%d discarded", delta, pce, npieces); 299 300 fclose(ofp); 301 unlink(pname); 302 303 status++; 304 decoding = 0; 305 continue; 306 } 307 308 for (i = 0; i < n; i++) 309 add_ck(cksum, out_buf[i]); 310 311 fwrite(out_buf, sizeof(char), n, ofp); 312 } 313 314 if (decoding) 315 { 316 err("truncated file"); 317 err("%s %d/%d discarded", delta, pce, npieces); 318 319 fclose(ofp); 320 unlink(pname); 321 322 status++; 323 } 324 325 if (ferror(ifp)) 326 { 327 err("error reading %s", input_file == NULL ? "stdin" : input_file); 328 status++; 329 } 330 331 if (input_file != NULL) 332 fclose(ifp); 333 334 return (status != 0); 335 } 336 337 338/* 339 * Put the pieces together to form a delta, if they are all present. 340 * Returns 1 on success (even if we didn't do anything), and 0 on failure. 341 */ 342int 343combine_if_complete(char *delta, int pce, int npieces) 344 { 345 int i; 346 FILE *dfp, *pfp; 347 int c; 348 struct stat sb; 349 char pname[1000]; 350 char dname[1000]; 351 352 /* 353 * All here? 354 */ 355 for (i = 1; i <= npieces; i++) 356 { 357 if (i == pce) 358 continue; 359 mk_piece_name(pname, delta, i, npieces); 360 if (stat(pname, &sb) < 0) 361 return 1; 362 } 363 364 mk_delta_name(dname, delta); 365 366 /* 367 * We can probably just rename() it in to place if it is a small delta. 368 */ 369 if (npieces == 1) 370 { 371 mk_piece_name(pname, delta, 1, 1); 372 if (rename(pname, dname) == 0) 373 { 374 err("%s complete", delta); 375 return 1; 376 } 377 } 378 379 if ((dfp = fopen(dname, "w")) == NULL) 380 { 381 err("cannot open '%s' for writing", dname); 382 return 0; 383 } 384 385 /* 386 * Ok, the hard way. Reconstruct the delta by reading each piece in order. 387 */ 388 for (i = 1; i <= npieces; i++) 389 { 390 mk_piece_name(pname, delta, i, npieces); 391 if ((pfp = fopen(pname, "r")) == NULL) 392 { 393 err("cannot open '%s' for reading", pname); 394 fclose(dfp); 395 unlink(dname); 396 return 0; 397 } 398 while ((c = getc(pfp)) != EOF) 399 putc(c, dfp); 400 fclose(pfp); 401 } 402 fflush(dfp); 403 if (ferror(dfp)) 404 { 405 err("error writing '%s'", dname); 406 fclose(dfp); 407 unlink(dname); 408 return 0; 409 } 410 fclose(dfp); 411 412 /* 413 * Throw the pieces away. 414 */ 415 for (i = 1; i <= npieces; i++) 416 { 417 mk_piece_name(pname, delta, i, npieces); 418 unlink(pname); 419 } 420 421 err("%s complete", delta); 422 return 1; 423 } 424 425 426/* 427 * MIME BASE64 decode table. 428 */ 429static unsigned char from_b64[0x80] = 430 { 431 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 432 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 433 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 434 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 435 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 436 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 437 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 438 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 439 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 440 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 441 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 442 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 443 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 444 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 445 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 446 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff 447 }; 448 449 450/* 451 * Decode a line of ASCII into binary. Returns the number of bytes in 452 * the output buffer, or < 0 on indigestable input. Error output is 453 * the negative of the index of the inedible character. 454 */ 455int 456decode_line(char *line, char *out_buf) 457 { 458 unsigned char *ip = (unsigned char *)line; 459 unsigned char *op = (unsigned char *)out_buf; 460 unsigned long bits; 461 unsigned x; 462 463 for (;;) 464 { 465 if (*ip >= 0x80 || (x = from_b64[*ip]) >= 0x40) 466 break; 467 bits = x << 18; 468 ip++; 469 if (*ip < 0x80 && (x = from_b64[*ip]) < 0x40) 470 { 471 bits |= x << 12; 472 *op++ = bits >> 16; 473 ip++; 474 if (*ip < 0x80 && (x = from_b64[*ip]) < 0x40) 475 { 476 bits |= x << 6; 477 *op++ = bits >> 8; 478 ip++; 479 if (*ip < 0x80 && (x = from_b64[*ip]) < 0x40) 480 { 481 bits |= x; 482 *op++ = bits; 483 ip++; 484 } 485 } 486 } 487 } 488 489 if (*ip == '\0' || *ip == '\n') 490 return op - (unsigned char *)out_buf; 491 else 492 return -(ip - (unsigned char *)line); 493 }
|