skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

commit f5e75663fef044cad02eef3eb7aef295312c1158
parent 6d8832cddea6e0d3407d8ce7f11d9baf6425a9ef
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Wed,  9 Oct 2019 15:07:23 +0000

 Add path_canonicalize, prepare for 2.9.1.0

Diffstat:
MNEWS | 6++++++
Mdoc/index.html | 2+-
Mdoc/libstddjb/djbunix.html | 13+++++++++++++
Mdoc/upgrade.html | 6++++++
Mpackage/deps.mak | 1+
Mpackage/info | 2+-
Msrc/include/skalibs/djbunix.h | 2++
Asrc/libstddjb/path_canonicalize.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS @@ -1,5 +1,11 @@ Changelog for skalibs. +In 2.9.1.0 +---------- + + - Added path_canonicalize() + + In 2.9.0.0 ---------- diff --git a/doc/index.html b/doc/index.html @@ -60,7 +60,7 @@ with a standard C development environment </li> <h3> Download </h3> <ul> - <li> The current released version of skalibs is <a href="skalibs-2.9.0.0.tar.gz">2.9.0.0</a>. </li> + <li> The current released version of skalibs is <a href="skalibs-2.9.1.0.tar.gz">2.9.1.0</a>. </li> <li> Alternatively, you can checkout a copy of the <a href="//git.skarnet.org/cgi-bin/cgit.cgi/skalibs/">skalibs git repository</a>: diff --git a/doc/libstddjb/djbunix.html b/doc/libstddjb/djbunix.html @@ -808,5 +808,18 @@ Sleeps <em>n</em> milliseconds. Signals received during that time are handled, but <em>do not</em> interrupt the sleep. </p> +<h3> Miscellaneous functions </h3> + +<p> +<code> size_t path_canonicalize (char *out, char const *in, int check) </code> <br /> +Writes into <em>out</em> the canonical form of the Unix path given in +<em>in</em>. The <em>out</em> array must be preallocated with at least +<tt>strlen(in)+2</tt> bytes. Returns the length of the <em>out</em> path, without +counting the terminating null byte. If <em>check</em> is nonzero, <em>in</em> is tested +for every <tt>foobar/..</tt> element, and the function returns 0, and sets errno +appropriately, if <tt>foobar</tt> is not a valid directory; in that case, <em>out</em> +contains the problematic path. +</p> + </body> </html> diff --git a/doc/upgrade.html b/doc/upgrade.html @@ -16,6 +16,12 @@ <a href="//skarnet.org/">skarnet.org</a> </p> +<h2> in 2.9.1.0 </h2> + +<ul> + <li> New function: <tt>path_canonicalize</tt> </li> +</ul> + <h2> in 2.9.0.0 </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak @@ -458,6 +458,7 @@ src/libstddjb/openwritenclose_unsafe.o src/libstddjb/openwritenclose_unsafe.lo: src/libstddjb/openwritevnclose.o src/libstddjb/openwritevnclose.lo: src/libstddjb/openwritevnclose.c src/include/skalibs/djbunix.h src/libstddjb/openwritevnclose_suffix.o src/libstddjb/openwritevnclose_suffix.lo: src/libstddjb/openwritevnclose_suffix.c src/include/skalibs/djbunix.h src/libstddjb/openwritevnclose_unsafe.o src/libstddjb/openwritevnclose_unsafe.lo: src/libstddjb/openwritevnclose_unsafe.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h +src/libstddjb/path_canonicalize.o src/libstddjb/path_canonicalize.lo: src/libstddjb/path_canonicalize.c src/include/skalibs/djbunix.h src/libstddjb/pathexec.o src/libstddjb/pathexec.lo: src/libstddjb/pathexec.c src/include/skalibs/djbunix.h src/include/skalibs/env.h src/include/skalibs/posixplz.h src/libstddjb/pathexec0.o src/libstddjb/pathexec0.lo: src/libstddjb/pathexec0.c src/include/skalibs/djbunix.h src/libstddjb/pathexec0_run.o src/libstddjb/pathexec0_run.lo: src/libstddjb/pathexec0_run.c src/include/skalibs/djbunix.h diff --git a/package/info b/package/info @@ -1,4 +1,4 @@ package=skalibs -version=2.9.0.0 +version=2.9.1.0 category=prog package_macro_name=SKALIBS diff --git a/src/include/skalibs/djbunix.h b/src/include/skalibs/djbunix.h @@ -53,6 +53,8 @@ extern int open_write (char const *) ; extern int socket_internal (int, int, int, unsigned int) ; extern int socketpair_internal (int, int, int, unsigned int, int *) ; +extern size_t path_canonicalize (char *, char const *, int) ; + extern int pathexec_env (char const *, char const *) ; extern void pathexec_r (char const *const *, char const *const *, size_t, char const *, size_t) ; extern void pathexec_r_name (char const *, char const *const *, char const *const *, size_t, char const *, size_t) ; diff --git a/src/libstddjb/path_canonicalize.c b/src/libstddjb/path_canonicalize.c @@ -0,0 +1,69 @@ +/* ISC license. */ + +#include <errno.h> +#include <sys/stat.h> + +#include <skalibs/djbunix.h> + +static unsigned char cclass (char c) +{ + switch (c) + { + case 0 : return 0 ; + case '/' : return 1 ; + case '.' : return 2 ; + default : return 3 ; + } +} + + /* out must be at least strlen(in) + 2 bytes */ + +size_t path_canonicalize (char *out, char const *in, int check) +{ + static unsigned char const table[4][4] = + { + { 0x04, 0x00, 0x12, 0x11 }, + { 0x04, 0x50, 0x11, 0x11 }, + { 0x24, 0x20, 0x13, 0x11 }, + { 0xa4, 0xa0, 0x11, 0x11 } + } ; + int isabsolute = in[0] == '/' ; + size_t j = 0 ; + unsigned int depth = 0 ; + unsigned char state = 0 ; + + if (isabsolute) *out++ = *in++ ; + while (state < 4) + { + char c = *in++ ; + unsigned char what = table[state][cclass(c)] ; + state = what & 0x07 ; + if (what & 0x80) + { + if (depth) + { + depth-- ; + j -= 3 ; + if (check) + { + struct stat st ; + out[j] = 0 ; + if (stat(out - isabsolute, &st) < 0) return 0 ; + if (!S_ISDIR(st.st_mode)) return (errno = ENOTDIR, 0) ; + } + } + else if (!isabsolute) + { + out[j++] = '/' ; + out[j++] = '.' ; + } + } + if (what & 0x40) depth++ ; + if (what & 0x20) while (j && out[j-1] != '/') j-- ; + if (what & 0x10) out[j++] = c ; + } + if (j && out[j-1] == '/') j-- ; + if (!j && !isabsolute) out[j++] = '.' ; + out[j] = 0 ; + return j ; +}