Initial import from FreeBSD RELENG_4:
[games.git] / contrib / sendmail / src / bf.c
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.2 2002/06/21 19:58:40 gshapiro 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,
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 }