+Changes in 2.2
+==============
+
+* UPD: Support for Berkeley DB 5.1
+* UPD: case-conversion is based on Unicode 6.0.0
+* UPD: cnid_metad: allow up to 4096 volumes
+* UPD: afpd: only forward SIGTERM and SIGUSR1 from parent to childs
+* FIX: afpd: configuration reload with SIGHUP
+* FIX: afpd: crashes in the dircache
+* FIX: afpd: Correct afp logout vs dsi eof behaviour
+* FIX: afpd: new catsearch was broken
+* FIX: afpd: only use volume UUIDs in master afpd
+* FIX: dbd: Multiple fixes, reliable locking
+* FIX: ad file suite: fix an error that resulted in CNID database inconsistencies
+
Changes in 2.2beta4
===================
if (reload_request) {
reload_request = 0;
load_volumes(AFPobj);
- dircache_dump();
- log_dircache_stat();
}
/* The first SIGINT enables debugging, the next restores the config */
static int debugging = 0;
debug_request = 0;
+ dircache_dump();
+
if (debugging) {
if (obj->options.logconfig)
setuplog(obj->options.logconfig);
while (NULL != (c = strstr(c, "-setuplog"))) {
char *optstr;
if ((optstr = getoption(c, "-setuplog"))) {
+ /* hokey2: options->logconfig must be converted to store an array of logstrings */
+ if (options->logconfig)
+ free(options->logconfig);
+ options->logconfig = strdup(optstr);
setuplog(optstr);
- options->logconfig = optstr; /* at least store the last (possibly only) one */
c += sizeof("-setuplog");
}
}
path.d_dir = dircache_search_by_name(vol,
curdir,
path.u_name,
- unlen,
- path.st.st_ctime);
+ unlen);
if (path.d_dir == NULL) {
/* path.m_name is set by adddir */
if ((path.d_dir = dir_add(vol,
* a struct dir is initialized, the fullpath to the directory is stored there.
*
* In order to speed up the CNID query for files too, which eg happens when a directory is enumerated,
- * files are stored too in the dircache. In order to differentiate between files and dirs, we re-use
- * the element fullpath, which for files is always NULL.
+ * files are stored too in the dircache. In order to differentiate between files and dirs, we set
+ * the flag DIRF_ISFILE in struct dir.d_flags for files.
*
* The most frequent codepatch that leads to caching is directory enumeration (cf enumerate.c):
* - if a element is a directory:
* Debugging
* =========
*
- * Sending SIGHUP to a afpd child causes it to dump the dircache to a file "/tmp/dircache.PID".
+ * Sending SIGINT to a afpd child causes it to dump the dircache to a file "/tmp/dircache.PID".
*/
/********************************************************
* This func builds on the fact, that all our code only ever needs to and does search
* the dircache by CNID expecting directories to be returned, but not files.
* Thus
- * (1) if we find a file (d_fullpath == NULL) for a given CNID we
+ * (1) if we find a file for a given CNID we
* (1a) remove it from the cache
* (1b) return NULL indicating nothing found
* (2) we can then use d_fullpath to stat the directory
cdir = hnode_get(hn);
if (cdir) {
- if (cdir->d_fullpath == NULL) { /* (1) */
+ if (cdir->d_flags & DIRF_ISFILE) { /* (1) */
LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not a directory:\"%s\"}",
ntohl(cnid), cfrombstr(cdir->d_u_name));
(void)dir_remove(vol, cdir); /* (1a) */
dircache_stat.expunged++;
return NULL;
}
- if (cdir->ctime_dircache != st.st_ctime) {
+ if ((cdir->dcache_ctime != st.st_ctime) || (cdir->dcache_ino != st.st_ino)) {
LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {modified:\"%s\"}",
ntohl(cnid), cfrombstr(cdir->d_u_name));
(void)dir_remove(vol, cdir);
* @param dir (r) directory
* @param name (r) name (server side encoding)
* @parma len (r) strlen of name
- * @param ctime (r) current st_ctime from stat
*
* @returns pointer to struct dir if found in cache, else NULL
*/
struct dir *dircache_search_by_name(const struct vol *vol,
const struct dir *dir,
char *name,
- int len,
- time_t ctime)
+ int len)
{
struct dir *cdir = NULL;
struct dir key;
+ struct stat st;
hnode_t *hn;
static_bstring uname = {-1, len, (unsigned char *)name};
}
if (cdir) {
- if (cdir->ctime_dircache != ctime) {
+ if (lstat(cfrombstr(cdir->d_fullpath), &st) != 0) {
+ LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {missing:\"%s\"}",
+ ntohl(dir->d_did), name, cfrombstr(cdir->d_fullpath));
+ (void)dir_remove(vol, cdir);
+ dircache_stat.expunged++;
+ return NULL;
+ }
+
+ /* Remove modified directories and files */
+ if ((cdir->dcache_ctime != st.st_ctime) || (cdir->dcache_ino != st.st_ino)) {
LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {modified}",
ntohl(dir->d_did), name);
(void)dir_remove(vol, cdir);
ntohs(dir->d_vid),
ntohl(dir->d_pdid),
ntohl(dir->d_did),
- dir->d_fullpath ? "d" : "f",
- cfrombstr(dir->d_u_name));
+ dir->d_flags & DIRF_ISFILE ? "f" : "d",
+ cfrombstr(dir->d_fullpath));
}
fprintf(dump, "\nSecondary DID/name index:\n");
ntohs(dir->d_vid),
ntohl(dir->d_pdid),
ntohl(dir->d_did),
- dir->d_fullpath ? "d" : "f",
- cfrombstr(dir->d_u_name));
+ dir->d_flags & DIRF_ISFILE ? "f" : "d",
+ cfrombstr(dir->d_fullpath));
}
fprintf(dump, "\nLRU Queue:\n");
ntohs(dir->d_vid),
ntohl(dir->d_pdid),
ntohl(dir->d_did),
- dir->d_fullpath ? "d" : "f",
- cfrombstr(dir->d_u_name));
+ dir->d_flags & DIRF_ISFILE ? "f" : "d",
+ cfrombstr(dir->d_fullpath));
n = n->next;
}
extern int dircache_add(const struct vol *, struct dir *);
extern void dircache_remove(const struct vol *, struct dir *, int flag);
extern struct dir *dircache_search_by_did(const struct vol *vol, cnid_t did);
-extern struct dir *dircache_search_by_name(const struct vol *, const struct dir *dir, char *name, int len, time_t ctime);
+extern struct dir *dircache_search_by_name(const struct vol *, const struct dir *dir, char *name, int len);
extern void dircache_dump(void);
extern void log_dircache_stat(void);
#endif /* DIRCACHE_H */
*/
static int diroffcnt(struct dir *dir, struct stat *st)
{
- return st->st_ctime == dir->ctime;
+ return st->st_ctime == dir->d_ctime;
}
/* --------------------- */
l = bsplit(rpath, '/');
for (int i = 0; i < l->qty ; i++) { /* 3. */
did = cnid;
+ EC_ZERO(bcatcstr(statpath, "/"));
EC_ZERO(bconcat(statpath, l->entry[i]));
EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
"lstat(rpath: %s, elem: %s): %s: %s",
if ((dir = dircache_search_by_name(vol, /* 5. */
dir,
cfrombstr(l->entry[i]),
- blength(l->entry[i]),
- st.st_ctime)) == NULL) {
+ blength(l->entry[i]))) == NULL) {
if ((cnid = cnid_add(vol->v_cdb, /* 6. */
&st,
did,
if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */
EC_FAIL;
}
-
- EC_ZERO(bcatcstr(statpath, "/"));
}
EC_CLEANUP:
* Resolve a DID, allocate a struct dir for it
* 1. Check for special CNIDs 0 (invalid), 1 and 2.
* 2a. Check if the DID is in the cache.
- * 2b. Check if it's really a dir (d_fullpath != NULL) because we cache files too.
+ * 2b. Check if it's really a dir because we cache files too.
* 3. If it's not in the cache resolve it via the database.
* 4. Build complete server-side path to the dir.
* 5. Check if it exists and is a directory.
int utf8;
int err = 0;
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u)", ntohl(did));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): START", ntohl(did));
/* check for did 0, 1 and 2 */
if (did == 0 || vol == NULL) { /* 1 */
/* Search the cache */
if ((ret = dircache_search_by_did(vol, did)) != NULL) { /* 2a */
- if (ret->d_fullpath == NULL) { /* 2b */
+ if (ret->d_flags & DIRF_ISFILE) { /* 2b */
afp_errno = AFPERR_BADTYPE;
ret = NULL;
goto exit;
}
if (lstat(cfrombstr(ret->d_fullpath), &st) != 0) {
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {lstat: %s}", ntohl(did), strerror(errno));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u, path: \"%s\"): lstat: %s",
+ ntohl(did), cfrombstr(ret->d_fullpath), strerror(errno));
switch (errno) {
case ENOENT:
case ENOTDIR:
/* It's not there anymore, so remove it */
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {calling dir_remove()}", ntohl(did));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): calling dir_remove", ntohl(did));
dir_remove(vol, ret);
afp_errno = AFPERR_NOOBJ;
ret = NULL;
/* Get it from the database */
cnid = did;
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): querying CNID database", ntohl(did));
if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) {
afp_errno = AFPERR_NOOBJ;
err = 1;
* - DIRDID_ROOT is hit
* - a cached entry is found
*/
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {recursion for did: %u}", ntohl(pdid));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): recursion for did: %u",
+ ntohl(did), ntohl(pdid));
if ((pdir = dirlookup(vol, pdid)) == NULL) {
err = 1;
goto exit;
}
/* stat it and check if it's a dir */
- LOG(log_debug, logtype_afpd, "dirlookup: {stating %s}", cfrombstr(fullpath));
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): stating \"%s\"",
+ ntohl(did), cfrombstr(fullpath));
- if (stat(cfrombstr(fullpath), &st) != 0) { /* 5a */
+ if (lstat(cfrombstr(fullpath), &st) != 0) { /* 5a */
switch (errno) {
case ENOENT:
afp_errno = AFPERR_NOOBJ;
}
/* Create struct dir */
- if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, st.st_ctime)) == NULL) { /* 6 */
+ if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, &st)) == NULL) { /* 6 */
LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno));
err = 1;
goto exit;
}
}
if (ret)
- LOG(log_debug, logtype_afpd, "dirlookup(did: %u): pdid: %u, \"%s\"",
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u): RESULT: pdid: %u, path: \"%s\"",
ntohl(ret->d_did), ntohl(ret->d_pdid), cfrombstr(ret->d_fullpath));
return ret;
* @param vol (r) pointer to struct vol
* @param pdid (r) Parent CNID
* @param did (r) CNID
- * @param path (r) Full unix path to dir or NULL for files
- * @param ctime (r) st_ctime from stat
+ * @param path (r) Full unix path to object
+ * @param st (r) struct stat of object
*
* @returns pointer to new struct dir or NULL on error
*
cnid_t pdid,
cnid_t did,
bstring path,
- time_t ctime)
+ struct stat *st)
{
struct dir *dir;
dir->d_pdid = pdid;
dir->d_vid = vol->v_vid;
dir->d_fullpath = path;
- dir->ctime_dircache = ctime;
+ dir->dcache_ctime = st->st_ctime;
+ dir->dcache_ino = st->st_ino;
+ if (!S_ISDIR(st->st_mode))
+ dir->d_flags = DIRF_ISFILE;
return dir;
}
AFP_ASSERT(path);
AFP_ASSERT(len > 0);
- if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name), path->st.st_ctime)) != NULL) {
+ if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) {
/* there's a stray entry in the dircache */
LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {stray cache entry: did:%u,'%s', removing}",
ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name,
}
/* Allocate and initialize struct dir */
- if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath, path->st.st_ctime)) == NULL) { /* 3 */
+ if ((cdir = dir_new(path->m_name,
+ path->u_name,
+ vol,
+ dir->d_did,
+ id,
+ fullpath,
+ &path->st)) == NULL) { /* 3 */
err = 4;
goto exit;
}
/* Search the cache */
int unamelen = strlen(ret.u_name);
- cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen, ret.st.st_ctime); /* 14 */
+ cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen); /* 14 */
if (cdir == NULL) {
/* Not in cache, create one */
if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */
/* --------------------- */
void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
{
- dir->offcnt = count;
- dir->ctime = st->st_ctime;
+ dir->d_offcnt = count;
+ dir->d_ctime = st->st_ctime;
dir->d_flags &= ~DIRF_CNID;
}
*/
int dirreenumerate(struct dir *dir, struct stat *st)
{
- return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
+ return st->st_ctime == dir->d_ctime && (dir->d_flags & DIRF_CNID);
}
/* ------------------------------
ashort = 0;
/* this needs to handle current directory access rights */
if (diroffcnt(dir, st)) {
- ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
+ ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt;
}
else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
setdiroffcnt(dir, st, ret);
- ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
+ ashort = (dir->d_offcnt > 0xffff)?0xffff:dir->d_offcnt;
}
ashort = htons( ashort );
memcpy( data, &ashort, sizeof( ashort ));
return AFPERR_MISC;
}
- curdir->offcnt++;
+ curdir->d_offcnt++;
if ((dir = dir_add(vol, curdir, s_path, strlen(s_path->u_name))) == NULL) {
return AFPERR_MISC;
#include "globals.h"
#include "volume.h"
-#define DIRF_FSMASK (3<<0)
-#define DIRF_NOFS (0<<0)
-#define DIRF_AFS (1<<0)
-#define DIRF_UFS (2<<0)
-
-#define DIRF_OFFCNT (1<<4) /* offsprings count is valid */
-#define DIRF_CNID (1<<5) /* renumerate id */
-
-#define AFPDIR_READ (1<<0)
-
/* directory bits */
#define DIRPBIT_ATTR 0
#define DIRPBIT_PDID 1
extern void dir_free_invalid_q(void);
extern struct dir *dir_new(const char *mname, const char *uname, const struct vol *,
- cnid_t pdid, cnid_t did, bstring fullpath, time_t ctime);
+ cnid_t pdid, cnid_t did, bstring fullpath, struct stat *);
extern void dir_free (struct dir *);
extern struct dir *dir_add(struct vol *, const struct dir *, struct path *, int);
extern int dir_modify(const struct vol *vol, struct dir *dir, cnid_t pdid, cnid_t did,
*/
*sd.sd_last = 0;
sd.sd_last += len + 1;
- curdir->offcnt--; /* a little lie */
+ curdir->d_offcnt--; /* a little lie */
continue;
}
continue;
}
int len = strlen(s_path.u_name);
- if ((dir = dircache_search_by_name(vol, curdir, s_path.u_name, len, s_path.st.st_ctime)) == NULL) {
+ if ((dir = dircache_search_by_name(vol, curdir, s_path.u_name, len)) == NULL) {
if ((dir = dir_add(vol, curdir, &s_path, len)) == NULL) {
LOG(log_error, logtype_afpd, "enumerate(vid:%u, did:%u, name:'%s'): error adding dir: '%s'",
ntohs(vid), ntohl(did), o_path->u_name, s_path.u_name);
|| (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
|| (bitmap & (1 << FILPBIT_FNUM))) {
if (!path->id) {
+ bstring fullpath;
struct dir *cachedfile;
int len = strlen(upath);
- if ((cachedfile = dircache_search_by_name(vol, dir, upath, len, st->st_ctime)) != NULL)
+ if ((cachedfile = dircache_search_by_name(vol, dir, upath, len)) != NULL)
id = cachedfile->d_did;
else {
id = get_id(vol, adp, st, dir->d_did, upath, len);
if (path->m_name == NULL) {
if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) {
LOG(log_error, logtype_afpd, "getmetadata: utompath error");
- exit(EXITERR_SYS);
+ return AFPERR_MISC;
}
}
- if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL, st->st_ctime)) == NULL) {
+ /* Build fullpath */
+ if (((fullpath = bstrcpy(dir->d_fullpath)) == NULL)
+ || (bconchar(fullpath, '/') != BSTR_OK)
+ || (bcatcstr(fullpath, upath)) != BSTR_OK) {
+ LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno));
+ return AFPERR_MISC;
+ }
+
+ if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, fullpath, st)) == NULL) {
LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
- exit(EXITERR_SYS);
+ return AFPERR_MISC;
}
if ((dircache_add(vol, cachedfile)) != 0) {
LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
- exit(EXITERR_SYS);
+ return AFPERR_MISC;
}
}
} else {
ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
createfile_done:
- curdir->offcnt++;
+ curdir->d_offcnt++;
setvoltime(obj, vol );
retvalue = err;
goto copy_exit;
}
- curdir->offcnt++;
+ curdir->d_offcnt++;
setvoltime(obj, d_vol );
if (dirreenumerate(dir, &st)) {
/* we already did it once and the dir haven't been modified */
- return dir->offcnt;
+ return dir->d_offcnt;
}
data.vol = vol;
rc = deletefile(vol, -1, upath, 1);
struct dir *cachedfile;
- if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath), s_path->st.st_ctime))) {
+ if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) {
dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
dir_free(cachedfile);
}
}
}
if ( rc == AFP_OK ) {
- curdir->offcnt--;
+ curdir->d_offcnt--;
setvoltime(obj, vol );
}
continue;
fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, config->fd);
}
- fd_set_listening_sockets();
}
/* ------------------ */
static void afp_goaway(int sig)
{
- if (server_children)
- server_child_kill(server_children, CHILD_DSIFORK, sig);
-
switch( sig ) {
case SIGTERM :
LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
AFPConfig *config;
+
+ if (server_children)
+ server_child_kill(server_children, CHILD_DSIFORK, sig);
+
for (config = configs; config; config = config->next)
if (config->server_cleanup)
config->server_cleanup(config);
nologin++;
auth_unload();
LOG(log_info, logtype_afpd, "disallowing logins");
+
+ if (server_children)
+ server_child_kill(server_children, CHILD_DSIFORK, sig);
break;
case SIGHUP :
if (reloadconfig) {
nologin++;
auth_unload();
+ fd_reset_listening_sockets();
LOG(log_info, logtype_afpd, "re-reading configuration file");
for (config = configs; config; config = config->next)
LOG(log_error, logtype_afpd, "config re-read: no servers configured");
exit(EXITERR_CONF);
}
- fd_reset_listening_sockets();
+
+ fd_set_listening_sockets();
+
nologin = 0;
reloadconfig = 0;
errno = saveerrno;
+ continue;
}
if (ret == 0)
if ( (flags & CONV_REQMANGLE) || (tmpvlen > AFPVOL_MACNAMELEN)) {
if (tmpvlen + suffixlen > AFPVOL_MACNAMELEN) {
flags = CONV_FORCE;
- tmpvlen = convert_charset(obj->options.unixcharset, obj->options.maccharset, 0, name, vlen, tmpname, AFPVOL_MACNAMELEN - suffixlen, &flags);
+ tmpvlen = convert_charset(obj->options.unixcharset,
+ obj->options.maccharset,
+ 0,
+ name,
+ vlen,
+ tmpname,
+ AFPVOL_MACNAMELEN - suffixlen,
+ &flags);
tmpname[tmpvlen >= 0 ? tmpvlen : 0] = 0;
}
strcat(tmpname, suffix);
}
/* Secondly convert name from maccharset to UCS2 */
- if ( 0 >= ( macvlen = convert_string(obj->options.maccharset, CH_UCS2, tmpname, tmpvlen, mactmpname, AFPVOL_U8MNAMELEN*2)) )
+ if ( 0 >= ( macvlen = convert_string(obj->options.maccharset,
+ CH_UCS2,
+ tmpname,
+ tmpvlen,
+ mactmpname,
+ AFPVOL_U8MNAMELEN*2)) )
return -1;
LOG(log_maxdebug, logtype_afpd, "createvol: Volume '%s' -> Longname: '%s'", name, tmpname);
/* check duplicate */
for ( volume = Volumes; volume; volume = volume->v_next ) {
- if (( strcasecmp_w( volume->v_u8mname, u8mtmpname ) == 0 ) || ( strcasecmp_w( volume->v_macname, mactmpname ) == 0 )){
- LOG (log_error, logtype_afpd, "ERROR: Volume name is duplicated. Check AppleVolumes files.");
+ if ((utf8_encoding() && (strcasecmp_w(volume->v_u8mname, u8mtmpname) == 0))
+ ||
+ (!utf8_encoding() && (strcasecmp_w(volume->v_macname, mactmpname) == 0))) {
+ LOG (log_error, logtype_afpd,
+ "Duplicate volume name, check AppleVolumes files: previous: \"%s\", new: \"%s\"",
+ volume->v_localname, name);
if (volume->v_deleted) {
volume->v_new = hide = 1;
}
check_ea_sys_support(volume);
initvol_vfs(volume);
- /* get/store uuid from file */
- if (volume->v_flags & AFPVOL_TM) {
+ /* get/store uuid from file in afpd master*/
+ if ((parent_or_child == 0) && (volume->v_flags & AFPVOL_TM)) {
char *uuid = get_vol_uuid(obj, volume->v_localname);
if (!uuid) {
LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID",
DIRDID_ROOT_PARENT,
DIRDID_ROOT,
bfromcstr(volume->v_path),
- st.st_ctime)
+ &st)
) == NULL) {
free(vol_mname);
LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
static int srvfd;
static int rqstfd;
static volatile sig_atomic_t sigchild = 0;
+static uint maxvol;
#define MAXSPAWN 3 /* Max times respawned in.. */
#define TESTTIME 42 /* this much seconds apfd client tries to *
* to reconnect every 5 secondes, catch it */
-#define MAXVOLS 512
+#define MAXVOLS 4096
#define DEFAULTHOST "localhost"
#define DEFAULTPORT "4700"
static struct server *test_usockfn(struct volinfo *volinfo)
{
int i;
- for (i = 0; i < MAXVOLS; i++) {
+ for (i = 0; i < maxvol; i++) {
if ((srv[i].volinfo) && (strcmp(srv[i].volinfo->v_path, volinfo->v_path) == 0)) {
return &srv[i];
}
time(&t);
if (!up) {
- /* find an empty slot */
- for (i = 0; i < MAXVOLS; i++) {
- if (srv[i].volinfo == NULL) {
+ /* find an empty slot (i < maxvol) or the first free slot (i == maxvol)*/
+ for (i = 0; i <= maxvol; i++) {
+ if (srv[i].volinfo == NULL && i < MAXVOLS) {
up = &srv[i];
up->volinfo = volinfo;
retainvolinfo(volinfo);
up->tm = t;
up->count = 0;
+ if (i == maxvol)
+ maxvol++;
break;
}
}
rqstfd = usockfd_check(srvfd, &set);
/* Collect zombie processes and log what happened to them */
if (sigchild) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- for (i = 0; i < MAXVOLS; i++) {
+ for (i = 0; i < maxvol; i++) {
if (srv[i].pid == pid) {
srv[i].pid = 0;
close(srv[i].control_fd);
#define DIRDID_ROOT_PARENT htonl(1) /* parent directory of root */
#define DIRDID_ROOT htonl(2) /* root directory */
+/* struct dir.d_flags */
+#define DIRF_FSMASK (3<<0)
+#define DIRF_NOFS (0<<0)
+#define DIRF_AFS (1<<0)
+#define DIRF_UFS (1<<1)
+#define DIRF_ISFILE (1<<3) /* it's cached file, not a directory */
+#define DIRF_OFFCNT (1<<4) /* offsprings count is valid */
+#define DIRF_CNID (1<<5) /* renumerate id */
+
struct dir {
- bstring d_fullpath; /* complete unix path to dir */
+ bstring d_fullpath; /* complete unix path to dir (or file) */
bstring d_m_name; /* mac name */
bstring d_u_name; /* unix name */
/* be careful here! if d_m_name == d_u_name, d_u_name */
/* will just point to the same storage as d_m_name !! */
ucs2_t *d_m_name_ucs2; /* mac name as UCS2 */
qnode_t *qidx_node; /* pointer to position in queue index */
- time_t ctime; /* inode ctime, used and modified by reenumeration */
- time_t ctime_dircache; /* inode ctime, used and modified by dircache */
+ time_t d_ctime; /* inode ctime, used and modified by reenumeration */
+
int d_flags; /* directory flags */
cnid_t d_pdid; /* CNID of parent directory */
cnid_t d_did; /* CNID of directory */
- uint32_t offcnt; /* offspring count */
+ uint32_t d_offcnt; /* offspring count */
uint16_t d_vid; /* only needed in the dircache, because
we put all directories in one cache. */
+ /* Stuff used in the dircache */
+ time_t dcache_ctime; /* inode ctime, used and modified by dircache */
+ ino_t dcache_ino; /* inode number, used to detect changes in the dircache */
};
struct path {
* Remove a fd from our pollfd array
*
* 1. Search fd
- * 2. If we remove the last array elemnt, just decrease count
+ * 2a
+ * 2b If we remove the last array elemnt, just decrease count
* 3. If found move all following elements down by one
* 4. Decrease count of used elements in array
*
struct pollfd *fdset = *fdsetp;
struct polldata *polldata = *polldatap;
+ if (*fdset_usedp < 1)
+ return;
+
for (int i = 0; i < *fdset_usedp; i++) {
if (fdset[i].fd == fd) { /* 1 */
- if (i < (*fdset_usedp - 1)) { /* 2 */
+ if (i == 0 && *fdset_usedp == 1) { /* 2a */
+ fdset[i].fd = -1;
+ memset(&polldata[i], 0, sizeof(struct polldata));
+ } else if (i < (*fdset_usedp - 1)) { /* 2b */
memmove(&fdset[i], &fdset[i+1], (*fdset_usedp - 1) * sizeof(struct pollfd)); /* 3 */
memmove(&polldata[i], &polldata[i+1], (*fdset_usedp - 1) * sizeof(struct polldata)); /* 3 */
}
\fBafpd\fR
process are propagated to the children, so all will be affected\&.
.PP
+To shut down a user\'s
+\fBafpd\fR
+process it is recommended that
+\fBSIGKILL (\-9)\fR
+\fINOT\fR
+be used, except as a last resort, as this may leave the CNID database in an inconsistent state\&. The safe way to terminate an
+\fBafpd\fR
+is to send it a
+\fBSIGTERM (\-15)\fR
+signal and wait for it to die on its own\&.
+.PP
SIGHUP
.RS 4
Sending a
logging for this process\&. The log is sent to fhe file
/tmp/afpd\&.PID\&.XXXXXX\&. Sending another
\fBSIGINT\fR
-will terminate the process\&.
+will revert to the original log settings\&.
.RE
.PP
SIGUSR1
\fBafpd\fR
process will look in the message directory configured at build time for a file named message\&.pid\&. For each one found, a the contents will be sent as a message to the associated AFP client\&. The file is removed after the message is sent\&. This should only be sent to a child
\fBafpd\fR\&.
-.sp
-To shut down a user\'s
-\fBafpd\fR
-process it is recommended that
-\fBSIGKILL (\-9)\fR
-\fINOT\fR
-be used, except as a last resort, as this may leave the CNID database in an inconsistent state\&. The safe way to terminate an
-\fBafpd\fR
-is to send it a
-\fBSIGTERM (\-15)\fR
-signal and wait for it to die on its own\&.
.RE
.SH "FILES"
.PP