mirror of
https://github.com/PDP-10/klh10.git
synced 2026-03-09 04:09:38 +00:00
762 lines
18 KiB
C
762 lines
18 KiB
C
/* VDKFMT.C - Utility to copy or format virtual disks.
|
||
*/
|
||
/* $Id: vdkfmt.c,v 2.6 2002/05/21 09:51:26 klh Exp $
|
||
*/
|
||
/* Copyright © 1994, 2001 Kenneth L. Harrenstien
|
||
** All Rights Reserved
|
||
**
|
||
** This file is part of the KLH10 Distribution. Use, modification, and
|
||
** re-distribution is permitted subject to the terms in the file
|
||
** named "LICENSE", which contains the full text of the legal notices
|
||
** and should always accompany this Distribution.
|
||
**
|
||
** This software is provided "AS IS" with NO WARRANTY OF ANY KIND.
|
||
**
|
||
** This notice (including the copyright and warranty disclaimer)
|
||
** must be included in all copies or derivations of this software.
|
||
*/
|
||
/*
|
||
* $Log: vdkfmt.c,v $
|
||
* Revision 2.6 2002/05/21 09:51:26 klh
|
||
* Change protos for vdk_read, vdk_write
|
||
*
|
||
* Revision 2.5 2001/11/19 10:51:43 klh
|
||
* Bugfix: was freeing d_path which is now static.
|
||
*
|
||
* Revision 2.4 2001/11/10 21:28:59 klh
|
||
* Final 2.0 distribution checkin
|
||
*
|
||
*/
|
||
|
||
/* VDKFMT is mainly used to copy or format virtual disks.
|
||
** later it may become a general-purpose utility for managing
|
||
** KLH10 disk packs.
|
||
**
|
||
*/
|
||
|
||
#include <string.h>
|
||
#include <fcntl.h>
|
||
#include <signal.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h> /* exit() */
|
||
#include <stdarg.h>
|
||
#include <errno.h>
|
||
#include <sys/file.h> /* For open() flags */
|
||
|
||
#include "rcsid.h"
|
||
#include "cenv.h"
|
||
#include "osdsup.h"
|
||
#include "vdisk.h" /* Include virtual disk stuff */
|
||
|
||
#if CENV_SYS_UNIX
|
||
# include <unistd.h> /* Basic Unix syscalls */
|
||
# include <sys/types.h>
|
||
# include <sys/ioctl.h>
|
||
# define NULLDEV "/dev/null"
|
||
# define FD_STDIN 0
|
||
# define FD_STDOUT 1
|
||
#endif
|
||
|
||
#if HAVE_ERRNO_H
|
||
# include <errno.h>
|
||
#endif
|
||
|
||
#define FNAMSIZ 200
|
||
|
||
#define TRUE 1
|
||
#define FALSE 0
|
||
|
||
#ifdef RCSID
|
||
RCSID(vdkfmt_c,"$Id: vdkfmt.c,v 2.6 2002/05/21 09:51:26 klh Exp $")
|
||
#endif
|
||
|
||
/* Disk type configuration params.
|
||
** All of these numbers assume drives using 18-bit formatting.
|
||
** (16-bit formatting has more sectors per track)
|
||
*/
|
||
static struct diskconf {
|
||
char dcf_name[8]; /* Drive type name (RP06, etc) */
|
||
int dcf_type; /* Type bits for type register */
|
||
int dcf_nwds; /* Words/Sector */
|
||
int dcf_nsec; /* Sectors/Track */
|
||
int dcf_ntrk; /* Tracks/Cylinder */
|
||
int dcf_ncyl; /* Cylinders/Drive */
|
||
} diskconfs[] = {
|
||
/* wrd sec trk cyl Cyl+maint totsec totmaintsec */
|
||
{ "RP02", 0, 128, 10, 20, 203 }, /* 200+3 40000 40,600 */
|
||
{ "RP03", 0, 128, 10, 20, 403 }, /* 400+3 80000 80,600 */
|
||
|
||
{ "RP04", 0, 128, 20, 19, 411 }, /* 406+5 154280 156,180 */
|
||
{ "RP05", 0, 128, 20, 19, 411 }, /* " " " */
|
||
{ "RP06", 0, 128, 20, 19, 815 }, /* 810+5 307800 309,700 */
|
||
{ "RP07", 0, 128, 43, 32, 630 }, /* 629+1 865504 866,880 */
|
||
{ "RM03", 0, 128, 30, 5, 823 }, /* 821+2 123150 123,450 */
|
||
{ "RM02", 0, 128, 30, 5, 823 }, /* " " " */
|
||
{ "RM05", 0, 128, 30, 19, 823 }, /* 821+2 467970 469,110 */
|
||
{ "RM80", 0, 128, 30, 14, 561 }, /* 559+2 234780 235,620 */
|
||
|
||
{ "" }
|
||
};
|
||
/* RP07 doc p.6-23 says addressing params are:
|
||
** Mode Cyl Head/Track Sector(18) Sector(16)
|
||
** Functional: 630 32 43 50
|
||
** Diagnostic: 632 32 43 50
|
||
*/
|
||
|
||
/* In ITS:
|
||
RP06 was 812+3
|
||
RP07 was 627+3
|
||
RM03 was 821+2
|
||
RM05 was 820
|
||
RM80 was 556+3
|
||
*/
|
||
|
||
/* VDKFMT parameters */
|
||
|
||
char nusage[] = "\
|
||
Usage: vdkfmt <params>\n\
|
||
ip=<path> Input disk device/file:\n\
|
||
op=<path> Output disk device\n\
|
||
ifmt=<fmt> format of input pack data\n\
|
||
ofmt=<fmt> format of output pack data\n\
|
||
dt=<type> Type of drive (RP06, etc)\n\
|
||
log=<path> Log filespec (optional, defaults to stderr)\n\
|
||
verbose Verbose (optional)\n\
|
||
";
|
||
|
||
|
||
|
||
/* Switch parameters */
|
||
int sw_tdtest;
|
||
int sw_peot;
|
||
int sw_verbose;
|
||
int sw_maxsec;
|
||
int sw_maxfile;
|
||
char *sw_logpath;
|
||
FILE *logfile;
|
||
|
||
#define DBGFLG sw_verbose
|
||
|
||
struct devdk {
|
||
char *d_pname; /* Print name, "In" or "Out" */
|
||
char *d_path; /* Disk drive path spec */
|
||
int d_isdisk; /* NZ if hardware device, else virtual */
|
||
int d_fmt; /* Format to use */
|
||
long d_totsec; /* Total # sectors */
|
||
struct vdk_unit d_vdk; /* Virtual disk info */
|
||
struct diskconf d_dcf;
|
||
};
|
||
struct devdk dvi = { "In" };
|
||
struct devdk dvo = { "Out" };
|
||
|
||
/* Values for d_isdisk */
|
||
#define MTYP_NULL 0 /* Null device */
|
||
#define MTYP_VIRT 1 /* Virtual disk */
|
||
#define MTYP_HARD 2 /* Hard raw disk partition */
|
||
|
||
char *mtypstr[] = {
|
||
"nulldev",
|
||
"virtual",
|
||
"hard"
|
||
};
|
||
|
||
int cmdsget(int ac, char **av);
|
||
int docopy(void);
|
||
int zerosector(w10_t *wp, int nwds);
|
||
|
||
int devopen(struct devdk *d, int wrtf);
|
||
int devclose(struct devdk *d);
|
||
int devread(struct devdk *d, long int daddr, w10_t *buff);
|
||
int devwrite(struct devdk *d, long int daddr, w10_t *buff);
|
||
|
||
void swerror(char *fmt, ...);
|
||
void efatal(char *errmsg);
|
||
void errhan(struct vdk_unit *t, char *s);
|
||
|
||
/* For now, must include VDISK source directly, so as to avoid compile-time
|
||
** switch conflicts (eg with KLH10).
|
||
*/
|
||
#include "vdisk.c"
|
||
|
||
|
||
static int partyp(char *cp, struct diskconf *dcf)
|
||
{
|
||
register struct diskconf *dc;
|
||
|
||
for (dc = diskconfs; dc->dcf_name[0]; ++dc) {
|
||
if (strcasecmp(cp, dc->dcf_name) == 0) {
|
||
*dcf = *dc; /* Found match, won */
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE; /* Unknown disk type */
|
||
}
|
||
|
||
/* Parse disk format -- something that VDISK understands.
|
||
*/
|
||
static char *fmttab[] = {
|
||
# define vdk_fmt(i,n,c,s,f,t) n
|
||
VDK_FORMATS
|
||
# undef vdk_fmt
|
||
};
|
||
|
||
static int parfmt(char *cp, int *afmt)
|
||
{
|
||
register int i;
|
||
|
||
for (i = 0; i < VDK_FMT_N; ++i) {
|
||
if (strcasecmp(cp, fmttab[i]) == 0) {
|
||
*afmt = i; /* Found match, won */
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE; /* Unknown disk format */
|
||
}
|
||
|
||
/* Error handling */
|
||
|
||
/* Copied from OSDSUP.C */
|
||
|
||
char *
|
||
os_strerror(int err)
|
||
{
|
||
if (err == -1 && errno != err)
|
||
return os_strerror(errno);
|
||
#if HAVE_STRERROR
|
||
return strerror(err);
|
||
#else
|
||
# if HAVE_SYS_ERRLIST
|
||
{
|
||
# if DECL_SYS_ERRLIST
|
||
extern int sys_nerr;
|
||
extern char *sys_errlist[];
|
||
# endif
|
||
if (0 < err && err <= sys_nerr)
|
||
return sys_errlist[err];
|
||
}
|
||
# endif /* HAVE_SYS_ERRLIST */
|
||
if (err == 0)
|
||
return "No error";
|
||
else {
|
||
static char ebuf[30];
|
||
sprintf(ebuf, "Unknown-error-%d", err);
|
||
return ebuf;
|
||
}
|
||
#endif /* !HAVE_STRERROR */
|
||
}
|
||
|
||
void errhan(struct vdk_unit *t, char *s)
|
||
{
|
||
fprintf(logfile, "; %s: %s\n", t->dk_devname, s);
|
||
}
|
||
|
||
|
||
void efatal(char *errmsg) /* print error message and exit */
|
||
/* error message string */
|
||
{
|
||
fflush(stdout);
|
||
fprintf(logfile, "\n?%s\n",errmsg);
|
||
exit(1);
|
||
}
|
||
|
||
|
||
int
|
||
main(int argc, char **argv)
|
||
{
|
||
int ret;
|
||
|
||
logfile = stderr;
|
||
signal(SIGINT, exit); /* Allow int to terminate log files etc */
|
||
|
||
dvi.d_fmt = dvo.d_fmt = -1;
|
||
|
||
if ((ret = cmdsget(argc, argv))) /* Parse and handle command line */
|
||
exit(ret);
|
||
|
||
|
||
if (!sw_logpath)
|
||
logfile = stderr;
|
||
else {
|
||
if ((logfile = fopen(sw_logpath, "w")) == NULL) {
|
||
logfile = stderr;
|
||
fprintf(logfile, "; Cannot open log file \"%s\", using stderr.\n",
|
||
sw_logpath);
|
||
}
|
||
}
|
||
|
||
/* Set up defaults for devices, and log all params if requested */
|
||
dvi.d_totsec = dvo.d_totsec =
|
||
dvi.d_dcf.dcf_nsec *
|
||
dvi.d_dcf.dcf_ntrk *
|
||
dvi.d_dcf.dcf_ncyl;
|
||
if (sw_verbose) {
|
||
fprintf(logfile, "; Input disk spec \"%s\" (Type: %s) Format: %s\n",
|
||
dvi.d_path, mtypstr[dvi.d_isdisk],
|
||
fmttab[dvi.d_fmt]);
|
||
fprintf(logfile, "; Output disk spec \"%s\" (Type: %s) Format: %s\n",
|
||
dvo.d_path, mtypstr[dvo.d_isdisk],
|
||
fmttab[dvo.d_fmt]);
|
||
|
||
/* Show config info here */
|
||
fprintf(logfile, "; Drive type: %s\n", dvi.d_dcf.dcf_name);
|
||
fprintf(logfile, "; %ld sectors, %d wds/sec\n", dvi.d_totsec,
|
||
dvi.d_dcf.dcf_nwds);
|
||
fprintf(logfile, "; (%d secs, %d trks, %d cyls\n",
|
||
dvi.d_dcf.dcf_nsec,
|
||
dvi.d_dcf.dcf_ntrk,
|
||
dvi.d_dcf.dcf_ncyl);
|
||
if (sw_logpath)
|
||
fprintf(logfile, "; Using logging path %s\n", sw_logpath);
|
||
}
|
||
|
||
/* Open I/O files as appropriate */
|
||
if (!devopen(&dvi, FALSE)) /* Open for reading */
|
||
exit(1);
|
||
if (!devopen(&dvo, TRUE)) /* Open for writing */
|
||
exit(1);
|
||
|
||
/* Do it! */
|
||
fprintf(logfile, "; Copying from \"%s\" to \"%s\"...\n", dvi.d_path,
|
||
dvo.d_path ? dvo.d_path : NULLDEV);
|
||
if ((ret = docopy()))
|
||
ret = devclose(&dvo);
|
||
else (void) devclose(&dvo);
|
||
|
||
if (!ret) fprintf(logfile, "; Stopped unexpectedly.\n");
|
||
|
||
#if 0
|
||
{
|
||
register struct devdk *d;
|
||
for (d = &dvi; d; d = (d == &dvi) ? &dvo : NULL) {
|
||
if (d->d_isdisk)
|
||
fprintf(logfile, "; %s: %d+%d errs, %d secs, %ld bytes\n",
|
||
d->d_pname, d->mta_herr, d->mta_serr,
|
||
d->d_secs, d->d_tloc);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
fclose(logfile);
|
||
exit(ret ? 0 : 1);
|
||
}
|
||
|
||
static char pagsym[4] = { '.', '-', '=', '#'};
|
||
|
||
int docopy(void)
|
||
{
|
||
int err;
|
||
long nsect = 0;
|
||
w10_t wbuff[512];
|
||
int nwrt = 0;
|
||
|
||
if (DBGFLG)
|
||
fprintf(logfile, "; Pages:\n");
|
||
|
||
for (; nsect <= dvi.d_totsec;) {
|
||
|
||
err = devread(&dvi, nsect, wbuff); /* Get a sector */
|
||
if (!err) {
|
||
fprintf(logfile, "; Aborting loop, last err: %s\n", os_strerror(-1));
|
||
return 0;
|
||
}
|
||
|
||
/* See whether there's any data in sector or not.
|
||
** If none, don't write it out!
|
||
** Later, always write if device is "hard".
|
||
*/
|
||
if (!zerosector(wbuff, 128)) {
|
||
/* Copy results to output device */
|
||
nwrt++;
|
||
err = devwrite(&dvo, nsect, wbuff); /* Write a sector */
|
||
if (!err) {
|
||
fprintf(logfile, "; Aborting loop, last err: %s\n",
|
||
os_strerror(-1));
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
++nsect;
|
||
|
||
/* Hack to show nice pattern, one char per 4-sector page */
|
||
if (DBGFLG) {
|
||
if ((nsect & 03) == 0) {
|
||
putc(pagsym[nwrt&03], logfile);
|
||
nwrt = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (DBGFLG)
|
||
fprintf(logfile, "\n");
|
||
return TRUE;
|
||
}
|
||
|
||
int zerosector(register w10_t *wp, register int nwds)
|
||
{
|
||
for (; --nwds >= 0; ++wp)
|
||
if (LHGET(*wp) || RHGET(*wp))
|
||
return FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
int swerrs = 0;
|
||
|
||
void swerror(char *fmt, ...)
|
||
{
|
||
++swerrs;
|
||
{
|
||
va_list ap;
|
||
va_start(ap, fmt);
|
||
vfprintf(stderr, fmt, ap);
|
||
va_end(ap);
|
||
}
|
||
putc('\n', stderr);
|
||
}
|
||
|
||
int
|
||
cmdsget(int ac, char **av)
|
||
{
|
||
register char *cp, *arg;
|
||
register int plen;
|
||
struct devdk *d;
|
||
|
||
dvi.d_isdisk = dvo.d_isdisk = MTYP_NULL;
|
||
|
||
while (--ac > 0 && (cp = *++av)) {
|
||
if ((arg = strchr(cp, '='))) /* If arg furnished for param, */
|
||
*arg++ = '\0'; /* split arg off */
|
||
if ((plen = strlen(cp)) <= 0)
|
||
break; /* Bad param */
|
||
|
||
/* Now identify parameter. No case folding for now, sigh */
|
||
if (*cp == 'i' || *cp == 'o') {
|
||
/* Handle {i,o}{t,d,f,b} */
|
||
if (!arg) {
|
||
swerror("Parameter requires arg: \"%s\"", *av);
|
||
continue;
|
||
}
|
||
d = (*cp == 'i') ? &dvi : &dvo;
|
||
switch (*++cp) {
|
||
case 'p':
|
||
if (strlen(cp) > 2) break;
|
||
if (d->d_path) {
|
||
swerror("Param already specified: \"%s\"", *av);
|
||
continue;
|
||
}
|
||
d->d_path = arg;
|
||
switch (*++cp) {
|
||
case '\0':
|
||
case 'v': d->d_isdisk = MTYP_VIRT; continue;
|
||
case 'h': d->d_isdisk = MTYP_HARD; continue;
|
||
/* default falls thru to fail */
|
||
}
|
||
break;
|
||
case 'f':
|
||
if (strcmp(cp, "fmt")!=0)
|
||
break;
|
||
if (d->d_fmt != -1) {
|
||
swerror("Param already specified: \"%s\"", *av);
|
||
continue;
|
||
}
|
||
if (!parfmt(arg, &(d->d_fmt))) {
|
||
swerror("Unknown format: \"%s\"", arg);
|
||
continue;
|
||
}
|
||
continue;
|
||
|
||
/* Default just drops thru to fail */
|
||
}
|
||
swerror("Unknown parameter \"%s\"", *av);
|
||
continue;
|
||
}
|
||
|
||
if (strcmp(cp, "drive")==0 || strcmp(cp, "dt")==0) {
|
||
if (!partyp(arg, &(dvi.d_dcf)))
|
||
swerror("Unknown drive type: \"%s\"", arg ? arg : "");
|
||
continue;
|
||
|
||
} else if (strcmp(cp, "log")==0) {
|
||
if (!(sw_logpath = arg))
|
||
swerror("Bad arg to log: \"\"");
|
||
continue;
|
||
|
||
} else if (strcmp(cp, "verbose")==0 || strcmp(cp, "v")) {
|
||
sw_verbose = TRUE;
|
||
continue;
|
||
}
|
||
|
||
swerror("Unknown parameter \"%s\"\n%s", *av, nusage);
|
||
return 1;
|
||
}
|
||
|
||
/* Clean up params */
|
||
if (dvi.d_dcf.dcf_nwds)
|
||
dvo.d_dcf = dvi.d_dcf; /* Copy drive type params */
|
||
else
|
||
swerror("Drive type must be specified");
|
||
if (dvi.d_fmt == -1)
|
||
swerror("Input pack format must be specified");
|
||
if (dvo.d_fmt == -1)
|
||
swerror("Output pack format must be specified");
|
||
|
||
/* Check for any parameter errors */
|
||
if (swerrs) {
|
||
fprintf(stderr, "%s", nusage);
|
||
return swerrs;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Generic device routines (null, virtual, and real)
|
||
** Open, Close, Read, Write, Write-EOF, Write-EOT.
|
||
*/
|
||
|
||
int devopen(register struct devdk *d, int wrtf)
|
||
{
|
||
char *opath, *path;
|
||
|
||
if (!(opath = d->d_path) || !*opath) {
|
||
fprintf(logfile, "; Null mount path\n");
|
||
return FALSE;
|
||
}
|
||
path = malloc(strlen(opath)+1);
|
||
strcpy(path, opath);
|
||
|
||
/* Set up config vars */
|
||
vdk_init(&(d->d_vdk), errhan, NULL);
|
||
|
||
d->d_vdk.dk_format = d->d_fmt;
|
||
strcpy(d->d_vdk.dk_devname, d->d_dcf.dcf_name);
|
||
d->d_vdk.dk_ncyls = d->d_dcf.dcf_ncyl;
|
||
d->d_vdk.dk_ntrks = d->d_dcf.dcf_ntrk;
|
||
d->d_vdk.dk_nsecs = d->d_dcf.dcf_nsec;
|
||
d->d_vdk.dk_nwds = d->d_dcf.dcf_nwds;
|
||
|
||
if (!vdk_mount(&(d->d_vdk), path, wrtf)) {
|
||
fprintf(logfile, "; Cannot mount device \"%s\": %s\n",
|
||
path, os_strerror(d->d_vdk.dk_err));
|
||
free(path);
|
||
return FALSE;
|
||
}
|
||
free(path);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
int devclose(struct devdk *d)
|
||
{
|
||
int res = TRUE;
|
||
|
||
if (DBGFLG && d->d_path)
|
||
fprintf(logfile, "; Closing \"%s\"\n", d->d_path);
|
||
|
||
if (d->d_isdisk) {
|
||
res = vdk_unmount(&(d->d_vdk)); /* Close real disk */
|
||
}
|
||
|
||
/* Force us to forget about it even if above stuff failed */
|
||
d->d_isdisk = FALSE;
|
||
return res;
|
||
}
|
||
|
||
|
||
/* Read from device
|
||
** Returns 1 if read something
|
||
** Returns 0 if read nothing or error
|
||
*/
|
||
|
||
int devread(struct devdk *d, long int daddr, w10_t *buff)
|
||
{
|
||
int nsec;
|
||
|
||
#if 0
|
||
if (DBGFLG)
|
||
fprintf(logfile, "; read daddr=%ld\n", daddr);
|
||
#endif
|
||
|
||
nsec = vdk_read(&d->d_vdk, buff, (uint32)daddr, 1);
|
||
|
||
if (d->d_vdk.dk_err
|
||
|| (nsec != 1)) {
|
||
fprintf(logfile, "; read error on %s: %s\n",
|
||
d->d_vdk.dk_filename, os_strerror(d->d_vdk.dk_err));
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/* Write to device.
|
||
*/
|
||
int devwrite(struct devdk *d, long int daddr, w10_t *buff)
|
||
{
|
||
int nsec;
|
||
|
||
#if 0
|
||
if (DBGFLG)
|
||
fprintf(logfile, "; write daddr=%ld\n", daddr);
|
||
#endif
|
||
|
||
nsec = vdk_write(&d->d_vdk, buff, (uint32)daddr, 1);
|
||
|
||
if (d->d_vdk.dk_err
|
||
|| (nsec != 1)) {
|
||
fprintf(logfile, "; write error on %s: %s\n",
|
||
d->d_vdk.dk_filename, os_strerror(d->d_vdk.dk_err));
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
/* General-purpose System-level I/O.
|
||
** It is intended that this level of IO be in some sense the fastest
|
||
** or most efficient way to interact with the host OS, as opposed to
|
||
** the more portable stdio interface.
|
||
*/
|
||
|
||
int
|
||
os_fdopen(osfd_t *afd, char *file, char *modes)
|
||
{
|
||
#if CENV_SYS_UNIX || CENV_SYS_MAC
|
||
int flags = 0;
|
||
if (!afd) return FALSE;
|
||
for (; modes && *modes; ++modes) switch (*modes) {
|
||
case 'r': flags |= O_RDONLY; break; /* Yes I know it's 0 */
|
||
case 'w': flags |= O_WRONLY; break;
|
||
case '+': flags |= O_RDWR; break;
|
||
case 'a': flags |= O_APPEND; break;
|
||
case 'b': /* Binary */
|
||
# if CENV_SYS_MAC
|
||
flags |= O_BINARY;
|
||
# endif
|
||
break;
|
||
case 'c': flags |= O_CREAT; break;
|
||
/* Ignore unknown chars for now */
|
||
}
|
||
# if CENV_SYS_MAC
|
||
if ((*afd = open(file, flags)) < 0)
|
||
# else
|
||
if ((*afd = open(file, flags, 0666)) < 0)
|
||
# endif
|
||
return FALSE;
|
||
return TRUE;
|
||
|
||
#elif CENV_SYS_MOONMAC
|
||
Boolean create = FALSE, append = FALSE;
|
||
short refnum;
|
||
OSErr err;
|
||
char pascal_string[256];
|
||
|
||
if (!afd) return FALSE;
|
||
for (; modes && *modes; ++modes) switch (*modes) {
|
||
case 'a': append = TRUE; break;
|
||
case 'c': create = TRUE; break;
|
||
/* Ignore read/write and unknown chars for now */
|
||
}
|
||
pascal_string[0] = strlen(file);
|
||
BlockMove(file, &pascal_string[1], pascal_string[0]);
|
||
if (create) Create(pascal_string, 0, 'KH10', 'TEXT');
|
||
err = FSOpen(pascal_string, 0, &refnum);
|
||
*afd = err;
|
||
if (err) return FALSE;
|
||
*afd = refnum;
|
||
return TRUE;
|
||
#endif
|
||
}
|
||
|
||
int
|
||
os_fdclose(osfd_t fd)
|
||
{
|
||
#if CENV_SYS_UNIX || CENV_SYS_MAC
|
||
return close(fd) != -1;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
int
|
||
os_fdseek(osfd_t fd, osdaddr_t addr)
|
||
{
|
||
#if CENV_SYS_UNIX
|
||
return lseek(fd, addr, L_SET) != -1;
|
||
#elif CENV_SYS_MAC || CENV_SYS_MOONMAC
|
||
return lseek(fd, addr, SEEK_SET) != -1;
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
int
|
||
os_fdread(osfd_t fd, char *buf, size_t len, size_t *ares)
|
||
{
|
||
#if CENV_SYS_UNIX || CENV_SYS_MOONMAC
|
||
register int res = read(fd, buf, len);
|
||
if (res < 0) {
|
||
if (ares) *ares = 0;
|
||
return FALSE;
|
||
}
|
||
#elif CENV_SYS_MAC
|
||
/* This is actually generic code for any system supporting unix-like
|
||
** calls with a 16-bit integer count interface.
|
||
*/
|
||
register size_t res = 0;
|
||
register unsigned int scnt, sres = 0;
|
||
|
||
while (len) {
|
||
scnt = len > (1<<14) ? (1<<14) : len; /* 16-bit count each whack */
|
||
if ((sres = read(fd, buf, cnt)) != scnt) {
|
||
if (sres == -1) { /* If didn't complete, check for err */
|
||
if (ares) *ares = res; /* Error, but may have read stuff */
|
||
return FALSE;
|
||
}
|
||
res += sres; /* No error, just update count */
|
||
break; /* and return successfully */
|
||
}
|
||
res += sres;
|
||
len -= sres;
|
||
buf += sres;
|
||
}
|
||
#endif
|
||
if (ares) *ares = res;
|
||
return TRUE;
|
||
}
|
||
|
||
int
|
||
os_fdwrite(osfd_t fd, char *buf, size_t len, size_t *ares)
|
||
{
|
||
#if CENV_SYS_UNIX || CENV_SYS_MOONMAC
|
||
register int res = write(fd, buf, len);
|
||
if (res < 0) {
|
||
if (ares) *ares = 0;
|
||
return FALSE;
|
||
}
|
||
#elif CENV_SYS_MAC
|
||
/* This is actually generic code for any system supporting unix-like
|
||
** calls with a 16-bit integer count interface.
|
||
*/
|
||
register size_t res = 0;
|
||
register unsigned int scnt, sres = 0;
|
||
|
||
while (len) {
|
||
scnt = len > (1<<14) ? (1<<14) : len; /* 16-bit count each whack */
|
||
if ((sres = write(fd, buf, cnt)) != scnt) {
|
||
if (sres == -1) { /* If didn't complete, check for err */
|
||
if (ares) *ares = res; /* Error, but may have written stuff */
|
||
return FALSE;
|
||
}
|
||
res += sres; /* No error, just update count */
|
||
break; /* and return successfully */
|
||
}
|
||
res += sres;
|
||
len -= sres;
|
||
buf += sres;
|
||
}
|
||
#endif
|
||
if (ares) *ares = res;
|
||
return TRUE;
|
||
}
|