/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1992-2010 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
*/
static const char usage_head[] =
"[-?@(#)$Id: cp (AT&T Research) 2010-01-20 $\n]"
;
static const char usage_cp[] =
"[+NAME?cp - copy files]"
"[+DESCRIPTION?If the last argument names an existing directory, \bcp\b"
" copies each \afile\a into a file with the same name in that"
" directory. Otherwise, if only two files are given, \bcp\b copies"
" the first onto the second. It is an error if the last argument is"
" not a directory and more than two files are given. By default"
" directories are not copied.]"
"[a:archive?Preserve as much as possible of the structure and attributes of"
" the original files in the copy. Equivalent to \b--physical\b"
" \b--preserve\b \b--recursive\b.]"
"[p:preserve?Preserve file owner, group, permissions and timestamps.]"
"[h:hierarchy|parents?Form the name of each destination file by appending"
" to the target directory a slash and the specified source file name."
" The last argument must be an existing directory. Missing destination"
" directories are created.]"
"[H:metaphysical?Follow command argument symbolic links, otherwise don't"
" follow.]"
"[l:link?Make hard links to destination files instead of copies.]"
"[L:logical|dereference?Follow symbolic links and copy the files"
" they point to.]"
"[P|d:physical|nodereference?Don't follow symbolic links; copy symbolic"
" rather than the files they point to.]"
;
static const char usage_ln[] =
"[+NAME?ln - link files]"
"[+DESCRIPTION?If the last argument names an existing directory, \bln\b"
" links each \afile\a into a file with the same name in that"
" directory. Otherwise, if only two files are given, \bln\b links"
" the first onto the second. It is an error if the last argument is"
" not a directory and more than two files are given. By default"
" directories are not linked.]"
;
static const char usage_mv[] =
"[+NAME?mv - rename files]"
"[+DESCRIPTION?If the last argument names an existing directory, \bmv\b"
" renames each \afile\a into a file with the same name in that"
" directory. Otherwise, if only two files are given, \bmv\b renames"
" the first onto the second. It is an error if the last argument is"
" not a directory and more than two files are given. If a source and"
" destination file reside on different filesystems then \bmv\b copies"
" the file contents to the destination and then deletes the source"
" file.]"
;
static const char usage_tail[] =
"[f:force?Replace existing destination files.]"
"[i:interactive|prompt?Prompt whether to replace existing destination files."
" An affirmative response (\by\b or \bY\b) replaces the file, a quit"
" response (\bq\b or \bQ\b) exits immediately, and all other"
" responses skip the file.]"
"[r|R:recursive?Operate on the contents of directories recursively.]"
"[s:symlink|symbolic-link?Make symbolic links to destination files.]"
"[u:update?Replace a destination file only if its modification time is older"
" than the corresponding source file modification time.]"
"[v:verbose?Print the name of each file before operating on it.]"
"[b:backup?Make backups of files that are about to be replaced. See"
" \b--suffix\b and \b--version-control\b for more information.]"
"[F:fsync|sync?\bfsync\b(2) each file after it is copied.]"
"[S:backup-suffix|suffix?A backup file is made by renaming the file to the"
" same name with the backup suffix appended. The backup suffix is"
" determined in this order: this option, the \bSIMPLE_BACKUP_SUFFIX\b,"
" environment variable, or the default value \b~\b.]:[suffix]"
"[V:backup-type|version-control?The backup type is determined in this order:"
" this option, the \bVERSION_CONTROL\b environment variable, or the"
" default value \bexisting\b. \atype\a may be one of:]:[type]{"
" [+numbered|t?Always make numbered backups. The numbered backup"
" suffix is \b.\aSNS\a, where \aS\a is the"
" \bbackup-suffix\b and \aN\a is the version number,"
" starting at 1, incremented with each version.]"
" [+existing|nil?Make numbered backups of files that already"
" have them, otherwise simple backups.]"
" [+simple|never?Always make simple backups.]"
"}"
"[x|X|l:xdev|local|mount|one-file-system?Do not descend into directories in"
" different filesystems than their parents.]"
"\n"
"\nsource destination\n"
"file ... directory\n"
"\n"
"[+SEE ALSO?\bpax\b(1), \bfsync\b(2), \brename\b(2), \bunlink\b(2),"
" \bremove\b(3)]"
;
#include <cmd.h>
#include <ls.h>
#include <times.h>
#include <fts_fix.h>
#include <fs3d.h>
#include <hashkey.h>
#include <stk.h>
#include <tmx.h>
{
} State_t;
/*
* preserve support
*/
static void
{
int n;
switch (n)
{
case 01:
break;
case 02:
break;
case 03:
error(ERROR_SYSTEM|2, "%s: cannot reset owner to %s and group to %s", path, fmtuid(os->st_uid), fmtgid(os->st_gid));
break;
}
}
/*
* visit a single file and state.op to the destination
*/
static int
{
register char* base;
register int n;
register int len;
int rm;
int rfd;
int wfd;
int m;
int v;
char* s;
char* e;
char* protection;
{
return 0;
}
{
else
{
else if (*base)
base--;
base--;
}
}
else
{
}
len++;
{
if ((state->postsiz + len) > state->pathsiz && !(state->path = newof(state->path, char, state->pathsiz = roundof(state->postsiz + len, PATH_CHUNK), 0)))
{
while (e = strchr(s, '/'))
{
*e = 0;
{
if (s = strrchr(s, '/'))
{
*s = 0;
*s = '/';
}
{
return 0;
}
}
*e++ = '/';
s = e;
}
}
}
{
case FTS_DP:
if (state->preserve && state->op != LN || ent->fts_level > 0 && (ent->fts_statp->st_mode & S_IRWXU) != S_IRWXU)
{
else
else
{
if ((ent->fts_statp->st_mode & S_IPERM) != (st.st_mode & S_IPERM) && chmod(state->path, ent->fts_statp->st_mode & S_IPERM))
error(ERROR_SYSTEM|2, "%s: cannot reset directory mode to %s", state->path, fmtmode(st.st_mode & S_IPERM, 0) + 1);
}
}
return 0;
case FTS_DNR:
case FTS_DNX:
case FTS_D:
{
{
return 0;
}
}
{
case FTS_DNR:
return 0;
case FTS_DNX:
/*FALLTHROUGH*/
case FTS_D:
{
{
return 0;
}
}
else if (mkdir(state->path, (ent->fts_statp->st_mode & S_IPERM)|(ent->fts_info == FTS_D ? S_IRWXU : 0)))
{
}
{
}
return 0;
}
break;
case FTS_ERR:
case FTS_NS:
case FTS_SLNONE:
{
return 0;
}
break;
#if 0
case FTS_SL:
{
return 0;
}
break;
#endif
}
else if (state->update && !S_ISDIR(st.st_mode) && (unsigned long)ent->fts_statp->st_mtime < (unsigned long)st.st_mtime)
{
return 0;
}
{
/*
* target is in top 3d view
*/
{
{
/*
* let rename() handle it
*/
goto operate;
}
return 0;
}
{
return 0;
}
{
{
close(n);
/* ok */;
else if (state->interactive)
{
return 0;
}
{
return 0;
}
}
rm = 1;
else
{
#ifdef ETXTBSY
#endif
if (state->interactive)
{
if (astquery(-1, "override protection %s for %s? ", protection, state->path) < 0 || sh_checksig(state->context))
return 0;
rm = 1;
}
else if (!rm)
{
return 0;
}
}
}
{
case BAK_existing:
case BAK_number:
v = 0;
{
*s++ = 0;
}
else
{
e = (char*)dot;
}
n = strlen(s);
if (fts = fts_open((char**)e, FTS_NOCHDIR|FTS_ONEPATH|FTS_PHYSICAL|FTS_NOPOSTORDER|FTS_NOSTAT|FTS_NOSEEDOTDIR, NiL))
{
{
if (strneq(s, sub->fts_name, n) && sub->fts_name[n] == '.' && strneq(sub->fts_name + n + 1, state->suffix, state->suflen) && (m = strtol(sub->fts_name + n + state->suflen + 1, &e, 10)) && streq(e, state->suffix) && m > v)
v = m;
}
}
*--s = '/';
{
goto backup;
}
/*FALLTHROUGH*/
case BAK_simple:
{
return 0;
}
break;
default:
{
return 0;
}
break;
}
}
{
case MV:
for (;;)
{
return 0;
rm = 1;
{
rm = 1;
continue;
}
{
return 0;
}
else
break;
}
/*FALLTHROUGH*/
case CP:
{
{
return 0;
}
{
return 0;
}
}
{
{
return 0;
}
else if ((wfd = open(state->path, st.st_mode ? (state->wflags & ~O_EXCL) : state->wflags, ent->fts_statp->st_mode & state->perm)) < 0)
{
return 0;
}
{
{
}
else
{
n = 0;
{
}
else
{
n |= 3;
n |= 1;
n |= 2;
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"));
}
}
}
else
}
else if (S_ISBLK(ent->fts_statp->st_mode) || S_ISCHR(ent->fts_statp->st_mode) || S_ISFIFO(ent->fts_statp->st_mode))
{
{
return 0;
}
}
else
{
error(2, "%s: cannot copy -- unknown file type 0%o", ent->fts_path, S_ITYPE(ent->fts_statp->st_mode));
return 0;
}
{
{
else
{
if ((ent->fts_statp->st_mode & state->perm) != (st.st_mode & state->perm) && chmod(state->path, ent->fts_statp->st_mode & state->perm))
error(ERROR_SYSTEM|2, "%s: cannot reset mode to %s", state->path, fmtmode(st.st_mode & state->perm, 0) + 1);
}
}
}
break;
case LN:
break;
}
return 0;
}
int
{
register char* file;
register char* s;
char** v;
char* backup_type;
const char* usage;
int path_resolve;
int standard;
{
if (sh)
}
else
backup_type = 0;
switch (error_info.id[0])
{
case 'c':
case 'C':
path_resolve = -1;
break;
case 'l':
case 'L':
path_resolve = 1;
break;
case 'm':
case 'M':
path_resolve = 1;
break;
default:
break;
}
state->opname = state->op == CP ? ERROR_translate(0, 0, 0, "overwrite") : ERROR_translate(0, 0, 0, "replace");
for (;;)
{
{
case 'a':
path_resolve = 1;
continue;
case 'b':
continue;
case 'f':
state->interactive = 0;
continue;
case 'h':
continue;
case 'i':
continue;
case 'l':
continue;
case 'p':
continue;
case 'r':
if (path_resolve < 0)
path_resolve = 0;
continue;
case 's':
continue;
case 'u':
continue;
case 'v':
continue;
case 'x':
continue;
case 'F':
#if _lib_fsync
#else
#endif
continue;
case 'H':
path_resolve = 1;
continue;
case 'L':
path_resolve = 1;
continue;
case 'P':
path_resolve = 1;
continue;
case 'R':
path_resolve = 1;
continue;
case 'S':
continue;
case 'V':
continue;
case '?':
continue;
case ':':
continue;
}
break;
}
{
argc--;
argv++;
}
argv = v;
if (!standard)
{
if (!argc)
{
argc++;
}
}
{
else
switch (strkey(backup_type))
{
case HASHKEY1('e'):
break;
case HASHKEY1('s'):
break;
case HASHKEY1('t'):
break;
default:
if (file)
break;
}
}
if (!path_resolve)
{
while (*s == '/')
s++;
if (!(!*s || *s == '.' && (!*++s || *s == '.' && !*++s)))
s = 0;
}
if (state->pathsiz < roundof(state->postsiz + 2, PATH_CHUNK) && !(state->path = newof(state->path, char, state->pathsiz = roundof(state->postsiz + 2, PATH_CHUNK), 0)))
{
}
{
}
{
case CP:
break;
case LN:
break;
case MV:
break;
}
{
}
return error_info.errors != 0;
}