1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 2002-2013 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * dss file support
23 *
24 * Glenn Fowler
25 * AT&T Research
26 */
27
28 #include "dsshdr.h"
29
30 #include <ls.h>
31 #include <pzip.h>
32
33 /*
34 * not open for read
35 */
36
37 static int
noreadf(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)38 noreadf(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
39 {
40 if (disc->errorf)
41 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: not open for read", file->path);
42 return -1;
43 }
44
45 /*
46 * empty input
47 */
48
49 static int
nullreadf(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)50 nullreadf(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
51 {
52 return 0;
53 }
54
55 /*
56 * not open for write
57 */
58
59 static int
nowritef(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)60 nowritef(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
61 {
62 if (disc->errorf)
63 (*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "%s: not open for write", file->path);
64 return -1;
65 }
66
67 /*
68 * file open
69 */
70
71 Dssfile_t*
dssfopen(Dss_t * dss,const char * path,Sfio_t * io,Dssflags_t flags,Dssformat_t * format)72 dssfopen(Dss_t* dss, const char* path, Sfio_t* io, Dssflags_t flags, Dssformat_t* format)
73 {
74 Dssfile_t* file;
75 Vmalloc_t* vm;
76 char* s;
77 size_t n;
78 int i;
79 struct stat st;
80 Sfdisc_t top;
81 char buf[PATH_MAX];
82
83 if (flags & DSS_FILE_WRITE)
84 {
85 if (io)
86 {
87 memset(&top, 0, sizeof(top));
88 if (sfdisc(io, &top))
89 {
90 n = top.disc == &dss->state->compress_preferred;
91 sfdisc(io, SF_POPDISC);
92 if (n)
93 {
94 sfdisc(io, SF_POPDISC);
95 sfdczip(io, path, dss->meth->compress ? dss->meth->compress : "gzip", dss->disc->errorf);
96 }
97 }
98 }
99 if (dss->flags & DSS_APPEND)
100 flags |= DSS_FILE_APPEND;
101 }
102 if (!path || !*path || streq(path, "-"))
103 {
104 if (flags & DSS_FILE_WRITE)
105 {
106 if (io)
107 path = "output-stream";
108 else
109 {
110 path = "/dev/stdout";
111 io = sfstdout;
112 }
113 }
114 else if (io)
115 path = "input-stream";
116 else
117 {
118 path = "/dev/stdin";
119 io = sfstdin;
120 }
121 flags |= DSS_FILE_KEEP;
122 }
123 else if (io)
124 flags |= DSS_FILE_KEEP;
125 else if (flags & DSS_FILE_WRITE)
126 {
127 if (!(io = sfopen(NiL, path, (flags & DSS_FILE_APPEND) ? "a" : "w")))
128 {
129 if (dss->disc->errorf)
130 (*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "%s: cannot open", path);
131 return 0;
132 }
133 }
134 else if (!(io = dssfind(path, "", DSS_VERBOSE, buf, sizeof(buf), dss->disc)))
135 return 0;
136 else
137 path = (const char*)buf;
138 if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
139 {
140 if (dss->disc->errorf)
141 (*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "out of space");
142 return 0;
143 }
144 if (!(file = vmnewof(vm, 0, Dssfile_t, 1, strlen(path) + 1)))
145 {
146 if (dss->disc->errorf)
147 (*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "out of space");
148 if (!(flags & DSS_FILE_KEEP))
149 sfclose(io);
150 vmclose(vm);
151 return 0;
152 }
153 strcpy(file->path = (char*)(file + 1), path);
154 file->dss = dss;
155 file->vm = vm;
156 file->io = io;
157 file->flags = flags;
158 if (flags & DSS_FILE_WRITE)
159 {
160 if (!(file->format = format) && !(file->format = dss->format))
161 {
162 if (dss->disc->errorf)
163 (*dss->disc->errorf)(NiL, dss->disc, 2, "output method format must be specified");
164 if (!(flags & DSS_FILE_KEEP))
165 sfclose(io);
166 return 0;
167 }
168 file->readf = noreadf;
169 file->writef = file->format->writef;
170 }
171 else
172 {
173 if (sfsize(file->io) || !fstat(sffileno(file->io), &st) && (S_ISFIFO(st.st_mode)
174 #ifdef S_ISSOCK
175 || S_ISSOCK(st.st_mode)
176 #endif
177 ))
178 {
179 if (sfdczip(file->io, file->path, NiL, dss->disc->errorf) < 0)
180 {
181 if (dss->disc->errorf)
182 (*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "%s: inflate error", file->path);
183 dssfclose(file);
184 return 0;
185 }
186 s = sfreserve(file->io, SF_UNBOUND, SF_LOCKR);
187 n = sfvalue(file->io);
188 if (!s)
189 {
190 if (n && dss->disc->errorf)
191 (*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "%s: cannot peek", file->path);
192 dssfclose(file);
193 return 0;
194 }
195 for (file->format = (Dssformat_t*)dtfirst(dss->meth->formats); file->format && !(i = (*file->format->identf)(file, s, n, dss->disc)); file->format = (Dssformat_t*)dtnext(dss->meth->formats, file->format));
196 sfread(file->io, s, 0);
197 if (!file->format)
198 {
199 if (dss->disc->errorf)
200 (*dss->disc->errorf)(NiL, dss->disc, 2, "%s: unknown %s format", file->path, dss->meth->name);
201 dssfclose(file);
202 return 0;
203 }
204 if (i < 0)
205 return 0;
206 if (format && format != file->format)
207 {
208 if (dss->disc->errorf)
209 (*dss->disc->errorf)(NiL, dss->disc, 2, "%s: %s file format %s incompatible with %s", file->path, dss->meth->name, file->format->name, format->name);
210 dssfclose(file);
211 return 0;
212 }
213 if ((dss->flags & DSS_VERBOSE) && dss->disc->errorf)
214 (*dss->disc->errorf)(dss, dss->disc, 1, "%s: %s method %s format", file->path, dss->meth->name, file->format->name);
215 file->readf = file->format->readf;
216 }
217 else
218 {
219 file->format = format ? format : dss->format ? dss->format : (Dssformat_t*)dtfirst(dss->meth->formats);
220 file->readf = nullreadf;
221 }
222 file->writef = nowritef;
223 if (!dss->format)
224 dss->format = file->format;
225 }
226 if (!file->format)
227 {
228 if (dss->disc->errorf)
229 (*dss->disc->errorf)(NiL, dss->disc, 2, "%s: %s method did not set file format", file->path, dss->meth->name);
230 dssfclose(file);
231 return 0;
232 }
233 file->record.file = file;
234 if ((*file->format->openf)(file, dss->disc))
235 {
236 dssfclose(file);
237 return 0;
238 }
239 return file;
240 }
241
242 /*
243 * file close
244 */
245
246 int
dssfclose(Dssfile_t * file)247 dssfclose(Dssfile_t* file)
248 {
249 int r;
250 Dss_t* dss;
251
252 if (!file)
253 return -1;
254 dss = file->dss;
255 if (!file->io)
256 r = -1;
257 else
258 {
259 r = file->format ? (*file->format->closef)(file, dss->disc) : 0;
260 if ((file->flags & DSS_FILE_WRITE) && sfsync(file->io))
261 {
262 if (dss->disc->errorf)
263 (*dss->disc->errorf)(NiL, dss->disc, ERROR_SYSTEM|2, "%s: write error", file->path);
264 r = -1;
265 }
266 if (!(file->flags & DSS_FILE_KEEP))
267 sfclose(file->io);
268 if (!r && (file->flags & DSS_FILE_ERROR))
269 r = -1;
270 }
271 vmclose(file->vm);
272 return r;
273 }
274
275 /*
276 * file read
277 */
278
279 Dssrecord_t*
dssfread(Dssfile_t * file)280 dssfread(Dssfile_t* file)
281 {
282 int r;
283
284 file->count++;
285 file->offset += file->length;
286 if ((r = (*file->readf)(file, &file->record, file->dss->disc)) <= 0)
287 {
288 if (r < 0)
289 file->flags |= DSS_FILE_ERROR;
290 file->count--;
291 return 0;
292 }
293 file->length = sftell(file->io) - file->offset;
294 return &file->record;
295 }
296
297 /*
298 * file write
299 */
300
301 int
dssfwrite(Dssfile_t * file,Dssrecord_t * record)302 dssfwrite(Dssfile_t* file, Dssrecord_t* record)
303 {
304 return (*file->writef)(file, record, file->dss->disc);
305 }
306
307 /*
308 * file tell
309 */
310
311 Sfoff_t
dssftell(Dssfile_t * file)312 dssftell(Dssfile_t* file)
313 {
314 return file->seekf ? (*file->seekf)(file, DSS_TELL, file->dss->disc) : file->offset;
315 }
316
317 /*
318 * file seek
319 */
320
321 int
dssfseek(Dssfile_t * file,Sfoff_t offset)322 dssfseek(Dssfile_t* file, Sfoff_t offset)
323 {
324 return (file->seekf ? (*file->seekf)(file, offset, file->dss->disc) : sfseek(file->io, offset, SEEK_SET)) == offset ? 0 : -1;
325 }
326
327 /*
328 * save record state
329 */
330
331 Dssrecord_t*
dsssave(Dssrecord_t * record)332 dsssave(Dssrecord_t* record)
333 {
334 return record->file->format->savef ? (*record->file->format->savef)(record->file, record, record->file->dss->disc) : (Dssrecord_t*)0;
335 }
336
337 /*
338 * drop saved record
339 */
340
341 int
dssdrop(Dssrecord_t * record)342 dssdrop(Dssrecord_t* record)
343 {
344 return record->file->format->dropf ? (*record->file->format->dropf)(record->file, record, record->file->dss->disc) : -1;
345 }
346
347 /*
348 * common diagnostics
349 */
350
351 Dssrecord_t*
dss_no_fread(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)352 dss_no_fread(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
353 {
354 if (disc->errorf)
355 (*disc->errorf)(NiL, disc, 2, "%s: %s file format %s read not implemented", file->path, file->dss->meth->name, file->format->name);
356 return 0;
357 }
358
359 int
dss_no_fwrite(Dssfile_t * file,Dssrecord_t * record,Dssdisc_t * disc)360 dss_no_fwrite(Dssfile_t* file, Dssrecord_t* record, Dssdisc_t* disc)
361 {
362 if (disc->errorf)
363 (*disc->errorf)(NiL, disc, 2, "%s: %s file format %s write not implemented", file->path, file->dss->meth->name, file->format->name);
364 return -1;
365 }
366
367 Sfoff_t
dss_no_fseek(Dssfile_t * file,Sfoff_t offset,Dssdisc_t * disc)368 dss_no_fseek(Dssfile_t* file, Sfoff_t offset, Dssdisc_t* disc)
369 {
370 if (disc->errorf)
371 (*disc->errorf)(NiL, disc, 2, "%s: %s file format %s seek not implemented", file->path, file->dss->meth->name, file->format->name);
372 return -1;
373 }
374