1 /* 2 * Copyright (c) 1999-2002 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.54.2.3 2003/09/03 19:58:26 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, O_RDWR | O_CREAT | O_EXCL, 705 bfp->bf_filemode, bfp->bf_flags); 706 save_errno = errno; 707 (void) umask(omask); 708 709 /* Couldn't create file: failure */ 710 if (retval < 0) 711 { 712 /* errno is set implicitly by open() */ 713 errno = save_errno; 714 return -1; 715 } 716 717 bfp->bf_disk_fd = retval; 718 bfp->bf_ondisk = true; 719 } 720 721 /* Write out the contents of our buffer, if we have any */ 722 if (bfp->bf_buffilled > 0) 723 { 724 byteswritten = 0; 725 726 if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0) 727 { 728 /* errno is set implicitly by lseek() */ 729 return -1; 730 } 731 732 while (byteswritten < bfp->bf_buffilled) 733 { 734 retval = write(bfp->bf_disk_fd, 735 bfp->bf_buf + byteswritten, 736 bfp->bf_buffilled - byteswritten); 737 if (retval < 0) 738 { 739 /* errno is set implicitly by write() */ 740 return -1; 741 } 742 else 743 byteswritten += retval; 744 } 745 } 746 bfp->bf_committed = true; 747 748 /* Invalidate buf; all goes to file now */ 749 bfp->bf_buffilled = 0; 750 if (bfp->bf_bufsize > 0) 751 { 752 /* Don't need buffer anymore; free it */ 753 bfp->bf_bufsize = 0; 754 sm_free(bfp->bf_buf); 755 } 756 return 0; 757 } 758 759 /* 760 ** SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T * 761 ** 762 ** Parameters: 763 ** fp -- SM_FILE_T * to truncate 764 ** 765 ** Returns: 766 ** 0 on success, -1 on error 767 ** 768 ** Side Effects: 769 ** rewinds the SM_FILE_T *, truncates it to zero length, and puts 770 ** it into write mode. 771 ** 772 ** Sets errno: 773 ** any value of errno specified by fseek() 774 ** any value of errno specified by ftruncate() 775 */ 776 777 static int 778 sm_bftruncate(fp) 779 SM_FILE_T *fp; 780 { 781 struct bf *bfp; 782 783 if (bfrewind(fp) < 0) 784 return -1; 785 786 /* Get bf structure */ 787 bfp = (struct bf *) fp->f_cookie; 788 bfp->bf_buffilled = 0; 789 bfp->bf_size = 0; 790 791 /* Need to zero the buffer */ 792 if (bfp->bf_bufsize > 0) 793 memset(bfp->bf_buf, '\0', bfp->bf_bufsize); 794 if (bfp->bf_ondisk) 795 { 796 #if NOFTRUNCATE 797 /* XXX: Not much we can do except rewind it */ 798 errno = EINVAL; 799 return -1; 800 #else /* NOFTRUNCATE */ 801 return ftruncate(bfp->bf_disk_fd, 0); 802 #endif /* NOFTRUNCATE */ 803 } 804 return 0; 805 } 806 807 /* 808 ** SM_BFSETINFO -- set/change info for an open file pointer 809 ** 810 ** Parameters: 811 ** fp -- file pointer to get info about 812 ** what -- type of info to set/change 813 ** valp -- thing to set/change the info to 814 ** 815 */ 816 817 static int 818 sm_bfsetinfo(fp, what, valp) 819 SM_FILE_T *fp; 820 int what; 821 void *valp; 822 { 823 struct bf *bfp; 824 int bsize; 825 826 /* Get bf structure */ 827 bfp = (struct bf *) fp->f_cookie; 828 switch (what) 829 { 830 case SM_BF_SETBUFSIZE: 831 bsize = *((int *) valp); 832 bfp->bf_bufsize = bsize; 833 834 /* A zero bsize is valid, just don't allocate memory */ 835 if (bsize > 0) 836 { 837 bfp->bf_buf = (char *) sm_malloc(bsize); 838 if (bfp->bf_buf == NULL) 839 { 840 bfp->bf_bufsize = 0; 841 errno = ENOMEM; 842 return -1; 843 } 844 } 845 else 846 bfp->bf_buf = NULL; 847 return 0; 848 case SM_BF_COMMIT: 849 return sm_bfcommit(fp); 850 case SM_BF_TRUNCATE: 851 return sm_bftruncate(fp); 852 case SM_BF_TEST: 853 return 1; /* always */ 854 default: 855 errno = EINVAL; 856 return -1; 857 } 858 } 859