1*479ab7f0SSascha Wildner /*
2*479ab7f0SSascha Wildner * Copyright (c) 2002 Maxim Sobolev
3*479ab7f0SSascha Wildner * All rights reserved.
4*479ab7f0SSascha Wildner *
5*479ab7f0SSascha Wildner * Redistribution and use in source and binary forms, with or without
6*479ab7f0SSascha Wildner * modification, are permitted provided that the following conditions
7*479ab7f0SSascha Wildner * are met:
8*479ab7f0SSascha Wildner * 1. Redistributions of source code must retain the above copyright
9*479ab7f0SSascha Wildner * notice, this list of conditions and the following disclaimer.
10*479ab7f0SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
11*479ab7f0SSascha Wildner * notice, this list of conditions and the following disclaimer in the
12*479ab7f0SSascha Wildner * documentation and/or other materials provided with the distribution.
13*479ab7f0SSascha Wildner *
14*479ab7f0SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*479ab7f0SSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*479ab7f0SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*479ab7f0SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*479ab7f0SSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*479ab7f0SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*479ab7f0SSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*479ab7f0SSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*479ab7f0SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*479ab7f0SSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*479ab7f0SSascha Wildner * SUCH DAMAGE.
25*479ab7f0SSascha Wildner *
26*479ab7f0SSascha Wildner * $FreeBSD: src/lib/libstand/splitfs.c,v 1.3.2.1 2002/04/08 13:50:09 sobomax Exp $
27*479ab7f0SSascha Wildner * $DragonFly: src/lib/libstand/splitfs.c,v 1.2 2003/06/17 04:26:51 dillon Exp $
28*479ab7f0SSascha Wildner */
29*479ab7f0SSascha Wildner
30*479ab7f0SSascha Wildner #include "stand.h"
31*479ab7f0SSascha Wildner
32*479ab7f0SSascha Wildner #define NTRIES (3)
33*479ab7f0SSascha Wildner #define CONF_BUF (512)
34*479ab7f0SSascha Wildner #define SEEK_BUF (512)
35*479ab7f0SSascha Wildner
36*479ab7f0SSascha Wildner struct split_file
37*479ab7f0SSascha Wildner {
38*479ab7f0SSascha Wildner char **filesv; /* Filenames */
39*479ab7f0SSascha Wildner char **descsv; /* Descriptions */
40*479ab7f0SSascha Wildner int filesc; /* Number of parts */
41*479ab7f0SSascha Wildner int curfile; /* Current file number */
42*479ab7f0SSascha Wildner int curfd; /* Current file descriptor */
43*479ab7f0SSascha Wildner off_t tot_pos; /* Offset from the beginning of the sequence */
44*479ab7f0SSascha Wildner off_t file_pos; /* Offset from the beginning of the slice */
45*479ab7f0SSascha Wildner };
46*479ab7f0SSascha Wildner
47*479ab7f0SSascha Wildner static int splitfs_open(const char *path, struct open_file *f);
48*479ab7f0SSascha Wildner static int splitfs_close(struct open_file *f);
49*479ab7f0SSascha Wildner static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
50*479ab7f0SSascha Wildner static off_t splitfs_seek(struct open_file *f, off_t offset, int where);
51*479ab7f0SSascha Wildner static int splitfs_stat(struct open_file *f, struct stat *sb);
52*479ab7f0SSascha Wildner
53*479ab7f0SSascha Wildner struct fs_ops splitfs_fsops = {
54*479ab7f0SSascha Wildner "split",
55*479ab7f0SSascha Wildner splitfs_open,
56*479ab7f0SSascha Wildner splitfs_close,
57*479ab7f0SSascha Wildner splitfs_read,
58*479ab7f0SSascha Wildner null_write,
59*479ab7f0SSascha Wildner splitfs_seek,
60*479ab7f0SSascha Wildner splitfs_stat,
61*479ab7f0SSascha Wildner null_readdir
62*479ab7f0SSascha Wildner };
63*479ab7f0SSascha Wildner
64*479ab7f0SSascha Wildner static void
split_file_destroy(struct split_file * sf)65*479ab7f0SSascha Wildner split_file_destroy(struct split_file *sf)
66*479ab7f0SSascha Wildner {
67*479ab7f0SSascha Wildner int i;
68*479ab7f0SSascha Wildner
69*479ab7f0SSascha Wildner if (sf->filesc > 0) {
70*479ab7f0SSascha Wildner for (i = 0; i < sf->filesc; i++) {
71*479ab7f0SSascha Wildner free(sf->filesv[i]);
72*479ab7f0SSascha Wildner free(sf->descsv[i]);
73*479ab7f0SSascha Wildner }
74*479ab7f0SSascha Wildner free(sf->filesv);
75*479ab7f0SSascha Wildner free(sf->descsv);
76*479ab7f0SSascha Wildner }
77*479ab7f0SSascha Wildner free(sf);
78*479ab7f0SSascha Wildner }
79*479ab7f0SSascha Wildner
80*479ab7f0SSascha Wildner static int
splitfs_open(const char * fname,struct open_file * f)81*479ab7f0SSascha Wildner splitfs_open(const char *fname, struct open_file *f)
82*479ab7f0SSascha Wildner {
83*479ab7f0SSascha Wildner char *buf, *confname, *cp;
84*479ab7f0SSascha Wildner int conffd;
85*479ab7f0SSascha Wildner struct split_file *sf;
86*479ab7f0SSascha Wildner struct stat sb;
87*479ab7f0SSascha Wildner
88*479ab7f0SSascha Wildner /* Have to be in "just read it" mode */
89*479ab7f0SSascha Wildner if ((f->f_flags & (F_READ | F_WRITE)) != F_READ)
90*479ab7f0SSascha Wildner return(EPERM);
91*479ab7f0SSascha Wildner
92*479ab7f0SSascha Wildner /* If the name already ends in `.split', ignore it */
93*479ab7f0SSascha Wildner if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split")))
94*479ab7f0SSascha Wildner return(ENOENT);
95*479ab7f0SSascha Wildner
96*479ab7f0SSascha Wildner /* Construct new name */
97*479ab7f0SSascha Wildner confname = malloc(strlen(fname) + 7);
98*479ab7f0SSascha Wildner sprintf(confname, "%s.split", fname);
99*479ab7f0SSascha Wildner
100*479ab7f0SSascha Wildner /* Try to open the configuration file */
101*479ab7f0SSascha Wildner conffd = open(confname, O_RDONLY);
102*479ab7f0SSascha Wildner free(confname);
103*479ab7f0SSascha Wildner if (conffd == -1)
104*479ab7f0SSascha Wildner return(ENOENT);
105*479ab7f0SSascha Wildner
106*479ab7f0SSascha Wildner if (fstat(conffd, &sb) < 0) {
107*479ab7f0SSascha Wildner printf("splitfs_open: stat failed\n");
108*479ab7f0SSascha Wildner close(conffd);
109*479ab7f0SSascha Wildner return(ENOENT);
110*479ab7f0SSascha Wildner }
111*479ab7f0SSascha Wildner if (!S_ISREG(sb.st_mode)) {
112*479ab7f0SSascha Wildner printf("splitfs_open: not a file\n");
113*479ab7f0SSascha Wildner close(conffd);
114*479ab7f0SSascha Wildner return(EISDIR); /* best guess */
115*479ab7f0SSascha Wildner }
116*479ab7f0SSascha Wildner
117*479ab7f0SSascha Wildner /* Allocate a split_file structure, populate it from the config file */
118*479ab7f0SSascha Wildner sf = malloc(sizeof(struct split_file));
119*479ab7f0SSascha Wildner bzero(sf, sizeof(struct split_file));
120*479ab7f0SSascha Wildner buf = malloc(CONF_BUF);
121*479ab7f0SSascha Wildner while (fgetstr(buf, CONF_BUF, conffd) > 0) {
122*479ab7f0SSascha Wildner cp = buf;
123*479ab7f0SSascha Wildner while ((*cp != '\0') && (isspace(*cp) == 0))
124*479ab7f0SSascha Wildner cp++;
125*479ab7f0SSascha Wildner if (*cp != '\0') {
126*479ab7f0SSascha Wildner *cp = '\0';
127*479ab7f0SSascha Wildner cp++;
128*479ab7f0SSascha Wildner }
129*479ab7f0SSascha Wildner while ((*cp != '\0') && (isspace(*cp) != 0))
130*479ab7f0SSascha Wildner cp++;
131*479ab7f0SSascha Wildner if (*cp == '\0')
132*479ab7f0SSascha Wildner cp = buf;
133*479ab7f0SSascha Wildner sf->filesc++;
134*479ab7f0SSascha Wildner sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc);
135*479ab7f0SSascha Wildner sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc);
136*479ab7f0SSascha Wildner sf->filesv[sf->filesc - 1] = strdup(buf);
137*479ab7f0SSascha Wildner sf->descsv[sf->filesc - 1] = strdup(cp);
138*479ab7f0SSascha Wildner }
139*479ab7f0SSascha Wildner free(buf);
140*479ab7f0SSascha Wildner close(conffd);
141*479ab7f0SSascha Wildner
142*479ab7f0SSascha Wildner if ((sf->filesc == 0) || ((sf->curfd = open(sf->filesv[0], O_RDONLY)) == -1)) {
143*479ab7f0SSascha Wildner split_file_destroy(sf);
144*479ab7f0SSascha Wildner return(ENOENT);
145*479ab7f0SSascha Wildner }
146*479ab7f0SSascha Wildner
147*479ab7f0SSascha Wildner /* Looks OK, we'll take it */
148*479ab7f0SSascha Wildner f->f_fsdata = sf;
149*479ab7f0SSascha Wildner return (0);
150*479ab7f0SSascha Wildner }
151*479ab7f0SSascha Wildner
152*479ab7f0SSascha Wildner static int
splitfs_close(struct open_file * f)153*479ab7f0SSascha Wildner splitfs_close(struct open_file *f)
154*479ab7f0SSascha Wildner {
155*479ab7f0SSascha Wildner int fd;
156*479ab7f0SSascha Wildner struct split_file *sf;
157*479ab7f0SSascha Wildner
158*479ab7f0SSascha Wildner sf = (struct split_file *)f->f_fsdata;
159*479ab7f0SSascha Wildner f->f_fsdata = NULL;
160*479ab7f0SSascha Wildner if (sf) {
161*479ab7f0SSascha Wildner fd = sf->curfd;
162*479ab7f0SSascha Wildner split_file_destroy(sf);
163*479ab7f0SSascha Wildner return(close(fd));
164*479ab7f0SSascha Wildner }
165*479ab7f0SSascha Wildner return(0);
166*479ab7f0SSascha Wildner }
167*479ab7f0SSascha Wildner
168*479ab7f0SSascha Wildner static int
splitfs_read(struct open_file * f,void * buf,size_t size,size_t * resid)169*479ab7f0SSascha Wildner splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
170*479ab7f0SSascha Wildner {
171*479ab7f0SSascha Wildner int i, nread, totread;
172*479ab7f0SSascha Wildner struct split_file *sf;
173*479ab7f0SSascha Wildner
174*479ab7f0SSascha Wildner sf = (struct split_file *)f->f_fsdata;
175*479ab7f0SSascha Wildner totread = 0;
176*479ab7f0SSascha Wildner do {
177*479ab7f0SSascha Wildner nread = read(sf->curfd, buf, size - totread);
178*479ab7f0SSascha Wildner
179*479ab7f0SSascha Wildner /* Error? */
180*479ab7f0SSascha Wildner if (nread == -1)
181*479ab7f0SSascha Wildner return (errno);
182*479ab7f0SSascha Wildner
183*479ab7f0SSascha Wildner sf->tot_pos += nread;
184*479ab7f0SSascha Wildner sf->file_pos += nread;
185*479ab7f0SSascha Wildner totread += nread;
186*479ab7f0SSascha Wildner buf += nread;
187*479ab7f0SSascha Wildner
188*479ab7f0SSascha Wildner if (totread < size) { /* EOF */
189*479ab7f0SSascha Wildner if (sf->curfile == (sf->filesc - 1)) /* Last slice */
190*479ab7f0SSascha Wildner break;
191*479ab7f0SSascha Wildner
192*479ab7f0SSascha Wildner /* Close previous slice */
193*479ab7f0SSascha Wildner if (close(sf->curfd) != 0)
194*479ab7f0SSascha Wildner return (errno);
195*479ab7f0SSascha Wildner
196*479ab7f0SSascha Wildner sf->curfile++;
197*479ab7f0SSascha Wildner for (i = 0;; i++) {
198*479ab7f0SSascha Wildner sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY);
199*479ab7f0SSascha Wildner if (sf->curfd >= 0)
200*479ab7f0SSascha Wildner break;
201*479ab7f0SSascha Wildner if ((sf->curfd == -1) && (errno != ENOENT))
202*479ab7f0SSascha Wildner return (errno);
203*479ab7f0SSascha Wildner if (i == NTRIES)
204*479ab7f0SSascha Wildner return (EIO);
205*479ab7f0SSascha Wildner printf("\nInsert disk labelled %s and press any key...", sf->descsv[sf->curfile]);
206*479ab7f0SSascha Wildner getchar();putchar('\n');
207*479ab7f0SSascha Wildner }
208*479ab7f0SSascha Wildner sf->file_pos = 0;
209*479ab7f0SSascha Wildner }
210*479ab7f0SSascha Wildner } while (totread < size);
211*479ab7f0SSascha Wildner
212*479ab7f0SSascha Wildner if (resid != NULL)
213*479ab7f0SSascha Wildner *resid = size - totread;
214*479ab7f0SSascha Wildner
215*479ab7f0SSascha Wildner return (0);
216*479ab7f0SSascha Wildner }
217*479ab7f0SSascha Wildner
218*479ab7f0SSascha Wildner static off_t
splitfs_seek(struct open_file * f,off_t offset,int where)219*479ab7f0SSascha Wildner splitfs_seek(struct open_file *f, off_t offset, int where)
220*479ab7f0SSascha Wildner {
221*479ab7f0SSascha Wildner int nread;
222*479ab7f0SSascha Wildner size_t resid;
223*479ab7f0SSascha Wildner off_t new_pos, seek_by;
224*479ab7f0SSascha Wildner struct split_file *sf;
225*479ab7f0SSascha Wildner
226*479ab7f0SSascha Wildner sf = (struct split_file *)f->f_fsdata;
227*479ab7f0SSascha Wildner
228*479ab7f0SSascha Wildner seek_by = offset;
229*479ab7f0SSascha Wildner switch (where) {
230*479ab7f0SSascha Wildner case SEEK_SET:
231*479ab7f0SSascha Wildner seek_by -= sf->tot_pos;
232*479ab7f0SSascha Wildner break;
233*479ab7f0SSascha Wildner case SEEK_CUR:
234*479ab7f0SSascha Wildner break;
235*479ab7f0SSascha Wildner case SEEK_END:
236*479ab7f0SSascha Wildner panic("splitfs_seek: SEEK_END not supported");
237*479ab7f0SSascha Wildner break;
238*479ab7f0SSascha Wildner }
239*479ab7f0SSascha Wildner
240*479ab7f0SSascha Wildner if (seek_by > 0) {
241*479ab7f0SSascha Wildner /*
242*479ab7f0SSascha Wildner * Seek forward - implemented using splitfs_read(), because otherwise we'll be
243*479ab7f0SSascha Wildner * unable to detect that we have crossed slice boundary and hence
244*479ab7f0SSascha Wildner * unable to do a long seek crossing that boundary.
245*479ab7f0SSascha Wildner */
246*479ab7f0SSascha Wildner void *tmp;
247*479ab7f0SSascha Wildner
248*479ab7f0SSascha Wildner tmp = malloc(SEEK_BUF);
249*479ab7f0SSascha Wildner if (tmp == NULL)
250*479ab7f0SSascha Wildner return (-1);
251*479ab7f0SSascha Wildner
252*479ab7f0SSascha Wildner nread = 0;
253*479ab7f0SSascha Wildner for (; seek_by > 0; seek_by -= nread) {
254*479ab7f0SSascha Wildner resid = 0;
255*479ab7f0SSascha Wildner errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid);
256*479ab7f0SSascha Wildner nread = min(seek_by, SEEK_BUF) - resid;
257*479ab7f0SSascha Wildner if ((errno != 0) || (nread == 0))
258*479ab7f0SSascha Wildner /* Error or EOF */
259*479ab7f0SSascha Wildner break;
260*479ab7f0SSascha Wildner }
261*479ab7f0SSascha Wildner free(tmp);
262*479ab7f0SSascha Wildner if (errno != 0)
263*479ab7f0SSascha Wildner return (-1);
264*479ab7f0SSascha Wildner }
265*479ab7f0SSascha Wildner
266*479ab7f0SSascha Wildner if (seek_by != 0) {
267*479ab7f0SSascha Wildner /* Seek backward or seek past the boundary of the last slice */
268*479ab7f0SSascha Wildner if (sf->file_pos + seek_by < 0)
269*479ab7f0SSascha Wildner panic("splitfs_seek: can't seek past the beginning of the slice");
270*479ab7f0SSascha Wildner new_pos = lseek(sf->curfd, seek_by, SEEK_CUR);
271*479ab7f0SSascha Wildner if (new_pos < 0)
272*479ab7f0SSascha Wildner return (-1);
273*479ab7f0SSascha Wildner sf->tot_pos += new_pos - sf->file_pos;
274*479ab7f0SSascha Wildner sf->file_pos = new_pos;
275*479ab7f0SSascha Wildner }
276*479ab7f0SSascha Wildner
277*479ab7f0SSascha Wildner return (sf->tot_pos);
278*479ab7f0SSascha Wildner }
279*479ab7f0SSascha Wildner
280*479ab7f0SSascha Wildner static int
splitfs_stat(struct open_file * f,struct stat * sb)281*479ab7f0SSascha Wildner splitfs_stat(struct open_file *f, struct stat *sb)
282*479ab7f0SSascha Wildner {
283*479ab7f0SSascha Wildner int result;
284*479ab7f0SSascha Wildner struct split_file *sf = (struct split_file *)f->f_fsdata;
285*479ab7f0SSascha Wildner
286*479ab7f0SSascha Wildner /* stat as normal, but indicate that size is unknown */
287*479ab7f0SSascha Wildner if ((result = fstat(sf->curfd, sb)) == 0)
288*479ab7f0SSascha Wildner sb->st_size = -1;
289*479ab7f0SSascha Wildner return (result);
290*479ab7f0SSascha Wildner }
291