Fixed 'real' vs. 'hole' mapping behaviour
authorshort <>
Tue, 21 Jan 2003 20:07:54 +0000 (20:07 +0000)
committershort <>
Tue, 21 Jan 2003 20:07:54 +0000 (20:07 +0000)
src/libcaptive/fs/mcb.c

index 7c1109f..62b5246 100644 (file)
@@ -29,8 +29,6 @@
 
 
 /* We use only real 'mapping' runs; we do not store 'holes' to our GTree.
- * Our first 'struct run' has RunIndex #0, the next 'struct run' RunIndex #2 etc.
- * The odd RunIndex values are computed from the neighbour 'struct run's.
  */
 struct run {
        LONGLONG Vbn_start;
@@ -82,6 +80,9 @@ static void run_destroy_func(struct run *run)
 {
        g_return_if_fail(run!=NULL);
 
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: run->Vbn_start=%lld,run->Vbn_end=%lld,run->Lbn_start=%lld",
+                       G_STRLOC,run->Vbn_start,run->Vbn_end,run->Lbn_start);
+
        g_free(run);
 }
 
@@ -189,7 +190,7 @@ struct run common_run;
  * %NULL value is forbidden.
  * @Vbn: Starting virtual block number to specify the range to delete.
  * @SectorCount: Length of the range to delete.
- * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
+ * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
  *
  * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
  * This call has no problems if no mappings exist there yet.
@@ -200,10 +201,12 @@ struct Mcb_priv *Mcb_priv;
 struct run needle_run,*haystack_run;
 
        g_return_if_fail(Mcb!=NULL);
+       g_return_if_fail(Vbn>=0);
        g_return_if_fail(SectorCount>0);
-       g_return_if_fail(Vbn+SectorCount>Vbn);
        /* FIXME: We are unable to delete the absolutely last sector G_MAXINT64 by this implementation! */
-       g_return_if_fail(Vbn+SectorCount+1>Vbn);
+       g_return_if_fail(Vbn+SectorCount>Vbn);
+
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Mcb=%p,Vbn=%lld,SectorCount=%lld",G_STRLOC,Mcb,Vbn,SectorCount);
 
        Mcb_hash_init();
        Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
@@ -238,7 +241,7 @@ struct run needle_run,*haystack_run;
  * @Vbn: Starting virtual block number of the wished range.
  * @Lbn: Starting logical block number of the wished range.
  * @SectorCount: Length of the wished range.
- * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
+ * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
  *
  * Adds the specified range @Vbn ... @Vbn+@SectorCount-1 to @Mcb.
  * Any mappings previously in this range are deleted first.
@@ -251,8 +254,11 @@ struct Mcb_priv *Mcb_priv;
 struct run *insert_run,current_run,needle_run,*lower_run,*higher_run;
 
        g_return_val_if_fail(Mcb!=NULL,FALSE);
+       g_return_val_if_fail(Vbn>=0,FALSE);
        g_return_val_if_fail(SectorCount>0,FALSE);
 
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Mcb=%p,Vbn=%lld,Lbn=%lld,SectorCount=%lld",G_STRLOC,Mcb,Vbn,Lbn,SectorCount);
+
        Mcb_hash_init();
        Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
        g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
@@ -292,10 +298,18 @@ struct run *insert_run,current_run,needle_run,*lower_run,*higher_run;
 }
 
 
+static const struct run static_run_below_0={
+               Vbn_start:-1,   /* ignored */
+               Vbn_end:   0,
+               Lbn_start:-1,   /* ignored */
+               };
+
+
 struct FsRtlGetNextLargeMcbEntry_input {
+       gboolean first;
        ULONG RunIndex_remaining;
-       struct run *run_found;
-       struct run *run_found_lower,*run_found_higher;
+       const struct run *run_found;
+       const struct run *run_found_lower,*run_found_higher;
        };
 
 static gboolean FsRtlGetNextLargeMcbEntry_traverse_func
@@ -306,6 +320,20 @@ static gboolean FsRtlGetNextLargeMcbEntry_traverse_func
        g_return_val_if_fail(run==run_value,TRUE);
        g_return_val_if_fail(input!=NULL,TRUE);
 
+       if (input->first) {
+               /* Take care when we must emulate missing 'hole' run at start of our run list. */
+               if (run->Vbn_start>0) {
+                       if (input->RunIndex_remaining==0) {
+                               input->run_found_lower=&static_run_below_0;
+                               input->run_found_higher=run;
+                               return TRUE;    /* stop the traversal */
+                               }
+                       /* If someone wants RunIndex #1 we are already on it. */
+                       input->RunIndex_remaining--;
+                       }
+               input->first=FALSE;
+               }
+
        if (input->RunIndex_remaining>0) {
                /* FIXME: performance: non-linear direct seek to the requested RunIndex */
                input->RunIndex_remaining--;
@@ -335,13 +363,13 @@ static gboolean FsRtlGetNextLargeMcbEntry_traverse_func
  * %NULL pointer is forbidden.
  * @SectorCount: Returns the length of the wished range.
  * %NULL pointer is forbidden.
- * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
+ * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
  *
  * Retrieves the parameters of the specified run with index @RunIndex.
- * First real mapping run is numbered by %0, the next real mapping run is numbered %2 etc.
- * Odd run numbers are reserved for the holes between; libcaptive does not store them to its #GTree
- * and their parameters are calculated automatically from the neighbour runs. Such 'hole' runs
- * will be returned with @Lbn value %-1.
+ * 
+ * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
+ * libcaptive does not store 'hole' information to its #GTree.
+ * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
  *
  * Returns: %TRUE if successful.
  */
@@ -360,6 +388,7 @@ struct FsRtlGetNextLargeMcbEntry_input input;
        Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
        g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
 
+       input.first=TRUE;
        input.RunIndex_remaining=RunIndex;
        input.run_found=NULL;
        input.run_found_lower=NULL;
@@ -367,7 +396,6 @@ struct FsRtlGetNextLargeMcbEntry_input input;
        g_tree_foreach(Mcb_priv->gtree,(GTraverseFunc)FsRtlGetNextLargeMcbEntry_traverse_func,&input);
 
        if (input.run_found) {
-               g_assert((RunIndex%2)==0);      /* search for mapping */
                g_assert(input.run_found_lower ==NULL);
                g_assert(input.run_found_higher==NULL);
                *Vbn        =input.run_found->Vbn_start;
@@ -377,7 +405,6 @@ struct FsRtlGetNextLargeMcbEntry_input input;
                }
 
        if (input.run_found_lower) {
-               g_assert((RunIndex%2)==1);      /* search for hole */
                g_assert(input.run_found_higher!=NULL);
                *Vbn        =input.run_found_lower->Vbn_end;
                *Lbn        =-1;
@@ -391,10 +418,11 @@ struct FsRtlGetNextLargeMcbEntry_input input;
 
 
 struct FsRtlLookupLargeMcbEntry_input {
+       gboolean first;
        LONGLONG Vbn;
        ULONG RunIndex;
-       struct run *run_found;
-       struct run *run_found_lower,*run_found_higher;
+       const struct run *run_found;
+       const struct run *run_found_lower,*run_found_higher;
        };
 
 static gboolean FsRtlLookupLargeMcbEntry_traverse_func
@@ -405,6 +433,15 @@ static gboolean FsRtlLookupLargeMcbEntry_traverse_func
        g_return_val_if_fail(run==run_value,TRUE);
        g_return_val_if_fail(input!=NULL,TRUE);
 
+       if (input->first) {
+               /* Take care when we must emulate missing 'hole' run at start of our run list. */
+               if (run->Vbn_start>0) {
+                       input->RunIndex+=1;
+                       input->run_found_lower=&static_run_below_0;
+                       }
+               input->first=FALSE;
+               }
+
        if (run->Vbn_start<=input->Vbn && input->Vbn<run->Vbn_end) {
                input->run_found=run;
                input->run_found_lower=NULL;
@@ -443,11 +480,11 @@ static gboolean FsRtlLookupLargeMcbEntry_traverse_func
  * %NULL value is permitted.
  *
  * Retrieves the information about the requested virtual block number @Vbn
- * and its mapping (either real mapping or the hole).
- * First real mapping run is numbered by %0, the next real mapping run is numbered %2 etc.
- * Odd run numbers are reserved for the holes between; libcaptive does not store them to its #GTree
- * and their parameters are calculated automatically from the neighbour runs. Such 'hole' runs
- * will be returned with @Lbn value %-1.
+ * and its mapping (either real 'mapping' or the 'hole').
+ * 
+ * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
+ * libcaptive does not store 'hole' information to its #GTree.
+ * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
  *
  * Returns: %TRUE if successful.
  */
@@ -462,11 +499,13 @@ struct Mcb_priv *Mcb_priv;
 struct FsRtlLookupLargeMcbEntry_input input;
 
        g_return_val_if_fail(Mcb!=NULL,FALSE);
+       g_return_val_if_fail(Vbn>=0,FALSE);
 
        Mcb_hash_init();
        Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
        g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
 
+       input.first=TRUE;
        input.Vbn=Vbn;
        input.RunIndex=0;
        input.run_found=NULL;
@@ -474,8 +513,7 @@ struct FsRtlLookupLargeMcbEntry_input input;
        input.run_found_higher=NULL;
        g_tree_foreach(Mcb_priv->gtree,(GTraverseFunc)FsRtlLookupLargeMcbEntry_traverse_func,&input);
 
-       if (input.run_found) {
-               g_assert((input.RunIndex%2)==0);        /* hit the mapping */
+       if (input.run_found) {  /* hit the mapping */
                g_assert(input.run_found_lower ==NULL);
                g_assert(input.run_found_higher==NULL);
                if (Lbn)
@@ -491,9 +529,8 @@ struct FsRtlLookupLargeMcbEntry_input input;
                return TRUE;
                }
 
-       if (input.run_found_lower) {
-               g_assert((input.RunIndex%2)==1);        /* search for hole */
-               g_assert(input.run_found_higher!=NULL);
+       if (input.run_found_higher) {   /* search for hole */
+               g_assert(input.run_found_lower!=NULL);
                if (Lbn)
                        *Lbn=-1;
                if (SectorCountFromLbn) /* FIXME: 'after' means including current 'Lbn' or without it? */
@@ -507,7 +544,7 @@ struct FsRtlLookupLargeMcbEntry_input input;
                return TRUE;
                }
 
-       g_assert(input.run_found_higher==NULL);
+       /* We may have some 'input.run_found_lower'. */
        return FALSE;
 }
 
@@ -516,7 +553,12 @@ static BOOLEAN FsRtlLookupLastLargeMcbEntryAndIndex_internal
                (IN PLARGE_MCB Mcb,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn,OUT PULONG Index OPTIONAL)
 {
 struct Mcb_priv *Mcb_priv;
-struct run needle_run,*found_run;
+const struct run needle_run_top={
+               Vbn_start:G_MAXINT64-1,
+               Vbn_end:G_MAXINT64,
+               Lbn_start:-1,   /* ignored*/
+               };
+const struct run *found_run;
 
        g_return_val_if_fail(Mcb!=NULL,FALSE);
        g_return_val_if_fail(Vbn!=NULL,FALSE);
@@ -526,12 +568,9 @@ struct run needle_run,*found_run;
        Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
        g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
 
-       needle_run.Vbn_start=G_MAXINT64-1;
-       needle_run.Vbn_end=G_MAXINT64;
-
        run_compare_func_last_a_run=NULL;
        run_compare_func_last_b_run=NULL;
-       found_run=g_tree_lookup(Mcb_priv->gtree,&needle_run);
+       found_run=g_tree_lookup(Mcb_priv->gtree,&needle_run_top);
        g_assert(found_run==NULL);
 
        if (run_compare_func_last_a_run==NULL) {
@@ -544,8 +583,8 @@ struct run needle_run,*found_run;
                        *Index=0;
                return FALSE;
                }
-       g_assert(run_compare_func_last_a_run!=&needle_run);
-       g_assert(run_compare_func_last_b_run==&needle_run);
+       g_assert(run_compare_func_last_a_run!=&needle_run_top);
+       g_assert(run_compare_func_last_b_run==&needle_run_top);
 
        *Vbn=run_compare_func_last_a_run->Vbn_end-1;
        *Lbn=run_compare_func_last_a_run->Lbn_start
@@ -555,7 +594,6 @@ ULONG runs=FsRtlNumberOfRunsInLargeMcb(Mcb);
 
                g_assert(runs>0);       /* There must be some runs if we found _something_. */
                *Index=runs-1;
-               g_assert((*Index%2)==0);        /* It must be 'real' run; libcaptive does not store 'holes'. */
                }
        return TRUE;
 }
@@ -624,15 +662,20 @@ BOOLEAN FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb,OUT PLONGLONG Vbn,OUT PLO
  * %NULL value is forbidden.
  *
  * Counts the number of runs mapped by @Mcb.
+ * 
+ * Mapping %0 always starts at virtual block %0, either as 'hole' or as 'real' mapping.
+ * libcaptive does not store 'hole' information to its #GTree.
+ * Last run is always a 'real' run. 'hole' runs appear as mapping to constant @Lbn value %-1.
  *
  * Returns: The sum of 'real' and 'hole' runs in @Mcb.
- * libcaptive stores only 'real' runs in its #GTree therefore it returns value 2*real_runs-1.
  * Returns value %0 if @Mcb is empty.
+ * Returns odd number iff the mapping has 'real' virtual block %0.
  */
 ULONG FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
 {
 struct Mcb_priv *Mcb_priv;
 gint nodes;
+LONGLONG Lbn_at_Vbn_0;
 
        g_return_val_if_fail(Mcb!=NULL,0);
 
@@ -641,10 +684,19 @@ gint nodes;
        g_return_val_if_fail(Mcb_priv!=NULL,0);
 
        nodes=g_tree_nnodes(Mcb_priv->gtree);
-
        if (!nodes)
                return 0;
-       return nodes*2-1;       /* include holes as 'runs' */
+
+       Lbn_at_Vbn_0=-1;
+       FsRtlLookupLargeMcbEntry(Mcb,
+                       0,      /* Vbn */
+                       &Lbn_at_Vbn_0,  /* Lbn */
+                       NULL,NULL,NULL,NULL);   /* 4 output arguments - not interested in them */
+
+       /* Return the number of 'real' and 'hole' runs.
+        * If we do not have sector 0 as 'real' emulate a 'hole' there.
+        */
+       return nodes*2 - (Lbn_at_Vbn_0!=-1 ? 1 : 0);    /* include holes as runs */
 }
 
 
@@ -702,7 +754,7 @@ struct run *lower_run;
  * %NULL value is forbidden.
  * @Vbn: First virtual block number of blocks to shift up.
  * @Amount: The amount of sectors to shift the blocks up by.
- * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
+ * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
  *
  * Takes the range of existing @Vbn..infinity 'real' block runs and shifts their
  * virtual block numbers up by @Amount. Any possible 'real' run crossed by @Vbn
@@ -720,8 +772,11 @@ struct Mcb_priv *Mcb_priv;
 struct FsRtlSplitLargeMcb_input input;
 
        g_return_val_if_fail(Mcb!=NULL,FALSE);
+       g_return_val_if_fail(Vbn>=0,FALSE);
        g_return_val_if_fail(Amount>0,FALSE);
 
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Mcb=%p,Vbn=%lld,Amount=%lld",G_STRLOC,Mcb,Vbn,Amount);
+
        Mcb_hash_init();
        Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
        g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
@@ -751,6 +806,9 @@ struct FsRtlSplitLargeMcb_input input;
 VOID FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,IN LONGLONG Vbn)
 {
        g_return_if_fail(Mcb!=NULL);
+       g_return_if_fail(Vbn>=0);
+
+       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Mcb=%p,Vbn=%lld",G_STRLOC,Mcb,Vbn);
 
        FsRtlRemoveLargeMcbEntry(Mcb,Vbn,G_MAXINT64-Vbn+1);
 }