Cover V05, I06
Article
Figure 1
Listing 1
Listing 2
Listing 3
Listing 4
Sidebar 1

jun96.tar


Listing 4: The client ccopy program

/*
* ccopy - copy only if the target file does not exist.  Used
*      to avoid race conditions.  This is a classical unix
*      lock-file creation mechanism: it's an atomic action.
*/
#include
#include        /* For open(2). */
#include        /* For umask and fstat(2). */
#include
#include        /* For error reporting. */
extern int sys_nerr;
extern char *sys_errlist[];

#define USERERR 1       /* Parameters messed up or missing. */
#define EXISTS  2       /* File exists, try again later. */
#define REALERR 3       /* Something bad happened. */
#define ERR (-1)        /* System's normal error value. */

char *ProgName = NULL;  /* Name (ie, ccopy) for error reports. */

main(argc, argv) int argc; char *argv[]; {

ProgName = argv[0];
if (argc != 3) {
(void) fprintf(stderr,
"%s: Error - you must supply exactly two filenames.\n",
ProgName);
(void) fprintf(stderr,
"%s - copy one file to another IFF the second doesn't exist\n",
ProgName);
(void) fprintf(stderr,
"Usage: %s infile outfile\n",
ProgName);
exit(USERERR);
}
exit(ccopy(argv[1],argv[2]));
/*NOTREACHED*/
}

ccopy(inFile,outFile) char *inFile, *outFile; {
struct stat  status;
int     inFd,
outFd;
int     rc = 0;
int     nread;
char    buf[BUFSIZ*10]; /* A biggish copy buffer. */
mode_t  oldUmask,
umask();

if ((inFd= open(inFile,O_RDONLY)) == ERR) {
sayOpenError(inFile,O_RDONLY,errno);
return REALERR;
}

if (fstat(inFd,&status) == ERR) {
sayOpenError(inFile,ERR,errno);
return REALERR;
}

oldUmask = umask((mode_t)0);
if ((outFd= open(outFile,O_CREAT|O_EXCL | O_WRONLY | O_TRUNC,
status.st_mode)) == ERR) {
switch (errno) {
case EEXIST:
rc = EXISTS;
sayExists(outFile);
break;
default:
rc = REALERR;
sayOpenError(outFile,O_WRONLY,errno);
break;
}
(void) umask(oldUmask);
return rc;
}
while ((nread= read(inFd,buf,sizeof(buf))) != 0) {
if (write(outFd,buf,nread) != nread) {
rc = REALERR;
sayWriteError(outFile,errno);
break;
}
}
(void) umask(oldUmask);

(void) close(inFd);
if (close(outFd) == ERR) {
sayWriteError(outFile,errno);
rc = REALERR;
}
return 0;
}

/*
* error reporters -- for open, existence and write errors.
*/
sayExists(outFile) char *outFile; {
(void) fprintf(stderr,
"%s: Error - file %s already exists, try again later.\n",
ProgName,outFile);
return;
}

sayOpenError(name,readWriteOrStat,errno)
char *name; int readWriteOrStat, errno; {
char    *operation;

switch (readWriteOrStat) {
case ERR:
operation = "stat input";
break;
case O_RDONLY:
operation = "read input";
break;
case O_WRONLY:
operation = "create output";
break;
}

(void) fprintf(stderr,
"%s: can't %s file \"%s\", %s (errno %d), halting.\n",
ProgName, operation, name,
(errno < sys_nerr)? sys_errlist[errno]: "Unknown error",
errno);
return;
}

sayWriteError(name,errno) char *name; int errno; {

(void) fprintf(stderr,
"%s: Error writing and closing output file \"%s\", %s (errno %d), halting.\n",
ProgName, name,
(errno < sys_nerr)? sys_errlist[errno]: "Unknown error",
errno);
(void)fprintf(stderr,
"%s: please inspect and remove remnant of \"%s\".\n",
ProgName,name);
return;
}

# End of File