Silence GCC warnings.
[reactos.git] / reactos / lib / fslib / ext2lib / Inode.c
1 /*
2 * PROJECT: Mke2fs
3 * FILE: Inode.c
4 * PROGRAMMER: Matt Wu <mattwu@163.com>
5 * HOMEPAGE: http://ext2.yeah.net
6 */
7
8 /* INCLUDES **************************************************************/
9
10 #include "Mke2fs.h"
11 #include <debug.h>
12
13 /* DEFINITIONS ***********************************************************/
14
15 extern char *device_name;
16
17 /* FUNCTIONS *************************************************************/
18
19
20 bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset)
21 {
22 LONGLONG loc = 0;
23 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
24
25 if (no < 1 || no > pExt2Sb->s_inodes_count)
26 {
27 DPRINT1("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n",
28 no, pExt2Sb->s_inodes_count);
29 *offset = 0;
30 return false;
31 }
32
33 loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table +
34 ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE);
35
36 *offset = loc;
37
38 return true;
39 }
40
41 bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode)
42 {
43 LONGLONG Offset;
44 bool bRet = false;
45
46 if (ext2_get_inode_lba(Ext2Sys, no, &Offset))
47 {
48 bRet = NT_SUCCESS(Ext2ReadDisk(
49 Ext2Sys,
50 Offset,
51 sizeof(EXT2_INODE),
52 (unsigned char *)pInode));
53 }
54
55 return bRet;
56 }
57
58
59 bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode)
60 {
61 LONGLONG offset;
62 bool bRet = false;
63
64 if (ext2_get_inode_lba(Ext2Sys, no, &offset))
65 {
66 bRet = NT_SUCCESS(Ext2WriteDisk(
67 Ext2Sys,
68 offset,
69 sizeof(EXT2_INODE),
70 (unsigned char *)pInode));
71 }
72
73 return bRet;
74 }
75
76
77 /*
78 * Right now, just search forward from the parent directory's block
79 * group to find the next free inode.
80 *
81 * Should have a special policy for directories.
82 */
83
84 bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode,
85 PEXT2_INODE_BITMAP map, ULONG *ret)
86 {
87 ULONG dir_group = 0;
88 ULONG i;
89 ULONG start_inode;
90
91 if (!map)
92 map = fs->inode_map;
93
94 if (!map)
95 return false;
96
97 if (dir > 0)
98 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb);
99
100 start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1;
101
102 if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb))
103 start_inode = EXT2_FIRST_INODE(fs->ext2_sb);
104
105 i = start_inode;
106
107 do
108 {
109 if (!ext2_test_inode_bitmap(map, i))
110 break;
111
112 i++;
113
114 if (i > fs->ext2_sb->s_inodes_count)
115 i = EXT2_FIRST_INODE(fs->ext2_sb);
116
117 } while (i != start_inode);
118
119 if (ext2_test_inode_bitmap(map, i))
120 return false;
121
122 *ret = i;
123
124 return true;
125 }
126
127
128 bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode,
129 ULONG dwContent, ULONG Index, int layer,
130 ULONG newBlk, ULONG *dwRet, ULONG *off )
131 {
132 ULONG *pData = NULL;
133 ULONG i = 0, j = 0, temp = 1;
134 ULONG dwBlk;
135 ULONG dwNewBlk = newBlk;
136 bool bDirty = false;
137 bool bRet = true;
138 ULONG Offset = 0;
139
140 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
141
142 pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize);
143
144 if (!pData)
145 {
146 bRet = false;
147 goto errorout;
148 }
149
150 if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))
151 {
152 bRet = false;
153 goto errorout;
154 }
155
156 if (layer == 1)
157 {
158 *dwRet = dwContent;
159 *off = Index;
160 pData[Index] = newBlk;
161
162 bDirty = TRUE;
163 }
164 else if (layer <= 3)
165 {
166 temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));
167
168 i = Index / temp;
169 j = Index % temp;
170
171 dwBlk = pData[i];
172
173 if (dwBlk == 0)
174 {
175 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )
176 {
177 pData[i] = dwBlk;
178 bDirty = true;
179
180 Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);
181 }
182
183 if (!bDirty)
184 goto errorout;
185 }
186
187 if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset))
188 {
189 bRet = false;
190 DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n");
191 goto errorout;
192 }
193 }
194
195 if (bDirty)
196 {
197 bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData);
198 }
199
200
201 errorout:
202
203 if (pData)
204 RtlFreeHeap(RtlGetProcessHeap(), 0, pData);
205
206 if (bRet && dwRet)
207 *dwRet = dwNewBlk;
208
209 return bRet;
210 }
211
212 bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys,
213 PEXT2_INODE Inode,
214 ULONG newBlk )
215 {
216 ULONG dwSizes[4] = {12, 1, 1, 1};
217 ULONG Index = 0;
218 ULONG dwTotal = 0;
219 ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0;
220 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
221 int i = 0;
222 bool bRet = true;
223 bool bDirty = false;
224 ULONG TotalBlocks;
225
226 TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE);
227 Index = Ext2DataBlocks(Ext2Sys, TotalBlocks);
228
229 for (i = 0; i < 4; i++)
230 {
231 dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i);
232 dwTotal += dwSizes[i];
233 }
234
235 if (Index >= dwTotal)
236 {
237 DPRINT1("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n");
238 return false;
239 }
240
241 for (i = 0; i < 4; i++)
242 {
243 if (Index < dwSizes[i])
244 {
245 if (i == 0)
246 {
247 Inode->i_block[Index] = newBlk;
248 bDirty = true;
249 }
250 else
251 {
252 dwBlk = Inode->i_block[(i + 12 - 1)];
253
254 if (dwBlk == 0)
255 {
256 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk))
257 {
258 Inode->i_block[(i + 12 - 1)] = dwBlk;
259 bDirty = true;
260
261 Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);
262 }
263 else
264 {
265 break;
266 }
267 }
268
269 dwNewBlk = 0;
270 bRet = ext2_expand_block(
271 Ext2Sys,
272 Inode,
273 dwBlk,
274 Index,
275 i,
276 newBlk,
277 &dwNewBlk,
278 &Offset );
279 }
280
281 break;
282 }
283
284 Index -= dwSizes[i];
285 }
286
287 return bRet;
288 }
289
290
291 bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet)
292 {
293 ULONG *pData = NULL;
294 LONGLONG Offset = 0;
295 ULONG i = 0, j = 0, temp = 1;
296 ULONG dwBlk = 0;
297 bool bRet = true;
298
299 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
300
301 Offset = (LONGLONG) dwContent;
302 Offset = Offset * Ext2Sys->blocksize;
303
304 pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize);
305
306 if (!pData)
307 {
308 return false;
309 }
310 memset(pData, 0, Ext2Sys->blocksize);
311
312 if (layer == 0)
313 {
314 dwBlk = dwContent;
315 }
316 else if (layer <= 3)
317 {
318
319 if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))
320 {
321 bRet = false;
322 goto errorout;
323 }
324
325 temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));
326
327 i = Index / temp;
328 j = Index % temp;
329
330 if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk))
331 {
332 bRet = false;
333 DPRINT1("Mke2fs: ext2_get_block: ... error recuise...\n");
334 goto errorout;
335 }
336 }
337
338 errorout:
339
340 if (pData)
341 RtlFreeHeap(RtlGetProcessHeap(), 0, pData);
342
343 if (bRet && dwRet)
344 *dwRet = dwBlk;
345
346 return bRet;
347 }
348
349 bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet)
350 {
351 ULONG dwSizes[4] = { 12, 1, 1, 1 };
352 ULONG Index = 0;
353 ULONG dwBlk = 0;
354 PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
355 UINT i;
356 bool bRet = false;
357
358 Index = block;
359
360 for (i = 0; i < 4; i++)
361 {
362 dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i);
363 }
364
365 if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE))
366 {
367 DPRINT1("Mke2fs: ext2_block_map: beyond the size of the inode.\n");
368 return false;
369 }
370
371 for (i = 0; i < 4; i++)
372 {
373 if (Index < dwSizes[i])
374 {
375 dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)];
376
377 bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk);
378
379 break;
380 }
381 Index -= dwSizes[i];
382 }
383
384 if (bRet && dwBlk)
385 {
386 if (dwRet)
387 *dwRet = dwBlk;
388
389 return true;
390 }
391 else
392 return false;
393 }
394
395 ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys,
396 PEXT2_INODE ext2_inode,
397 IN ULONG offset,
398 IN ULONG size,
399 OUT PEXT2_BDL *ext2_bdl )
400 {
401 ULONG nBeg, nEnd, nBlocks;
402 ULONG dwBlk;
403 ULONG i;
404 ULONG dwBytes = 0;
405 LONGLONG lba;
406
407 PEXT2_BDL ext2bdl = NULL;
408
409 *ext2_bdl = NULL;
410
411 if (offset >= ext2_inode->i_size)
412 {
413 DPRINT1("Mke2fs: ext2_build_bdl: beyond the file range.\n");
414 return 0;
415 }
416
417 /*
418 if (offset + size > ext2_inode->i_size)
419 {
420 size = ext2_inode->i_size - offset;
421 }
422 */
423
424 nBeg = offset / Ext2Sys->blocksize;
425 nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;
426
427 nBlocks = nEnd - nBeg;
428
429 if (nBlocks > 0)
430 {
431 ext2bdl = (PEXT2_BDL)
432 RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks);
433
434 if (ext2bdl)
435 {
436
437 memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks);
438
439 for (i = nBeg; i < nEnd; i++)
440 {
441 if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk))
442 {
443 goto fail;
444 }
445
446 lba = (LONGLONG) dwBlk;
447 lba = lba * Ext2Sys->blocksize;
448
449 if (nBlocks == 1) // ie. (nBeg == nEnd - 1)
450 {
451 dwBytes = size;
452 ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize));
453 ext2bdl[i - nBeg].Length = dwBytes;
454 ext2bdl[i - nBeg].Offset = 0;
455 }
456 else
457 {
458 if (i == nBeg)
459 {
460 dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize));
461 ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize));
462 ext2bdl[i - nBeg].Length = dwBytes;
463 ext2bdl[i - nBeg].Offset = 0;
464 }
465 else if (i == nEnd - 1)
466 {
467 ext2bdl[i - nBeg].Lba = lba;
468 ext2bdl[i - nBeg].Length = size - dwBytes;
469 ext2bdl[i - nBeg].Offset = dwBytes;
470 dwBytes = size;
471 }
472 else
473 {
474 ext2bdl[i - nBeg].Lba = lba;
475 ext2bdl[i - nBeg].Length = Ext2Sys->blocksize;
476 ext2bdl[i - nBeg].Offset = dwBytes;
477 dwBytes += Ext2Sys->blocksize;
478 }
479 }
480 }
481
482 *ext2_bdl = ext2bdl;
483 return nBlocks;
484 }
485 }
486
487 fail:
488
489 if (ext2bdl)
490 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2bdl);
491
492 // Error
493 return 0;
494 }
495
496
497 bool ext2_read_inode(PEXT2_FILESYS Ext2Sys,
498 ULONG ino,
499 ULONG offset,
500 PVOID Buffer,
501 ULONG size,
502 PULONG dwReturn)
503 {
504 PEXT2_BDL ext2_bdl = NULL;
505 ULONG blocks, i;
506 bool bRet = true;
507 EXT2_INODE ext2_inode;
508 ULONG dwTotal = 0;
509
510 if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode))
511 {
512 return false;
513 }
514
515 blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl);
516
517 if (blocks <= 0)
518 return false;
519
520
521 for(i = 0; i < blocks; i++)
522 {
523 bRet = NT_SUCCESS(Ext2ReadDisk(
524 Ext2Sys,
525 ext2_bdl[i].Lba,
526 ext2_bdl[i].Length,
527 (PUCHAR)Buffer + ext2_bdl[i].Offset
528 ));
529
530 if (!bRet)
531 break;
532 dwTotal += ext2_bdl[i].Length;
533 }
534
535 *dwReturn = dwTotal;
536
537 if (ext2_bdl)
538 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl);
539
540 return bRet;
541 }
542
543
544 bool ext2_write_inode (PEXT2_FILESYS Ext2Sys,
545 ULONG ino,
546 ULONG offset,
547 PVOID Buffer,
548 ULONG size,
549 PULONG dwReturn )
550 {
551 PEXT2_BDL ext2_bdl = NULL;
552 ULONG blocks, i;
553 bool bRet = true;
554 EXT2_INODE inode;
555 ULONG dwTotal = 0;
556 ULONG dwBlk = 0;
557 ULONG TotalBlks;
558
559 blocks = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;
560
561 if (!ext2_load_inode(Ext2Sys, ino, &inode))
562 {
563 return false;
564 }
565
566 TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE);
567 TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks);
568
569 if (blocks > TotalBlks)
570 {
571 for (i=0; i < (blocks - TotalBlks); i++)
572 {
573 if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )
574 {
575 ext2_expand_inode(Ext2Sys, &inode, dwBlk);
576 inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE);
577 }
578 }
579 }
580
581 blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl);
582
583 if (blocks <= 0)
584 return false;
585
586 for(i = 0; i < blocks; i++)
587 {
588 bRet = NT_SUCCESS(Ext2WriteDisk(
589 Ext2Sys,
590 ext2_bdl[i].Lba,
591 ext2_bdl[i].Length,
592 (PUCHAR)Buffer + ext2_bdl[i].Offset
593 ));
594
595 if (!bRet)
596 {
597 goto errorout;
598 }
599
600 dwTotal += ext2_bdl[i].Length;
601 }
602
603 *dwReturn = dwTotal;
604
605 if (size + offset > inode.i_size)
606 {
607 inode.i_size = size + offset;
608 }
609
610 ext2_save_inode(Ext2Sys, ino, &inode);
611
612
613 errorout:
614
615 if (ext2_bdl)
616 RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl);
617
618 return bRet;
619 }
620
621 bool
622 ext2_add_entry( PEXT2_FILESYS Ext2Sys,
623 ULONG parent, ULONG inode,
624 int filetype, char *name )
625 {
626 PEXT2_DIR_ENTRY2 dir = NULL, newdir = NULL;
627 EXT2_INODE parent_inode;
628 ULONG dwRet;
629 char *buf;
630 int rec_len;
631 bool bRet = false;
632
633 rec_len = EXT2_DIR_REC_LEN(strlen(name));
634
635 if (!ext2_load_inode(Ext2Sys, parent, &parent_inode))
636 {
637 return false;
638 }
639
640 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, parent_inode.i_size);
641
642 if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet))
643 {
644 return false;
645 }
646
647 dir = (PEXT2_DIR_ENTRY2) buf;
648
649 while ((char *)dir < buf + parent_inode.i_size)
650 {
651 if ((dir->inode == 0 && dir->rec_len >= rec_len) ||
652 (dir->rec_len >= dir->name_len + rec_len) )
653 {
654 if (dir->inode)
655 {
656 newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len));
657 newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len);
658
659 dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len);
660
661 dir = newdir;
662 }
663
664 dir->file_type = filetype;
665 dir->inode = inode;
666 dir->name_len = strlen(name);
667 memcpy(dir->name, name, strlen(name));
668
669 bRet = true;
670 break;
671 }
672
673 dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir);
674 }
675
676
677 if (bRet)
678 return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet);
679
680 return bRet;
681 }
682
683
684 bool ext2_reserve_inodes(PEXT2_FILESYS fs)
685 {
686 ULONG i;
687 int group;
688
689 for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++)
690 {
691 ext2_mark_inode_bitmap(fs->inode_map, i);
692 group = ext2_group_of_ino(fs, i);
693 fs->group_desc[group].bg_free_inodes_count--;
694 fs->ext2_sb->s_free_inodes_count--;
695 }
696
697 return true;
698 }