/* As long as directory.c hasn't got its own init call, this get initialized in dircache_init */
struct dir rootParent = {
NULL, NULL, NULL, NULL, /* path, d_m_name, d_u_name, d_m_name_ucs2 */
- NULL, NULL, 0, 0, /* qidx_node, d_ofork, ctime, d_flags */
+ NULL, 0, 0, /* qidx_node, ctime, d_flags */
0, 0, 0, 0 /* pdid, did, offcnt, d_vid */
};
struct dir *curdir = &rootParent;
{0} /* struct stat */
};
+/*
+ * dir_remove queues struct dirs to be freed here. We can't just delete them immeidately
+ * eg in dircache_search_by_id, because a caller somewhere up the stack might be
+ * referencing it.
+ * So instead:
+ * - we mark it as invalid by setting d_did to CNID_INVALID (ie 0)
+ * - queue it in "invalid_dircache_entries" queue
+ * - which is finally freed at the end of every AFP func in afp_dsi.c.
+ */
+q_t *invalid_dircache_entries;
+
/*******************************************************************************************
* Locals
{
static char temp[ MAXPATHLEN + 1];
char *t;
- cnid_t fileid;
+ cnid_t fileid = 0;
if (afp_version >= 30) {
if (toUTF8) {
}
/* Create struct dir */
- if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath)) == NULL) { /* 6 */
+ if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, st.st_ctime)) == NULL) { /* 6 */
LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno));
err = 1;
goto exit;
}
-
+
/* Add it to the cache only if it's a dir */
if (dircache_add(ret) != 0) { /* 7 */
err = 1;
* @param vol (r) pointer to struct vol
* @param pdid (r) Parent CNID
* @param did (r) CNID
- * @param fullpath (r) Full unix path to dir or NULL for files
+ * @param path (r) Full unix path to dir or NULL for files
+ * @param ctime (r) st_ctime from stat
*
* @returns pointer to new struct dir or NULL on error
*
const struct vol *vol,
cnid_t pdid,
cnid_t did,
- bstring path)
+ bstring path,
+ time_t ctime)
{
struct dir *dir;
dir->d_pdid = pdid;
dir->d_vid = vol->v_vid;
dir->d_fullpath = path;
+ dir->ctime_dircache = ctime;
return dir;
}
* @brief Create struct dir from struct path
*
* Create a new struct dir from struct path. Then add it to the cache.
- * The caller must have assured that the dir is not already in the cache,
- * cf theAFP_ASSERTion.
+ *
* 1. Open adouble file, get CNID from it.
* 2. Search the database, hinting with the CNID from (1).
* 3. Build fullpath and create struct dir.
AFP_ASSERT(path);
AFP_ASSERT(len > 0);
- if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) {
+ if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name), path->st.st_ctime)) != 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)) == NULL) { /* 3 */
+ if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath, path->st.st_ctime)) == NULL) { /* 3 */
err = 4;
goto exit;
}
}
/*!
- * @brief Remove a dir from a cache and free it and any ressources with it
+ * Free the queue with invalid struct dirs
+ *
+ * This gets called at the end of every AFP func.
+ */
+void dir_free_invalid_q(void)
+{
+ struct dir *dir;
+ while (dir = (struct dir *)dequeue(invalid_dircache_entries))
+ dir_free(dir);
+}
+
+/*!
+ * @brief Remove a dir from a cache and queue it for freeing
*
* 1. Check if the dir is locked or has opened forks
* 2. If it's a request to remove curdir, just chdir to volume root
* 3. Remove it from the cache
- * 4. Remove the dir plus any allocated resources it references
+ * 4. Queue it for removal
+ * 5. Mark it as invalid
*
* @param (r) pointer to struct vol
* @param (rw) pointer to struct dir
if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
return 0;
- if (dir->d_flags & DIRF_CACHELOCK || dir->d_ofork) { /* 1 */
- LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked or has opened forks",
- ntohl(dir->d_did), cfrombstr(dir->d_fullpath));
+ if (dir->d_flags & DIRF_CACHELOCK) { /* 1 */
+ LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked",
+ ntohl(dir->d_did), cfrombstr(dir->d_u_name));
return 0;
}
}
LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}",
- ntohl(dir->d_did), cfrombstr(dir->d_fullpath));
+ ntohl(dir->d_did), cfrombstr(dir->d_u_name));
dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */
- dir_free(dir); /* 4 */
-
+ enqueue(invalid_dircache_entries, dir); /* 4 */
+ dir->d_did = CNID_INVALID; /* 5 */
return 0;
}
/* 6*/
for ( p = path; *data != 0 && len > 0; len-- ) {
*p++ = *data++;
- if (p > &path[ MAXPATHLEN]) {
+ if (p > &path[UTF8FILELEN_EARLY]) { /* FIXME safeguard, limit of early Mac OS X */
afp_errno = AFPERR_PARAM;
return NULL;
}
/* Search the cache */
int unamelen = strlen(ret.u_name);
- cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen); /* 14 */
+ cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen, ret.st.st_ctime); /* 14 */
if (cdir == NULL) {
/* Not in cache, create one */
if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */
struct maccess ma;
accessmode(path->u_name, &ma, curdir, &path->st);
- if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
+
+ LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x",
+ path->u_name, ma.ma_user);
+
+ if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) {
+ LOG(log_debug, logtype_afpd, "file_access(\"%s\"): write access denied", path->u_name);
return -1;
- if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
+ }
+ if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) {
+ LOG(log_debug, logtype_afpd, "file_access(\"%s\"): read access denied", path->u_name);
return -1;
+ }
return 0;
}
ad_close_metadata( &ad);
createdir_done:
-#if 0
- /* FIXME: are we really inside the created dir? */
- if (createdir_inherit_acl(vol) != 0) {
- LOG(log_error, logtype_afpd, "Error inhereting ACL to .AppleDouble directory");
- return AFPERR_MISC;
- }
-#endif
-
memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
*rbuflen = sizeof( u_int32_t );
setvoltime(obj, vol );
name = NULL;
}
break;
-#ifdef HAVE_ACLS
+
case 5 : /* UUID -> username */
case 6 : /* UUID -> groupname */
if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
return AFPERR_PARAM;
LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
uuidtype_t type;
- len = getnamefromuuid( ibuf, &name, &type);
+ len = getnamefromuuid((unsigned char*) ibuf, &name, &type);
if (len != 0) /* its a error code, not len */
return AFPERR_NOITEM;
switch (type) {
return AFPERR_MISC;
}
break;
-#endif /* HAVE_ACLS */
+
default :
return( AFPERR_PARAM );
}
case 4 :
len = (unsigned char) *ibuf++;
break;
-#ifdef HAVE_ACLS
case 5 : /* username -> UUID */
case 6 : /* groupname -> UUID */
if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
len = ntohs(ulen);
ibuf += 2;
break;
-#endif /* HAVE_ACLS */
default :
return( AFPERR_PARAM );
}
memcpy( rbuf, &id, sizeof( id ));
*rbuflen = sizeof( id );
break;
-#ifdef HAVE_ACLS
case 5 : /* username -> UUID */
LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
- if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
+ if (0 != getuuidfromname(ibuf, UUID_USER, (unsigned char *)rbuf))
return AFPERR_NOITEM;
*rbuflen = UUID_BINSIZE;
break;
case 6 : /* groupname -> UUID */
LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
- if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
+ if (0 != getuuidfromname(ibuf, UUID_GROUP, (unsigned char *)rbuf))
return AFPERR_NOITEM;
*rbuflen = UUID_BINSIZE;
break;
-#endif /* HAVE_ACLS */
}
}
return( AFP_OK );