implement cp and mv and improve rm
This commit is contained in:
parent
4192b13768
commit
cec53d14b1
1
LICENSE
1
LICENSE
|
@ -7,6 +7,7 @@ MIT/X Consortium License
|
||||||
© 2011 Hiltjo Posthuma <hiltjo@codemadness.org>
|
© 2011 Hiltjo Posthuma <hiltjo@codemadness.org>
|
||||||
© 2011 pancake <pancake@youterm.com>
|
© 2011 pancake <pancake@youterm.com>
|
||||||
© 2011 Random832 <random832@fastmail.us>
|
© 2011 Random832 <random832@fastmail.us>
|
||||||
|
© 2012 William Haddon <william@haddonthethird.net>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -1,17 +1,20 @@
|
||||||
include config.mk
|
include config.mk
|
||||||
|
|
||||||
HDR = text.h util.h
|
HDR = fs.h text.h util.h
|
||||||
LIB = \
|
LIB = \
|
||||||
util/afgets.o \
|
util/afgets.o \
|
||||||
util/agetcwd.o \
|
util/agetcwd.o \
|
||||||
util/apathmax.o \
|
util/apathmax.o \
|
||||||
util/concat.o \
|
util/concat.o \
|
||||||
|
util/cp.o \
|
||||||
util/enmasse.o \
|
util/enmasse.o \
|
||||||
util/eprintf.o \
|
util/eprintf.o \
|
||||||
util/enprintf.o \
|
util/enprintf.o \
|
||||||
util/estrtol.o \
|
util/estrtol.o \
|
||||||
|
util/fnck.o \
|
||||||
util/putword.o \
|
util/putword.o \
|
||||||
util/recurse.o \
|
util/recurse.o \
|
||||||
|
util/rm.o \
|
||||||
util/venprintf.o
|
util/venprintf.o
|
||||||
|
|
||||||
SRC = \
|
SRC = \
|
||||||
|
@ -21,6 +24,7 @@ SRC = \
|
||||||
chown.c \
|
chown.c \
|
||||||
cksum.c \
|
cksum.c \
|
||||||
cmp.c \
|
cmp.c \
|
||||||
|
cp.c \
|
||||||
date.c \
|
date.c \
|
||||||
dirname.c \
|
dirname.c \
|
||||||
echo.c \
|
echo.c \
|
||||||
|
@ -33,6 +37,7 @@ SRC = \
|
||||||
ls.c \
|
ls.c \
|
||||||
mkdir.c \
|
mkdir.c \
|
||||||
mkfifo.c \
|
mkfifo.c \
|
||||||
|
mv.c \
|
||||||
nl.c \
|
nl.c \
|
||||||
nohup.c \
|
nohup.c \
|
||||||
pwd.c \
|
pwd.c \
|
||||||
|
@ -56,7 +61,8 @@ all: $(BIN)
|
||||||
|
|
||||||
$(OBJ): util.h config.mk
|
$(OBJ): util.h config.mk
|
||||||
$(BIN): util.a
|
$(BIN): util.a
|
||||||
cat.o grep.o tail.o: text.h
|
cat.o cp.o mv.o grep.o tail.o: text.h
|
||||||
|
cp.o mv.o rm.o: fs.h
|
||||||
|
|
||||||
.o:
|
.o:
|
||||||
@echo LD $@
|
@echo LD $@
|
||||||
|
|
6
TODO
6
TODO
|
@ -1,17 +1,11 @@
|
||||||
comm [-123] file1 file2
|
comm [-123] file1 file2
|
||||||
|
|
||||||
cp [-r] file [name]
|
|
||||||
cp [-r] [file...] [directory]
|
|
||||||
|
|
||||||
cut [-bcfs] [-d delim] list [file...]
|
cut [-bcfs] [-d delim] list [file...]
|
||||||
|
|
||||||
diff [-ru] file1 file2
|
diff [-ru] file1 file2
|
||||||
|
|
||||||
id [-gnru] [user]
|
id [-gnru] [user]
|
||||||
|
|
||||||
mv file [name]
|
|
||||||
mv [file...] directory
|
|
||||||
|
|
||||||
paste [-s] [-d list] [file...]
|
paste [-s] [-d list] [file...]
|
||||||
|
|
||||||
printf format [argument...]
|
printf format [argument...]
|
||||||
|
|
|
@ -10,7 +10,7 @@ MANPREFIX = $(PREFIX)/share/man
|
||||||
LD = $(CC)
|
LD = $(CC)
|
||||||
CPPFLAGS = -D_POSIX_C_SOURCE=200112L
|
CPPFLAGS = -D_POSIX_C_SOURCE=200112L
|
||||||
CFLAGS = -Os -ansi -Wall -pedantic $(CPPFLAGS)
|
CFLAGS = -Os -ansi -Wall -pedantic $(CPPFLAGS)
|
||||||
LDFLAGS = -static #-s
|
LDFLAGS =
|
||||||
|
|
||||||
#CC = tcc
|
#CC = tcc
|
||||||
#LD = $(CC)
|
#LD = $(CC)
|
||||||
|
|
22
cp.1
Normal file
22
cp.1
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
.TH CP 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
cp \- copy files and directories
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B cp
|
||||||
|
.RB [ \-r ]
|
||||||
|
.I file
|
||||||
|
.RI [ name ]
|
||||||
|
.P
|
||||||
|
.B cp
|
||||||
|
.RB [ \-r ]
|
||||||
|
.RI [ file ...]
|
||||||
|
.RI [ directory ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B cp
|
||||||
|
copies a given file, naming it the given name. If multiple files are listed
|
||||||
|
they will be copied into the given directory.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-r
|
||||||
|
copies directories recursively. If this flag is not specified, directories are
|
||||||
|
not copied.
|
27
cp.c
Normal file
27
cp.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while((c = getopt(argc, argv, "r")) != -1)
|
||||||
|
switch(c) {
|
||||||
|
case 'r':
|
||||||
|
cp_rflag = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if(argc > 3 && !cp_rflag && !(stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode)))
|
||||||
|
eprintf("%s: not a directory\n", argv[argc-1]);
|
||||||
|
enmasse(argc - optind, &argv[optind], cp);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
9
fs.h
Normal file
9
fs.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
extern bool cp_rflag;
|
||||||
|
extern bool rm_fflag;
|
||||||
|
extern bool rm_rflag;
|
||||||
|
|
||||||
|
int cp(const char *, const char *);
|
||||||
|
void rm(const char *);
|
16
mv.1
Normal file
16
mv.1
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.TH MV 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
mv \- move files and directories
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B mv
|
||||||
|
.I file
|
||||||
|
.RI [ name ]
|
||||||
|
.P
|
||||||
|
.B mv
|
||||||
|
.RI [ file ...]
|
||||||
|
.RI [ directory ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B mv
|
||||||
|
moves or renames a given file or directory, naming it the given name. If
|
||||||
|
multiple files and directories are listed they will be moved into the given
|
||||||
|
directory.
|
39
mv.c
Normal file
39
mv.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "fs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int mv(const char *, const char *);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(getopt(argc, argv, "") != -1)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
if(argc > 3 && !(stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode)))
|
||||||
|
eprintf("%s: not a directory\n", argv[argc-1]);
|
||||||
|
enmasse(argc - optind, &argv[optind], mv);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mv (const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
if (rename(s1, s2) == 0)
|
||||||
|
return 0;
|
||||||
|
if (errno == EXDEV)
|
||||||
|
{
|
||||||
|
cp_rflag = true;
|
||||||
|
rm_rflag = true;
|
||||||
|
cp(s1, s2);
|
||||||
|
rm(s1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
3
rm.1
3
rm.1
|
@ -14,6 +14,7 @@ removes the given files and directories.
|
||||||
ignore files that cannot be removed.
|
ignore files that cannot be removed.
|
||||||
.TP
|
.TP
|
||||||
.B \-r
|
.B \-r
|
||||||
remove directories recursively.
|
remove directories recursively. If this flag is not specified, directories are
|
||||||
|
not removed.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.IR remove (3)
|
.IR remove (3)
|
||||||
|
|
28
rm.c
28
rm.c
|
@ -3,39 +3,33 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "fs.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static void rm(const char *);
|
|
||||||
|
|
||||||
static bool fflag = false;
|
|
||||||
static bool rflag = false;
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
while((c = getopt(argc, argv, "fr")) != -1)
|
while((c = getopt(argc, argv, "fr")) != -1)
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
fflag = true;
|
rm_fflag = true;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
rflag = true;
|
rm_rflag = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
for(; optind < argc; optind++)
|
for(; optind < argc; optind++) {
|
||||||
|
if(!rm_rflag && stat(argv[optind], &st) == 0 &&
|
||||||
|
S_ISDIR(st.st_mode))
|
||||||
|
fprintf(stderr, "%s: is a directory\n", argv[optind]);
|
||||||
|
else
|
||||||
rm(argv[optind]);
|
rm(argv[optind]);
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
rm(const char *path)
|
|
||||||
{
|
|
||||||
if(rflag)
|
|
||||||
recurse(path, rm);
|
|
||||||
if(remove(path) == -1 && !fflag)
|
|
||||||
eprintf("remove %s:", path);
|
|
||||||
}
|
|
||||||
|
|
1
util.h
1
util.h
|
@ -8,5 +8,6 @@ void enmasse(int, char **, int (*)(const char *, const char *));
|
||||||
void eprintf(const char *, ...);
|
void eprintf(const char *, ...);
|
||||||
void enprintf(int, const char *, ...);
|
void enprintf(int, const char *, ...);
|
||||||
long estrtol(const char *, int);
|
long estrtol(const char *, int);
|
||||||
|
void fnck(const char *, const char *, int (*)(const char *, const char *));
|
||||||
void putword(const char *);
|
void putword(const char *);
|
||||||
void recurse(const char *, void (*)(const char *));
|
void recurse(const char *, void (*)(const char *));
|
||||||
|
|
59
util/cp.c
Normal file
59
util/cp.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "../fs.h"
|
||||||
|
#include "../text.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
bool cp_rflag = false;
|
||||||
|
|
||||||
|
int
|
||||||
|
cp(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
FILE *f1, *f2;
|
||||||
|
char *ns1, *ns2;
|
||||||
|
long size1, size2;
|
||||||
|
struct dirent *d;
|
||||||
|
struct stat st;
|
||||||
|
DIR *dp;
|
||||||
|
|
||||||
|
if (stat(s1, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||||
|
if (!cp_rflag) {
|
||||||
|
eprintf("%s: is a directory\n", s1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(!(dp = opendir(s1)))
|
||||||
|
eprintf("opendir %s:", s1);
|
||||||
|
if (mkdir(s2, st.st_mode) == -1 && errno != EEXIST)
|
||||||
|
eprintf("mkdir %s:", s2);
|
||||||
|
apathmax(&ns1, &size1);
|
||||||
|
apathmax(&ns2, &size2);
|
||||||
|
while((d = readdir(dp)))
|
||||||
|
if(strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) {
|
||||||
|
if(snprintf(ns1, size1, "%s/%s", s1, d->d_name) > size1)
|
||||||
|
eprintf("%s/%s: filename too long\n", s1, d->d_name);
|
||||||
|
if(snprintf(ns2, size2, "%s/%s", s2, d->d_name) > size2)
|
||||||
|
eprintf("%s/%s: filename too long\n", s2, d->d_name);
|
||||||
|
fnck(ns1, ns2, cp);
|
||||||
|
}
|
||||||
|
closedir(dp);
|
||||||
|
free(ns1);
|
||||||
|
free(ns2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(!(f1 = fopen(s1, "r")))
|
||||||
|
eprintf("fopen %s:", s1);
|
||||||
|
if(!(f2 = fopen(s2, "w")))
|
||||||
|
eprintf("fopen %s:", s2);
|
||||||
|
concat(f1, s1, f2, s2);
|
||||||
|
fclose(f2);
|
||||||
|
fclose(f1);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -7,8 +7,6 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
static void fnck(const char *, const char *, int (*)(const char *, const char *));
|
|
||||||
|
|
||||||
void
|
void
|
||||||
enmasse(int argc, char **argv, int (*fn)(const char *, const char *))
|
enmasse(int argc, char **argv, int (*fn)(const char *, const char *))
|
||||||
{
|
{
|
||||||
|
@ -32,15 +30,3 @@ enmasse(int argc, char **argv, int (*fn)(const char *, const char *))
|
||||||
}
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
fnck(const char *a, const char *b, int (*fn)(const char *, const char *))
|
|
||||||
{
|
|
||||||
struct stat sta, stb;
|
|
||||||
|
|
||||||
if(stat(a, &sta) == 0 && stat(b, &stb) == 0
|
|
||||||
&& sta.st_dev == stb.st_dev && sta.st_ino == stb.st_ino)
|
|
||||||
eprintf("%s -> %s: same file\n", a, b);
|
|
||||||
if(fn(a, b) == -1)
|
|
||||||
eprintf("%s -> %s:", a, b);
|
|
||||||
}
|
|
||||||
|
|
15
util/fnck.c
Normal file
15
util/fnck.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
fnck(const char *a, const char *b, int (*fn)(const char *, const char *))
|
||||||
|
{
|
||||||
|
struct stat sta, stb;
|
||||||
|
|
||||||
|
if(stat(a, &sta) == 0 && stat(b, &stb) == 0
|
||||||
|
&& sta.st_dev == stb.st_dev && sta.st_ino == stb.st_ino)
|
||||||
|
eprintf("%s -> %s: same file\n", a, b);
|
||||||
|
if(fn(a, b) == -1)
|
||||||
|
eprintf("%s -> %s:", a, b);
|
||||||
|
}
|
17
util/rm.c
Normal file
17
util/rm.c
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../fs.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
bool rm_fflag = false;
|
||||||
|
bool rm_rflag = false;
|
||||||
|
|
||||||
|
void
|
||||||
|
rm(const char *path)
|
||||||
|
{
|
||||||
|
if(rm_rflag)
|
||||||
|
recurse(path, rm);
|
||||||
|
if(remove(path) == -1 && !rm_fflag)
|
||||||
|
eprintf("remove %s:", path);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user