Merge from vendor branch GROFF:
[dragonfly.git] / sbin / jscan / jfile.c
1 /*
2  * Copyright (c) 2004,2005 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sbin/jscan/jfile.c,v 1.5 2005/07/06 06:06:44 dillon Exp $
35  */
36
37 #include "jscan.h"
38
39 /*
40  * Open a journal for directional scanning
41  */
42 struct jfile *
43 jopen_stream(const char *path, enum jdirection jdir, int flags)
44 {
45     FILE *fp;
46     struct jfile *jf;
47
48     if ((fp = fopen(path, "r")) == NULL)
49         return (NULL);
50     if ((jf = jopen_fp(fp, jdir, flags)) == NULL)
51         fclose (fp);
52     return(jf);
53 }
54
55 struct jfile *
56 jopen_fp(FILE *fp, enum jdirection jdir, int flags)
57 {
58     struct jfile *jf;
59
60     jf = malloc(sizeof(struct jfile));
61     bzero(jf, sizeof(struct jfile));
62     jf->jf_fp = fp;
63     jf->jf_direction = jdir;
64     jf->jf_setpt = -1;
65     jf->jf_flags = flags;
66     if (jdir == JF_BACKWARDS) {
67         fseeko(jf->jf_fp, 0L, SEEK_END);
68         jf->jf_pos = ftello(jf->jf_fp);
69     }
70     return(jf);
71 }
72
73 /*
74  * Close a previously opened journal, clean up any side allocations.
75  */
76 void
77 jclose_stream(struct jfile *jf)
78 {
79     struct jdata *jd;
80
81     fclose(jf->jf_fp);
82     jf->jf_fp = NULL;
83     while ((jd = jf->jf_saved) != NULL) {
84         jf->jf_saved = jd->jd_next;
85         free(jd);
86     }
87     free(jf);
88 }
89
90 /*
91  * Align us to the next 16 byte boundary.  If scanning forwards we align
92  * forwards if not already aligned.  If scanning backwards we align
93  * backwards if not already aligned.
94  */
95 void
96 jalign(struct jfile *jf)
97 {
98     if (jf->jf_direction == JF_FORWARDS) {
99         jf->jf_pos = (jf->jf_pos + 15) & ~15;
100         fseeko(jf->jf_fp, jf->jf_pos, SEEK_SET);
101     } else {
102         jf->jf_pos = jf->jf_pos & ~15;
103     }
104 }
105
106 /*
107  * Read data from a journal forwards or backwards.  Note that the file
108  * pointer's actual seek position does not match jf_pos in the reverse
109  * scan case.  Callers should never access jf_fp directly.
110  */
111 int
112 jread(struct jfile *jf, void *buf, int bytes)
113 {
114     int n;
115     
116     if (jf->jf_direction == JF_FORWARDS) {
117         while (bytes) {
118             n = fread(buf, 1, bytes, jf->jf_fp);
119             if (n <= 0)
120                 break;
121             assert(n <= bytes);
122             jf->jf_pos += n;
123             buf = (char *)buf + n;
124             bytes -= n;
125         }
126         if (bytes == 0) {
127                 return (0);
128         } else {
129                 fseeko(jf->jf_fp, jf->jf_pos, SEEK_SET);
130                 return (errno ? errno : ENOENT);
131         }
132     } else {
133         if (bytes > jf->jf_pos)
134                 return (ENOENT);
135         jf->jf_pos -= bytes;
136         fseeko(jf->jf_fp, jf->jf_pos, SEEK_SET);
137         if (fread(buf, bytes, 1, jf->jf_fp) == 1) {
138                 return (0);
139         } else {
140                 jf->jf_pos += bytes;
141                 return (errno);
142         }
143     }
144 }
145
146 int
147 jwrite(struct jfile *jf, void *buf, int bytes)
148 {
149     int n;
150
151     n = write(fileno(jf->jf_fp), buf, bytes);
152     return(n);
153 }
154
155 void
156 jset(struct jfile *jf)
157 {
158     jf->jf_setpt = jf->jf_pos;
159 }
160
161 void
162 jreturn(struct jfile *jf)
163 {
164     jf->jf_pos = jf->jf_setpt;
165     jf->jf_setpt = -1;
166     fseeko(jf->jf_fp, jf->jf_pos, SEEK_SET);
167 }
168
169 void
170 jflush(struct jfile *jf)
171 {
172     jf->jf_setpt = -1;
173 }
174