1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             generic.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 #include "linux/ext4.h"
14 
15 /* GLOBALS ***************************************************************/
16 
17 extern PEXT2_GLOBAL Ext2Global;
18 
19 /* DEFINITIONS *************************************************************/
20 
21 
22 /* FUNCTIONS ***************************************************************/
23 
24 NTSTATUS
25 Ext2LoadSuper(IN PEXT2_VCB      Vcb,
26               IN BOOLEAN        bVerify,
27               OUT PEXT2_SUPER_BLOCK * Sb)
28 {
29     NTSTATUS          Status;
30     PEXT2_SUPER_BLOCK Ext2Sb = NULL;
31 
32     Ext2Sb = (PEXT2_SUPER_BLOCK)
33              Ext2AllocatePool(
34                  PagedPool,
35                  SUPER_BLOCK_SIZE,
36                  EXT2_SB_MAGIC
37              );
38     if (!Ext2Sb) {
39         Status = STATUS_INSUFFICIENT_RESOURCES;
40         goto errorout;
41     }
42 
43     Status = Ext2ReadDisk(
44                  Vcb,
45                  (ULONGLONG) SUPER_BLOCK_OFFSET,
46                  SUPER_BLOCK_SIZE,
47                  (PVOID) Ext2Sb,
48                  bVerify );
49 
50     if (!NT_SUCCESS(Status)) {
51         Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
52         Ext2Sb = NULL;
53     }
54 
55 errorout:
56 
57     *Sb = Ext2Sb;
58     return Status;
59 }
60 
61 
62 BOOLEAN
63 Ext2SaveSuper(
64     IN PEXT2_IRP_CONTEXT    IrpContext,
65     IN PEXT2_VCB            Vcb
66 )
67 {
68     LONGLONG    offset;
69     BOOLEAN     rc;
70 
71     offset = (LONGLONG) SUPER_BLOCK_OFFSET;
72     rc = Ext2SaveBuffer( IrpContext,
73                          Vcb,
74                          offset,
75                          SUPER_BLOCK_SIZE,
76                          Vcb->SuperBlock
77                        );
78 
79     if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
80         Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
81     }
82 
83     return rc;
84 }
85 
86 
87 BOOLEAN
88 Ext2RefreshSuper (
89     IN PEXT2_IRP_CONTEXT    IrpContext,
90     IN PEXT2_VCB            Vcb
91 )
92 {
93     LONGLONG        offset;
94     IO_STATUS_BLOCK iosb;
95 
96     offset = (LONGLONG) SUPER_BLOCK_OFFSET;
97     if (!CcCopyRead(
98                 Vcb->Volume,
99                 (PLARGE_INTEGER)&offset,
100                 SUPER_BLOCK_SIZE,
101                 TRUE,
102                 (PVOID)Vcb->SuperBlock,
103                 &iosb )) {
104         return FALSE;
105     }
106 
107     if (!NT_SUCCESS(iosb.Status)) {
108         return FALSE;
109     }
110 
111     /* reload root inode */
112     if (Vcb->McbTree) {
113 
114         if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode))
115             return FALSE;
116 
117         /* initializeroot node */
118         Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
119         Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
120         Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
121         Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
122     }
123 
124     return TRUE;
125 }
126 
127 VOID
128 Ext2DropGroupBH(IN PEXT2_VCB Vcb)
129 {
130     struct ext3_sb_info *sbi = &Vcb->sbi;
131     unsigned long i;
132 
133     if (NULL == Vcb->sbi.s_gd) {
134         return;
135     }
136 
137     for (i = 0; i < Vcb->sbi.s_gdb_count; i++) {
138         if (Vcb->sbi.s_gd[i].bh) {
139             fini_bh(&sbi->s_gd[i].bh);
140             Vcb->sbi.s_gd[i].bh = NULL;
141         }
142     }
143 }
144 
145 VOID
146 Ext2PutGroup(IN PEXT2_VCB Vcb)
147 {
148     struct ext3_sb_info *sbi = &Vcb->sbi;
149     unsigned long i;
150 
151 
152     if (NULL == Vcb->sbi.s_gd) {
153         return;
154     }
155 
156     Ext2DropGroupBH(Vcb);
157 
158     kfree(Vcb->sbi.s_gd);
159     Vcb->sbi.s_gd = NULL;
160 
161     ClearFlag(Vcb->Flags, VCB_GD_LOADED);
162 }
163 
164 
165 BOOLEAN
166 Ext2LoadGroupBH(IN PEXT2_VCB Vcb)
167 {
168     struct super_block  *sb = &Vcb->sb;
169     struct ext3_sb_info *sbi = &Vcb->sbi;
170     unsigned long i;
171     BOOLEAN rc = FALSE;
172 
173     _SEH2_TRY {
174 
175         ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
176         ASSERT (NULL != sbi->s_gd);
177 
178         for (i = 0; i < sbi->s_gdb_count; i++) {
179             ASSERT (sbi->s_gd[i].block);
180             if (sbi->s_gd[i].bh)
181                 continue;
182             sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
183             if (!sbi->s_gd[i].bh) {
184                 DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i));
185                 DbgBreak();
186                 _SEH2_LEAVE;
187             }
188             sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
189         }
190 
191         rc = TRUE;
192 
193     } _SEH2_FINALLY {
194 
195         ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
196     } _SEH2_END;
197 
198     return rc;
199 }
200 
201 
202 BOOLEAN
203 Ext2LoadGroup(IN PEXT2_VCB Vcb)
204 {
205     struct super_block  *sb = &Vcb->sb;
206     struct ext3_sb_info *sbi = &Vcb->sbi;
207     ext3_fsblk_t sb_block = 1;
208     unsigned long i;
209     BOOLEAN rc = FALSE;
210 
211     _SEH2_TRY {
212 
213         ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
214 
215         if (NULL == sbi->s_gd) {
216             sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd),
217                                         GFP_KERNEL);
218         }
219         if (sbi->s_gd == NULL) {
220             DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
221             _SEH2_LEAVE;
222         }
223 
224         if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
225             sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
226         }
227 
228         for (i = 0; i < sbi->s_gdb_count; i++) {
229             sbi->s_gd[i].block =  descriptor_loc(sb, sb_block, i);
230             if (!sbi->s_gd[i].block) {
231                 DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i));
232                 _SEH2_LEAVE;
233             }
234         }
235 
236         if (!Ext2LoadGroupBH(Vcb)) {
237             DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n"));
238             _SEH2_LEAVE;
239         }
240 
241         if (!ext4_check_descriptors(sb)) {
242             DbgBreak();
243             DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n"));
244             _SEH2_LEAVE;
245         }
246 
247         SetFlag(Vcb->Flags, VCB_GD_LOADED);
248         rc = TRUE;
249 
250     } _SEH2_FINALLY {
251 
252         if (!rc)
253             Ext2PutGroup(Vcb);
254 
255         ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
256     } _SEH2_END;
257 
258     return rc;
259 }
260 
261 VOID
262 Ext2DropBH(IN PEXT2_VCB Vcb)
263 {
264     struct ext3_sb_info *sbi = &Vcb->sbi;
265 
266     /* do nothing if Vcb is not initialized yet */
267     if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
268         return;
269 
270     _SEH2_TRY {
271 
272         /* acquire bd lock to avoid bh creation */
273         ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
274 
275         SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
276         Ext2DropGroupBH(Vcb);
277 
278         while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
279             struct buffer_head *bh;
280             PLIST_ENTRY         l;
281             l = RemoveHeadList(&Vcb->bd.bd_bh_free);
282             bh = CONTAINING_RECORD(l, struct buffer_head, b_link);
283             InitializeListHead(&bh->b_link);
284             if (0 == atomic_read(&bh->b_count)) {
285                 buffer_head_remove(&Vcb->bd, bh);
286                 free_buffer_head(bh);
287             }
288         }
289 
290     } _SEH2_FINALLY {
291         ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
292     } _SEH2_END;
293 
294     ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
295 }
296 
297 
298 VOID
299 Ext2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e)
300 {
301     ULONG len;
302 
303     if (e.QuadPart <= s.QuadPart)
304         return;
305 
306     /* loop per 2G */
307     while (s.QuadPart < e.QuadPart) {
308         if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) {
309             len = 1024 * 1024 * 1024;
310         } else {
311             len = (ULONG) (e.QuadPart - s.QuadPart);
312         }
313         CcFlushCache(&Vcb->SectionObject, &s, len, NULL);
314         s.QuadPart += len;
315     }
316 }
317 
318 NTSTATUS
319 Ext2FlushVcb(IN PEXT2_VCB Vcb)
320 {
321     LARGE_INTEGER        s = {0}, o;
322     struct ext3_sb_info *sbi = &Vcb->sbi;
323     struct rb_node      *node;
324     struct buffer_head  *bh;
325 
326     if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) {
327         CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
328         goto errorout;
329     }
330 
331     ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource));
332 
333     _SEH2_TRY {
334 
335         /* acqurie gd block */
336         ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
337 
338         /* acquire bd lock to avoid bh creation */
339         ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
340 
341         /* drop unused bh */
342         Ext2DropBH(Vcb);
343 
344         /* flush volume with all outstanding bh skipped */
345 
346         node = rb_first(&Vcb->bd.bd_bh_root);
347         while (node) {
348 
349             bh = container_of(node, struct buffer_head, b_rb_node);
350             node = rb_next(node);
351 
352             o.QuadPart = bh->b_blocknr << BLOCK_BITS;
353             ASSERT(o.QuadPart >= s.QuadPart);
354 
355             if (o.QuadPart == s.QuadPart) {
356                 s.QuadPart = s.QuadPart + bh->b_size;
357                 continue;
358             }
359 
360             if (o.QuadPart > s.QuadPart) {
361                 Ext2FlushRange(Vcb, s, o);
362                 s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size;
363                 continue;
364             }
365         }
366 
367         o = Vcb->PartitionInformation.PartitionLength;
368         Ext2FlushRange(Vcb, s, o);
369 
370     } _SEH2_FINALLY {
371 
372         ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
373         ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
374     } _SEH2_END;
375 
376 errorout:
377     return STATUS_SUCCESS;
378 }
379 
380 
381 BOOLEAN
382 Ext2SaveGroup(
383     IN PEXT2_IRP_CONTEXT    IrpContext,
384     IN PEXT2_VCB            Vcb,
385     IN ULONG                Group
386 )
387 {
388     struct ext4_group_desc *gd;
389     struct buffer_head     *gb = NULL;
390     unsigned long i;
391 
392     gd = ext4_get_group_desc(&Vcb->sb, Group, &gb);
393     if (!gd)
394         return 0;
395 
396     gd->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, gd);
397     mark_buffer_dirty(gb);
398     fini_bh(&gb);
399 
400     return TRUE;
401 }
402 
403 
404 BOOLEAN
405 Ext2RefreshGroup(
406     IN PEXT2_IRP_CONTEXT    IrpContext,
407     IN PEXT2_VCB            Vcb
408 )
409 {
410     return TRUE;
411 }
412 
413 BOOLEAN
414 Ext2GetInodeLba (
415     IN PEXT2_VCB    Vcb,
416     IN  ULONG       inode,
417     OUT PLONGLONG   offset
418 )
419 {
420     PEXT2_GROUP_DESC gd;
421     struct buffer_head *bh = NULL;
422     ext4_fsblk_t loc;
423     int group;
424 
425     if (inode < 1 || inode > INODES_COUNT)  {
426         DEBUG(DL_ERR, ( "Ext2GetInodeLba: Inode value %xh is invalid.\n",inode));
427         *offset = 0;
428         return FALSE;
429     }
430 
431     group = (inode - 1) / INODES_PER_GROUP ;
432     gd = ext4_get_group_desc(&Vcb->sb, group, &bh);
433     if (!bh) {
434         *offset = 0;
435         DbgBreak();
436         return FALSE;
437     }
438     loc = (LONGLONG)ext4_inode_table(&Vcb->sb, gd);
439     loc = loc << BLOCK_BITS;
440     loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
441 
442     *offset = loc;
443     __brelse(bh);
444 
445     return TRUE;
446 }
447 
448 void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src)
449 {
450     dst->i_mode = src->i_mode;
451     dst->i_flags = src->i_flags;
452     dst->i_uid = src->i_uid;
453     dst->i_gid = src->i_gid;
454     dst->i_nlink = src->i_links_count;
455     dst->i_generation = src->i_generation;
456     dst->i_size = src->i_size;
457     if (S_ISREG(src->i_mode)) {
458         dst->i_size |= (loff_t)src->i_size_high << 32;
459     }
460     dst->i_file_acl = src->i_file_acl_lo;
461     dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32;
462     dst->i_atime = src->i_atime;
463     dst->i_ctime = src->i_ctime;
464     dst->i_mtime = src->i_mtime;
465     dst->i_dtime = src->i_dtime;
466     dst->i_blocks = ext3_inode_blocks(src, dst);
467     memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
468     if (EXT3_HAS_RO_COMPAT_FEATURE(dst->i_sb,
469                                    EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
470         dst->i_extra_isize = src->i_extra_isize;
471     else
472         dst->i_extra_isize = 0;
473 }
474 
475 void Ext2EncodeInode(struct ext3_inode *dst,  struct inode *src)
476 {
477     dst->i_mode = src->i_mode;
478     dst->i_flags = src->i_flags;
479     dst->i_uid = src->i_uid;
480     dst->i_gid = src->i_gid;
481     dst->i_links_count = src->i_nlink;
482     dst->i_generation = src->i_generation;
483     dst->i_size = (__u32)src->i_size;
484     if (S_ISREG(src->i_mode)) {
485         dst->i_size_high = (__u32)(src->i_size >> 32);
486     }
487     dst->i_file_acl_lo = (__u32)src->i_file_acl;
488     dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32);
489     dst->i_atime = src->i_atime;
490     dst->i_ctime = src->i_ctime;
491     dst->i_mtime = src->i_mtime;
492     dst->i_dtime = src->i_dtime;
493     dst->i_extra_isize = src->i_extra_isize;
494     ASSERT(src->i_sb);
495     ext3_inode_blocks_set(dst, src);
496     memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
497     if (EXT3_HAS_RO_COMPAT_FEATURE(src->i_sb,
498                                    EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
499         dst->i_extra_isize = src->i_extra_isize;
500 }
501 
502 
503 BOOLEAN
504 Ext2LoadInode (IN PEXT2_VCB Vcb,
505                IN struct inode *Inode)
506 {
507     struct ext3_inode   ext3i = {0};
508     LONGLONG            offset;
509 
510     if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset))  {
511         DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino));
512         return FALSE;
513     }
514 
515     if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) {
516         return FALSE;
517     }
518 
519     Ext2DecodeInode(Inode, &ext3i);
520 
521     return TRUE;
522 }
523 
524 
525 BOOLEAN
526 Ext2ClearInode (
527     IN PEXT2_IRP_CONTEXT IrpContext,
528     IN PEXT2_VCB Vcb,
529     IN ULONG Inode)
530 {
531     LONGLONG            Offset = 0;
532     BOOLEAN             rc;
533 
534     rc = Ext2GetInodeLba(Vcb, Inode, &Offset);
535     if (!rc)  {
536         DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode));
537         goto errorout;
538     }
539 
540     rc = Ext2ZeroBuffer(IrpContext, Vcb, Offset, Vcb->InodeSize);
541 
542 errorout:
543 
544     return rc;
545 }
546 
547 BOOLEAN
548 Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext,
549                 IN PEXT2_VCB Vcb,
550                 IN struct inode *Inode)
551 {
552     struct ext3_inode   ext3i = {0};
553 
554     LONGLONG            Offset = 0;
555     ULONG               InodeSize = sizeof(ext3i);
556     BOOLEAN             rc = 0;
557 
558     DEBUG(DL_INF, ( "Ext2SaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
559                     Inode->i_ino, Inode->i_mode, Inode->i_size));
560     rc = Ext2GetInodeLba(Vcb,  Inode->i_ino, &Offset);
561     if (!rc)  {
562         DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino));
563         goto errorout;
564     }
565 
566     rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext3i);
567     if (!rc) {
568         DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino));
569         goto errorout;;
570     }
571 
572     Ext2EncodeInode(&ext3i, Inode);
573     if (InodeSize > Vcb->InodeSize)
574         InodeSize = Vcb->InodeSize;
575     rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, InodeSize, &ext3i);
576 
577     if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
578         Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
579     }
580 
581 errorout:
582     return rc;
583 }
584 
585 BOOLEAN
586 Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,
587 	IN struct inode *Inode,
588 	IN PEXT2_INODE InodeXattr)
589 {
590 	IO_STATUS_BLOCK     IoStatus;
591 	LONGLONG            Offset;
592 
593 	if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) {
594 		DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
595 		return FALSE;
596 	}
597 
598 	if (!CcCopyRead(
599 		Vcb->Volume,
600 		(PLARGE_INTEGER)&Offset,
601 		Vcb->InodeSize,
602 		PIN_WAIT,
603 		(PVOID)InodeXattr,
604 		&IoStatus)) {
605 		return FALSE;
606 	}
607 
608 	if (!NT_SUCCESS(IoStatus.Status)) {
609 		return FALSE;
610 	}
611 
612 	Ext2EncodeInode(InodeXattr, Inode);
613 	return TRUE;
614 }
615 
616 BOOLEAN
617 Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,
618 	IN PEXT2_VCB Vcb,
619 	IN struct inode *Inode,
620 	IN PEXT2_INODE InodeXattr)
621 {
622 	IO_STATUS_BLOCK     IoStatus;
623 	LONGLONG            Offset = 0;
624 	ULONG               InodeSize = Vcb->InodeSize;
625 	BOOLEAN             rc = 0;
626 
627 	/* There is no way to put EA information in such a small inode */
628 	if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE)
629 		return FALSE;
630 
631 	DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n",
632 		Inode->i_ino, Inode->i_mode, Inode->i_size));
633 	rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
634 	if (!rc) {
635 		DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino));
636 		goto errorout;
637 	}
638 
639 	rc = Ext2SaveBuffer(IrpContext,
640 									Vcb,
641 									Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize,
642 									InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize,
643 									(char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize);
644 
645 	if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
646 		Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
647 	}
648 
649 errorout:
650 	return rc;
651 }
652 
653 
654 BOOLEAN
655 Ext2LoadBlock (IN PEXT2_VCB Vcb,
656                IN ULONG     Index,
657                IN PVOID     Buffer )
658 {
659     struct buffer_head *bh = NULL;
660     BOOLEAN             rc = 0;
661 
662     _SEH2_TRY {
663 
664         bh = sb_getblk(&Vcb->sb, (sector_t)Index);
665 
666         if (!bh) {
667             DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index));
668             DbgBreak();
669             _SEH2_LEAVE;
670         }
671 
672         if (!buffer_uptodate(bh)) {
673             int err = bh_submit_read(bh);
674 	        if (err < 0) {
675 	            DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err));
676 		        _SEH2_LEAVE;
677 	        }
678         }
679 
680         RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE);
681         rc = TRUE;
682 
683     } _SEH2_FINALLY {
684 
685         if (bh)
686             fini_bh(&bh);
687     } _SEH2_END;
688 
689     return rc;
690 }
691 
692 
693 BOOLEAN
694 Ext2SaveBlock ( IN PEXT2_IRP_CONTEXT    IrpContext,
695                 IN PEXT2_VCB            Vcb,
696                 IN ULONG                Index,
697                 IN PVOID                Buf )
698 {
699     struct buffer_head *bh = NULL;
700     BOOLEAN             rc = 0;
701 
702     _SEH2_TRY {
703 
704         bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index);
705 
706         if (!bh) {
707             DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index));
708             DbgBreak();
709             _SEH2_LEAVE;
710         }
711 
712         if (!buffer_uptodate(bh)) {
713         }
714 
715         RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE);
716         mark_buffer_dirty(bh);
717         rc = TRUE;
718 
719     } _SEH2_FINALLY {
720 
721         if (bh)
722             fini_bh(&bh);
723     } _SEH2_END;
724 
725     return rc;
726 }
727 
728 BOOLEAN
729 Ext2LoadBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
730                 IN PEXT2_VCB            Vcb,
731                 IN LONGLONG             offset,
732                 IN ULONG                size,
733                 IN PVOID                buf )
734 {
735     struct buffer_head *bh = NULL;
736     BOOLEAN             rc;
737 
738     _SEH2_TRY {
739 
740         while (size) {
741 
742             sector_t    block;
743             ULONG       len = 0, delta = 0;
744 
745             block = (sector_t) (offset >> BLOCK_BITS);
746             delta = (ULONG)offset & (BLOCK_SIZE - 1);
747             len = BLOCK_SIZE - delta;
748             if (size < len)
749                 len = size;
750 
751             bh = sb_getblk(&Vcb->sb, block);
752             if (!bh) {
753                 DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
754                 DbgBreak();
755                 _SEH2_LEAVE;
756             }
757 
758             if (!buffer_uptodate(bh)) {
759 	            int err = bh_submit_read(bh);
760 	            if (err < 0) {
761 		            DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
762 		            _SEH2_LEAVE;
763 	            }
764             }
765 
766             _SEH2_TRY {
767                 RtlCopyMemory(buf, bh->b_data + delta, len);
768             } _SEH2_FINALLY {
769                 fini_bh(&bh);
770             } _SEH2_END;
771 
772             buf = (PUCHAR)buf + len;
773             offset = offset + len;
774             size = size - len;
775         }
776 
777         rc = TRUE;
778 
779     } _SEH2_FINALLY {
780 
781         if (bh)
782             fini_bh(&bh);
783 
784     } _SEH2_END;
785 
786     return rc;
787 }
788 
789 
790 BOOLEAN
791 Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
792                 IN PEXT2_VCB            Vcb,
793                 IN LONGLONG             offset,
794                 IN ULONG                size
795     )
796 {
797     struct buffer_head *bh = NULL;
798     BOOLEAN             rc = 0;
799 
800     _SEH2_TRY {
801 
802         while (size) {
803 
804             sector_t    block;
805             ULONG       len = 0, delta = 0;
806 
807             block = (sector_t) (offset >> BLOCK_BITS);
808             delta = (ULONG)offset & (BLOCK_SIZE - 1);
809             len = BLOCK_SIZE - delta;
810             if (size < len)
811                 len = size;
812 
813             if (delta == 0 && len >= BLOCK_SIZE) {
814                 bh = sb_getblk_zero(&Vcb->sb, block);
815             } else {
816                 bh = sb_getblk(&Vcb->sb, block);
817             }
818 
819             if (!bh) {
820                 DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
821                 DbgBreak();
822                 _SEH2_LEAVE;
823             }
824 
825             if (!buffer_uptodate(bh)) {
826 	            int err = bh_submit_read(bh);
827 	            if (err < 0) {
828 		            DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
829 		            _SEH2_LEAVE;
830 	            }
831             }
832 
833             _SEH2_TRY {
834                 if (delta == 0 && len >= BLOCK_SIZE) {
835                     /* bh (cache) was already cleaned as zero */
836                 } else {
837                     RtlZeroMemory(bh->b_data + delta, len);
838                 }
839                 mark_buffer_dirty(bh);
840             } _SEH2_FINALLY {
841                 fini_bh(&bh);
842             } _SEH2_END;
843 
844             offset = offset + len;
845             size = size - len;
846         }
847 
848         rc = TRUE;
849 
850     } _SEH2_FINALLY {
851 
852         if (bh)
853             fini_bh(&bh);
854 
855     } _SEH2_END;
856 
857     return rc;
858 }
859 
860 
861 BOOLEAN
862 Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT    IrpContext,
863                 IN PEXT2_VCB            Vcb,
864                 IN LONGLONG             offset,
865                 IN ULONG                size,
866                 IN PVOID                buf )
867 {
868     struct buffer_head *bh = NULL;
869     BOOLEAN             rc = 0;
870 
871     _SEH2_TRY {
872 
873         while (size) {
874 
875             sector_t    block;
876             ULONG       len = 0, delta = 0;
877 
878             block = (sector_t) (offset >> BLOCK_BITS);
879             delta = (ULONG)offset & (BLOCK_SIZE - 1);
880             len = BLOCK_SIZE - delta;
881             if (size < len)
882                 len = size;
883 
884             if (delta == 0 && len >= BLOCK_SIZE) {
885                 bh = sb_getblk_zero(&Vcb->sb, block);
886             } else {
887                 bh = sb_getblk(&Vcb->sb, block);
888             }
889 
890             if (!bh) {
891                 DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
892                 DbgBreak();
893                 _SEH2_LEAVE;
894             }
895 
896             if (!buffer_uptodate(bh)) {
897 	            int err = bh_submit_read(bh);
898 	            if (err < 0) {
899 		            DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
900 		            _SEH2_LEAVE;
901 	            }
902             }
903 
904             _SEH2_TRY {
905                 RtlCopyMemory(bh->b_data + delta, buf, len);
906                 mark_buffer_dirty(bh);
907             } _SEH2_FINALLY {
908                 fini_bh(&bh);
909             } _SEH2_END;
910 
911             buf = (PUCHAR)buf + len;
912             offset = offset + len;
913             size = size - len;
914         }
915 
916         rc = TRUE;
917 
918     } _SEH2_FINALLY {
919 
920         if (bh)
921             fini_bh(&bh);
922 
923     } _SEH2_END;
924 
925     return rc;
926 }
927 
928 
929 VOID
930 Ext2UpdateVcbStat(
931     IN PEXT2_IRP_CONTEXT    IrpContext,
932     IN PEXT2_VCB            Vcb
933 )
934 {
935     Vcb->SuperBlock->s_free_inodes_count = ext4_count_free_inodes(&Vcb->sb);
936     ext3_free_blocks_count_set(SUPER_BLOCK, ext4_count_free_blocks(&Vcb->sb));
937     Ext2SaveSuper(IrpContext, Vcb);
938 }
939 
940 NTSTATUS
941 Ext2NewBlock(
942     IN PEXT2_IRP_CONTEXT    IrpContext,
943     IN PEXT2_VCB            Vcb,
944     IN ULONG                GroupHint,
945     IN ULONG                BlockHint,
946     OUT PULONG              Block,
947     IN OUT PULONG           Number
948 )
949 {
950     struct super_block      *sb = &Vcb->sb;
951     PEXT2_GROUP_DESC        gd;
952     struct buffer_head     *gb = NULL;
953     struct buffer_head     *bh = NULL;
954     ext4_fsblk_t            bitmap_blk;
955 
956     RTL_BITMAP              BlockBitmap;
957 
958     ULONG                   Group = 0;
959     ULONG                   Index = 0xFFFFFFFF;
960     ULONG                   dwHint = 0;
961     ULONG                   Count = 0;
962     ULONG                   Length = 0;
963 
964     NTSTATUS                Status = STATUS_DISK_FULL;
965 
966     *Block = 0;
967 
968     ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
969 
970     /* validate the hint group and hint block */
971     if (GroupHint >= Vcb->sbi.s_groups_count) {
972         DbgBreak();
973         GroupHint = Vcb->sbi.s_groups_count - 1;
974     }
975 
976     if (BlockHint != 0) {
977         GroupHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
978         dwHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
979     }
980 
981     Group = GroupHint;
982 
983 Again:
984 
985     if (bh)
986         fini_bh(&bh);
987 
988     if (gb)
989         fini_bh(&gb);
990 
991     gd = ext4_get_group_desc(sb, Group, &gb);
992     if (!gd) {
993         DbgBreak();
994         Status = STATUS_INSUFFICIENT_RESOURCES;
995         goto errorout;
996     }
997 
998     bitmap_blk = ext4_block_bitmap(sb, gd);
999 
1000     if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
1001         bh = sb_getblk_zero(sb, bitmap_blk);
1002         if (!bh) {
1003             DbgBreak();
1004             Status = STATUS_INSUFFICIENT_RESOURCES;
1005             goto errorout;
1006         }
1007         gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
1008         ext4_init_block_bitmap(sb, bh, Group, gd);
1009         set_buffer_uptodate(bh);
1010         gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
1011         Ext2SaveGroup(IrpContext, Vcb, Group);
1012     } else {
1013         bh = sb_getblk(sb, bitmap_blk);
1014         if (!bh) {
1015             DbgBreak();
1016             Status = STATUS_INSUFFICIENT_RESOURCES;
1017             goto errorout;
1018         }
1019     }
1020 
1021     if (!buffer_uptodate(bh)) {
1022 	    int err = bh_submit_read(bh);
1023 	    if (err < 0) {
1024 		    DbgPrint("bh_submit_read error! err: %d\n", err);
1025 		    Status = Ext2WinntError(err);
1026 		    goto errorout;
1027 	    }
1028     }
1029 
1030     if (ext4_free_blks_count(sb, gd)) {
1031 
1032         if (Group == Vcb->sbi.s_groups_count - 1) {
1033 
1034             Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1035 
1036             /* s_blocks_count is integer multiple of s_blocks_per_group */
1037             if (Length == 0) {
1038                 Length = BLOCKS_PER_GROUP;
1039             }
1040         } else {
1041             Length = BLOCKS_PER_GROUP;
1042         }
1043 
1044         /* initialize bitmap buffer */
1045         RtlInitializeBitMap(&BlockBitmap, (PULONG)bh->b_data, Length);
1046 
1047         /* try to find a clear bit range */
1048         Index = RtlFindClearBits(&BlockBitmap, *Number, dwHint);
1049 
1050         /* We could not get new block in the prefered group */
1051         if (Index == 0xFFFFFFFF) {
1052 
1053             /* search clear bits from the hint block */
1054             Count = RtlFindNextForwardRunClear(&BlockBitmap, dwHint, &Index);
1055             if (dwHint != 0 && Count == 0) {
1056                 /* search clear bits from the very beginning */
1057                 Count = RtlFindNextForwardRunClear(&BlockBitmap, 0, &Index);
1058             }
1059 
1060             if (Count == 0) {
1061 
1062                 RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
1063 
1064                 /* no blocks found: set bg_free_blocks_count to 0 */
1065                 ext4_free_blks_set(sb, gd, 0);
1066                 Ext2SaveGroup(IrpContext, Vcb, Group);
1067 
1068                 /* will try next group */
1069                 goto Again;
1070 
1071             } else {
1072 
1073                 /* we got free blocks */
1074                 if (Count <= *Number) {
1075                     *Number = Count;
1076                 }
1077             }
1078         }
1079 
1080     } else {
1081 
1082         /* try next group */
1083         dwHint = 0;
1084         Group = (Group + 1) % Vcb->sbi.s_groups_count;
1085         if (Group != GroupHint) {
1086             goto Again;
1087         }
1088 
1089         Index = 0xFFFFFFFF;
1090     }
1091 
1092     if (Index < Length) {
1093 
1094         /* mark block bits as allocated */
1095         RtlSetBits(&BlockBitmap, Index, *Number);
1096 
1097         /* set block bitmap dirty in cache */
1098         mark_buffer_dirty(bh);
1099 
1100         /* update group description */
1101         ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
1102         Ext2SaveGroup(IrpContext, Vcb, Group);
1103 
1104         /* update Vcb free blocks */
1105         Ext2UpdateVcbStat(IrpContext, Vcb);
1106 
1107         /* validate the new allocated block number */
1108         *Block = Index + EXT2_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP;
1109         if (*Block >= TOTAL_BLOCKS || *Block + *Number > TOTAL_BLOCKS) {
1110             DbgBreak();
1111             dwHint = 0;
1112             goto Again;
1113         }
1114 
1115         if (ext4_block_bitmap(sb, gd) == *Block ||
1116             ext4_inode_bitmap(sb, gd) == *Block ||
1117             ext4_inode_table(sb,  gd)  == *Block ) {
1118             DbgBreak();
1119             dwHint = 0;
1120             goto Again;
1121         }
1122 
1123         /* Always remove dirty MCB to prevent Volume's lazy writing.
1124            Metadata blocks will be re-added during modifications.*/
1125         if (Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number)) {
1126         } else {
1127             DbgBreak();
1128             Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number);
1129         }
1130 
1131         DEBUG(DL_INF, ("Ext2NewBlock:  Block %xh - %x allocated.\n",
1132                        *Block, *Block + *Number));
1133         Status = STATUS_SUCCESS;
1134     }
1135 
1136 errorout:
1137 
1138     ExReleaseResourceLite(&Vcb->MetaBlock);
1139 
1140     if (bh)
1141         fini_bh(&bh);
1142 
1143     if (gb)
1144         fini_bh(&gb);
1145 
1146     return Status;
1147 }
1148 
1149 NTSTATUS
1150 Ext2FreeBlock(
1151     IN PEXT2_IRP_CONTEXT    IrpContext,
1152     IN PEXT2_VCB            Vcb,
1153     IN ULONG                Block,
1154     IN ULONG                Number
1155 )
1156 {
1157     struct super_block     *sb = &Vcb->sb;
1158     PEXT2_GROUP_DESC        gd;
1159     struct buffer_head     *gb = NULL;
1160     ext4_fsblk_t            bitmap_blk;
1161 
1162     RTL_BITMAP      BlockBitmap;
1163     LARGE_INTEGER   Offset;
1164 
1165     PBCB            BitmapBcb;
1166     PVOID           BitmapCache;
1167 
1168     ULONG           Group;
1169     ULONG           Index;
1170     ULONG           Length;
1171     ULONG           Count;
1172 
1173     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
1174 
1175     ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
1176 
1177     DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n",
1178                    Block, Block + Number));
1179 
1180     Group = (Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1181     Index = (Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1182 
1183 Again:
1184 
1185     if (gb)
1186         fini_bh(&gb);
1187 
1188     if ( Block < EXT2_FIRST_DATA_BLOCK ||
1189          Block >= TOTAL_BLOCKS ||
1190          Group >= Vcb->sbi.s_groups_count) {
1191 
1192         DbgBreak();
1193         Status = STATUS_SUCCESS;
1194 
1195     } else  {
1196 
1197         gd = ext4_get_group_desc(sb, Group, &gb);
1198         if (!gd) {
1199             DbgBreak();
1200             Status = STATUS_INSUFFICIENT_RESOURCES;
1201             goto errorout;
1202         }
1203         bitmap_blk = ext4_block_bitmap(sb, gd);
1204 
1205         /* check the block is valid or not */
1206         if (bitmap_blk >= TOTAL_BLOCKS) {
1207             DbgBreak();
1208             Status = STATUS_DISK_CORRUPT_ERROR;
1209             goto errorout;
1210         }
1211 
1212         /* get bitmap block offset and length */
1213         Offset.QuadPart = bitmap_blk;
1214         Offset.QuadPart = Offset.QuadPart << BLOCK_BITS;
1215 
1216         if (Group == Vcb->sbi.s_groups_count - 1) {
1217 
1218             Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1219 
1220             /* s_blocks_count is integer multiple of s_blocks_per_group */
1221             if (Length == 0) {
1222                 Length = BLOCKS_PER_GROUP;
1223             }
1224 
1225         } else {
1226             Length = BLOCKS_PER_GROUP;
1227         }
1228 
1229         /* read and initialize bitmap */
1230         if (!CcPinRead( Vcb->Volume,
1231                         &Offset,
1232                         Vcb->BlockSize,
1233                         PIN_WAIT,
1234                         &BitmapBcb,
1235                         &BitmapCache ) ) {
1236 
1237             DEBUG(DL_ERR, ("Ext2FreeBlock: failed to PinLock bitmap block %xh.\n",
1238                            bitmap_blk));
1239             Status = STATUS_CANT_WAIT;
1240             DbgBreak();
1241             goto errorout;
1242         }
1243 
1244         /* clear usused bits */
1245         RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length);
1246         Count = min(Length - Index, Number);
1247         RtlClearBits(&BlockBitmap, Index, Count);
1248 
1249         /* update group description table */
1250         ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
1251 
1252         /* indict the cache range is dirty */
1253         CcSetDirtyPinnedData(BitmapBcb, NULL );
1254         Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
1255         CcUnpinData(BitmapBcb);
1256         BitmapBcb = NULL;
1257         BitmapCache = NULL;
1258         Ext2SaveGroup(IrpContext, Vcb, Group);
1259 
1260         /* remove dirty MCB to prevent Volume's lazy writing. */
1261         if (Ext2RemoveBlockExtent(Vcb, NULL, Block, Count)) {
1262         } else {
1263             DbgBreak();
1264             Ext2RemoveBlockExtent(Vcb, NULL, Block, Count);
1265         }
1266 
1267         /* save super block (used/unused blocks statics) */
1268         Ext2UpdateVcbStat(IrpContext, Vcb);
1269 
1270         /* try next group to clear all remaining */
1271         Number -= Count;
1272         if (Number) {
1273             Group += 1;
1274             if (Group < Vcb->sbi.s_groups_count) {
1275                 Index = 0;
1276                 Block += Count;
1277                 goto Again;
1278             } else {
1279                 DEBUG(DL_ERR, ("Ext2FreeBlock: block number beyonds max group.\n"));
1280                 goto errorout;
1281             }
1282         }
1283     }
1284 
1285     Status = STATUS_SUCCESS;
1286 
1287 errorout:
1288 
1289     if (gb)
1290         fini_bh(&gb);
1291 
1292     ExReleaseResourceLite(&Vcb->MetaBlock);
1293 
1294     return Status;
1295 }
1296 
1297 
1298 NTSTATUS
1299 Ext2NewInode(
1300     IN PEXT2_IRP_CONTEXT    IrpContext,
1301     IN PEXT2_VCB            Vcb,
1302     IN ULONG                GroupHint,
1303     IN ULONG                Type,
1304     OUT PULONG              Inode
1305 )
1306 {
1307     struct super_block     *sb = &Vcb->sb;
1308     PEXT2_GROUP_DESC        gd;
1309     struct buffer_head     *gb = NULL;
1310     struct buffer_head     *bh = NULL;
1311     ext4_fsblk_t            bitmap_blk;
1312 
1313     RTL_BITMAP      InodeBitmap;
1314 
1315     ULONG           Group, i, j;
1316     ULONG           Average, Length;
1317 
1318     ULONG           dwInode;
1319 
1320     NTSTATUS        Status = STATUS_DISK_FULL;
1321 
1322     *Inode = dwInode = 0XFFFFFFFF;
1323 
1324     ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
1325 
1326     if (GroupHint >= Vcb->sbi.s_groups_count)
1327         GroupHint = GroupHint % Vcb->sbi.s_groups_count;
1328 
1329 repeat:
1330 
1331     if (bh)
1332         fini_bh(&bh);
1333 
1334     if (gb)
1335         fini_bh(&gb);
1336 
1337     Group = i = 0;
1338     gd = NULL;
1339 
1340     if (Type == EXT2_FT_DIR) {
1341 
1342         Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->sbi.s_groups_count;
1343 
1344         for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
1345 
1346             i = (j + GroupHint) % (Vcb->sbi.s_groups_count);
1347             gd = ext4_get_group_desc(sb, i, &gb);
1348             if (!gd) {
1349                     DbgBreak();
1350                 Status = STATUS_INSUFFICIENT_RESOURCES;
1351                 goto errorout;
1352             }
1353 
1354             if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
1355                 (ext4_used_dirs_count(sb, gd) << 8 <
1356                  ext4_free_inodes_count(sb, gd)) ) {
1357                 Group = i + 1;
1358                 break;
1359             }
1360             fini_bh(&gb);
1361         }
1362 
1363         if (!Group) {
1364 
1365             PEXT2_GROUP_DESC  desc = NULL;
1366 
1367             gd = NULL;
1368 
1369             /* get the group with the biggest vacancy */
1370             for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
1371 
1372                 struct buffer_head *gt = NULL;
1373                 desc = ext4_get_group_desc(sb, j, &gt);
1374                 if (!desc) {
1375                     DbgBreak();
1376                     Status = STATUS_INSUFFICIENT_RESOURCES;
1377                     goto errorout;
1378                 }
1379 
1380                 /* return the group if it's not initialized yet */
1381                 if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
1382                     Group = j + 1;
1383                     gd = desc;
1384 
1385                     if (gb)
1386                         fini_bh(&gb);
1387                     gb = gt;
1388                     gt = NULL;
1389                     break;
1390                 }
1391 
1392                 if (!gd) {
1393                     if (ext4_free_inodes_count(sb, desc) > 0) {
1394                         Group = j + 1;
1395                         gd = desc;
1396                         if (gb)
1397                             fini_bh(&gb);
1398                         gb = gt;
1399                         gt = NULL;
1400                     }
1401                 } else {
1402                     if (ext4_free_inodes_count(sb, desc) >
1403                         ext4_free_inodes_count(sb, gd)) {
1404                         Group = j + 1;
1405                         gd = desc;
1406                         if (gb)
1407                             fini_bh(&gb);
1408                         gb = gt;
1409                         gt = NULL;
1410                         break;
1411                     }
1412                 }
1413                 if (gt)
1414                     fini_bh(&gt);
1415             }
1416         }
1417 
1418     } else {
1419 
1420         /*
1421          * Try to place the inode in its parent directory (GroupHint)
1422          */
1423 
1424         gd = ext4_get_group_desc(sb, GroupHint, &gb);
1425         if (!gb) {
1426             DbgBreak();
1427             Status = STATUS_INSUFFICIENT_RESOURCES;
1428             goto errorout;
1429         }
1430 
1431         if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
1432             ext4_free_inodes_count(sb, gd)) {
1433 
1434             Group = GroupHint + 1;
1435 
1436         } else {
1437 
1438             /* this group is 100% cocucpied */
1439             fini_bh(&gb);
1440 
1441             i = GroupHint;
1442 
1443             /*
1444              * Use a quadratic hash to find a group with a free inode
1445              */
1446 
1447             for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
1448 
1449 
1450                 i = (i + j) % Vcb->sbi.s_groups_count;
1451                 gd = ext4_get_group_desc(sb, i, &gb);
1452                 if (!gd) {
1453                     DbgBreak();
1454                     Status = STATUS_INSUFFICIENT_RESOURCES;
1455                     goto errorout;
1456                 }
1457 
1458                 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
1459                     ext4_free_inodes_count(sb, gd)) {
1460                     Group = i + 1;
1461                     break;
1462                 }
1463 
1464                 fini_bh(&gb);
1465             }
1466         }
1467 
1468         if (!Group) {
1469             /*
1470              * That failed: try linear search for a free inode
1471              */
1472             i = GroupHint;
1473             for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
1474 
1475                 i = (i + 1) % Vcb->sbi.s_groups_count;
1476                 gd = ext4_get_group_desc(sb, i, &gb);
1477                 if (!gd) {
1478                     DbgBreak();
1479                     Status = STATUS_INSUFFICIENT_RESOURCES;
1480                     goto errorout;
1481                 }
1482 
1483                 if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
1484                     ext4_free_inodes_count(sb, gd)) {
1485                     Group = i + 1;
1486                     break;
1487                 }
1488 
1489                 fini_bh(&gb);
1490             }
1491         }
1492     }
1493 
1494     if (gd == NULL || Group == 0) {
1495         goto errorout;
1496     }
1497 
1498     /* finally we got the group, but is it valid ? */
1499     if (Group > Vcb->sbi.s_groups_count) {
1500         DbgBreak();
1501         goto errorout;
1502     }
1503 
1504     /* valid group number starts from 1, not 0 */
1505     Group -= 1;
1506 
1507     ASSERT(gd);
1508     bitmap_blk = ext4_inode_bitmap(sb, gd);
1509     /* check the block is valid or not */
1510     if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) {
1511         DbgBreak();
1512         Status = STATUS_DISK_CORRUPT_ERROR;
1513         goto errorout;
1514     }
1515 
1516     if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
1517         bh = sb_getblk_zero(sb, bitmap_blk);
1518         if (!bh) {
1519             DbgBreak();
1520             Status = STATUS_INSUFFICIENT_RESOURCES;
1521             goto errorout;
1522         }
1523         gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
1524         ext4_init_inode_bitmap(sb, bh, Group, gd);
1525         set_buffer_uptodate(bh);
1526         gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
1527         Ext2SaveGroup(IrpContext, Vcb, Group);
1528     } else {
1529         bh = sb_getblk(sb, bitmap_blk);
1530         if (!bh) {
1531             DbgBreak();
1532             Status = STATUS_INSUFFICIENT_RESOURCES;
1533             goto errorout;
1534         }
1535     }
1536 
1537     if (!buffer_uptodate(bh)) {
1538 	    int err = bh_submit_read(bh);
1539 	    if (err < 0) {
1540 		    DbgPrint("bh_submit_read error! err: %d\n", err);
1541 		    Status = Ext2WinntError(err);
1542 		    goto errorout;
1543 	    }
1544     }
1545 
1546     if (Vcb->sbi.s_groups_count == 1) {
1547         Length = INODES_COUNT;
1548     } else {
1549         if (Group + 1 == Vcb->sbi.s_groups_count) {
1550             Length = INODES_COUNT % INODES_PER_GROUP;
1551             if (!Length) {
1552                 /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
1553                 Length = INODES_PER_GROUP;
1554             }
1555         } else  {
1556             Length = INODES_PER_GROUP;
1557         }
1558     }
1559 
1560     RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
1561     dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
1562 
1563     if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
1564 
1565         RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
1566         if (ext4_free_inodes_count(sb, gd) > 0) {
1567             ext4_free_inodes_set(sb, gd, 0);
1568             Ext2SaveGroup(IrpContext, Vcb, Group);
1569         }
1570         goto repeat;
1571 
1572     } else {
1573 
1574         __u32 count = 0;
1575 
1576         /* update unused inodes count */
1577         count = ext4_free_inodes_count(sb, gd) - 1;
1578         ext4_free_inodes_set(sb, gd, count);
1579 
1580         RtlSetBits(&InodeBitmap, dwInode, 1);
1581 
1582         /* set block bitmap dirty in cache */
1583         mark_buffer_dirty(bh);
1584 
1585         /* If we didn't allocate from within the initialized part of the inode
1586          * table then we need to initialize up to this inode. */
1587         if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
1588 
1589             __u32 free;
1590 
1591             if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
1592                 gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
1593                 /* When marking the block group with
1594                  * ~EXT4_BG_INODE_UNINIT we don't want to depend
1595                  * on the value of bg_itable_unused even though
1596                  * mke2fs could have initialized the same for us.
1597                  * Instead we calculated the value below
1598                  */
1599 
1600                 free = 0;
1601             } else {
1602                 free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd);
1603             }
1604 
1605             /*
1606              * Check the relative inode number against the last used
1607              * relative inode number in this group. if it is greater
1608              * we need to  update the bg_itable_unused count
1609              *
1610              */
1611             if (dwInode + 1 > free) {
1612                 ext4_itable_unused_set(sb, gd,
1613                                        (EXT3_INODES_PER_GROUP(sb) - 1 - dwInode));
1614             }
1615 
1616             /* We may have to initialize the block bitmap if it isn't already */
1617             if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
1618 
1619                 struct buffer_head *block_bitmap_bh = NULL;
1620 
1621                 /* recheck and clear flag under lock if we still need to */
1622                 block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd));
1623                 if (block_bitmap_bh) {
1624                     gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
1625                     free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd);
1626                     set_buffer_uptodate(block_bitmap_bh);
1627                     brelse(block_bitmap_bh);
1628                     gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
1629                     ext4_free_blks_set(sb, gd, free);
1630                     Ext2SaveGroup(IrpContext, Vcb, Group);
1631                 }
1632             }
1633         }
1634 
1635         *Inode = dwInode + 1 + Group * INODES_PER_GROUP;
1636 
1637         /* update group_desc / super_block */
1638         if (Type == EXT2_FT_DIR) {
1639             ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1);
1640         }
1641         Ext2SaveGroup(IrpContext, Vcb, Group);
1642         Ext2UpdateVcbStat(IrpContext, Vcb);
1643         Status = STATUS_SUCCESS;
1644     }
1645 
1646 errorout:
1647 
1648     ExReleaseResourceLite(&Vcb->MetaInode);
1649 
1650     if (bh)
1651         fini_bh(&bh);
1652 
1653     if (gb)
1654         fini_bh(&gb);
1655 
1656 
1657     return Status;
1658 }
1659 
1660 NTSTATUS
1661 Ext2UpdateGroupDirStat(
1662     IN PEXT2_IRP_CONTEXT    IrpContext,
1663     IN PEXT2_VCB            Vcb,
1664     IN ULONG                group
1665     )
1666 {
1667     struct super_block     *sb = &Vcb->sb;
1668     PEXT2_GROUP_DESC        gd;
1669     struct buffer_head     *gb = NULL;
1670     NTSTATUS                status;
1671 
1672     ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
1673 
1674     /* get group desc */
1675     gd = ext4_get_group_desc(sb, group, &gb);
1676     if (!gd) {
1677         status = STATUS_INSUFFICIENT_RESOURCES;
1678         goto errorout;
1679     }
1680 
1681     /* update group_desc and super_block */
1682     ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1);
1683     Ext2SaveGroup(IrpContext, Vcb, group);
1684     Ext2UpdateVcbStat(IrpContext, Vcb);
1685     status = STATUS_SUCCESS;
1686 
1687 errorout:
1688 
1689     ExReleaseResourceLite(&Vcb->MetaInode);
1690 
1691     if (gb)
1692         fini_bh(&gb);
1693 
1694     return status;
1695 }
1696 
1697 
1698 NTSTATUS
1699 Ext2FreeInode(
1700     IN PEXT2_IRP_CONTEXT    IrpContext,
1701     IN PEXT2_VCB            Vcb,
1702     IN ULONG                Inode,
1703     IN ULONG                Type
1704 )
1705 {
1706     struct super_block     *sb = &Vcb->sb;
1707     PEXT2_GROUP_DESC        gd;
1708     struct buffer_head     *gb = NULL;
1709     struct buffer_head     *bh = NULL;
1710     ext4_fsblk_t            bitmap_blk;
1711 
1712     RTL_BITMAP      InodeBitmap;
1713     ULONG           Group;
1714     ULONG           Length;
1715     LARGE_INTEGER   Offset;
1716 
1717     ULONG           dwIno;
1718     BOOLEAN         bModified = FALSE;
1719 
1720     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
1721 
1722     ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
1723 
1724     Group = (Inode - 1) / INODES_PER_GROUP;
1725     dwIno = (Inode - 1) % INODES_PER_GROUP;
1726 
1727     DEBUG(DL_INF, ( "Ext2FreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
1728                     Inode, Group, dwIno));
1729 
1730     if (Group >= Vcb->sbi.s_groups_count)  {
1731         DbgBreak();
1732         goto errorout;
1733     }
1734 
1735     gd = ext4_get_group_desc(sb, Group, &gb);
1736     if (!gd) {
1737         DbgBreak();
1738         Status = STATUS_INSUFFICIENT_RESOURCES;
1739         goto errorout;
1740     }
1741 
1742     bitmap_blk = ext4_inode_bitmap(sb, gd);
1743     bh = sb_getblk(sb, bitmap_blk);
1744     if (!bh) {
1745         DbgBreak();
1746         Status = STATUS_INSUFFICIENT_RESOURCES;
1747         goto errorout;
1748     }
1749     if (!buffer_uptodate(bh)) {
1750         int err = bh_submit_read(bh);
1751         if (err < 0) {
1752             DbgPrint("bh_submit_read error! err: %d\n", err);
1753             Status = Ext2WinntError(err);
1754             goto errorout;
1755         }
1756     }
1757 
1758     if (Group == Vcb->sbi.s_groups_count - 1) {
1759 
1760         Length = INODES_COUNT % INODES_PER_GROUP;
1761         if (!Length) {
1762             /* s_inodes_count is integer multiple of s_inodes_per_group */
1763             Length = INODES_PER_GROUP;
1764         }
1765     } else {
1766         Length = INODES_PER_GROUP;
1767     }
1768 
1769     RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
1770 
1771     if (RtlCheckBit(&InodeBitmap, dwIno) == 0) {
1772         DbgBreak();
1773         Status = STATUS_SUCCESS;
1774     } else {
1775         RtlClearBits(&InodeBitmap, dwIno, 1);
1776         bModified = TRUE;
1777     }
1778 
1779     if (bModified) {
1780         /* update group free inodes */
1781         ext4_free_inodes_set(sb, gd,
1782                              RtlNumberOfClearBits(&InodeBitmap));
1783 
1784         /* set inode block dirty and add to vcb dirty range */
1785         mark_buffer_dirty(bh);
1786 
1787         /* update group_desc and super_block */
1788         if (Type == EXT2_FT_DIR) {
1789             ext4_used_dirs_set(sb, gd,
1790                                ext4_used_dirs_count(sb, gd) - 1);
1791         }
1792         Ext2SaveGroup(IrpContext, Vcb, Group);
1793         Ext2UpdateVcbStat(IrpContext, Vcb);
1794         Status = STATUS_SUCCESS;
1795     }
1796 
1797 errorout:
1798 
1799     ExReleaseResourceLite(&Vcb->MetaInode);
1800 
1801     if (bh)
1802         fini_bh(&bh);
1803 
1804     if (gb)
1805         fini_bh(&gb);
1806 
1807     return Status;
1808 }
1809 
1810 
1811 NTSTATUS
1812 Ext2AddEntry (
1813     IN PEXT2_IRP_CONTEXT   IrpContext,
1814     IN PEXT2_VCB           Vcb,
1815     IN PEXT2_FCB           Dcb,
1816     IN struct inode       *Inode,
1817     IN PUNICODE_STRING     FileName,
1818     struct dentry        **Dentry
1819 )
1820 {
1821     struct dentry          *de = NULL;
1822 
1823     NTSTATUS                status = STATUS_UNSUCCESSFUL;
1824     OEM_STRING              oem;
1825     int                     rc;
1826 
1827     BOOLEAN                 MainResourceAcquired = FALSE;
1828 
1829     if (!IsDirectory(Dcb)) {
1830         DbgBreak();
1831         return STATUS_NOT_A_DIRECTORY;
1832     }
1833 
1834     ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1835     MainResourceAcquired = TRUE;
1836 
1837     _SEH2_TRY {
1838 
1839         Ext2ReferXcb(&Dcb->ReferenceCount);
1840         de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName);
1841         if (!de) {
1842             status = STATUS_INSUFFICIENT_RESOURCES;
1843             _SEH2_LEAVE;
1844         }
1845         de->d_inode = Inode;
1846 
1847         rc = ext3_add_entry(IrpContext, de, Inode);
1848         status = Ext2WinntError(rc);
1849         if (NT_SUCCESS(status)) {
1850 
1851             /* increase dir inode's nlink for .. */
1852             if (S_ISDIR(Inode->i_mode)) {
1853                 ext3_inc_count(Dcb->Inode);
1854                 ext3_mark_inode_dirty(IrpContext, Dcb->Inode);
1855             }
1856 
1857             /* increase inode nlink reference */
1858             ext3_inc_count(Inode);
1859             ext3_mark_inode_dirty(IrpContext, Inode);
1860 
1861             if (Dentry) {
1862                 *Dentry = de;
1863                 de = NULL;
1864             }
1865         }
1866 
1867     } _SEH2_FINALLY {
1868 
1869         Ext2DerefXcb(&Dcb->ReferenceCount);
1870 
1871         if (MainResourceAcquired)    {
1872             ExReleaseResourceLite(&Dcb->MainResource);
1873         }
1874 
1875         if (de)
1876             Ext2FreeEntry(de);
1877     } _SEH2_END;
1878 
1879     return status;
1880 }
1881 
1882 
1883 NTSTATUS
1884 Ext2SetFileType (
1885     IN PEXT2_IRP_CONTEXT    IrpContext,
1886     IN PEXT2_VCB            Vcb,
1887     IN PEXT2_FCB            Dcb,
1888     IN PEXT2_MCB            Mcb,
1889     IN umode_t              mode
1890     )
1891 {
1892     struct inode *dir = Dcb->Inode;
1893     struct buffer_head *bh = NULL;
1894     struct ext3_dir_entry_2 *de;
1895     struct inode *inode;
1896     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1897     BOOLEAN  MainResourceAcquired = FALSE;
1898 
1899     if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
1900         return STATUS_SUCCESS;
1901     }
1902 
1903     if (!IsDirectory(Dcb)) {
1904         return STATUS_NOT_A_DIRECTORY;
1905     }
1906 
1907     ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1908     MainResourceAcquired = TRUE;
1909 
1910     _SEH2_TRY {
1911 
1912         Ext2ReferXcb(&Dcb->ReferenceCount);
1913 
1914         bh = ext3_find_entry(IrpContext, Mcb->de, &de);
1915         if (!bh)
1916             _SEH2_LEAVE;
1917 
1918         inode = &Mcb->Inode;
1919         if (le32_to_cpu(de->inode) != inode->i_ino)
1920             _SEH2_LEAVE;
1921 
1922         ext3_set_de_type(inode->i_sb, de, mode);
1923         mark_buffer_dirty(bh);
1924 
1925         if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) {
1926         } else if (S_ISDIR(inode->i_mode)) {
1927             ext3_dec_count(dir);
1928         } else if (S_ISDIR(mode)) {
1929             ext3_inc_count(dir);
1930         }
1931         dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
1932         ext3_mark_inode_dirty(IrpContext, dir);
1933 
1934         inode->i_mode = mode;
1935         ext3_mark_inode_dirty(IrpContext, inode);
1936 
1937         Status = STATUS_SUCCESS;
1938 
1939     } _SEH2_FINALLY {
1940 
1941         Ext2DerefXcb(&Dcb->ReferenceCount);
1942 
1943         if (MainResourceAcquired)
1944             ExReleaseResourceLite(&Dcb->MainResource);
1945 
1946         if (bh)
1947             brelse(bh);
1948     } _SEH2_END;
1949 
1950     return Status;
1951 }
1952 
1953 NTSTATUS
1954 Ext2RemoveEntry (
1955     IN PEXT2_IRP_CONTEXT    IrpContext,
1956     IN PEXT2_VCB            Vcb,
1957     IN PEXT2_FCB            Dcb,
1958     IN PEXT2_MCB            Mcb
1959 )
1960 {
1961     struct inode *dir = Dcb->Inode;
1962     struct buffer_head *bh = NULL;
1963     struct ext3_dir_entry_2 *de;
1964     struct inode *inode;
1965     int rc = -ENOENT;
1966     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1967     BOOLEAN  MainResourceAcquired = FALSE;
1968 
1969     if (!IsDirectory(Dcb)) {
1970         return STATUS_NOT_A_DIRECTORY;
1971     }
1972 
1973     ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1974     MainResourceAcquired = TRUE;
1975 
1976     _SEH2_TRY {
1977 
1978         Ext2ReferXcb(&Dcb->ReferenceCount);
1979 
1980         bh = ext3_find_entry(IrpContext, Mcb->de, &de);
1981         if (!bh)
1982             _SEH2_LEAVE;
1983 
1984         inode = &Mcb->Inode;
1985         if (le32_to_cpu(de->inode) != inode->i_ino)
1986             _SEH2_LEAVE;
1987 
1988         if (!inode->i_nlink) {
1989             ext3_warning (inode->i_sb, "ext3_unlink",
1990                           "Deleting nonexistent file (%lu), %d",
1991                           inode->i_ino, inode->i_nlink);
1992             inode->i_nlink = 1;
1993         }
1994         rc = ext3_delete_entry(IrpContext, dir, de, bh);
1995         if (rc) {
1996             Status = Ext2WinntError(rc);
1997             _SEH2_LEAVE;
1998         }
1999         /*
2000         	    if (!inode->i_nlink)
2001         		    ext3_orphan_add(handle, inode);
2002         */
2003         inode->i_ctime = dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
2004         ext3_dec_count(inode);
2005         ext3_mark_inode_dirty(IrpContext, inode);
2006 
2007         /* decrease dir inode's nlink for .. */
2008         if (S_ISDIR(inode->i_mode)) {
2009             ext3_update_dx_flag(dir);
2010             ext3_dec_count(dir);
2011             ext3_mark_inode_dirty(IrpContext, dir);
2012         }
2013 
2014         Status = STATUS_SUCCESS;
2015 
2016     } _SEH2_FINALLY {
2017 
2018         Ext2DerefXcb(&Dcb->ReferenceCount);
2019 
2020         if (MainResourceAcquired)
2021             ExReleaseResourceLite(&Dcb->MainResource);
2022 
2023         if (bh)
2024             brelse(bh);
2025     } _SEH2_END;
2026 
2027     return Status;
2028 }
2029 
2030 NTSTATUS
2031 Ext2SetParentEntry (
2032     IN PEXT2_IRP_CONTEXT   IrpContext,
2033     IN PEXT2_VCB           Vcb,
2034     IN PEXT2_FCB           Dcb,
2035     IN ULONG               OldParent,
2036     IN ULONG               NewParent )
2037 {
2038     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
2039 
2040     PEXT2_DIR_ENTRY2        pSelf   = NULL;
2041     PEXT2_DIR_ENTRY2        pParent = NULL;
2042 
2043     ULONG                   dwBytes = 0;
2044 
2045     BOOLEAN                 MainResourceAcquired = FALSE;
2046 
2047     ULONG                   Offset = 0;
2048 
2049     if (!IsDirectory(Dcb)) {
2050         return STATUS_NOT_A_DIRECTORY;
2051     }
2052 
2053     if (OldParent == NewParent) {
2054         return STATUS_SUCCESS;
2055     }
2056 
2057     MainResourceAcquired =
2058         ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
2059 
2060     _SEH2_TRY {
2061 
2062         Ext2ReferXcb(&Dcb->ReferenceCount);
2063 
2064         pSelf = (PEXT2_DIR_ENTRY2)
2065                 Ext2AllocatePool(
2066                     PagedPool,
2067                     EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
2068                     EXT2_DENTRY_MAGIC
2069                 );
2070         if (!pSelf) {
2071             DEBUG(DL_ERR, ( "Ex2SetParentEntry: failed to allocate pSelf.\n"));
2072             Status = STATUS_INSUFFICIENT_RESOURCES;
2073             _SEH2_LEAVE;
2074         }
2075 
2076         dwBytes = 0;
2077 
2078         //
2079         // Reading the DCB contents
2080         //
2081 
2082         Status = Ext2ReadInode(
2083                      IrpContext,
2084                      Vcb,
2085                      Dcb->Mcb,
2086                      (ULONGLONG)Offset,
2087                      (PVOID)pSelf,
2088                      EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
2089                      FALSE,
2090                      &dwBytes );
2091 
2092         if (!NT_SUCCESS(Status)) {
2093             DEBUG(DL_ERR, ( "Ext2SetParentEntry: failed to read directory.\n"));
2094             _SEH2_LEAVE;
2095         }
2096 
2097         ASSERT(dwBytes == EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2));
2098 
2099         pParent = (PEXT2_DIR_ENTRY2)((PUCHAR)pSelf + pSelf->rec_len);
2100 
2101         if (pSelf->name_len == 1 && pSelf->name[0] == '.' &&
2102                 pParent->name_len == 2 && pParent->name[0] == '.' &&
2103                 pParent->name[1] == '.') {
2104 
2105             if (pParent->inode != OldParent) {
2106                 DbgBreak();
2107             }
2108             pParent->inode = NewParent;
2109 
2110             Status = Ext2WriteInode(
2111                          IrpContext,
2112                          Vcb,
2113                          Dcb->Mcb,
2114                          (ULONGLONG)Offset,
2115                          pSelf,
2116                          dwBytes,
2117                          FALSE,
2118                          &dwBytes );
2119         } else {
2120             DbgBreak();
2121         }
2122 
2123     } _SEH2_FINALLY {
2124 
2125 
2126         if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) {
2127             DEBUG(DL_ERR, ( "Ext2SetParentEntry: Dcb reference goes to ZERO.\n"));
2128         }
2129 
2130         if (MainResourceAcquired)    {
2131             ExReleaseResourceLite(&Dcb->MainResource);
2132         }
2133 
2134         if (pSelf) {
2135             Ext2FreePool(pSelf, EXT2_DENTRY_MAGIC);
2136         }
2137     } _SEH2_END;
2138 
2139     return Status;
2140 }
2141 
2142 int ext3_check_dir_entry (const char * function, struct inode * dir,
2143                           struct ext3_dir_entry_2 * de,
2144                           struct buffer_head * bh,
2145                           unsigned long offset)
2146 {
2147     const char * error_msg = NULL;
2148     const int rlen = ext3_rec_len_from_disk(de->rec_len);
2149 
2150     if (rlen < EXT3_DIR_REC_LEN(1))
2151         error_msg = "rec_len is smaller than minimal";
2152     else if (rlen % 4 != 0)
2153         error_msg = "rec_len % 4 != 0";
2154     else if (rlen < EXT3_DIR_REC_LEN(de->name_len))
2155         error_msg = "rec_len is too small for name_len";
2156     else if ((char *) de + rlen > bh->b_data + dir->i_sb->s_blocksize)
2157         error_msg = "directory entry across blocks";
2158     else if (le32_to_cpu(de->inode) >
2159              le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
2160         error_msg = "inode out of bounds";
2161 
2162     if (error_msg != NULL) {
2163         DEBUG(DL_ERR, ("%s: bad entry in directory %u: %s - "
2164                        "offset=%u, inode=%u, rec_len=%d, name_len=%d\n",
2165                        function, dir->i_ino, error_msg, offset,
2166                        (unsigned long) le32_to_cpu(de->inode),
2167                        rlen, de->name_len));
2168     }
2169     return error_msg == NULL ? 1 : 0;
2170 }
2171 
2172 
2173 /*
2174  * p is at least 6 bytes before the end of page
2175  */
2176 struct ext3_dir_entry_2 *
2177             ext3_next_entry(struct ext3_dir_entry_2 *p)
2178 {
2179     return (struct ext3_dir_entry_2 *)((char *)p +
2180                                        ext3_rec_len_from_disk(p->rec_len));
2181 }
2182 
2183 #define MAX_LFS_FILESIZE 	0x7fffffffffffffff
2184 
2185 /*
2186  * Maximal extent format file size.
2187  * Resulting logical blkno at s_maxbytes must fit in our on-disk
2188  * extent format containers, within a sector_t, and within i_blocks
2189  * in the vfs.  ext4 inode has 48 bits of i_block in fsblock units,
2190  * so that won't be a limiting factor.
2191  *
2192  * Note, this does *not* consider any metadata overhead for vfs i_blocks.
2193  */
2194 static loff_t ext4_max_size(int blkbits, int has_huge_files)
2195 {
2196     loff_t res;
2197     loff_t upper_limit = MAX_LFS_FILESIZE;
2198 
2199     /* small i_blocks in vfs inode? */
2200     if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
2201         /*
2202          * CONFIG_LBD is not enabled implies the inode
2203          * i_block represent total blocks in 512 bytes
2204          * 32 == size of vfs inode i_blocks * 8
2205          */
2206         upper_limit = (1LL << 32) - 1;
2207 
2208         /* total blocks in file system block size */
2209         upper_limit >>= (blkbits - 9);
2210         upper_limit <<= blkbits;
2211     }
2212 
2213     /* 32-bit extent-start container, ee_block */
2214     res = 1LL << 32;
2215     res <<= blkbits;
2216     res -= 1;
2217 
2218     /* Sanity check against vm- & vfs- imposed limits */
2219     if (res > upper_limit)
2220         res = upper_limit;
2221 
2222     return res;
2223 }
2224 
2225 /*
2226  * Maximal extent format file size.
2227  * Resulting logical blkno at s_maxbytes must fit in our on-disk
2228  * extent format containers, within a sector_t, and within i_blocks
2229  * in the vfs.  ext4 inode has 48 bits of i_block in fsblock units,
2230  * so that won't be a limiting factor.
2231  *
2232  * Note, this does *not* consider any metadata overhead for vfs i_blocks.
2233  */
2234 loff_t ext3_max_size(int blkbits, int has_huge_files)
2235 {
2236     loff_t res;
2237     loff_t upper_limit = MAX_LFS_FILESIZE;
2238 
2239     /* small i_blocks in vfs inode? */
2240     if (!has_huge_files) {
2241         /*
2242          * CONFIG_LBD is not enabled implies the inode
2243          * i_block represent total blocks in 512 bytes
2244          * 32 == size of vfs inode i_blocks * 8
2245          */
2246         upper_limit = ((loff_t)1 << 32) - 1;
2247 
2248         /* total blocks in file system block size */
2249         upper_limit >>= (blkbits - 9);
2250         upper_limit <<= blkbits;
2251     }
2252 
2253     /* 32-bit extent-start container, ee_block */
2254     res = (loff_t)1 << 32;
2255     res <<= blkbits;
2256     res -= 1;
2257 
2258     /* Sanity check against vm- & vfs- imposed limits */
2259     if (res > upper_limit)
2260         res = upper_limit;
2261 
2262     return res;
2263 }
2264 
2265 /*
2266  * Maximal bitmap file size.  There is a direct, and {,double-,triple-}indirect
2267  * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
2268  * We need to be 1 filesystem block less than the 2^48 sector limit.
2269  */
2270 loff_t ext3_max_bitmap_size(int bits, int has_huge_files)
2271 {
2272     loff_t res = EXT3_NDIR_BLOCKS;
2273     int meta_blocks;
2274     loff_t upper_limit;
2275     /* This is calculated to be the largest file size for a
2276      * dense, bitmapped file such that the total number of
2277      * sectors in the file, including data and all indirect blocks,
2278      * does not exceed 2^48 -1
2279      * __u32 i_blocks_lo and _u16 i_blocks_high representing the
2280      * total number of  512 bytes blocks of the file
2281      */
2282 
2283     if (!has_huge_files) {
2284         /*
2285          * !has_huge_files or CONFIG_LBD is not enabled
2286          * implies the inode i_block represent total blocks in
2287          * 512 bytes 32 == size of vfs inode i_blocks * 8
2288          */
2289         upper_limit = ((loff_t)1 << 32) - 1;
2290 
2291         /* total blocks in file system block size */
2292         upper_limit >>= (bits - 9);
2293 
2294     } else {
2295         /*
2296          * We use 48 bit ext4_inode i_blocks
2297          * With EXT4_HUGE_FILE_FL set the i_blocks
2298          * represent total number of blocks in
2299          * file system block size
2300          */
2301         upper_limit = ((loff_t)1 << 48) - 1;
2302 
2303     }
2304 
2305     /* indirect blocks */
2306     meta_blocks = 1;
2307     /* double indirect blocks */
2308     meta_blocks += 1 + ((loff_t)1 << (bits-2));
2309     /* tripple indirect blocks */
2310     meta_blocks += 1 + ((loff_t)1 << (bits-2)) + ((loff_t)1 << (2*(bits-2)));
2311 
2312     upper_limit -= meta_blocks;
2313     upper_limit <<= bits;
2314 
2315     res += (loff_t)1 << (bits-2);
2316     res += (loff_t)1 << (2*(bits-2));
2317     res += (loff_t)1 << (3*(bits-2));
2318     res <<= bits;
2319     if (res > upper_limit)
2320         res = upper_limit;
2321 
2322     if (res > MAX_LFS_FILESIZE)
2323         res = MAX_LFS_FILESIZE;
2324 
2325     return res;
2326 }
2327 
2328 blkcnt_t ext3_inode_blocks(struct ext3_inode *raw_inode,
2329                            struct inode *inode)
2330 {
2331     blkcnt_t i_blocks ;
2332     struct super_block *sb = inode->i_sb;
2333     PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
2334 
2335     if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
2336                                    EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
2337         /* we are using combined 48 bit field */
2338         i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
2339                    le32_to_cpu(raw_inode->i_blocks);
2340         if (inode->i_flags & EXT4_HUGE_FILE_FL) {
2341             /* i_blocks represent file system block size */
2342             return i_blocks  << (BLOCK_BITS - 9);
2343         } else {
2344             return i_blocks;
2345         }
2346     } else {
2347         return le32_to_cpu(raw_inode->i_blocks);
2348     }
2349 }
2350 
2351 int ext3_inode_blocks_set(struct ext3_inode *raw_inode,
2352                           struct inode * inode)
2353 {
2354     u64 i_blocks = inode->i_blocks;
2355     struct super_block *sb = inode->i_sb;
2356     PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
2357 
2358     if (i_blocks < 0x100000000) {
2359         /*
2360          * i_blocks can be represnted in a 32 bit variable
2361          * as multiple of 512 bytes
2362          */
2363         raw_inode->i_blocks = cpu_to_le32(i_blocks);
2364         raw_inode->i_blocks_high = 0;
2365         inode->i_flags &= ~EXT4_HUGE_FILE_FL;
2366         return 0;
2367     }
2368 
2369     if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
2370         EXT3_SET_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2371         Ext2SaveSuper(NULL, Vcb);
2372     }
2373 
2374     if (i_blocks <= 0xffffffffffff) {
2375         /*
2376          * i_blocks can be represented in a 48 bit variable
2377          * as multiple of 512 bytes
2378          */
2379         raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks);
2380         raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
2381         inode->i_flags &= ~EXT4_HUGE_FILE_FL;
2382     } else {
2383         inode->i_flags |= EXT4_HUGE_FILE_FL;
2384         /* i_block is stored in file system block size */
2385         i_blocks = i_blocks >> (BLOCK_BITS - 9);
2386         raw_inode->i_blocks  = (__u32)cpu_to_le32(i_blocks);
2387         raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
2388     }
2389     return 0;
2390 }
2391 
2392 ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
2393                                struct ext4_group_desc *bg)
2394 {
2395     return le32_to_cpu(bg->bg_block_bitmap) |
2396            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2397             (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
2398 }
2399 
2400 ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
2401                                struct ext4_group_desc *bg)
2402 {
2403     return le32_to_cpu(bg->bg_inode_bitmap) |
2404            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2405             (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
2406 }
2407 
2408 ext4_fsblk_t ext4_inode_table(struct super_block *sb,
2409                               struct ext4_group_desc *bg)
2410 {
2411     return le32_to_cpu(bg->bg_inode_table) |
2412            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2413             (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
2414 }
2415 
2416 __u32 ext4_free_blks_count(struct super_block *sb,
2417                            struct ext4_group_desc *bg)
2418 {
2419     return le16_to_cpu(bg->bg_free_blocks_count) |
2420            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2421             (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
2422 }
2423 
2424 __u32 ext4_free_inodes_count(struct super_block *sb,
2425                              struct ext4_group_desc *bg)
2426 {
2427     return le16_to_cpu(bg->bg_free_inodes_count) |
2428            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2429             (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
2430 }
2431 
2432 __u32 ext4_used_dirs_count(struct super_block *sb,
2433                            struct ext4_group_desc *bg)
2434 {
2435     return le16_to_cpu(bg->bg_used_dirs_count) |
2436            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2437             (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
2438 }
2439 
2440 __u32 ext4_itable_unused_count(struct super_block *sb,
2441                                struct ext4_group_desc *bg)
2442 {
2443     return le16_to_cpu(bg->bg_itable_unused) |
2444            (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
2445             (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
2446 }
2447 
2448 void ext4_block_bitmap_set(struct super_block *sb,
2449                            struct ext4_group_desc *bg, ext4_fsblk_t blk)
2450 {
2451     bg->bg_block_bitmap = cpu_to_le32((u32)blk);
2452     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2453         bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
2454 }
2455 
2456 void ext4_inode_bitmap_set(struct super_block *sb,
2457                            struct ext4_group_desc *bg, ext4_fsblk_t blk)
2458 {
2459     bg->bg_inode_bitmap  = cpu_to_le32((u32)blk);
2460     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2461         bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
2462 }
2463 
2464 void ext4_inode_table_set(struct super_block *sb,
2465                           struct ext4_group_desc *bg, ext4_fsblk_t blk)
2466 {
2467     bg->bg_inode_table = cpu_to_le32((u32)blk);
2468     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2469         bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
2470 }
2471 
2472 void ext4_free_blks_set(struct super_block *sb,
2473                         struct ext4_group_desc *bg, __u32 count)
2474 {
2475     bg->bg_free_blocks_count = cpu_to_le16((__u16)count);
2476     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2477         bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);
2478 }
2479 
2480 void ext4_free_inodes_set(struct super_block *sb,
2481                           struct ext4_group_desc *bg, __u32 count)
2482 {
2483     bg->bg_free_inodes_count = cpu_to_le16((__u16)count);
2484     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2485         bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16);
2486 }
2487 
2488 void ext4_used_dirs_set(struct super_block *sb,
2489                         struct ext4_group_desc *bg, __u32 count)
2490 {
2491     bg->bg_used_dirs_count = cpu_to_le16((__u16)count);
2492     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2493         bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);
2494 }
2495 
2496 void ext4_itable_unused_set(struct super_block *sb,
2497                             struct ext4_group_desc *bg, __u32 count)
2498 {
2499     bg->bg_itable_unused = cpu_to_le16((__u16)count);
2500     if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
2501         bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
2502 }
2503 
2504 /** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
2505 __u16 const crc16_table[256] = {
2506     0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
2507     0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
2508     0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
2509     0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
2510     0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
2511     0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
2512     0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
2513     0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
2514     0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
2515     0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
2516     0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
2517     0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
2518     0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
2519     0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
2520     0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
2521     0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
2522     0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
2523     0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
2524     0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
2525     0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
2526     0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
2527     0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
2528     0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
2529     0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
2530     0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
2531     0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
2532     0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
2533     0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
2534     0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
2535     0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
2536     0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
2537     0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
2538 };
2539 
2540 static inline __u16 crc16_byte(__u16 crc, const __u8 data)
2541 {
2542     return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
2543 }
2544 
2545 __u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
2546 {
2547     while (len--)
2548         crc = crc16_byte(crc, *buffer++);
2549     return crc;
2550 }
2551 
2552 __le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
2553                             struct ext4_group_desc *gdp)
2554 {
2555 	int offset;
2556 	__u16 crc = 0;
2557 	__le32 le_group = cpu_to_le32(block_group);
2558 
2559 	/* old crc16 code */
2560 	if (!(sbi->s_es->s_feature_ro_compat &
2561 	      cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
2562 		return 0;
2563 
2564 	offset = offsetof(struct ext4_group_desc, bg_checksum);
2565 
2566 	crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
2567 	crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
2568 	crc = crc16(crc, (__u8 *)gdp, offset);
2569 	offset += sizeof(gdp->bg_checksum); /* skip checksum */
2570 	/* for checksum of struct ext4_group_desc do the rest...*/
2571 	if ((sbi->s_es->s_feature_incompat &
2572 	     cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
2573 	    offset < le16_to_cpu(sbi->s_es->s_desc_size))
2574 		crc = crc16(crc, (__u8 *)gdp + offset,
2575 			    le16_to_cpu(sbi->s_es->s_desc_size) -
2576 				offset);
2577 
2578 	return cpu_to_le16(crc);
2579 }
2580 
2581 int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
2582                                 struct ext4_group_desc *gdp)
2583 {
2584     if ((sbi->s_es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
2585         (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
2586         return 0;
2587 
2588     return 1;
2589 }
2590 
2591 
2592 static inline int test_root(ext3_group_t a, ext3_group_t b)
2593 {
2594     ext3_group_t num = b;
2595 
2596     while (a > num)
2597         num *= b;
2598     return num == a;
2599 }
2600 
2601 static int ext3_group_sparse(ext3_group_t group)
2602 {
2603     if (group <= 1)
2604         return 1;
2605     if (!(group & 1))
2606         return 0;
2607     return (test_root(group, 7) || test_root(group, 5) ||
2608             test_root(group, 3));
2609 }
2610 
2611 /**
2612  *	ext4_bg_has_super - number of blocks used by the superblock in group
2613  *	@sb: superblock for filesystem
2614  *	@group: group number to check
2615  *
2616  *	Return the number of blocks used by the superblock (primary or backup)
2617  *	in this group.  Currently this will be only 0 or 1.
2618  */
2619 int ext3_bg_has_super(struct super_block *sb, ext3_group_t group)
2620 {
2621     if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
2622                                    EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
2623             !ext3_group_sparse(group))
2624         return 0;
2625     return 1;
2626 }
2627 
2628 static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,
2629         ext4_group_t group)
2630 {
2631     unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
2632     ext4_group_t first = metagroup * EXT4_DESC_PER_BLOCK(sb);
2633     ext4_group_t last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
2634 
2635     if (group == first || group == first + 1 || group == last)
2636         return 1;
2637     return 0;
2638 }
2639 
2640 static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
2641         ext4_group_t group)
2642 {
2643     return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;
2644 }
2645 
2646 /**
2647  *	ext4_bg_num_gdb - number of blocks used by the group table in group
2648  *	@sb: superblock for filesystem
2649  *	@group: group number to check
2650  *
2651  *	Return the number of blocks used by the group descriptor table
2652  *	(primary or backup) in this group.  In the future there may be a
2653  *	different number of descriptor blocks in each group.
2654  */
2655 unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
2656 {
2657     unsigned long first_meta_bg =
2658         le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg);
2659     unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
2660 
2661     if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
2662             metagroup < first_meta_bg)
2663         return ext4_bg_num_gdb_nometa(sb, group);
2664 
2665     return ext4_bg_num_gdb_meta(sb,group);
2666 
2667 }
2668 
2669 ext3_fsblk_t descriptor_loc(struct super_block *sb,
2670                             ext3_fsblk_t logical_sb_block, unsigned int nr)
2671 {
2672     struct ext3_sb_info *sbi = EXT3_SB(sb);
2673     ext3_group_t bg, first_meta_bg;
2674     int has_super = 0;
2675 
2676     first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
2677 
2678     if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
2679             nr < first_meta_bg)
2680         return logical_sb_block + nr + 1;
2681     bg = sbi->s_desc_per_block * nr;
2682     if (ext3_bg_has_super(sb, bg))
2683         has_super = 1;
2684     return (has_super + ext3_group_first_block_no(sb, bg));
2685 }
2686 
2687 #define ext4_set_bit(n, p) set_bit((int)(n), (unsigned long *)(p))
2688 
2689 /*
2690  * The free inodes are managed by bitmaps.  A file system contains several
2691  * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap
2692  * block for inodes, N blocks for the inode table and data blocks.
2693  *
2694  * The file system contains group descriptors which are located after the
2695  * super block.  Each descriptor contains the number of the bitmap block and
2696  * the free blocks count in the block.
2697  */
2698 
2699 /*
2700  * To avoid calling the atomic setbit hundreds or thousands of times, we only
2701  * need to use it within a single byte (to ensure we get endianness right).
2702  * We can use memset for the rest of the bitmap as there are no other users.
2703  */
2704 void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
2705 {
2706     int i;
2707 
2708     if (start_bit >= end_bit)
2709         return;
2710 
2711     DEBUG(DL_INF, ("mark end bits +%d through +%d used\n", start_bit, end_bit));
2712     for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
2713         ext4_set_bit(i, bitmap);
2714     if (i < end_bit)
2715         memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
2716 }
2717 
2718 /* Initializes an uninitialized inode bitmap */
2719 unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
2720                                 ext4_group_t block_group,
2721                                 struct ext4_group_desc *gdp)
2722 {
2723     struct ext3_sb_info *sbi = EXT3_SB(sb);
2724 
2725     mark_buffer_dirty(bh);
2726 
2727     /* If checksum is bad mark all blocks and inodes use to prevent
2728      * allocation, essentially implementing a per-group read-only flag. */
2729     if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
2730         ext4_error(sb, __FUNCTION__, "Checksum bad for group %u",
2731                    block_group);
2732         ext4_free_blks_set(sb, gdp, 0);
2733         ext4_free_inodes_set(sb, gdp, 0);
2734         ext4_itable_unused_set(sb, gdp, 0);
2735         memset(bh->b_data, 0xff, sb->s_blocksize);
2736         return 0;
2737     }
2738 
2739     memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
2740     mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
2741                     bh->b_data);
2742     ext4_itable_unused_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
2743 
2744     return EXT4_INODES_PER_GROUP(sb);
2745 }
2746 
2747 /*
2748  * Calculate the block group number and offset, given a block number
2749  */
2750 void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
2751                                   ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp)
2752 {
2753     struct ext3_super_block *es = EXT3_SB(sb)->s_es;
2754     ext4_grpblk_t offset;
2755 
2756     blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
2757     offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
2758     if (offsetp)
2759         *offsetp = offset;
2760     if (blockgrpp)
2761         *blockgrpp = (ext4_grpblk_t)blocknr;
2762 
2763 }
2764 
2765 static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
2766                                ext4_group_t block_group)
2767 {
2768     ext4_group_t actual_group;
2769     ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
2770     if (actual_group == block_group)
2771         return 1;
2772     return 0;
2773 }
2774 
2775 static int ext4_group_used_meta_blocks(struct super_block *sb,
2776                                        ext4_group_t block_group)
2777 {
2778     ext4_fsblk_t tmp;
2779     struct ext3_sb_info *sbi = EXT3_SB(sb);
2780     /* block bitmap, inode bitmap, and inode table blocks */
2781     int used_blocks = sbi->s_itb_per_group + 2;
2782 
2783     if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
2784         struct ext4_group_desc *gdp;
2785         struct buffer_head *bh = NULL;
2786 
2787         gdp = ext4_get_group_desc(sb, block_group, &bh);
2788         if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
2789                                  block_group))
2790             used_blocks--;
2791 
2792         if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp),
2793                                  block_group))
2794             used_blocks--;
2795 
2796         tmp = ext4_inode_table(sb, gdp);
2797         for (; tmp < ext4_inode_table(sb, gdp) +
2798                 sbi->s_itb_per_group; tmp++) {
2799             if (!ext4_block_in_group(sb, tmp, block_group))
2800                 used_blocks -= 1;
2801         }
2802         if (bh)
2803             fini_bh(&bh);
2804     }
2805     return used_blocks;
2806 }
2807 
2808 /* Initializes an uninitialized block bitmap if given, and returns the
2809  * number of blocks free in the group. */
2810 unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
2811                                 ext4_group_t block_group, struct ext4_group_desc *gdp)
2812 {
2813     int bit, bit_max;
2814     unsigned free_blocks, group_blocks;
2815     struct ext3_sb_info *sbi = EXT3_SB(sb);
2816 
2817     if (bh) {
2818         mark_buffer_dirty(bh);
2819         /* If checksum is bad mark all blocks used to prevent allocation
2820          * essentially implementing a per-group read-only flag. */
2821         if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
2822             ext4_error(sb, __FUNCTION__,
2823                        "Checksum bad for group %u", block_group);
2824             ext4_free_blks_set(sb, gdp, 0);
2825             ext4_free_inodes_set(sb, gdp, 0);
2826             ext4_itable_unused_set(sb, gdp, 0);
2827             memset(bh->b_data, 0xff, sb->s_blocksize);
2828             return 0;
2829         }
2830         memset(bh->b_data, 0, sb->s_blocksize);
2831     }
2832 
2833     /* Check for superblock and gdt backups in this group */
2834     bit_max = ext3_bg_has_super(sb, block_group);
2835 
2836     if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
2837             block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
2838             sbi->s_desc_per_block) {
2839         if (bit_max) {
2840             bit_max += ext4_bg_num_gdb(sb, block_group);
2841             bit_max +=
2842                 le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
2843         }
2844     } else { /* For META_BG_BLOCK_GROUPS */
2845         bit_max += ext4_bg_num_gdb(sb, block_group);
2846     }
2847 
2848     if (block_group == sbi->s_groups_count - 1) {
2849         /*
2850          * Even though mke2fs always initialize first and last group
2851          * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
2852          * to make sure we calculate the right free blocks
2853          */
2854         group_blocks = (unsigned int)(ext3_blocks_count(sbi->s_es) -
2855                                       le32_to_cpu(sbi->s_es->s_first_data_block) -
2856                                       (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1)));
2857     } else {
2858         group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
2859     }
2860 
2861     free_blocks = group_blocks - bit_max;
2862 
2863     if (bh) {
2864         ext4_fsblk_t start, tmp;
2865         int flex_bg = 0;
2866 
2867         for (bit = 0; bit < bit_max; bit++)
2868             ext4_set_bit(bit, bh->b_data);
2869 
2870         start = ext3_group_first_block_no(sb, block_group);
2871 
2872         if (EXT3_HAS_INCOMPAT_FEATURE(sb,
2873                                       EXT4_FEATURE_INCOMPAT_FLEX_BG))
2874             flex_bg = 1;
2875 
2876         /* Set bits for block and inode bitmaps, and inode table */
2877         tmp = ext4_block_bitmap(sb, gdp);
2878         if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
2879             ext4_set_bit(tmp - start, bh->b_data);
2880 
2881         tmp = ext4_inode_bitmap(sb, gdp);
2882         if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
2883             ext4_set_bit(tmp - start, bh->b_data);
2884 
2885         tmp = ext4_inode_table(sb, gdp);
2886         for (; tmp < ext4_inode_table(sb, gdp) +
2887                 sbi->s_itb_per_group; tmp++) {
2888             if (!flex_bg ||
2889                     ext4_block_in_group(sb, tmp, block_group))
2890                 ext4_set_bit(tmp - start, bh->b_data);
2891         }
2892         /*
2893          * Also if the number of blocks within the group is
2894          * less than the blocksize * 8 ( which is the size
2895          * of bitmap ), set rest of the block bitmap to 1
2896          */
2897         mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
2898     }
2899     return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
2900 }
2901 
2902 /**
2903  * ext4_get_group_desc() -- load group descriptor from disk
2904  * @sb:			super block
2905  * @block_group:	given block group
2906  * @bh:			pointer to the buffer head to store the block
2907  *			group descriptor
2908  */
2909 struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
2910                     ext4_group_t block_group, struct buffer_head **bh)
2911 {
2912     struct ext4_group_desc *desc = NULL;
2913     struct ext3_sb_info *sbi = EXT3_SB(sb);
2914     PEXT2_VCB vcb = sb->s_priv;
2915     ext4_group_t group;
2916     ext4_group_t offset;
2917 
2918     if (bh)
2919         *bh = NULL;
2920 
2921     if (block_group >= sbi->s_groups_count) {
2922         ext4_error(sb, "ext4_get_group_desc",
2923                    "block_group >= groups_count - "
2924                    "block_group = %u, groups_count = %u",
2925                    block_group, sbi->s_groups_count);
2926 
2927         return NULL;
2928     }
2929 
2930     _SEH2_TRY {
2931 
2932         group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
2933         offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
2934 
2935         if (!sbi->s_gd) {
2936             if (!Ext2LoadGroup(vcb)) {
2937                 _SEH2_LEAVE;
2938             }
2939         } else if ( !sbi->s_gd[group].block ||
2940                     !sbi->s_gd[group].bh) {
2941             if (!Ext2LoadGroupBH(vcb)) {
2942                 _SEH2_LEAVE;
2943             }
2944         }
2945 
2946         desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
2947                                           offset * EXT4_DESC_SIZE(sb));
2948         if (bh) {
2949             atomic_inc(&sbi->s_gd[group].bh->b_count);
2950             *bh = sbi->s_gd[group].bh;
2951         }
2952     } _SEH2_FINALLY {
2953         /* do cleanup */
2954     } _SEH2_END;
2955 
2956     return desc;
2957 }
2958 
2959 
2960 /**
2961  * ext4_count_free_blocks() -- count filesystem free blocks
2962  * @sb:		superblock
2963  *
2964  * Adds up the number of free blocks from each block group.
2965  */
2966 ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
2967 {
2968     ext4_fsblk_t desc_count;
2969     struct ext4_group_desc *gdp;
2970     struct buffer_head *bh = NULL;
2971     ext4_group_t i;
2972     ext4_group_t ngroups = EXT3_SB(sb)->s_groups_count;
2973 
2974     desc_count = 0;
2975     smp_rmb();
2976     for (i = 0; i < ngroups; i++) {
2977         gdp = ext4_get_group_desc(sb, i, &bh);
2978         if (!bh)
2979             continue;
2980         desc_count += ext4_free_blks_count(sb, gdp);
2981         fini_bh(&bh);
2982     }
2983 
2984     return desc_count;
2985 }
2986 
2987 unsigned long ext4_count_free_inodes(struct super_block *sb)
2988 {
2989     unsigned long desc_count;
2990     struct ext4_group_desc *gdp;
2991     struct buffer_head *bh = NULL;
2992     ext4_group_t i;
2993 
2994     desc_count = 0;
2995     for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
2996         gdp = ext4_get_group_desc(sb, i, &bh);
2997         if (!bh)
2998             continue;
2999         desc_count += ext4_free_inodes_count(sb, gdp);
3000         fini_bh(&bh);
3001     }
3002     return desc_count;
3003 }
3004 
3005 /* Called at mount-time, super-block is locked */
3006 unsigned long ext4_count_dirs(struct super_block * sb)
3007 {
3008     struct ext4_group_desc *gdp;
3009     struct buffer_head *bh = NULL;
3010     unsigned long count = 0;
3011     ext4_group_t i;
3012 
3013     for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
3014         gdp = ext4_get_group_desc(sb, i, &bh);
3015         if (!bh)
3016             continue;
3017         count += ext4_used_dirs_count(sb, gdp);
3018         fini_bh(&bh);
3019     }
3020     return count;
3021 }
3022 
3023 /* Called at mount-time, super-block is locked */
3024 int ext4_check_descriptors(struct super_block *sb)
3025 {
3026     PEXT2_VCB            Vcb = sb->s_priv;
3027     struct ext3_sb_info *sbi = EXT3_SB(sb);
3028     ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
3029     ext4_fsblk_t last_block;
3030     ext4_fsblk_t block_bitmap;
3031     ext4_fsblk_t inode_bitmap;
3032     ext4_fsblk_t inode_table;
3033     int flexbg_flag = 0;
3034     ext4_group_t i;
3035 
3036     if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
3037         flexbg_flag = 1;
3038 
3039     DEBUG(DL_INF, ("Checking group descriptors"));
3040 
3041     for (i = 0; i < sbi->s_groups_count; i++) {
3042 
3043         struct buffer_head *bh = NULL;
3044         struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
3045 
3046         if (!bh)
3047             continue;
3048 
3049         if (i == sbi->s_groups_count - 1 || flexbg_flag)
3050             last_block = ext3_blocks_count(sbi->s_es) - 1;
3051         else
3052             last_block = first_block +
3053                          (EXT3_BLOCKS_PER_GROUP(sb) - 1);
3054 
3055         block_bitmap = ext4_block_bitmap(sb, gdp);
3056         if (block_bitmap < first_block || block_bitmap > last_block) {
3057             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3058                    "Block bitmap for group %u not in group "
3059                    "(block %llu)!\n", i, block_bitmap);
3060             __brelse(bh);
3061             return 0;
3062         }
3063         inode_bitmap = ext4_inode_bitmap(sb, gdp);
3064         if (inode_bitmap < first_block || inode_bitmap > last_block) {
3065             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3066                    "Inode bitmap for group %u not in group "
3067                    "(block %llu)!\n", i, inode_bitmap);
3068             __brelse(bh);
3069             return 0;
3070         }
3071         inode_table = ext4_inode_table(sb, gdp);
3072         if (inode_table < first_block ||
3073                 inode_table + sbi->s_itb_per_group - 1 > last_block) {
3074             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3075                    "Inode table for group %u not in group "
3076                    "(block %llu)!\n", i, inode_table);
3077             __brelse(bh);
3078             return 0;
3079         }
3080 
3081         if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
3082             printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
3083                    "Checksum for group %u failed (%u!=%u)\n",
3084                    i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
3085                                                        gdp)),
3086                    le16_to_cpu(gdp->bg_checksum));
3087             if (!IsVcbReadOnly(Vcb)) {
3088                 __brelse(bh);
3089                 return 0;
3090             }
3091         }
3092 
3093         if (!flexbg_flag)
3094             first_block += EXT4_BLOCKS_PER_GROUP(sb);
3095 
3096         __brelse(bh);
3097     }
3098 
3099     ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
3100     sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
3101     return 1;
3102 }
3103