1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-06-01 21:06:04 +02:00

24972: Phil Pennock: zf_* variants of zsh/files builtins plus extra options

This commit is contained in:
Peter Stephenson 2008-05-08 09:03:49 +00:00
parent ed671ad85a
commit 16c03b4cbf
4 changed files with 100 additions and 19 deletions

View File

@ -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:

View File

@ -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) ...)(

View File

@ -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 = {

View File

@ -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"