Windows: return ENOMEM from cm_BPlus functions on malloc failure
[openafs.git] / src / WINNT / afsd / cm_btree.c
index ec5c853..5002832 100644 (file)
@@ -1613,7 +1613,7 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *centry,
          */
         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;
         }
@@ -2160,18 +2160,21 @@ cm_BPlusEnumAlloc(afs_uint32 entries)
     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;
@@ -2191,6 +2194,7 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
      * 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");
@@ -2292,6 +2296,9 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
     }   
 
     enump->dscp = scp;
+    enump->userp = userp;
+    enump->reqFlags = reqp->flags;
+    enump->fetchStatus = fetchStatus;
 
   done:
     if (!locked)
@@ -2303,6 +2310,7 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
        
         /* 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);
@@ -2318,17 +2326,24 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
 }
 
 long 
-cm_BPlusDirEnumBulkStat(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++ ) {
@@ -2345,6 +2360,7 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
                      */
                     lock_ReleaseWrite(&tscp->rw);
                     cm_ReleaseSCache(tscp);
+                    enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
                     continue;
                 }
                 lock_ReleaseWrite(&tscp->rw);
@@ -2356,21 +2372,84 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
         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) {
@@ -2380,6 +2459,10 @@ cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
        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");
@@ -2391,6 +2474,31 @@ cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
     }
 }
 
+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)
 {
@@ -2401,6 +2509,7 @@ cm_BPlusDirFreeEnumeration(cm_direnum_t *enump)
     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);
@@ -2411,15 +2520,16 @@ cm_BPlusDirFreeEnumeration(cm_direnum_t *enump)
 }
 
 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];