Skip to content

mv fails to move directory hierarchies across file systems #871

@JohnoKing

Description

@JohnoKing

This gave me grief after a script failed when prepending PATH=/opt/ast/bin:$PATH. Reproducer:

# run on Linux at ksh repo root; /tmp and /dev/shm are both mounted to tmpfs
$ /opt/ast/bin/mv bin /dev/shm
mv: bin: /dev/shm/bin read error [Is a directory]
$ /opt/ast/bin/cp -r bin /dev/shm
cp: /dev/shm/bin: not a directory -- bin ignored
cp: /dev/shm/bin/package: cannot write [Not a directory]
cp: /dev/shm/bin/shtests: cannot write [Not a directory]
$ /opt/ast/bin/mv bin /tmp    
mv: bin: /tmp/bin read error [Is a directory]

Code where the error occurs:

ksh/src/lib/libcmd/cp.c

Lines 603 to 615 in 68fe82b

if (sfmove(ip, op, (Sfoff_t)SFIO_UNBOUND, -1) < 0)
n |= 3;
if (!sfeof(ip))
n |= 1;
if (sfsync(op) || state->sync && fsync(wfd) || sfclose(op))
n |= 2;
if (sfclose(ip))
n |= 1;
if (n)
{
error(ERROR_SYSTEM|2, "%s: %s %s error", ent->fts_path, state->path, n == 1 ? ERROR_translate(0, 0, 0, "read") : n == 2 ? ERROR_translate(0, 0, 0, "write") : ERROR_translate(0, 0, 0, "io"));
return 0;
}

I was able to trace the error as occurring after sfmove() fails. I haven't been able to debug it any further.

ksh93v- has some sort of bugfix applied to this area. I tried backporting that but it didn't help.

ksh93v-cp-mv-backport.patch
diff --git a/src/lib/libcmd/cp.c b/src/lib/libcmd/cp.c
index 2087baef4..69a368738 100644
--- a/src/lib/libcmd/cp.c
+++ b/src/lib/libcmd/cp.c
@@ -573,7 +573,7 @@ visit(State_t* state, FTSENT* ent)
 		{
 			int	rfd = -1;
 			int	wfd = -1;
-			if (ent->fts_statp->st_size > 0 && (rfd = open(ent->fts_path, O_RDONLY|O_BINARY|O_cloexec)) < 0)
+			if ((!S_ISREG(ent->fts_statp->st_mode) || ent->fts_statp->st_size > 0) && (rfd = open(ent->fts_path, O_RDONLY|O_BINARY|O_cloexec)) < 0)
 			{
 				error(ERROR_SYSTEM|2, "%s: cannot read", ent->fts_path);
 				return 0;
@@ -581,11 +581,11 @@ visit(State_t* state, FTSENT* ent)
 			else if ((wfd = open(state->path, (st.st_mode ? (state->wflags & ~O_EXCL) : state->wflags)|O_cloexec, ent->fts_statp->st_mode & state->perm)) < 0)
 			{
 				error(ERROR_SYSTEM|2, "%s: cannot write", state->path);
-				if (ent->fts_statp->st_size > 0)
+				if (rfd >= 0)
 					close(rfd);
 				return 0;
 			}
-			else if (ent->fts_statp->st_size > 0)
+			else if (rfd >= 0)
 			{
 				if (!(ip = sfnew(NULL, NULL, (size_t)SFIO_UNBOUND, rfd, SFIO_READ)))
 				{

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions