126 lines
2.4 KiB
C
126 lines
2.4 KiB
C
/* cp.c */
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#define sys_error(msg) { fprintf(stderr, "%s", "cp: "); perror(msg); return 2; }
|
|
|
|
|
|
/* cp */
|
|
static int _cp_single(char * src, char * dst);
|
|
static int _cp_multiple(int argc, char * argv[]);
|
|
static int _cp(int argc, char * argv[])
|
|
{
|
|
/* FIXME
|
|
* - cp_multiple already checks if last arg is a dir
|
|
* => always call cp_multiple
|
|
* if argc == 2 && returns 1, call cp_single
|
|
* - blah blah */
|
|
struct stat st;
|
|
|
|
if(argc > 2)
|
|
return _cp_multiple(argc, argv);
|
|
if(stat(argv[1], &st) == -1 && errno != ENOENT)
|
|
sys_error(argv[1]);
|
|
if(S_ISDIR(st.st_mode))
|
|
return _cp_multiple(argc, argv);
|
|
return _cp_single(argv[0], argv[1]);
|
|
}
|
|
|
|
static int _cp_single(char * src, char * dst)
|
|
{
|
|
FILE * fsrc;
|
|
FILE * fdst;
|
|
char buf[BUFSIZ];
|
|
size_t size;
|
|
char * err = src;
|
|
struct stat st;
|
|
|
|
if(stat(src, &st) == -1)
|
|
sys_error(src);
|
|
if(S_ISDIR(st.st_mode))
|
|
{
|
|
fprintf(stderr, "%s%s%s", "cp: ", src, ": omitting directory\n");
|
|
return 2;
|
|
}
|
|
if((fsrc = fopen(src, "r")) == NULL)
|
|
sys_error(src);
|
|
if((fdst = fopen(dst, "w")) == NULL)
|
|
{
|
|
fclose(fsrc);
|
|
sys_error(dst);
|
|
}
|
|
while((size = fread(buf, sizeof(char), BUFSIZ, fsrc)) > 0)
|
|
if(fwrite(buf, sizeof(char), size, fdst) != BUFSIZ)
|
|
{
|
|
err = dst;
|
|
break;
|
|
}
|
|
fclose(fdst);
|
|
if(!feof(fsrc))
|
|
{
|
|
fclose(fsrc);
|
|
sys_error(err);
|
|
}
|
|
fclose(fsrc);
|
|
return 0;
|
|
}
|
|
|
|
static int _cp_multiple(int argc, char * argv[])
|
|
{
|
|
char * dst = NULL;
|
|
char * p;
|
|
int i, len;
|
|
|
|
for(i = 0; i < argc - 1; i++)
|
|
{
|
|
len = strlen(argv[i]) + strlen(argv[argc-1]) + 2;
|
|
if((p = realloc(dst, len * sizeof(char))) == NULL)
|
|
{
|
|
free(dst);
|
|
sys_error("malloc");
|
|
}
|
|
dst = p;
|
|
sprintf(dst, "%s/%s", argv[argc-1], argv[i]);
|
|
_cp_single(argv[i], dst);
|
|
}
|
|
free(dst);
|
|
return 2;
|
|
}
|
|
|
|
/* usage */
|
|
static int _usage(void)
|
|
{
|
|
fprintf(stderr, "%s", "Usage: cp [-fip] source_file target_file\n\
|
|
cp [-fip] source_file ... target\n\
|
|
cp -R [-H | -L | -P][-fip] source_file ... target\n\
|
|
cp -r [-H | -L | -P][-fip] source_file ... target\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* main */
|
|
int main(int argc, char * argv[])
|
|
{
|
|
int o;
|
|
|
|
while((o = getopt(argc, argv, "")) != -1)
|
|
{
|
|
switch(o)
|
|
{
|
|
case '?':
|
|
return _usage();
|
|
}
|
|
}
|
|
if(optind + 1 >= argc)
|
|
return _usage();
|
|
return _cp(argc - optind, &argv[optind]);
|
|
}
|