| @@ -1,1155 +1,1158 @@ | | | @@ -1,1155 +1,1158 @@ |
1 | /* $NetBSD: ffs.c,v 1.51 2013/01/23 21:32:32 christos Exp $ */ | | 1 | /* $NetBSD: ffs.c,v 1.52 2013/01/23 21:42:22 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Luke Mewburn for Wasabi Systems, Inc. | | 7 | * Written by Luke Mewburn for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by | | 19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. | | 20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior | | 22 | * or promote products derived from this software without specific prior |
23 | * written permission. | | 23 | * written permission. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | /* | | 37 | /* |
38 | * Copyright (c) 1982, 1986, 1989, 1993 | | 38 | * Copyright (c) 1982, 1986, 1989, 1993 |
39 | * The Regents of the University of California. All rights reserved. | | 39 | * The Regents of the University of California. All rights reserved. |
40 | * | | 40 | * |
41 | * Redistribution and use in source and binary forms, with or without | | 41 | * Redistribution and use in source and binary forms, with or without |
42 | * modification, are permitted provided that the following conditions | | 42 | * modification, are permitted provided that the following conditions |
43 | * are met: | | 43 | * are met: |
44 | * 1. Redistributions of source code must retain the above copyright | | 44 | * 1. Redistributions of source code must retain the above copyright |
45 | * notice, this list of conditions and the following disclaimer. | | 45 | * notice, this list of conditions and the following disclaimer. |
46 | * 2. Redistributions in binary form must reproduce the above copyright | | 46 | * 2. Redistributions in binary form must reproduce the above copyright |
47 | * notice, this list of conditions and the following disclaimer in the | | 47 | * notice, this list of conditions and the following disclaimer in the |
48 | * documentation and/or other materials provided with the distribution. | | 48 | * documentation and/or other materials provided with the distribution. |
49 | * 3. Neither the name of the University nor the names of its contributors | | 49 | * 3. Neither the name of the University nor the names of its contributors |
50 | * may be used to endorse or promote products derived from this software | | 50 | * may be used to endorse or promote products derived from this software |
51 | * without specific prior written permission. | | 51 | * without specific prior written permission. |
52 | * | | 52 | * |
53 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 53 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 54 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
63 | * SUCH DAMAGE. | | 63 | * SUCH DAMAGE. |
64 | * | | 64 | * |
65 | * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95 | | 65 | * @(#)ffs_alloc.c 8.19 (Berkeley) 7/13/95 |
66 | */ | | 66 | */ |
67 | | | 67 | |
68 | #if HAVE_NBTOOL_CONFIG_H | | 68 | #if HAVE_NBTOOL_CONFIG_H |
69 | #include "nbtool_config.h" | | 69 | #include "nbtool_config.h" |
70 | #endif | | 70 | #endif |
71 | | | 71 | |
72 | #include <sys/cdefs.h> | | 72 | #include <sys/cdefs.h> |
73 | #if defined(__RCSID) && !defined(__lint) | | 73 | #if defined(__RCSID) && !defined(__lint) |
74 | __RCSID("$NetBSD: ffs.c,v 1.51 2013/01/23 21:32:32 christos Exp $"); | | 74 | __RCSID("$NetBSD: ffs.c,v 1.52 2013/01/23 21:42:22 christos Exp $"); |
75 | #endif /* !__lint */ | | 75 | #endif /* !__lint */ |
76 | | | 76 | |
77 | #include <sys/param.h> | | 77 | #include <sys/param.h> |
78 | | | 78 | |
79 | #if !HAVE_NBTOOL_CONFIG_H | | 79 | #if !HAVE_NBTOOL_CONFIG_H |
80 | #include <sys/mount.h> | | 80 | #include <sys/mount.h> |
81 | #endif | | 81 | #endif |
82 | | | 82 | |
83 | #include <assert.h> | | 83 | #include <assert.h> |
84 | #include <errno.h> | | 84 | #include <errno.h> |
85 | #include <fcntl.h> | | 85 | #include <fcntl.h> |
86 | #include <stdarg.h> | | 86 | #include <stdarg.h> |
87 | #include <stdio.h> | | 87 | #include <stdio.h> |
88 | #include <stdlib.h> | | 88 | #include <stdlib.h> |
89 | #include <string.h> | | 89 | #include <string.h> |
90 | #include <unistd.h> | | 90 | #include <unistd.h> |
91 | | | 91 | |
92 | #include "makefs.h" | | 92 | #include "makefs.h" |
93 | #include "ffs.h" | | 93 | #include "ffs.h" |
94 | | | 94 | |
95 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS | | 95 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS |
96 | #include <sys/statvfs.h> | | 96 | #include <sys/statvfs.h> |
97 | #endif | | 97 | #endif |
98 | | | 98 | |
99 | #include <ufs/ufs/dinode.h> | | 99 | #include <ufs/ufs/dinode.h> |
100 | #include <ufs/ufs/dir.h> | | 100 | #include <ufs/ufs/dir.h> |
101 | #include <ufs/ffs/fs.h> | | 101 | #include <ufs/ffs/fs.h> |
102 | #include <ufs/ufs/ufs_bswap.h> | | 102 | #include <ufs/ufs/ufs_bswap.h> |
103 | | | 103 | |
104 | #include "ffs/ufs_inode.h" | | 104 | #include "ffs/ufs_inode.h" |
105 | #include "ffs/newfs_extern.h" | | 105 | #include "ffs/newfs_extern.h" |
106 | #include "ffs/ffs_extern.h" | | 106 | #include "ffs/ffs_extern.h" |
107 | | | 107 | |
108 | #undef DIP | | 108 | #undef DIP |
109 | #define DIP(dp, field) \ | | 109 | #define DIP(dp, field) \ |
110 | ((ffs_opts->version == 1) ? \ | | 110 | ((ffs_opts->version == 1) ? \ |
111 | (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field) | | 111 | (dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field) |
112 | | | 112 | |
113 | /* | | 113 | /* |
114 | * Various file system defaults (cribbed from newfs(8)). | | 114 | * Various file system defaults (cribbed from newfs(8)). |
115 | */ | | 115 | */ |
116 | #define DFL_FRAGSIZE 1024 /* fragment size */ | | 116 | #define DFL_FRAGSIZE 1024 /* fragment size */ |
117 | #define DFL_BLKSIZE 8192 /* block size */ | | 117 | #define DFL_BLKSIZE 8192 /* block size */ |
118 | #define DFL_SECSIZE 512 /* sector size */ | | 118 | #define DFL_SECSIZE 512 /* sector size */ |
119 | #define DFL_CYLSPERGROUP 65536 /* cylinders per group */ | | 119 | #define DFL_CYLSPERGROUP 65536 /* cylinders per group */ |
120 | #define DFL_FRAGSPERINODE 4 /* fragments per inode */ | | 120 | #define DFL_FRAGSPERINODE 4 /* fragments per inode */ |
121 | #define DFL_ROTDELAY 0 /* rotational delay */ | | 121 | #define DFL_ROTDELAY 0 /* rotational delay */ |
122 | #define DFL_NRPOS 1 /* rotational positions */ | | 122 | #define DFL_NRPOS 1 /* rotational positions */ |
123 | #define DFL_RPM 3600 /* rpm of disk */ | | 123 | #define DFL_RPM 3600 /* rpm of disk */ |
124 | #define DFL_NSECTORS 64 /* # of sectors */ | | 124 | #define DFL_NSECTORS 64 /* # of sectors */ |
125 | #define DFL_NTRACKS 16 /* # of tracks */ | | 125 | #define DFL_NTRACKS 16 /* # of tracks */ |
126 | | | 126 | |
127 | | | 127 | |
128 | typedef struct { | | 128 | typedef struct { |
129 | u_char *buf; /* buf for directory */ | | 129 | u_char *buf; /* buf for directory */ |
130 | doff_t size; /* full size of buf */ | | 130 | doff_t size; /* full size of buf */ |
131 | doff_t cur; /* offset of current entry */ | | 131 | doff_t cur; /* offset of current entry */ |
132 | } dirbuf_t; | | 132 | } dirbuf_t; |
133 | | | 133 | |
134 | | | 134 | |
135 | static int ffs_create_image(const char *, fsinfo_t *); | | 135 | static int ffs_create_image(const char *, fsinfo_t *); |
136 | static void ffs_dump_fsinfo(fsinfo_t *); | | 136 | static void ffs_dump_fsinfo(fsinfo_t *); |
137 | static void ffs_dump_dirbuf(dirbuf_t *, const char *, int); | | 137 | static void ffs_dump_dirbuf(dirbuf_t *, const char *, int); |
138 | static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int); | | 138 | static void ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int); |
139 | static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *); | | 139 | static int ffs_populate_dir(const char *, fsnode *, fsinfo_t *); |
140 | static void ffs_size_dir(fsnode *, fsinfo_t *); | | 140 | static void ffs_size_dir(fsnode *, fsinfo_t *); |
141 | static void ffs_validate(const char *, fsnode *, fsinfo_t *); | | 141 | static void ffs_validate(const char *, fsnode *, fsinfo_t *); |
142 | static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *); | | 142 | static void ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *); |
143 | static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *); | | 143 | static void ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *); |
144 | static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *, | | 144 | static void *ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *, |
145 | fsnode *, fsinfo_t *); | | 145 | fsnode *, fsinfo_t *); |
146 | static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, | | 146 | static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, |
147 | fsnode *, fsinfo_t *); | | 147 | fsnode *, fsinfo_t *); |
148 | | | 148 | |
149 | | | 149 | |
150 | | | 150 | |
151 | int sectorsize; /* XXX: for buf.c::getblk() */ | | 151 | int sectorsize; /* XXX: for buf.c::getblk() */ |
152 | | | 152 | |
153 | /* publically visible functions */ | | 153 | /* publically visible functions */ |
154 | | | 154 | |
155 | void | | 155 | void |
156 | ffs_prep_opts(fsinfo_t *fsopts) | | 156 | ffs_prep_opts(fsinfo_t *fsopts) |
157 | { | | 157 | { |
158 | ffs_opt_t *ffs_opts; | | 158 | ffs_opt_t *ffs_opts; |
159 | | | 159 | |
160 | if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL) | | 160 | if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL) |
161 | err(1, "Allocating memory for ffs_options"); | | 161 | err(1, "Allocating memory for ffs_options"); |
162 | | | 162 | |
163 | fsopts->fs_specific = ffs_opts; | | 163 | fsopts->fs_specific = ffs_opts; |
164 | | | 164 | |
165 | ffs_opts->bsize= -1; | | 165 | ffs_opts->bsize= -1; |
166 | ffs_opts->fsize= -1; | | 166 | ffs_opts->fsize= -1; |
167 | ffs_opts->cpg= -1; | | 167 | ffs_opts->cpg= -1; |
168 | ffs_opts->density= -1; | | 168 | ffs_opts->density= -1; |
169 | ffs_opts->minfree= -1; | | 169 | ffs_opts->minfree= -1; |
170 | ffs_opts->optimization= -1; | | 170 | ffs_opts->optimization= -1; |
171 | ffs_opts->maxcontig= -1; | | 171 | ffs_opts->maxcontig= -1; |
172 | ffs_opts->maxbpg= -1; | | 172 | ffs_opts->maxbpg= -1; |
173 | ffs_opts->avgfilesize= -1; | | 173 | ffs_opts->avgfilesize= -1; |
174 | ffs_opts->avgfpdir= -1; | | 174 | ffs_opts->avgfpdir= -1; |
175 | ffs_opts->version = 1; | | 175 | ffs_opts->version = 1; |
176 | } | | 176 | } |
177 | | | 177 | |
178 | void | | 178 | void |
179 | ffs_cleanup_opts(fsinfo_t *fsopts) | | 179 | ffs_cleanup_opts(fsinfo_t *fsopts) |
180 | { | | 180 | { |
181 | if (fsopts->fs_specific) | | 181 | if (fsopts->fs_specific) |
182 | free(fsopts->fs_specific); | | 182 | free(fsopts->fs_specific); |
183 | } | | 183 | } |
184 | | | 184 | |
185 | int | | 185 | int |
186 | ffs_parse_opts(const char *option, fsinfo_t *fsopts) | | 186 | ffs_parse_opts(const char *option, fsinfo_t *fsopts) |
187 | { | | 187 | { |
188 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | | 188 | ffs_opt_t *ffs_opts = fsopts->fs_specific; |
189 | char optimization[24]; | | 189 | char optimization[24]; |
190 | | | 190 | |
191 | option_t ffs_options[] = { | | 191 | option_t ffs_options[] = { |
192 | { '\0', "bsize", &ffs_opts->bsize, OPT_INT32, | | 192 | { '\0', "bsize", &ffs_opts->bsize, OPT_INT32, |
193 | 1, INT_MAX, "block size" }, | | 193 | 1, INT_MAX, "block size" }, |
194 | { '\0', "fsize", &ffs_opts->fsize, OPT_INT32, | | 194 | { '\0', "fsize", &ffs_opts->fsize, OPT_INT32, |
195 | 1, INT_MAX, "fragment size" }, | | 195 | 1, INT_MAX, "fragment size" }, |
196 | { '\0', "density", &ffs_opts->density, OPT_INT32, | | 196 | { '\0', "density", &ffs_opts->density, OPT_INT32, |
197 | 1, INT_MAX, "bytes per inode" }, | | 197 | 1, INT_MAX, "bytes per inode" }, |
198 | { '\0', "minfree", &ffs_opts->minfree, OPT_INT32, | | 198 | { '\0', "minfree", &ffs_opts->minfree, OPT_INT32, |
199 | 0, 99, "minfree" }, | | 199 | 0, 99, "minfree" }, |
200 | { '\0', "maxbpf", &ffs_opts->maxbpg, OPT_INT32, | | 200 | { '\0', "maxbpf", &ffs_opts->maxbpg, OPT_INT32, |
201 | 1, INT_MAX, "max blocks per file in a cg" }, | | 201 | 1, INT_MAX, "max blocks per file in a cg" }, |
202 | { '\0', "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, | | 202 | { '\0', "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, |
203 | 1, INT_MAX, "expected average file size" }, | | 203 | 1, INT_MAX, "expected average file size" }, |
204 | { '\0', "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, | | 204 | { '\0', "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, |
205 | 1, INT_MAX, "expected # of files per directory" }, | | 205 | 1, INT_MAX, "expected # of files per directory" }, |
206 | { '\0', "extent", &ffs_opts->maxbsize, OPT_INT32, | | 206 | { '\0', "extent", &ffs_opts->maxbsize, OPT_INT32, |
207 | 1, INT_MAX, "maximum # extent size" }, | | 207 | 1, INT_MAX, "maximum # extent size" }, |
208 | { '\0', "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, | | 208 | { '\0', "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, |
209 | 1, INT_MAX, "max # of blocks per group" }, | | 209 | 1, INT_MAX, "max # of blocks per group" }, |
210 | { '\0', "version", &ffs_opts->version, OPT_INT32, | | 210 | { '\0', "version", &ffs_opts->version, OPT_INT32, |
211 | 1, 2, "UFS version" }, | | 211 | 1, 2, "UFS version" }, |
212 | { '\0', "optimization", optimization, OPT_STRARRAY, | | 212 | { '\0', "optimization", optimization, OPT_STRARRAY, |
213 | 1, sizeof(optimization), "Optimization (time|space)" }, | | 213 | 1, sizeof(optimization), "Optimization (time|space)" }, |
214 | { '\0', "label", ffs_opts->label, OPT_STRARRAY, | | 214 | { '\0', "label", ffs_opts->label, OPT_STRARRAY, |
215 | 1, sizeof(ffs_opts->label), "UFS label" }, | | 215 | 1, sizeof(ffs_opts->label), "UFS label" }, |
216 | { .name = NULL } | | 216 | { .name = NULL } |
217 | }; | | 217 | }; |
218 | | | 218 | |
219 | int rv, i; | | 219 | int rv, i; |
220 | | | 220 | |
221 | assert(option != NULL); | | 221 | assert(option != NULL); |
222 | assert(fsopts != NULL); | | 222 | assert(fsopts != NULL); |
223 | assert(ffs_opts != NULL); | | 223 | assert(ffs_opts != NULL); |
224 | | | 224 | |
225 | if (debug & DEBUG_FS_PARSE_OPTS) | | 225 | if (debug & DEBUG_FS_PARSE_OPTS) |
226 | printf("ffs_parse_opts: got `%s'\n", option); | | 226 | printf("ffs_parse_opts: got `%s'\n", option); |
227 | | | 227 | |
228 | rv = set_option(ffs_options, option); | | 228 | rv = set_option(ffs_options, option); |
229 | if (rv == 0) | | 229 | if (rv == 0) |
230 | return 0; | | 230 | return 0; |
231 | | | 231 | |
232 | for (i = 0; ffs_options[i].name && (1 << i) != rv; i++) | | 232 | for (i = 0; ffs_options[i].name && (1 << i) != rv; i++) |
233 | continue; | | 233 | continue; |
234 | | | 234 | |
| | | 235 | if (ffs_options[i].name == NULL) |
| | | 236 | abort(); |
| | | 237 | |
235 | if (strcmp(ffs_options[i].name, "optimization") == 0) { | | 238 | if (strcmp(ffs_options[i].name, "optimization") == 0) { |
236 | if (strcmp(optimization, "time") == 0) { | | 239 | if (strcmp(optimization, "time") == 0) { |
237 | ffs_opts->optimization = FS_OPTTIME; | | 240 | ffs_opts->optimization = FS_OPTTIME; |
238 | } else if (strcmp(optimization, "space") == 0) { | | 241 | } else if (strcmp(optimization, "space") == 0) { |
239 | ffs_opts->optimization = FS_OPTSPACE; | | 242 | ffs_opts->optimization = FS_OPTSPACE; |
240 | } else { | | 243 | } else { |
241 | warnx("Invalid optimization `%s'", optimization); | | 244 | warnx("Invalid optimization `%s'", optimization); |
242 | return 0; | | 245 | return 0; |
243 | } | | 246 | } |
244 | } | | 247 | } |
245 | return rv; | | 248 | return rv; |
246 | } | | 249 | } |
247 | | | 250 | |
248 | | | 251 | |
249 | void | | 252 | void |
250 | ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) | | 253 | ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) |
251 | { | | 254 | { |
252 | struct fs *superblock; | | 255 | struct fs *superblock; |
253 | struct timeval start; | | 256 | struct timeval start; |
254 | | | 257 | |
255 | assert(image != NULL); | | 258 | assert(image != NULL); |
256 | assert(dir != NULL); | | 259 | assert(dir != NULL); |
257 | assert(root != NULL); | | 260 | assert(root != NULL); |
258 | assert(fsopts != NULL); | | 261 | assert(fsopts != NULL); |
259 | | | 262 | |
260 | if (debug & DEBUG_FS_MAKEFS) | | 263 | if (debug & DEBUG_FS_MAKEFS) |
261 | printf("ffs_makefs: image %s directory %s root %p\n", | | 264 | printf("ffs_makefs: image %s directory %s root %p\n", |
262 | image, dir, root); | | 265 | image, dir, root); |
263 | | | 266 | |
264 | /* validate tree and options */ | | 267 | /* validate tree and options */ |
265 | TIMER_START(start); | | 268 | TIMER_START(start); |
266 | ffs_validate(dir, root, fsopts); | | 269 | ffs_validate(dir, root, fsopts); |
267 | TIMER_RESULTS(start, "ffs_validate"); | | 270 | TIMER_RESULTS(start, "ffs_validate"); |
268 | | | 271 | |
269 | printf("Calculated size of `%s': %lld bytes, %lld inodes\n", | | 272 | printf("Calculated size of `%s': %lld bytes, %lld inodes\n", |
270 | image, (long long)fsopts->size, (long long)fsopts->inodes); | | 273 | image, (long long)fsopts->size, (long long)fsopts->inodes); |
271 | | | 274 | |
272 | /* create image */ | | 275 | /* create image */ |
273 | TIMER_START(start); | | 276 | TIMER_START(start); |
274 | if (ffs_create_image(image, fsopts) == -1) | | 277 | if (ffs_create_image(image, fsopts) == -1) |
275 | errx(1, "Image file `%s' not created.", image); | | 278 | errx(1, "Image file `%s' not created.", image); |
276 | TIMER_RESULTS(start, "ffs_create_image"); | | 279 | TIMER_RESULTS(start, "ffs_create_image"); |
277 | | | 280 | |
278 | fsopts->curinode = UFS_ROOTINO; | | 281 | fsopts->curinode = UFS_ROOTINO; |
279 | | | 282 | |
280 | if (debug & DEBUG_FS_MAKEFS) | | 283 | if (debug & DEBUG_FS_MAKEFS) |
281 | putchar('\n'); | | 284 | putchar('\n'); |
282 | | | 285 | |
283 | /* populate image */ | | 286 | /* populate image */ |
284 | printf("Populating `%s'\n", image); | | 287 | printf("Populating `%s'\n", image); |
285 | TIMER_START(start); | | 288 | TIMER_START(start); |
286 | if (! ffs_populate_dir(dir, root, fsopts)) | | 289 | if (! ffs_populate_dir(dir, root, fsopts)) |
287 | errx(1, "Image file `%s' not populated.", image); | | 290 | errx(1, "Image file `%s' not populated.", image); |
288 | TIMER_RESULTS(start, "ffs_populate_dir"); | | 291 | TIMER_RESULTS(start, "ffs_populate_dir"); |
289 | | | 292 | |
290 | /* ensure no outstanding buffers remain */ | | 293 | /* ensure no outstanding buffers remain */ |
291 | if (debug & DEBUG_FS_MAKEFS) | | 294 | if (debug & DEBUG_FS_MAKEFS) |
292 | bcleanup(); | | 295 | bcleanup(); |
293 | | | 296 | |
294 | /* update various superblock parameters */ | | 297 | /* update various superblock parameters */ |
295 | superblock = fsopts->superblock; | | 298 | superblock = fsopts->superblock; |
296 | superblock->fs_fmod = 0; | | 299 | superblock->fs_fmod = 0; |
297 | superblock->fs_old_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir; | | 300 | superblock->fs_old_cstotal.cs_ndir = superblock->fs_cstotal.cs_ndir; |
298 | superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree; | | 301 | superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree; |
299 | superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree; | | 302 | superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree; |
300 | superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree; | | 303 | superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree; |
301 | | | 304 | |
302 | /* write out superblock; image is now complete */ | | 305 | /* write out superblock; image is now complete */ |
303 | ffs_write_superblock(fsopts->superblock, fsopts); | | 306 | ffs_write_superblock(fsopts->superblock, fsopts); |
304 | if (close(fsopts->fd) == -1) | | 307 | if (close(fsopts->fd) == -1) |
305 | err(1, "Closing `%s'", image); | | 308 | err(1, "Closing `%s'", image); |
306 | fsopts->fd = -1; | | 309 | fsopts->fd = -1; |
307 | printf("Image `%s' complete\n", image); | | 310 | printf("Image `%s' complete\n", image); |
308 | } | | 311 | } |
309 | | | 312 | |
310 | /* end of public functions */ | | 313 | /* end of public functions */ |
311 | | | 314 | |
312 | | | 315 | |
313 | static void | | 316 | static void |
314 | ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) | | 317 | ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) |
315 | { | | 318 | { |
316 | int32_t ncg = 1; | | 319 | int32_t ncg = 1; |
317 | #if notyet | | 320 | #if notyet |
318 | int32_t spc, nspf, ncyl, fssize; | | 321 | int32_t spc, nspf, ncyl, fssize; |
319 | #endif | | 322 | #endif |
320 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | | 323 | ffs_opt_t *ffs_opts = fsopts->fs_specific; |
321 | | | 324 | |
322 | assert(dir != NULL); | | 325 | assert(dir != NULL); |
323 | assert(root != NULL); | | 326 | assert(root != NULL); |
324 | assert(fsopts != NULL); | | 327 | assert(fsopts != NULL); |
325 | assert(ffs_opts != NULL); | | 328 | assert(ffs_opts != NULL); |
326 | | | 329 | |
327 | if (debug & DEBUG_FS_VALIDATE) { | | 330 | if (debug & DEBUG_FS_VALIDATE) { |
328 | printf("ffs_validate: before defaults set:\n"); | | 331 | printf("ffs_validate: before defaults set:\n"); |
329 | ffs_dump_fsinfo(fsopts); | | 332 | ffs_dump_fsinfo(fsopts); |
330 | } | | 333 | } |
331 | | | 334 | |
332 | /* set FFS defaults */ | | 335 | /* set FFS defaults */ |
333 | if (fsopts->sectorsize == -1) | | 336 | if (fsopts->sectorsize == -1) |
334 | fsopts->sectorsize = DFL_SECSIZE; | | 337 | fsopts->sectorsize = DFL_SECSIZE; |
335 | if (ffs_opts->fsize == -1) | | 338 | if (ffs_opts->fsize == -1) |
336 | ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize); | | 339 | ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize); |
337 | if (ffs_opts->bsize == -1) | | 340 | if (ffs_opts->bsize == -1) |
338 | ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize); | | 341 | ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize); |
339 | if (ffs_opts->cpg == -1) | | 342 | if (ffs_opts->cpg == -1) |
340 | ffs_opts->cpg = DFL_CYLSPERGROUP; | | 343 | ffs_opts->cpg = DFL_CYLSPERGROUP; |
341 | else | | 344 | else |
342 | ffs_opts->cpgflg = 1; | | 345 | ffs_opts->cpgflg = 1; |
343 | /* fsopts->density is set below */ | | 346 | /* fsopts->density is set below */ |
344 | if (ffs_opts->nsectors == -1) | | 347 | if (ffs_opts->nsectors == -1) |
345 | ffs_opts->nsectors = DFL_NSECTORS; | | 348 | ffs_opts->nsectors = DFL_NSECTORS; |
346 | if (ffs_opts->minfree == -1) | | 349 | if (ffs_opts->minfree == -1) |
347 | ffs_opts->minfree = MINFREE; | | 350 | ffs_opts->minfree = MINFREE; |
348 | if (ffs_opts->optimization == -1) | | 351 | if (ffs_opts->optimization == -1) |
349 | ffs_opts->optimization = DEFAULTOPT; | | 352 | ffs_opts->optimization = DEFAULTOPT; |
350 | if (ffs_opts->maxcontig == -1) | | 353 | if (ffs_opts->maxcontig == -1) |
351 | ffs_opts->maxcontig = | | 354 | ffs_opts->maxcontig = |
352 | MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize); | | 355 | MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize); |
353 | /* XXX ondisk32 */ | | 356 | /* XXX ondisk32 */ |
354 | if (ffs_opts->maxbpg == -1) | | 357 | if (ffs_opts->maxbpg == -1) |
355 | ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t); | | 358 | ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t); |
356 | if (ffs_opts->avgfilesize == -1) | | 359 | if (ffs_opts->avgfilesize == -1) |
357 | ffs_opts->avgfilesize = AVFILESIZ; | | 360 | ffs_opts->avgfilesize = AVFILESIZ; |
358 | if (ffs_opts->avgfpdir == -1) | | 361 | if (ffs_opts->avgfpdir == -1) |
359 | ffs_opts->avgfpdir = AFPDIR; | | 362 | ffs_opts->avgfpdir = AFPDIR; |
360 | | | 363 | |
361 | /* calculate size of tree */ | | 364 | /* calculate size of tree */ |
362 | ffs_size_dir(root, fsopts); | | 365 | ffs_size_dir(root, fsopts); |
363 | fsopts->inodes += UFS_ROOTINO; /* include first two inodes */ | | 366 | fsopts->inodes += UFS_ROOTINO; /* include first two inodes */ |
364 | | | 367 | |
365 | if (debug & DEBUG_FS_VALIDATE) | | 368 | if (debug & DEBUG_FS_VALIDATE) |
366 | printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n", | | 369 | printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n", |
367 | (long long)fsopts->size, (long long)fsopts->inodes); | | 370 | (long long)fsopts->size, (long long)fsopts->inodes); |
368 | | | 371 | |
369 | /* add requested slop */ | | 372 | /* add requested slop */ |
370 | fsopts->size += fsopts->freeblocks; | | 373 | fsopts->size += fsopts->freeblocks; |
371 | fsopts->inodes += fsopts->freefiles; | | 374 | fsopts->inodes += fsopts->freefiles; |
372 | if (fsopts->freefilepc > 0) | | 375 | if (fsopts->freefilepc > 0) |
373 | fsopts->inodes = | | 376 | fsopts->inodes = |
374 | fsopts->inodes * (100 + fsopts->freefilepc) / 100; | | 377 | fsopts->inodes * (100 + fsopts->freefilepc) / 100; |
375 | if (fsopts->freeblockpc > 0) | | 378 | if (fsopts->freeblockpc > 0) |
376 | fsopts->size = | | 379 | fsopts->size = |
377 | fsopts->size * (100 + fsopts->freeblockpc) / 100; | | 380 | fsopts->size * (100 + fsopts->freeblockpc) / 100; |
378 | | | 381 | |
379 | /* add space needed for superblocks */ | | 382 | /* add space needed for superblocks */ |
380 | /* | | 383 | /* |
381 | * The old SBOFF (SBLOCK_UFS1) is used here because makefs is | | 384 | * The old SBOFF (SBLOCK_UFS1) is used here because makefs is |
382 | * typically used for small filesystems where space matters. | | 385 | * typically used for small filesystems where space matters. |
383 | * XXX make this an option. | | 386 | * XXX make this an option. |
384 | */ | | 387 | */ |
385 | fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg; | | 388 | fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg; |
386 | /* add space needed to store inodes, x3 for blockmaps, etc */ | | 389 | /* add space needed to store inodes, x3 for blockmaps, etc */ |
387 | if (ffs_opts->version == 1) | | 390 | if (ffs_opts->version == 1) |
388 | fsopts->size += ncg * DINODE1_SIZE * | | 391 | fsopts->size += ncg * DINODE1_SIZE * |
389 | roundup(fsopts->inodes / ncg, | | 392 | roundup(fsopts->inodes / ncg, |
390 | ffs_opts->bsize / DINODE1_SIZE); | | 393 | ffs_opts->bsize / DINODE1_SIZE); |
391 | else | | 394 | else |
392 | fsopts->size += ncg * DINODE2_SIZE * | | 395 | fsopts->size += ncg * DINODE2_SIZE * |
393 | roundup(fsopts->inodes / ncg, | | 396 | roundup(fsopts->inodes / ncg, |
394 | ffs_opts->bsize / DINODE2_SIZE); | | 397 | ffs_opts->bsize / DINODE2_SIZE); |
395 | | | 398 | |
396 | /* add minfree */ | | 399 | /* add minfree */ |
397 | if (ffs_opts->minfree > 0) | | 400 | if (ffs_opts->minfree > 0) |
398 | fsopts->size = | | 401 | fsopts->size = |
399 | fsopts->size * (100 + ffs_opts->minfree) / 100; | | 402 | fsopts->size * (100 + ffs_opts->minfree) / 100; |
400 | /* | | 403 | /* |
401 | * XXX any other fs slop to add, such as csum's, bitmaps, etc ?? | | 404 | * XXX any other fs slop to add, such as csum's, bitmaps, etc ?? |
402 | */ | | 405 | */ |
403 | | | 406 | |
404 | if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */ | | 407 | if (fsopts->size < fsopts->minsize) /* ensure meets minimum size */ |
405 | fsopts->size = fsopts->minsize; | | 408 | fsopts->size = fsopts->minsize; |
406 | | | 409 | |
407 | /* round up to the next block */ | | 410 | /* round up to the next block */ |
408 | fsopts->size = roundup(fsopts->size, ffs_opts->bsize); | | 411 | fsopts->size = roundup(fsopts->size, ffs_opts->bsize); |
409 | | | 412 | |
410 | /* calculate density if necessary */ | | 413 | /* calculate density if necessary */ |
411 | if (ffs_opts->density == -1) | | 414 | if (ffs_opts->density == -1) |
412 | ffs_opts->density = fsopts->size / fsopts->inodes + 1; | | 415 | ffs_opts->density = fsopts->size / fsopts->inodes + 1; |
413 | | | 416 | |
414 | if (debug & DEBUG_FS_VALIDATE) { | | 417 | if (debug & DEBUG_FS_VALIDATE) { |
415 | printf("ffs_validate: after defaults set:\n"); | | 418 | printf("ffs_validate: after defaults set:\n"); |
416 | ffs_dump_fsinfo(fsopts); | | 419 | ffs_dump_fsinfo(fsopts); |
417 | printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n", | | 420 | printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n", |
418 | dir, (long long)fsopts->size, (long long)fsopts->inodes); | | 421 | dir, (long long)fsopts->size, (long long)fsopts->inodes); |
419 | } | | 422 | } |
420 | sectorsize = fsopts->sectorsize; /* XXX - see earlier */ | | 423 | sectorsize = fsopts->sectorsize; /* XXX - see earlier */ |
421 | | | 424 | |
422 | /* now check calculated sizes vs requested sizes */ | | 425 | /* now check calculated sizes vs requested sizes */ |
423 | if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { | | 426 | if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) { |
424 | errx(1, "`%s' size of %lld is larger than the maxsize of %lld.", | | 427 | errx(1, "`%s' size of %lld is larger than the maxsize of %lld.", |
425 | dir, (long long)fsopts->size, (long long)fsopts->maxsize); | | 428 | dir, (long long)fsopts->size, (long long)fsopts->maxsize); |
426 | } | | 429 | } |
427 | } | | 430 | } |
428 | | | 431 | |
429 | | | 432 | |
430 | static void | | 433 | static void |
431 | ffs_dump_fsinfo(fsinfo_t *f) | | 434 | ffs_dump_fsinfo(fsinfo_t *f) |
432 | { | | 435 | { |
433 | | | 436 | |
434 | ffs_opt_t *fs = f->fs_specific; | | 437 | ffs_opt_t *fs = f->fs_specific; |
435 | | | 438 | |
436 | printf("fsopts at %p\n", f); | | 439 | printf("fsopts at %p\n", f); |
437 | | | 440 | |
438 | printf("\tsize %lld, inodes %lld, curinode %u\n", | | 441 | printf("\tsize %lld, inodes %lld, curinode %u\n", |
439 | (long long)f->size, (long long)f->inodes, f->curinode); | | 442 | (long long)f->size, (long long)f->inodes, f->curinode); |
440 | | | 443 | |
441 | printf("\tminsize %lld, maxsize %lld\n", | | 444 | printf("\tminsize %lld, maxsize %lld\n", |
442 | (long long)f->minsize, (long long)f->maxsize); | | 445 | (long long)f->minsize, (long long)f->maxsize); |
443 | printf("\tfree files %lld, freefile %% %d\n", | | 446 | printf("\tfree files %lld, freefile %% %d\n", |
444 | (long long)f->freefiles, f->freefilepc); | | 447 | (long long)f->freefiles, f->freefilepc); |
445 | printf("\tfree blocks %lld, freeblock %% %d\n", | | 448 | printf("\tfree blocks %lld, freeblock %% %d\n", |
446 | (long long)f->freeblocks, f->freeblockpc); | | 449 | (long long)f->freeblocks, f->freeblockpc); |
447 | printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize); | | 450 | printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize); |
448 | | | 451 | |
449 | printf("\tbsize %d, fsize %d, cpg %d, density %d\n", | | 452 | printf("\tbsize %d, fsize %d, cpg %d, density %d\n", |
450 | fs->bsize, fs->fsize, fs->cpg, fs->density); | | 453 | fs->bsize, fs->fsize, fs->cpg, fs->density); |
451 | printf("\tnsectors %d, rpm %d, minfree %d\n", | | 454 | printf("\tnsectors %d, rpm %d, minfree %d\n", |
452 | fs->nsectors, fs->rpm, fs->minfree); | | 455 | fs->nsectors, fs->rpm, fs->minfree); |
453 | printf("\tmaxcontig %d, maxbpg %d\n", | | 456 | printf("\tmaxcontig %d, maxbpg %d\n", |
454 | fs->maxcontig, fs->maxbpg); | | 457 | fs->maxcontig, fs->maxbpg); |
455 | printf("\toptimization %s\n", | | 458 | printf("\toptimization %s\n", |
456 | fs->optimization == FS_OPTSPACE ? "space" : "time"); | | 459 | fs->optimization == FS_OPTSPACE ? "space" : "time"); |
457 | } | | 460 | } |
458 | | | 461 | |
459 | | | 462 | |
460 | static int | | 463 | static int |
461 | ffs_create_image(const char *image, fsinfo_t *fsopts) | | 464 | ffs_create_image(const char *image, fsinfo_t *fsopts) |
462 | { | | 465 | { |
463 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS | | 466 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS |
464 | struct statvfs sfs; | | 467 | struct statvfs sfs; |
465 | #endif | | 468 | #endif |
466 | struct fs *fs; | | 469 | struct fs *fs; |
467 | char *buf; | | 470 | char *buf; |
468 | int i, bufsize; | | 471 | int i, bufsize; |
469 | off_t bufrem; | | 472 | off_t bufrem; |
470 | | | 473 | |
471 | assert (image != NULL); | | 474 | assert (image != NULL); |
472 | assert (fsopts != NULL); | | 475 | assert (fsopts != NULL); |
473 | | | 476 | |
474 | /* create image */ | | 477 | /* create image */ |
475 | if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) | | 478 | if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666)) |
476 | == -1) { | | 479 | == -1) { |
477 | warn("Can't open `%s' for writing", image); | | 480 | warn("Can't open `%s' for writing", image); |
478 | return (-1); | | 481 | return (-1); |
479 | } | | 482 | } |
480 | | | 483 | |
481 | /* zero image */ | | 484 | /* zero image */ |
482 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS | | 485 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS |
483 | if (fstatvfs(fsopts->fd, &sfs) == -1) { | | 486 | if (fstatvfs(fsopts->fd, &sfs) == -1) { |
484 | #endif | | 487 | #endif |
485 | bufsize = 8192; | | 488 | bufsize = 8192; |
486 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS | | 489 | #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS |
487 | warn("can't fstatvfs `%s', using default %d byte chunk", | | 490 | warn("can't fstatvfs `%s', using default %d byte chunk", |
488 | image, bufsize); | | 491 | image, bufsize); |
489 | } else | | 492 | } else |
490 | bufsize = sfs.f_iosize; | | 493 | bufsize = sfs.f_iosize; |
491 | #endif | | 494 | #endif |
492 | bufrem = fsopts->size; | | 495 | bufrem = fsopts->size; |
493 | | | 496 | |
494 | if (fsopts->sparse) { | | 497 | if (fsopts->sparse) { |
495 | if (ftruncate(fsopts->fd, bufrem) == -1) { | | 498 | if (ftruncate(fsopts->fd, bufrem) == -1) { |
496 | printf ("ERROR in truncate. Sparse option disabled\n"); | | 499 | printf ("ERROR in truncate. Sparse option disabled\n"); |
497 | fsopts->sparse = 0; | | 500 | fsopts->sparse = 0; |
498 | } else { | | 501 | } else { |
499 | bufrem = 0; /* File truncated at bufrem. Remaining is 0 */ | | 502 | bufrem = 0; /* File truncated at bufrem. Remaining is 0 */ |
500 | buf = NULL; | | 503 | buf = NULL; |
501 | } | | 504 | } |
502 | } | | 505 | } |
503 | | | 506 | |
504 | if ((debug & DEBUG_FS_CREATE_IMAGE) && fsopts->sparse == 0) | | 507 | if ((debug & DEBUG_FS_CREATE_IMAGE) && fsopts->sparse == 0) |
505 | printf( | | 508 | printf( |
506 | "zero-ing image `%s', %lld sectors, using %d byte chunks\n", | | 509 | "zero-ing image `%s', %lld sectors, using %d byte chunks\n", |
507 | image, (long long)bufrem, bufsize); | | 510 | image, (long long)bufrem, bufsize); |
508 | if ((bufrem > 0) && ((buf = calloc(1, bufsize)) == NULL)) { | | 511 | if ((bufrem > 0) && ((buf = calloc(1, bufsize)) == NULL)) { |
509 | warn("Can't create buffer for sector"); | | 512 | warn("Can't create buffer for sector"); |
510 | return (-1); | | 513 | return (-1); |
511 | } | | 514 | } |
512 | while (bufrem > 0) { | | 515 | while (bufrem > 0) { |
513 | i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); | | 516 | i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); |
514 | if (i == -1) { | | 517 | if (i == -1) { |
515 | warn("zeroing image, %lld bytes to go", | | 518 | warn("zeroing image, %lld bytes to go", |
516 | (long long)bufrem); | | 519 | (long long)bufrem); |
517 | free(buf); | | 520 | free(buf); |
518 | return (-1); | | 521 | return (-1); |
519 | } | | 522 | } |
520 | bufrem -= i; | | 523 | bufrem -= i; |
521 | } | | 524 | } |
522 | if (buf) | | 525 | if (buf) |
523 | free(buf); | | 526 | free(buf); |
524 | | | 527 | |
525 | /* make the file system */ | | 528 | /* make the file system */ |
526 | if (debug & DEBUG_FS_CREATE_IMAGE) | | 529 | if (debug & DEBUG_FS_CREATE_IMAGE) |
527 | printf("calling mkfs(\"%s\", ...)\n", image); | | 530 | printf("calling mkfs(\"%s\", ...)\n", image); |
528 | fs = ffs_mkfs(image, fsopts); | | 531 | fs = ffs_mkfs(image, fsopts); |
529 | fsopts->superblock = (void *)fs; | | 532 | fsopts->superblock = (void *)fs; |
530 | if (debug & DEBUG_FS_CREATE_IMAGE) { | | 533 | if (debug & DEBUG_FS_CREATE_IMAGE) { |
531 | time_t t; | | 534 | time_t t; |
532 | | | 535 | |
533 | t = (time_t)((struct fs *)fsopts->superblock)->fs_time; | | 536 | t = (time_t)((struct fs *)fsopts->superblock)->fs_time; |
534 | printf("mkfs returned %p; fs_time %s", | | 537 | printf("mkfs returned %p; fs_time %s", |
535 | fsopts->superblock, ctime(&t)); | | 538 | fsopts->superblock, ctime(&t)); |
536 | printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n", | | 539 | printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n", |
537 | (long long)fs->fs_cstotal.cs_nbfree, | | 540 | (long long)fs->fs_cstotal.cs_nbfree, |
538 | (long long)fs->fs_cstotal.cs_nffree, | | 541 | (long long)fs->fs_cstotal.cs_nffree, |
539 | (long long)fs->fs_cstotal.cs_nifree, | | 542 | (long long)fs->fs_cstotal.cs_nifree, |
540 | (long long)fs->fs_cstotal.cs_ndir); | | 543 | (long long)fs->fs_cstotal.cs_ndir); |
541 | } | | 544 | } |
542 | | | 545 | |
543 | if ((off_t)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO) < fsopts->inodes) { | | 546 | if ((off_t)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO) < fsopts->inodes) { |
544 | warnx( | | 547 | warnx( |
545 | "Image file `%s' has %lld free inodes; %lld are required.", | | 548 | "Image file `%s' has %lld free inodes; %lld are required.", |
546 | image, | | 549 | image, |
547 | (long long)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO), | | 550 | (long long)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO), |
548 | (long long)fsopts->inodes); | | 551 | (long long)fsopts->inodes); |
549 | return (-1); | | 552 | return (-1); |
550 | } | | 553 | } |
551 | return (fsopts->fd); | | 554 | return (fsopts->fd); |
552 | } | | 555 | } |
553 | | | 556 | |
554 | | | 557 | |
555 | static void | | 558 | static void |
556 | ffs_size_dir(fsnode *root, fsinfo_t *fsopts) | | 559 | ffs_size_dir(fsnode *root, fsinfo_t *fsopts) |
557 | { | | 560 | { |
558 | struct direct tmpdir; | | 561 | struct direct tmpdir; |
559 | fsnode * node; | | 562 | fsnode * node; |
560 | int curdirsize, this; | | 563 | int curdirsize, this; |
561 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | | 564 | ffs_opt_t *ffs_opts = fsopts->fs_specific; |
562 | | | 565 | |
563 | /* node may be NULL (empty directory) */ | | 566 | /* node may be NULL (empty directory) */ |
564 | assert(fsopts != NULL); | | 567 | assert(fsopts != NULL); |
565 | assert(ffs_opts != NULL); | | 568 | assert(ffs_opts != NULL); |
566 | | | 569 | |
567 | if (debug & DEBUG_FS_SIZE_DIR) | | 570 | if (debug & DEBUG_FS_SIZE_DIR) |
568 | printf("ffs_size_dir: entry: bytes %lld inodes %lld\n", | | 571 | printf("ffs_size_dir: entry: bytes %lld inodes %lld\n", |
569 | (long long)fsopts->size, (long long)fsopts->inodes); | | 572 | (long long)fsopts->size, (long long)fsopts->inodes); |
570 | | | 573 | |
571 | #define ADDDIRENT(e) do { \ | | 574 | #define ADDDIRENT(e) do { \ |
572 | tmpdir.d_namlen = strlen((e)); \ | | 575 | tmpdir.d_namlen = strlen((e)); \ |
573 | this = DIRSIZ(0, &tmpdir, 0); \ | | 576 | this = DIRSIZ(0, &tmpdir, 0); \ |
574 | if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \ | | 577 | if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \ |
575 | printf("ADDDIRENT: was: %s (%d) this %d cur %d\n", \ | | 578 | printf("ADDDIRENT: was: %s (%d) this %d cur %d\n", \ |
576 | e, tmpdir.d_namlen, this, curdirsize); \ | | 579 | e, tmpdir.d_namlen, this, curdirsize); \ |
577 | if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ)) \ | | 580 | if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ)) \ |
578 | curdirsize = roundup(curdirsize, DIRBLKSIZ); \ | | 581 | curdirsize = roundup(curdirsize, DIRBLKSIZ); \ |
579 | curdirsize += this; \ | | 582 | curdirsize += this; \ |
580 | if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \ | | 583 | if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \ |
581 | printf("ADDDIRENT: now: %s (%d) this %d cur %d\n", \ | | 584 | printf("ADDDIRENT: now: %s (%d) this %d cur %d\n", \ |
582 | e, tmpdir.d_namlen, this, curdirsize); \ | | 585 | e, tmpdir.d_namlen, this, curdirsize); \ |
583 | } while (0); | | 586 | } while (0); |
584 | | | 587 | |
585 | /* | | 588 | /* |
586 | * XXX this needs to take into account extra space consumed | | 589 | * XXX this needs to take into account extra space consumed |
587 | * by indirect blocks, etc. | | 590 | * by indirect blocks, etc. |
588 | */ | | 591 | */ |
589 | #define ADDSIZE(x) do { \ | | 592 | #define ADDSIZE(x) do { \ |
590 | fsopts->size += roundup((x), ffs_opts->fsize); \ | | 593 | fsopts->size += roundup((x), ffs_opts->fsize); \ |
591 | } while (0); | | 594 | } while (0); |
592 | | | 595 | |
593 | curdirsize = 0; | | 596 | curdirsize = 0; |
594 | for (node = root; node != NULL; node = node->next) { | | 597 | for (node = root; node != NULL; node = node->next) { |
595 | ADDDIRENT(node->name); | | 598 | ADDDIRENT(node->name); |
596 | if (node == root) { /* we're at "." */ | | 599 | if (node == root) { /* we're at "." */ |
597 | assert(strcmp(node->name, ".") == 0); | | 600 | assert(strcmp(node->name, ".") == 0); |
598 | ADDDIRENT(".."); | | 601 | ADDDIRENT(".."); |
599 | } else if ((node->inode->flags & FI_SIZED) == 0) { | | 602 | } else if ((node->inode->flags & FI_SIZED) == 0) { |
600 | /* don't count duplicate names */ | | 603 | /* don't count duplicate names */ |
601 | node->inode->flags |= FI_SIZED; | | 604 | node->inode->flags |= FI_SIZED; |
602 | if (debug & DEBUG_FS_SIZE_DIR_NODE) | | 605 | if (debug & DEBUG_FS_SIZE_DIR_NODE) |
603 | printf("ffs_size_dir: `%s' size %lld\n", | | 606 | printf("ffs_size_dir: `%s' size %lld\n", |
604 | node->name, | | 607 | node->name, |
605 | (long long)node->inode->st.st_size); | | 608 | (long long)node->inode->st.st_size); |
606 | fsopts->inodes++; | | 609 | fsopts->inodes++; |
607 | if (node->type == S_IFREG) | | 610 | if (node->type == S_IFREG) |
608 | ADDSIZE(node->inode->st.st_size); | | 611 | ADDSIZE(node->inode->st.st_size); |
609 | if (node->type == S_IFLNK) { | | 612 | if (node->type == S_IFLNK) { |
610 | size_t slen; | | 613 | size_t slen; |
611 | | | 614 | |
612 | slen = strlen(node->symlink) + 1; | | 615 | slen = strlen(node->symlink) + 1; |
613 | if (slen >= (ffs_opts->version == 1 ? | | 616 | if (slen >= (ffs_opts->version == 1 ? |
614 | UFS1_MAXSYMLINKLEN : | | 617 | UFS1_MAXSYMLINKLEN : |
615 | UFS2_MAXSYMLINKLEN)) | | 618 | UFS2_MAXSYMLINKLEN)) |
616 | ADDSIZE(slen); | | 619 | ADDSIZE(slen); |
617 | } | | 620 | } |
618 | } | | 621 | } |
619 | if (node->type == S_IFDIR) | | 622 | if (node->type == S_IFDIR) |
620 | ffs_size_dir(node->child, fsopts); | | 623 | ffs_size_dir(node->child, fsopts); |
621 | } | | 624 | } |
622 | ADDSIZE(curdirsize); | | 625 | ADDSIZE(curdirsize); |
623 | | | 626 | |
624 | if (debug & DEBUG_FS_SIZE_DIR) | | 627 | if (debug & DEBUG_FS_SIZE_DIR) |
625 | printf("ffs_size_dir: exit: size %lld inodes %lld\n", | | 628 | printf("ffs_size_dir: exit: size %lld inodes %lld\n", |
626 | (long long)fsopts->size, (long long)fsopts->inodes); | | 629 | (long long)fsopts->size, (long long)fsopts->inodes); |
627 | } | | 630 | } |
628 | | | 631 | |
629 | static void * | | 632 | static void * |
630 | ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, | | 633 | ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, |
631 | fsnode *root, fsinfo_t *fsopts) | | 634 | fsnode *root, fsinfo_t *fsopts) |
632 | { | | 635 | { |
633 | size_t slen; | | 636 | size_t slen; |
634 | void *membuf; | | 637 | void *membuf; |
635 | | | 638 | |
636 | memset(dinp, 0, sizeof(*dinp)); | | 639 | memset(dinp, 0, sizeof(*dinp)); |
637 | dinp->di_mode = cur->inode->st.st_mode; | | 640 | dinp->di_mode = cur->inode->st.st_mode; |
638 | dinp->di_nlink = cur->inode->nlink; | | 641 | dinp->di_nlink = cur->inode->nlink; |
639 | dinp->di_size = cur->inode->st.st_size; | | 642 | dinp->di_size = cur->inode->st.st_size; |
640 | dinp->di_atime = cur->inode->st.st_atime; | | 643 | dinp->di_atime = cur->inode->st.st_atime; |
641 | dinp->di_mtime = cur->inode->st.st_mtime; | | 644 | dinp->di_mtime = cur->inode->st.st_mtime; |
642 | dinp->di_ctime = cur->inode->st.st_ctime; | | 645 | dinp->di_ctime = cur->inode->st.st_ctime; |
643 | #if HAVE_STRUCT_STAT_ST_MTIMENSEC | | 646 | #if HAVE_STRUCT_STAT_ST_MTIMENSEC |
644 | dinp->di_atimensec = cur->inode->st.st_atimensec; | | 647 | dinp->di_atimensec = cur->inode->st.st_atimensec; |
645 | dinp->di_mtimensec = cur->inode->st.st_mtimensec; | | 648 | dinp->di_mtimensec = cur->inode->st.st_mtimensec; |
646 | dinp->di_ctimensec = cur->inode->st.st_ctimensec; | | 649 | dinp->di_ctimensec = cur->inode->st.st_ctimensec; |
647 | #endif | | 650 | #endif |
648 | #if HAVE_STRUCT_STAT_ST_FLAGS | | 651 | #if HAVE_STRUCT_STAT_ST_FLAGS |
649 | dinp->di_flags = cur->inode->st.st_flags; | | 652 | dinp->di_flags = cur->inode->st.st_flags; |
650 | #endif | | 653 | #endif |
651 | #if HAVE_STRUCT_STAT_ST_GEN | | 654 | #if HAVE_STRUCT_STAT_ST_GEN |
652 | dinp->di_gen = cur->inode->st.st_gen; | | 655 | dinp->di_gen = cur->inode->st.st_gen; |
653 | #endif | | 656 | #endif |
654 | dinp->di_uid = cur->inode->st.st_uid; | | 657 | dinp->di_uid = cur->inode->st.st_uid; |
655 | dinp->di_gid = cur->inode->st.st_gid; | | 658 | dinp->di_gid = cur->inode->st.st_gid; |
656 | /* not set: di_db, di_ib, di_blocks, di_spare */ | | 659 | /* not set: di_db, di_ib, di_blocks, di_spare */ |
657 | | | 660 | |
658 | membuf = NULL; | | 661 | membuf = NULL; |
659 | if (cur == root) { /* "."; write dirbuf */ | | 662 | if (cur == root) { /* "."; write dirbuf */ |
660 | membuf = dbufp->buf; | | 663 | membuf = dbufp->buf; |
661 | dinp->di_size = dbufp->size; | | 664 | dinp->di_size = dbufp->size; |
662 | } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { | | 665 | } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { |
663 | dinp->di_size = 0; /* a device */ | | 666 | dinp->di_size = 0; /* a device */ |
664 | dinp->di_rdev = | | 667 | dinp->di_rdev = |
665 | ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap); | | 668 | ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap); |
666 | } else if (S_ISLNK(cur->type)) { /* symlink */ | | 669 | } else if (S_ISLNK(cur->type)) { /* symlink */ |
667 | slen = strlen(cur->symlink); | | 670 | slen = strlen(cur->symlink); |
668 | if (slen < UFS1_MAXSYMLINKLEN) { /* short link */ | | 671 | if (slen < UFS1_MAXSYMLINKLEN) { /* short link */ |
669 | memcpy(dinp->di_db, cur->symlink, slen); | | 672 | memcpy(dinp->di_db, cur->symlink, slen); |
670 | } else | | 673 | } else |
671 | membuf = cur->symlink; | | 674 | membuf = cur->symlink; |
672 | dinp->di_size = slen; | | 675 | dinp->di_size = slen; |
673 | } | | 676 | } |
674 | return membuf; | | 677 | return membuf; |
675 | } | | 678 | } |
676 | | | 679 | |
677 | static void * | | 680 | static void * |
678 | ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, | | 681 | ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur, |
679 | fsnode *root, fsinfo_t *fsopts) | | 682 | fsnode *root, fsinfo_t *fsopts) |
680 | { | | 683 | { |
681 | size_t slen; | | 684 | size_t slen; |
682 | void *membuf; | | 685 | void *membuf; |
683 | | | 686 | |
684 | memset(dinp, 0, sizeof(*dinp)); | | 687 | memset(dinp, 0, sizeof(*dinp)); |
685 | dinp->di_mode = cur->inode->st.st_mode; | | 688 | dinp->di_mode = cur->inode->st.st_mode; |
686 | dinp->di_nlink = cur->inode->nlink; | | 689 | dinp->di_nlink = cur->inode->nlink; |
687 | dinp->di_size = cur->inode->st.st_size; | | 690 | dinp->di_size = cur->inode->st.st_size; |
688 | dinp->di_atime = cur->inode->st.st_atime; | | 691 | dinp->di_atime = cur->inode->st.st_atime; |
689 | dinp->di_mtime = cur->inode->st.st_mtime; | | 692 | dinp->di_mtime = cur->inode->st.st_mtime; |
690 | dinp->di_ctime = cur->inode->st.st_ctime; | | 693 | dinp->di_ctime = cur->inode->st.st_ctime; |
691 | #if HAVE_STRUCT_STAT_ST_MTIMENSEC | | 694 | #if HAVE_STRUCT_STAT_ST_MTIMENSEC |
692 | dinp->di_atimensec = cur->inode->st.st_atimensec; | | 695 | dinp->di_atimensec = cur->inode->st.st_atimensec; |
693 | dinp->di_mtimensec = cur->inode->st.st_mtimensec; | | 696 | dinp->di_mtimensec = cur->inode->st.st_mtimensec; |
694 | dinp->di_ctimensec = cur->inode->st.st_ctimensec; | | 697 | dinp->di_ctimensec = cur->inode->st.st_ctimensec; |
695 | #endif | | 698 | #endif |
696 | #if HAVE_STRUCT_STAT_ST_FLAGS | | 699 | #if HAVE_STRUCT_STAT_ST_FLAGS |
697 | dinp->di_flags = cur->inode->st.st_flags; | | 700 | dinp->di_flags = cur->inode->st.st_flags; |
698 | #endif | | 701 | #endif |
699 | #if HAVE_STRUCT_STAT_ST_GEN | | 702 | #if HAVE_STRUCT_STAT_ST_GEN |
700 | dinp->di_gen = cur->inode->st.st_gen; | | 703 | dinp->di_gen = cur->inode->st.st_gen; |
701 | #endif | | 704 | #endif |
702 | #if HAVE_STRUCT_STAT_BIRTHTIME | | 705 | #if HAVE_STRUCT_STAT_BIRTHTIME |
703 | dinp->di_birthtime = cur->inode->st.st_birthtime; | | 706 | dinp->di_birthtime = cur->inode->st.st_birthtime; |
704 | dinp->di_birthnsec = cur->inode->st.st_birthtimensec; | | 707 | dinp->di_birthnsec = cur->inode->st.st_birthtimensec; |
705 | #endif | | 708 | #endif |
706 | dinp->di_uid = cur->inode->st.st_uid; | | 709 | dinp->di_uid = cur->inode->st.st_uid; |
707 | dinp->di_gid = cur->inode->st.st_gid; | | 710 | dinp->di_gid = cur->inode->st.st_gid; |
708 | /* not set: di_db, di_ib, di_blocks, di_spare */ | | 711 | /* not set: di_db, di_ib, di_blocks, di_spare */ |
709 | | | 712 | |
710 | membuf = NULL; | | 713 | membuf = NULL; |
711 | if (cur == root) { /* "."; write dirbuf */ | | 714 | if (cur == root) { /* "."; write dirbuf */ |
712 | membuf = dbufp->buf; | | 715 | membuf = dbufp->buf; |
713 | dinp->di_size = dbufp->size; | | 716 | dinp->di_size = dbufp->size; |
714 | } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { | | 717 | } else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) { |
715 | dinp->di_size = 0; /* a device */ | | 718 | dinp->di_size = 0; /* a device */ |
716 | dinp->di_rdev = | | 719 | dinp->di_rdev = |
717 | ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap); | | 720 | ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap); |
718 | } else if (S_ISLNK(cur->type)) { /* symlink */ | | 721 | } else if (S_ISLNK(cur->type)) { /* symlink */ |
719 | slen = strlen(cur->symlink); | | 722 | slen = strlen(cur->symlink); |
720 | if (slen < UFS2_MAXSYMLINKLEN) { /* short link */ | | 723 | if (slen < UFS2_MAXSYMLINKLEN) { /* short link */ |
721 | memcpy(dinp->di_db, cur->symlink, slen); | | 724 | memcpy(dinp->di_db, cur->symlink, slen); |
722 | } else | | 725 | } else |
723 | membuf = cur->symlink; | | 726 | membuf = cur->symlink; |
724 | dinp->di_size = slen; | | 727 | dinp->di_size = slen; |
725 | } | | 728 | } |
726 | return membuf; | | 729 | return membuf; |
727 | } | | 730 | } |
728 | | | 731 | |
729 | static int | | 732 | static int |
730 | ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts) | | 733 | ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts) |
731 | { | | 734 | { |
732 | fsnode *cur; | | 735 | fsnode *cur; |
733 | dirbuf_t dirbuf; | | 736 | dirbuf_t dirbuf; |
734 | union dinode din; | | 737 | union dinode din; |
735 | void *membuf; | | 738 | void *membuf; |
736 | char path[MAXPATHLEN + 1]; | | 739 | char path[MAXPATHLEN + 1]; |
737 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | | 740 | ffs_opt_t *ffs_opts = fsopts->fs_specific; |
738 | | | 741 | |
739 | assert(dir != NULL); | | 742 | assert(dir != NULL); |
740 | assert(root != NULL); | | 743 | assert(root != NULL); |
741 | assert(fsopts != NULL); | | 744 | assert(fsopts != NULL); |
742 | assert(ffs_opts != NULL); | | 745 | assert(ffs_opts != NULL); |
743 | | | 746 | |
744 | (void)memset(&dirbuf, 0, sizeof(dirbuf)); | | 747 | (void)memset(&dirbuf, 0, sizeof(dirbuf)); |
745 | | | 748 | |
746 | if (debug & DEBUG_FS_POPULATE) | | 749 | if (debug & DEBUG_FS_POPULATE) |
747 | printf("ffs_populate_dir: PASS 1 dir %s node %p\n", dir, root); | | 750 | printf("ffs_populate_dir: PASS 1 dir %s node %p\n", dir, root); |
748 | | | 751 | |
749 | /* | | 752 | /* |
750 | * pass 1: allocate inode numbers, build directory `file' | | 753 | * pass 1: allocate inode numbers, build directory `file' |
751 | */ | | 754 | */ |
752 | for (cur = root; cur != NULL; cur = cur->next) { | | 755 | for (cur = root; cur != NULL; cur = cur->next) { |
753 | if ((cur->inode->flags & FI_ALLOCATED) == 0) { | | 756 | if ((cur->inode->flags & FI_ALLOCATED) == 0) { |
754 | cur->inode->flags |= FI_ALLOCATED; | | 757 | cur->inode->flags |= FI_ALLOCATED; |
755 | if (cur == root && cur->parent != NULL) | | 758 | if (cur == root && cur->parent != NULL) |
756 | cur->inode->ino = cur->parent->inode->ino; | | 759 | cur->inode->ino = cur->parent->inode->ino; |
757 | else { | | 760 | else { |
758 | cur->inode->ino = fsopts->curinode; | | 761 | cur->inode->ino = fsopts->curinode; |
759 | fsopts->curinode++; | | 762 | fsopts->curinode++; |
760 | } | | 763 | } |
761 | } | | 764 | } |
762 | ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap); | | 765 | ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap); |
763 | if (cur == root) { /* we're at "."; add ".." */ | | 766 | if (cur == root) { /* we're at "."; add ".." */ |
764 | ffs_make_dirbuf(&dirbuf, "..", | | 767 | ffs_make_dirbuf(&dirbuf, "..", |
765 | cur->parent == NULL ? cur : cur->parent->first, | | 768 | cur->parent == NULL ? cur : cur->parent->first, |
766 | fsopts->needswap); | | 769 | fsopts->needswap); |
767 | root->inode->nlink++; /* count my parent's link */ | | 770 | root->inode->nlink++; /* count my parent's link */ |
768 | } else if (cur->child != NULL) | | 771 | } else if (cur->child != NULL) |
769 | root->inode->nlink++; /* count my child's link */ | | 772 | root->inode->nlink++; /* count my child's link */ |
770 | | | 773 | |
771 | /* | | 774 | /* |
772 | * XXX possibly write file and long symlinks here, | | 775 | * XXX possibly write file and long symlinks here, |
773 | * ensuring that blocks get written before inodes? | | 776 | * ensuring that blocks get written before inodes? |
774 | * otoh, this isn't a real filesystem, so who | | 777 | * otoh, this isn't a real filesystem, so who |
775 | * cares about ordering? :-) | | 778 | * cares about ordering? :-) |
776 | */ | | 779 | */ |
777 | } | | 780 | } |
778 | if (debug & DEBUG_FS_POPULATE_DIRBUF) | | 781 | if (debug & DEBUG_FS_POPULATE_DIRBUF) |
779 | ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap); | | 782 | ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap); |
780 | | | 783 | |
781 | /* | | 784 | /* |
782 | * pass 2: write out dirbuf, then non-directories at this level | | 785 | * pass 2: write out dirbuf, then non-directories at this level |
783 | */ | | 786 | */ |
784 | if (debug & DEBUG_FS_POPULATE) | | 787 | if (debug & DEBUG_FS_POPULATE) |
785 | printf("ffs_populate_dir: PASS 2 dir %s\n", dir); | | 788 | printf("ffs_populate_dir: PASS 2 dir %s\n", dir); |
786 | for (cur = root; cur != NULL; cur = cur->next) { | | 789 | for (cur = root; cur != NULL; cur = cur->next) { |
787 | if (cur->inode->flags & FI_WRITTEN) | | 790 | if (cur->inode->flags & FI_WRITTEN) |
788 | continue; /* skip hard-linked entries */ | | 791 | continue; /* skip hard-linked entries */ |
789 | cur->inode->flags |= FI_WRITTEN; | | 792 | cur->inode->flags |= FI_WRITTEN; |
790 | | | 793 | |
791 | if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root, | | 794 | if ((size_t)snprintf(path, sizeof(path), "%s/%s/%s", cur->root, |
792 | cur->path, cur->name) >= sizeof(path)) | | 795 | cur->path, cur->name) >= sizeof(path)) |
793 | errx(1, "Pathname too long."); | | 796 | errx(1, "Pathname too long."); |
794 | | | 797 | |
795 | if (cur->child != NULL) | | 798 | if (cur->child != NULL) |
796 | continue; /* child creates own inode */ | | 799 | continue; /* child creates own inode */ |
797 | | | 800 | |
798 | /* build on-disk inode */ | | 801 | /* build on-disk inode */ |
799 | if (ffs_opts->version == 1) | | 802 | if (ffs_opts->version == 1) |
800 | membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur, | | 803 | membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur, |
801 | root, fsopts); | | 804 | root, fsopts); |
802 | else | | 805 | else |
803 | membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur, | | 806 | membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur, |
804 | root, fsopts); | | 807 | root, fsopts); |
805 | | | 808 | |
806 | if (debug & DEBUG_FS_POPULATE_NODE) { | | 809 | if (debug & DEBUG_FS_POPULATE_NODE) { |
807 | printf("ffs_populate_dir: writing ino %d, %s", | | 810 | printf("ffs_populate_dir: writing ino %d, %s", |
808 | cur->inode->ino, inode_type(cur->type)); | | 811 | cur->inode->ino, inode_type(cur->type)); |
809 | if (cur->inode->nlink > 1) | | 812 | if (cur->inode->nlink > 1) |
810 | printf(", nlink %d", cur->inode->nlink); | | 813 | printf(", nlink %d", cur->inode->nlink); |
811 | putchar('\n'); | | 814 | putchar('\n'); |
812 | } | | 815 | } |
813 | | | 816 | |
814 | if (membuf != NULL) { | | 817 | if (membuf != NULL) { |
815 | ffs_write_file(&din, cur->inode->ino, membuf, fsopts); | | 818 | ffs_write_file(&din, cur->inode->ino, membuf, fsopts); |
816 | } else if (S_ISREG(cur->type)) { | | 819 | } else if (S_ISREG(cur->type)) { |
817 | ffs_write_file(&din, cur->inode->ino, path, fsopts); | | 820 | ffs_write_file(&din, cur->inode->ino, path, fsopts); |
818 | } else { | | 821 | } else { |
819 | assert (! S_ISDIR(cur->type)); | | 822 | assert (! S_ISDIR(cur->type)); |
820 | ffs_write_inode(&din, cur->inode->ino, fsopts); | | 823 | ffs_write_inode(&din, cur->inode->ino, fsopts); |
821 | } | | 824 | } |
822 | } | | 825 | } |
823 | | | 826 | |
824 | /* | | 827 | /* |
825 | * pass 3: write out sub-directories | | 828 | * pass 3: write out sub-directories |
826 | */ | | 829 | */ |
827 | if (debug & DEBUG_FS_POPULATE) | | 830 | if (debug & DEBUG_FS_POPULATE) |
828 | printf("ffs_populate_dir: PASS 3 dir %s\n", dir); | | 831 | printf("ffs_populate_dir: PASS 3 dir %s\n", dir); |
829 | for (cur = root; cur != NULL; cur = cur->next) { | | 832 | for (cur = root; cur != NULL; cur = cur->next) { |
830 | if (cur->child == NULL) | | 833 | if (cur->child == NULL) |
831 | continue; | | 834 | continue; |
832 | if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir, | | 835 | if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir, |
833 | cur->name) >= sizeof(path)) | | 836 | cur->name) >= sizeof(path)) |
834 | errx(1, "Pathname too long."); | | 837 | errx(1, "Pathname too long."); |
835 | if (! ffs_populate_dir(path, cur->child, fsopts)) | | 838 | if (! ffs_populate_dir(path, cur->child, fsopts)) |
836 | return (0); | | 839 | return (0); |
837 | } | | 840 | } |
838 | | | 841 | |
839 | if (debug & DEBUG_FS_POPULATE) | | 842 | if (debug & DEBUG_FS_POPULATE) |
840 | printf("ffs_populate_dir: DONE dir %s\n", dir); | | 843 | printf("ffs_populate_dir: DONE dir %s\n", dir); |
841 | | | 844 | |
842 | /* cleanup */ | | 845 | /* cleanup */ |
843 | if (dirbuf.buf != NULL) | | 846 | if (dirbuf.buf != NULL) |
844 | free(dirbuf.buf); | | 847 | free(dirbuf.buf); |
845 | return (1); | | 848 | return (1); |
846 | } | | 849 | } |
847 | | | 850 | |
848 | | | 851 | |
849 | static void | | 852 | static void |
850 | ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts) | | 853 | ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts) |
851 | { | | 854 | { |
852 | int isfile, ffd; | | 855 | int isfile, ffd; |
853 | char *fbuf, *p; | | 856 | char *fbuf, *p; |
854 | off_t bufleft, chunk, offset; | | 857 | off_t bufleft, chunk, offset; |
855 | ssize_t nread; | | 858 | ssize_t nread; |
856 | struct inode in; | | 859 | struct inode in; |
857 | struct buf * bp; | | 860 | struct buf * bp; |
858 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | | 861 | ffs_opt_t *ffs_opts = fsopts->fs_specific; |
859 | | | 862 | |
860 | assert (din != NULL); | | 863 | assert (din != NULL); |
861 | assert (buf != NULL); | | 864 | assert (buf != NULL); |
862 | assert (fsopts != NULL); | | 865 | assert (fsopts != NULL); |
863 | assert (ffs_opts != NULL); | | 866 | assert (ffs_opts != NULL); |
864 | | | 867 | |
865 | isfile = S_ISREG(DIP(din, mode)); | | 868 | isfile = S_ISREG(DIP(din, mode)); |
866 | fbuf = NULL; | | 869 | fbuf = NULL; |
867 | ffd = -1; | | 870 | ffd = -1; |
868 | p = NULL; | | 871 | p = NULL; |
869 | | | 872 | |
870 | in.i_fs = (struct fs *)fsopts->superblock; | | 873 | in.i_fs = (struct fs *)fsopts->superblock; |
871 | | | 874 | |
872 | if (debug & DEBUG_FS_WRITE_FILE) { | | 875 | if (debug & DEBUG_FS_WRITE_FILE) { |
873 | printf( | | 876 | printf( |
874 | "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld", | | 877 | "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld", |
875 | ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT), | | 878 | ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT), |
876 | (long long)DIP(din, size)); | | 879 | (long long)DIP(din, size)); |
877 | if (isfile) | | 880 | if (isfile) |
878 | printf(", file '%s'\n", (char *)buf); | | 881 | printf(", file '%s'\n", (char *)buf); |
879 | else | | 882 | else |
880 | printf(", buffer %p\n", buf); | | 883 | printf(", buffer %p\n", buf); |
881 | } | | 884 | } |
882 | | | 885 | |
883 | in.i_number = ino; | | 886 | in.i_number = ino; |
884 | in.i_size = DIP(din, size); | | 887 | in.i_size = DIP(din, size); |
885 | if (ffs_opts->version == 1) | | 888 | if (ffs_opts->version == 1) |
886 | memcpy(&in.i_din.ffs1_din, &din->ffs1_din, | | 889 | memcpy(&in.i_din.ffs1_din, &din->ffs1_din, |
887 | sizeof(in.i_din.ffs1_din)); | | 890 | sizeof(in.i_din.ffs1_din)); |
888 | else | | 891 | else |
889 | memcpy(&in.i_din.ffs2_din, &din->ffs2_din, | | 892 | memcpy(&in.i_din.ffs2_din, &din->ffs2_din, |
890 | sizeof(in.i_din.ffs2_din)); | | 893 | sizeof(in.i_din.ffs2_din)); |
891 | in.i_fd = fsopts->fd; | | 894 | in.i_fd = fsopts->fd; |
892 | | | 895 | |
893 | if (DIP(din, size) == 0) | | 896 | if (DIP(din, size) == 0) |
894 | goto write_inode_and_leave; /* mmm, cheating */ | | 897 | goto write_inode_and_leave; /* mmm, cheating */ |
895 | | | 898 | |
896 | if (isfile) { | | 899 | if (isfile) { |
897 | if ((fbuf = malloc(ffs_opts->bsize)) == NULL) | | 900 | if ((fbuf = malloc(ffs_opts->bsize)) == NULL) |
898 | err(1, "Allocating memory for write buffer"); | | 901 | err(1, "Allocating memory for write buffer"); |
899 | if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) { | | 902 | if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) { |
900 | warn("Can't open `%s' for reading", (char *)buf); | | 903 | warn("Can't open `%s' for reading", (char *)buf); |
901 | goto leave_ffs_write_file; | | 904 | goto leave_ffs_write_file; |
902 | } | | 905 | } |
903 | } else { | | 906 | } else { |
904 | p = buf; | | 907 | p = buf; |
905 | } | | 908 | } |
906 | | | 909 | |
907 | chunk = 0; | | 910 | chunk = 0; |
908 | for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) { | | 911 | for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) { |
909 | chunk = MIN(bufleft, ffs_opts->bsize); | | 912 | chunk = MIN(bufleft, ffs_opts->bsize); |
910 | if (!isfile) | | 913 | if (!isfile) |
911 | ; | | 914 | ; |
912 | else if ((nread = read(ffd, fbuf, chunk)) == -1) | | 915 | else if ((nread = read(ffd, fbuf, chunk)) == -1) |
913 | err(EXIT_FAILURE, "Reading `%s', %lld bytes to go", | | 916 | err(EXIT_FAILURE, "Reading `%s', %lld bytes to go", |
914 | (char *)buf, (long long)bufleft); | | 917 | (char *)buf, (long long)bufleft); |
915 | else if (nread != chunk) | | 918 | else if (nread != chunk) |
916 | errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, " | | 919 | errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, " |
917 | "read %zd bytes, expected %ju bytes, does " | | 920 | "read %zd bytes, expected %ju bytes, does " |
918 | "metalog size= attribute mismatch source size?", | | 921 | "metalog size= attribute mismatch source size?", |
919 | (char *)buf, (long long)bufleft, nread, | | 922 | (char *)buf, (long long)bufleft, nread, |
920 | (uintmax_t)chunk); | | 923 | (uintmax_t)chunk); |
921 | else | | 924 | else |
922 | p = fbuf; | | 925 | p = fbuf; |
923 | offset = DIP(din, size) - bufleft; | | 926 | offset = DIP(din, size) - bufleft; |
924 | if (debug & DEBUG_FS_WRITE_FILE_BLOCK) | | 927 | if (debug & DEBUG_FS_WRITE_FILE_BLOCK) |
925 | printf( | | 928 | printf( |
926 | "ffs_write_file: write %p offset %lld size %lld left %lld\n", | | 929 | "ffs_write_file: write %p offset %lld size %lld left %lld\n", |
927 | p, (long long)offset, | | 930 | p, (long long)offset, |
928 | (long long)chunk, (long long)bufleft); | | 931 | (long long)chunk, (long long)bufleft); |
929 | /* | | 932 | /* |
930 | * XXX if holey support is desired, do the check here | | 933 | * XXX if holey support is desired, do the check here |
931 | * | | 934 | * |
932 | * XXX might need to write out last bit in fragroundup | | 935 | * XXX might need to write out last bit in fragroundup |
933 | * sized chunk. however, ffs_balloc() handles this for us | | 936 | * sized chunk. however, ffs_balloc() handles this for us |
934 | */ | | 937 | */ |
935 | errno = ffs_balloc(&in, offset, chunk, &bp); | | 938 | errno = ffs_balloc(&in, offset, chunk, &bp); |
936 | bad_ffs_write_file: | | 939 | bad_ffs_write_file: |
937 | if (errno != 0) | | 940 | if (errno != 0) |
938 | err(1, | | 941 | err(1, |
939 | "Writing inode %d (%s), bytes %lld + %lld", | | 942 | "Writing inode %d (%s), bytes %lld + %lld", |
940 | ino, | | 943 | ino, |
941 | isfile ? (char *)buf : | | 944 | isfile ? (char *)buf : |
942 | inode_type(DIP(din, mode) & S_IFMT), | | 945 | inode_type(DIP(din, mode) & S_IFMT), |
943 | (long long)offset, (long long)chunk); | | 946 | (long long)offset, (long long)chunk); |
944 | memcpy(bp->b_data, p, chunk); | | 947 | memcpy(bp->b_data, p, chunk); |
945 | errno = bwrite(bp); | | 948 | errno = bwrite(bp); |
946 | if (errno != 0) | | 949 | if (errno != 0) |
947 | goto bad_ffs_write_file; | | 950 | goto bad_ffs_write_file; |
948 | brelse(bp); | | 951 | brelse(bp); |
949 | if (!isfile) | | 952 | if (!isfile) |
950 | p += chunk; | | 953 | p += chunk; |
951 | } | | 954 | } |
952 | | | 955 | |
953 | write_inode_and_leave: | | 956 | write_inode_and_leave: |
954 | ffs_write_inode(&in.i_din, in.i_number, fsopts); | | 957 | ffs_write_inode(&in.i_din, in.i_number, fsopts); |
955 | | | 958 | |
956 | leave_ffs_write_file: | | 959 | leave_ffs_write_file: |
957 | if (fbuf) | | 960 | if (fbuf) |
958 | free(fbuf); | | 961 | free(fbuf); |
959 | if (ffd != -1) | | 962 | if (ffd != -1) |
960 | close(ffd); | | 963 | close(ffd); |
961 | } | | 964 | } |
962 | | | 965 | |
963 | | | 966 | |
964 | static void | | 967 | static void |
965 | ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap) | | 968 | ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap) |
966 | { | | 969 | { |
967 | doff_t i; | | 970 | doff_t i; |
968 | struct direct *de; | | 971 | struct direct *de; |
969 | uint16_t reclen; | | 972 | uint16_t reclen; |
970 | | | 973 | |
971 | assert (dbuf != NULL); | | 974 | assert (dbuf != NULL); |
972 | assert (dir != NULL); | | 975 | assert (dir != NULL); |
973 | printf("ffs_dump_dirbuf: dir %s size %d cur %d\n", | | 976 | printf("ffs_dump_dirbuf: dir %s size %d cur %d\n", |
974 | dir, dbuf->size, dbuf->cur); | | 977 | dir, dbuf->size, dbuf->cur); |
975 | | | 978 | |
976 | for (i = 0; i < dbuf->size; ) { | | 979 | for (i = 0; i < dbuf->size; ) { |
977 | de = (struct direct *)(dbuf->buf + i); | | 980 | de = (struct direct *)(dbuf->buf + i); |
978 | reclen = ufs_rw16(de->d_reclen, needswap); | | 981 | reclen = ufs_rw16(de->d_reclen, needswap); |
979 | printf( | | 982 | printf( |
980 | " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n", | | 983 | " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n", |
981 | ufs_rw32(de->d_fileno, needswap), | | 984 | ufs_rw32(de->d_fileno, needswap), |
982 | inode_type(DTTOIF(de->d_type)), i, reclen, | | 985 | inode_type(DTTOIF(de->d_type)), i, reclen, |
983 | de->d_namlen, de->d_name); | | 986 | de->d_namlen, de->d_name); |
984 | i += reclen; | | 987 | i += reclen; |
985 | assert(reclen > 0); | | 988 | assert(reclen > 0); |
986 | } | | 989 | } |
987 | } | | 990 | } |
988 | | | 991 | |
989 | static void | | 992 | static void |
990 | ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap) | | 993 | ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap) |
991 | { | | 994 | { |
992 | struct direct de, *dp; | | 995 | struct direct de, *dp; |
993 | uint16_t llen, reclen; | | 996 | uint16_t llen, reclen; |
994 | u_char *newbuf; | | 997 | u_char *newbuf; |
995 | | | 998 | |
996 | assert (dbuf != NULL); | | 999 | assert (dbuf != NULL); |
997 | assert (name != NULL); | | 1000 | assert (name != NULL); |
998 | assert (node != NULL); | | 1001 | assert (node != NULL); |
999 | /* create direct entry */ | | 1002 | /* create direct entry */ |
1000 | (void)memset(&de, 0, sizeof(de)); | | 1003 | (void)memset(&de, 0, sizeof(de)); |
1001 | de.d_fileno = ufs_rw32(node->inode->ino, needswap); | | 1004 | de.d_fileno = ufs_rw32(node->inode->ino, needswap); |
1002 | de.d_type = IFTODT(node->type); | | 1005 | de.d_type = IFTODT(node->type); |
1003 | de.d_namlen = (uint8_t)strlen(name); | | 1006 | de.d_namlen = (uint8_t)strlen(name); |
1004 | strcpy(de.d_name, name); | | 1007 | strcpy(de.d_name, name); |
1005 | reclen = DIRSIZ(0, &de, needswap); | | 1008 | reclen = DIRSIZ(0, &de, needswap); |
1006 | de.d_reclen = ufs_rw16(reclen, needswap); | | 1009 | de.d_reclen = ufs_rw16(reclen, needswap); |
1007 | | | 1010 | |
1008 | dp = (struct direct *)(dbuf->buf + dbuf->cur); | | 1011 | dp = (struct direct *)(dbuf->buf + dbuf->cur); |
1009 | llen = 0; | | 1012 | llen = 0; |
1010 | if (dp != NULL) | | 1013 | if (dp != NULL) |
1011 | llen = DIRSIZ(0, dp, needswap); | | 1014 | llen = DIRSIZ(0, dp, needswap); |
1012 | | | 1015 | |
1013 | if (debug & DEBUG_FS_MAKE_DIRBUF) | | 1016 | if (debug & DEBUG_FS_MAKE_DIRBUF) |
1014 | printf( | | 1017 | printf( |
1015 | "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n" | | 1018 | "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n" |
1016 | " ino %d type %d reclen %d namlen %d name %.30s\n", | | 1019 | " ino %d type %d reclen %d namlen %d name %.30s\n", |
1017 | dbuf->size, dbuf->cur, llen, | | 1020 | dbuf->size, dbuf->cur, llen, |
1018 | ufs_rw32(de.d_fileno, needswap), de.d_type, reclen, | | 1021 | ufs_rw32(de.d_fileno, needswap), de.d_type, reclen, |
1019 | de.d_namlen, de.d_name); | | 1022 | de.d_namlen, de.d_name); |
1020 | | | 1023 | |
1021 | if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) { | | 1024 | if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) { |
1022 | if (debug & DEBUG_FS_MAKE_DIRBUF) | | 1025 | if (debug & DEBUG_FS_MAKE_DIRBUF) |
1023 | printf("ffs_make_dirbuf: growing buf to %d\n", | | 1026 | printf("ffs_make_dirbuf: growing buf to %d\n", |
1024 | dbuf->size + DIRBLKSIZ); | | 1027 | dbuf->size + DIRBLKSIZ); |
1025 | if ((newbuf = realloc(dbuf->buf, dbuf->size + DIRBLKSIZ)) == NULL) | | 1028 | if ((newbuf = realloc(dbuf->buf, dbuf->size + DIRBLKSIZ)) == NULL) |
1026 | err(1, "Allocating memory for directory buffer"); | | 1029 | err(1, "Allocating memory for directory buffer"); |
1027 | dbuf->buf = newbuf; | | 1030 | dbuf->buf = newbuf; |
1028 | dbuf->size += DIRBLKSIZ; | | 1031 | dbuf->size += DIRBLKSIZ; |
1029 | memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ); | | 1032 | memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ); |
1030 | dbuf->cur = dbuf->size - DIRBLKSIZ; | | 1033 | dbuf->cur = dbuf->size - DIRBLKSIZ; |
1031 | } else if (dp) { /* shrink end of previous */ | | 1034 | } else if (dp) { /* shrink end of previous */ |
1032 | dp->d_reclen = ufs_rw16(llen,needswap); | | 1035 | dp->d_reclen = ufs_rw16(llen,needswap); |
1033 | dbuf->cur += llen; | | 1036 | dbuf->cur += llen; |
1034 | } | | 1037 | } |
1035 | dp = (struct direct *)(dbuf->buf + dbuf->cur); | | 1038 | dp = (struct direct *)(dbuf->buf + dbuf->cur); |
1036 | memcpy(dp, &de, reclen); | | 1039 | memcpy(dp, &de, reclen); |
1037 | dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap); | | 1040 | dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap); |
1038 | } | | 1041 | } |
1039 | | | 1042 | |
1040 | /* | | 1043 | /* |
1041 | * cribbed from sys/ufs/ffs/ffs_alloc.c | | 1044 | * cribbed from sys/ufs/ffs/ffs_alloc.c |
1042 | */ | | 1045 | */ |
1043 | static void | | 1046 | static void |
1044 | ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts) | | 1047 | ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts) |
1045 | { | | 1048 | { |
1046 | char *buf; | | 1049 | char *buf; |
1047 | struct ufs1_dinode *dp1; | | 1050 | struct ufs1_dinode *dp1; |
1048 | struct ufs2_dinode *dp2, *dip; | | 1051 | struct ufs2_dinode *dp2, *dip; |
1049 | struct cg *cgp; | | 1052 | struct cg *cgp; |
1050 | struct fs *fs; | | 1053 | struct fs *fs; |
1051 | int cg, cgino, i; | | 1054 | int cg, cgino, i; |
1052 | daddr_t d; | | 1055 | daddr_t d; |
1053 | char sbbuf[FFS_MAXBSIZE]; | | 1056 | char sbbuf[FFS_MAXBSIZE]; |
1054 | uint32_t initediblk; | | 1057 | uint32_t initediblk; |
1055 | ffs_opt_t *ffs_opts = fsopts->fs_specific; | | 1058 | ffs_opt_t *ffs_opts = fsopts->fs_specific; |
1056 | | | 1059 | |
1057 | assert (dp != NULL); | | 1060 | assert (dp != NULL); |
1058 | assert (ino > 0); | | 1061 | assert (ino > 0); |
1059 | assert (fsopts != NULL); | | 1062 | assert (fsopts != NULL); |
1060 | assert (ffs_opts != NULL); | | 1063 | assert (ffs_opts != NULL); |
1061 | | | 1064 | |
1062 | fs = (struct fs *)fsopts->superblock; | | 1065 | fs = (struct fs *)fsopts->superblock; |
1063 | cg = ino_to_cg(fs, ino); | | 1066 | cg = ino_to_cg(fs, ino); |
1064 | cgino = ino % fs->fs_ipg; | | 1067 | cgino = ino % fs->fs_ipg; |
1065 | if (debug & DEBUG_FS_WRITE_INODE) | | 1068 | if (debug & DEBUG_FS_WRITE_INODE) |
1066 | printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n", | | 1069 | printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n", |
1067 | dp, ino, cg, cgino); | | 1070 | dp, ino, cg, cgino); |
1068 | | | 1071 | |
1069 | ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, | | 1072 | ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, |
1070 | fsopts); | | 1073 | fsopts); |
1071 | cgp = (struct cg *)sbbuf; | | 1074 | cgp = (struct cg *)sbbuf; |
1072 | if (!cg_chkmagic(cgp, fsopts->needswap)) | | 1075 | if (!cg_chkmagic(cgp, fsopts->needswap)) |
1073 | errx(1, "ffs_write_inode: cg %d: bad magic number", cg); | | 1076 | errx(1, "ffs_write_inode: cg %d: bad magic number", cg); |
1074 | | | 1077 | |
1075 | assert (isclr(cg_inosused(cgp, fsopts->needswap), cgino)); | | 1078 | assert (isclr(cg_inosused(cgp, fsopts->needswap), cgino)); |
1076 | | | 1079 | |
1077 | buf = malloc(fs->fs_bsize); | | 1080 | buf = malloc(fs->fs_bsize); |
1078 | if (buf == NULL) | | 1081 | if (buf == NULL) |
1079 | errx(1, "ffs_write_inode: cg %d: can't alloc inode block", cg); | | 1082 | errx(1, "ffs_write_inode: cg %d: can't alloc inode block", cg); |
1080 | | | 1083 | |
1081 | dp1 = (struct ufs1_dinode *)buf; | | 1084 | dp1 = (struct ufs1_dinode *)buf; |
1082 | dp2 = (struct ufs2_dinode *)buf; | | 1085 | dp2 = (struct ufs2_dinode *)buf; |
1083 | | | 1086 | |
1084 | if (fs->fs_cstotal.cs_nifree == 0) | | 1087 | if (fs->fs_cstotal.cs_nifree == 0) |
1085 | errx(1, "ffs_write_inode: fs out of inodes for ino %u", | | 1088 | errx(1, "ffs_write_inode: fs out of inodes for ino %u", |
1086 | ino); | | 1089 | ino); |
1087 | if (fs->fs_cs(fs, cg).cs_nifree == 0) | | 1090 | if (fs->fs_cs(fs, cg).cs_nifree == 0) |
1088 | errx(1, | | 1091 | errx(1, |
1089 | "ffs_write_inode: cg %d out of inodes for ino %u", | | 1092 | "ffs_write_inode: cg %d out of inodes for ino %u", |
1090 | cg, ino); | | 1093 | cg, ino); |
1091 | setbit(cg_inosused(cgp, fsopts->needswap), cgino); | | 1094 | setbit(cg_inosused(cgp, fsopts->needswap), cgino); |
1092 | ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap); | | 1095 | ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap); |
1093 | fs->fs_cstotal.cs_nifree--; | | 1096 | fs->fs_cstotal.cs_nifree--; |
1094 | fs->fs_cs(fs, cg).cs_nifree--; | | 1097 | fs->fs_cs(fs, cg).cs_nifree--; |
1095 | if (S_ISDIR(DIP(dp, mode))) { | | 1098 | if (S_ISDIR(DIP(dp, mode))) { |
1096 | ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap); | | 1099 | ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap); |
1097 | fs->fs_cstotal.cs_ndir++; | | 1100 | fs->fs_cstotal.cs_ndir++; |
1098 | fs->fs_cs(fs, cg).cs_ndir++; | | 1101 | fs->fs_cs(fs, cg).cs_ndir++; |
1099 | } | | 1102 | } |
1100 | | | 1103 | |
1101 | /* | | 1104 | /* |
1102 | * Initialize inode blocks on the fly for UFS2. | | 1105 | * Initialize inode blocks on the fly for UFS2. |
1103 | */ | | 1106 | */ |
1104 | initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap); | | 1107 | initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap); |
1105 | if (ffs_opts->version == 2 && | | 1108 | if (ffs_opts->version == 2 && |
1106 | (uint32_t)(cgino + INOPB(fs)) > initediblk && | | 1109 | (uint32_t)(cgino + INOPB(fs)) > initediblk && |
1107 | initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) { | | 1110 | initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) { |
1108 | memset(buf, 0, fs->fs_bsize); | | 1111 | memset(buf, 0, fs->fs_bsize); |
1109 | dip = (struct ufs2_dinode *)buf; | | 1112 | dip = (struct ufs2_dinode *)buf; |
1110 | srandom(time(NULL)); | | 1113 | srandom(time(NULL)); |
1111 | for (i = 0; i < INOPB(fs); i++) { | | 1114 | for (i = 0; i < INOPB(fs); i++) { |
1112 | dip->di_gen = random() / 2 + 1; | | 1115 | dip->di_gen = random() / 2 + 1; |
1113 | dip++; | | 1116 | dip++; |
1114 | } | | 1117 | } |
1115 | ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs, | | 1118 | ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs, |
1116 | cg * fs->fs_ipg + initediblk)), | | 1119 | cg * fs->fs_ipg + initediblk)), |
1117 | fs->fs_bsize, buf, fsopts); | | 1120 | fs->fs_bsize, buf, fsopts); |
1118 | initediblk += INOPB(fs); | | 1121 | initediblk += INOPB(fs); |
1119 | cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap); | | 1122 | cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap); |
1120 | } | | 1123 | } |
1121 | | | 1124 | |
1122 | | | 1125 | |
1123 | ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, | | 1126 | ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf, |
1124 | fsopts); | | 1127 | fsopts); |
1125 | | | 1128 | |
1126 | /* now write inode */ | | 1129 | /* now write inode */ |
1127 | d = fsbtodb(fs, ino_to_fsba(fs, ino)); | | 1130 | d = fsbtodb(fs, ino_to_fsba(fs, ino)); |
1128 | ffs_rdfs(d, fs->fs_bsize, buf, fsopts); | | 1131 | ffs_rdfs(d, fs->fs_bsize, buf, fsopts); |
1129 | if (fsopts->needswap) { | | 1132 | if (fsopts->needswap) { |
1130 | if (ffs_opts->version == 1) | | 1133 | if (ffs_opts->version == 1) |
1131 | ffs_dinode1_swap(&dp->ffs1_din, | | 1134 | ffs_dinode1_swap(&dp->ffs1_din, |
1132 | &dp1[ino_to_fsbo(fs, ino)]); | | 1135 | &dp1[ino_to_fsbo(fs, ino)]); |
1133 | else | | 1136 | else |
1134 | ffs_dinode2_swap(&dp->ffs2_din, | | 1137 | ffs_dinode2_swap(&dp->ffs2_din, |
1135 | &dp2[ino_to_fsbo(fs, ino)]); | | 1138 | &dp2[ino_to_fsbo(fs, ino)]); |
1136 | } else { | | 1139 | } else { |
1137 | if (ffs_opts->version == 1) | | 1140 | if (ffs_opts->version == 1) |
1138 | dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din; | | 1141 | dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din; |
1139 | else | | 1142 | else |
1140 | dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din; | | 1143 | dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din; |
1141 | } | | 1144 | } |
1142 | ffs_wtfs(d, fs->fs_bsize, buf, fsopts); | | 1145 | ffs_wtfs(d, fs->fs_bsize, buf, fsopts); |
1143 | free(buf); | | 1146 | free(buf); |
1144 | } | | 1147 | } |
1145 | | | 1148 | |
1146 | void | | 1149 | void |
1147 | panic(const char *fmt, ...) | | 1150 | panic(const char *fmt, ...) |
1148 | { | | 1151 | { |
1149 | va_list ap; | | 1152 | va_list ap; |
1150 | | | 1153 | |
1151 | va_start(ap, fmt); | | 1154 | va_start(ap, fmt); |
1152 | vwarnx(fmt, ap); | | 1155 | vwarnx(fmt, ap); |
1153 | va_end(ap); | | 1156 | va_end(ap); |
1154 | exit(1); | | 1157 | exit(1); |
1155 | } | | 1158 | } |