home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
diskutil
/
mtools
/
mread.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-05
|
8KB
|
346 lines
/*
* Read (copy) an MSDOS file to Unix
*
* Emmet P. Gray US Army, HQ III Corps & Fort Hood
* ...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
* fthood!egray@uxc.cso.uiuc.edu Directorate of Engineering & Housing
* Environmental Management Office
* Fort Hood, TX 76544-5057
*/
#define LOWERCASE
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef BSD
#include <sys/time.h>
#else /* BSD */
#include <time.h>
#endif /* BSD */
#include "msdos.h"
#include "patchlevel.h"
int fd = -1; /* the file descriptor for the device */
int dir_start; /* starting sector for directory */
int dir_len; /* length of directory (in sectors) */
int dir_entries; /* number of directory entries */
int clus_size; /* cluster size (in sectors) */
char *mcwd; /* the Current Working Directory */
int fat_error; /* FAT error detected? */
static void set_mtime();
static FILE *open_file();
static long conv_stamp();
main(argc, argv)
int argc;
char *argv[];
{
FILE *fp;
extern int optind;
extern char *optarg;
int i, ismatch, entry, single, c, oops, preserve, nowarn, textmode;
unsigned int fat;
long size, mtime;
char *filename, *newfile, *get_name(), *unix_name(), *pathname;
char *get_path(), *target, tmp[MAX_PATH], *strcat(), *strcpy(), drive;
char get_drive(), last_drive, *fix_mcwd(), *s;
void exit();
struct directory *dir, *dir_read();
struct stat stbuf;
/* get command line options */
oops = 0;
preserve = 0;
nowarn = 0;
textmode = 0;
while ((c = getopt(argc, argv, "tnmv")) != EOF) {
switch (c) {
case 't':
textmode = 1;
break;
case 'n':
nowarn = 1;
break;
case 'm':
preserve = 1;
break;
case 'v': /* dummy option for mcopy */
break;
default:
oops = 1;
break;
}
}
if (oops || (argc - optind) < 2) {
fprintf(stderr, "Mtools version %s, dated %s\n", VERSION, DATE);
fprintf(stderr, "Usage: %s [-tnm] msdosfile unixfile\n", argv[0]);
fprintf(stderr, " %s [-tnm] msdosfile [msdosfiles...] unixdirectory\n", argv[0]);
exit(1);
}
last_drive = 'x';
mcwd = fix_mcwd();
/* only 1 file to copy... */
single = 1;
target = argv[argc - 1];
/* ...unless last arg is a directory */
if (!stat(target, &stbuf)) {
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
single = 0;
}
/* too many arguments */
if (single && (argc - optind) != 2) {
fprintf(stderr, "%s: Too many arguments or destination directory omitted\n", argv[0]);
exit(1);
}
for (i = optind; i < argc - 1; i++) {
drive = get_drive(argv[i]);
if (drive != last_drive) {
if (init(drive, 0)) {
fprintf(stderr, "%s: Cannot initialize '%c:'\n", argv[0], drive);
continue;
}
last_drive = drive;
}
filename = get_name(argv[i]);
pathname = get_path(argv[i]);
if (subdir(drive, pathname))
continue;
ismatch = 0;
for (entry = 0; entry < dir_entries; entry++) {
dir = dir_read(entry);
/* if empty */
if (dir->name[0] == 0x0)
break;
/* if erased */
if (dir->name[0] == 0xe5)
continue;
/* if dir or volume label */
if ((dir->attr & 0x10) || (dir->attr & 0x08))
continue;
newfile = unix_name(dir->name, dir->ext);
/* if single file */
if (single) {
if (!strcmp(newfile, filename)) {
fat = dir->start[1] * 0x100 + dir->start[0];
size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0];
if (preserve)
mtime = conv_stamp(dir->time, dir->date);
else
mtime = 0L;
if ((fp = open_file(target, nowarn))) {
if (file_read(fp, fat, textmode, 0, size)) {
fclose(fp);
break;
}
fclose(fp);
set_mtime(target, mtime);
}
ismatch = 1;
break;
}
}
/* if multiple files */
else {
if (match(newfile, filename)) {
fat = dir->start[1] * 0x100 + dir->start[0];
size = dir->size[3] * 0x1000000L + dir->size[2] * 0x10000L + dir->size[1] * 0x100 + dir->size[0];
if (preserve)
mtime = conv_stamp(dir->time, dir->date);
else
mtime = 0L;
printf("Copying %s\n", newfile);
#ifdef LOWERCASE
s = newfile;
while (*s) {
if (isupper(*s))
*s = tolower(*s);
s++;
}
#endif /* LOWERCASE */
strcpy(tmp, target);
strcat(tmp, "/");
strcat(tmp, newfile);
if ((fp = open_file(tmp, nowarn))) {
if (file_read(fp, fat, textmode, 0, size)) {
fclose(fp);
break;
}
fclose(fp);
set_mtime(tmp, mtime);
}
ismatch = 1;
}
}
}
if (fat_error)
break;
if (!ismatch)
fprintf(stderr, "%s: File \"%s\" not found\n", argv[0], filename);
}
close(fd);
exit(0);
}
/*
* Open the named Unix file for write.
*/
static FILE *
open_file(target, nowarn)
char *target;
int nowarn;
{
static FILE *fp;
char ans[10];
struct stat stbuf;
if (!nowarn) {
if (!access(target, 0)) {
/* CONSTCOND */
while (1) {
printf("File \"%s\" exists, overwrite (y/n) ? ", target);
gets(ans);
if (ans[0] == 'n' || ans[0] == 'N')
return(NULL);
if (ans[0] == 'y' || ans[0] == 'Y')
break;
}
/* sanity checking */
if (!stat(target, &stbuf)) {
if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
fprintf(stderr, "\"%s\" is not a regular file\n", target);
return(NULL);
}
}
}
}
if (!(fp = fopen(target, "w"))) {
fprintf(stderr, "Can't open \"%s\" for write\n", target);
return(NULL);
}
return(fp);
}
/*
* Convert an MSDOS time & date stamp to the Unix time() format
*/
static long
conv_stamp(time_field, date_field)
unsigned char *time_field, *date_field;
{
#ifdef BSD
struct timeval tv;
struct timezone tz;
#else /* BSD */
extern long timezone;
void tzset();
#endif /* BSD */
struct tm *tmbuf, *localtime();
int year, mon, mday, hour, min, sec, old_leaps;
long answer, sec_year, sec_mon, sec_mday, sec_hour, sec_min, sec_leap;
long tzone, dst;
static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304,
334};
/* dissect the parts */
year = (date_field[1] >> 1) + 1980;
mon = (((date_field[1] & 0x1) << 3) + (date_field[0] >> 5));
mday = date_field[0] & 0x1f;
hour = time_field[1] >> 3;
min = (((time_field[1] & 0x7) << 3) + (time_field[0] >> 5));
sec = (time_field[0] & 0x1f) * 2;
/* how many previous leap years */
old_leaps = (year - 1972) / 4L;
sec_leap = old_leaps * 24L * 60L * 60L;
/* back off 1 day if before 29 Feb */
if (!(year % 4) && mon < 3)
sec_leap -= 24L * 60L * 60L;
sec_year = (year - 1970) * 365L * 24L * 60L * 60L;
sec_mon = month[mon - 1] * 24L * 60L * 60L;
sec_mday = mday * 24L * 60L * 60L;
sec_hour = hour * 60L * 60L;
sec_min = min * 60L;
/* correct for Time Zone */
#ifdef BSD
gettimeofday(&tv, &tz);
tzone = tz.tz_minuteswest * 60L;
#else /* BSD */
tzset();
tzone = timezone;
#endif /* BSD */
answer = sec_leap + sec_year + sec_mon + sec_mday + sec_hour + sec_min + sec + tzone;
/* correct for Daylight Saving Time */
tmbuf = localtime(&answer);
dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
answer += dst;
return(answer);
}
/*
* Preserve the file modification times after the fclose()
*/
static void
set_mtime(target, mtime)
char *target;
long mtime;
{
#ifdef BSD
struct timeval tv[2];
if (mtime != 0L) {
tv[0].tv_sec = mtime;
tv[0].tv_usec = 0;
tv[1].tv_sec = mtime;
tv[1].tv_usec = 0;
utimes(target, tv);
}
#else /* BSD */
struct {
time_t actime;
time_t modtime;
} utbuf;
if (mtime != 0L) {
utbuf.actime = mtime;
utbuf.modtime = mtime;
utime(target, &utbuf);
}
#endif /* BSD */
return;
}
/*
* stubs for read-only programs
*/
void
disk_flush()
{
extern int disk_dirty;
disk_dirty = 0;
return;
}
void
dir_flush()
{
extern int dir_dirty;
dir_dirty = 0;
return;
}