normchar_t * entry = NULL;
if (op->scp->dirBplus == NULL ||
- op->dataVersion != op->scp->dirDataVersion) {
+ op->dataVersion > op->scp->dirDataVersion) {
rc = EINVAL;
goto done;
}
entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+ if (!entry) {
+ rc = EINVAL;
+ goto done;
+ }
key.name = entry;
lock_AssertAny(&op->scp->dirlock);
*/
slot = getSlot(op->scp->dirBplus, leafNode);
if (slot <= BTERROR) {
- op->scp->dirDataVersion = 0;
+ op->scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
rc = (slot == BTERROR ? EINVAL : ENOENT);
goto done;
}
LARGE_INTEGER start, end;
if (op->scp->dirBplus == NULL ||
- op->dataVersion != op->scp->dirDataVersion) {
+ op->dataVersion > op->scp->dirDataVersion) {
rc = EINVAL;
goto done;
}
entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+ if (!entry) {
+ rc = EINVAL;
+ goto done;
+ }
key.name = entry;
lock_AssertAny(&op->scp->dirlock);
}
normalizedName = cm_ClientStringToNormStringAlloc(entry, -1, NULL);
+ if (!normalizedName) {
+ rc = EINVAL;
+ goto done;
+ }
key.name = normalizedName;
lock_AssertWrite(&op->scp->dirlock);
}
normalizedEntry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+ if (!normalizedEntry) {
+ rc = EINVAL;
+ goto done;
+ }
key.name = normalizedEntry;
lock_AssertWrite(&op->scp->dirlock);
}
data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
+ if (data.cname == NULL) {
+#ifdef DEBUG
+ DebugBreak();
+#endif
+ return 0;
+ }
data.fsname = cm_FsStrDup(dep->name);
data.shortform = FALSE;
key.name = wshortName;
data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
- data.fsname = cm_FsStrDup(dep->name);
- data.shortform = TRUE;
+ if (data.cname) {
+ data.fsname = cm_FsStrDup(dep->name);
+ data.shortform = TRUE;
- insert(scp->dirBplus, key, data);
+ insert(scp->dirBplus, key, data);
+ }
}
if (normalized_name)
size_t size;
if (entries == 0)
- return NULL;
-
- size = sizeof(cm_direnum_t)+(entries-1)*sizeof(cm_direnum_entry_t);
+ size = sizeof(cm_direnum_t);
+ else
+ size = sizeof(cm_direnum_t)+(entries-1)*sizeof(cm_direnum_entry_t);
enump = (cm_direnum_t *)malloc(size);
- memset(enump, 0, size);
- enump->count = entries;
+ if (enump) {
+ memset(enump, 0, size);
+ enump->count = entries;
+ }
return enump;
}
long
-cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
- clientchar_t * maskp, cm_direnum_t **enumpp)
+cm_BPlusDirEnumerate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
+ afs_uint32 locked, clientchar_t * maskp,
+ afs_uint32 fetchStatus, cm_direnum_t **enumpp)
{
afs_uint32 count = 0, slot, numentries;
Nptr leafNode = NONODE, nextLeafNode;
Nptr firstDataNode, dataNode, nextDataNode;
- cm_direnum_t * enump;
+ cm_direnum_t * enump = NULL;
long rc = 0;
char buffer[512];
if (!locked)
lock_ObtainRead(&scp->dirlock);
+ /*
+ * Hold a reference to the directory so that it wont' be
+ * recycled while the enumeration is active.
+ */
+ cm_HoldSCache(scp);
+ cm_HoldUser(userp);
+
if (scp->dirBplus == NULL) {
osi_Log0(afsd_logp, "cm_BPlusDirEnumerate No BPlus Tree");
+ rc = CM_ERROR_WOULDBLOCK;
goto done;
}
nextLeafNode = getnextnode(leafNode);
}
+ enump->dscp = scp;
+ enump->userp = userp;
+ enump->reqFlags = reqp->flags;
+ enump->fetchStatus = fetchStatus;
+
done:
if (!locked)
lock_ReleaseRead(&scp->dirlock);
/* if we failed, cleanup any mess */
if (rc != 0) {
osi_Log0(afsd_logp, "cm_BPlusDirEnumerate rc != 0");
- if (enump) {
+
+ /* release the directory because we failed to generate an enumeration object */
+ cm_ReleaseSCache(scp);
+ cm_ReleaseUser(userp);
+ if (enump) {
for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
free(enump->entry[count].name);
}
}
long
-cm_BPlusDirEnumBulkStat(cm_scache_t *dscp, cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
+cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
{
+ cm_scache_t *dscp = enump->dscp;
+ cm_user_t *userp = enump->userp;
cm_bulkStat_t *bsp;
afs_uint32 count;
- afs_uint32 code;
+ afs_uint32 code = 0;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+ req.flags = enump->reqFlags;
if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
return 0;
bsp = malloc(sizeof(cm_bulkStat_t));
+ if (!bsp)
+ return ENOMEM;
memset(bsp, 0, sizeof(cm_bulkStat_t));
for ( count = 0; count < enump->count; count++ ) {
*/
lock_ReleaseWrite(&tscp->rw);
cm_ReleaseSCache(tscp);
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
continue;
}
lock_ReleaseWrite(&tscp->rw);
bsp->fids[i].Volume = enump->entry[count].fid.volume;
bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
bsp->fids[i].Unique = enump->entry[count].fid.unique;
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
if (bsp->counter == AFSCBMAX) {
- code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
memset(bsp, 0, sizeof(cm_bulkStat_t));
}
}
if (bsp->counter > 0)
- code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
free(bsp);
- return 0;
+ return code;
}
-long
+static long
+cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
+{
+ cm_scache_t *dscp = enump->dscp;
+ cm_user_t *userp = enump->userp;
+ cm_bulkStat_t *bsp;
+ afs_uint32 count;
+ afs_uint32 code = 0;
+ cm_req_t req;
+
+ cm_InitReq(&req);
+ req.flags = enump->reqFlags;
+
+ if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
+ return 0;
+
+ bsp = malloc(sizeof(cm_bulkStat_t));
+ if (!bsp)
+ return ENOMEM;
+ memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+ for ( count = enump->next; count < enump->count; count++ ) {
+ cm_scache_t *tscp = cm_FindSCache(&enump->entry[count].fid);
+ int i;
+
+ if (tscp) {
+ if (lock_TryWrite(&tscp->rw)) {
+ /* we have an entry that we can look at */
+ if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+ /* we have a callback on it. Don't bother
+ * fetching this stat entry, since we're happy
+ * with the info we have.
+ */
+ lock_ReleaseWrite(&tscp->rw);
+ cm_ReleaseSCache(tscp);
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+ continue;
+ }
+ lock_ReleaseWrite(&tscp->rw);
+ } /* got lock */
+ cm_ReleaseSCache(tscp);
+ } /* found entry */
+
+ i = bsp->counter++;
+ bsp->fids[i].Volume = enump->entry[count].fid.volume;
+ bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
+ bsp->fids[i].Unique = enump->entry[count].fid.unique;
+ enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+
+ if (bsp->counter == AFSCBMAX) {
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+ break;
+ }
+ }
+
+ if (bsp->counter > 0 && bsp->counter < AFSCBMAX)
+ code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+
+ free(bsp);
+ return code;
+}
+
+long
cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
{
- if (enump == NULL || entrypp == NULL || enump->next > enump->count) {
+ if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
if (entrypp)
*entrypp = NULL;
osi_Log0(afsd_logp, "cm_BPlusDirNextEnumEntry invalid input");
- return CM_ERROR_INVAL; \
+ return CM_ERROR_INVAL;
}
+ if (enump->fetchStatus &&
+ !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
+ cm_BPlusDirEnumBulkStatNext(enump);
+
*entrypp = &enump->entry[enump->next++];
if ( enump->next == enump->count ) {
osi_Log0(afsd_logp, "cm_BPlusDirNextEnumEntry STOPNOW");
}
}
+long
+cm_BPlusDirPeekNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
+{
+ if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
+ if (entrypp)
+ *entrypp = NULL;
+ osi_Log0(afsd_logp, "cm_BPlusDirPeekNextEnumEntry invalid input");
+ return CM_ERROR_INVAL;
+ }
+
+ if (enump->fetchStatus &&
+ !(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS))
+ cm_BPlusDirEnumBulkStatNext(enump);
+
+ *entrypp = &enump->entry[enump->next];
+ if ( enump->next == enump->count ) {
+ osi_Log0(afsd_logp, "cm_BPlusDirPeekNextEnumEntry STOPNOW");
+ return CM_ERROR_STOPNOW;
+ }
+ else {
+ osi_Log0(afsd_logp, "cm_BPlusDirPeekNextEnumEntry SUCCESS");
+ return 0;
+ }
+}
+
long
cm_BPlusDirFreeEnumeration(cm_direnum_t *enump)
{
osi_Log0(afsd_logp, "cm_BPlusDirFreeEnumeration");
if (enump) {
+ /* Release the directory object */
+ cm_ReleaseSCache(enump->dscp);
+ cm_ReleaseUser(enump->userp);
+
for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
free(enump->entry[count].name);
}
}
long
-cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked)
+cm_BPlusDirEnumTest(cm_scache_t * dscp, cm_user_t *userp, cm_req_t *reqp, afs_uint32 locked)
{
cm_direnum_t * enump = NULL;
cm_direnum_entry_t * entryp;
long code;
+
osi_Log0(afsd_logp, "cm_BPlusDirEnumTest start");
- for (code = cm_BPlusDirEnumerate(dscp, locked, NULL, &enump); code == 0; ) {
+ for (code = cm_BPlusDirEnumerate(dscp, userp, reqp, locked, NULL, 1, &enump); code == 0; ) {
code = cm_BPlusDirNextEnumEntry(enump, &entryp);
if (code == 0 || code == CM_ERROR_STOPNOW) {
char buffer[1024];