/*
* hostfs.c - Routines for reading the ramdisk contents from a host
* filesystem
*
* Copyright (C) 2002-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* 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 <common.h>
#include <nblib.h>
#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);
}
syntax highlighted by Code2HTML, v. 0.9.1