Back to index

avfs  1.0.1
floppy.c
Go to the documentation of this file.
00001 /*  
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998  Miklos Szeredi <miklos@szeredi.hu>
00004     
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 
00008     FLOPPY module (interface for mtools)
00009 */
00010 
00011 #include "remote.h"
00012 #include "runprog.h"
00013 
00014 #include <sys/stat.h>
00015 #include <fcntl.h>
00016 
00017 struct floppylocalfile {
00018     char *tmpfile;
00019     struct program *pr;
00020     avoff_t currsize;
00021 };
00022 
00023 static void strip_spaces(const char *buf, int *ip)
00024 {
00025     int i = *ip;
00026     while(isspace((unsigned char) buf[i])) i++;
00027     *ip = i;
00028 }
00029 
00030 static void strip_nonspace(const char *buf, int *ip)
00031 {
00032     int i = *ip;
00033     while(!isspace((unsigned char) buf[i])) i++;
00034     *ip = i;
00035 }
00036 
00037 static void strip_spaces_end(char *buf)
00038 {
00039     unsigned int i = strlen(buf);
00040 
00041     while(i > 0 && isspace((unsigned char) buf[i-1]))
00042         i--;
00043     buf[i] = '\0';
00044 }
00045 
00046 static int get_num(const char *s, int *ip)
00047 {
00048     int i;
00049     int num;
00050   
00051     i = *ip;
00052   
00053     if(s[i] < '0' || s[i] > '9') return -1;
00054 
00055     num = 0;
00056     for(;; i++) {
00057         if(s[i] >= '0' && s[i] <= '9') num = (num * 10) + (s[i] - '0');
00058         else if(s[i] != ',' && s[i] != '.') break;
00059     }
00060   
00061     *ip = i;
00062     return num;
00063 }
00064 
00065 static int conv_date(const char *s, struct avtm *tms)
00066 {
00067     int num;
00068     int i;
00069   
00070     i = 0;
00071 
00072     if((num = get_num(s, &i)) == -1 || num < 1 || num > 12) return -1;
00073     tms->mon = num - 1;
00074     i++;
00075   
00076     if((num = get_num(s, &i)) == -1 || num < 1 || num > 31) return -1;
00077     tms->day = num;
00078     i++;
00079 
00080     if((num = get_num(s, &i)) == -1) return -1;
00081     if(num >= 80 && num < 100) num += 1900;
00082     else if(num >= 0 && num < 80) num += 2000;
00083 
00084     if(num < 1900) return -1;
00085     tms->year = num - 1900;
00086 
00087     return 0;
00088 }
00089 
00090 
00091 static int conv_time(const char *s, struct avtm *tms)
00092 {
00093     int num;
00094     int i;
00095   
00096     i = 0;
00097 
00098     if((num = get_num(s, &i)) == -1 || num < 0) return -1;
00099     tms->hour = num;
00100     i++;
00101   
00102     if((num = get_num(s, &i)) == -1 || num < 0 || num > 59) return -1;
00103     tms->min = num;
00104 
00105     if(s[i] == ':') {
00106         i++;
00107         if((num = get_num(s, &i)) == -1 || num < 0 ||  num > 59) return -1;
00108 
00109         tms->sec = num;
00110     }
00111     else tms->sec = 0;
00112   
00113     if((s[i] == 'p' || s[i] == 'P') && tms->hour < 12) tms->hour += 12;
00114     if(tms->hour > 24) return -1;
00115     if(tms->hour == 24) tms->hour = 0;
00116 
00117     return 0;
00118 }
00119 
00120 
00121 static int process_vollabel(const char *buf, struct avstat *st, char **namep)
00122 {
00123     *namep = av_stradd(NULL, ".vol-", buf + 22, NULL);
00124     strip_spaces_end(*namep);
00125 
00126     st->mode = AV_IFREG | 0444;
00127     st->size = 0;
00128 
00129     return 0;
00130 }
00131 
00132 static int process_dir_line(const char *buf, int vollabel, struct avstat *st,
00133                             char **namep)
00134 {
00135     int i, start;
00136     int namelen;
00137     struct avtm tms;
00138     char shortname[32];
00139 
00140     i = 0;
00141 
00142     if(strncmp(buf, " Volume in drive ", 17) == 0 && 
00143        buf[17] && strncmp(buf+18, " is ", 4) == 0 && buf[22]) {
00144         if(vollabel)
00145             return process_vollabel(buf, st, namep);
00146         else
00147             return -1;
00148     }
00149 
00150     strip_nonspace(buf, &i);
00151     if(!buf[i] || i == 0 || i > 8) return -1;
00152     
00153     namelen = i;
00154     strncpy(shortname, buf, namelen);
00155     shortname[namelen] = '\0';
00156     
00157     strip_spaces(buf, &i);
00158     if(i == 9) {
00159         int extlen;
00160         
00161         strip_nonspace(buf, &i);
00162         extlen = i - 9;
00163         
00164         if(extlen > 3) return -1;
00165         
00166         shortname[namelen++] = '.';
00167         strncpy(shortname+namelen, buf+9, extlen);
00168         namelen += extlen;
00169         shortname[namelen] = '\0';
00170         
00171         strip_spaces(buf, &i);
00172     }
00173     
00174     if(!buf[i] || i < 13) return -1;
00175     
00176     start = i;
00177     strip_nonspace(buf, &i);
00178     
00179     if(strncmp("<DIR>", buf + start, i - start) == 0) {
00180         st->size = 0;
00181         st->mode = AV_IFDIR | 0777;
00182     }
00183     else {
00184         int size;
00185         if((size = get_num(buf, &start)) == -1) return -1;
00186         st->size = size;
00187         st->mode = AV_IFREG | 0666;
00188     }
00189     strip_spaces(buf, &i);
00190     if(!buf[i]) return -1;
00191     
00192     start = i;
00193     strip_nonspace(buf, &i);
00194     if(conv_date(buf + start, &tms) == -1) return -1;
00195     strip_spaces(buf, &i);
00196     if(!buf[i]) return -1;
00197     
00198     start = i;
00199     strip_nonspace(buf, &i);
00200     if(conv_time(buf + start, &tms) == -1) return -1;
00201     strip_spaces(buf, &i);
00202     
00203     st->mtime.sec = av_mktime(&tms);
00204     st->mtime.nsec = 0;
00205     
00206     if(buf[i]) {
00207         *namep = av_strdup(buf+i);
00208         strip_spaces_end(*namep);
00209     }
00210     else
00211         *namep = av_strdup(shortname);
00212 
00213     return 0;
00214 }
00215 
00216 static void floppy_parse_line(const char *line, struct remdirlist *dl)
00217 {
00218     int res;
00219     char *filename;
00220     struct avstat stbuf;
00221     int vollabel;
00222 
00223     if(strcmp(dl->hostpath.path, "/") == 0)
00224         vollabel = 1;
00225     else
00226         vollabel = 0;
00227 
00228     av_default_stat(&stbuf);
00229     res = process_dir_line(line, vollabel, &stbuf, &filename);
00230     if(res != 0)
00231         return;
00232 
00233     stbuf.nlink = 1;
00234     stbuf.blksize = 512;
00235     stbuf.blocks = AV_BLOCKS(stbuf.size);
00236     stbuf.atime = stbuf.mtime;
00237     stbuf.ctime = stbuf.mtime;
00238 
00239     av_remote_add(dl, filename, NULL, &stbuf);
00240 
00241     av_free(filename);
00242 }
00243 
00244 static int floppy_read_list(struct program *pr, struct remdirlist *dl)
00245 {
00246     int res;
00247 
00248     while(1) {
00249         char *line;
00250 
00251         res = av_program_getline(pr, &line, -1);
00252         if(res <= 0)
00253             return res;
00254         if(line == NULL)
00255             return 0;
00256 
00257         floppy_parse_line(line, dl);
00258         av_free(line);
00259     }
00260 }
00261 
00262 static int floppy_get_path(struct remote *rem, struct remhostpath *hp,
00263                            char **resp)
00264 {
00265     char drive[2];
00266     char *alias = (char *) rem->data;
00267 
00268     if(alias != NULL)
00269         drive[0] = alias[0];
00270     else {
00271         if(strlen(hp->host) != 1)
00272             return -ENOENT;
00273         drive[0] = tolower((unsigned char) hp->host[0]);
00274         if(drive[0] < 'a' || drive[0] > 'z')
00275             return -ENOENT;
00276     }
00277     drive[1] = '\0';
00278 
00279     *resp = av_stradd(NULL, drive, ":", hp->path, NULL);
00280     return 0;
00281 }
00282 
00283 
00284 static int floppy_list(struct remote *rem, struct remdirlist *dl)
00285 {
00286     int res;
00287     struct program *pr;
00288     const char *prog[4];
00289     char *path;
00290 
00291     res = floppy_get_path(rem, &dl->hostpath, &path);
00292     if(res < 0)
00293         return res;
00294 
00295     prog[0] = "mdir";
00296     prog[1] = "-a";
00297     prog[2] = path;
00298     prog[3] = NULL;
00299 
00300     res = av_start_program(prog, &pr);
00301     if(res == 0) {
00302         res = floppy_read_list(pr, dl);
00303         av_unref_obj(pr);
00304     }
00305     av_free(path);
00306 
00307     return res;
00308 }
00309 
00310 static void floppy_free_localfile(struct floppylocalfile *lf)
00311 {
00312     
00313     if(lf->pr != NULL) {
00314         av_program_log_output(lf->pr);
00315         av_unref_obj(lf->pr);
00316     }
00317 }
00318 
00319 static int floppy_get(struct remote *rem, struct remgetparam *gp)
00320 {
00321     int res;
00322     struct floppylocalfile *lf;
00323     char *tmpfile;
00324     const char *prog[4];
00325     char *path;
00326 
00327     res = floppy_get_path(rem, &gp->hostpath, &path);
00328     if(res < 0)
00329         return res;
00330 
00331     res = av_get_tmpfile(&tmpfile);
00332     if(res < 0) {
00333         av_free(path);
00334        return res;
00335     }
00336 
00337     if(strncmp(gp->hostpath.path, "/.vol-", 6) == 0) {
00338         av_free(path);
00339         open(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
00340         gp->data = NULL;
00341         gp->localname = tmpfile;
00342         return 0;
00343     }
00344 
00345     AV_NEW_OBJ(lf, floppy_free_localfile);
00346     lf->pr = NULL;
00347     lf->tmpfile = tmpfile;
00348 
00349     prog[0] = "mcopy";
00350     prog[1] = path;
00351     prog[2] = lf->tmpfile;
00352     prog[3] = NULL;
00353 
00354     res = av_start_program(prog, &lf->pr);
00355     av_free(path);
00356     if(res < 0) {
00357         av_unref_obj(lf);
00358         av_del_tmpfile(tmpfile);
00359         return res;
00360     }
00361 
00362     lf->currsize = 0;
00363 
00364     gp->data = lf;
00365     gp->localname = lf->tmpfile;
00366 
00367     return 1;
00368 }
00369 
00370 static int floppy_wait(struct remote *rem, void *data, avoff_t end)
00371 {
00372     int res;
00373     struct floppylocalfile *lf = (struct floppylocalfile *) data;
00374 
00375     /* FIXME: timeout? */
00376     do {
00377         struct stat stbuf;
00378         
00379         res = av_program_log_output(lf->pr);
00380         if(res <= 0)
00381             return res;
00382 
00383         res = stat(lf->tmpfile, &stbuf);
00384         if(res == 0)
00385             lf->currsize = stbuf.st_size;
00386 
00387         if(lf->currsize < end)
00388             av_sleep(250);
00389 
00390     } while(lf->currsize < end);
00391 
00392     return 1;
00393 }
00394 
00395 
00396 static void floppy_destroy(struct remote *rem)
00397 {
00398     av_free(rem->name);
00399     av_free(rem->data);
00400     av_free(rem);
00401 }
00402 
00403 static int floppy_init(struct vmodule *module, const char *modname,
00404                        const char *alias)
00405 {
00406     int res;
00407     struct remote *rem;
00408     struct avfs *avfs;
00409     
00410     AV_NEW(rem);
00411     
00412     /* FIXME: Dont cache (at least not for long) */
00413     rem->flags   = REM_DIR_ONLY | REM_NOCASE;
00414     rem->data    = av_strdup(alias);
00415     rem->name    = av_strdup(modname);
00416     rem->destroy = floppy_destroy;
00417     rem->list    = floppy_list;
00418     rem->get     = floppy_get;
00419     rem->wait    = floppy_wait;
00420 
00421     res = av_remote_init(module, rem, &avfs);
00422 
00423     return res;
00424 }
00425 
00426 extern int av_init_module_floppy(struct vmodule *module);
00427 
00428 int av_init_module_floppy(struct vmodule *module)
00429 {
00430     int res;
00431 
00432     res = floppy_init(module, "floppy", NULL);
00433     if(res < 0)
00434         return res;
00435 
00436     res = floppy_init(module, "a", "a");
00437     if(res < 0)
00438         return res;
00439 
00440     return 0;
00441 }