Fixes bug #474.
* FIX: Fix _device-info service type registered with dns-sd API
* FIX: Fix pathname bug for FCE modified event.
-* FIX: "valid users" options and friends only use ',' as field delimiter.
- Fixes bug #472.
* FIX: Remove length limitation of options like "valid users".
Fixes bug #473.
+* FIX: Dont copy our metadata EA in copyfile().
+ Fixes bug #452.
+* FIX: Fix an error where catalog search gave incomplete results.
+ Fixes bug #479.
* REM: Remove TimeMachine volume used size FCE event.
+* UPD: Add quoting support to '[in]valid users' option.
+ Fixes bug #472.
Changes in 3.0.1
================
/* Master afpd reloading config */
auth_unload();
if (! (obj->options.flags & OPTION_NOZEROCONF)) {
- unload_volumes(obj);
zeroconf_deregister();
}
}
+ unload_volumes(obj);
+
/* Master and child releasing unneeded DSI handles */
for (p = obj->dsi; p; p = q) {
q = p->next;
#include "config.h"
#endif /* HAVE_CONFIG_H */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
*
*/
struct dsitem {
-// struct dir *dir; /* Structure describing this directory */
-// cnid_t did; /* CNID of this directory */
- int pidx; /* Parent's dsitem structure index. */
- int checked; /* Have we checked this directory ? */
- int path_len;
- char *path; /* absolute UNIX path to this directory */
+ cnid_t ds_did; /* CNID of this directory */
+ int ds_checked; /* Have we checked this directory ? */
};
save_cidx = -1;
while (dsidx > 0) {
dsidx--;
- free(dstack[dsidx].path);
}
}
/* Put new element. Allocate and copy lname and path. */
ds = dstack + dsidx++;
-// ds->did = dir->d_did;
- ds->pidx = pidx;
- ds->checked = 0;
- if (pidx >= 0) {
- l = dstack[pidx].path_len;
- u = strlen(uname) +1;
- if (!(ds->path = malloc(l + u + 1) ))
- return -1;
- memcpy(ds->path, dstack[pidx].path, l);
- ds->path[l] = '/';
- memcpy(&ds->path[l+1], uname, u);
- ds->path_len = l +u;
- }
- else {
- ds->path = strdup(uname);
- ds->path_len = strlen(uname);
- }
+ ds->ds_did = dir->d_did;
+ ds->ds_checked = 0;
return 0;
}
}
while (dsidx > 0) {
- if (dstack[dsidx-1].checked) {
+ if (dstack[dsidx-1].ds_checked) {
dsidx--;
- free(dstack[dsidx].path);
+// free(dstack[dsidx].path);
} else
return dsidx - 1;
}
int num_rounds = NUM_ROUNDS;
int cwd = -1;
int error;
-
+ int unlen;
+
if (*pos != 0 && *pos != cur_pos) {
result = AFPERR_CATCHNG;
goto catsearch_end;
start_time = time(NULL);
while ((cidx = reducestack()) != -1) {
- LOG(log_debug, logtype_afpd, "catsearch: dir: \"%s\"", dstack[cidx].path);
+ if ((currentdir = dirlookup(vol, dstack[cidx].ds_did)) == NULL) {
+ result = AFPERR_MISC;
+ goto catsearch_end;
+ }
+ LOG(log_debug, logtype_afpd, "catsearch: current struct dir: \"%s\"", cfrombstr(currentdir->d_fullpath));
- error = lchdir(dstack[cidx].path);
+ error = movecwd(vol, currentdir);
if (!error && dirpos == NULL)
dirpos = opendir(".");
if (dirpos == NULL)
- dirpos = opendir(dstack[cidx].path);
+ dirpos = opendir(bdata(currentdir->d_fullpath));
if (error || dirpos == NULL) {
switch (errno) {
case EACCES:
- dstack[cidx].checked = 1;
+ dstack[cidx].ds_checked = 1;
continue;
case EMFILE:
case ENFILE:
goto catsearch_end;
}
- if ((currentdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
- result = AFPERR_MISC;
- goto catsearch_end;
- }
- LOG(log_debug, logtype_afpd, "catsearch: current struct dir: \"%s\"", cfrombstr(currentdir->d_fullpath));
while ((entry = readdir(dirpos)) != NULL) {
(*pos)++;
goto catsearch_end;
}
}
- if (S_ISDIR(path.st.st_mode)) {
+ switch (S_IFMT & path.st.st_mode) {
+ case S_IFDIR:
/* here we can short cut
ie if in the same loop the parent dir wasn't in the cache
ALL dirsearch_byname will fail.
*/
- int unlen = strlen(path.u_name);
+ unlen = strlen(path.u_name);
path.d_dir = dircache_search_by_name(vol,
currentdir,
path.u_name,
result = AFPERR_MISC;
goto catsearch_end;
}
- } else {
+ break;
+ case S_IFREG:
path.d_dir = currentdir;
+ break;
+ default:
+ continue;
}
ccr = crit_check(vol, &path);
} /* while ((entry=readdir(dirpos)) != NULL) */
closedir(dirpos);
dirpos = NULL;
- dstack[cidx].checked = 1;
+ dstack[cidx].ds_checked = 1;
} /* while (current_idx = reducestack()) != -1) */
/* We have finished traversing our tree. Return EOF here. */
}
/* do a recursive copy. */
-static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
+static int copydir(struct vol *vol, struct dir *ddir, int dirfd, char *src, char *dst)
{
char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
DIR *dp;
strcpy(dpath + dlen, de->d_name);
if (S_ISDIR(st.st_mode)) {
- if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
+ if (AFP_OK != (err = copydir(vol, ddir, dirfd, spath, dpath)))
goto copydir_done;
- } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
+ } else if (AFP_OK != (err = copyfile(vol, vol, ddir, dirfd, spath, dpath, NULL, NULL))) {
goto copydir_done;
} else {
* newparent curdir
* dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
*/
-int renamedir(const struct vol *vol,
+int renamedir(struct vol *vol,
int dirfd,
char *src,
char *dst,
case EXDEV:
/* this needs to copy and delete. bleah. that means we have
* to deal with entire directory hierarchies. */
- if ((err = copydir(vol, dirfd, src, dst)) < 0) {
+ if ((err = copydir(vol, newparent, dirfd, src, dst)) < 0) {
deletedir(-1, dst);
return err;
}
/* bail if it's not a symlink */
if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): not empty",
- curdir->d_fullpath);
+ bdata(curdir->d_fullpath));
closedir(dp);
return AFPERR_DIRNEMPT;
}
struct dir *, char *, size_t *);
extern int setdirparams(struct vol *, struct path *, uint16_t, char *);
-extern int renamedir(const struct vol *, int, char *, char *, struct dir *,
+extern int renamedir(struct vol *, int, char *, char *, struct dir *,
struct dir *, char *);
extern int path_error(struct path *, int error);
extern void setdiroffcnt(struct dir *dir, struct stat *st, uint32_t count);
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)
+ if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)) != 0)
LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname));
}
}
isad = 0;
} else if ((ad_get_MD_flags( adp ) & O_CREAT) ) {
ad_setname(adp, path->m_name);
+ cnid_t id;
+ if ((id = get_id(vol, adp, &path->st, curdir->d_did, upath, strlen(upath))) == CNID_INVALID) {
+ LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath);
+ return AFPERR_MISC;
+ }
+ (void)ad_setid(adp, path->st.st_dev, path->st.st_ino, id, curdir->d_did, vol->v_stamp);
}
bit = 0;
* adp adouble struct of src file, if open, or & zeroed one
*
*/
-int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp)
+int renamefile(struct vol *vol, struct dir *ddir, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp)
{
int rc;
/* FIXME warning in syslog so admin'd know there's a conflict ?*/
return AFPERR_OLOCK; /* little lie */
}
- if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) {
+ if (AFP_OK != ( rc = copyfile(vol, vol, ddir, sdir_fd, src, dst, newname, NULL )) ) {
/* on error copyfile delete dest */
return( rc );
}
goto copy_exit;
}
- if ( (err = copyfile(s_vol, d_vol, -1, p, upath , newname, adp)) < 0 ) {
+ if ( (err = copyfile(s_vol, d_vol, curdir, -1, p, upath , newname, adp)) < 0 ) {
retvalue = err;
goto copy_exit;
}
* because we are doing it elsewhere.
* currently if newname is NULL then adp is NULL.
*/
-int copyfile(const struct vol *s_vol,
- const struct vol *d_vol,
+int copyfile(struct vol *s_vol,
+ struct vol *d_vol,
+ struct dir *d_dir,
int sfd,
char *src,
char *dst,
adp = &ads;
}
- adflags = ADFLAGS_DF | ADFLAGS_RF | ADFLAGS_NORF;
+ adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF | ADFLAGS_RF | ADFLAGS_NORF;
if (ad_openat(adp, sfd, src, adflags | ADFLAGS_RDONLY) < 0) {
ret_err = errno;
goto done;
}
+ if (!AD_META_OPEN(adp))
+ /* no resource fork, don't create one for dst file */
+ adflags &= ~ADFLAGS_HF;
+
if (!AD_RSRC_OPEN(adp))
/* no resource fork, don't create one for dst file */
adflags &= ~ADFLAGS_RF;
if (err < 0)
ret_err = errno;
- if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
- /* set the new name in the resource fork */
- ad_copy_header(&add, adp);
- ad_setname(&add, newname);
- ad_flush( &add );
+ if (AD_META_OPEN(&add)) {
+ if (AD_META_OPEN(adp))
+ ad_copy_header(&add, adp);
+ ad_setname(&add, dst);
+ cnid_t id;
+ struct stat stdest;
+ if (fstat(ad_meta_fileno(&add), &stdest) != 0) {
+ ret_err = errno;
+ goto error;
+ }
+ if ((id = get_id(d_vol, &add, &stdest, d_dir->d_did, dst, strlen(dst))) == CNID_INVALID) {
+ ret_err = EINVAL;
+ goto error;
+ }
+ (void)ad_setid(&add, stdest.st_dev, stdest.st_ino, id, d_dir->d_did, d_vol->v_stamp);
+ ad_flush(&add);
}
+
+error:
ad_close( adp, adflags );
if (ad_close( &add, adflags ) <0) {
}
/* now, quickly rename the file. we error if we can't. */
- if ((err = renamefile(vol, -1, p, temp, temp, adsp)) != AFP_OK)
+ if ((err = renamefile(vol, curdir, -1, p, temp, temp, adsp)) != AFP_OK)
goto err_exchangefile;
of_rename(vol, s_of, sdir, spath, curdir, temp);
/* rename destination to source */
- if ((err = renamefile(vol, -1, upath, p, spath, addp)) != AFP_OK)
+ if ((err = renamefile(vol, curdir, -1, upath, p, spath, addp)) != AFP_OK)
goto err_src_to_tmp;
of_rename(vol, d_of, curdir, path->m_name, sdir, spath);
/* rename temp to destination */
- if ((err = renamefile(vol, -1, temp, upath, path->m_name, adsp)) != AFP_OK)
+ if ((err = renamefile(vol, curdir, -1, temp, upath, path->m_name, adsp)) != AFP_OK)
goto err_dest_to_src;
of_rename(vol, s_of, curdir, temp, curdir, path->m_name);
* properly. */
err_temp_to_dest:
/* rename dest to temp */
- renamefile(vol, -1, upath, temp, temp, adsp);
+ renamefile(vol, curdir, -1, upath, temp, temp, adsp);
of_rename(vol, s_of, curdir, upath, curdir, temp);
err_dest_to_src:
/* rename source back to dest */
- renamefile(vol, -1, p, upath, path->m_name, addp);
+ renamefile(vol, curdir, -1, p, upath, path->m_name, addp);
of_rename(vol, d_of, sdir, spath, curdir, path->m_name);
err_src_to_tmp:
/* rename temp back to source */
- renamefile(vol, -1, temp, p, spath, adsp);
+ renamefile(vol, curdir, -1, temp, p, spath, adsp);
of_rename(vol, s_of, curdir, temp, sdir, spath);
err_exchangefile:
extern int getfilparams (const AFPObj *obj, struct vol *, uint16_t, struct path *,
struct dir *, char *buf, size_t *, int);
extern int setfilparams (const AFPObj *obj, struct vol *, struct path *, uint16_t, char *);
-extern int renamefile (const struct vol *, int, char *, char *, char *, struct adouble *);
-extern int copyfile (const struct vol *, const struct vol *, int, char *, char *, char *, struct adouble *);
+extern int renamefile (struct vol *, struct dir *, int, char *, char *, char *, struct adouble *);
+extern int copyfile (struct vol *, struct vol *, struct dir *, int, char *, char *, char *, struct adouble *);
extern int deletefile (const struct vol *, int, char *, int);
extern int getmetadata (const AFPObj *obj, struct vol *vol, uint16_t bitmap, struct path *path,
move and rename sdir:oldname to curdir:newname in volume vol
special care is needed for lock
*/
-static int moveandrename(const struct vol *vol,
+static int moveandrename(struct vol *vol,
struct dir *sdir,
int sdir_fd,
char *oldname,
if (of_findname(&path)) {
rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
} else {
- rc = renamefile(vol, sdir_fd, oldunixname, upath, newname, adp );
+ rc = renamefile(vol, curdir, sdir_fd, oldunixname, upath, newname, adp );
if (rc == AFP_OK)
of_rename(vol, opened, sdir, oldname, curdir, newname);
}
extern int run_cmd(const char *cmd, char **cmd_argv);
extern char *realpath_safe(const char *path);
extern const char *basename_safe(const char *path);
+extern char *strtok_quote (char *s, const char *delim);
/******************************************************************
* cnid.c
}
add->ad_rlen = ads->ad_rlen;
- if ((ads->ad_vers == AD_VERSION2) && (add->ad_vers = AD_VERSION_EA)
- || (ads->ad_vers == AD_VERSION_EA) && (add->ad_vers = AD_VERSION2)) {
+ if (((ads->ad_vers == AD_VERSION2) && (add->ad_vers == AD_VERSION_EA))
+ || ((ads->ad_vers == AD_VERSION_EA) && (add->ad_vers == AD_VERSION2))) {
cnid_t id;
memcpy(&id, ad_entry(add, ADEID_PRIVID), sizeof(cnid_t));
id = htonl(id);
if (ad->ad_adflags & ADFLAGS_DIR) {
EC_NEG1_LOG( cwd = open(".", O_RDONLY) );
EC_NEG1_LOG( fchdir(ad_data_fileno(ad)) );
- EC_ZERO_LOG( sys_lsetxattr(".", AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) );
+ EC_ZERO_LOGSTR( sys_lsetxattr(".", AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0),
+ "sys_lsetxattr(\"%s\"): %s", fullpathname(".") ,strerror(errno));
EC_NEG1_LOG( fchdir(cwd) );
EC_NEG1_LOG( close(cwd) );
cwd = -1;
break;
}
- if (ret != 0)
+ if (ret == 0)
+ ad->ad_meta_refcount++;
+ else
ret = ad_error(ad, adflags);
return ret;
static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble *ad)
{
+ EC_INIT;
+
/*
* ad_open_hf_v2() does the work, but if it failed and adflags are ADFLAGS_NOHF | ADFLAGS_RF
* ad_open_hf_v2() didn't give an error, but we're supposed to return a reso fork fd
*/
- if (!AD_RSRC_OPEN(ad) && !(adflags & ADFLAGS_NORF))
- return -1;
- return 0;
+
+ LOG(log_debug, logtype_ad, "ad_open_rf_v2(\"%s\"): BEGIN", fullpathname(path));
+
+ if (!AD_META_OPEN(ad) && !(adflags & ADFLAGS_NORF))
+ EC_FAIL;
+ if (AD_META_OPEN(ad))
+ ad->ad_reso_refcount++;
+
+EC_CLEANUP:
+ LOG(log_debug, logtype_ad, "ad_open_rf_v2(\"%s\"): END: %d", fullpathname(path), ret);
+ EC_EXIT;
}
static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble *ad)
opened = 1;
ad->ad_rfp->adf_refcount = 1;
ad->ad_rfp->adf_flags = oflags;
+ ad->ad_reso_refcount++;
#ifndef HAVE_EAFD
EC_ZERO_LOG( fstat(ad_reso_fileno(ad), &st) );
if (opened && (ad_reso_fileno(ad) != -1)) {
close(ad_reso_fileno(ad));
ad_reso_fileno(ad) = -1;
+ ad->ad_reso_refcount--;
ad->ad_rfp->adf_refcount = 0;
}
if (adflags & ADFLAGS_NORF) {
}
if (adflags & ADFLAGS_HF) {
- ad->ad_meta_refcount++;
if (ad_open_hf(path, adflags, mode, ad) != 0) {
- ad->ad_meta_refcount--;
EC_FAIL;
}
}
if (adflags & ADFLAGS_RF) {
- ad->ad_reso_refcount++;
if (ad_open_rf(path, adflags, mode, ad) != 0) {
- ad->ad_reso_refcount--;
EC_FAIL;
}
}
free(dsi->buffer);
dsi->buffer = NULL;
+#ifdef USE_ZEROCONF
free(dsi->bonjourname);
dsi->bonjourname = NULL;
+#endif
}
static struct itimerval itimer;
*/
/*---------------------------- Includes ------------------------------------*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include <ctype.h>
#include <atalk/iniparser.h>
strcpy(section, strstrip(section));
strcpy(section, section);
sta = LINE_SECTION ;
- } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
- || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
+ } else if (sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
|| sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
/* Usual key=value, with or without comments */
strcpy(key, strstrip(key));
/*!
* check access list
*
- * this function wants something of the following form:
- * "@group,name,name2,@group2,name3".
+ * this function wants a string consisting of names seperated by comma
+ * or space. Names may be quoted within a pair of quotes. Groups are
+ * denoted by a leading @ symbol.
+ * Example:
+ * user1 user2, user3, @group1 @group2, @group3 "user name1", "@group name1"
* A NULL argument allows everybody to have access.
* We return three things:
* -1: no list
EC_NULL_LOG( names = strdup(args) );
- if ((p = strtok(names, ",")) == NULL) /* nothing, return okay */
+ if ((p = strtok_quote(names, ", ")) == NULL) /* nothing, return okay */
EC_EXIT_STATUS(-1);
while (p) {
EC_EXIT_STATUS(1);
} else if (strcasecmp(p, name) == 0) /* it's a user name */
EC_EXIT_STATUS(1);
- p = strtok(NULL, ", ");
+ p = strtok_quote(NULL, ", ");
}
EC_CLEANUP:
strlcpy(buf, path, MAXPATHLEN);
return basename(buf);
}
+
+/**
+ * extended strtok allows the quoted strings
+ * modified strtok.c in glibc 2.0.6
+ **/
+char *strtok_quote(char *s, const char *delim)
+{
+ static char *olds = NULL;
+ char *token;
+
+ if (s == NULL)
+ s = olds;
+
+ /* Scan leading delimiters. */
+ s += strspn (s, delim);
+ if (*s == '\0')
+ return NULL;
+
+ /* Find the end of the token. */
+ token = s;
+
+ if (token[0] == '\"') {
+ token++;
+ s = strpbrk (token, "\"");
+ } else {
+ s = strpbrk (token, delim);
+ }
+
+ if (s == NULL) {
+ /* This token finishes the string. */
+ olds = strchr (token, '\0');
+ } else {
+ /* Terminate the token and make OLDS point past it. */
+ *s = '\0';
+ olds = s + 1;
+ }
+ return token;
+}
if (!*name)
continue;
+ if (STRCMP(name, ==, AD_EA_META))
+ continue;
+
if (sfd != -1) {
if (fchdir(sfd) == -1) {
LOG(log_error, logtype_afpd, "sys_ea_copyfile: cant chdir to sfd: %s",
EC_FAIL;
default:
LOG(log_debug, logtype_default, "open(\"%s\"): %s", fullpathname(path), strerror(errno));
- errno = ENOATTR;
EC_FAIL;
}
}
EC_FAIL;
default:
LOG(log_debug, logtype_default, "openat(\"%s\"): %s", fullpathname(path), strerror(errno));
- errno = ENOATTR;
EC_FAIL;
}
}
.\" Title: afp.conf
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\" Date: 22 Nov 2012
+.\" Date: 06 Dez 2012
.\" Manual: Netatalk 3.0
.\" Source: Netatalk 3.0
.\" Language: English
.\"
-.TH "AFP\&.CONF" "5" "22 Nov 2012" "Netatalk 3.0" "Netatalk 3.0"
+.TH "AFP\&.CONF" "5" "06 Dez 2012" "Netatalk 3.0" "Netatalk 3.0"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.RS 4
SASL\&. Not yet supported !
.RE
-.sp
.RE
.PP
ldap auth dn = \fIdn\fR \fB(G)\fR
.RS 4
Binary objectGUID from Active Directory
.RE
-.sp
.RE
.PP
ldap group attr = \fIdn\fR \fB(G)\fR
This is an approimated calculation taking into accout the contents of Time Machine sparsebundle images\&. Therefor you MUST NOT use this volume to store other content when using this option, because it would NOT be accounted\&. The calculation works by reading the band size from the Info\&.plist XML file of the sparsebundle, reading the bands/ directory counting the number of band files, and then multiplying one with the other\&.
.RE
.PP
-valid users = \fIusers/groups\fR \fB(V)\fR
+valid users = \fIuser @group\fR \fB(V)\fR
.RS 4
-The allow option allows the users and groups that access a share to be specified\&. Users and groups are specified, delimited by spaces or commas\&. Groups are designated by a @ prefix\&. Example: "valid users = user1 user2 @group"
+The allow option allows the users and groups that access a share to be specified\&. Users and groups are specified, delimited by spaces or commas\&. Groups are designated by a @ prefix\&. Names may be quoted in order to allow for spaces in names\&. Example:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+valid users = user "user 2" @group \(lq@group 2"
+.fi
+.if n \{\
+.RE
+.\}
.RE
.PP
invalid users = \fIusers/groups\fR \fB(V)\fR
is for directories only\&. Don\'t use with "\fBunix priv = no\fR"\&.
.PP
\fBExample.\ \&Volume for a collaborative workgroup\fR
-
.sp
.if n \{\
.RS 4
.if n \{\
.RE
.\}
-.sp
.RE
.PP
option will allow you to select another volume encoding\&. E\&.g\&. for western users another useful setting could be vol charset ISO\-8859\-15\&.
\fBafpd\fR
will accept any
-\fB iconv \fR(1)
+\fBiconv\fR(1)
provided charset\&. If a character cannot be converted from the
\fBmac charset\fR
to the selected
TEST_int( afp_config_parse(&obj, NULL), 0);
TEST_int( configinit(&obj), 0);
TEST( cnid_init() );
- TEST( load_volumes(&obj, NULL) );
+ TEST( load_volumes(&obj) );
TEST_int( dircache_init(8192), 0);
obj.afp_version = 32;