splitfs.c revision 124571
1209878Snwhitehorn/* 2209878Snwhitehorn * Copyright (c) 2002 Maxim Sobolev 3209878Snwhitehorn * All rights reserved. 4209878Snwhitehorn * 5209878Snwhitehorn * Redistribution and use in source and binary forms, with or without 6209878Snwhitehorn * modification, are permitted provided that the following conditions 7209878Snwhitehorn * are met: 8209878Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9209878Snwhitehorn * notice, this list of conditions and the following disclaimer. 10209878Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11209878Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12209878Snwhitehorn * documentation and/or other materials provided with the distribution. 13209878Snwhitehorn * 14209878Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15209878Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16209878Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17209878Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18209878Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19209878Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20209878Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21209878Snwhitehorn * 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. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/lib/libstand/splitfs.c 124571 2004-01-15 18:36:48Z jhb $"); 29 30#include "stand.h" 31 32#define NTRIES (3) 33#define CONF_BUF (512) 34#define SEEK_BUF (512) 35 36struct split_file 37{ 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 */ 45}; 46 47static int splitfs_open(const char *path, struct open_file *f); 48static int splitfs_close(struct open_file *f); 49static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 50static off_t splitfs_seek(struct open_file *f, off_t offset, int where); 51static int splitfs_stat(struct open_file *f, struct stat *sb); 52 53struct 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 62}; 63 64static void 65split_file_destroy(struct split_file *sf) 66{ 67 int i; 68 69 if (sf->filesc > 0) { 70 for (i = 0; i < sf->filesc; i++) { 71 free(sf->filesv[i]); 72 free(sf->descsv[i]); 73 } 74 free(sf->filesv); 75 free(sf->descsv); 76 } 77 free(sf); 78} 79 80static int 81splitfs_open(const char *fname, struct open_file *f) 82{ 83 char *buf, *confname, *cp; 84 int conffd; 85 struct split_file *sf; 86 struct stat sb; 87 88 /* Have to be in "just read it" mode */ 89 if (f->f_flags != F_READ) 90 return(EPERM); 91 92 /* If the name already ends in `.split', ignore it */ 93 if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split"))) 94 return(ENOENT); 95 96 /* Construct new name */ 97 confname = malloc(strlen(fname) + 7); 98 sprintf(confname, "%s.split", fname); 99 100 /* Try to open the configuration file */ 101 conffd = open(confname, O_RDONLY); 102 free(confname); 103 if (conffd == -1) 104 return(ENOENT); 105 106 if (fstat(conffd, &sb) < 0) { 107 printf("splitfs_open: stat failed\n"); 108 close(conffd); 109 return(ENOENT); 110 } 111 if (!S_ISREG(sb.st_mode)) { 112 printf("splitfs_open: not a file\n"); 113 close(conffd); 114 return(EISDIR); /* best guess */ 115 } 116 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++; 128 } 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); 138 } 139 free(buf); 140 close(conffd); 141 142 if ((sf->filesc == 0) || ((sf->curfd = open(sf->filesv[0], O_RDONLY)) == -1)) { 143 split_file_destroy(sf); 144 return(ENOENT); 145 } 146 147 /* Looks OK, we'll take it */ 148 f->f_fsdata = sf; 149 return (0); 150} 151 152static int 153splitfs_close(struct open_file *f) 154{ 155 int fd; 156 struct split_file *sf; 157 158 sf = (struct split_file *)f->f_fsdata; 159 fd = sf->curfd; 160 split_file_destroy(sf); 161 return(close(fd)); 162} 163 164static int 165splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 166{ 167 int i, nread, totread; 168 struct split_file *sf; 169 170 sf = (struct split_file *)f->f_fsdata; 171 totread = 0; 172 do { 173 nread = read(sf->curfd, buf, size - totread); 174 175 /* Error? */ 176 if (nread == -1) 177 return (errno); 178 179 sf->tot_pos += nread; 180 sf->file_pos += nread; 181 totread += nread; 182 buf += nread; 183 184 if (totread < size) { /* EOF */ 185 if (sf->curfile == (sf->filesc - 1)) /* Last slice */ 186 break; 187 188 /* Close previous slice */ 189 if (close(sf->curfd) != 0) 190 return (errno); 191 192 sf->curfile++; 193 for (i = 0;; i++) { 194 sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY); 195 if (sf->curfd >= 0) 196 break; 197 if ((sf->curfd == -1) && (errno != ENOENT)) 198 return (errno); 199 if (i == NTRIES) 200 return (EIO); 201 printf("\nInsert disk labelled %s and press any key...", sf->descsv[sf->curfile]); 202 getchar();putchar('\n'); 203 } 204 sf->file_pos = 0; 205 } 206 } while (totread < size); 207 208 if (resid != NULL) 209 *resid = size - totread; 210 211 return (0); 212} 213 214static off_t 215splitfs_seek(struct open_file *f, off_t offset, int where) 216{ 217 int nread; 218 size_t resid; 219 off_t new_pos, seek_by; 220 struct split_file *sf; 221 222 sf = (struct split_file *)f->f_fsdata; 223 224 seek_by = offset; 225 switch (where) { 226 case SEEK_SET: 227 seek_by -= sf->tot_pos; 228 break; 229 case SEEK_CUR: 230 break; 231 case SEEK_END: 232 panic("splitfs_seek: SEEK_END not supported"); 233 break; 234 } 235 236 if (seek_by > 0) { 237 /* 238 * Seek forward - implemented using splitfs_read(), because otherwise we'll be 239 * unable to detect that we have crossed slice boundary and hence 240 * unable to do a long seek crossing that boundary. 241 */ 242 void *tmp; 243 244 tmp = malloc(SEEK_BUF); 245 if (tmp == NULL) 246 return (-1); 247 248 nread = 0; 249 for (; seek_by > 0; seek_by -= nread) { 250 resid = 0; 251 errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid); 252 nread = min(seek_by, SEEK_BUF) - resid; 253 if ((errno != 0) || (nread == 0)) 254 /* Error or EOF */ 255 break; 256 } 257 free(tmp); 258 if (errno != 0) 259 return (-1); 260 } 261 262 if (seek_by != 0) { 263 /* Seek backward or seek past the boundary of the last slice */ 264 if (sf->file_pos + seek_by < 0) 265 panic("splitfs_seek: can't seek past the beginning of the slice"); 266 new_pos = lseek(sf->curfd, seek_by, SEEK_CUR); 267 if (new_pos < 0) 268 return (-1); 269 sf->tot_pos += new_pos - sf->file_pos; 270 sf->file_pos = new_pos; 271 } 272 273 return (sf->tot_pos); 274} 275 276static int 277splitfs_stat(struct open_file *f, struct stat *sb) 278{ 279 int result; 280 struct split_file *sf = (struct split_file *)f->f_fsdata; 281 282 /* stat as normal, but indicate that size is unknown */ 283 if ((result = fstat(sf->curfd, sb)) == 0) 284 sb->st_size = -1; 285 return (result); 286} 287