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