X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=bin%2Fad%2Fad_util.c;h=897bdf3b1415c609efdae24f2104d019ef3464fc;hb=bb90c6c56688f908a1d93125fec0941e1c79fed5;hp=ac05fc0a8807d09b360330da0d9e6aeef0a12ee0;hpb=869777e486e0cf24c3cef64b57765a18c0c227de;p=netatalk.git diff --git a/bin/ad/ad_util.c b/bin/ad/ad_util.c index ac05fc0a..897bdf3b 100644 --- a/bin/ad/ad_util.c +++ b/bin/ad/ad_util.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2009 Frank Lahm * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. @@ -25,7 +25,7 @@ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H @@ -33,7 +33,6 @@ #endif /* HAVE_CONFIG_H */ #include -#include #include #include #include @@ -47,14 +46,28 @@ #include #include #include +#include +#ifdef HAVE_SOLARIS_ACLS +#include +#endif /* HAVE_SOLARIS_ACLS */ + +#ifdef HAVE_POSIX_ACLS +#include +#include +#endif /* HAVE_POSIX_ACLS */ + +#include #include -#include #include #include -#include #include #include +#include +#include +#include + + #include "ad.h" int log_verbose; /* Logging flag */ @@ -78,66 +91,64 @@ void _log(enum logtype lt, char *fmt, ...) /*! * Load volinfo and initialize struct vol * + * Only opens "dbd" volumes ! + * * @param path (r) path to evaluate - * @param vol (rw) structure to initialize -* + * @param vol (rw) structure to initialize + * * @returns 0 on success, exits on error */ -int openvol(const char *path, afpvol_t *vol) +int openvol(AFPObj *obj, const char *path, afpvol_t *vol) { int flags = 0; memset(vol, 0, sizeof(afpvol_t)); - /* try to find a .AppleDesktop/.volinfo */ - if (loadvolinfo((char *)path, &vol->volinfo) == 0) { + if ((vol->vol = getvolbypath(obj, path)) == NULL) + return -1; - if (vol_load_charsets(&vol->volinfo) == -1) - ERROR("Error loading charsets!"); + if (STRCMP(vol->vol->v_cnidscheme, != , "dbd")) + ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->vol->v_path); - /* Sanity checks to ensure we can touch this volume */ - if (vol->volinfo.v_adouble != AD_VERSION2) - ERROR("Unsupported adouble versions: %u", vol->volinfo.v_adouble); + /* Sanity checks to ensure we can touch this volume */ + if (vol->vol->v_adouble != AD_VERSION2 + && vol->vol->v_adouble != AD_VERSION_EA) + ERROR("Unsupported adouble versions: %u", vol->vol->v_adouble); - if (vol->volinfo.v_vfs_ea != AFPVOL_EA_SYS) - ERROR("Unsupported Extended Attributes option: %u", vol->volinfo.v_vfs_ea); + if (vol->vol->v_vfs_ea != AFPVOL_EA_SYS) + ERROR("Unsupported Extended Attributes option: %u", vol->vol->v_vfs_ea); - /* initialize sufficient struct vol for VFS initialisation */ - vol->volume.v_adouble = AD_VERSION2; - vol->volume.v_vfs_ea = AFPVOL_EA_SYS; - initvol_vfs(&vol->volume); + if ((vol->vol->v_flags & AFPVOL_NODEV)) + flags |= CNID_FLAG_NODEV; - if ((vol->volinfo.v_flags & AFPVOL_NODEV)) - flags |= CNID_FLAG_NODEV; - - if ((vol->volume.v_cdb = cnid_open(vol->volinfo.v_dbpath, - 0000, - "dbd", - flags, - vol->volinfo.v_dbd_host, - vol->volinfo.v_dbd_port)) == NULL) - ERROR("Cant initialize CNID database connection for %s", vol->volinfo.v_path); - - cnid_getstamp(vol->volume.v_cdb, - vol->db_stamp, - sizeof(vol->db_stamp)); - } + if ((vol->vol->v_cdb = cnid_open(vol->vol->v_path, + 0000, + "dbd", + flags, + vol->vol->v_cnidserver, + vol->vol->v_cnidport)) == NULL) + ERROR("Cant initialize CNID database connection for %s", vol->vol->v_path); + cnid_getstamp(vol->vol->v_cdb, + vol->db_stamp, + sizeof(vol->db_stamp)); + return 0; } void closevol(afpvol_t *vol) { - if (vol->volume.v_cdb) - cnid_close(vol->volume.v_cdb); - + if (vol->vol->v_cdb) { + cnid_close(vol->vol->v_cdb); + vol->vol->v_cdb = NULL; + } memset(vol, 0, sizeof(afpvol_t)); } /* Taken form afpd/desktop.c */ -char *utompath(const struct volinfo *volinfo, const char *upath) +char *utompath(const struct vol *vol, const char *upath) { static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ char *m; @@ -152,30 +163,76 @@ char *utompath(const struct volinfo *volinfo, const char *upath) u = upath; outlen = strlen(upath); - if ((volinfo->v_casefold & AFPVOL_UTOMUPPER)) + if ((vol->v_casefold & AFPVOL_UTOMUPPER)) flags |= CONV_TOUPPER; - else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER)) + else if ((vol->v_casefold & AFPVOL_UTOMLOWER)) flags |= CONV_TOLOWER; - if ((volinfo->v_flags & AFPVOL_EILSEQ)) { + if ((vol->v_flags & AFPVOL_EILSEQ)) { flags |= CONV__EILSEQ; } /* convert charsets */ - if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset, + if ((size_t)-1 == ( outlen = convert_charset(vol->v_volcharset, CH_UTF8_MAC, - volinfo->v_maccharset, + vol->v_maccharset, u, outlen, mpath, MAXPATHLEN, &flags)) ) { SLOG("Conversion from %s to %s for %s failed.", - volinfo->v_volcodepage, volinfo->v_maccodepage, u); + vol->v_volcodepage, vol->v_maccodepage, u); return NULL; } return(m); } + +/*! + * Convert dot encoding of basename _in place_ + * + * path arg can be "[/][dir/ | ...]filename". It will be converted in place + * possible encoding ".file" as ":2efile" which means the result will be + * longer then the original which means provide a big enough buffer. + * + * @param svol (r) source volume + * @param dvol (r) destinatio volume + * @param path (rw) path to convert _in place_ + * @param buflen (r) size of path buffer (max strlen == buflen -1) + * + * @returns 0 on sucess, -1 on error + */ +int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path, size_t buflen) +{ + static charset_t from = (charset_t) -1; + static char buf[MAXPATHLEN+2]; + char *bname = stripped_slashes_basename(path); + int pos = bname - path; + uint16_t flags = 0; + + if ( ! svol->vol->v_path) { + /* no source volume: escape special chars (eg ':') */ + from = dvol->vol->v_volcharset; /* src = dst charset */ + if (dvol->vol->v_adouble == AD_VERSION2) + flags |= CONV_ESCAPEHEX; + } else { + from = svol->vol->v_volcharset; + } + + int len = convert_charset(from, + dvol->vol->v_volcharset, + dvol->vol->v_maccharset, + bname, strlen(bname), + buf, MAXPATHLEN, + &flags); + if (len == -1) + return -1; + + if (strlcpy(bname, buf, MAXPATHLEN - pos) > MAXPATHLEN - pos) + return -1; + return 0; +} + /*! - * Build path relativ to volume root + * ResolvesCNID of a given paths * * path might be: * (a) relative: @@ -183,48 +240,66 @@ char *utompath(const struct volinfo *volinfo, const char *upath) * (b) absolute: * "/afp_volume/dir/subdir" * - * @param path (r) path relative to cwd() or absolute - * @param volpath (r) volume path that path is a subdir of (has been computed in volinfo funcs) + * path MUST be pointing inside vol, this is usually the case as vol has been build from + * path using loadvolinfo and friends. * - * @returns relative path in new bstring, caller must bdestroy it + * @param vol (r) pointer to afpvol_t + * @param path (r) path, see above + * @param did (rw) parent CNID of returned CNID + * + * @returns CNID of path */ -static bstring rel_path_in_vol(const char *path, const char *volpath) +cnid_t cnid_for_path(const afpvol_t *vol, + const char *path, + cnid_t *did) { EC_INIT; - if (path == NULL || volpath == NULL) - return NULL; + cnid_t cnid; + bstring rpath = NULL; + bstring statpath = NULL; + struct bstrList *l = NULL; + struct stat st; - bstring fpath = NULL; + cnid = htonl(2); - /* Make path absolute by concetanating for case (a) */ - if (path[0] != '/') { - EC_NULL(fpath = bfromcstr(getcwdpath())); - if (bchar(fpath, blength(fpath) - 1) != '/') - EC_ZERO(bcatcstr(fpath, "/")); - EC_ZERO(bcatcstr(fpath, path)); - BSTRING_STRIP_SLASH(fpath); - } else { - EC_NULL(fpath = bfromcstr(path)); - BSTRING_STRIP_SLASH(fpath); - } + EC_NULL(rpath = rel_path_in_vol(path, vol->vol->v_path)); + EC_NULL(statpath = bfromcstr(vol->vol->v_path)); + EC_ZERO(bcatcstr(statpath, "/")); + + l = bsplit(rpath, '/'); + for (int i = 0; i < l->qty ; i++) { + *did = cnid; - /* - * Now we have eg: - * fpath: /Volume/netatalk/dir/bla - * volpath: /Volume/netatalk/ - * we want: "dir/bla" - */ - EC_ZERO(bdelete(fpath, 0, strlen(volpath))); - return fpath; + EC_ZERO(bconcat(statpath, l->entry[i])); + EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), + "lstat(rpath: %s, elem: %s): %s: %s", + cfrombstr(rpath), cfrombstr(l->entry[i]), + cfrombstr(statpath), strerror(errno)); + + if ((cnid = cnid_add(vol->vol->v_cdb, + &st, + *did, + cfrombstr(l->entry[i]), + blength(l->entry[i]), + 0)) == CNID_INVALID) { + EC_FAIL; + } + EC_ZERO(bcatcstr(statpath, "/")); + } EC_CLEANUP: - bdestroy(fpath); - return NULL; + bdestroy(rpath); + bstrListDestroy(l); + bdestroy(statpath); + if (ret != 0) + return CNID_INVALID; + + return cnid; } /*! - * ResolvesCNID of a given paths + * Resolves CNID of a given paths parent directory * * path might be: * (a) relative: @@ -232,24 +307,18 @@ EC_CLEANUP: * (b) absolute: * "/afp_volume/dir/subdir" * - * 1) start recursive CNID search with - * a) DID:2 / "topdir" - * b) DID:2 / "dir" - * 2) ...until we have the CNID for - * a) "/afp_volume/topdir/dir" - * b) "/afp_volume/dir" (no recursion required) + * path MUST be pointing inside vol, this is usually the case as vol has been build from + * path using loadvolinfo and friends. * - * @param vi (r) pointer to volinfo struct - * @param vol (r) pointer to vol struct + * @param vol (r) pointer to afpvol_t * @param path (r) path, see above * @param did (rw) parent CNID of returned CNID * * @returns CNID of path */ -cnid_t cnid_for_path(const struct volinfo *vi, - const struct vol *vol, - const char *path, - cnid_t *did) +cnid_t cnid_for_paths_parent(const afpvol_t *vol, + const char *path, + cnid_t *did) { EC_INIT; @@ -259,26 +328,33 @@ cnid_t cnid_for_path(const struct volinfo *vi, struct bstrList *l = NULL; struct stat st; - cnid = *did = htonl(2); + *did = htonl(1); + cnid = htonl(2); - EC_NULL(rpath = rel_path_in_vol(path, vi->v_path)); - EC_NULL(statpath = bfromcstr(vi->v_path)); + EC_NULL(rpath = rel_path_in_vol(path, vol->vol->v_path)); + EC_NULL(statpath = bfromcstr(vol->vol->v_path)); l = bsplit(rpath, '/'); - for(int i = 0; i < l->qty ; i++) { + if (l->qty == 1) + /* only one path element, means parent dir cnid is volume root = 2 */ + goto EC_CLEANUP; + for (int i = 0; i < (l->qty - 1); i++) { *did = cnid; EC_ZERO(bconcat(statpath, l->entry[i])); - EC_ZERO_LOG(stat(cfrombstr(statpath), &st)); - - cnid = cnid_add(vol->v_cdb, - &st, - *did, - cfrombstr(l->entry[i]), - blength(l->entry[i]), - 0); - + EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), + "lstat(rpath: %s, elem: %s): %s: %s", + cfrombstr(rpath), cfrombstr(l->entry[i]), + cfrombstr(statpath), strerror(errno)); + + if ((cnid = cnid_add(vol->vol->v_cdb, + &st, + *did, + cfrombstr(l->entry[i]), + blength(l->entry[i]), + 0)) == CNID_INVALID) { + EC_FAIL; + } EC_ZERO(bcatcstr(statpath, "/")); - } EC_CLEANUP: @@ -291,4 +367,3 @@ EC_CLEANUP: return cnid; } -