[Toybox] [PATCH, WIP] New toy - mv

Georgi Chorbadzhiyski gf at unixsol.org
Mon Mar 12 08:58:55 PDT 2012


Ok, I have problems in mv implementation since I'm trying to use internal
cp and rm toys. I have used toy_exec() variation:

int internal_exec(char *argv[])
{
    struct toy_list *which;
    which = toy_find(argv[0]);
    if (!which)
        return -1;
    toy_init(which, argv);
    toys.which->toy_main();
    return toys.exitval;
}

and in mv.c:

        if (rename(src, toybuf) != 0) {
            if (errno == EXDEV) {
                char *cp_argv[5] = { "cp", "-af", src, dest, NULL };
                char *rm_argv[4] = { "rm", "-rf", src, NULL };
                if (internal_exec(cp_argv) != 0 || internal_exec(rm_argv) != 0) {
                    ret = 1;
                }
            } else {
                perror_msg("%s", toybuf);
                ret = 1;
            }
        }

The problem is that calling toy_init() overwrites toys.optc, toys.optflags,
toys.optargs, toys.exitval, etc. I can save and restore them but should I
do it that way?

The attached mv.c works only for the first file if copying is needed. If
args related parameters are saved and restore between internal_exec() it
should work as expected.

Maybe toy_state_push() and toy_stat_pop() function can be added?

And also yesno() really should take va_arg parameters and flush stdout
after writing to it.

-- 
Georgi Chorbadzhiyski
http://georgi.unixsol.org/
-------------- next part --------------
/* vi: set sw=4 ts=4:
 *
 * mv.c - Move files.
 *
 * Copyright 2008 Rob Landley <rob at landley.net>
 *
 * See http://www.opengroup.org/onlinepubs/009695399/utilities/mv.html
 *

USE_MV(NEWTOY(mv, "<2fiv", TOYFLAG_BIN))

config MV
	bool "mv"
	default y
	help
	  usage: mv -fiv SOURCE... DEST

	  Move files from SOURCE to DEST.  If more than one SOURCE, DEST must
	  be a directory.

	  -f	force overwrite
	  -i	interactive, prompt before moving file
	  -v	verbose
*/

#include "toys.h"

#define FLAG_f 4
#define FLAG_i 2
#define FLAG_v 1

// Remove trailing /
// Remove ./ infront
char *normalize(char *x, int xlen) {
	if (!xlen)
		return x;
	while (x[--xlen] == '/')
		x[xlen] = '\0';
	if (xlen > 1) {
		if (x[0] == '.' && x[1] == '/') {
			x += 1;
			while (x[0] == '/')
				x++;
		}
	}
	return x;
}

int internal_exec(char *argv[])
{
	struct toy_list *which;
	which = toy_find(argv[0]);
	if (!which)
		return -1;
	toy_init(which, argv);
	toys.which->toy_main();
	return toys.exitval;
}

void mv_main(void)
{
	char *dest;
	struct stat st;
	int i;
	int ret = 0;

	dest = toys.optargs[--toys.optc];

	// Many sources, destination must be a directory
	if (toys.optc > 1) {
		if (stat(dest, &st) != 0 || !S_ISDIR(st.st_mode)) {
			error_exit("'%s' is not a directory", dest);
		}
	}

	dest = normalize(dest, strlen(dest));

	for (i=0; i<toys.optc; i++) {
		char *src = normalize(toys.optargs[i], strlen(toys.optargs[i]));

		if (!strcmp(src, dest))
			continue;

		snprintf(toybuf, sizeof(toybuf) - 1, "%s/%s", dest, src);
		toybuf[sizeof(toybuf) - 1] = '\0';

		if ((toys.optflags & FLAG_i) && !yesno("Confirm mv", 1))
			continue;

		if (toys.optflags & FLAG_v)
			xprintf("mv '%s' -> '%s'\n", src, toybuf);

		if (rename(src, toybuf) != 0) {
			if (errno == EXDEV) {
				char *cp_argv[5] = { "cp", "-af", src, dest, NULL };
				char *rm_argv[4] = { "rm", "-rf", src, NULL };
				if (internal_exec(cp_argv) != 0 || internal_exec(rm_argv) != 0) {
					ret = 1;
				}
			} else {
				perror_msg("%s", toybuf);
				ret = 1;
			}
		}
	}

	toys.exitval = ret;
}


More information about the Toybox mailing list