/* 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;
{
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);
}
* %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.
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);
* @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.
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);
}
+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
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--;
* %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.
*/
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;
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;
}
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;
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
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;
* %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.
*/
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;
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)
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? */
return TRUE;
}
- g_assert(input.run_found_higher==NULL);
+ /* We may have some 'input.run_found_lower'. */
return FALSE;
}
(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);
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) {
*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
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;
}
* %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);
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 */
}
* %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
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);
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);
}