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