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