#include <atalk/unix.h>
#include "directory.h"
+#include "dircache.h"
#include "desktop.h"
#include "volume.h"
#include "fork.h"
(1 << FILPBIT_UNIXPR)))
/* -------------------------- */
-u_int32_t get_id(const struct vol *vol, struct adouble *adp, const struct stat *st,
- const cnid_t did, char *upath, const int len)
+uint32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st,
+ const cnid_t did, char *upath, const int len)
{
+ static int first = 1; /* mark if this func is called the first time */
u_int32_t adcnid;
u_int32_t dbcnid = CNID_INVALID;
+restart:
if (vol->v_cdb != NULL) {
/* prime aint with what we think is the cnid, set did to zero for
catching moved files */
case CNID_ERR_PARAM:
LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
afp_errno = AFPERR_PARAM;
- return CNID_INVALID;
+ goto exit;
case CNID_ERR_PATH:
afp_errno = AFPERR_PARAM;
- return CNID_INVALID;
+ goto exit;
default:
+ /* Close CNID backend if "dbd" and switch to temp in-memory "tdb" */
+ /* we have to do it here for "dbd" because it uses "lazy opening" */
+ /* In order to not end in a loop somehow with goto restart below */
+ /* */
+ if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) {
+ cnid_close(vol->v_cdb);
+ free(vol->v_cnidscheme);
+ vol->v_cnidscheme = strdup("tdb");
+
+ int flags = CNID_FLAG_MEMORY;
+ if ((vol->v_flags & AFPVOL_NODEV)) {
+ flags |= CNID_FLAG_NODEV;
+ }
+ LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
+ vol->v_path);
+ vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL);
+ if (vol->v_cdb) {
+ /* deactivate cnid caching/storing in AppleDouble files and set ro mode*/
+ vol->v_flags &= ~AFPVOL_CACHE;
+ vol->v_flags |= AFPVOL_RO;
+#ifdef SERVERTEXT
+ /* kill ourself with SIGUSR2 aka msg pending */
+ setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead."
+ "Check server messages for details. Switching to read-only mode.");
+ kill(getpid(), SIGUSR2);
+#endif
+ goto restart; /* not try again with the temp CNID db */
+ } else {
+#ifdef SERVERTEXT
+ setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB failed too!"
+ "Check server messages for details, can't recover from this state!");
+#endif
+ }
+ }
afp_errno = AFPERR_MISC;
- return CNID_INVALID;
+ goto exit;
}
}
else if (adp && (adcnid != dbcnid)) {
}
}
}
+
+exit:
+ first = 0;
return dbcnid;
}
struct stat *st;
struct maccess ma;
-
upath = path->u_name;
st = &path->st;
-
data = buf;
if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
|| (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
|| (bitmap & (1 << FILPBIT_FNUM))) {
- if (!path->id)
- id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
- else
+ if (!path->id) {
+ struct dir *cachedfile;
+ int len = strlen(upath);
+ 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);
+
+ /* Add it to the cache */
+ LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u",
+ ntohl(dir->d_did), upath, ntohl(id));
+
+ /* Get macname from unixname first */
+ 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);
+ }
+ }
+
+ if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL)) == NULL) {
+ LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
+ exit(EXITERR_SYS);
+ }
+ if ((dircache_add(cachedfile)) != 0) {
+ LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
+ exit(EXITERR_SYS);
+ }
+ }
+ } else {
id = path->id;
+ }
+
if (id == CNID_INVALID)
return afp_errno;
+
if (!path->m_name) {
path->m_name = utompath(vol, upath, id, utf8_encoding());
}