]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - fs/ext4/ext4_write.c
ext4: Use correct value for inode size even on revision 0 filesystems
[karo-tx-uboot.git] / fs / ext4 / ext4_write.c
1 /*
2  * (C) Copyright 2011 - 2012 Samsung Electronics
3  * EXT4 filesystem implementation in Uboot by
4  * Uma Shankar <uma.shankar@samsung.com>
5  * Manjunatha C Achar <a.manjunatha@samsung.com>
6  *
7  * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8  *                     Ext4 read optimization taken from Open-Moko
9  *                     Qi bootloader
10  *
11  * (C) Copyright 2004
12  * esd gmbh <www.esd-electronics.com>
13  * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
14  *
15  * based on code from grub2 fs/ext2.c and fs/fshelp.c by
16  * GRUB  --  GRand Unified Bootloader
17  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
18  *
19  * ext4write : Based on generic ext4 protocol.
20  *
21  * SPDX-License-Identifier:     GPL-2.0+
22  */
23
24
25 #include <common.h>
26 #include <memalign.h>
27 #include <linux/stat.h>
28 #include <div64.h>
29 #include "ext4_common.h"
30
31 static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock *sb)
32 {
33         sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) + 1);
34 }
35
36 static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock *sb)
37 {
38         sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) + 1);
39 }
40
41 static inline void ext4fs_bg_free_inodes_inc(struct ext2_block_group *bg)
42 {
43         bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) + 1);
44 }
45
46 static inline void ext4fs_bg_free_blocks_inc(struct ext2_block_group *bg)
47 {
48         bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) + 1);
49 }
50
51 static void ext4fs_update(void)
52 {
53         short i;
54         ext4fs_update_journal();
55         struct ext_filesystem *fs = get_fs();
56
57         /* update  super block */
58         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
59                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
60
61         /* update block groups */
62         for (i = 0; i < fs->no_blkgrp; i++) {
63                 fs->bgd[i].bg_checksum = cpu_to_le16(ext4fs_checksum_update(i));
64                 put_ext4((uint64_t)le32_to_cpu(fs->bgd[i].block_id) * fs->blksz,
65                          fs->blk_bmaps[i], fs->blksz);
66         }
67
68         /* update inode table groups */
69         for (i = 0; i < fs->no_blkgrp; i++) {
70                 put_ext4((uint64_t)le32_to_cpu(fs->bgd[i].inode_id) * fs->blksz,
71                          fs->inode_bmaps[i], fs->blksz);
72         }
73
74         /* update the block group descriptor table */
75         put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz),
76                  (struct ext2_block_group *)fs->gdtable,
77                  (fs->blksz * fs->no_blk_pergdt));
78
79         ext4fs_dump_metadata();
80
81         gindex = 0;
82         gd_index = 0;
83 }
84
85 int ext4fs_get_bgdtable(void)
86 {
87         int status;
88         int grp_desc_size;
89         struct ext_filesystem *fs = get_fs();
90         grp_desc_size = sizeof(struct ext2_block_group);
91         fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
92         if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
93                 fs->no_blk_pergdt++;
94
95         /* allocate memory for gdtable */
96         fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
97         if (!fs->gdtable)
98                 return -ENOMEM;
99         /* read the group descriptor table */
100         status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
101                                 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
102         if (status == 0)
103                 goto fail;
104
105         if (ext4fs_log_gdt(fs->gdtable)) {
106                 printf("Error in ext4fs_log_gdt\n");
107                 return -1;
108         }
109
110         return 0;
111 fail:
112         free(fs->gdtable);
113         fs->gdtable = NULL;
114
115         return -1;
116 }
117
118 static void delete_single_indirect_block(struct ext2_inode *inode)
119 {
120         struct ext2_block_group *bgd = NULL;
121         static int prev_bg_bmap_idx = -1;
122         uint32_t blknr;
123         int remainder;
124         int bg_idx;
125         int status;
126         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
127         struct ext_filesystem *fs = get_fs();
128         char *journal_buffer = zalloc(fs->blksz);
129         if (!journal_buffer) {
130                 printf("No memory\n");
131                 return;
132         }
133         /* get  block group descriptor table */
134         bgd = (struct ext2_block_group *)fs->gdtable;
135
136         /* deleting the single indirect block associated with inode */
137         if (inode->b.blocks.indir_block != 0) {
138                 blknr = le32_to_cpu(inode->b.blocks.indir_block);
139                 debug("SIPB releasing %u\n", blknr);
140                 bg_idx = blknr / blk_per_grp;
141                 if (fs->blksz == 1024) {
142                         remainder = blknr % blk_per_grp;
143                         if (!remainder)
144                                 bg_idx--;
145                 }
146                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
147                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
148                 ext4fs_sb_free_blocks_inc(fs->sb);
149                 /* journal backup */
150                 if (prev_bg_bmap_idx != bg_idx) {
151                         status = ext4fs_devread(
152                                            (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
153                                            fs->sect_perblk, 0, fs->blksz,
154                                            journal_buffer);
155                         if (status == 0)
156                                 goto fail;
157                         if (ext4fs_log_journal
158                             (journal_buffer, le32_to_cpu(bgd[bg_idx].block_id)))
159                                 goto fail;
160                         prev_bg_bmap_idx = bg_idx;
161                 }
162         }
163 fail:
164         free(journal_buffer);
165 }
166
167 static void delete_double_indirect_block(struct ext2_inode *inode)
168 {
169         int i;
170         short status;
171         static int prev_bg_bmap_idx = -1;
172         uint32_t blknr;
173         int remainder;
174         int bg_idx;
175         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
176         __le32 *di_buffer = NULL;
177         void *dib_start_addr = NULL;
178         struct ext2_block_group *bgd = NULL;
179         struct ext_filesystem *fs = get_fs();
180         char *journal_buffer = zalloc(fs->blksz);
181         if (!journal_buffer) {
182                 printf("No memory\n");
183                 return;
184         }
185         /* get the block group descriptor table */
186         bgd = (struct ext2_block_group *)fs->gdtable;
187
188         if (inode->b.blocks.double_indir_block != 0) {
189                 di_buffer = zalloc(fs->blksz);
190                 if (!di_buffer) {
191                         printf("No memory\n");
192                         return;
193                 }
194                 dib_start_addr = di_buffer;
195                 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
196                 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
197                                         fs->blksz, (char *)di_buffer);
198                 for (i = 0; i < fs->blksz / sizeof(int); i++) {
199                         if (*di_buffer == 0)
200                                 break;
201
202                         debug("DICB releasing %u\n", *di_buffer);
203                         bg_idx = le32_to_cpu(*di_buffer) / blk_per_grp;
204                         if (fs->blksz == 1024) {
205                                 remainder = le32_to_cpu(*di_buffer) % blk_per_grp;
206                                 if (!remainder)
207                                         bg_idx--;
208                         }
209                         ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer),
210                                         fs->blk_bmaps[bg_idx], bg_idx);
211                         di_buffer++;
212                         ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
213                         ext4fs_sb_free_blocks_inc(fs->sb);
214                         /* journal backup */
215                         if (prev_bg_bmap_idx != bg_idx) {
216                                 status = ext4fs_devread(
217                                                         (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id)
218                                                         * fs->sect_perblk, 0,
219                                                         fs->blksz,
220                                                         journal_buffer);
221                                 if (status == 0)
222                                         goto fail;
223
224                                 if (ext4fs_log_journal(journal_buffer,
225                                                         le32_to_cpu(bgd[bg_idx].block_id)))
226                                         goto fail;
227                                 prev_bg_bmap_idx = bg_idx;
228                         }
229                 }
230
231                 /* removing the parent double indirect block */
232                 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
233                 bg_idx = blknr / blk_per_grp;
234                 if (fs->blksz == 1024) {
235                         remainder = blknr % blk_per_grp;
236                         if (!remainder)
237                                 bg_idx--;
238                 }
239                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
240                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
241                 ext4fs_sb_free_blocks_inc(fs->sb);
242                 /* journal backup */
243                 if (prev_bg_bmap_idx != bg_idx) {
244                         memset(journal_buffer, '\0', fs->blksz);
245                         status = ext4fs_devread((lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
246                                                 fs->sect_perblk, 0, fs->blksz,
247                                                 journal_buffer);
248                         if (status == 0)
249                                 goto fail;
250
251                         if (ext4fs_log_journal(journal_buffer,
252                                                 le32_to_cpu(bgd[bg_idx].block_id)))
253                                 goto fail;
254                         prev_bg_bmap_idx = bg_idx;
255                 }
256                 debug("DIPB releasing %d\n", blknr);
257         }
258 fail:
259         free(dib_start_addr);
260         free(journal_buffer);
261 }
262
263 static void delete_triple_indirect_block(struct ext2_inode *inode)
264 {
265         int i, j;
266         short status;
267         static int prev_bg_bmap_idx = -1;
268         uint32_t blknr;
269         int remainder;
270         int bg_idx;
271         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
272         __le32 *tigp_buffer = NULL;
273         void *tib_start_addr = NULL;
274         __le32 *tip_buffer = NULL;
275         void *tipb_start_addr = NULL;
276         struct ext2_block_group *bgd = NULL;
277         struct ext_filesystem *fs = get_fs();
278         char *journal_buffer = zalloc(fs->blksz);
279         if (!journal_buffer) {
280                 printf("No memory\n");
281                 return;
282         }
283         /* get block group descriptor table */
284         bgd = (struct ext2_block_group *)fs->gdtable;
285
286         if (inode->b.blocks.triple_indir_block != 0) {
287                 tigp_buffer = zalloc(fs->blksz);
288                 if (!tigp_buffer) {
289                         printf("No memory\n");
290                         return;
291                 }
292                 tib_start_addr = tigp_buffer;
293                 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
294                 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
295                                         fs->blksz, (char *)tigp_buffer);
296                 for (i = 0; i < fs->blksz / sizeof(int); i++) {
297                         if (*tigp_buffer == 0)
298                                 break;
299                         debug("tigp buffer releasing %u\n", *tigp_buffer);
300
301                         tip_buffer = zalloc(fs->blksz);
302                         if (!tip_buffer)
303                                 goto fail;
304                         tipb_start_addr = tip_buffer;
305                         status = ext4fs_devread((lbaint_t)le32_to_cpu(*tigp_buffer) *
306                                                 fs->sect_perblk, 0, fs->blksz,
307                                                 (char *)tip_buffer);
308                         for (j = 0; j < fs->blksz / sizeof(int); j++) {
309                                 if (le32_to_cpu(*tip_buffer) == 0)
310                                         break;
311                                 bg_idx = le32_to_cpu(*tip_buffer) / blk_per_grp;
312                                 if (fs->blksz == 1024) {
313                                         remainder = le32_to_cpu(*tip_buffer) % blk_per_grp;
314                                         if (!remainder)
315                                                 bg_idx--;
316                                 }
317
318                                 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer),
319                                                         fs->blk_bmaps[bg_idx],
320                                                         bg_idx);
321
322                                 tip_buffer++;
323                                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
324                                 ext4fs_sb_free_blocks_inc(fs->sb);
325                                 /* journal backup */
326                                 if (prev_bg_bmap_idx != bg_idx) {
327                                         status =
328                                             ext4fs_devread(
329                                                         (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
330                                                         fs->sect_perblk, 0,
331                                                         fs->blksz,
332                                                         journal_buffer);
333                                         if (status == 0)
334                                                 goto fail;
335
336                                         if (ext4fs_log_journal(journal_buffer,
337                                                                le32_to_cpu(bgd[bg_idx].block_id)))
338                                                 goto fail;
339                                         prev_bg_bmap_idx = bg_idx;
340                                 }
341                         }
342                         free(tipb_start_addr);
343                         tipb_start_addr = NULL;
344
345                         /*
346                          * removing the grand parent blocks
347                          * which is connected to inode
348                          */
349                         bg_idx = le32_to_cpu(*tigp_buffer) / blk_per_grp;
350                         if (fs->blksz == 1024) {
351                                 remainder = le32_to_cpu(*tigp_buffer) % blk_per_grp;
352                                 if (!remainder)
353                                         bg_idx--;
354                         }
355                         ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer),
356                                                 fs->blk_bmaps[bg_idx], bg_idx);
357
358                         tigp_buffer++;
359                         ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
360                         ext4fs_sb_free_blocks_inc(fs->sb);
361                         /* journal backup */
362                         if (prev_bg_bmap_idx != bg_idx) {
363                                 memset(journal_buffer, '\0', fs->blksz);
364                                 status =
365                                     ext4fs_devread(
366                                                    (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
367                                                    fs->sect_perblk, 0,
368                                                    fs->blksz, journal_buffer);
369                                 if (status == 0)
370                                         goto fail;
371
372                                 if (ext4fs_log_journal(journal_buffer,
373                                                         le32_to_cpu(bgd[bg_idx].block_id)))
374                                         goto fail;
375                                 prev_bg_bmap_idx = bg_idx;
376                         }
377                 }
378
379                 /* removing the grand parent triple indirect block */
380                 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
381                 bg_idx = blknr / blk_per_grp;
382                 if (fs->blksz == 1024) {
383                         remainder = blknr % blk_per_grp;
384                         if (!remainder)
385                                 bg_idx--;
386                 }
387                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
388                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
389                 ext4fs_sb_free_blocks_inc(fs->sb);
390                 /* journal backup */
391                 if (prev_bg_bmap_idx != bg_idx) {
392                         memset(journal_buffer, '\0', fs->blksz);
393                         status = ext4fs_devread(
394                                                 (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
395                                                 fs->sect_perblk, 0, fs->blksz,
396                                                 journal_buffer);
397                         if (status == 0)
398                                 goto fail;
399
400                         if (ext4fs_log_journal(journal_buffer,
401                                                 le32_to_cpu(bgd[bg_idx].block_id)))
402                                 goto fail;
403                         prev_bg_bmap_idx = bg_idx;
404                 }
405                 debug("tigp buffer itself releasing %d\n", blknr);
406         }
407 fail:
408         free(tib_start_addr);
409         free(tipb_start_addr);
410         free(journal_buffer);
411 }
412
413 static int ext4fs_delete_file(int inodeno)
414 {
415         struct ext2_inode inode;
416         short status;
417         int i;
418         int remainder;
419         long int blknr;
420         int bg_idx;
421         int ibmap_idx;
422         char *read_buffer = NULL;
423         char *start_block_address = NULL;
424         uint32_t no_blocks;
425
426         static int prev_bg_bmap_idx = -1;
427         unsigned int inodes_per_block;
428         uint32_t blkno;
429         unsigned int blkoff;
430         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
431         uint32_t inode_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
432         struct ext2_inode *inode_buffer = NULL;
433         struct ext2_block_group *bgd = NULL;
434         struct ext_filesystem *fs = get_fs();
435         char *journal_buffer = zalloc(fs->blksz);
436         if (!journal_buffer)
437                 return -ENOMEM;
438         /* get the block group descriptor table */
439         bgd = (struct ext2_block_group *)fs->gdtable;
440         status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
441         if (status == 0)
442                 goto fail;
443
444         /* read the block no allocated to a file */
445         no_blocks = le32_to_cpu(inode.size) / fs->blksz;
446         if (le32_to_cpu(inode.size) % fs->blksz)
447                 no_blocks++;
448
449         if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
450                 struct ext2fs_node *node_inode =
451                     zalloc(sizeof(struct ext2fs_node));
452                 if (!node_inode)
453                         goto fail;
454                 node_inode->data = ext4fs_root;
455                 node_inode->ino = inodeno;
456                 node_inode->inode_read = 0;
457                 memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
458
459                 for (i = 0; i < no_blocks; i++) {
460                         blknr = read_allocated_block(&(node_inode->inode), i);
461                         bg_idx = blknr / blk_per_grp;
462                         if (fs->blksz == 1024) {
463                                 remainder = blknr % blk_per_grp;
464                                 if (!remainder)
465                                         bg_idx--;
466                         }
467                         ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
468                                                 bg_idx);
469                         debug("EXT4_EXTENTS Block releasing %ld: %d\n",
470                               blknr, bg_idx);
471
472                         ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
473                         ext4fs_sb_free_blocks_inc(fs->sb);
474
475                         /* journal backup */
476                         if (prev_bg_bmap_idx != bg_idx) {
477                                 status =
478                                     ext4fs_devread(
479                                                    (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
480                                                    fs->sect_perblk, 0,
481                                                    fs->blksz, journal_buffer);
482                                 if (status == 0)
483                                         goto fail;
484                                 if (ext4fs_log_journal(journal_buffer,
485                                                         le32_to_cpu(bgd[bg_idx].block_id)))
486                                         goto fail;
487                                 prev_bg_bmap_idx = bg_idx;
488                         }
489                 }
490                 if (node_inode) {
491                         free(node_inode);
492                         node_inode = NULL;
493                 }
494         } else {
495
496                 delete_single_indirect_block(&inode);
497                 delete_double_indirect_block(&inode);
498                 delete_triple_indirect_block(&inode);
499
500                 /* read the block no allocated to a file */
501                 no_blocks = le32_to_cpu(inode.size) / fs->blksz;
502                 if (le32_to_cpu(inode.size) % fs->blksz)
503                         no_blocks++;
504                 for (i = 0; i < no_blocks; i++) {
505                         blknr = read_allocated_block(&inode, i);
506                         bg_idx = blknr / blk_per_grp;
507                         if (fs->blksz == 1024) {
508                                 remainder = blknr % blk_per_grp;
509                                 if (!remainder)
510                                         bg_idx--;
511                         }
512                         ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
513                                                 bg_idx);
514                         debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
515
516                         ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
517                         ext4fs_sb_free_blocks_inc(fs->sb);
518                         /* journal backup */
519                         if (prev_bg_bmap_idx != bg_idx) {
520                                 memset(journal_buffer, '\0', fs->blksz);
521                                 status = ext4fs_devread(
522                                                         (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id)
523                                                         * fs->sect_perblk,
524                                                         0, fs->blksz,
525                                                         journal_buffer);
526                                 if (status == 0)
527                                         goto fail;
528                                 if (ext4fs_log_journal(journal_buffer,
529                                                 le32_to_cpu(bgd[bg_idx].block_id)))
530                                         goto fail;
531                                 prev_bg_bmap_idx = bg_idx;
532                         }
533                 }
534         }
535
536         /* from the inode no to blockno */
537         inodes_per_block = fs->blksz / fs->inodesz;
538         ibmap_idx = inodeno / inode_per_grp;
539
540         /* get the block no */
541         inodeno--;
542         blkno = le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
543                 (inodeno % inode_per_grp) / inodes_per_block;
544
545         /* get the offset of the inode */
546         blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
547
548         /* read the block no containing the inode */
549         read_buffer = zalloc(fs->blksz);
550         if (!read_buffer)
551                 goto fail;
552         start_block_address = read_buffer;
553         status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk,
554                                 0, fs->blksz, read_buffer);
555         if (status == 0)
556                 goto fail;
557
558         if (ext4fs_log_journal(read_buffer, blkno))
559                 goto fail;
560
561         read_buffer = read_buffer + blkoff;
562         inode_buffer = (struct ext2_inode *)read_buffer;
563         memset(inode_buffer, '\0', sizeof(struct ext2_inode));
564
565         /* write the inode to original position in inode table */
566         if (ext4fs_put_metadata(start_block_address, blkno))
567                 goto fail;
568
569         /* update the respective inode bitmaps */
570         inodeno++;
571         ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
572         ext4fs_bg_free_inodes_inc(&bgd[ibmap_idx]);
573         ext4fs_sb_free_inodes_inc(fs->sb);
574         /* journal backup */
575         memset(journal_buffer, '\0', fs->blksz);
576         status = ext4fs_devread((lbaint_t)le32_to_cpu(bgd[ibmap_idx].inode_id) *
577                                 fs->sect_perblk, 0, fs->blksz, journal_buffer);
578         if (status == 0)
579                 goto fail;
580         if (ext4fs_log_journal(journal_buffer, le32_to_cpu(bgd[ibmap_idx].inode_id)))
581                 goto fail;
582
583         ext4fs_update();
584         ext4fs_deinit();
585         ext4fs_reinit_global();
586
587         if (ext4fs_init() != 0) {
588                 printf("error in File System init\n");
589                 goto fail;
590         }
591
592         free(start_block_address);
593         free(journal_buffer);
594
595         return 0;
596 fail:
597         free(start_block_address);
598         free(journal_buffer);
599
600         return -1;
601 }
602
603 int ext4fs_init(void)
604 {
605         short status;
606         int i;
607         uint32_t real_free_blocks = 0;
608         struct ext_filesystem *fs = get_fs();
609
610         /* populate fs */
611         fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
612         fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
613
614         /* get the superblock */
615         fs->sb = zalloc(SUPERBLOCK_SIZE);
616         if (!fs->sb)
617                 return -ENOMEM;
618         if (!ext4_read_superblock((char *)fs->sb))
619                 goto fail;
620
621         /* init journal */
622         if (ext4fs_init_journal())
623                 goto fail;
624
625         /* get total no of blockgroups */
626         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
627                         le32_to_cpu(ext4fs_root->sblock.total_blocks)
628                         - le32_to_cpu(ext4fs_root->sblock.first_data_block),
629                         le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
630
631         /* get the block group descriptor table */
632         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
633         if (ext4fs_get_bgdtable() == -1) {
634                 printf("Error in getting the block group descriptor table\n");
635                 goto fail;
636         }
637         fs->bgd = (struct ext2_block_group *)fs->gdtable;
638
639         /* load all the available bitmap block of the partition */
640         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
641         if (!fs->blk_bmaps)
642                 goto fail;
643         for (i = 0; i < fs->no_blkgrp; i++) {
644                 fs->blk_bmaps[i] = zalloc(fs->blksz);
645                 if (!fs->blk_bmaps[i])
646                         goto fail;
647         }
648
649         for (i = 0; i < fs->no_blkgrp; i++) {
650                 status =
651                     ext4fs_devread(
652                                    (lbaint_t)le32_to_cpu(fs->bgd[i].block_id) *
653                                    fs->sect_perblk, 0,
654                                    fs->blksz, (char *)fs->blk_bmaps[i]);
655                 if (status == 0)
656                         goto fail;
657         }
658
659         /* load all the available inode bitmap of the partition */
660         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
661         if (!fs->inode_bmaps)
662                 goto fail;
663         for (i = 0; i < fs->no_blkgrp; i++) {
664                 fs->inode_bmaps[i] = zalloc(fs->blksz);
665                 if (!fs->inode_bmaps[i])
666                         goto fail;
667         }
668
669         for (i = 0; i < fs->no_blkgrp; i++) {
670                 status = ext4fs_devread(
671                                         (lbaint_t)le32_to_cpu(fs->bgd[i].inode_id) *
672                                         fs->sect_perblk,
673                                         0, fs->blksz,
674                                         (char *)fs->inode_bmaps[i]);
675                 if (status == 0)
676                         goto fail;
677         }
678
679         /*
680          * check filesystem consistency with free blocks of file system
681          * some time we observed that superblock freeblocks does not match
682          * with the  blockgroups freeblocks when improper
683          * reboot of a linux kernel
684          */
685         for (i = 0; i < fs->no_blkgrp; i++)
686                 real_free_blocks = real_free_blocks + le16_to_cpu(fs->bgd[i].free_blocks);
687         if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks))
688                 fs->sb->free_blocks = cpu_to_le32(real_free_blocks);
689
690         return 0;
691 fail:
692         ext4fs_deinit();
693
694         return -1;
695 }
696
697 void ext4fs_deinit(void)
698 {
699         int i;
700         struct ext2_inode inode_journal;
701         struct journal_superblock_t *jsb;
702         uint32_t blknr;
703         struct ext_filesystem *fs = get_fs();
704         uint32_t new_feature_incompat;
705
706         /* free journal */
707         char *temp_buff = zalloc(fs->blksz);
708         if (temp_buff) {
709                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
710                                   &inode_journal);
711                 blknr = read_allocated_block(&inode_journal,
712                                         EXT2_JOURNAL_SUPERBLOCK);
713                 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
714                                temp_buff);
715                 jsb = (struct journal_superblock_t *)temp_buff;
716                 jsb->s_start = 0;
717                 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
718                          (struct journal_superblock_t *)temp_buff, fs->blksz);
719                 free(temp_buff);
720         }
721         ext4fs_free_journal();
722
723         /* get the superblock */
724         ext4_read_superblock((char *)fs->sb);
725         new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
726         new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
727         fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
728         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
729                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
730         free(fs->sb);
731         fs->sb = NULL;
732
733         if (fs->blk_bmaps) {
734                 for (i = 0; i < fs->no_blkgrp; i++) {
735                         free(fs->blk_bmaps[i]);
736                         fs->blk_bmaps[i] = NULL;
737                 }
738                 free(fs->blk_bmaps);
739                 fs->blk_bmaps = NULL;
740         }
741
742         if (fs->inode_bmaps) {
743                 for (i = 0; i < fs->no_blkgrp; i++) {
744                         free(fs->inode_bmaps[i]);
745                         fs->inode_bmaps[i] = NULL;
746                 }
747                 free(fs->inode_bmaps);
748                 fs->inode_bmaps = NULL;
749         }
750
751
752         free(fs->gdtable);
753         fs->gdtable = NULL;
754         fs->bgd = NULL;
755         /*
756          * reinitiliazed the global inode and
757          * block bitmap first execution check variables
758          */
759         fs->first_pass_ibmap = 0;
760         fs->first_pass_bbmap = 0;
761         fs->curr_inode_no = 0;
762         fs->curr_blkno = 0;
763 }
764
765 static int ext4fs_write_file(struct ext2_inode *file_inode,
766                              int pos, unsigned int len, char *buf)
767 {
768         int i;
769         int blockcnt;
770         uint32_t filesize = le32_to_cpu(file_inode->size);
771         struct ext_filesystem *fs = get_fs();
772         int log2blksz = fs->dev_desc->log2blksz;
773         int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
774         int previous_block_number = -1;
775         int delayed_start = 0;
776         int delayed_extent = 0;
777         int delayed_next = 0;
778         char *delayed_buf = NULL;
779
780         /* Adjust len so it we can't read past the end of the file. */
781         if (len > filesize)
782                 len = filesize;
783
784         blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
785
786         for (i = pos / fs->blksz; i < blockcnt; i++) {
787                 long int blknr;
788                 int blockend = fs->blksz;
789                 int skipfirst = 0;
790                 blknr = read_allocated_block(file_inode, i);
791                 if (blknr < 0)
792                         return -1;
793
794                 blknr = blknr << log2_fs_blocksize;
795
796                 if (blknr) {
797                         if (previous_block_number != -1) {
798                                 if (delayed_next == blknr) {
799                                         delayed_extent += blockend;
800                                         delayed_next += blockend >> log2blksz;
801                                 } else {        /* spill */
802                                         put_ext4((uint64_t)
803                                                  ((uint64_t)delayed_start << log2blksz),
804                                                  delayed_buf,
805                                                  (uint32_t) delayed_extent);
806                                         previous_block_number = blknr;
807                                         delayed_start = blknr;
808                                         delayed_extent = blockend;
809                                         delayed_buf = buf;
810                                         delayed_next = blknr +
811                                             (blockend >> log2blksz);
812                                 }
813                         } else {
814                                 previous_block_number = blknr;
815                                 delayed_start = blknr;
816                                 delayed_extent = blockend;
817                                 delayed_buf = buf;
818                                 delayed_next = blknr +
819                                     (blockend >> log2blksz);
820                         }
821                 } else {
822                         if (previous_block_number != -1) {
823                                 /* spill */
824                                 put_ext4((uint64_t) ((uint64_t)delayed_start <<
825                                                      log2blksz),
826                                          delayed_buf,
827                                          (uint32_t) delayed_extent);
828                                 previous_block_number = -1;
829                         }
830                         memset(buf, 0, fs->blksz - skipfirst);
831                 }
832                 buf += fs->blksz - skipfirst;
833         }
834         if (previous_block_number != -1) {
835                 /* spill */
836                 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
837                          delayed_buf, (uint32_t) delayed_extent);
838                 previous_block_number = -1;
839         }
840
841         return len;
842 }
843
844 int ext4fs_write(const char *fname, unsigned char *buffer,
845                                         unsigned long sizebytes)
846 {
847         int ret = 0;
848         struct ext2_inode *file_inode = NULL;
849         unsigned char *inode_buffer = NULL;
850         int parent_inodeno;
851         int inodeno;
852         time_t timestamp = 0;
853
854         uint64_t bytes_reqd_for_file;
855         unsigned int blks_reqd_for_file;
856         unsigned int blocks_remaining;
857         int existing_file_inodeno;
858         char *temp_ptr = NULL;
859         long int itable_blkno;
860         long int parent_itable_blkno;
861         long int blkoff;
862         struct ext2_sblock *sblock = &(ext4fs_root->sblock);
863         unsigned int inodes_per_block;
864         unsigned int ibmap_idx;
865         struct ext_filesystem *fs = get_fs();
866         ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
867         memset(filename, 0x00, 256);
868
869         g_parent_inode = zalloc(sizeof(struct ext2_inode));
870         if (!g_parent_inode)
871                 goto fail;
872
873         if (ext4fs_init() != 0) {
874                 printf("error in File System init\n");
875                 return -1;
876         }
877         inodes_per_block = fs->blksz / fs->inodesz;
878         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
879         if (parent_inodeno == -1)
880                 goto fail;
881         if (ext4fs_iget(parent_inodeno, g_parent_inode))
882                 goto fail;
883         /* do not mess up a directory using hash trees */
884         if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) {
885                 printf("hash tree directory\n");
886                 goto fail;
887         }
888         /* check if the filename is already present in root */
889         existing_file_inodeno = ext4fs_filename_unlink(filename);
890         if (existing_file_inodeno != -1) {
891                 ret = ext4fs_delete_file(existing_file_inodeno);
892                 fs->first_pass_bbmap = 0;
893                 fs->curr_blkno = 0;
894
895                 fs->first_pass_ibmap = 0;
896                 fs->curr_inode_no = 0;
897                 if (ret)
898                         goto fail;
899         }
900         /* calucalate how many blocks required */
901         bytes_reqd_for_file = sizebytes;
902         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
903         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
904                 blks_reqd_for_file++;
905                 debug("total bytes for a file %u\n", blks_reqd_for_file);
906         }
907         blocks_remaining = blks_reqd_for_file;
908         /* test for available space in partition */
909         if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
910                 printf("Not enough space on partition !!!\n");
911                 goto fail;
912         }
913
914         inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
915         if (inodeno == -1)
916                 goto fail;
917         /* prepare file inode */
918         inode_buffer = zalloc(fs->inodesz);
919         if (!inode_buffer)
920                 goto fail;
921         file_inode = (struct ext2_inode *)inode_buffer;
922         file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
923             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
924         /* ToDo: Update correct time */
925         file_inode->mtime = cpu_to_le32(timestamp);
926         file_inode->atime = cpu_to_le32(timestamp);
927         file_inode->ctime = cpu_to_le32(timestamp);
928         file_inode->nlinks = cpu_to_le16(1);
929         file_inode->size = cpu_to_le32(sizebytes);
930
931         /* Allocate data blocks */
932         ext4fs_allocate_blocks(file_inode, blocks_remaining,
933                                &blks_reqd_for_file);
934         file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
935                 fs->dev_desc->log2blksz);
936
937         temp_ptr = zalloc(fs->blksz);
938         if (!temp_ptr)
939                 goto fail;
940         ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
941         inodeno--;
942         itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
943                         (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
944                         inodes_per_block;
945         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
946         ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
947                        temp_ptr);
948         if (ext4fs_log_journal(temp_ptr, itable_blkno))
949                 goto fail;
950
951         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
952         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
953                 goto fail;
954         /* copy the file content into data blocks */
955         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
956                 printf("Error in copying content\n");
957                 goto fail;
958         }
959         ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
960         parent_inodeno--;
961         parent_itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
962             (parent_inodeno %
963              le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
964         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
965         if (parent_itable_blkno != itable_blkno) {
966                 memset(temp_ptr, '\0', fs->blksz);
967                 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
968                                0, fs->blksz, temp_ptr);
969                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
970                         goto fail;
971
972                 memcpy(temp_ptr + blkoff, g_parent_inode,
973                         sizeof(struct ext2_inode));
974                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
975                         goto fail;
976         } else {
977                 /*
978                  * If parent and child fall in same inode table block
979                  * both should be kept in 1 buffer
980                  */
981                 memcpy(temp_ptr + blkoff, g_parent_inode,
982                        sizeof(struct ext2_inode));
983                 gd_index--;
984                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
985                         goto fail;
986         }
987         ext4fs_update();
988         ext4fs_deinit();
989
990         fs->first_pass_bbmap = 0;
991         fs->curr_blkno = 0;
992         fs->first_pass_ibmap = 0;
993         fs->curr_inode_no = 0;
994         free(inode_buffer);
995         free(g_parent_inode);
996         free(temp_ptr);
997         g_parent_inode = NULL;
998
999         return 0;
1000 fail:
1001         ext4fs_deinit();
1002         free(inode_buffer);
1003         free(g_parent_inode);
1004         free(temp_ptr);
1005         g_parent_inode = NULL;
1006
1007         return -1;
1008 }
1009
1010 int ext4_write_file(const char *filename, void *buf, loff_t offset,
1011                     loff_t len, loff_t *actwrite)
1012 {
1013         int ret;
1014
1015         if (offset != 0) {
1016                 printf("** Cannot support non-zero offset **\n");
1017                 return -1;
1018         }
1019
1020         ret = ext4fs_write(filename, buf, len);
1021         if (ret) {
1022                 printf("** Error ext4fs_write() **\n");
1023                 goto fail;
1024         }
1025
1026         *actwrite = len;
1027
1028         return 0;
1029
1030 fail:
1031         *actwrite = 0;
1032
1033         return -1;
1034 }