home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
SRC
/
msdos_diskaccess.lzh
/
MS_DISK_ACCESS
/
mwrite.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-08
|
11KB
|
479 lines
/*
* Write (copy) a Unix file to MSDOS
*
* Emmet P. Gray US Army, HQ III Corps & Fort Hood
* ...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
* Directorate of Engineering & Housing
* Environmental Management Office
* Fort Hood, TX 76544-5057
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "msdos.h"
int fd; /* the file descriptor for the floppy */
int dir_start; /* starting sector for directory */
int dir_len; /* length of directory (in sectors) */
int dir_entries; /* number of directory entries */
int dir_chain[25]; /* chain of sectors in directory */
int clus_size; /* cluster size (in sectors) */
unsigned long clus_len; /* The cluster lenght in bytes */
int fat_len; /* length of FAT table (in sectors) */
int num_clus; /* number of available clusters */
unsigned char *fatbuf; /* the File Allocation Table */
char *mcwd; /* the Current Working Directory */
static char *outbuf; /* The output buffer */
int bufsiz; /* Buffer size */
int maxcontig; /* Max contiguous clusters per write call */
long size; /* Size of DOS file */
int full = 0;
int textmode = 0;
int nowarn = 0;
int need_nl = 0;
extern union bootblock bb;
extern short is_tos0;
void exit(), zapit(), writefat(), writedir(), free(), perror(), move();
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
extern char *optarg;
int i, entry, ismatch, nogo, slot, start, dot, single;
int root, c, oops, verbose, first, mod_time;
char *filename, *newfile, tname[9], text[4], *fixname(), *getname();
char *unixname(), ans[10], *strncpy(), *pathname, *getpath(), *fixed;
char tmp[MAX_PATH], *target, *strcat(), *strcpy();
struct directory *dir, *search(), *writeit();
if (init(2)) {
fprintf(stderr, "mwrite: Cannot initialize diskette\n");
exit(1);
}
/* get command line options */
oops = 0;
verbose = 0;
mod_time = 0;
while ((c = getopt(argc, argv, "tnvm")) != EOF) {
switch(c) {
case 't':
textmode = 1;
break;
case 'n':
nowarn = 1;
break;
case 'v':
verbose = 1;
break;
case 'm':
mod_time = 1;
break;
default:
oops = 1;
break;
}
}
if (oops || (argc - optind) < 2) {
fprintf(stderr, "Usage: mwrite [-tnv] unixfile msdosfile\n");
fprintf(stderr, " or mwrite [-tnv] unixfile [unixfiles...] msdosdirectory\n");
exit(1);
}
root = 0;
if (!strcmp(argv[argc-1], "/") || !strcmp(argv[argc-1], "\\"))
root = 1;
filename = getname(argv[argc-1]);
pathname = getpath(argv[argc-1]);
/* test if path is ok first */
if (subdir(pathname))
exit(1);
/* test if last argv is a dir */
if (isdir(filename) || root) {
if (!strlen(pathname)) {
/* don't alter the presence or */
/* absence of a leading separator */
strcpy(tmp, filename);
}
else {
strcpy(tmp, pathname);
strcat(tmp, "/");
strcat(tmp, filename);
}
/* subdir is not recursive */
subdir(tmp);
single = 0;
}
else {
single = 1;
/* too many arguments */
if ((argc - optind) != 2) {
fprintf(stderr, "mwrite: too many arguments or destination directory omitted\n");
exit(1);
}
}
clus_len = clus_size * MSECSIZ;
/* Round cylinder up to nearest cluster multiple */
bufsiz = NTRACK(bb.sb) * NSECT(bb.sb);
maxcontig = (bufsiz += clus_size - (--bufsiz) % clus_size) / clus_size;
bufsiz *= MSECSIZ;
if( (outbuf = (char *)malloc(bufsiz)) == NULL) {
fprintf(stderr, "mwrite: Cannot allocate I/O buffer\n");
perror("malloc") ;
exit(1);
}
for (i=optind; i<argc-1; i++) {
if (single)
fixed = fixname(argv[argc-1], verbose);
else
fixed = fixname(argv[i], verbose);
strncpy(tname, fixed, 8);
strncpy(text, fixed+8, 3);
tname[8] = '\0';
text[3] = '\0';
target = unixname(tname, text);
/* see if exists and get slot */
ismatch = 0;
slot = -1;
dot = 0;
nogo = 0;
first = 1;
for (entry=0; entry<dir_entries; entry++) {
dir = search(entry);
/* save the '.' entry info */
if (first) {
first = 0;
if ((dir->attr & 0x10) && dir->name[0] == '.') {
dot = dir->start[1]*0x100 + dir->start[0];
continue;
}
}
/* is empty */
if (dir->name[0] == 0x0) {
if (slot < 0)
slot = entry;
break;
}
/* is erased */
if (dir->name[0] == 0xe5) {
if (slot < 0)
slot = entry;
continue;
}
/* is dir or volume lable */
if ((dir->attr & 0x10) || (dir->attr & 0x08))
continue;
strncpy(tname, (char *) dir->name, 8);
strncpy(text, (char *) dir->ext, 3);
tname[8] = '\0';
text[3] = '\0';
newfile = unixname(tname, text);
/* if file exists, delete it first */
if (!strcmp(target, newfile)) {
ismatch = 1;
start = dir->start[1]*0x100 + dir->start[0];
if (nowarn) {
zapit(start);
dir->name[0] = 0xe5;
writedir(entry, dir);
if (slot < 0)
slot = entry;
} else {
while (1) {
printf("File \"%s\" exists, overwrite (y/n) ? ", target);
gets(ans);
if (ans[0] == 'n' || ans[0] == 'N') {
nogo = 1;
break;
}
if (ans[0] == 'y' || ans[0] == 'Y') {
zapit(start);
dir->name[0] = 0xe5;
writedir(entry, dir);
if (slot < 0)
slot = entry;
break;
}
}
}
}
free(newfile);
if (ismatch)
break;
}
if (nogo) { /* chickened out... */
free(fixed);
free(target);
continue;
}
/* no '.' entry means root directory */
if (dot == 0 && slot < 0) {
fprintf(stderr, "mwrite: No directory slots\n");
exit(1);
}
/* make the directory grow */
if (dot && slot < 0) {
if (grow(dot)) {
fprintf(stderr, "mwrite: Disk full\n");
exit(1);
}
/* first entry in 'new' directory */
slot = entry;
}
if (!single)
printf("Copying %s\n", target);
/* write the file */
if (dir = writeit(fixed, argv[i], verbose, mod_time))
writedir(slot, dir);
free(fixed);
free(target);
if (full) {
fprintf(stderr, "mwrite: Disk Full\n");
break;
}
if (single)
break;
}
/* write FAT sectors */
writefat();
close(fd);
exit(0);
}
/*
* Open the named file for write, create the cluster chain, return the
* directory structure or NULL on error.
*/
struct directory *
writeit(fixed, path, verbose, mod_time)
char *fixed, *path;
int verbose, mod_time;
{
FILE *fp;
int fat, firstfat, oldfat, curfat, chain;
long time(), now;
struct directory *dir, *mk_entry();
struct stat stbuf;
if (stat(path, &stbuf) < 0) {
fprintf(stderr, "mwrite: Can't stat \"%s\"\n", path);
return(NULL);
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
if (verbose)
fprintf(stderr, "mwrite: \"%s\" is a directory\n", path);
return(NULL);
}
if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
fprintf(stderr, "mwrite: \"%s\" is not a regular file\n", path);
return(NULL);
}
/* preserve mod time? */
if (mod_time)
now = stbuf.st_mtime;
else
time(&now);
if (!(fp = fopen(path, "r"))) {
fprintf(stderr, "mwrite: Can't open \"%s\" for read\n", path);
return(NULL);
}
#ifdef OSK
fp->_bufsiz = 20480;
#endif
#ifdef HAVE_SETBUFFER
setbuffer(fp,inbuf,bufsiz) ;
#endif
fat = oldfat = firstfat = nextfat(size=0);
for(;;) {
if (fat == -1) {
full = 1;
if(size)
zapit(firstfat) ;
return(NULL) ;
}
/*
* grab a bunch of contiguous FAT slots
* curfat -> 1 + last grabbed slot.
* FIX ME!
* someone should try to read and cache a cylinder on
* first write access, do write to memory until a new
* cylinder is requested.
* The overhead is higher, but should be more robust under
* fragmentation.
* In mread this may even be a win! (Also see comments
* in putclusters() )
*/
for(curfat=fat;
++curfat < fat + maxcontig &&
nextfat(curfat-1) == curfat;) ;
if((oldfat=putclusters(oldfat,fat, curfat, fp)) == 0)
break ;
fat = nextfat(oldfat);
}
fclose(fp);
dir = mk_entry(fixed, 0x20, firstfat, size, now);
return(dir);
}
/*
* Write to the cluster chain from the named Unix file descriptor.
* N.B. all the clusters in the chain are contiguous.
*/
static int writepos = -1;
int
putclusters(chain,start,end,fp)
FILE *fp;
{
static int blk;
int c, nclust, current, eof=0;
int buflen = ( end - start ) * MSECSIZ * clus_size ;
register char *tbuf=outbuf;
blk = (start - 2)*clus_size + dir_start + dir_len;
if (textmode) { /* '\n' to '\r\n' translation */
current = 0;
if (need_nl) {
tbuf[current++] = '\l';
need_nl = 0;
}
while (current < buflen) {
if ((c = fgetc(fp)) == EOF) {
/* put a file EOF marker */
tbuf[current++] = 0x1a;
++eof;
break;
}
if (c == '\n') {
tbuf[current++] = c;
c = '\l';
/* if at the end of the buffer */
if (current == buflen) {
need_nl++;
break;
}
}
tbuf[current++] = c;
}
}
else {
/*
* FIX ME!
* The kernel guarantees to satisfy REGULAR file
* read requests unless EOF,
* This code will break on pipes, sockets, etc.
* To fix one should do something akin to the
* "atomic" I/O of Berkeley multiprocess dump, which loops
* on read/write requests until EOF or enough data has been
* gathered. If you want to do this please change
* all instances of read/write with Read/Write and
* add an offset parameter to allow arbitrary sorting/queuing
* etc, behind the back of the DOS code. This will
* make the overall code much cleaner, and we
* can put Read/Write in a sysdep.c where they belong.
* Also one may want to memory map the input file. Avoiding
* redundant copying to user space, this is for perfectionists
* as the floppy is much slower than UNIX disks, so gains
* here are small.
*/
if ( (current = fread(outbuf, 1, buflen, fp)) < 0) {
perror("putcluster: fread");
exit(1);
}
if ( current != buflen )
++eof;
}
size += current;
if (current == 0) {
putfat(chain,0xfff) ;
return(0) ;
}
putfat(chain,start) ;
/*
* chain the clusters, we are about to overwrite
* making sure to terminate the chain.
*/
for(end=start; current > clus_len ; ++end) {
putfat(end,end+1);
current -= clus_len ;
}
putfat(end, 0xfff) ;
if ( blk != writepos )
move(blk);
nclust=(end-start)+1;
writepos = eof ? -1 : blk + nclust*clus_size;
buflen = nclust * clus_size * MSECSIZ;
if (is_tos0) {
unsigned rp, pos;
pos = lseek(fd, 0, 1);
for(rp = 0; rp < buflen; rp += 1024) {
lseek(fd, pos+rp, 0);
write(fd, outbuf+pos, 512);
}
for(rp = 512; rp < buflen; rp += 1024) {
lseek(fd, pos+rp, 0);
write(fd, outbuf+pos, 512);
}
lseek(fd, pos+buflen, 0);
} else {
if (write(fd, outbuf, buflen) != buflen) {
perror("putclusters: write");
exit(1);
}
}
return(eof ? 0: end) ;
}
/*
* Returns next free cluster or -1 if none are available.
*/
int
nextfat(last)
int last;
{
register int i;
for (i=last+1; i<num_clus+2; i++) {
if (!getfat(i))
return(i);
}
return(-1);
}