1 /* 2 * Copyright (c) 1999-2002, 2004, 2006 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 * Contributed by Exactis.com, Inc. 10 * 11 */ 12 13 #pragma ident "%Z%%M% %I% %E% SMI" 14 15 /* 16 ** This is in transition. Changed from the original bf_torek.c code 17 ** to use sm_io function calls directly rather than through stdio 18 ** translation layer. Will be made a built-in file type of libsm 19 ** next (once safeopen() linkable from libsm). 20 */ 21 22 #include <sm/gen.h> 23 SM_RCSID("@(#)$Id: bf.c,v 8.62 2006/03/31 18:45:56 ca Exp $") 24 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <sys/uio.h> 28 #include <fcntl.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <errno.h> 33 #include "sendmail.h" 34 #include "bf.h" 35 36 #include <syslog.h> 37 38 /* bf io functions */ 39 static ssize_t sm_bfread __P((SM_FILE_T *, char *, size_t)); 40 static ssize_t sm_bfwrite __P((SM_FILE_T *, const char *, size_t)); 41 static off_t sm_bfseek __P((SM_FILE_T *, off_t, int)); 42 static int sm_bfclose __P((SM_FILE_T *)); 43 static int sm_bfcommit __P((SM_FILE_T *)); 44 static int sm_bftruncate __P((SM_FILE_T *)); 45 46 static int sm_bfopen __P((SM_FILE_T *, const void *, int, const void *)); 47 static int sm_bfsetinfo __P((SM_FILE_T *, int , void *)); 48 static int sm_bfgetinfo __P((SM_FILE_T *, int , void *)); 49 50 /* 51 ** Data structure for storing information about each buffered file 52 ** (Originally in sendmail/bf_torek.h for the curious.) 53 */ 54 55 struct bf 56 { 57 bool bf_committed; /* Has this buffered file been committed? */ 58 bool bf_ondisk; /* On disk: committed or buffer overflow */ 59 long bf_flags; 60 int bf_disk_fd; /* If on disk, associated file descriptor */ 61 char *bf_buf; /* Memory buffer */ 62 int bf_bufsize; /* Length of above buffer */ 63 int bf_buffilled; /* Bytes of buffer actually filled */ 64 char *bf_filename; /* Name of buffered file, if ever committed */ 65 MODE_T bf_filemode; /* Mode of buffered file, if ever committed */ 66 off_t bf_offset; /* Currect file offset */ 67 int bf_size; /* Total current size of file */ 68 }; 69 70 #ifdef BF_STANDALONE 71 # define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode) 72 #else /* BF_STANDALONE */ 73 # define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff) 74 #endif /* BF_STANDALONE */ 75 76 struct bf_info 77 { 78 char *bi_filename; 79 MODE_T bi_fmode; 80 size_t bi_bsize; 81 long bi_flags; 82 }; 83 84 /* 85 ** SM_BFOPEN -- the "base" open function called by sm_io_open() for the 86 ** internal, file-type-specific info setup. 87 ** 88 ** Parameters: 89 ** fp -- file pointer being filled-in for file being open'd 90 ** info -- information about file being opened 91 ** flags -- ignored 92 ** rpool -- ignored (currently) 93 ** 94 ** Returns: 95 ** Failure: -1 and sets errno 96 ** Success: 0 (zero) 97 */ 98 99 static int 100 sm_bfopen(fp, info, flags, rpool) 101 SM_FILE_T *fp; 102 const void *info; 103 int flags; 104 const void *rpool; 105 { 106 char *filename; 107 MODE_T fmode; 108 size_t bsize; 109 long sflags; 110 struct bf *bfp; 111 int l; 112 struct stat st; 113 114 filename = ((struct bf_info *) info)->bi_filename; 115 fmode = ((struct bf_info *) info)->bi_fmode; 116 bsize = ((struct bf_info *) info)->bi_bsize; 117 sflags = ((struct bf_info *) info)->bi_flags; 118 119 /* Sanity checks */ 120 if (*filename == '\0') 121 { 122 /* Empty filename string */ 123 errno = ENOENT; 124 return -1; 125 } 126 if (stat(filename, &st) == 0) 127 { 128 /* File already exists on disk */ 129 errno = EEXIST; 130 return -1; 131 } 132 133 /* Allocate memory */ 134 bfp = (struct bf *) sm_malloc(sizeof(struct bf)); 135 if (bfp == NULL) 136 { 137 errno = ENOMEM; 138 return -1; 139 } 140 141 /* Assign data buffer */ 142 /* A zero bsize is valid, just don't allocate memory */ 143 if (bsize > 0) 144 { 145 bfp->bf_buf = (char *) sm_malloc(bsize); 146 if (bfp->bf_buf == NULL) 147 { 148 bfp->bf_bufsize = 0; 149 sm_free(bfp); 150 errno = ENOMEM; 151 return -1; 152 } 153 } 154 else 155 bfp->bf_buf = NULL; 156 157 /* Nearly home free, just set all the parameters now */ 158 bfp->bf_committed = false; 159 bfp->bf_ondisk = false; 160 bfp->bf_flags = sflags; 161 bfp->bf_bufsize = bsize; 162 bfp->bf_buffilled = 0; 163 l = strlen(filename) + 1; 164 bfp->bf_filename = (char *) sm_malloc(l); 165 if (bfp->bf_filename == NULL) 166 { 167 if (bfp->bf_buf != NULL) 168 sm_free(bfp->bf_buf); 169 sm_free(bfp); 170 errno = ENOMEM; 171 return -1; 172 } 173 (void) sm_strlcpy(bfp->bf_filename, filename, l); 174 bfp->bf_filemode = fmode; 175 bfp->bf_offset = 0; 176 bfp->bf_size = 0; 177 bfp->bf_disk_fd = -1; 178 fp->f_cookie = bfp; 179 180 if (tTd(58, 8)) 181 sm_dprintf("sm_bfopen(%s)\n", filename); 182 183 return 0; 184 } 185 186 /* 187 ** BFOPEN -- create a new buffered file 188 ** 189 ** Parameters: 190 ** filename -- the file's name 191 ** fmode -- what mode the file should be created as 192 ** bsize -- amount of buffer space to allocate (may be 0) 193 ** flags -- if running under sendmail, passed directly to safeopen 194 ** 195 ** Returns: 196 ** a SM_FILE_T * which may then be used with stdio functions, 197 ** or NULL on failure. SM_FILE_T * is opened for writing 198 ** "SM_IO_WHAT_VECTORS"). 199 ** 200 ** Side Effects: 201 ** none. 202 ** 203 ** Sets errno: 204 ** any value of errno specified by sm_io_setinfo_type() 205 ** any value of errno specified by sm_io_open() 206 ** any value of errno specified by sm_io_setinfo() 207 */ 208 209 #ifdef __STDC__ 210 /* 211 ** XXX This is a temporary hack since MODE_T on HP-UX 10.x is short. 212 ** If we use K&R here, the compiler will complain about 213 ** Inconsistent parameter list declaration 214 ** due to the change from short to int. 215 */ 216 217 SM_FILE_T * 218 bfopen(char *filename, MODE_T fmode, size_t bsize, long flags) 219 #else /* __STDC__ */ 220 SM_FILE_T * 221 bfopen(filename, fmode, bsize, flags) 222 char *filename; 223 MODE_T fmode; 224 size_t bsize; 225 long flags; 226 #endif /* __STDC__ */ 227 { 228 MODE_T omask; 229 SM_FILE_T SM_IO_SET_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose, 230 sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo, 231 SM_TIME_FOREVER); 232 struct bf_info info; 233 234 /* 235 ** Apply current umask to fmode as it may change by the time 236 ** the file is actually created. fmode becomes the true 237 ** permissions of the file, which OPEN() must obey. 238 */ 239 240 omask = umask(0); 241 fmode &= ~omask; 242 (void) umask(omask); 243 244 SM_IO_INIT_TYPE(vector, BF_FILE_TYPE, sm_bfopen, sm_bfclose, 245 sm_bfread, sm_bfwrite, sm_bfseek, sm_bfgetinfo, sm_bfsetinfo, 246 SM_TIME_FOREVER); 247 info.bi_filename = filename; 248 info.bi_fmode = fmode; 249 info.bi_bsize = bsize; 250 info.bi_flags = flags; 251 252 return sm_io_open(&vector, SM_TIME_DEFAULT, &info, SM_IO_RDWR, NULL); 253 } 254 255 /* 256 ** SM_BFGETINFO -- returns info about an open file pointer 257 ** 258 ** Parameters: 259 ** fp -- file pointer to get info about 260 ** what -- type of info to obtain 261 ** valp -- thing to return the info in 262 */ 263 264 static int 265 sm_bfgetinfo(fp, what, valp) 266 SM_FILE_T *fp; 267 int what; 268 void *valp; 269 { 270 struct bf *bfp; 271 272 bfp = (struct bf *) fp->f_cookie; 273 switch (what) 274 { 275 case SM_IO_WHAT_FD: 276 return bfp->bf_disk_fd; 277 case SM_IO_WHAT_SIZE: 278 return bfp->bf_size; 279 default: 280 return -1; 281 } 282 } 283 284 /* 285 ** SM_BFCLOSE -- close a buffered file 286 ** 287 ** Parameters: 288 ** fp -- cookie of file to close 289 ** 290 ** Returns: 291 ** 0 to indicate success 292 ** 293 ** Side Effects: 294 ** deletes backing file, sm_frees memory. 295 ** 296 ** Sets errno: 297 ** never. 298 */ 299 300 static int 301 sm_bfclose(fp) 302 SM_FILE_T *fp; 303 { 304 struct bf *bfp; 305 306 /* Cast cookie back to correct type */ 307 bfp = (struct bf *) fp->f_cookie; 308 309 /* Need to clean up the file */ 310 if (bfp->bf_ondisk && !bfp->bf_committed) 311 unlink(bfp->bf_filename); 312 sm_free(bfp->bf_filename); 313 314 if (bfp->bf_disk_fd != -1) 315 close(bfp->bf_disk_fd); 316 317 /* Need to sm_free the buffer */ 318 if (bfp->bf_bufsize > 0) 319 sm_free(bfp->bf_buf); 320 321 /* Finally, sm_free the structure */ 322 sm_free(bfp); 323 return 0; 324 } 325 326 /* 327 ** SM_BFREAD -- read a buffered file 328 ** 329 ** Parameters: 330 ** cookie -- cookie of file to read 331 ** buf -- buffer to fill 332 ** nbytes -- how many bytes to read 333 ** 334 ** Returns: 335 ** number of bytes read or -1 indicate failure 336 ** 337 ** Side Effects: 338 ** none. 339 ** 340 */ 341 342 static ssize_t 343 sm_bfread(fp, buf, nbytes) 344 SM_FILE_T *fp; 345 char *buf; 346 size_t nbytes; 347 { 348 struct bf *bfp; 349 ssize_t count = 0; /* Number of bytes put in buf so far */ 350 int retval; 351 352 /* Cast cookie back to correct type */ 353 bfp = (struct bf *) fp->f_cookie; 354 355 if (bfp->bf_offset < bfp->bf_buffilled) 356 { 357 /* Need to grab some from buffer */ 358 count = nbytes; 359 if ((bfp->bf_offset + count) > bfp->bf_buffilled) 360 count = bfp->bf_buffilled - bfp->bf_offset; 361 362 memcpy(buf, bfp->bf_buf + bfp->bf_offset, count); 363 } 364 365 if ((bfp->bf_offset + nbytes) > bfp->bf_buffilled) 366 { 367 /* Need to grab some from file */ 368 if (!bfp->bf_ondisk) 369 { 370 /* Oops, the file doesn't exist. EOF. */ 371 if (tTd(58, 8)) 372 sm_dprintf("sm_bfread(%s): to disk\n", 373 bfp->bf_filename); 374 goto finished; 375 } 376 377 /* Catch a read() on an earlier failed write to disk */ 378 if (bfp->bf_disk_fd < 0) 379 { 380 errno = EIO; 381 return -1; 382 } 383 384 if (lseek(bfp->bf_disk_fd, 385 bfp->bf_offset + count, SEEK_SET) < 0) 386 { 387 if ((errno == EINVAL) || (errno == ESPIPE)) 388 { 389 /* 390 ** stdio won't be expecting these 391 ** errnos from read()! Change them 392 ** into something it can understand. 393 */ 394 395 errno = EIO; 396 } 397 return -1; 398 } 399 400 while (count < nbytes) 401 { 402 retval = read(bfp->bf_disk_fd, 403 buf + count, 404 nbytes - count); 405 if (retval < 0) 406 { 407 /* errno is set implicitly by read() */ 408 return -1; 409 } 410 else if (retval == 0) 411 goto finished; 412 else 413 count += retval; 414 } 415 } 416 417 finished: 418 bfp->bf_offset += count; 419 return count; 420 } 421 422 /* 423 ** SM_BFSEEK -- seek to a position in a buffered file 424 ** 425 ** Parameters: 426 ** fp -- fp of file to seek 427 ** offset -- position to seek to 428 ** whence -- how to seek 429 ** 430 ** Returns: 431 ** new file offset or -1 indicate failure 432 ** 433 ** Side Effects: 434 ** none. 435 ** 436 */ 437 438 static off_t 439 sm_bfseek(fp, offset, whence) 440 SM_FILE_T *fp; 441 off_t offset; 442 int whence; 443 444 { 445 struct bf *bfp; 446 447 /* Cast cookie back to correct type */ 448 bfp = (struct bf *) fp->f_cookie; 449 450 switch (whence) 451 { 452 case SEEK_SET: 453 bfp->bf_offset = offset; 454 break; 455 456 case SEEK_CUR: 457 bfp->bf_offset += offset; 458 break; 459 460 case SEEK_END: 461 bfp->bf_offset = bfp->bf_size + offset; 462 break; 463 464 default: 465 errno = EINVAL; 466 return -1; 467 } 468 return bfp->bf_offset; 469 } 470 471 /* 472 ** SM_BFWRITE -- write to a buffered file 473 ** 474 ** Parameters: 475 ** fp -- fp of file to write 476 ** buf -- data buffer 477 ** nbytes -- how many bytes to write 478 ** 479 ** Returns: 480 ** number of bytes written or -1 indicate failure 481 ** 482 ** Side Effects: 483 ** may create backing file if over memory limit for file. 484 ** 485 */ 486 487 static ssize_t 488 sm_bfwrite(fp, buf, nbytes) 489 SM_FILE_T *fp; 490 const char *buf; 491 size_t nbytes; 492 { 493 struct bf *bfp; 494 ssize_t count = 0; /* Number of bytes written so far */ 495 int retval; 496 497 /* Cast cookie back to correct type */ 498 bfp = (struct bf *) fp->f_cookie; 499 500 /* If committed, go straight to disk */ 501 if (bfp->bf_committed) 502 { 503 if (lseek(bfp->bf_disk_fd, bfp->bf_offset, SEEK_SET) < 0) 504 { 505 if ((errno == EINVAL) || (errno == ESPIPE)) 506 { 507 /* 508 ** stdio won't be expecting these 509 ** errnos from write()! Change them 510 ** into something it can understand. 511 */ 512 513 errno = EIO; 514 } 515 return -1; 516 } 517 518 count = write(bfp->bf_disk_fd, buf, nbytes); 519 if (count < 0) 520 { 521 /* errno is set implicitly by write() */ 522 return -1; 523 } 524 goto finished; 525 } 526 527 if (bfp->bf_offset < bfp->bf_bufsize) 528 { 529 /* Need to put some in buffer */ 530 count = nbytes; 531 if ((bfp->bf_offset + count) > bfp->bf_bufsize) 532 count = bfp->bf_bufsize - bfp->bf_offset; 533 534 memcpy(bfp->bf_buf + bfp->bf_offset, buf, count); 535 if ((bfp->bf_offset + count) > bfp->bf_buffilled) 536 bfp->bf_buffilled = bfp->bf_offset + count; 537 } 538 539 if ((bfp->bf_offset + nbytes) > bfp->bf_bufsize) 540 { 541 /* Need to put some in file */ 542 if (!bfp->bf_ondisk) 543 { 544 MODE_T omask; 545 int save_errno; 546 547 /* Clear umask as bf_filemode are the true perms */ 548 omask = umask(0); 549 retval = OPEN(bfp->bf_filename, 550 O_RDWR | O_CREAT | O_TRUNC | QF_O_EXTRA, 551 bfp->bf_filemode, bfp->bf_flags); 552 save_errno = errno; 553 (void) umask(omask); 554 errno = save_errno; 555 556 /* Couldn't create file: failure */ 557 if (retval < 0) 558 { 559 /* 560 ** stdio may not be expecting these 561 ** errnos from write()! Change to 562 ** something which it can understand. 563 ** Note that ENOSPC and EDQUOT are saved 564 ** because they are actually valid for 565 ** write(). 566 */ 567 568 if (!(errno == ENOSPC 569 #ifdef EDQUOT 570 || errno == EDQUOT 571 #endif /* EDQUOT */ 572 )) 573 errno = EIO; 574 575 return -1; 576 } 577 bfp->bf_disk_fd = retval; 578 bfp->bf_ondisk = true; 579 } 580 581 /* Catch a write() on an earlier failed write to disk */ 582 if (bfp->bf_ondisk && bfp->bf_disk_fd < 0) 583 { 584 errno = EIO; 585 return -1; 586 } 587 588 if (lseek(bfp->bf_disk_fd, 589 bfp->bf_offset + count, SEEK_SET) < 0) 590 { 591 if ((errno == EINVAL) || (errno == ESPIPE)) 592 { 593 /* 594 ** stdio won't be expecting these 595 ** errnos from write()! Change them into 596 ** something which it can understand. 597 */ 598 599 errno = EIO; 600 } 601 return -1; 602 } 603 604 while (count < nbytes) 605 { 606 retval = write(bfp->bf_disk_fd, buf + count, 607 nbytes - count); 608 if (retval < 0) 609 { 610 /* errno is set implicitly by write() */ 611 return -1; 612 } 613 else 614 count += retval; 615 } 616 } 617 618 finished: 619 bfp->bf_offset += count; 620 if (bfp->bf_offset > bfp->bf_size) 621 bfp->bf_size = bfp->bf_offset; 622 return count; 623 } 624 625 /* 626 ** BFREWIND -- rewinds the SM_FILE_T * 627 ** 628 ** Parameters: 629 ** fp -- SM_FILE_T * to rewind 630 ** 631 ** Returns: 632 ** 0 on success, -1 on error 633 ** 634 ** Side Effects: 635 ** rewinds the SM_FILE_T * and puts it into read mode. Normally 636 ** one would bfopen() a file, write to it, then bfrewind() and 637 ** fread(). If fp is not a buffered file, this is equivalent to 638 ** rewind(). 639 ** 640 ** Sets errno: 641 ** any value of errno specified by sm_io_rewind() 642 */ 643 644 int 645 bfrewind(fp) 646 SM_FILE_T *fp; 647 { 648 (void) sm_io_flush(fp, SM_TIME_DEFAULT); 649 sm_io_clearerr(fp); /* quicker just to do it */ 650 return sm_io_seek(fp, SM_TIME_DEFAULT, 0, SM_IO_SEEK_SET); 651 } 652 653 /* 654 ** SM_BFCOMMIT -- "commits" the buffered file 655 ** 656 ** Parameters: 657 ** fp -- SM_FILE_T * to commit to disk 658 ** 659 ** Returns: 660 ** 0 on success, -1 on error 661 ** 662 ** Side Effects: 663 ** Forces the given SM_FILE_T * to be written to disk if it is not 664 ** already, and ensures that it will be kept after closing. If 665 ** fp is not a buffered file, this is a no-op. 666 ** 667 ** Sets errno: 668 ** any value of errno specified by open() 669 ** any value of errno specified by write() 670 ** any value of errno specified by lseek() 671 */ 672 673 static int 674 sm_bfcommit(fp) 675 SM_FILE_T *fp; 676 { 677 struct bf *bfp; 678 int retval; 679 int byteswritten; 680 681 /* Get associated bf structure */ 682 bfp = (struct bf *) fp->f_cookie; 683 684 /* If already committed, noop */ 685 if (bfp->bf_committed) 686 return 0; 687 688 /* Do we need to open a file? */ 689 if (!bfp->bf_ondisk) 690 { 691 int save_errno; 692 MODE_T omask; 693 struct stat st; 694 695 if (tTd(58, 8)) 696 { 697 sm_dprintf("bfcommit(%s): to disk\n", bfp->bf_filename); 698 if (tTd(58, 32)) 699 sm_dprintf("bfcommit(): filemode %o flags %ld\n", 700 bfp->bf_filemode, bfp->bf_flags); 701 } 702 703 if (stat(bfp->bf_filename, &st) == 0) 704 { 705 errno = EEXIST; 706 return -1; 707 } 708 709 /* Clear umask as bf_filemode are the true perms */ 710 omask = umask(0); 711 retval = OPEN(bfp->bf_filename, 712 O_RDWR | O_CREAT | O_EXCL | QF_O_EXTRA, 713 bfp->bf_filemode, bfp->bf_flags); 714 save_errno = errno; 715 (void) umask(omask); 716 717 /* Couldn't create file: failure */ 718 if (retval < 0) 719 { 720 /* errno is set implicitly by open() */ 721 errno = save_errno; 722 return -1; 723 } 724 725 bfp->bf_disk_fd = retval; 726 bfp->bf_ondisk = true; 727 } 728 729 /* Write out the contents of our buffer, if we have any */ 730 if (bfp->bf_buffilled > 0) 731 { 732 byteswritten = 0; 733 734 if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0) 735 { 736 /* errno is set implicitly by lseek() */ 737 return -1; 738 } 739 740 while (byteswritten < bfp->bf_buffilled) 741 { 742 retval = write(bfp->bf_disk_fd, 743 bfp->bf_buf + byteswritten, 744 bfp->bf_buffilled - byteswritten); 745 if (retval < 0) 746 { 747 /* errno is set implicitly by write() */ 748 return -1; 749 } 750 else 751 byteswritten += retval; 752 } 753 } 754 bfp->bf_committed = true; 755 756 /* Invalidate buf; all goes to file now */ 757 bfp->bf_buffilled = 0; 758 if (bfp->bf_bufsize > 0) 759 { 760 /* Don't need buffer anymore; free it */ 761 bfp->bf_bufsize = 0; 762 sm_free(bfp->bf_buf); 763 } 764 return 0; 765 } 766 767 /* 768 ** SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T * 769 ** 770 ** Parameters: 771 ** fp -- SM_FILE_T * to truncate 772 ** 773 ** Returns: 774 ** 0 on success, -1 on error 775 ** 776 ** Side Effects: 777 ** rewinds the SM_FILE_T *, truncates it to zero length, and puts 778 ** it into write mode. 779 ** 780 ** Sets errno: 781 ** any value of errno specified by fseek() 782 ** any value of errno specified by ftruncate() 783 */ 784 785 static int 786 sm_bftruncate(fp) 787 SM_FILE_T *fp; 788 { 789 struct bf *bfp; 790 791 if (bfrewind(fp) < 0) 792 return -1; 793 794 /* Get bf structure */ 795 bfp = (struct bf *) fp->f_cookie; 796 bfp->bf_buffilled = 0; 797 bfp->bf_size = 0; 798 799 /* Need to zero the buffer */ 800 if (bfp->bf_bufsize > 0) 801 memset(bfp->bf_buf, '\0', bfp->bf_bufsize); 802 if (bfp->bf_ondisk) 803 { 804 #if NOFTRUNCATE 805 /* XXX: Not much we can do except rewind it */ 806 errno = EINVAL; 807 return -1; 808 #else /* NOFTRUNCATE */ 809 return ftruncate(bfp->bf_disk_fd, 0); 810 #endif /* NOFTRUNCATE */ 811 } 812 return 0; 813 } 814 815 /* 816 ** SM_BFSETINFO -- set/change info for an open file pointer 817 ** 818 ** Parameters: 819 ** fp -- file pointer to get info about 820 ** what -- type of info to set/change 821 ** valp -- thing to set/change the info to 822 ** 823 */ 824 825 static int 826 sm_bfsetinfo(fp, what, valp) 827 SM_FILE_T *fp; 828 int what; 829 void *valp; 830 { 831 struct bf *bfp; 832 int bsize; 833 834 /* Get bf structure */ 835 bfp = (struct bf *) fp->f_cookie; 836 switch (what) 837 { 838 case SM_BF_SETBUFSIZE: 839 bsize = *((int *) valp); 840 bfp->bf_bufsize = bsize; 841 842 /* A zero bsize is valid, just don't allocate memory */ 843 if (bsize > 0) 844 { 845 bfp->bf_buf = (char *) sm_malloc(bsize); 846 if (bfp->bf_buf == NULL) 847 { 848 bfp->bf_bufsize = 0; 849 errno = ENOMEM; 850 return -1; 851 } 852 } 853 else 854 bfp->bf_buf = NULL; 855 return 0; 856 case SM_BF_COMMIT: 857 return sm_bfcommit(fp); 858 case SM_BF_TRUNCATE: 859 return sm_bftruncate(fp); 860 case SM_BF_TEST: 861 return 1; /* always */ 862 default: 863 errno = EINVAL; 864 return -1; 865 } 866 } 867