SAI ||
Sommersemester 1997 ||
Systemnahe Software II ||
Übungen
Übungen zu Systemnahe Software II
Lösungen zu Blatt 1 (Aufgabe 1)
/*
* clone.c - Duplication of regular Files (with times and permissions).
*
* Martin Hasch, University of Ulm, April 1997.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <utime.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define PATHSEP '/'
#define NAMESIZ 1024 /* maximum target name size */
#define BUFFSIZ 4096 /* buffer size for file copy */
#ifndef EXIT_SUCCESS /* should be in stdlib.h, though */
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#endif
/*
* Find the last component of a path.
* Result points into original string.
*/
char * basename(char *path)
{
char *base;
base = path + strlen(path);
/* ignore trailing separators: */
while ( base > path && base[-1] == PATHSEP )
--base;
while ( base > path && base[-1] != PATHSEP )
--base;
return base;
}
/*
* Check whether file exists and is a directory.
* Result is 1 for a directory, else 0.
*/
int is_directory(char *filename)
{
struct stat statbuf;
return
!stat(filename, &statbuf) &&
(statbuf.st_mode & S_IFMT) == S_IFDIR;
}
/*
* Create a clone named clonename of file filename.
* Original file must exist and be a regular file, clone must not exist.
* Clone gets same permissions and modification time as original.
* Access time of original is updated (as a consequence of reading).
* Creation time of clone is updated (unavoidably).
* Result is 1 on success, otherwise 0.
*/
int clone(char *filename, char *clonename)
{
struct stat statbuf;
struct utimbuf ubuf;
char copybuf[BUFFSIZ];
int sourcefd, targetfd;
size_t nbytes;
if ( stat(filename, &statbuf) ) {
perror(filename);
return 0;
}
if ( (statbuf.st_mode & S_IFMT) != S_IFREG ) {
fprintf(stderr, "%s: not a regular file\n", filename);
return 0;
}
if ( (sourcefd = open(filename, O_RDONLY)) < 0 ) {
perror(filename);
return 0;
}
if ( (targetfd = open(clonename, O_WRONLY | O_CREAT | O_EXCL,
statbuf.st_mode)) < 0 ) {
perror(clonename);
(void) close(sourcefd);
return 0;
}
while ( (nbytes = read(sourcefd, copybuf, sizeof copybuf)) > 0 &&
write(targetfd, copybuf, nbytes) == nbytes )
;
if ( close(targetfd) || nbytes > 0 ) {
perror(clonename);
(void) close(sourcefd);
return 0;
}
if ( close(sourcefd) || nbytes < 0 ) {
perror(filename);
return 0;
}
ubuf.actime = statbuf.st_atime;
ubuf.modtime = statbuf.st_mtime;
if ( utime(clonename, &ubuf) ) {
perror(clonename);
return 0;
}
return 1;
}
/*
* Create a clone in directory dirname of file filename.
* Result is 1 on success, otherwise 0.
*/
int clone_into(char *filename, char *dirname)
{
char clonename[NAMESIZ];
char *base;
base = basename(filename);
if ( strlen(dirname) + strlen(base) > NAMESIZ-2 ) {
fprintf(stderr, "%s%c%s: name too long\n",
dirname, PATHSEP, base);
return 0;
}
(void) sprintf(clonename, "%s%c%s", dirname, PATHSEP, base);
return clone(filename, clonename);
}
/*
* Print usage message and exit.
*/
static void usage(char *cmdname)
{
fprintf(stderr, "Usage: %s f1 f2\n"
" %s f1 ... fn dir\n", cmdname, cmdname);
exit(EXIT_FAILURE);
}
/*
* Main routine: command line processing.
*/
int main(int argc, char *argv[])
{
int i;
int errors;
char * lastarg;
if ( argc < 3 )
usage(basename(argv[0]));
(void) umask(0L); /* => don't mask mode bits on file creation */
errors = 0;
lastarg = argv[argc-1];
if ( is_directory(lastarg) ) {
for ( i=1; i<argc-1; ++i )
if ( !clone_into(argv[i], lastarg) )
++errors;
} else {
if ( argc != 3 )
usage(basename(argv[0]));
if ( !clone(argv[1], argv[2]) )
++errors;
}
exit(errors? EXIT_FAILURE: EXIT_SUCCESS);
}
SAI ||
Sommersemester 1997 ||
Systemnahe Software II ||
Übungen
Martin Hasch, April 1997