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
|