source: trunk/third/sendmail/sendmail/bf.c @ 19204

Revision 19204, 17.5 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
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>
21SM_RCSID("@(#)$Id: bf.c,v 1.1.1.1 2003-04-08 15:07:43 zacheiss 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 */
37static ssize_t  sm_bfread __P((SM_FILE_T *, char *, size_t));
38static ssize_t  sm_bfwrite __P((SM_FILE_T *, const char *, size_t));
39static off_t    sm_bfseek __P((SM_FILE_T *, off_t, int));
40static int      sm_bfclose __P((SM_FILE_T *));
41
42static int      sm_bfopen __P((SM_FILE_T *, const void *, int, const void *));
43static int      sm_bfsetinfo __P((SM_FILE_T *, int , void *));
44static 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
51struct 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
72struct 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
95static int
96sm_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
213SM_FILE_T *
214bfopen(char *filename, MODE_T fmode, size_t bsize, long flags)
215#else /* __STDC__ */
216SM_FILE_T *
217bfopen(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
260static int
261sm_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
296static int
297sm_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
338static ssize_t
339sm_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
413finished:
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
434static off_t
435sm_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
483static ssize_t
484sm_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
611finished:
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
637int
638bfrewind(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
666static int
667sm_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
777static int
778sm_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
817static int
818sm_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}
Note: See TracBrowser for help on using the repository browser.