2 * reactos MCB (map control block) functions emulation of libcaptive
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "reactos/ddk/fsfuncs.h" /* self */
23 #include <glib/gmessages.h>
24 #include "reactos/ntos/types.h" /* for VOID */
25 #include <glib/gtree.h>
26 #include <glib/ghash.h>
27 #include "reactos/ddk/exfuncs.h" /* for ExInitializeFastMutex() */
28 #include "captive/macros.h"
31 /* We use only real 'mapping' runs; we do not store 'holes' to our GTree.
32 * Our first 'struct run' has RunIndex #0, the next 'struct run' RunIndex #2 etc.
33 * The odd RunIndex values are computed from the neighbour 'struct run's.
37 LONGLONG Vbn_end; /* Vbn_start+SectorCount; that means +1 after the last sector */
38 LONGLONG Lbn_start; /* Lbn of 'Vbn_start' */
42 GTree *gtree; /* map (struct run *)->(struct run *) */
45 static const struct run *run_compare_func_last_a_run;
46 static const struct run *run_compare_func_last_b_run;
47 static const struct run *run_compare_func_minus_a_run; /* last run where we returned -1 */
48 static const struct run *run_compare_func_minus_b_run;
49 static const struct run *run_compare_func_plus_a_run; /* last run where we returned +1 */
50 static const struct run *run_compare_func_plus_b_run;
52 static gint run_compare_func(const struct run *a_run,const struct run *b_run,gpointer user_data /* unused */)
56 g_return_val_if_fail(a_run!=NULL,0);
57 g_return_val_if_fail(a_run->Vbn_end>a_run->Vbn_start,0);
58 g_return_val_if_fail(b_run!=NULL,0);
59 g_return_val_if_fail(b_run->Vbn_end>b_run->Vbn_start,0);
61 run_compare_func_last_a_run=a_run;
62 run_compare_func_last_b_run=b_run;
65 && !(r=(a_run->Vbn_start>b_run->Vbn_start)-(a_run->Vbn_start<b_run->Vbn_start))
66 && !(r=(a_run->Vbn_end >b_run->Vbn_end )-(a_run->Vbn_end <b_run->Vbn_end )))
70 run_compare_func_minus_a_run=a_run;
71 run_compare_func_minus_b_run=b_run;
74 run_compare_func_plus_a_run=a_run;
75 run_compare_func_plus_b_run=b_run;
81 static void run_destroy_func(struct run *run)
83 g_return_if_fail(run!=NULL);
88 /* map (LARGE_MCB *)->(struct Mcb_priv *) */
89 static GHashTable *Mcb_hash;
91 static void Mcb_hash_init(void)
95 Mcb_hash=g_hash_table_new(
96 g_direct_hash, /* key_compare_func */
97 g_direct_equal); /* key_compare_data */
102 * FsRtlInitializeLargeMcb:
103 * @Mcb: Allocated memory to be initialized as #PLARGE_MCB.
104 * %NULL value is forbidden.
105 * @PoolType: Memory type to use for the items. Ignored by libcaptive.
107 * You must use this function to be able to pass @Mcb to any other
108 * FsRtl*LargeMcb*() function.
110 VOID FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb,IN POOL_TYPE PoolType)
112 struct Mcb_priv *Mcb_priv;
114 g_return_if_fail(Mcb!=NULL);
117 g_return_if_fail(NULL==g_hash_table_lookup(Mcb_hash,Mcb));
119 ExInitializeFastMutex(&Mcb->FastMutex);
120 Mcb->MaximumPairCount=0;
122 Mcb->PoolType=PoolType;
125 captive_new(Mcb_priv);
126 Mcb_priv->gtree=g_tree_new_full(
127 (GCompareDataFunc)run_compare_func, /* key_compare_func */
128 NULL, /* key_compare_data */
129 (GDestroyNotify)run_destroy_func, /* key_destroy_func */
130 NULL); /* value_destroy_func */
132 g_hash_table_insert(Mcb_hash,
134 Mcb_priv); /* value */
139 * FsRtlUninitializeLargeMcb:
140 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
141 * %NULL value is forbidden.
143 * Frees all the resources associated with @Mcb.
144 * You must not pass this pointer to any FsRtl*LargeMcb*() function afterwards.
146 VOID FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
148 struct Mcb_priv *Mcb_priv;
151 g_return_if_fail(Mcb!=NULL);
154 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
155 g_return_if_fail(Mcb_priv!=NULL);
157 errbool=g_hash_table_remove(Mcb_hash,Mcb);
158 g_assert(errbool==TRUE);
159 g_tree_destroy(Mcb_priv->gtree);
164 static gint run_intersect_compare_func(const struct run *haystack_run,const struct run *needle_run)
167 struct run common_run;
169 g_return_val_if_fail(haystack_run!=NULL,0);
170 g_return_val_if_fail(haystack_run->Vbn_end>haystack_run->Vbn_start,0);
171 g_return_val_if_fail(needle_run!=NULL,0);
172 g_return_val_if_fail(needle_run->Vbn_end>needle_run->Vbn_start,0);
174 common_run.Vbn_start=MAX(haystack_run->Vbn_start,needle_run->Vbn_start);
175 common_run.Vbn_end =MIN(haystack_run->Vbn_end ,needle_run->Vbn_end );
177 if (common_run.Vbn_end>common_run.Vbn_start)
179 r=run_compare_func(needle_run,haystack_run,
180 NULL); /* user_data; unused */
181 g_assert(r!=0); /* otherwise we would hit it by 'common_run' */
187 * FsRtlRemoveLargeMcbEntry:
188 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
189 * %NULL value is forbidden.
190 * @Vbn: Starting virtual block number to specify the range to delete.
191 * @SectorCount: Length of the range to delete.
192 * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
194 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
195 * This call has no problems if no mappings exist there yet.
197 VOID FsRtlRemoveLargeMcbEntry(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG SectorCount)
199 struct Mcb_priv *Mcb_priv;
200 struct run needle_run,*haystack_run;
202 g_return_if_fail(Mcb!=NULL);
203 g_return_if_fail(SectorCount>0);
204 g_return_if_fail(Vbn+SectorCount>Vbn);
205 /* FIXME: We are unable to delete the absolutely last sector G_MAXINT64 by this implementation! */
206 g_return_if_fail(Vbn+SectorCount+1>Vbn);
209 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
210 g_return_if_fail(Mcb_priv!=NULL);
212 needle_run.Vbn_start=Vbn;
213 needle_run.Vbn_end=Vbn+SectorCount;
215 /* adjust/destroy all intersecting ranges */
216 while ((haystack_run=g_tree_search(Mcb_priv->gtree,(GCompareFunc)run_intersect_compare_func,&needle_run))) {
217 /**/ if (haystack_run->Vbn_start<needle_run.Vbn_start) {
218 g_assert(haystack_run->Vbn_end >needle_run.Vbn_start);
219 haystack_run->Vbn_end =needle_run.Vbn_start;
221 else if (haystack_run->Vbn_end >needle_run.Vbn_end ) {
222 g_assert(haystack_run->Vbn_start<needle_run.Vbn_end );
223 haystack_run->Vbn_start=needle_run.Vbn_end;
226 g_assert(needle_run.Vbn_start>=haystack_run->Vbn_start);
227 g_assert(needle_run.Vbn_end <=haystack_run->Vbn_end );
228 g_tree_remove(Mcb_priv->gtree,haystack_run);
235 * FsRtlAddLargeMcbEntry:
236 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
237 * %NULL value is forbidden.
238 * @Vbn: Starting virtual block number of the wished range.
239 * @Lbn: Starting logical block number of the wished range.
240 * @SectorCount: Length of the wished range.
241 * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
243 * Adds the specified range @Vbn ... @Vbn+@SectorCount-1 to @Mcb.
244 * Any mappings previously in this range are deleted first.
246 * Returns: %TRUE if successful.
248 BOOLEAN FsRtlAddLargeMcbEntry(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG Lbn,IN LONGLONG SectorCount)
250 struct Mcb_priv *Mcb_priv;
251 struct run *insert_run,current_run,needle_run,*lower_run,*higher_run;
253 g_return_val_if_fail(Mcb!=NULL,FALSE);
254 g_return_val_if_fail(SectorCount>0,FALSE);
257 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
258 g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
260 /* clean any possible previous entries in our range */
261 FsRtlRemoveLargeMcbEntry(Mcb,Vbn,SectorCount);
263 /* initially we think we will be inserted as a separate run */
264 current_run.Vbn_start=Vbn;
265 current_run.Vbn_end =Vbn+SectorCount;
266 current_run.Lbn_start=Lbn;
268 /* optionally merge with lower run */
269 needle_run.Vbn_start=current_run.Vbn_start-1;
270 needle_run.Vbn_end =needle_run.Vbn_start+1;
271 if ((lower_run=g_tree_search(Mcb_priv->gtree,(GCompareFunc)run_intersect_compare_func,&needle_run))) {
272 g_assert(lower_run->Vbn_end==current_run.Vbn_start);
273 current_run.Vbn_start=lower_run->Vbn_start;
274 g_tree_remove(Mcb_priv->gtree,lower_run);
277 /* optionally merge with higher run */
278 needle_run.Vbn_start=current_run.Vbn_end;
279 needle_run.Vbn_end =needle_run.Vbn_start+1;
280 if ((higher_run=g_tree_search(Mcb_priv->gtree,(GCompareFunc)run_intersect_compare_func,&needle_run))) {
281 g_assert(higher_run->Vbn_start==current_run.Vbn_end);
282 current_run.Vbn_end=higher_run->Vbn_end;
283 g_tree_remove(Mcb_priv->gtree,higher_run);
286 /* finally insert the resulting run */
287 captive_new(insert_run);
288 *insert_run=current_run;
289 g_tree_insert(Mcb_priv->gtree,insert_run,insert_run);
291 return TRUE; /* success */
295 struct FsRtlGetNextLargeMcbEntry_input {
296 ULONG RunIndex_remaining;
297 struct run *run_found;
298 struct run *run_found_lower,*run_found_higher;
301 static gboolean FsRtlGetNextLargeMcbEntry_traverse_func
302 (struct run *run /* _key */,struct run *run_value,struct FsRtlGetNextLargeMcbEntry_input *input)
304 g_return_val_if_fail(run!=NULL,TRUE);
305 g_return_val_if_fail(run_value!=NULL,TRUE);
306 g_return_val_if_fail(run==run_value,TRUE);
307 g_return_val_if_fail(input!=NULL,TRUE);
309 if (input->RunIndex_remaining>0) {
310 /* FIXME: performance: non-linear direct seek to the requested RunIndex */
311 input->RunIndex_remaining--;
312 if (input->RunIndex_remaining==0)
313 input->run_found_lower=run;
315 input->RunIndex_remaining--;
316 return FALSE; /* continue the traversal */
319 if (input->run_found_lower)
320 input->run_found_higher=run;
322 input->run_found=run;
323 return TRUE; /* stop the traversal */
328 * FsRtlGetNextLargeMcbEntry:
329 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
330 * %NULL value is forbidden.
331 * @RunIndex: Requested range index to retrieve.
332 * @Vbn: Returns the starting virtual block number of the wished range.
333 * %NULL pointer is forbidden.
334 * @Lbn: Returns the starting logical block number of the wished range (or -1 if it is a hole).
335 * %NULL pointer is forbidden.
336 * @SectorCount: Returns the length of the wished range.
337 * %NULL pointer is forbidden.
338 * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
340 * Retrieves the parameters of the specified run with index @RunIndex.
341 * First real mapping run is numbered by %0, the next real mapping run is numbered %2 etc.
342 * Odd run numbers are reserved for the holes between; libcaptive does not store them to its #GTree
343 * and their parameters are calculated automatically from the neighbour runs. Such 'hole' runs
344 * will be returned with @Lbn value %-1.
346 * Returns: %TRUE if successful.
348 BOOLEAN FsRtlGetNextLargeMcbEntry
349 (IN PLARGE_MCB Mcb,IN ULONG RunIndex,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn,OUT PLONGLONG SectorCount)
351 struct Mcb_priv *Mcb_priv;
352 struct FsRtlGetNextLargeMcbEntry_input input;
354 g_return_val_if_fail(Mcb!=NULL,FALSE);
355 g_return_val_if_fail(Vbn!=NULL,FALSE);
356 g_return_val_if_fail(Lbn!=NULL,FALSE);
357 g_return_val_if_fail(SectorCount!=NULL,FALSE);
360 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
361 g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
363 input.RunIndex_remaining=RunIndex;
364 input.run_found=NULL;
365 input.run_found_lower=NULL;
366 input.run_found_higher=NULL;
367 g_tree_foreach(Mcb_priv->gtree,(GTraverseFunc)FsRtlGetNextLargeMcbEntry_traverse_func,&input);
369 if (input.run_found) {
370 g_assert((RunIndex%2)==0); /* search for mapping */
371 g_assert(input.run_found_lower ==NULL);
372 g_assert(input.run_found_higher==NULL);
373 *Vbn =input.run_found->Vbn_start;
374 *Lbn =input.run_found->Lbn_start;
375 *SectorCount=input.run_found->Vbn_end-input.run_found->Vbn_start;
379 if (input.run_found_lower) {
380 g_assert((RunIndex%2)==1); /* search for hole */
381 g_assert(input.run_found_higher!=NULL);
382 *Vbn =input.run_found_lower->Vbn_end;
384 *SectorCount=input.run_found_higher->Vbn_start-input.run_found_lower->Vbn_end;
388 g_assert(input.run_found_higher==NULL);
393 struct FsRtlLookupLargeMcbEntry_input {
396 struct run *run_found;
397 struct run *run_found_lower,*run_found_higher;
400 static gboolean FsRtlLookupLargeMcbEntry_traverse_func
401 (struct run *run /* _key */,struct run *run_value,struct FsRtlLookupLargeMcbEntry_input *input)
403 g_return_val_if_fail(run!=NULL,TRUE);
404 g_return_val_if_fail(run_value!=NULL,TRUE);
405 g_return_val_if_fail(run==run_value,TRUE);
406 g_return_val_if_fail(input!=NULL,TRUE);
408 if (run->Vbn_start<=input->Vbn && input->Vbn<run->Vbn_end) {
409 input->run_found=run;
410 input->run_found_lower=NULL;
411 return TRUE; /* stop the traversal; hit */
413 if (run->Vbn_end<=input->Vbn) {
414 input->run_found_lower=run;
416 return FALSE; /* continue the traversal; not yet crossed by the run */
418 if (input->Vbn<run->Vbn_start) {
419 input->run_found_higher=run;
421 return TRUE; /* stop the traversal; the run skipped us */
423 g_assert_not_reached();
424 return TRUE; /* stop the traversal */
429 * FsRtlLookupLargeMcbEntry:
430 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
431 * %NULL value is forbidden.
432 * @Vbn: Starting virtual block number of the requested sector.
433 * @Lbn: Returns the logical block number corresponding to @Vbn (or -1 if it is a hole).
434 * %NULL value is permitted.
435 * @SectorCountFromLbn: Returns the number of sectors after @Vbn in the mapping found.
436 * FIXME: 'after' means including current 'Lbn' or without it?
437 * %NULL value is permitted.
438 * @StartingLbn: Returns the first logical block number of the mapping found (or -1 if it is a hole).
439 * %NULL value is permitted.
440 * @SectorCountFromStartingLbn: Returns total length in blocks of the mapping found.
441 * %NULL value is permitted.
442 * @Index: Returns the range index of the mapping found.
443 * %NULL value is permitted.
445 * Retrieves the information about the requested virtual block number @Vbn
446 * and its mapping (either real mapping or the hole).
447 * First real mapping run is numbered by %0, the next real mapping run is numbered %2 etc.
448 * Odd run numbers are reserved for the holes between; libcaptive does not store them to its #GTree
449 * and their parameters are calculated automatically from the neighbour runs. Such 'hole' runs
450 * will be returned with @Lbn value %-1.
452 * Returns: %TRUE if successful.
454 BOOLEAN FsRtlLookupLargeMcbEntry(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,
455 OUT PLONGLONG Lbn OPTIONAL,
456 OUT PLONGLONG SectorCountFromLbn OPTIONAL,
457 OUT PLONGLONG StartingLbn OPTIONAL,
458 OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
459 OUT PULONG Index OPTIONAL)
461 struct Mcb_priv *Mcb_priv;
462 struct FsRtlLookupLargeMcbEntry_input input;
464 g_return_val_if_fail(Mcb!=NULL,FALSE);
467 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
468 g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
472 input.run_found=NULL;
473 input.run_found_lower=NULL;
474 input.run_found_higher=NULL;
475 g_tree_foreach(Mcb_priv->gtree,(GTraverseFunc)FsRtlLookupLargeMcbEntry_traverse_func,&input);
477 if (input.run_found) {
478 g_assert((input.RunIndex%2)==0); /* hit the mapping */
479 g_assert(input.run_found_lower ==NULL);
480 g_assert(input.run_found_higher==NULL);
482 *Lbn=input.run_found->Lbn_start+(Vbn-input.run_found->Vbn_start);
483 if (SectorCountFromLbn) /* FIXME: 'after' means including current 'Lbn' or without it? */
484 *SectorCountFromLbn=input.run_found->Vbn_end-Vbn;
486 *StartingLbn=input.run_found->Lbn_start;
487 if (SectorCountFromStartingLbn)
488 *SectorCountFromStartingLbn=input.run_found->Vbn_end-input.run_found->Vbn_start;
490 *Index=input.RunIndex;
494 if (input.run_found_lower) {
495 g_assert((input.RunIndex%2)==1); /* search for hole */
496 g_assert(input.run_found_higher!=NULL);
499 if (SectorCountFromLbn) /* FIXME: 'after' means including current 'Lbn' or without it? */
500 *SectorCountFromLbn=input.run_found_higher->Vbn_start-Vbn;
503 if (SectorCountFromStartingLbn)
504 *SectorCountFromStartingLbn=input.run_found_higher->Vbn_start-input.run_found_lower->Vbn_end;
506 *Index=input.RunIndex;
510 g_assert(input.run_found_higher==NULL);
516 * FsRtlLookupLastLargeMcbEntry:
517 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
518 * %NULL value is forbidden.
519 * @Vbn: Returns the virtual block number of the last mapped sector.
520 * %NULL pointer is forbidden.
521 * @Lbn: Returns the logical block number of the last mapped sector.
522 * %NULL pointer is forbidden.
524 * Retrieves the mapping of the ever last sector mapped by @Mcb.
525 * FIXME: W32 doc says the returned @Lbn may get value %-1 but such 'hole' is not
526 * a real mapping - why not to return the previous real mapping instead?
527 * How can be some trailing 'hole's present?
529 * Returns: %TRUE if successful. %FALSE if @Mcb is empty.
531 BOOLEAN FsRtlLookupLastLargeMcbEntry(IN PLARGE_MCB Mcb,OUT PLONGLONG Vbn,OUT PLONGLONG Lbn)
533 struct Mcb_priv *Mcb_priv;
534 struct run needle_run,*found_run;
536 g_return_val_if_fail(Mcb!=NULL,FALSE);
537 g_return_val_if_fail(Vbn!=NULL,FALSE);
538 g_return_val_if_fail(Lbn!=NULL,FALSE);
541 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
542 g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
544 needle_run.Vbn_start=G_MAXINT64-1;
545 needle_run.Vbn_end=G_MAXINT64;
547 run_compare_func_last_a_run=NULL;
548 run_compare_func_last_b_run=NULL;
549 found_run=g_tree_lookup(Mcb_priv->gtree,&needle_run);
550 g_assert(found_run==NULL);
552 if (run_compare_func_last_a_run==NULL) {
553 g_assert(run_compare_func_last_b_run==NULL);
554 g_assert(g_tree_nnodes(Mcb_priv->gtree)==0);
560 g_assert(run_compare_func_last_a_run!=&needle_run);
561 g_assert(run_compare_func_last_b_run==&needle_run);
563 *Vbn=run_compare_func_last_a_run->Vbn_end-1;
564 *Lbn=run_compare_func_last_a_run->Lbn_start
565 +((run_compare_func_last_a_run->Vbn_end-1)-run_compare_func_last_a_run->Vbn_start);
571 * FsRtlNumberOfRunsInLargeMcb:
572 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
573 * %NULL value is forbidden.
575 * Counts the number of runs mapped by @Mcb.
577 * Returns: The sum of 'real' and 'hole' runs in @Mcb.
578 * libcaptive stores only 'real' runs in its #GTree therefore it returns value 2*real_runs-1.
579 * Returns value %0 if @Mcb is empty.
581 ULONG FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
583 struct Mcb_priv *Mcb_priv;
586 g_return_val_if_fail(Mcb!=NULL,0);
589 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
590 g_return_val_if_fail(Mcb_priv!=NULL,0);
592 nodes=g_tree_nnodes(Mcb_priv->gtree);
596 return nodes*2-1; /* include holes as 'runs' */
600 struct FsRtlSplitLargeMcb_input {
603 struct Mcb_priv *Mcb_priv;
604 struct run *insert_lower_run; /* 'run' to insert after g_tree_foreach() finishes */
607 static gboolean FsRtlSplitLargeMcb_traverse_func
608 (struct run *run /* _key */,struct run *run_value,struct FsRtlSplitLargeMcb_input *input)
610 g_return_val_if_fail(run!=NULL,TRUE);
611 g_return_val_if_fail(run_value!=NULL,TRUE);
612 g_return_val_if_fail(run==run_value,TRUE);
613 g_return_val_if_fail(input!=NULL,TRUE);
615 /* unaffected run? */
616 /* FIXME: performance: effective skip of all 'lower' runs without traversing them */
617 if (input->Vbn>=run->Vbn_end)
618 return FALSE; /* continue the traversal */
620 /* crossing run to be split?
621 * 'lower_run' is created on the original place; just shortened.
622 * current 'run' is shifted up later
624 if (input->Vbn<run->Vbn_end) {
625 struct run *lower_run;
627 captive_new(lower_run);
629 lower_run->Vbn_end=input->Vbn;
630 /* FIXME: shift 'run->Lbn_start' ? */
631 run->Vbn_start=input->Vbn;
633 input->insert_lower_run=lower_run;
636 /* Shift the current 'run'.
637 * Ordering is not changed in GTree so I hope I do not need to reinsert it.
639 run->Vbn_start+=input->Amount;
640 g_assert(run->Vbn_end+input->Amount>run->Vbn_end); /* overflow? */
641 run->Vbn_end+=input->Amount;
642 /* FIXME: shift 'run->Lbn_start' ? */
644 return FALSE; /* continue the traversal */
649 * FsRtlSplitLargeMcb:
650 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
651 * %NULL value is forbidden.
652 * @Vbn: First virtual block number of blocks to shift up.
653 * @Amount: The amount of sectors to shift the blocks up by.
654 * Value less or equal to %0 is forbidden; FIXME: Is it W32 compliant?
656 * Takes the range of existing @Vbn..infinity 'real' block runs and shifts their
657 * virtual block numbers up by @Amount. Any possible 'real' run crossed by @Vbn
658 * threshold value gets split with the 'hole' of size @Amount blocks.
660 * FIXME: W32 doc does not say if logical block number should be also shifted.
661 * libcaptive does not touch logical block numbers.
663 * Returns: %TRUE if we crossed some 'real' run and we needed to create new 'hole'.
664 * We still may map a lot of 'real' runs and return %FALSE if no such run will be hit by @Vbn directly.
666 BOOLEAN FsRtlSplitLargeMcb(IN PLARGE_MCB Mcb,IN LONGLONG Vbn,IN LONGLONG Amount)
668 struct Mcb_priv *Mcb_priv;
669 struct FsRtlSplitLargeMcb_input input;
671 g_return_val_if_fail(Mcb!=NULL,FALSE);
672 g_return_val_if_fail(Amount>0,FALSE);
675 Mcb_priv=g_hash_table_lookup(Mcb_hash,Mcb);
676 g_return_val_if_fail(Mcb_priv!=NULL,FALSE);
680 input.insert_lower_run=NULL;
681 input.Mcb_priv=Mcb_priv;
682 g_tree_foreach(Mcb_priv->gtree,(GTraverseFunc)FsRtlSplitLargeMcb_traverse_func,&input);
684 if (input.insert_lower_run)
685 g_tree_insert(input.Mcb_priv->gtree,input.insert_lower_run,input.insert_lower_run);
687 return (input.insert_lower_run!=NULL); /* the hole was successfuly created? */
692 * FsRtlTruncateLargeMcb:
693 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
694 * %NULL value is forbidden.
695 * @Vbn: First virtual block number of blocks to delete.
697 * Deletes the mapping from @Vbn upwards. If no such blocks exist this function
700 VOID FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,IN LONGLONG Vbn)
702 g_return_if_fail(Mcb!=NULL);
704 FsRtlRemoveLargeMcbEntry(Mcb,Vbn,G_MAXINT64-Vbn+1);