]> git.sur5r.net Git - u-boot/blob - fs/ext4/ext4_write.c
ext4: propagate error if creation of directory entry fails
[u-boot] / 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->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
613         fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
614
615         /* get the superblock */
616         fs->sb = zalloc(SUPERBLOCK_SIZE);
617         if (!fs->sb)
618                 return -ENOMEM;
619         if (!ext4_read_superblock((char *)fs->sb))
620                 goto fail;
621
622         /* init journal */
623         if (ext4fs_init_journal())
624                 goto fail;
625
626         /* get total no of blockgroups */
627         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
628                         le32_to_cpu(ext4fs_root->sblock.total_blocks)
629                         - le32_to_cpu(ext4fs_root->sblock.first_data_block),
630                         le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
631
632         /* get the block group descriptor table */
633         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
634         if (ext4fs_get_bgdtable() == -1) {
635                 printf("Error in getting the block group descriptor table\n");
636                 goto fail;
637         }
638         fs->bgd = (struct ext2_block_group *)fs->gdtable;
639
640         /* load all the available bitmap block of the partition */
641         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
642         if (!fs->blk_bmaps)
643                 goto fail;
644         for (i = 0; i < fs->no_blkgrp; i++) {
645                 fs->blk_bmaps[i] = zalloc(fs->blksz);
646                 if (!fs->blk_bmaps[i])
647                         goto fail;
648         }
649
650         for (i = 0; i < fs->no_blkgrp; i++) {
651                 status =
652                     ext4fs_devread(
653                                    (lbaint_t)le32_to_cpu(fs->bgd[i].block_id) *
654                                    fs->sect_perblk, 0,
655                                    fs->blksz, (char *)fs->blk_bmaps[i]);
656                 if (status == 0)
657                         goto fail;
658         }
659
660         /* load all the available inode bitmap of the partition */
661         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
662         if (!fs->inode_bmaps)
663                 goto fail;
664         for (i = 0; i < fs->no_blkgrp; i++) {
665                 fs->inode_bmaps[i] = zalloc(fs->blksz);
666                 if (!fs->inode_bmaps[i])
667                         goto fail;
668         }
669
670         for (i = 0; i < fs->no_blkgrp; i++) {
671                 status = ext4fs_devread(
672                                         (lbaint_t)le32_to_cpu(fs->bgd[i].inode_id) *
673                                         fs->sect_perblk,
674                                         0, fs->blksz,
675                                         (char *)fs->inode_bmaps[i]);
676                 if (status == 0)
677                         goto fail;
678         }
679
680         /*
681          * check filesystem consistency with free blocks of file system
682          * some time we observed that superblock freeblocks does not match
683          * with the  blockgroups freeblocks when improper
684          * reboot of a linux kernel
685          */
686         for (i = 0; i < fs->no_blkgrp; i++)
687                 real_free_blocks = real_free_blocks + le16_to_cpu(fs->bgd[i].free_blocks);
688         if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks))
689                 fs->sb->free_blocks = cpu_to_le32(real_free_blocks);
690
691         return 0;
692 fail:
693         ext4fs_deinit();
694
695         return -1;
696 }
697
698 void ext4fs_deinit(void)
699 {
700         int i;
701         struct ext2_inode inode_journal;
702         struct journal_superblock_t *jsb;
703         uint32_t blknr;
704         struct ext_filesystem *fs = get_fs();
705         uint32_t new_feature_incompat;
706
707         /* free journal */
708         char *temp_buff = zalloc(fs->blksz);
709         if (temp_buff) {
710                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
711                                   &inode_journal);
712                 blknr = read_allocated_block(&inode_journal,
713                                         EXT2_JOURNAL_SUPERBLOCK);
714                 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
715                                temp_buff);
716                 jsb = (struct journal_superblock_t *)temp_buff;
717                 jsb->s_start = 0;
718                 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
719                          (struct journal_superblock_t *)temp_buff, fs->blksz);
720                 free(temp_buff);
721         }
722         ext4fs_free_journal();
723
724         /* get the superblock */
725         ext4_read_superblock((char *)fs->sb);
726         new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
727         new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
728         fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
729         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
730                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
731         free(fs->sb);
732         fs->sb = NULL;
733
734         if (fs->blk_bmaps) {
735                 for (i = 0; i < fs->no_blkgrp; i++) {
736                         free(fs->blk_bmaps[i]);
737                         fs->blk_bmaps[i] = NULL;
738                 }
739                 free(fs->blk_bmaps);
740                 fs->blk_bmaps = NULL;
741         }
742
743         if (fs->inode_bmaps) {
744                 for (i = 0; i < fs->no_blkgrp; i++) {
745                         free(fs->inode_bmaps[i]);
746                         fs->inode_bmaps[i] = NULL;
747                 }
748                 free(fs->inode_bmaps);
749                 fs->inode_bmaps = NULL;
750         }
751
752
753         free(fs->gdtable);
754         fs->gdtable = NULL;
755         fs->bgd = NULL;
756         /*
757          * reinitiliazed the global inode and
758          * block bitmap first execution check variables
759          */
760         fs->first_pass_ibmap = 0;
761         fs->first_pass_bbmap = 0;
762         fs->curr_inode_no = 0;
763         fs->curr_blkno = 0;
764 }
765
766 static int ext4fs_write_file(struct ext2_inode *file_inode,
767                              int pos, unsigned int len, char *buf)
768 {
769         int i;
770         int blockcnt;
771         uint32_t filesize = le32_to_cpu(file_inode->size);
772         struct ext_filesystem *fs = get_fs();
773         int log2blksz = fs->dev_desc->log2blksz;
774         int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
775         int previous_block_number = -1;
776         int delayed_start = 0;
777         int delayed_extent = 0;
778         int delayed_next = 0;
779         char *delayed_buf = NULL;
780
781         /* Adjust len so it we can't read past the end of the file. */
782         if (len > filesize)
783                 len = filesize;
784
785         blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
786
787         for (i = pos / fs->blksz; i < blockcnt; i++) {
788                 long int blknr;
789                 int blockend = fs->blksz;
790                 int skipfirst = 0;
791                 blknr = read_allocated_block(file_inode, i);
792                 if (blknr < 0)
793                         return -1;
794
795                 blknr = blknr << log2_fs_blocksize;
796
797                 if (blknr) {
798                         if (previous_block_number != -1) {
799                                 if (delayed_next == blknr) {
800                                         delayed_extent += blockend;
801                                         delayed_next += blockend >> log2blksz;
802                                 } else {        /* spill */
803                                         put_ext4((uint64_t)
804                                                  ((uint64_t)delayed_start << log2blksz),
805                                                  delayed_buf,
806                                                  (uint32_t) delayed_extent);
807                                         previous_block_number = blknr;
808                                         delayed_start = blknr;
809                                         delayed_extent = blockend;
810                                         delayed_buf = buf;
811                                         delayed_next = blknr +
812                                             (blockend >> log2blksz);
813                                 }
814                         } else {
815                                 previous_block_number = blknr;
816                                 delayed_start = blknr;
817                                 delayed_extent = blockend;
818                                 delayed_buf = buf;
819                                 delayed_next = blknr +
820                                     (blockend >> log2blksz);
821                         }
822                 } else {
823                         if (previous_block_number != -1) {
824                                 /* spill */
825                                 put_ext4((uint64_t) ((uint64_t)delayed_start <<
826                                                      log2blksz),
827                                          delayed_buf,
828                                          (uint32_t) delayed_extent);
829                                 previous_block_number = -1;
830                         }
831                         memset(buf, 0, fs->blksz - skipfirst);
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, unsigned char *buffer,
846                                         unsigned long sizebytes)
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 ext_filesystem *fs = get_fs();
867         ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
868         memset(filename, 0x00, 256);
869
870         g_parent_inode = zalloc(sizeof(struct ext2_inode));
871         if (!g_parent_inode)
872                 goto fail;
873
874         if (ext4fs_init() != 0) {
875                 printf("error in File System init\n");
876                 return -1;
877         }
878         inodes_per_block = fs->blksz / fs->inodesz;
879         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
880         if (parent_inodeno == -1)
881                 goto fail;
882         if (ext4fs_iget(parent_inodeno, g_parent_inode))
883                 goto fail;
884         /* check if the filename is already present in root */
885         existing_file_inodeno = ext4fs_filename_unlink(filename);
886         if (existing_file_inodeno != -1) {
887                 ret = ext4fs_delete_file(existing_file_inodeno);
888                 fs->first_pass_bbmap = 0;
889                 fs->curr_blkno = 0;
890
891                 fs->first_pass_ibmap = 0;
892                 fs->curr_inode_no = 0;
893                 if (ret)
894                         goto fail;
895         }
896         /* calucalate how many blocks required */
897         bytes_reqd_for_file = sizebytes;
898         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
899         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
900                 blks_reqd_for_file++;
901                 debug("total bytes for a file %u\n", blks_reqd_for_file);
902         }
903         blocks_remaining = blks_reqd_for_file;
904         /* test for available space in partition */
905         if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
906                 printf("Not enough space on partition !!!\n");
907                 goto fail;
908         }
909
910         inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
911         if (inodeno == -1)
912                 goto fail;
913         /* prepare file inode */
914         inode_buffer = zalloc(fs->inodesz);
915         if (!inode_buffer)
916                 goto fail;
917         file_inode = (struct ext2_inode *)inode_buffer;
918         file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
919             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
920         /* ToDo: Update correct time */
921         file_inode->mtime = cpu_to_le32(timestamp);
922         file_inode->atime = cpu_to_le32(timestamp);
923         file_inode->ctime = cpu_to_le32(timestamp);
924         file_inode->nlinks = cpu_to_le16(1);
925         file_inode->size = cpu_to_le32(sizebytes);
926
927         /* Allocate data blocks */
928         ext4fs_allocate_blocks(file_inode, blocks_remaining,
929                                &blks_reqd_for_file);
930         file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
931                 fs->dev_desc->log2blksz);
932
933         temp_ptr = zalloc(fs->blksz);
934         if (!temp_ptr)
935                 goto fail;
936         ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
937         inodeno--;
938         itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
939                         (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
940                         inodes_per_block;
941         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
942         ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
943                        temp_ptr);
944         if (ext4fs_log_journal(temp_ptr, itable_blkno))
945                 goto fail;
946
947         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
948         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
949                 goto fail;
950         /* copy the file content into data blocks */
951         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
952                 printf("Error in copying content\n");
953                 goto fail;
954         }
955         ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
956         parent_inodeno--;
957         parent_itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
958             (parent_inodeno %
959              le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
960         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
961         if (parent_itable_blkno != itable_blkno) {
962                 memset(temp_ptr, '\0', fs->blksz);
963                 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
964                                0, fs->blksz, temp_ptr);
965                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
966                         goto fail;
967
968                 memcpy(temp_ptr + blkoff, g_parent_inode,
969                         sizeof(struct ext2_inode));
970                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
971                         goto fail;
972                 free(temp_ptr);
973         } else {
974                 /*
975                  * If parent and child fall in same inode table block
976                  * both should be kept in 1 buffer
977                  */
978                 memcpy(temp_ptr + blkoff, g_parent_inode,
979                        sizeof(struct ext2_inode));
980                 gd_index--;
981                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
982                         goto fail;
983                 free(temp_ptr);
984         }
985         ext4fs_update();
986         ext4fs_deinit();
987
988         fs->first_pass_bbmap = 0;
989         fs->curr_blkno = 0;
990         fs->first_pass_ibmap = 0;
991         fs->curr_inode_no = 0;
992         free(inode_buffer);
993         free(g_parent_inode);
994         g_parent_inode = NULL;
995
996         return 0;
997 fail:
998         ext4fs_deinit();
999         free(inode_buffer);
1000         free(g_parent_inode);
1001         g_parent_inode = NULL;
1002
1003         return -1;
1004 }
1005
1006 int ext4_write_file(const char *filename, void *buf, loff_t offset,
1007                     loff_t len, loff_t *actwrite)
1008 {
1009         int ret;
1010
1011         if (offset != 0) {
1012                 printf("** Cannot support non-zero offset **\n");
1013                 return -1;
1014         }
1015
1016         ret = ext4fs_write(filename, buf, len);
1017         if (ret) {
1018                 printf("** Error ext4fs_write() **\n");
1019                 goto fail;
1020         }
1021
1022         *actwrite = len;
1023
1024         return 0;
1025
1026 fail:
1027         *actwrite = 0;
1028
1029         return -1;
1030 }