/*
- * $Id: volume.c,v 1.111 2009-12-17 09:25:40 franklahm Exp $
+ * $Id: volume.c,v 1.125 2010-04-08 05:51:16 franklahm Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
#define VOLOPT_CASEFOLD 5 /* character case mangling */
#define VOLOPT_FLAGS 6 /* various flags */
#define VOLOPT_DBPATH 7 /* path to database */
-#define VOLOPT_MAPCHARS 8 /* does mtou and utom mappings. syntax:
- m and u can be double-byte hex
- strings if necessary.
- m=u -> map both ways
- m>u -> map m to u
- m<u -> map u to m
- !u -> make u illegal always
- ~u -> make u illegal only as the first
- part of a double-byte character.
- */
+/* Usable slots: 8 and 9 */
#define VOLOPT_VETO 10 /* list of veto filespec */
#define VOLOPT_PREEXEC 11 /* preexec command */
#define VOLOPT_ROOTPREEXEC 12 /* root preexec command */
-
#define VOLOPT_POSTEXEC 13 /* postexec command */
#define VOLOPT_ROOTPOSTEXEC 14 /* root postexec command */
-
#define VOLOPT_ENCODING 15 /* mac encoding (pre OSX)*/
#define VOLOPT_MACCHARSET 16
#define VOLOPT_CNIDSCHEME 17
#define VOLOPT_ADOUBLE 18 /* adouble version */
+
#ifdef FORCE_UIDGID
#warning UIDGID
#include "uid.h"
-#define VOLOPT_FORCEUID 19 /* force uid for username x */
-#define VOLOPT_FORCEGID 20 /* force gid for group x */
+#define VOLOPT_FORCEUID 19 /* force uid for username x */
+#define VOLOPT_FORCEGID 20 /* force gid for group x */
#endif /* FORCE_UIDGID */
-#define VOLOPT_UMASK 21
+#define VOLOPT_UMASK 21
#define VOLOPT_ALLOWED_HOSTS 22
#define VOLOPT_DENIED_HOSTS 23
-#define VOLOPT_DPERM 24 /* dperm default directories perms */
-#define VOLOPT_FPERM 25 /* fperm default files perms */
-#define VOLOPT_DFLTPERM 26 /* perm */
-#define VOLOPT_EA_VFS 27 /* Extended Attributes vfs indirection */
+#define VOLOPT_DPERM 24 /* dperm default directories perms */
+#define VOLOPT_FPERM 25 /* fperm default files perms */
+#define VOLOPT_DFLTPERM 26 /* perm */
+#define VOLOPT_EA_VFS 27 /* Extended Attributes vfs indirection */
+#define VOLOPT_CNIDSERVER 28 /* CNID Server ip address*/
+#define VOLOPT_CNIDPORT 30 /* CNID server tcp port */
-#define VOLOPT_MAX 28 /* <== IMPORTANT !!!!!! */
-#define VOLOPT_NUM (VOLOPT_MAX + 1)
+#define VOLOPT_MAX 31 /* <== IMPORTANT !!!!!! */
+#define VOLOPT_NUM (VOLOPT_MAX + 1)
#define VOLPASSLEN 8
#define VOLOPT_DEFAULT ":DEFAULT:"
#endif
{NULL, 0, 0, 0}};
+/* Forward declarations */
static void handle_special_folders (const struct vol *);
static void deletevol(struct vol *vol);
static void volume_free(struct vol *vol);
+static void check_ea_sys_support(struct vol *vol);
-static void volfree(struct vol_option *options,
- const struct vol_option *save)
+static void volfree(struct vol_option *options, const struct vol_option *save)
{
int i;
p = strtok(NULL, ",");
}
+ } else if (optionok(tmp, "cnidserver:", val)) {
+ setoption(options, save, VOLOPT_CNIDSERVER, val);
+
+ char *p = strrchr(val + 1, ':');
+ if (p) {
+ *p = 0;
+ setoption(options, save, VOLOPT_CNIDPORT, p);
+ }
+
+ LOG(log_debug, logtype_afpd, "CNID Server for volume '%s': %s:%s",
+ volname, val + 1, p ? p + 1 : Cnid_port);
+
} else if (optionok(tmp, "dbpath:", val)) {
setoption(options, save, VOLOPT_DBPATH, val);
options[VOLOPT_FPERM].i_value = (int)strtol(val+1, NULL, 8);
} else if (optionok(tmp, "perm:", val)) {
options[VOLOPT_DFLTPERM].i_value = (int)strtol(val+1, NULL, 8);
- } else if (optionok(tmp, "mapchars:",val)) {
- setoption(options, save, VOLOPT_MAPCHARS, val);
-
} else if (optionok(tmp, "password:", val)) {
setoption(options, save, VOLOPT_PASSWORD, val);
} else if (optionok(tmp, "ea:", val)) {
if (strcasecmp(val + 1, "ad") == 0)
options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AD;
+ else if (strcasecmp(val + 1, "sys") == 0)
+ options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_SYS;
+ else if (strcasecmp(val + 1, "none") == 0)
+ options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_NONE;
} else {
/* ignore unknown options */
/* os X start at 1 and use network order ie. 1 2 3 */
volume->v_vid = ++lastvid;
volume->v_vid = htons(volume->v_vid);
- volume->v_vfs_ea = AFPVOL_EA_SYS;
/* handle options */
if (options) {
volume->v_ad_options |= ADVOL_UNIXPRIV;
if ((volume->v_flags & AFPVOL_INV_DOTS))
volume->v_ad_options |= ADVOL_INVDOTS;
+ if ((volume->v_flags & AFPVOL_NOADOUBLE))
+ volume->v_ad_options |= ADVOL_NOADOUBLE;
if (options[VOLOPT_PASSWORD].c_value)
volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value);
if (options[VOLOPT_CNIDSCHEME].c_value)
volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value);
+ if (options[VOLOPT_CNIDSERVER].c_value)
+ volume->v_cnidserver = strdup(options[VOLOPT_CNIDSERVER].c_value);
+
+ if (options[VOLOPT_CNIDPORT].c_value)
+ volume->v_cnidport = strdup(options[VOLOPT_CNIDPORT].c_value);
+
if (options[VOLOPT_UMASK].i_value)
volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
if ((volume->v_flags & AFPVOL_EILSEQ))
volume->v_utom_flags |= CONV__EILSEQ;
- initvol_vfs(volume);
-
#ifdef FORCE_UIDGID
if (options[VOLOPT_FORCEUID].c_value) {
volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
volume->v_dperm |= volume->v_perm;
volume->v_fperm |= volume->v_perm;
+ /* Check EA support on volume */
+ if (volume->v_vfs_ea == AFPVOL_EA_AUTO)
+ check_ea_sys_support(volume);
+ initvol_vfs(volume);
+
volume->v_next = Volumes;
Volumes = volume;
return 0;
}
if ( *type == '\0' ) {
- memcpy(em->em_type, "????", sizeof( em->em_type ));
+ memcpy(em->em_type, "\0\0\0\0", sizeof( em->em_type ));
} else {
memcpy(em->em_type, type, sizeof( em->em_type ));
}
if ( *creator == '\0' ) {
- memcpy(em->em_creator, "UNIX", sizeof( em->em_creator ));
+ memcpy(em->em_creator, "\0\0\0\0", sizeof( em->em_creator ));
} else {
memcpy(em->em_creator, creator, sizeof( em->em_creator ));
}
static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent)
{
FILE *fp;
- char path[ MAXPATHLEN + 1], tmp[ MAXPATHLEN + 1],
- volname[ AFPVOL_U8MNAMELEN + 1 ], buf[ BUFSIZ ],
- type[ 5 ], creator[ 5 ];
+ char path[MAXPATHLEN + 1];
+ char tmp[MAXPATHLEN + 1];
+ char volname[AFPVOL_U8MNAMELEN + 1];
+ char buf[BUFSIZ];
+ char type[5], creator[5];
char *u, *p;
struct passwd *pw;
- struct vol_option options[VOLOPT_NUM], save_options[VOLOPT_NUM];
+ struct vol_option save_options[VOLOPT_NUM];
+ struct vol_option options[VOLOPT_NUM];
int i;
struct stat st;
int fd;
/* Enable some default options for all volumes */
save_options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE;
+ save_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO;
while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) {
initline( strlen( buf ), buf );
* .Parent file here if it doesn't exist. */
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ( ad_open_metadata( vol->v_path, vol_noadouble(vol) | ADFLAGS_DIR, O_CREAT, &ad) < 0 ) {
+ if ( ad_open_metadata( vol->v_path, ADFLAGS_DIR, O_CREAT, &ad) < 0 ) {
isad = 0;
vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME);
LOG(log_info, logtype_afpd, "Volume %s use CNID scheme %s.", volume->v_path, volume->v_cnidscheme);
}
- if (volume->v_dbpath)
- volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, flags);
- else
- volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, flags);
+
+ LOG(log_info, logtype_afpd, "%s:%s", volume->v_cnidserver, volume->v_cnidport);
+
+ volume->v_cdb = cnid_open(volume->v_dbpath ? volume->v_dbpath : volume->v_path,
+ volume->v_umask,
+ volume->v_cnidscheme,
+ flags,
+ volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
+ volume->v_cnidport ? volume->v_cnidport : Cnid_port);
if (!volume->v_cdb) {
flags |= CNID_FLAG_MEMORY;
LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.", volume->v_path);
- volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags);
+ volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL);
#ifdef SERVERTEXT
/* kill ourself with SIGUSR2 aka msg pending */
if (volume->v_cdb) {
/*
Check if the underlying filesystem supports EAs for ea:sys volumes.
If not, switch to ea:ad.
+ As we can't check (requires write access) on ro-volumes, we switch ea:auto
+ volumes that are options:ro to ea:none.
*/
static void check_ea_sys_support(struct vol *vol)
{
uid_t process_uid = 0;
- const char *fname = ".";
char eaname[] = {"org.netatalk.supports-eas.XXXXXX"};
const char *eacontent = "yes";
- if (vol->v_vfs_ea == AFPVOL_EA_SYS) {
+ if (vol->v_vfs_ea == AFPVOL_EA_AUTO) {
+
+ if ((vol->v_flags & AFPVOL_RO) == AFPVOL_RO) {
+ LOG(log_info, logtype_logger, "read-only volume '%s', can't test for EA support, disabling EAs", vol->v_localname);
+ vol->v_vfs_ea = AFPVOL_EA_NONE;
+ return;
+ }
+
mktemp(eaname);
process_uid = geteuid();
exit(EXITERR_SYS);
}
- if ((sys_setxattr(fname, eaname, eacontent, 4, 0)) == -1) {
+ if ((sys_setxattr(vol->v_path, eaname, eacontent, 4, 0)) == 0) {
+ sys_removexattr(vol->v_path, eaname);
+ vol->v_vfs_ea = AFPVOL_EA_SYS;
+ } else {
LOG(log_warning, logtype_afpd, "volume \"%s\" does not support Extended Attributes, using ea:ad instead",
vol->v_localname);
vol->v_vfs_ea = AFPVOL_EA_AD;
- initvol_vfs(vol);
}
- sys_removexattr(fname, eaname);
-
if (process_uid) {
if (seteuid(process_uid) == -1) {
LOG(log_error, logtype_logger, "can't seteuid back %s", strerror(errno));
return AFPERR_MISC;
}
+ /* Normalize volume path */
+#ifdef REALPATH_TAKES_NULL
+ if ((volume->v_path = realpath(path, NULL)) == NULL)
+ return AFPERR_MISC;
+#else
+ if ((volume->v_path = malloc(MAXPATHLEN+1)) == NULL)
+ return AFPERR_MISC;
+ if (realpath(path, volume->v_path) == NULL) {
+ free(volume->v_path);
+ return AFPERR_MISC;
+ }
+ /* Safe some memory */
+ char *tmp;
+ if ((tmp = strdup(volume->v_path)) == NULL) {
+ free(volume->v_path);
+ return AFPERR_MISC;
+ }
+ free(volume->v_path);
+ volume->v_path = tmp;
+#endif
+
if (volume_codepage(obj, volume) < 0) {
ret = AFPERR_MISC;
goto openvol_err;
if (!(volume->v_flags & AFPVOL_RO)) {
handle_special_folders( volume );
- check_ea_sys_support(volume);
- savevolinfo(volume, Cnid_srv, Cnid_port);
+ savevolinfo(volume,
+ volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv,
+ volume->v_cnidport ? volume->v_cnidport : Cnid_port);
}
/*
if (vol->v_mtime < tv.tv_sec) {
vol->v_mtime = tv.tv_sec;
/* or finder doesn't update free space
- * XXX is it still true with newer OSX?
+ * AFP 3.2 and above clients seem to be ok without so many notification
*/
- if (afp_version > 21 && obj->options.server_notif) {
+ if (afp_version < 32 && obj->options.server_notif) {
obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
}
}
if ( !ret && folder->hide) {
/* Hide it */
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR,
- O_RDWR|O_CREAT, 0666, &ad) < 0) {
+ if (ad_open_metadata( p, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
free (p);
free(q);
return (-1);
}
- if ((ad_get_HF_flags( &ad ) & O_CREAT) ) {
- if (ad_getentryoff(&ad, ADEID_NAME)) {
- ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name));
- memcpy(ad_entry( &ad, ADEID_NAME ), folder->name,
- ad_getentrylen( &ad, ADEID_NAME ));
- }
- }
+
+ ad_setname(&ad, folder->name);
ad_getattr(&ad, &attr);
attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE );
}
ad_flush( &ad );
- ad_close( &ad, ADFLAGS_HF );
+ ad_close_metadata( &ad);
}
free(p);
free(q);