/*
- * $Id: volume.c,v 1.23 2002-03-13 19:29:17 srittau Exp $
+ * $Id: volume.c,v 1.46 2003-01-12 14:40:04 didg Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
static char *Trash = "\02\024Network Trash Folder";
#endif /* CNID_DB */
static struct extmap *extmap = NULL, *defextmap = NULL;
+static int extmap_cnt;
#define VOLOPT_ALLOW 0 /* user allow list */
#define VOLOPT_DENY 1 /* user deny list */
#define VOLOPT_VETO 10 /* list of veto filespec */
#ifdef FORCE_UIDGID
+#warning UIDGID
+#include "uid.h"
+
#define VOLOPT_FORCEUID 11 /* force uid for username x */
#define VOLOPT_FORCEGID 12 /* force gid for group x */
-#define VOLOPT_MAX 12
+#define VOLOPT_UMASK 13
+#define VOLOPT_MAX 13
#else /* normally, there are only 9 possible options */
-#define VOLOPT_MAX 10
+#define VOLOPT_UMASK 11
+#define VOLOPT_MAX 11
#endif /* FORCE_UIDGID */
#define VOLOPT_NUM (VOLOPT_MAX + 1)
}
/* debug: show which codepage directory we are using */
- LOG(log_debug, logtype_default, "using codepage directory: %s", page);
+ LOG(log_debug, logtype_afpd, "using codepage directory: %s", page);
return page;
}
/* handle all the options. tmp can't be NULL. */
static void volset(struct vol_option *options, char *volname, int vlen,
- const char *nlspath, const char *tmp)
+ const char *nlspath, const char *tmp, AFPObj *obj,
+ struct passwd *pwd)
{
char *val;
val = strchr(tmp, ':');
+ LOG(log_debug, logtype_afpd, "Parsing volset %s", val);
+
if (optionok(tmp, "allow:", val)) {
if (options[VOLOPT_ALLOW].c_value)
free(options[VOLOPT_ALLOW].c_value);
options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
else if (strcasecmp(p, "dropkludge") == 0)
options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
+ else if (strcasecmp(p, "nofileid") == 0)
+ options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID;
+ else if (strcasecmp(p, "utf8") == 0)
+ options[VOLOPT_FLAGS].i_value |= AFPVOL_UTF8;
p = strtok(NULL, ",");
}
#ifdef CNID_DB
} else if (optionok(tmp, "dbpath:", val)) {
+ char t[MAXPATHLEN + 1];
if (options[VOLOPT_DBPATH].c_value)
free(options[VOLOPT_DBPATH].c_value);
- options[VOLOPT_DBPATH].c_value = strdup(val + 1);
+ volxlate(obj, t, MAXPATHLEN, val, pwd, NULL);
+ options[VOLOPT_DBPATH].c_value = strdup(t + 1);
#endif /* CNID_DB */
+ } else if (optionok(tmp, "umask:", val)) {
+ options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8);
} else if (optionok(tmp, "mapchars:",val)) {
if (options[VOLOPT_MAPCHARS].c_value)
free(options[VOLOPT_MAPCHARS].c_value);
} else if (val) {
/* ignore unknown options */
- LOG(log_debug, logtype_default, "ignoring unknown volume option: %s", tmp);
+ LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
} else {
/* we'll assume it's a volume name. */
if (( volume =
(struct vol *)calloc(1, sizeof( struct vol ))) == NULL ) {
- LOG(log_error, logtype_default, "creatvol: malloc: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
return -1;
}
if (( volume->v_name =
(char *)malloc( vlen + 1 )) == NULL ) {
- LOG(log_error, logtype_default, "creatvol: malloc: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
free(volume);
return -1;
}
if (( volume->v_path =
(char *)malloc( strlen( path ) + 1 )) == NULL ) {
- LOG(log_error, logtype_default, "creatvol: malloc: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
free(volume->v_name);
free(volume);
return -1;
volume->v_dbpath = strdup(options[VOLOPT_DBPATH].c_value);
#endif /* CNID_DB */
+ if (options[VOLOPT_UMASK].i_value)
+ volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
+
#ifdef FORCE_UIDGID
if (options[VOLOPT_FORCEUID].c_value) {
int c;
p = buf;
- while ((( c = getc( fp )) != EOF ) && ( size > 0 )) {
+ while ((EOF != ( c = getc( fp )) ) && ( size > 0 )) {
if ( c == '\n' || c == '\r' ) {
*p++ = '\n';
break;
int user;
{
struct extmap *em;
+ int cnt;
- for ( em = extmap; em; em = em->em_next ) {
- if ( strdiacasecmp( em->em_ext, ext ) == 0 ) {
+ if (extmap == NULL) {
+ if (( extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
+ LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) );
+ return;
+ }
+ }
+ ext++;
+ for ( em = extmap, cnt = 0; em->em_ext; em++, cnt++) {
+ if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) {
break;
}
}
- if ( em == NULL ) {
- if (( em =
- (struct extmap *)malloc( sizeof( struct extmap ))) == NULL ) {
- LOG(log_error, logtype_default, "setextmap: malloc: %s", strerror(errno) );
+ if ( em->em_ext == NULL ) {
+ if (!(extmap = realloc( extmap, sizeof( struct extmap ) * (cnt +2))) ) {
+ LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) );
return;
}
- em->em_next = extmap;
- extmap = em;
+ (extmap +cnt +1)->em_ext = NULL;
+ em = extmap +cnt;
} else if ( !user ) {
return;
}
+ if (em->em_ext)
+ free(em->em_ext);
- strcpy( em->em_ext, ext );
+ if (!(em->em_ext = strdup( ext))) {
+ LOG(log_error, logtype_afpd, "setextmap: strdup: %s", strerror(errno) );
+ return;
+ }
if ( *type == '\0' ) {
memcpy(em->em_type, "????", sizeof( em->em_type ));
} else {
memcpy(em->em_creator, creator, sizeof( em->em_creator ));
}
+}
- if ( strcmp( ext, "." ) == 0 ) {
- defextmap = em;
+/* -------------------------- */
+static int extmap_cmp(const void *map1, const void *map2)
+{
+ const struct extmap *em1 = map1;
+ const struct extmap *em2 = map2;
+ return strdiacasecmp(em1->em_ext, em2->em_ext);
+}
+
+static void sortextmap( void)
+{
+ struct extmap *em;
+
+ extmap_cnt = 0;
+ if ((em = extmap) == NULL) {
+ return;
+ }
+ while (em->em_ext) {
+ em++;
+ extmap_cnt++;
+ }
+ if (extmap_cnt) {
+ qsort(extmap, extmap_cnt, sizeof(struct extmap), extmap_cmp);
+ defextmap = extmap;
}
}
+
/*
* Read a volume configuration file and add the volumes contained within to
* the global volume list. If p2 is non-NULL, the file that is opened is
strcat( path, p2 );
}
- if (( fp = fopen( path, "r" )) == NULL ) {
+ if (NULL == ( fp = fopen( path, "r" )) ) {
return( -1 );
}
path + VOLOPT_DEFAULT_LEN) < 0)
break;
volset(save_options, tmp, sizeof(tmp) - 1,
- obj->options.nlspath, path + VOLOPT_DEFAULT_LEN);
+ obj->options.nlspath, path + VOLOPT_DEFAULT_LEN,
+ obj, pwent);
}
}
break;
strcat( tmp, "/" );
strcat( tmp, p );
}
+ /* Tag a user's home directory with their umask. Note, this will
+ * be overwritten if the user actually specifies a umask: option
+ * for a '~' volume. */
+ save_options[VOLOPT_UMASK].i_value = obj->options.save_mask;
/* fall through */
case '/' :
break;
volset(options, volname, sizeof(volname) - 1,
- obj->options.nlspath, tmp);
+ obj->options.nlspath, tmp, obj, pwent);
}
/* check allow/deny lists:
}
}
volfree(save_options, NULL);
+ sortextmap();
if ( fclose( fp ) != 0 ) {
- LOG(log_error, logtype_default, "readvolfile: fclose: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
}
return( 0 );
}
ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
memcpy(ad_entry( &ad, ADEID_NAME ), slash,
ad_getentrylen( &ad, ADEID_NAME ));
+ ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st->st_mtime);
ad_flush(&ad, ADFLAGS_HF);
}
switch ( bit ) {
case VOLPBIT_ATTR :
-#ifdef CNID_DB
- ashort = VOLPBIT_ATTR_FILEID;
-#else /* CNID_DB */
ashort = 0;
+#ifdef CNID_DB
+ if (0 == (vol->v_flags & AFPVOL_NOFILEID)) {
+ ashort = VOLPBIT_ATTR_FILEID;
+ }
#endif /* CNID_DB */
/* check for read-only.
* NOTE: we don't actually set the read-only flag unless
* it's passed in that way as it's possible to mount
* a read-write filesystem under a read-only one. */
if ((vol->v_flags & AFPVOL_RO) ||
- ((utime(vol->v_path, NULL) < 0) && (errno == EROFS)))
+ ((utime(vol->v_path, NULL) < 0) && (errno == EROFS))) {
ashort |= VOLPBIT_ATTR_RO;
+ }
+ ashort |= VOLPBIT_ATTR_CATSEARCH;
+ if (afp_version >= 30) {
+ ashort |= VOLPBIT_ATTR_UTF8;
+ }
ashort = htons(ashort);
memcpy(data, &ashort, sizeof( ashort ));
data += sizeof( ashort );
data = rbuf + 5;
for ( vcnt = 0, volume = volumes; volume; volume = volume->v_next ) {
if ( stat( volume->v_path, &st ) < 0 ) {
- LOG(log_info, logtype_default, "afp_getsrvrparms: stat %s: %s",
+ LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s",
volume->v_path, strerror(errno) );
continue; /* can't access directory */
}
*rbuflen = data - rbuf;
data = rbuf;
if ( gettimeofday( &tv, 0 ) < 0 ) {
- LOG(log_error, logtype_default, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
*rbuflen = 0;
return AFPERR_PARAM;
}
ret = AFPERR_ACCESS;
goto openvol_err;
}
-
+ /* FIXME
+ */
+ if (afp_version >= 30) {
+ volume->max_filename = 255;
+ }
+ else {
+ volume->max_filename = MACFILELEN;
+ }
if (( volume->v_flags & AFPVOL_OPEN ) == 0 ) {
- if ((dir = dirnew(strlen(volume->v_name) + 1)) == NULL) {
- LOG(log_error, logtype_default, "afp_openvol: malloc: %s", strerror(errno) );
+ /* FIXME unix name != mac name */
+ if ((dir = dirnew(volume->v_name, volume->v_name) ) == NULL) {
+ LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) );
ret = AFPERR_MISC;
goto openvol_err;
}
dir->d_did = DIRDID_ROOT;
dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
- strcpy( dir->d_name, volume->v_name );
volume->v_dir = volume->v_root = dir;
volume->v_flags |= AFPVOL_OPEN;
}
+#ifdef FORCE_UIDGID
+ set_uidgid ( volume );
+#endif /* FORCE_UIDGID */
if ( stat( volume->v_path, &st ) < 0 ) {
ret = AFPERR_PARAM;
bitmap = htons( bitmap );
memcpy(rbuf, &bitmap, sizeof( bitmap ));
- curdir = volume->v_dir;
if ( chdir( volume->v_path ) < 0 ) {
ret = AFPERR_PARAM;
goto openvol_err;
}
+ curdir = volume->v_dir;
#ifdef CNID_DB
if (volume->v_dbpath)
- volume->v_db = cnid_open (volume->v_dbpath);
- if (volume->v_db == 0)
- volume->v_db = cnid_open (volume->v_path);
+ volume->v_db = cnid_open (volume->v_dbpath, volume->v_umask);
+ if (volume->v_db == NULL)
+ volume->v_db = cnid_open (volume->v_path, volume->v_umask);
#endif /* CNID_DB */
#ifndef CNID_DB
*rbuflen = 0;
ibuf += 2;
memcpy(&vid, ibuf, sizeof( vid ));
- if (( vol = getvolbyvid( vid )) == NULL ) {
+ if (NULL == ( vol = getvolbyvid( vid )) ) {
return( AFPERR_PARAM );
}
}
}
if ( ovol != NULL ) {
- curdir = ovol->v_dir;
- if ( chdir( ovol->v_path ) < 0 ) {
- return( AFPERR_PARAM );
+ /* Even if chdir fails, we can't say afp_closevol fails. */
+ if ( chdir( ovol->v_path ) == 0 ) {
+ curdir = ovol->v_dir;
}
}
-
dirfree( vol->v_root );
vol->v_dir = NULL;
#ifdef CNID_DB
return( NULL );
}
+#ifdef FORCE_UIDGID
+ set_uidgid ( vol );
+#endif /* FORCE_UIDGID */
+
return( vol );
}
+/* ------------------------ */
+static int ext_cmp_key(const void *key, const void *obj)
+{
+ const char *p = key;
+ const struct extmap *em = obj;
+ return strdiacasecmp(p, em->em_ext);
+}
struct extmap *getextmap(const char *path)
{
- char *p;
- struct extmap *em;
+ char *p;
+ struct extmap *em;
- if (( p = strrchr( path, '.' )) == NULL ) {
+ if (NULL == ( p = strrchr( path, '.' )) ) {
return( defextmap );
}
-
- for ( em = extmap; em; em = em->em_next ) {
- if ( strdiacasecmp( em->em_ext, p ) == 0 ) {
- break;
- }
- }
- if ( em == NULL ) {
+ p++;
+ if (!*p || !extmap_cnt) {
return( defextmap );
- } else {
+ }
+ em = bsearch(p, extmap, extmap_cnt, sizeof(struct extmap), ext_cmp_key);
+ if (em) {
return( em );
+ } else {
+ return( defextmap );
}
}
+struct extmap *getdefextmap(void)
+{
+ return( defextmap );
+}
+
+/*
+ poll if a volume is changed by other processes.
+*/
+int pollvoltime(obj)
+AFPObj *obj;
+{
+ struct vol *vol;
+ struct timeval tv;
+ struct stat st;
+
+ if (!(afp_version > 21 && obj->options.server_notif))
+ return 0;
+
+ if ( gettimeofday( &tv, 0 ) < 0 )
+ return 0;
+
+ for ( vol = volumes; vol; vol = vol->v_next ) {
+ if ( (vol->v_flags & AFPVOL_OPEN) && vol->v_time + 30 < tv.tv_sec) {
+ if ( !stat( vol->v_path, &st ) && vol->v_time != st.st_mtime ) {
+ vol->v_time = st.st_mtime;
+ if (!obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED))
+ return -1;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
void setvoltime(obj, vol )
AFPObj *obj;
struct vol *vol;
* [RS] */
if ( gettimeofday( &tv, 0 ) < 0 ) {
- LOG(log_error, logtype_default, "setvoltime: gettimeofday: %s", strerror(errno) );
+ LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) );
return;
}
if( utime( vol->v_path, NULL ) < 0 ) {
/* a little granularity */
if (vol->v_time < tv.tv_sec) {
vol->v_time = tv.tv_sec;
- if (obj->options.server_notif) {
+ if (afp_version > 21 && obj->options.server_notif) {
obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
}
}
memcpy(&bitmap, ibuf, sizeof( bitmap ));
bitmap = ntohs( bitmap );
- if (( vol = getvolbyvid( vid )) == NULL ) {
+ if (NULL == ( vol = getvolbyvid( vid )) ) {
*rbuflen = 0;
return( AFPERR_PARAM );
}
}
-int wincheck(struct vol *vol, const char *path)
+int wincheck(const struct vol *vol, const char *path)
{
int len;