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.61 2004/08/03 23:59:02 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; /* Currect 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 /* BF_STANDALONE */ 71 # define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff) 72 #endif /* BF_STANDALONE */ 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 544 /* Clear umask as bf_filemode are the true perms */ 545 omask = umask(0); 546 retval = OPEN(bfp->bf_filename, 547 O_RDWR | O_CREAT | O_TRUNC | QF_O_EXTRA, 548 bfp->bf_filemode, bfp->bf_flags); 549 (void) umask(omask); 550 551 /* Couldn't create file: failure */ 552 if (retval < 0) 553 { 554 /* 555 ** stdio may not be expecting these 556 ** errnos from write()! Change to 557 ** something which it can understand. 558 ** Note that ENOSPC and EDQUOT are saved 559 ** because they are actually valid for 560 ** write(). 561 */ 562 563 if (!(errno == ENOSPC 564 #ifdef EDQUOT 565 || errno == EDQUOT 566 #endif /* EDQUOT */ 567 )) 568 errno = EIO; 569 570 return -1; 571 } 572 bfp->bf_disk_fd = retval; 573 bfp->bf_ondisk = true; 574 } 575 576 /* Catch a write() on an earlier failed write to disk */ 577 if (bfp->bf_ondisk && bfp->bf_disk_fd < 0) 578 { 579 errno = EIO; 580 return -1; 581 } 582 583 if (lseek(bfp->bf_disk_fd, 584 bfp->bf_offset + count, SEEK_SET) < 0) 585 { 586 if ((errno == EINVAL) || (errno == ESPIPE)) 587 { 588 /* 589 ** stdio won't be expecting these 590 ** errnos from write()! Change them into 591 ** something which it can understand. 592 */ 593 594 errno = EIO; 595 } 596 return -1; 597 } 598 599 while (count < nbytes) 600 { 601 retval = write(bfp->bf_disk_fd, buf + count, 602 nbytes - count); 603 if (retval < 0) 604 { 605 /* errno is set implicitly by write() */ 606 return -1; 607 } 608 else 609 count += retval; 610 } 611 } 612 613 finished: 614 bfp->bf_offset += count; 615 if (bfp->bf_offset > bfp->bf_size) 616 bfp->bf_size = bfp->bf_offset; 617 return count; 618 } 619 620 /* 621 ** BFREWIND -- rewinds the SM_FILE_T * 622 ** 623 ** Parameters: 624 ** fp -- SM_FILE_T * to rewind 625 ** 626 ** Returns: 627 ** 0 on success, -1 on error 628 ** 629 ** Side Effects: 630 ** rewinds the SM_FILE_T * and puts it into read mode. Normally 631 ** one would bfopen() a file, write to it, then bfrewind() and 632 ** fread(). If fp is not a buffered file, this is equivalent to 633 ** rewind(). 634 ** 635 ** Sets errno: 636 ** any value of errno specified by sm_io_rewind() 637 */ 638 639 int 640 bfrewind(fp) 641 SM_FILE_T *fp; 642 { 643 (void) sm_io_flush(fp, SM_TIME_DEFAULT); 644 sm_io_clearerr(fp); /* quicker just to do it */ 645 return sm_io_seek(fp, SM_TIME_DEFAULT, 0, SM_IO_SEEK_SET); 646 } 647 648 /* 649 ** SM_BFCOMMIT -- "commits" the buffered file 650 ** 651 ** Parameters: 652 ** fp -- SM_FILE_T * to commit to disk 653 ** 654 ** Returns: 655 ** 0 on success, -1 on error 656 ** 657 ** Side Effects: 658 ** Forces the given SM_FILE_T * to be written to disk if it is not 659 ** already, and ensures that it will be kept after closing. If 660 ** fp is not a buffered file, this is a no-op. 661 ** 662 ** Sets errno: 663 ** any value of errno specified by open() 664 ** any value of errno specified by write() 665 ** any value of errno specified by lseek() 666 */ 667 668 static int 669 sm_bfcommit(fp) 670 SM_FILE_T *fp; 671 { 672 struct bf *bfp; 673 int retval; 674 int byteswritten; 675 676 /* Get associated bf structure */ 677 bfp = (struct bf *) fp->f_cookie; 678 679 /* If already committed, noop */ 680 if (bfp->bf_committed) 681 return 0; 682 683 /* Do we need to open a file? */ 684 if (!bfp->bf_ondisk) 685 { 686 int save_errno; 687 MODE_T omask; 688 struct stat st; 689 690 if (tTd(58, 8)) 691 { 692 sm_dprintf("bfcommit(%s): to disk\n", bfp->bf_filename); 693 if (tTd(58, 32)) 694 sm_dprintf("bfcommit(): filemode %o flags %ld\n", 695 bfp->bf_filemode, bfp->bf_flags); 696 } 697 698 if (stat(bfp->bf_filename, &st) == 0) 699 { 700 errno = EEXIST; 701 return -1; 702 } 703 704 /* Clear umask as bf_filemode are the true perms */ 705 omask = umask(0); 706 retval = OPEN(bfp->bf_filename, 707 O_RDWR | O_CREAT | O_EXCL | QF_O_EXTRA, 708 bfp->bf_filemode, bfp->bf_flags); 709 save_errno = errno; 710 (void) umask(omask); 711 712 /* Couldn't create file: failure */ 713 if (retval < 0) 714 { 715 /* errno is set implicitly by open() */ 716 errno = save_errno; 717 return -1; 718 } 719 720 bfp->bf_disk_fd = retval; 721 bfp->bf_ondisk = true; 722 } 723 724 /* Write out the contents of our buffer, if we have any */ 725 if (bfp->bf_buffilled > 0) 726 { 727 byteswritten = 0; 728 729 if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0) 730 { 731 /* errno is set implicitly by lseek() */ 732 return -1; 733 } 734 735 while (byteswritten < bfp->bf_buffilled) 736 { 737 retval = write(bfp->bf_disk_fd, 738 bfp->bf_buf + byteswritten, 739 bfp->bf_buffilled - byteswritten); 740 if (retval < 0) 741 { 742 /* errno is set implicitly by write() */ 743 return -1; 744 } 745 else 746 byteswritten += retval; 747 } 748 } 749 bfp->bf_committed = true; 750 751 /* Invalidate buf; all goes to file now */ 752 bfp->bf_buffilled = 0; 753 if (bfp->bf_bufsize > 0) 754 { 755 /* Don't need buffer anymore; free it */ 756 bfp->bf_bufsize = 0; 757 sm_free(bfp->bf_buf); 758 } 759 return 0; 760 } 761 762 /* 763 ** SM_BFTRUNCATE -- rewinds and truncates the SM_FILE_T * 764 ** 765 ** Parameters: 766 ** fp -- SM_FILE_T * to truncate 767 ** 768 ** Returns: 769 ** 0 on success, -1 on error 770 ** 771 ** Side Effects: 772 ** rewinds the SM_FILE_T *, truncates it to zero length, and puts 773 ** it into write mode. 774 ** 775 ** Sets errno: 776 ** any value of errno specified by fseek() 777 ** any value of errno specified by ftruncate() 778 */ 779 780 static int 781 sm_bftruncate(fp) 782 SM_FILE_T *fp; 783 { 784 struct bf *bfp; 785 786 if (bfrewind(fp) < 0) 787 return -1; 788 789 /* Get bf structure */ 790 bfp = (struct bf *) fp->f_cookie; 791 bfp->bf_buffilled = 0; 792 bfp->bf_size = 0; 793 794 /* Need to zero the buffer */ 795 if (bfp->bf_bufsize > 0) 796 memset(bfp->bf_buf, '\0', bfp->bf_bufsize); 797 if (bfp->bf_ondisk) 798 { 799 #if NOFTRUNCATE 800 /* XXX: Not much we can do except rewind it */ 801 errno = EINVAL; 802 return -1; 803 #else /* NOFTRUNCATE */ 804 return ftruncate(bfp->bf_disk_fd, 0); 805 #endif /* NOFTRUNCATE */ 806 } 807 return 0; 808 } 809 810 /* 811 ** SM_BFSETINFO -- set/change info for an open file pointer 812 ** 813 ** Parameters: 814 ** fp -- file pointer to get info about 815 ** what -- type of info to set/change 816 ** valp -- thing to set/change the info to 817 ** 818 */ 819 820 static int 821 sm_bfsetinfo(fp, what, valp) 822 SM_FILE_T *fp; 823 int what; 824 void *valp; 825 { 826 struct bf *bfp; 827 int bsize; 828 829 /* Get bf structure */ 830 bfp = (struct bf *) fp->f_cookie; 831 switch (what) 832 { 833 case SM_BF_SETBUFSIZE: 834 bsize = *((int *) valp); 835 bfp->bf_bufsize = bsize; 836 837 /* A zero bsize is valid, just don't allocate memory */ 838 if (bsize > 0) 839 { 840 bfp->bf_buf = (char *) sm_malloc(bsize); 841 if (bfp->bf_buf == NULL) 842 { 843 bfp->bf_bufsize = 0; 844 errno = ENOMEM; 845 return -1; 846 } 847 } 848 else 849 bfp->bf_buf = NULL; 850 return 0; 851 case SM_BF_COMMIT: 852 return sm_bfcommit(fp); 853 case SM_BF_TRUNCATE: 854 return sm_bftruncate(fp); 855 case SM_BF_TEST: 856 return 1; /* always */ 857 default: 858 errno = EINVAL; 859 return -1; 860 } 861 } 862