summaryrefslogtreecommitdiff
path: root/usr/src/lib/libcmd/common/cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libcmd/common/cp.c')
-rw-r--r--usr/src/lib/libcmd/common/cp.c208
1 files changed, 111 insertions, 97 deletions
diff --git a/usr/src/lib/libcmd/common/cp.c b/usr/src/lib/libcmd/common/cp.c
index 3aa6b75273..c3484b0cb0 100644
--- a/usr/src/lib/libcmd/common/cp.c
+++ b/usr/src/lib/libcmd/common/cp.c
@@ -1,10 +1,10 @@
/***********************************************************************
* *
* This software is part of the ast package *
-* Copyright (c) 1992-2007 AT&T Knowledge Ventures *
+* Copyright (c) 1992-2008 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
-* by AT&T Knowledge Ventures *
+* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* http://www.opensource.org/licenses/cpl1.0.txt *
@@ -27,7 +27,7 @@
*/
static const char usage_head[] =
-"[-?@(#)$Id: cp (AT&T Research) 2006-11-21 $\n]"
+"[-?@(#)$Id: cp (AT&T Research) 2007-12-13 $\n]"
USAGE_LICENSE
;
@@ -152,7 +152,6 @@ typedef struct State_s /* program state */
int missmode; /* default missing dir mode */
int official; /* move to next view */
int op; /* {CP,LN,MV} */
- int pathsiz; /* state.path buffer size */
int perm; /* permissions to preserve */
int postsiz; /* state.path post index */
int presiz; /* state.path pre index */
@@ -163,10 +162,15 @@ typedef struct State_s /* program state */
int uid; /* caller uid */
int update; /* replace only if newer */
int verbose; /* list each file before op */
+ int wflags; /* open() for write flags */
int (*link)(const char*, const char*); /* link */
int (*stat)(const char*, struct stat*); /* stat */
+#define INITSTATE pathsiz /* (re)init state before this */
+ int pathsiz; /* state.path buffer size */
+
+
char* path; /* to pathname buffer */
char* opname; /* state.op message string */
char* suffix; /* backup suffix */
@@ -229,8 +233,6 @@ visit(State_t* state, register FTSENT* ent)
FTSENT* sub;
struct stat st;
- if (cmdquit())
- return -1;
if (ent->fts_info == FTS_DC)
{
error(2, "%s: directory causes cycle", ent->fts_path);
@@ -569,7 +571,7 @@ visit(State_t* state, register FTSENT* ent)
error(ERROR_SYSTEM|2, "%s: cannot read", ent->fts_path);
return 0;
}
- else if ((wfd = open(state->path, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, ent->fts_statp->st_mode & state->perm)) < 0)
+ else if ((wfd = open(state->path, st.st_mode ? (state->wflags & ~O_EXCL) : state->wflags, ent->fts_statp->st_mode & state->perm)) < 0)
{
error(ERROR_SYSTEM|2, "%s: cannot write", state->path);
if (ent->fts_statp->st_size > 0)
@@ -662,134 +664,144 @@ b_cp(int argc, register char** argv, void* context)
int path_resolve;
int standard;
struct stat st;
- State_t state;
+ State_t* state;
+ Shbltin_t* sh;
cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_NOTIFY);
- memset(&state, 0, sizeof(state));
- state.presiz = -1;
+ if (!(sh = CMD_CONTEXT(context)) || !(state = (State_t*)sh->ptr))
+ {
+ if (!(state = newof(0, State_t, 1, 0)))
+ error(ERROR_SYSTEM|3, "out of space");
+ if (sh)
+ sh->ptr = state;
+ }
+ else
+ memset(state, 0, offsetof(State_t, INITSTATE));
+ state->presiz = -1;
backup_type = 0;
- state.flags = FTS_NOCHDIR|FTS_NOSEEDOTDIR;
- state.uid = geteuid();
- if (!(state.tmp = sfstropen()))
+ state->flags = FTS_NOCHDIR|FTS_NOSEEDOTDIR;
+ state->uid = geteuid();
+ state->wflags = O_WRONLY|O_CREAT|O_TRUNC|O_BINARY;
+ if (!state->tmp && !(state->tmp = sfstropen()))
error(ERROR_SYSTEM|3, "out of space [tmp string]");
- sfputr(state.tmp, usage_head, -1);
+ sfputr(state->tmp, usage_head, -1);
standard = !strcmp(astconf("CONFORMANCE", NiL, NiL), "standard");
switch (error_info.id[0])
{
case 'c':
case 'C':
- sfputr(state.tmp, usage_cp, -1);
- state.op = CP;
- state.stat = stat;
+ sfputr(state->tmp, usage_cp, -1);
+ state->op = CP;
+ state->stat = stat;
path_resolve = -1;
break;
case 'l':
case 'L':
- sfputr(state.tmp, usage_ln, -1);
- state.op = LN;
- state.flags |= FTS_PHYSICAL;
- state.link = link;
- state.stat = lstat;
+ sfputr(state->tmp, usage_ln, -1);
+ state->op = LN;
+ state->flags |= FTS_PHYSICAL;
+ state->link = link;
+ state->stat = lstat;
path_resolve = 1;
break;
case 'm':
case 'M':
- sfputr(state.tmp, usage_mv, -1);
- state.op = MV;
- state.flags |= FTS_PHYSICAL;
- state.preserve = 1;
- state.stat = lstat;
+ sfputr(state->tmp, usage_mv, -1);
+ state->op = MV;
+ state->flags |= FTS_PHYSICAL;
+ state->preserve = 1;
+ state->stat = lstat;
path_resolve = 1;
break;
default:
error(3, "not implemented");
break;
}
- sfputr(state.tmp, usage_tail, -1);
- if (!(usage = sfstruse(state.tmp)))
- error(ERROR_SYSTEM|3, "%s: out of space", state.path);
- state.opname = state.op == CP ? ERROR_translate(0, 0, 0, "overwrite") : ERROR_translate(0, 0, 0, "replace");
+ sfputr(state->tmp, usage_tail, -1);
+ if (!(usage = sfstruse(state->tmp)))
+ error(ERROR_SYSTEM|3, "%s: out of space", state->path);
+ state->opname = state->op == CP ? ERROR_translate(0, 0, 0, "overwrite") : ERROR_translate(0, 0, 0, "replace");
for (;;)
{
switch (optget(argv, usage))
{
case 'a':
- state.flags |= FTS_PHYSICAL;
- state.preserve = 1;
- state.recursive = 1;
+ state->flags |= FTS_PHYSICAL;
+ state->preserve = 1;
+ state->recursive = 1;
path_resolve = 1;
continue;
case 'b':
- state.backup = 1;
+ state->backup = 1;
continue;
case 'f':
- state.force = 1;
- if (state.op != CP || !standard)
- state.interactive = 0;
+ state->force = 1;
+ if (state->op != CP || !standard)
+ state->interactive = 0;
continue;
case 'h':
- state.hierarchy = 1;
+ state->hierarchy = 1;
continue;
case 'i':
- state.interactive = 1;
- if (state.op != CP || !standard)
- state.force = 0;
+ state->interactive = 1;
+ if (state->op != CP || !standard)
+ state->force = 0;
continue;
case 'l':
- state.op = LN;
- state.link = link;
- state.stat = lstat;
+ state->op = LN;
+ state->link = link;
+ state->stat = lstat;
continue;
case 'p':
- state.preserve = 1;
+ state->preserve = 1;
continue;
case 'r':
- state.recursive = 1;
+ state->recursive = 1;
if (path_resolve < 0)
path_resolve = 0;
continue;
case 's':
- state.op = LN;
- state.link = pathsetlink;
- state.stat = lstat;
+ state->op = LN;
+ state->link = pathsetlink;
+ state->stat = lstat;
continue;
case 'u':
- state.update = 1;
+ state->update = 1;
continue;
case 'v':
- state.verbose = 1;
+ state->verbose = 1;
continue;
case 'x':
- state.flags |= FTS_XDEV;
+ state->flags |= FTS_XDEV;
continue;
case 'F':
#if _lib_fsync
- state.sync = 1;
+ state->sync = 1;
#else
error(1, "%s not implemented on this system", opt_info.name);
#endif
continue;
case 'H':
- state.flags |= FTS_META|FTS_PHYSICAL;
+ state->flags |= FTS_META|FTS_PHYSICAL;
path_resolve = 1;
continue;
case 'L':
- state.flags &= ~FTS_PHYSICAL;
+ state->flags &= ~FTS_PHYSICAL;
path_resolve = 1;
continue;
case 'P':
- state.flags &= ~FTS_META;
- state.flags |= FTS_PHYSICAL;
+ state->flags &= ~FTS_META;
+ state->flags |= FTS_PHYSICAL;
path_resolve = 1;
continue;
case 'R':
- state.recursive = 1;
- state.flags &= ~FTS_META;
- state.flags |= FTS_PHYSICAL;
+ state->recursive = 1;
+ state->flags &= ~FTS_META;
+ state->flags |= FTS_PHYSICAL;
path_resolve = 1;
continue;
case 'S':
- state.suffix = opt_info.arg;
+ state->suffix = opt_info.arg;
continue;
case 'V':
backup_type = opt_info.arg;
@@ -814,15 +826,19 @@ b_cp(int argc, register char** argv, void* context)
error(3, "out of space");
memcpy(v, argv, (argc + 1) * sizeof(char*));
argv = v;
- if (!argc && !standard)
+ if (!standard)
{
- argc++;
- argv[1] = (char*)dot;
+ state->wflags |= O_EXCL;
+ if (!argc)
+ {
+ argc++;
+ argv[1] = (char*)dot;
+ }
}
- if (state.backup)
+ if (state->backup)
{
if (!(file = backup_type) && !(backup_type = getenv("VERSION_CONTROL")))
- state.backup = BAK_existing;
+ state->backup = BAK_existing;
else
switch (strkey(backup_type))
{
@@ -834,7 +850,7 @@ b_cp(int argc, register char** argv, void* context)
case HASHKEY1('e'):
case HASHKEY3('n','i','l'):
case HASHKEY2('n','i'):
- state.backup = BAK_existing;
+ state->backup = BAK_existing;
break;
case HASHKEY5('n','e','v','e','r'):
case HASHKEY4('n','e','v','e'):
@@ -846,7 +862,7 @@ b_cp(int argc, register char** argv, void* context)
case HASHKEY3('s','i','m'):
case HASHKEY2('s','i'):
case HASHKEY1('s'):
- state.backup = BAK_simple;
+ state->backup = BAK_simple;
break;
case HASHKEY6('n','u','m','b','e','r'):
case HASHKEY5('n','u','m','b','e'):
@@ -854,21 +870,21 @@ b_cp(int argc, register char** argv, void* context)
case HASHKEY3('n','u','m'):
case HASHKEY2('n','u'):
case HASHKEY1('t'):
- state.backup = BAK_number;
+ state->backup = BAK_number;
break;
default:
if (file)
error(2, "%s: unknown backup type", backup_type);
break;
}
- if (!state.suffix && !(state.suffix = getenv("SIMPLE_BACKUP_SUFFIX")))
- state.suffix = "~";
- state.suflen = strlen(state.suffix);
+ if (!state->suffix && !(state->suffix = getenv("SIMPLE_BACKUP_SUFFIX")))
+ state->suffix = "~";
+ state->suflen = strlen(state->suffix);
}
if (argc <= 0 || error_info.errors)
error(ERROR_USAGE|4, "%s", optusage(NiL));
if (!path_resolve)
- state.flags |= fts_flags();
+ state->flags |= fts_flags();
file = argv[argc];
argv[argc] = 0;
if (s = strrchr(file, '/'))
@@ -880,35 +896,34 @@ b_cp(int argc, register char** argv, void* context)
}
if (file != (char*)dot)
pathcanon(file, 0);
- if (!(state.directory = !stat(file, &st) && S_ISDIR(st.st_mode)) && argc > 1)
+ if (!(state->directory = !stat(file, &st) && S_ISDIR(st.st_mode)) && argc > 1)
error(ERROR_USAGE|4, "%s", optusage(NiL));
- if (s && !state.directory)
+ if (s && !state->directory)
error(3, "%s: not a directory", file);
- if ((state.fs3d = fs3d(FS3D_TEST)) && strmatch(file, "...|*/...|.../*"))
- state.official = 1;
- state.postsiz = strlen(file);
- state.pathsiz = roundof(state.postsiz + 2, PATH_CHUNK);
- if (!(state.path = newof(0, char, state.pathsiz, 0)))
+ if ((state->fs3d = fs3d(FS3D_TEST)) && strmatch(file, "...|*/...|.../*"))
+ state->official = 1;
+ state->postsiz = strlen(file);
+ if (state->pathsiz < roundof(state->postsiz + 2, PATH_CHUNK) && !(state->path = newof(state->path, char, state->pathsiz = roundof(state->postsiz + 2, PATH_CHUNK), 0)))
error(3, "out of space");
- memcpy(state.path, file, state.postsiz + 1);
- if (state.directory && state.path[state.postsiz - 1] != '/')
- state.path[state.postsiz++] = '/';
- if (state.hierarchy)
+ memcpy(state->path, file, state->postsiz + 1);
+ if (state->directory && state->path[state->postsiz - 1] != '/')
+ state->path[state->postsiz++] = '/';
+ if (state->hierarchy)
{
- if (!state.directory)
+ if (!state->directory)
error(3, "%s: last argument must be a directory", file);
- state.missmode = st.st_mode;
+ state->missmode = st.st_mode;
}
- state.perm = state.uid ? S_IPERM : (S_IPERM & ~S_ISVTX);
- if (!state.recursive)
- state.flags |= FTS_TOP;
- if (fts = fts_open(argv, state.flags, NiL))
+ state->perm = state->uid ? S_IPERM : (S_IPERM & ~S_ISVTX);
+ if (!state->recursive)
+ state->flags |= FTS_TOP;
+ if (fts = fts_open(argv, state->flags, NiL))
{
- while ((ent = fts_read(fts)) && !visit(&state, ent));
+ while (!sh_checksig(context) && (ent = fts_read(fts)) && !visit(state, ent));
fts_close(fts);
}
- else if (state.link != pathsetlink)
- switch (state.op)
+ else if (state->link != pathsetlink)
+ switch (state->op)
{
case CP:
error(ERROR_SYSTEM|2, "%s: cannot copy", argv[0]);
@@ -920,8 +935,7 @@ b_cp(int argc, register char** argv, void* context)
error(ERROR_SYSTEM|2, "%s: cannot move", argv[0]);
break;
}
- else if ((*state.link)(*argv, state.path))
- error(ERROR_SYSTEM|2, "%s: cannot link to %s", *argv, state.path);
- free(state.path);
+ else if ((*state->link)(*argv, state->path))
+ error(ERROR_SYSTEM|2, "%s: cannot link to %s", *argv, state->path);
return error_info.errors != 0;
}