/* * hostfs.c - Routines for reading the ramdisk contents from a host * filesystem * * Copyright (C) 2002-2003 Gero Kuhlmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: hostfs.c,v 1.2 2003/01/25 23:29:43 gkminix Exp $ */ #define NEED_BINARY 1 #define NEED_DIR 1 #define NEED_TIME 1 #include #include #include "mknbi.h" #include "dir.h" #ifndef _MKNBI_H_DOS_ #error Included wrong header file #endif /*************************************************************************** Routines to parse directory tree ***************************************************************************/ /* * Encode a file name into a unicode integer array. Note that this * routine assumes the host to work with latin1 character set. */ static void unicode(src, dest, len) char *src; utf16_t *dest; int len; { int i; for (i = 0; i < len; i++) *(dest++) = (int)(*(src++) & 0x00ff); *dest = 0; } /* * Convert UNIX path name into DOS file name. If the file name doesn't * fit into 8.3 format, the name will be converted accoording to DOS * rules. */ static void cvtname(dsp, namep, path) struct dir_struct *dsp; struct fname_struct *namep; char *path; { char *cp, *fname; char numbuf[5]; int name_end; int i, j, k; int needs_lfn = FALSE; /* Isolate file name */ if ((cp = strrchr(path, '/')) == NULL) cp = path; else cp++; fname = cp; /* Copy file name (max. 8 chars) */ i = 0; while (*cp && *cp != '.') { if (i < 8) namep->name[i++] = toupper(*cp); else needs_lfn = TRUE; cp++; } name_end = i; while (i < 8) namep->name[i++] = ' '; if (*cp == '.') cp++; /* Copy file extension (max. 3 chars) */ i = 0; while (*cp) { if (i < 3) namep->ext[i++] = toupper(*cp); else needs_lfn = TRUE; cp++; } while (i < 3) namep->ext[i++] = ' '; /* Clear long file name fields */ namep->lfn_num = 0; if (namep->lfn_name != NULL) { free(namep->lfn_name); namep->lfn_name = NULL; } /* Check if the file name already exists after conversion */ if (!needs_lfn && (findfile(dsp, FALSE, namep->name, namep->ext) != NULL)) needs_lfn = TRUE; if (!needs_lfn) return; /* For long file names we have to search for a suitable 8.3 name */ for (i = 1; i <= 999; i++) { sprintf(numbuf, "%d", i); if ((strlen(numbuf) + name_end) > 8) j = 8 - strlen(numbuf); else j = name_end; cp = numbuf; namep->name[j++] = '~'; while (*cp) namep->name[j++] = *(cp++); if (findfile(dsp, FALSE, namep->name, namep->ext) == NULL) { k = roundup(strlen(fname), LFN_CHARS); namep->lfn_num = k / LFN_CHARS; namep->lfn_name = (utf16_t *)nbmalloc(k * sizeof(utf16_t)); memset((__u8 *)namep->lfn_name, 0xff, (k * sizeof(utf16_t))); unicode(fname, namep->lfn_name, strlen(fname)); return; } } prnerr1("unable to convert name of file %s into 8.3 format", path); exit(EXIT_DOS_DOUBLEFILE); } /* * Read in the complete directory structure for the ramdisk image. */ static struct dir_struct *rdhostdir(parent, path, mtime) struct dir_struct *parent; char *path; time_t mtime; { DIR *dirp; char *cp; char tmppath[MAXNAMLEN + 1]; struct stat sbuf; struct dirent *ent; struct dir_struct *dsp; struct dir_struct *tmpdsp; struct file_struct *fsp; /* Initialize directory structure */ dsp = (struct dir_struct *)nbmalloc(sizeof(struct dir_struct) + strlen(path)); strcpy(dsp->src.path, path); if (parent != NULL) { if ((cp = strrchr(path, '/')) == NULL) cp = path; else cp++; if (*cp == '.') { dsp->attrib |= ATTR_HIDDEN; cp++; } dsp->attrib = ATTR_DIR; cvtname(parent, &(dsp->name), cp); gettime(mtime, &(dsp->date), &(dsp->time)); } else { dsp->attrib = ATTR_DIR; gettime(time(NULL), &(dsp->date), &(dsp->time)); } dsp->subdirnum = 0; dsp->filenum = 0; dsp->lfnnum = 0; dsp->totsize = 0L; dsp->subdirs = NULL; dsp->files = NULL; dsp->next = NULL; /* Open directory */ if ((dirp = opendir(path)) == NULL) { prnerr1("unable to open directory %s", path); exit(EXIT_OPENDIR); } /* Read in whole directory */ while ((ent = readdir(dirp)) != NULL) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; sprintf(tmppath, "%s/%s", path, ent->d_name); if (stat(tmppath, &sbuf) != 0) { prnerr1("unable to stat file %s", tmppath); exit(EXIT_STAT); } if ((sbuf.st_mode & S_IFMT) == S_IFREG) { fsp = (struct file_struct *)nbmalloc (sizeof(struct file_struct) + strlen(tmppath)); fsp->attrib = 0; cp = ent->d_name; if (*cp == '.') { fsp->attrib |= ATTR_HIDDEN; cp++; } cvtname(dsp, &(fsp->name), cp); if (!(sbuf.st_mode & S_IWRITE)) fsp->attrib |= ATTR_READONLY; if (!strncmp(fsp->name.ext, "SYS", 3) && (!strncmp(fsp->name.name, "IO ", 8) || !strncmp(fsp->name.name, "MSDOS ", 8) || !strncmp(fsp->name.name, "KERNEL ", 8))) fsp->attrib |= ATTR_HIDDEN + ATTR_SYSTEM + ATTR_READONLY; if (!strncmp(fsp->name.ext, "COM", 3) && (!strncmp(fsp->name.name, "IBMBIO ", 8) || !strncmp(fsp->name.name, "IBMDOS ", 8))) fsp->attrib |= ATTR_HIDDEN + ATTR_SYSTEM + ATTR_READONLY; strcpy(fsp->src.path, tmppath); gettime(sbuf.st_mtime, &(fsp->date), &(fsp->time)); fsp->size = (unsigned long)sbuf.st_size; fsp->next = dsp->files; dsp->totsize += howmany(fsp->size, 1024); dsp->lfnnum += fsp->name.lfn_num; dsp->files = fsp; dsp->filenum++; } else if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { tmpdsp = rdhostdir(dsp, tmppath, sbuf.st_mtime); tmpdsp->next = dsp->subdirs; dsp->totsize += tmpdsp->totsize; dsp->lfnnum += tmpdsp->name.lfn_num; dsp->subdirs = tmpdsp; dsp->subdirnum++; } } /* Add size of directory to total size, except for root directory */ if (parent != NULL) dsp->totsize += howmany(DIR_ENTRIES(dsp) * sizeof(struct dos_dir), 1024); /* Close directory and return */ closedir(dirp); return(dsp); } /*************************************************************************** Routines to open and close the host directory ***************************************************************************/ /* * Open a host directory and read it recursively */ void hostopen(name) char *name; { struct boot_record *bp; union { time_t curtime; unsigned long serno; } serial; /* Read the host root directory */ root_dir = rdhostdir(NULL, name, (time_t)0); /* Prepare the boot block */ boot_size = roundup(boot_data_size, SECTSIZE); boot_block = (__u8 *)nbmalloc(boot_size); memcpy(boot_block, boot_data, boot_data_size); bp = (struct boot_record *)boot_block; assign(bp->reserved_sect, htot(boot_size / SECTSIZE)); bytecpy("MSDOS5.0", bp->oem_name, sizeof(bp->oem_name)); /* We use the current UNIX time as the serial number */ serial.serno = 0; time(&serial.curtime); assign(bp->vol_num.low, htot(low_word(serial.serno))); assign(bp->vol_num.high, htot(high_word(serial.serno))); } /* * Close host directory */ void hostclose() { if (boot_block != NULL) free(boot_block); } /* * Copy a file from the host directory into the output file */ void hostcopy(clustsize, handle, fsp) int clustsize; int handle; struct file_struct *fsp; { __u8 *buf; unsigned long num; int eof = FALSE; int readsize; int infile; if ((infile = open(fsp->src.path, O_RDONLY | O_BINARY)) < 0) { perror(fsp->src.path); exit(EXIT_OPEN); } buf = (__u8 *)nbmalloc(clustsize); for (num = 0; num < fsp->clustnum; num++) { memset(buf, 0, clustsize); if (!eof) { readsize = nbread(buf, clustsize, infile); eof = (readsize < clustsize); } (void)nbwrite(buf, clustsize, handle); } close(infile); free(buf); }