2 * Copyright (c) 2002 Maxim Sobolev
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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 $
33 #define CONF_BUF (512)
34 #define SEEK_BUF (512)
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
= {
65 split_file_destroy(struct split_file
*sf
)
70 for (i
= 0; i
< sf
->filesc
; i
++) {
81 splitfs_open(const char *fname
, struct open_file
*f
)
83 char *buf
, *confname
, *cp
;
85 struct split_file
*sf
;
88 /* Have to be in "just read it" mode */
89 if ((f
->f_flags
& (F_READ
| F_WRITE
)) != F_READ
)
92 /* If the name already ends in `.split', ignore it */
93 if ((cp
= strrchr(fname
, '.')) && (!strcmp(cp
, ".split")))
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
);
106 if (fstat(conffd
, &sb
) < 0) {
107 printf("splitfs_open: stat failed\n");
111 if (!S_ISREG(sb
.st_mode
)) {
112 printf("splitfs_open: not a file\n");
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) {
123 while ((*cp
!= '\0') && (isspace(*cp
) == 0))
129 while ((*cp
!= '\0') && (isspace(*cp
) != 0))
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
);
142 if ((sf
->filesc
== 0) || ((sf
->curfd
= open(sf
->filesv
[0], O_RDONLY
)) == -1)) {
143 split_file_destroy(sf
);
147 /* Looks OK, we'll take it */
153 splitfs_close(struct open_file
*f
)
156 struct split_file
*sf
;
158 sf
= (struct split_file
*)f
->f_fsdata
;
162 split_file_destroy(sf
);
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
;
177 nread
= read(sf
->curfd
, buf
, size
- totread
);
183 sf
->tot_pos
+= nread
;
184 sf
->file_pos
+= nread
;
188 if (totread
< size
) { /* EOF */
189 if (sf
->curfile
== (sf
->filesc
- 1)) /* Last slice */
192 /* Close previous slice */
193 if (close(sf
->curfd
) != 0)
198 sf
->curfd
= open(sf
->filesv
[sf
->curfile
], O_RDONLY
);
201 if ((sf
->curfd
== -1) && (errno
!= ENOENT
))
205 printf("\nInsert disk labelled %s and press any key...", sf
->descsv
[sf
->curfile
]);
206 getchar();putchar('\n');
210 } while (totread
< size
);
213 *resid
= size
- totread
;
219 splitfs_seek(struct open_file
*f
, off_t offset
, int where
)
223 off_t new_pos
, seek_by
;
224 struct split_file
*sf
;
226 sf
= (struct split_file
*)f
->f_fsdata
;
231 seek_by
-= sf
->tot_pos
;
236 panic("splitfs_seek: SEEK_END not supported");
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.
248 tmp
= malloc(SEEK_BUF
);
253 for (; seek_by
> 0; seek_by
-= nread
) {
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))
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
);
273 sf
->tot_pos
+= new_pos
- sf
->file_pos
;
274 sf
->file_pos
= new_pos
;
277 return (sf
->tot_pos
);
281 splitfs_stat(struct open_file
*f
, struct stat
*sb
)
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)