From: Frank Lahm Date: Tue, 10 May 2011 06:01:02 +0000 (+0200) Subject: Merge master X-Git-Url: https://arthur.barton.de/gitweb/?a=commitdiff_plain;h=313b5f94348618d65523c1d8bde1fba9988f040a;hp=b4d826a5afed64e9a97a106fbc0bbc9c0d8c3b49;p=netatalk.git Merge master --- diff --git a/NEWS b/NEWS index 757b22a7..f8d92829 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,18 @@ +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 =================== diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index 96188688..dfebaca0 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -512,8 +512,6 @@ void afp_over_dsi(AFPObj *obj) if (reload_request) { reload_request = 0; load_volumes(AFPobj); - dircache_dump(); - log_dircache_stat(); } /* The first SIGINT enables debugging, the next restores the config */ @@ -521,6 +519,8 @@ void afp_over_dsi(AFPObj *obj) static int debugging = 0; debug_request = 0; + dircache_dump(); + if (debugging) { if (obj->options.logconfig) setuplog(obj->options.logconfig); diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index ec4b762d..ffe28590 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -350,8 +350,11 @@ int afp_options_parseline(char *buf, struct afp_options *options) 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"); } } diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c index 6a9161e2..d0e89f39 100644 --- a/etc/afpd/catsearch.c +++ b/etc/afpd/catsearch.c @@ -613,8 +613,7 @@ static int catsearch(struct vol *vol, 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, diff --git a/etc/afpd/dircache.c b/etc/afpd/dircache.c index 9907c5dd..44b74ada 100644 --- a/etc/afpd/dircache.c +++ b/etc/afpd/dircache.c @@ -52,8 +52,8 @@ * 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: @@ -100,7 +100,7 @@ * 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". */ /******************************************************** @@ -288,7 +288,7 @@ static void dircache_evict(void) * 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 @@ -315,7 +315,7 @@ struct dir *dircache_search_by_did(const struct vol *vol, cnid_t cnid) 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) */ @@ -330,7 +330,7 @@ struct dir *dircache_search_by_did(const struct vol *vol, cnid_t cnid) 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); @@ -358,18 +358,17 @@ struct dir *dircache_search_by_did(const struct vol *vol, cnid_t cnid) * @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}; @@ -394,7 +393,16 @@ struct dir *dircache_search_by_name(const struct vol *vol, } 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); @@ -643,8 +651,8 @@ void dircache_dump(void) 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"); @@ -659,8 +667,8 @@ void dircache_dump(void) 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"); @@ -676,8 +684,8 @@ void dircache_dump(void) 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; } diff --git a/etc/afpd/dircache.h b/etc/afpd/dircache.h index 16c2df1d..42466d2d 100644 --- a/etc/afpd/dircache.h +++ b/etc/afpd/dircache.h @@ -35,7 +35,7 @@ extern int dircache_init(int reqsize); 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 */ diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 488f900a..df01ccc4 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -265,7 +265,7 @@ copydir_done: */ static int diroffcnt(struct dir *dir, struct stat *st) { - return st->st_ctime == dir->ctime; + return st->st_ctime == dir->d_ctime; } /* --------------------- */ @@ -468,6 +468,7 @@ struct dir *dirlookup_bypath(const struct vol *vol, const char *path) 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", @@ -480,8 +481,7 @@ struct dir *dirlookup_bypath(const struct vol *vol, const char *path) 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, @@ -494,8 +494,6 @@ struct dir *dirlookup_bypath(const struct vol *vol, const char *path) if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */ EC_FAIL; } - - EC_ZERO(bcatcstr(statpath, "/")); } EC_CLEANUP: @@ -514,7 +512,7 @@ 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. @@ -539,7 +537,7 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) 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 */ @@ -557,18 +555,19 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) /* 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; @@ -590,6 +589,7 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) /* 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; @@ -607,7 +607,8 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) * - 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; @@ -622,9 +623,10 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) } /* 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; @@ -655,7 +657,7 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) } /* 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; @@ -680,7 +682,7 @@ 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; @@ -778,8 +780,8 @@ int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir) * @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 * @@ -791,7 +793,7 @@ struct dir *dir_new(const char *m_name, cnid_t pdid, cnid_t did, bstring path, - time_t ctime) + struct stat *st) { struct dir *dir; @@ -825,7 +827,10 @@ struct dir *dir_new(const char *m_name, 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; } @@ -879,7 +884,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i 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, @@ -923,7 +928,13 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i } /* 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; } @@ -1281,7 +1292,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath) /* 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 */ @@ -1431,8 +1442,8 @@ int file_access(struct path *path, int mode) /* --------------------- */ 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; } @@ -1442,7 +1453,7 @@ void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count) */ 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); } /* ------------------------------ @@ -1569,11 +1580,11 @@ int getdirparams(const struct vol *vol, 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 )); @@ -2221,7 +2232,7 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_ 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; diff --git a/etc/afpd/directory.h b/etc/afpd/directory.h index 1504c649..b438b370 100644 --- a/etc/afpd/directory.h +++ b/etc/afpd/directory.h @@ -39,16 +39,6 @@ #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 @@ -107,7 +97,7 @@ typedef int (*dir_loop)(struct dirent *, char *, void *); 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, diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c index 1659fb77..0bc24cec 100644 --- a/etc/afpd/enumerate.c +++ b/etc/afpd/enumerate.c @@ -359,7 +359,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, */ *sd.sd_last = 0; sd.sd_last += len + 1; - curdir->offcnt--; /* a little lie */ + curdir->d_offcnt--; /* a little lie */ continue; } @@ -375,7 +375,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, 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); diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 009ec195..b5a89637 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -311,9 +311,10 @@ int getmetadata(struct vol *vol, || (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); @@ -326,18 +327,26 @@ int getmetadata(struct vol *vol, 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 { @@ -738,7 +747,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF ); createfile_done: - curdir->offcnt++; + curdir->d_offcnt++; setvoltime(obj, vol ); @@ -1324,7 +1333,7 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si retvalue = err; goto copy_exit; } - curdir->offcnt++; + curdir->d_offcnt++; setvoltime(obj, d_vol ); @@ -1782,7 +1791,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir) 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; diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 1478299e..9453111b 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -522,14 +522,14 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size 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 ); } diff --git a/etc/afpd/main.c b/etc/afpd/main.c index c926c368..37bb4bd4 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -107,20 +107,20 @@ static void fd_reset_listening_sockets(void) 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); @@ -132,6 +132,9 @@ static void afp_goaway(int sig) nologin++; auth_unload(); LOG(log_info, logtype_afpd, "disallowing logins"); + + if (server_children) + server_child_kill(server_children, CHILD_DSIFORK, sig); break; case SIGHUP : @@ -341,6 +344,7 @@ int main(int ac, char **av) 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) @@ -354,10 +358,13 @@ int main(int ac, char **av) 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) diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 60fc73e9..23bd2c16 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -604,7 +604,14 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, 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); @@ -612,15 +619,24 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, } /* 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; } @@ -787,8 +803,8 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, 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", @@ -2129,7 +2145,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t 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) ); diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c index 11987cc7..b23d57cf 100644 --- a/etc/cnid_dbd/cnid_metad.c +++ b/etc/cnid_dbd/cnid_metad.c @@ -99,11 +99,12 @@ 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" @@ -142,7 +143,7 @@ static void sigterm_handler(int sig) 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]; } @@ -178,14 +179,16 @@ static int maybe_start_dbd(char *dbdpn, struct volinfo *volinfo) 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; } } @@ -524,7 +527,7 @@ int main(int argc, char *argv[]) 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); diff --git a/include/atalk/directory.h b/include/atalk/directory.h index e8f333fb..47434759 100644 --- a/include/atalk/directory.h +++ b/include/atalk/directory.h @@ -46,22 +46,34 @@ #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 { diff --git a/libatalk/util/socket.c b/libatalk/util/socket.c index 528b2646..5bdc03c3 100644 --- a/libatalk/util/socket.c +++ b/libatalk/util/socket.c @@ -486,7 +486,8 @@ void fdset_add_fd(struct pollfd **fdsetp, * 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 * @@ -507,9 +508,15 @@ void fdset_del_fd(struct pollfd **fdsetp, 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 */ } diff --git a/man/man8/afpd.8.tmpl b/man/man8/afpd.8.tmpl index 9fc6dd37..63b340e4 100644 --- a/man/man8/afpd.8.tmpl +++ b/man/man8/afpd.8.tmpl @@ -205,6 +205,17 @@ Signals that are sent to the main \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 @@ -223,7 +234,7 @@ enables 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 @@ -239,17 +250,6 @@ The \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