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