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