from = svol->vol->v_volcharset;
}
- if ( (svol->vol->v_path)
- && ! (svol->vol->v_flags & AFPVOL_USEDOTS)
- && (dvol->vol->v_flags & AFPVOL_USEDOTS)) {
- /* source is without dots, destination is with */
- flags |= CONV_UNESCAPEHEX;
- } else if (! (dvol->vol->v_flags & AFPVOL_USEDOTS)) {
- flags |= CONV_ESCAPEDOTS;
- }
-
int len = convert_charset(from,
dvol->vol->v_volcharset,
dvol->vol->v_maccharset,
continue;
}
memset(&s_path, 0, sizeof(s_path));
+
+ /* conversions on the fly */
+ const char *convname;
s_path.u_name = sd.sd_last;
- if (of_stat( &s_path) < 0 ) {
- /*
- * Somebody else plays with the dir, well it can be us with
- * "Empty Trash..."
- */
+ if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0 && convname) {
+ s_path.u_name = (char *)convname;
+ }
+ if (of_stat( &s_path) < 0 ) {
/* so the next time it won't try to stat it again
* another solution would be to invalidate the cache with
* sd.sd_did = 0 but if it's not ENOENT error it will start again
continue;
}
+ /* Fixup CNID db if ad_convert resulted in a rename (then convname != NULL) */
+ if (convname) {
+ s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last));
+ if (s_path.id != CNID_INVALID) {
+ if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, convname, strlen(convname)) != 0)
+ LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname));
+ }
+ }
+
sd.sd_last += len + 1;
s_path.m_name = NULL;
- /* Convert adouble:v2 to adouble:ea on the fly */
- (void)ad_convert(s_path.u_name, &s_path.st, vol);
-
/*
* If a fil/dir is not a dir, it's a file. This is slightly
* inaccurate, since that means /dev/null is a file, /dev/printer
*/
int check_name(const struct vol *vol, char *name)
{
- if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/'))
- return AFPERR_PARAM;
-
if (!vol->vfs->vfs_validupath(vol, name)) {
LOG(log_error, logtype_afpd, "check_name: illegal name: '%s'", name);
return AFPERR_EXIST;
* .Parent file here if it doesn't exist. */
/* Convert adouble:v2 to adouble:ea on the fly */
- (void)ad_convert(vol->v_path, st, vol);
+ (void)ad_convert(vol->v_path, st, vol, NULL);
ad_init(&ad, vol);
if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) {
}
/* set conversion flags */
- if (!(myvol->v_flags & AFPVOL_NOHEX))
- flags |= CONV_ESCAPEHEX;
- if (!(myvol->v_flags & AFPVOL_USEDOTS))
- flags |= CONV_ESCAPEDOTS;
-
if ((myvol->v_casefold & AFPVOL_MTOUUPPER))
flags |= CONV_TOUPPER;
else if ((myvol->v_casefold & AFPVOL_MTOULOWER))
if (myvol->v_adouble == AD_VERSION_EA) {
if (!(dbd_flags & DBD_FLAGS_V2TOEA))
return 0;
- if (ad_convert(fname, st, myvol) != 0) {
+ if (ad_convert(fname, st, myvol, NULL) != 0) {
switch (errno) {
case ENOENT:
break;
if ((myvol->v_adouble == AD_VERSION_EA) && (dbd_flags & DBD_FLAGS_V2TOEA)) {
if (lstat(".", &st) != 0)
return -1;
- if (ad_convert(".", &st, vol) != 0) {
+ if (ad_convert(".", &st, vol, NULL) != 0) {
switch (errno) {
case ENOENT:
break;
extern int ad_metadata (const char *, int, struct adouble *);
extern int ad_metadataat (int, const char *, int, struct adouble *);
extern mode_t ad_hf_mode(mode_t mode);
-extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol);
extern int ad_valid_header_osx(const char *path);
+
+/* ad_conv.c */
+extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath);
+
/* ad_read.c/ad_write.c */
extern int sys_ftruncate(int fd, off_t length);
extern ssize_t ad_read(struct adouble *, uint32_t, off_t, char *, size_t);
#define AFPVOL_NOV2TOEACONV (1 << 5) /* no adouble:v2 to adouble:ea conversion */
#define AFPVOL_UNIX_CTXT (1 << 6) /* volume created by getvolbypath ie UNIX access, not afpd AFP user session */
#define AFPVOL_RO (1 << 8) /* read-only volume */
-#define AFPVOL_NOHEX (1 << 10) /* don't do :hex translation */
-#define AFPVOL_USEDOTS (1 << 11) /* use real dots */
#define AFPVOL_NOSTAT (1 << 16) /* advertise the volume even if we can't stat() it
* maybe because it will be mounted later in preexec */
#define AFPVOL_UNIX_PRIV (1 << 17) /* support unix privileges */
noinst_LTLIBRARIES = libadouble.la
-libadouble_la_SOURCES = ad_open.c ad_flush.c ad_read.c ad_write.c ad_size.c \
- ad_mmap.c ad_lock.c ad_date.c ad_attr.c ad_sendfile.c
+libadouble_la_SOURCES = \
+ ad_attr.c \
+ ad_conv.c \
+ ad_date.c \
+ ad_flush.c \
+ ad_lock.c \
+ ad_mmap.c \
+ ad_open.c \
+ ad_read.c \
+ ad_sendfile.c \
+ ad_size.c \
+ ad_write.c
noinst_HEADERS = ad_lock.h
--- /dev/null
+/*
+ * Copyright (c) 2012 Frank Lahm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*!
+ * @file
+ * Part of Netatalk's AppleDouble implementatation
+ * @sa include/atalk/adouble.h
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <errno.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <arpa/inet.h>
+
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+#include <atalk/ea.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/compat.h>
+#include <atalk/errchk.h>
+#include <atalk/volume.h>
+
+#include "ad_lock.h"
+
+static char emptyfilad[32] = {0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0};
+
+static char emptydirad[32] = {0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,1,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0};
+
+static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
+{
+ EC_INIT;
+ struct adouble adv2;
+ struct adouble adea;
+ const char *adpath;
+ int adflags;
+ uint32_t ctime, mtime, afpinfo = 0;
+ char *emptyad;
+
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
+
+ ad_init(&adea, vol);
+ ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+ adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+
+ /* Open and lock adouble:v2 file */
+ EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
+
+ EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+ EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
+
+ /* Check if it's a non-empty header */
+ if (S_ISREG(sp->st_mode))
+ emptyad = &emptyfilad[0];
+ else
+ emptyad = &emptydirad[0];
+
+ if (ad_getentrylen(&adv2, ADEID_COMMENT) != 0)
+ goto copy;
+ if (ad_getentryoff(&adv2, ADEID_FINDERI)
+ && (ad_getentrylen(&adv2, ADEID_FINDERI) == ADEDLEN_FINDERI)
+ && (memcmp(ad_entry(&adv2, ADEID_FINDERI), emptyad, ADEDLEN_FINDERI) != 0))
+ goto copy;
+ if (ad_getentryoff(&adv2, ADEID_FILEDATESI)) {
+ EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_CREATE | AD_DATE_UNIX, &ctime) );
+ EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_MODIFY | AD_DATE_UNIX, &mtime) );
+ if ((ctime != mtime) || (mtime != sp->st_mtime))
+ goto copy;
+ }
+ if (ad_getentryoff(&adv2, ADEID_AFPFILEI)) {
+ if (memcmp(ad_entry(&adv2, ADEID_AFPFILEI), &afpinfo, ADEDLEN_AFPFILEI) != 0)
+ goto copy;
+ }
+
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): default adouble", fullpathname(path), ret);
+ goto EC_CLEANUP;
+
+copy:
+ /* Create a adouble:ea meta EA */
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): copying adouble", fullpathname(path), ret);
+ EC_ZERO_LOG( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE) );
+ EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
+ ad_flush(&adea);
+
+EC_CLEANUP:
+ EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
+ EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): END: %d", fullpathname(path), ret);
+ EC_EXIT;
+}
+
+static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
+{
+ EC_INIT;
+ struct adouble adv2;
+ struct adouble adea;
+
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
+
+ if (S_ISDIR(sp->st_mode))
+ return 0;
+
+ ad_init(&adea, vol);
+ ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
+
+ /* Open and lock adouble:v2 file */
+ EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
+
+ if (adv2.ad_rlen > 0) {
+ EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
+
+ /* Create a adouble:ea resource fork */
+ EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
+
+ EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
+ adea.ad_rlen = adv2.ad_rlen;
+ ad_flush(&adea);
+ }
+
+EC_CLEANUP:
+ EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
+ EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): END: %d", fullpathname(path), ret);
+ EC_EXIT;
+}
+
+static int ad_conv_v22ea(const char *path, const struct stat *sp, const struct vol *vol)
+{
+ EC_INIT;
+ const char *adpath;
+ int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+
+ EC_ZERO( ad_conv_v22ea_hf(path, sp, vol) );
+ EC_ZERO( ad_conv_v22ea_rf(path, sp, vol) );
+
+ EC_NULL( adpath = ad_path(path, adflags) );
+ LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
+ path, fullpathname(adpath));
+
+ become_root();
+ EC_ZERO_LOG( unlink(adpath) );
+ unbecome_root();
+
+EC_CLEANUP:
+ if (errno == ENOENT)
+ EC_STATUS(0);
+ EC_EXIT;
+}
+
+/*!
+ * Remove hexencoded dots and slashes (":2e" and ":2f")
+ */
+static int ad_conv_dehex(const char *path, const struct stat *sp, const struct vol *vol, const char **newpathp)
+{
+ EC_INIT;
+ static char buf[MAXPATHLEN];
+ const char *adpath, *p;
+ int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
+ bstring newpath = NULL;
+
+ LOG(log_debug, logtype_default,"ad_conv_dehex(\"%s\"): BEGIN", fullpathname(path));
+
+ *newpathp = NULL;
+
+ if ((p = strchr(path, ':')) == NULL)
+ goto EC_CLEANUP;
+
+ EC_NULL( newpath = bfromcstr(path) );
+
+ EC_ZERO( bfindreplace(newpath, bfromcstr(":2e"), bfromcstr("."), 0) );
+ EC_ZERO( bfindreplace(newpath, bfromcstr(":2f"), bfromcstr(":"), 0) );
+
+ become_root();
+ if (adflags != ADFLAGS_DIR)
+ rename(vol->ad_path(path, 0), vol->ad_path(bdata(newpath), 0));
+ rename(path, bdata(newpath));
+ unbecome_root();
+
+ strlcpy(buf, bdata(newpath), sizeof(buf));
+ *newpathp = buf;
+
+EC_CLEANUP:
+ if (newpath)
+ bdestroy(newpath);
+ EC_EXIT;
+}
+
+/*!
+ * AppleDouble and encoding conversion on the fly
+ *
+ * @param path (r) path to file or directory
+ * @param sp (r) stat(path)
+ * @param vol (r) volume handle
+ * @param newpath (w) if encoding changed, new name. Can be NULL.
+ *
+ * @returns -1 on internal error, otherwise 0. newpath is NULL if no character conversion was done,
+ * otherwise newpath points to a static string with the converted name
+ */
+int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath)
+{
+ EC_INIT;
+ const char *p;
+
+ LOG(log_debug, logtype_default,"ad_convert(\"%s\"): BEGIN", fullpathname(path));
+
+ if (newpath)
+ *newpath = NULL;
+
+ if ((vol->v_adouble == AD_VERSION_EA) && !(vol->v_flags & AFPVOL_NOV2TOEACONV))
+ EC_ZERO( ad_conv_v22ea(path, sp, vol) );
+
+ if (vol->v_adouble == AD_VERSION_EA) {
+ EC_ZERO( ad_conv_dehex(path, sp, vol, &p) );
+ if (p && newpath)
+ *newpath = p;
+ }
+
+EC_CLEANUP:
+ LOG(log_debug, logtype_default,"ad_convert(\"%s\"): END: %d", fullpathname(path), ret);
+ EC_EXIT;
+}
+
return oflags;
}
-static char emptyfilad[32] = {0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0};
-
-static char emptydirad[32] = {0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,1,0,
- 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0};
-
-static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
-{
- EC_INIT;
- struct adouble adv2;
- struct adouble adea;
- const char *adpath;
- int adflags;
- uint32_t ctime, mtime, afpinfo = 0;
- char *emptyad;
-
- LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
-
- ad_init(&adea, vol);
- ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
- adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
-
- /* Open and lock adouble:v2 file */
- EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
- EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
- EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
-
- /* Check if it's a non-empty header */
- if (S_ISREG(sp->st_mode))
- emptyad = &emptyfilad[0];
- else
- emptyad = &emptydirad[0];
-
- if (ad_getentrylen(&adv2, ADEID_COMMENT) != 0)
- goto copy;
- if (ad_getentryoff(&adv2, ADEID_FINDERI)
- && (ad_getentrylen(&adv2, ADEID_FINDERI) == ADEDLEN_FINDERI)
- && (memcmp(ad_entry(&adv2, ADEID_FINDERI), emptyad, ADEDLEN_FINDERI) != 0))
- goto copy;
- if (ad_getentryoff(&adv2, ADEID_FILEDATESI)) {
- EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_CREATE | AD_DATE_UNIX, &ctime) );
- EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_MODIFY | AD_DATE_UNIX, &mtime) );
- if ((ctime != mtime) || (mtime != sp->st_mtime))
- goto copy;
- }
- if (ad_getentryoff(&adv2, ADEID_AFPFILEI)) {
- if (memcmp(ad_entry(&adv2, ADEID_AFPFILEI), &afpinfo, ADEDLEN_AFPFILEI) != 0)
- goto copy;
- }
-
- LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): default adouble", fullpathname(path), ret);
- goto EC_CLEANUP;
-
-copy:
- /* Create a adouble:ea meta EA */
- LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): copying adouble", fullpathname(path), ret);
- EC_ZERO_LOG( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE) );
- EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
- ad_flush(&adea);
-
-EC_CLEANUP:
- EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
- EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
- LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): END: %d", fullpathname(path), ret);
- EC_EXIT;
-}
-
-static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
-{
- EC_INIT;
- struct adouble adv2;
- struct adouble adea;
-
- LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
-
- if (S_ISDIR(sp->st_mode))
- return 0;
-
- ad_init(&adea, vol);
- ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
-
- /* Open and lock adouble:v2 file */
- EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
- if (adv2.ad_rlen > 0) {
- EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
-
- /* Create a adouble:ea resource fork */
- EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
-
- EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
- adea.ad_rlen = adv2.ad_rlen;
- ad_flush(&adea);
- }
-
-EC_CLEANUP:
- EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
- EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
- LOG(log_debug, logtype_default,"ad_conv_v22ea_rf(\"%s\"): END: %d", fullpathname(path), ret);
- EC_EXIT;
-}
-
static int ad_open_df(const char *path, int adflags, mode_t mode, struct adouble *ad)
{
EC_INIT;
return ret;
}
-int ad_convert(const char *path, const struct stat *sp, const struct vol *vol)
-{
- EC_INIT;
- const char *adpath;
- int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
-
- LOG(log_debug, logtype_default,"ad_convert(\"%s\"): BEGIN", fullpathname(path));
-
- if (!(vol->v_adouble == AD_VERSION_EA) || (vol->v_flags & AFPVOL_NOV2TOEACONV))
- goto EC_CLEANUP;
-
- EC_ZERO( ad_conv_v22ea_hf(path, sp, vol) );
- EC_ZERO( ad_conv_v22ea_rf(path, sp, vol) );
-
- EC_NULL( adpath = ad_path(path, adflags) );
- LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
- path, fullpathname(adpath));
-
- become_root();
- EC_ZERO_LOG( unlink(adpath) );
- unbecome_root();
-
-EC_CLEANUP:
- LOG(log_debug, logtype_default,"ad_convert(\"%s\"): END: %d", fullpathname(path), ret);
- EC_EXIT;
-}
-
/* build a resource fork mode from the data fork mode:
* remove X mode and extend header to RW if R or W (W if R for locking),
*/
o_len=destlen;
while (i_len > 0) {
- if ((option & CONV_UNESCAPEHEX)) {
- for (j = 0; j < i_len; ++j) {
- if (inbuf[j] == ':') break;
- }
- j = i_len - j;
- i_len -= j;
- }
+ for (j = 0; j < i_len; ++j)
+ if (inbuf[j] == ':')
+ break;
+ j = i_len - j;
+ i_len -= j;
if (i_len > 0 &&
atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) {
}
if (j) {
- /* we're at the start on an hex encoded ucs2 char */
- char h[MAXPATHLEN];
- size_t hlen = 0;
-
+ /* we have a ':' */
i_len = j, j = 0;
- while (i_len >= 3 && inbuf[0] == ':' &&
- isxdigit(inbuf[1]) && isxdigit(inbuf[2])) {
- h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]);
- inbuf += 3;
- i_len -= 3;
- }
- if (hlen) {
- const char *h_buf = h;
- if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) {
- i_len += hlen * 3;
- inbuf -= hlen * 3;
- if (errno == EILSEQ && (option & CONV_IGNORE)) {
+
+ if ((option & CONV_UNESCAPEHEX)) {
+ /* treat it as a CAP hex encoded char */
+ char h[MAXPATHLEN];
+ size_t hlen = 0;
+
+ while (i_len >= 3 && inbuf[0] == ':' &&
+ isxdigit(inbuf[1]) && isxdigit(inbuf[2])) {
+ h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]);
+ inbuf += 3;
+ i_len -= 3;
+ }
+ if (hlen) {
+ const char *h_buf = h;
+ if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) {
+ i_len += hlen * 3;
+ inbuf -= hlen * 3;
+ if (errno == EILSEQ && (option & CONV_IGNORE)) {
+ *flags |= CONV_REQMANGLE;
+ return destlen - o_len;
+ }
+ goto end;
+ }
+ } else {
+ /* We have an invalid :xx sequence */
+ errno = EILSEQ;
+ if ((option & CONV_IGNORE)) {
*flags |= CONV_REQMANGLE;
return destlen - o_len;
}
goto end;
}
} else {
- /* We have an invalid :xx sequence */
- errno = EILSEQ;
- if ((option & CONV_IGNORE)) {
- *flags |= CONV_REQMANGLE;
- return destlen - o_len;
- }
- goto end;
+ /* a ':' that we just convert to a '/' */
+ ucs2_t slash = 0x002f;
+ memcpy(outbuf, &slash, sizeof(ucs2_t));
+ outbuf += 2;
+ o_len -= 2;
+ inbuf++;
+ i_len--;
}
}
}
}
while (i_len >= 2) {
- if ((option & CONV_ESCAPEHEX)) {
- for (i = 0; i < i_len; i += 2) {
- ucs2_t c = SVAL(inbuf, i);
- switch (c) {
- case 0x003a: /* 0x003a = ':' */
- if ( ! (option & CONV_ALLOW_COLON)) {
- errno = EILSEQ;
- goto end;
- }
- escch = c;
- j = i_len - i;
- i_len = i;
- break;
- case 0x002f: /* 0x002f = '/' */
- escch = c;
- j = i_len - i;
- i_len = i;
- break;
+ for (i = 0; i < i_len; i += 2) {
+ ucs2_t c = SVAL(inbuf, i);
+ switch (c) {
+ case 0x003a: /* 0x003a = ':' */
+ if ( ! (option & CONV_ALLOW_COLON)) {
+ errno = EILSEQ;
+ goto end;
}
+ escch = c;
+ j = i_len - i;
+ i_len = i;
+ break;
+ case 0x002f: /* 0x002f = '/' */
+ escch = c;
+ j = i_len - i;
+ i_len = i;
+ break;
}
}
while (i_len > 0 &&
}
if (j) {
+ /* we have a ':' or '/' */
i_len = j, j = 0;
- if (o_len < 3) {
- errno = E2BIG;
- goto end;
- }
- switch (escch) {
- case '/':
- *outbuf++ = ':';
- *outbuf++ = '2';
- *outbuf++ = 'f';
- break;
- case ':':
- *outbuf++ = ':';
- *outbuf++ = '3';
- *outbuf++ = 'a';
- break;
- default:
- /*
- * THIS SHOULD NEVER BE REACHED !!!
- * As a safety net I put in a ' ' here
- */
- *outbuf++ = ':';
- *outbuf++ = '2';
- *outbuf++ = '0';
- break;
+
+ if ((option & CONV_ESCAPEHEX)) {
+ /* CAP hex encode it */
+ if (o_len < 3) {
+ errno = E2BIG;
+ goto end;
+ }
+ switch (escch) {
+ case '/':
+ *outbuf++ = ':';
+ *outbuf++ = '2';
+ *outbuf++ = 'f';
+ break;
+ case ':':
+ *outbuf++ = ':';
+ *outbuf++ = '3';
+ *outbuf++ = 'a';
+ break;
+ default:
+ /*
+ * THIS SHOULD NEVER BE REACHED !!!
+ * As a safety net I put in a ' ' here
+ */
+ *outbuf++ = ':';
+ *outbuf++ = '2';
+ *outbuf++ = '0';
+ break;
+ }
+ o_len -= 3;
+ inbuf += 2;
+ i_len -= 2;
+ } else {
+ switch (escch) {
+ case '/':
+ case ':':
+ *outbuf++ = ':';
+ break;
+ default: /* should never be reached */
+ *outbuf++ = ' ';
+ break;
+ }
+ o_len--;
+ inbuf += 2;
+ i_len -= 2;
}
- o_len -= 3;
- inbuf += 2;
- i_len -= 2;
}
}
if (i_len > 0) errno = EINVAL;
if (getoption_bool(obj->iniconfig, section, "read only", preset, 0))
volume->v_flags |= AFPVOL_RO;
- if (!getoption_bool(obj->iniconfig, section, "hex encoding", preset, 1))
- volume->v_flags |= AFPVOL_NOHEX;
- if (getoption_bool(obj->iniconfig, section, "use dots", preset, 1))
- volume->v_flags |= AFPVOL_USEDOTS;
if (getoption_bool(obj->iniconfig, section, "invisible dots", preset, 0))
volume->v_flags |= AFPVOL_INV_DOTS;
if (!getoption_bool(obj->iniconfig, section, "stat vol", preset, 1))
volume->v_ad_options |= ADVOL_INVDOTS;
/* Mac to Unix conversion flags*/
- if (!(volume->v_flags & AFPVOL_NOHEX))
- volume->v_mtou_flags |= CONV_ESCAPEHEX;
- if (!(volume->v_flags & AFPVOL_USEDOTS))
- volume->v_mtou_flags |= CONV_ESCAPEDOTS;
if ((volume->v_flags & AFPVOL_EILSEQ))
volume->v_mtou_flags |= CONV__EILSEQ;
volume->v_mtou_flags |= CONV_TOLOWER;
/* Unix to Mac conversion flags*/
- volume->v_utom_flags = CONV_IGNORE | CONV_UNESCAPEHEX;
+ volume->v_utom_flags = CONV_IGNORE;
if ((volume->v_casefold & AFPVOL_UTOMUPPER))
volume->v_utom_flags |= CONV_TOUPPER;
else if ((volume->v_casefold & AFPVOL_UTOMLOWER))
if (name[0] != '.')
return 1;
- if (!(vol->v_flags & AFPVOL_USEDOTS))
- return 0;
-
return netatalk_name(name) && strcmp(name,".AppleDouble") && strcasecmp(name,".Parent");
}
if (name[0] != '.')
return 1;
- if (!(vol->v_flags & AFPVOL_USEDOTS))
- return 0;
-
#ifndef HAVE_EAFD
if (name[1] == '_')
return ad_valid_header_osx(name);