aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/mv/mv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/mv/mv.c')
-rw-r--r--sys/cmd/mv/mv.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/sys/cmd/mv/mv.c b/sys/cmd/mv/mv.c
new file mode 100644
index 0000000..0d19248
--- /dev/null
+++ b/sys/cmd/mv/mv.c
@@ -0,0 +1,130 @@
+#include <u.h>
+#include <libn.h>
+
+static struct Flags
+{
+ uchar f : 1;
+ uchar i : 1;
+ uchar v : 1;
+} flag;
+
+static
+char *
+strcpyn(char *dst, char *src, int n)
+{
+ while(*src && n-->0)
+ *dst++ = *src++;
+
+ *dst = 0;
+ return dst;
+}
+
+static
+int
+mv(char *from, char *to)
+{
+ io·Stat src, dst;
+
+ if(lstat(from, &src)) {
+ errorf("%s", from);
+ return 1;
+ }
+
+ if(!flag.f && !access(to, F_OK)) {
+ int ask = 1;
+ int ch, first;
+
+ if(flag.i && !access(from, F_OK))
+ fprintf(stderr, "overwrite %s? ", to);
+ else
+ ask = 0;
+
+ if (ask) {
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+
+ if (first != 'y' || first != 'Y')
+ return 0;
+ }
+ }
+
+ if(!rename(from, to)) {
+ if (flag.v)
+ fprintf(stdout, "%s -> %s\n", from, to);
+ return 0;
+ }
+
+ /* TODO: errno = EXDEV */
+ errorf("rename: %s to %s: %s", from, to, strerror(errno));
+ return 1;
+}
+
+static
+void
+usage(void)
+{
+ fputs("usage: mv [-fiv] source ... dest\n", stderr);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int err, len;
+ io·Stat info;
+ char *arg, *nm, *e, path[4096];
+
+ ARGBEGIN{
+ case 'f':
+ flag.f++;
+ break;
+ case 'i':
+ flag.i++;
+ break;
+ case 'v':
+ flag.v++;
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc < 2)
+ usage();
+
+ if(stat(argv[argc-1],&info) || !S_ISDIR(info.st_mode)) {
+ if (argc > 2)
+ usage();
+ exit(mv(argv[0], argv[1]));
+ }
+
+ /* we know the last argument is a directory */
+ e = strcpyn(path, argv[argc-1], sizeof path-1);
+ *e++ = '/';
+
+ for(err=0; --argc; ++argv) {
+ arg = argv[0];
+
+ if ((nm = strrchr(arg, '/')) == nil)
+ nm = arg;
+ else {
+ /* case: name/ */
+ if (!nm[1]) {
+ while(nm >= arg && nm[0] == '/')
+ nm--;
+ while(nm >= arg && nm[0] != '/')
+ nm--;
+ }
+ nm++;
+ }
+
+ if ((len = strlen(nm)) >= arrend(path)-e) {
+ errorf("%s: path name overflow\n", arg);
+ err++;
+ continue;
+ }
+ memmove(e, nm, len+1);
+ err += mv(arg, path);
+ }
+ exit(err);
+}