mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-01 05:16:05 +01:00
24972: Phil Pennock: zf_* variants of zsh/files builtins plus extra options
This commit is contained in:
parent
ed671ad85a
commit
16c03b4cbf
4 changed files with 100 additions and 19 deletions
|
@ -1,3 +1,9 @@
|
|||
2008-05-08 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* 24972: Phil Pennock: Doc/Zsh/mod_files.yo, Src/Modules/files.c,
|
||||
Src/Modules/files.mdd: Add zf_* commands for zsh/files modules
|
||||
plus a few extra options.
|
||||
|
||||
2008-05-07 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 24962: Oliver: Functions/Prompts/prompt_oliver_setup:
|
||||
|
|
|
@ -2,7 +2,17 @@ COMMENT(!MOD!zsh/files
|
|||
Some basic file manipulation commands as builtins.
|
||||
!MOD!)
|
||||
cindex(files, manipulating)
|
||||
The tt(zsh/files) module makes some standard commands available as builtins:
|
||||
The tt(zsh/files) module makes available some common commands for file
|
||||
manipulation as builtins; these commands are probably not needed for
|
||||
many normal situations but can be useful in emergency recovery
|
||||
situations with constrained resources. The commands do not implement
|
||||
all features now required by relevant standards committees.
|
||||
|
||||
For all commands, a variant beginning tt(zf_) is also available and loaded
|
||||
automatically. Using the features capability of zmodload will let you load
|
||||
only those names you want.
|
||||
|
||||
The commands loaded by default are:
|
||||
|
||||
startitem()
|
||||
findex(chgrp)
|
||||
|
@ -51,8 +61,8 @@ a deep directory tree can't end up recursively chowning tt(/usr) as
|
|||
a result of directories being moved up the tree.
|
||||
)
|
||||
findex(ln)
|
||||
xitem(tt(ln) [ tt(-dfis) ] var(filename) var(dest))
|
||||
item(tt(ln) [ tt(-dfis) ] var(filename) ... var(dir))(
|
||||
xitem(tt(ln) [ tt(-dfhins) ] var(filename) var(dest))
|
||||
item(tt(ln) [ tt(-dfhins) ] var(filename) ... var(dir))(
|
||||
Creates hard (or, with tt(-s), symbolic) links. In the first form, the
|
||||
specified var(dest)ination is created, as a link to the specified
|
||||
var(filename). In the second form, each of the var(filename)s is
|
||||
|
@ -69,6 +79,16 @@ By default, existing files cannot be replaced by links.
|
|||
The tt(-i) option causes the user to be queried about replacing
|
||||
existing files. The tt(-f) option causes existing files to be
|
||||
silently deleted, without querying. tt(-f) takes precedence.
|
||||
|
||||
The tt(-h) and tt(-n) options are identical and both exist for
|
||||
compatibility; either one indicates that if the target is a symlink
|
||||
then it should not be dereferenced.
|
||||
Typically this is used in combination with tt(-sf) so that if an
|
||||
existing link points to a directory then it will be removed,
|
||||
instead of followed.
|
||||
If this option is used with multiple filenames and the target
|
||||
is a symbolic link pointing to a directory then the result is
|
||||
an error.
|
||||
)
|
||||
findex(mkdir)
|
||||
item(tt(mkdir) [ tt(-p) ] [ tt(-m) var(mode) ] var(dir) ...)(
|
||||
|
|
|
@ -166,23 +166,37 @@ bin_rmdir(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
|
|||
#define BIN_LN 0
|
||||
#define BIN_MV 1
|
||||
|
||||
#define MV_NODIRS (1<<0)
|
||||
#define MV_FORCE (1<<1)
|
||||
#define MV_INTER (1<<2)
|
||||
#define MV_ASKNW (1<<3)
|
||||
#define MV_ATOMIC (1<<4)
|
||||
#define MV_NODIRS (1<<0)
|
||||
#define MV_FORCE (1<<1)
|
||||
#define MV_INTERACTIVE (1<<2)
|
||||
#define MV_ASKNW (1<<3)
|
||||
#define MV_ATOMIC (1<<4)
|
||||
#define MV_NOCHASETARGET (1<<5)
|
||||
|
||||
/* bin_ln actually does three related jobs: hard linking, symbolic *
|
||||
* linking, and renaming. If called as mv it renames, otherwise *
|
||||
* it looks at the -s option. If hard linking, it will refuse to *
|
||||
* attempt linking to a directory unless the -d option is given. */
|
||||
/*
|
||||
* bin_ln actually does three related jobs: hard linking, symbolic
|
||||
* linking, and renaming. If called as mv it renames, otherwise
|
||||
* it looks at the -s option. If hard linking, it will refuse to
|
||||
* attempt linking to a directory unless the -d option is given.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Option compatibility: BSD systems settled on using mostly-standardised
|
||||
* options across multiple commands to deal with symlinks; see, eg,
|
||||
* symlink(7) on a *BSD system for details. Per this, to work on a link
|
||||
* directly we use "-h" and "ln -hsf" will not follow the target if it
|
||||
* points to a directory. GNU settled on using -n for ln(1), so we
|
||||
* have "ln -nsf". We handle them both.
|
||||
*
|
||||
* Logic compared against that of FreeBSD's ln.c, compatible license.
|
||||
*/
|
||||
|
||||
/**/
|
||||
static int
|
||||
bin_ln(char *nam, char **args, Options ops, int func)
|
||||
{
|
||||
MoveFunc move;
|
||||
int flags, err = 0;
|
||||
int flags, have_dir, err = 0;
|
||||
char **a, *ptr, *rp, *buf;
|
||||
struct stat st;
|
||||
size_t blen;
|
||||
|
@ -195,6 +209,8 @@ bin_ln(char *nam, char **args, Options ops, int func)
|
|||
} else {
|
||||
flags = OPT_ISSET(ops,'f') ? MV_FORCE : 0;
|
||||
#ifdef HAVE_LSTAT
|
||||
if(OPT_ISSET(ops,'h') || OPT_ISSET(ops,'n'))
|
||||
flags |= MV_NOCHASETARGET;
|
||||
if(OPT_ISSET(ops,'s'))
|
||||
move = (MoveFunc) symlink;
|
||||
else
|
||||
|
@ -206,12 +222,39 @@ bin_ln(char *nam, char **args, Options ops, int func)
|
|||
}
|
||||
}
|
||||
if(OPT_ISSET(ops,'i') && !OPT_ISSET(ops,'f'))
|
||||
flags |= MV_INTER;
|
||||
flags |= MV_INTERACTIVE;
|
||||
for(a = args; a[1]; a++) ;
|
||||
if(a != args) {
|
||||
rp = unmeta(*a);
|
||||
if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode))
|
||||
goto havedir;
|
||||
if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode)) {
|
||||
have_dir = 1;
|
||||
if((flags & MV_NOCHASETARGET)
|
||||
&& !lstat(rp, &st) && S_ISLNK(st.st_mode)) {
|
||||
/*
|
||||
* So we have "ln -h" with the target being a symlink pointing
|
||||
* to a directory; if there are multiple sources but the target
|
||||
* is a symlink, then it's an error as we're not following
|
||||
* symlinks; if OTOH there's just one source, then we need to
|
||||
* either fail EEXIST or if "-f" given then remove the target.
|
||||
*/
|
||||
if(a > args+1) {
|
||||
errno = ENOTDIR;
|
||||
zwarnnam(nam, "%s: %e", *a, errno);
|
||||
return 1;
|
||||
}
|
||||
if(flags & MV_FORCE) {
|
||||
unlink(rp);
|
||||
have_dir = 0;
|
||||
} else {
|
||||
errno = EEXIST;
|
||||
zwarnnam(nam, "%s: %e", *a, errno);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Normal case, target is a directory, chase into it */
|
||||
if (have_dir)
|
||||
goto havedir;
|
||||
}
|
||||
}
|
||||
if(a > args+1) {
|
||||
zwarnnam(nam, "last of many arguments must be a directory");
|
||||
|
@ -269,7 +312,7 @@ domove(char *nam, MoveFunc move, char *p, char *q, int flags)
|
|||
zwarnnam(nam, "%s: cannot overwrite directory", q);
|
||||
zsfree(pbuf);
|
||||
return 1;
|
||||
} else if(flags & MV_INTER) {
|
||||
} else if(flags & MV_INTERACTIVE) {
|
||||
nicezputs(nam, stderr);
|
||||
fputs(": replace `", stderr);
|
||||
nicezputs(q, stderr);
|
||||
|
@ -705,12 +748,14 @@ bin_chown(char *nam, char **args, Options ops, int func)
|
|||
/* module paraphernalia */
|
||||
|
||||
#ifdef HAVE_LSTAT
|
||||
# define LN_OPTS "dfis"
|
||||
# define LN_OPTS "dfhins"
|
||||
#else
|
||||
# define LN_OPTS "dfi"
|
||||
#endif
|
||||
|
||||
static struct builtin bintab[] = {
|
||||
/* The names which overlap commands without necessarily being
|
||||
* fully compatible. */
|
||||
BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs", NULL),
|
||||
BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs", NULL),
|
||||
BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
|
||||
|
@ -719,6 +764,16 @@ static struct builtin bintab[] = {
|
|||
BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
|
||||
BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
|
||||
BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
|
||||
/* The "safe" zsh-only names */
|
||||
BUILTIN("zf_chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs", NULL),
|
||||
BUILTIN("zf_chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs", NULL),
|
||||
BUILTIN("zf_ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
|
||||
BUILTIN("zf_mkdir", 0, bin_mkdir, 1, -1, 0, "pm:", NULL),
|
||||
BUILTIN("zf_mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
|
||||
BUILTIN("zf_rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
|
||||
BUILTIN("zf_rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
|
||||
BUILTIN("zf_sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
|
||||
|
||||
};
|
||||
|
||||
static struct features module_features = {
|
||||
|
|
|
@ -2,6 +2,6 @@ name=zsh/files
|
|||
link=dynamic
|
||||
load=no
|
||||
|
||||
autofeatures="b:chgrp b:chown b:ln b:mkdir b:mv b:rm b:rmdir b:sync"
|
||||
autofeatures="b:chgrp b:chown b:ln b:mkdir b:mv b:rm b:rmdir b:sync b:zf_chgrp b:zf_chown b:zf_ln b:zf_mkdir b:zf_mv b:zf_rm b:zf_rmdir b:zf_sync"
|
||||
|
||||
objects="files.o"
|
||||
|
|
Loading…
Reference in a new issue