]> git.sven.stormbind.net Git - sven/exfat-utils.git/blob - mkfs/mkexfat.c
Merge tag 'upstream/1.2.5'
[sven/exfat-utils.git] / mkfs / mkexfat.c
1 /*
2         mkexfat.c (22.04.12)
3         FS creation engine.
4
5         Free exFAT implementation.
6         Copyright (C) 2011-2016  Andrew Nayenko
7
8         This program is free software; you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 2 of the License, or
11         (at your option) any later version.
12
13         This program is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License along
19         with this program; if not, write to the Free Software Foundation, Inc.,
20         51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include "mkexfat.h"
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <inttypes.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 static int check_size(off_t volume_size)
31 {
32         const struct fs_object** pp;
33         off_t position = 0;
34
35         for (pp = objects; *pp; pp++)
36         {
37                 position = ROUND_UP(position, (*pp)->get_alignment());
38                 position += (*pp)->get_size();
39         }
40
41         if (position > volume_size)
42         {
43                 struct exfat_human_bytes vhb;
44
45                 exfat_humanize_bytes(volume_size, &vhb);
46                 exfat_error("too small device (%"PRIu64" %s)", vhb.value, vhb.unit);
47                 return 1;
48         }
49
50         return 0;
51
52 }
53
54 static int erase_object(struct exfat_dev* dev, const void* block,
55                 size_t block_size, off_t start, off_t size)
56 {
57         const off_t block_count = DIV_ROUND_UP(size, block_size);
58         off_t i;
59
60         if (exfat_seek(dev, start, SEEK_SET) == (off_t) -1)
61         {
62                 exfat_error("seek to 0x%"PRIx64" failed", start);
63                 return 1;
64         }
65         for (i = 0; i < size; i += block_size)
66         {
67                 if (exfat_write(dev, block, MIN(size - i, block_size)) < 0)
68                 {
69                         exfat_error("failed to erase block %"PRIu64"/%"PRIu64
70                                         " at 0x%"PRIx64, i + 1, block_count, start);
71                         return 1;
72                 }
73         }
74         return 0;
75 }
76
77 static int erase(struct exfat_dev* dev)
78 {
79         const struct fs_object** pp;
80         off_t position = 0;
81         const size_t block_size = 1024 * 1024;
82         void* block = malloc(block_size);
83
84         if (block == NULL)
85         {
86                 exfat_error("failed to allocate erase block of %zu bytes", block_size);
87                 return 1;
88         }
89         memset(block, 0, block_size);
90
91         for (pp = objects; *pp; pp++)
92         {
93                 position = ROUND_UP(position, (*pp)->get_alignment());
94                 if (erase_object(dev, block, block_size, position,
95                                 (*pp)->get_size()) != 0)
96                 {
97                         free(block);
98                         return 1;
99                 }
100                 position += (*pp)->get_size();
101         }
102
103         free(block);
104         return 0;
105 }
106
107 static int create(struct exfat_dev* dev)
108 {
109         const struct fs_object** pp;
110         off_t position = 0;
111
112         for (pp = objects; *pp; pp++)
113         {
114                 position = ROUND_UP(position, (*pp)->get_alignment());
115                 if (exfat_seek(dev, position, SEEK_SET) == (off_t) -1)
116                 {
117                         exfat_error("seek to 0x%"PRIx64" failed", position);
118                         return 1;
119                 }
120                 if ((*pp)->write(dev) != 0)
121                         return 1;
122                 position += (*pp)->get_size();
123         }
124         return 0;
125 }
126
127 int mkfs(struct exfat_dev* dev, off_t volume_size)
128 {
129         if (check_size(volume_size) != 0)
130                 return 1;
131
132         fputs("Creating... ", stdout);
133         fflush(stdout);
134         if (erase(dev) != 0)
135                 return 1;
136         if (create(dev) != 0)
137                 return 1;
138         puts("done.");
139
140         fputs("Flushing... ", stdout);
141         fflush(stdout);
142         if (exfat_fsync(dev) != 0)
143                 return 1;
144         puts("done.");
145
146         return 0;
147 }
148
149 off_t get_position(const struct fs_object* object)
150 {
151         const struct fs_object** pp;
152         off_t position = 0;
153
154         for (pp = objects; *pp; pp++)
155         {
156                 position = ROUND_UP(position, (*pp)->get_alignment());
157                 if (*pp == object)
158                         return position;
159                 position += (*pp)->get_size();
160         }
161         exfat_bug("unknown object");
162 }