mirror of
https://codeberg.org/landley/toybox.git
synced 2026-01-26 14:13:25 +00:00
Add ln -r and relative_path() to lib, plus test.
And a few small cleanups while I was there.
This commit is contained in:
parent
dec46177db
commit
49feb50f22
29
lib/lib.c
29
lib/lib.c
@ -216,6 +216,7 @@ int mkpath(char *dir)
|
||||
}
|
||||
|
||||
// Split a path into linked list of components, tracking head and tail of list.
|
||||
// Assigns head of list to *list, returns address of ->next entry to extend list
|
||||
// Filters out // entries with no contents.
|
||||
struct string_list **splitpath(char *path, struct string_list **list)
|
||||
{
|
||||
@ -1028,6 +1029,34 @@ char *fileunderdir(char *file, char *dir)
|
||||
return rc ? s2 : 0;
|
||||
}
|
||||
|
||||
// return (malloced) relative path to get from "from" to "to"
|
||||
char *relative_path(char *from, char *to)
|
||||
{
|
||||
char *s, *ret = 0;
|
||||
int i, j, k;
|
||||
|
||||
if (!(from = xabspath(from, -1))) return 0;
|
||||
if (!(to = xabspath(to, -1))) goto error;
|
||||
|
||||
// skip common directories from root
|
||||
for (i = j = 0; from[i] && from[i] == to[i]; i++) if (to[i] == '/') j = i+1;
|
||||
|
||||
// count remaining destination directories
|
||||
for (i = j, k = 0; from[i]; i++) if (from[i] == '/') k++;
|
||||
|
||||
if (!k) ret = xstrdup(to+j);
|
||||
else {
|
||||
s = ret = xmprintf("%*c%s", 3*k, ' ', to+j);
|
||||
while (k--) memcpy(s+3*k, "../", 3);
|
||||
}
|
||||
|
||||
error:
|
||||
free(from);
|
||||
free(to);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Execute a callback for each PID that matches a process name from a list.
|
||||
void names_to_pid(char **names, int (*callback)(pid_t pid, char *name),
|
||||
int scripts)
|
||||
|
||||
@ -402,6 +402,7 @@ mode_t string_to_mode(char *mode_str, mode_t base);
|
||||
void mode_to_string(mode_t mode, char *buf);
|
||||
char *getbasename(char *name);
|
||||
char *fileunderdir(char *file, char *dir);
|
||||
char *relative_path(char *from, char *to);
|
||||
void names_to_pid(char **names, int (*callback)(pid_t pid, char *name),
|
||||
int scripts);
|
||||
|
||||
|
||||
@ -55,6 +55,7 @@ rm -rf file dir slink
|
||||
|
||||
testing "-t" "ln -st . one/two three && readlink two three" "one/two\nthree\n" \
|
||||
"" ""
|
||||
rm -f two three
|
||||
|
||||
touch file1 file2 && mkdir dir
|
||||
testing "create_multiple_hardlinks" "ln file* dir/ &&
|
||||
@ -78,3 +79,12 @@ testing "create_hardlink_and_remove_sourcefile" "ln file hlink &&
|
||||
[ file -ef hlink ] && rm file && [ -f hlink ] && echo 'yes'" \
|
||||
"yes\n" "" ""
|
||||
rm -f file hlink
|
||||
|
||||
mkdir -p one/two
|
||||
ln -s . circular
|
||||
mkdir -p three
|
||||
echo hello > three/four
|
||||
testing "ln -r" \
|
||||
"ln -sr circular/three/../three/four one/two/five && cat one/two/five" \
|
||||
"hello\n" "" ""
|
||||
rm -rf one three circular
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*
|
||||
* See http://opengroup.org/onlinepubs/9699919799/utilities/ln.html
|
||||
|
||||
USE_LN(NEWTOY(ln, "<1t:Tvnfs", TOYFLAG_BIN))
|
||||
USE_LN(NEWTOY(ln, "<1rt:Tvnfs", TOYFLAG_BIN))
|
||||
|
||||
config LN
|
||||
bool "ln"
|
||||
@ -18,6 +18,7 @@ config LN
|
||||
-s Create a symbolic link
|
||||
-f Force the creation of the link, even if TO already exists
|
||||
-n Symlink at TO treated as file
|
||||
-r Create relative symlink from -> to
|
||||
-t Create links in DIR
|
||||
-T TO always treated as file, max 2 arguments
|
||||
-v Verbose
|
||||
@ -34,30 +35,37 @@ void ln_main(void)
|
||||
{
|
||||
char *dest = TT.t ? TT.t : toys.optargs[--toys.optc], *new;
|
||||
struct stat buf;
|
||||
int i;
|
||||
int i, rc;
|
||||
|
||||
if (FLAG(T) && toys.optc>1) help_exit("Max 2 arguments");
|
||||
|
||||
// With one argument, create link in current directory.
|
||||
if (!toys.optc) {
|
||||
toys.optc++;
|
||||
dest=".";
|
||||
dest = ".";
|
||||
}
|
||||
|
||||
if (FLAG(T) && toys.optc>1) help_exit("Max 2 arguments");
|
||||
// Is destination a directory?
|
||||
if (!((FLAG(n)||FLAG(T)) ? lstat : stat)(dest, &buf)) {
|
||||
i = S_ISDIR(buf.st_mode);
|
||||
|
||||
if ((FLAG(T) && i) || (!i && (toys.optc>1 || TT.t)))
|
||||
if ((i = S_ISDIR(buf.st_mode)) ? FLAG(T) : (toys.optc>1 || TT.t))
|
||||
error_exit("'%s' %s a directory", dest, i ? "is" : "not");
|
||||
} else buf.st_mode = 0;
|
||||
|
||||
for (i=0; i<toys.optc; i++) {
|
||||
int rc;
|
||||
char *oldnew, *try = toys.optargs[i];
|
||||
char *oldnew = 0, *try = toys.optargs[i];
|
||||
|
||||
if (S_ISDIR(buf.st_mode)) new = xmprintf("%s/%s", dest, basename(try));
|
||||
else new = dest;
|
||||
|
||||
if (FLAG(r)) {
|
||||
try = relative_path(new, try);
|
||||
if (!try) {
|
||||
if (new != dest) free(new);
|
||||
continue;
|
||||
}
|
||||
toys.optflags |= FLAG_s;
|
||||
}
|
||||
|
||||
// Force needs to unlink the existing target (if any). Do that by creating
|
||||
// a temp version and renaming it over the old one, so we can retain the
|
||||
// old file in cases we can't replace it (such as hardlink between mounts).
|
||||
@ -88,6 +96,7 @@ void ln_main(void)
|
||||
FLAG(s) ? "symbolic" : "hard", try, new);
|
||||
else if (FLAG(v)) fprintf(stderr, "'%s' -> '%s'\n", new, try);
|
||||
|
||||
if (try != toys.optargs[i]) free(try);
|
||||
if (new != dest) free(new);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user