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
sm_bfopen(fp,info,flags,rpool)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 *
bfopen(char * filename,MODE_T fmode,size_t bsize,long flags)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
sm_bfgetinfo(fp,what,valp)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
sm_bfclose(fp)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
sm_bfread(fp,buf,nbytes)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
sm_bfseek(fp,offset,whence)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
sm_bfwrite(fp,buf,nbytes)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
bfrewind(fp)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
sm_bfcommit(fp)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
sm_bftruncate(fp)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
sm_bfsetinfo(fp,what,valp)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