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