Bug Summary

File:src/usr.sbin/makefs/msdos/msdosfs_fat.c
Warning:line 875, column 13
Access to field 'b_data' results in a dereference of a null pointer (loaded from variable 'bp')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name msdosfs_fat.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/makefs/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/makefs -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/makefs/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/makefs/msdos/msdosfs_fat.c
1/* $OpenBSD: msdosfs_fat.c,v 1.7 2022/01/11 05:34:33 jsg Exp $ */
2/* $NetBSD: msdosfs_fat.c,v 1.31 2016/05/07 16:43:02 mlelstv Exp $ */
3
4/*-
5 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
6 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7 * All rights reserved.
8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by TooLs GmbH.
21 * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35/*
36 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 *
38 * You can do anything you want with this software, just don't say you wrote
39 * it, and don't remove this notice.
40 *
41 * This software is provided "as is".
42 *
43 * The author supplies this software to be publicly redistributed on the
44 * understanding that the author is not responsible for the correct
45 * functioning of this software in any circumstances and is not liable for
46 * any damages caused by this software.
47 *
48 * October 1992
49 */
50
51#include <sys/types.h>
52#include <sys/time.h>
53
54/*
55 * kernel include files.
56 */
57
58#include "ffs/buf.h"
59
60/*
61 * msdosfs include files.
62 */
63#include <msdosfs/bpb.h>
64#include "msdos/msdosfsmount.h"
65#include "msdos/direntry.h"
66#include "msdos/denode.h"
67#include "msdos/fat.h"
68#include "makefs.h"
69
70/*
71 * Fat cache stats.
72 */
73int fc_fileextends; /* # of file extends */
74int fc_lfcempty; /* # of time last file cluster cache entry
75 * was empty */
76int fc_bmapcalls; /* # of times pcbmap was called */
77
78#define LMMAX20 20
79int fc_lmdistance[LMMAX20]; /* counters for how far off the last
80 * cluster mapped entry was. */
81int fc_largedistance; /* off by more than LMMAX */
82int fc_wherefrom, fc_whereto, fc_lastclust;
83int pm_fatblocksize;
84
85#ifdef MSDOSFS_DEBUG
86#define DPRINTF(a) printf a
87#else
88#define DPRINTF(a)
89#endif
90
91static void fatblock(struct msdosfsmount *, u_long, u_long *, u_long *,
92 u_long *);
93void updatefats(struct msdosfsmount *, struct mkfsbuf *, u_long);
94static inline void usemap_free(struct msdosfsmount *, u_long);
95static inline void usemap_alloc(struct msdosfsmount *, u_long);
96static int fatchain(struct msdosfsmount *, u_long, u_long, u_long);
97int chainlength(struct msdosfsmount *, u_long, u_long);
98int chainalloc(struct msdosfsmount *, u_long, u_long, u_long, u_long *,
99 u_long *);
100
101static void
102fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, u_long *sizep, u_long *bop)
103{
104 u_long bn, size;
105
106 bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
107 size = MINIMUM(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)(((pmp->pm_fatblocksec) < (pmp->pm_FATsecs - bn)) ? (
pmp->pm_fatblocksec) : (pmp->pm_FATsecs - bn))
6
Assuming the condition is true
7
'?' condition is true
108 * pmp->pm_BytesPerSecpm_bpb.bpbBytesPerSec;
109 bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs;
110
111 DPRINTF(("%s(ofs=%lu bn=%lu, size=%lu, bo=%lu)\n", __func__, ofs, bn,
112 size, ofs % pmp->pm_fatblocksize));
113 if (bnp
7.1
'bnp' is non-null
)
8
Taking true branch
114 *bnp = bn;
115 if (sizep
8.1
'sizep' is non-null
)
9
Taking true branch
116 *sizep = size;
117 if (bop
9.1
'bop' is non-null
)
10
Taking true branch
118 *bop = ofs % pmp->pm_fatblocksize;
119
120 pm_fatblocksize = pmp->pm_fatblocksize;
121}
11
Returning without writing to 'pmp->pm_fatmask', which participates in a condition later
122
123/*
124 * Map the logical cluster number of a file into a physical disk sector
125 * that is filesystem relative.
126 *
127 * dep - address of denode representing the file of interest
128 * findcn - file relative cluster whose filesystem relative cluster number
129 * and/or block number are/is to be found
130 * bnp - address of where to place the file system relative block number.
131 * If this pointer is null then don't return this quantity.
132 * cnp - address of where to place the file system relative cluster number.
133 * If this pointer is null then don't return this quantity.
134 *
135 * NOTE: Either bnp or cnp must be non-null.
136 * This function has one side effect. If the requested file relative cluster
137 * is beyond the end of file, then the actual number of clusters in the file
138 * is returned in *cnp. This is useful for determining how long a directory is.
139 * If cnp is null, nothing is returned.
140 */
141int
142pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int *sp)
143 /* findcn: file relative cluster to get */
144 /* bnp: returned filesys rel sector number */
145 /* cnp: returned cluster number */
146 /* sp: returned block size */
147{
148 int error;
149 u_long i;
150 u_long cn;
151 u_long prevcn = 0; /* XXX: prevcn could be used uninitialized */
152 u_long byteoffset;
153 u_long bn;
154 u_long bo;
155 struct mkfsbuf *bp = NULL((void*)0);
156 u_long bp_bn = -1;
157 struct msdosfsmount *pmp = dep->de_pmp;
158 u_long bsize;
159
160 fc_bmapcalls++;
161
162 /*
163 * If they don't give us someplace to return a value then don't
164 * bother doing anything.
165 */
166 if (bnp == NULL((void*)0) && cnp == NULL((void*)0) && sp == NULL((void*)0))
167 return (0);
168
169 cn = dep->de_StartCluster;
170 DPRINTF(("%s(start cluster=%lu)\n", __func__, cn));
171 /*
172 * The "file" that makes up the root directory is contiguous,
173 * permanently allocated, of fixed size, and is not made up of
174 * clusters. If the cluster number is beyond the end of the root
175 * directory, then return the number of clusters in the file.
176 */
177 if (cn == MSDOSFSROOT0) {
178 if (dep->de_Attributes & ATTR_DIRECTORY0x10) {
179 if (de_cn2off(pmp, findcn)((findcn) << (pmp)->pm_cnshift) >= dep->de_FileSize) {
180 if (cnp)
181 *cnp = de_bn2cn(pmp, pmp->pm_rootdirsize)((pmp->pm_rootdirsize) >> ((pmp)->pm_cnshift - (pmp
)->pm_bnshift))
;
182 DPRINTF(("%s(root, %lu ETOOBIG)\n", __func__,
183 de_cn2off(pmp, findcn)));
184 return (E2BIG7);
185 }
186 if (bnp)
187 *bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn)((findcn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift
))
;
188 if (cnp)
189 *cnp = MSDOSFSROOT0;
190 if (sp)
191 *sp = MINIMUM(pmp->pm_bpcluster,(((pmp->pm_bpcluster) < (dep->de_FileSize - ((findcn
) << (pmp)->pm_cnshift))) ? (pmp->pm_bpcluster) :
(dep->de_FileSize - ((findcn) << (pmp)->pm_cnshift
)))
192 dep->de_FileSize - de_cn2off(pmp, findcn))(((pmp->pm_bpcluster) < (dep->de_FileSize - ((findcn
) << (pmp)->pm_cnshift))) ? (pmp->pm_bpcluster) :
(dep->de_FileSize - ((findcn) << (pmp)->pm_cnshift
)))
;
193 DPRINTF(("%s(root, bn=%lu, cn=%u)\n", __func__,
194 pmp->pm_rootdirblk + de_cn2bn(pmp, findcn),
195 MSDOSFSROOT));
196 return (0);
197 } else { /* just an empty file */
198 if (cnp)
199 *cnp = 0;
200 DPRINTF(("%s(root, empty ETOOBIG)\n", __func__));
201 return (E2BIG7);
202 }
203 }
204
205 /*
206 * All other files do I/O in cluster sized blocks
207 */
208 if (sp)
209 *sp = pmp->pm_bpcluster;
210
211 /*
212 * Rummage around in the FAT cache, maybe we can avoid tromping
213 * thru every FAT entry for the file. And, keep track of how far
214 * off the cache was from where we wanted to be.
215 */
216 i = 0;
217 fc_lookup(dep, findcn, &i, &cn);
218 DPRINTF(("%s(bpcluster=%lu i=%lu cn=%lu\n", __func__, pmp->pm_bpcluster,
219 i, cn));
220 if ((bn = findcn - i) >= LMMAX20) {
221 fc_largedistance++;
222 fc_wherefrom = i;
223 fc_whereto = findcn;
224 fc_lastclust = dep->de_fc[FC_LASTFC1].fc_frcn;
225 } else
226 fc_lmdistance[bn]++;
227
228 /*
229 * Handle all other files or directories the normal way.
230 */
231 for (; i < findcn; i++) {
232 /*
233 * Stop with all reserved clusters, not just with EOF.
234 */
235 if (cn >= (CLUST_RSRVD0xfffffff6 & pmp->pm_fatmask))
236 goto hiteof;
237
238 /*
239 * Also stop when cluster is not in the filesystem
240 */
241 if (cn < CLUST_FIRST2 || cn > pmp->pm_maxcluster) {
242 DPRINTF(("%s(cn, %lu not in %lu..%lu)\n", __func__,
243 cn, (u_long)CLUST_FIRST, pmp->pm_maxcluster));
244 if (bp)
245 brelse(bp, 0);
246 return (EINVAL22);
247 }
248
249 byteoffset = FATOFS(pmp, cn)((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv);
250 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
251 if (bn != bp_bn) {
252 if (bp)
253 brelse(bp, 0);
254 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn)((bn) << ((pmp)->pm_bnshift - 9)), bsize,
255 0, &bp);
256 if (error) {
257 DPRINTF(("%s(bread, %d)\n", __func__, error));
258 return (error);
259 }
260 bp_bn = bn;
261 }
262 prevcn = cn;
263 if (bo >= bsize) {
264 if (bp)
265 brelse(bp, 0);
266 DPRINTF(("%s(block, %lu >= %lu)\n", __func__, bo,
267 bsize));
268 return (EIO5);
269 }
270 KASSERT(bp != NULL);
271 if (FAT32(pmp)(pmp->pm_fatmask == 0x0fffffff))
272 cn = getulong((char *)bp->b_data + bo)*((u_int32_t *)((char *)bp->b_data + bo));
273 else
274 cn = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
275 if (FAT12(pmp)(pmp->pm_fatmask == 0x00000fff) && (prevcn & 1))
276 cn >>= 4;
277 DPRINTF(("%s(cn=%lu masked=%lu)\n", __func__, cn,
278 cn & pmp->pm_fatmask));
279 cn &= pmp->pm_fatmask;
280 }
281
282 if (!MSDOSFSEOF(cn, pmp->pm_fatmask)(((cn) & 0xfffffff8) == (0xfffffff8 & (pmp->pm_fatmask
)))
) {
283 if (bp)
284 brelse(bp, 0);
285 if (bnp)
286 *bnp = cntobn(pmp, cn)((((cn)-2) << (((pmp))->pm_cnshift - ((pmp))->pm_bnshift
)) + (pmp)->pm_firstcluster)
;
287 if (cnp)
288 *cnp = cn;
289 DPRINTF(("%s(bn=%lu, cn=%lu)\n", __func__, cntobn(pmp, cn),
290 cn));
291 fc_setcache(dep, FC_LASTMAP, i, cn)(dep)->de_fc[0].fc_frcn = i; (dep)->de_fc[0].fc_fsrcn =
cn;
;
292 return (0);
293 }
294
295hiteof:;
296 if (cnp)
297 *cnp = i;
298 if (bp)
299 brelse(bp, 0);
300 /* update last file cluster entry in the FAT cache */
301 fc_setcache(dep, FC_LASTFC, i - 1, prevcn)(dep)->de_fc[1].fc_frcn = i - 1; (dep)->de_fc[1].fc_fsrcn
= prevcn;
;
302 DPRINTF(("%s(eof, %lu)\n", __func__, i));
303 return (E2BIG7);
304}
305
306/*
307 * Find the closest entry in the FAT cache to the cluster we are looking
308 * for.
309 */
310void
311fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, u_long *fsrcnp)
312{
313 int i;
314 u_long cn;
315 struct fatcache *closest = 0;
316
317 for (i = 0; i < FC_SIZE3; i++) {
318 cn = dep->de_fc[i].fc_frcn;
319 if (cn != FCE_EMPTY0xffffffff && cn <= findcn) {
320 if (closest == 0 || cn > closest->fc_frcn)
321 closest = &dep->de_fc[i];
322 }
323 }
324 if (closest) {
325 *frcnp = closest->fc_frcn;
326 *fsrcnp = closest->fc_fsrcn;
327 }
328}
329
330/*
331 * Purge the FAT cache in denode dep of all entries relating to file
332 * relative cluster frcn and beyond.
333 */
334void
335fc_purge(struct denode *dep, u_int frcn)
336{
337 int i;
338 struct fatcache *fcp;
339
340 fcp = dep->de_fc;
341 for (i = 0; i < FC_SIZE3; i++, fcp++) {
342 if (fcp->fc_frcn >= frcn)
343 fcp->fc_frcn = FCE_EMPTY0xffffffff;
344 }
345}
346
347/*
348 * Update the FAT.
349 * If mirroring the FAT, update all copies, with the first copy as last.
350 * Else update only the current FAT (ignoring the others).
351 *
352 * pmp - msdosfsmount structure for filesystem to update
353 * bp - addr of modified FAT block
354 * fatbn - block number relative to begin of filesystem of the modified FAT block.
355 */
356void
357updatefats(struct msdosfsmount *pmp, struct mkfsbuf *bp, u_long fatbn)
358{
359 int i, error;
360 struct mkfsbuf *bpn;
361
362 DPRINTF(("%s(pmp %p, bp %p, fatbn %lu)\n", __func__, pmp, bp, fatbn));
363
364 /*
365 * If we have an FSInfo block, update it.
366 */
367 if (pmp->pm_fsinfo) {
368 u_long cn = pmp->pm_nxtfree;
369
370 if (pmp->pm_freeclustercount
371 && (pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))]
372 & (1 << (cn % N_INUSEBITS(8 * sizeof(u_int)))))) {
373 /*
374 * The cluster indicated in FSInfo isn't free
375 * any longer. Got get a new free one.
376 */
377 for (cn = 0; cn < pmp->pm_maxcluster; cn++)
378 if (pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))] != (u_int)-1)
379 break;
380 pmp->pm_nxtfree = cn
381 + ffs(pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))]
382 ^ (u_int)-1) - 1;
383 }
384 /*
385 * XXX If the fsinfo block is stored on media with
386 * 2KB or larger sectors, is the fsinfo structure
387 * padded at the end or in the middle?
388 */
389 if (bread(pmp->pm_devvp, de_bn2kb(pmp, pmp->pm_fsinfo)((pmp->pm_fsinfo) << ((pmp)->pm_bnshift - 9)),
390 pmp->pm_BytesPerSecpm_bpb.bpbBytesPerSec, B_MODIFY0, &bpn) != 0) {
391 /*
392 * Ignore the error, but turn off FSInfo update for the future.
393 */
394 pmp->pm_fsinfo = 0;
395 } else {
396 struct fsinfo *fp = (struct fsinfo *)bpn->b_data;
397
398 putulong(fp->fsinfree, pmp->pm_freeclustercount)(*((u_int32_t *)(fp->fsinfree)) = (pmp->pm_freeclustercount
))
;
399 putulong(fp->fsinxtfree, pmp->pm_nxtfree)(*((u_int32_t *)(fp->fsinxtfree)) = (pmp->pm_nxtfree));
400 if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT0x40000000)
401 bwrite(bpn);
402 else
403 bdwrite(bpn)bwrite(bpn);
404 }
405 }
406
407 if (pmp->pm_flags & MSDOSFS_FATMIRROR0x20000000) {
408 /*
409 * Now copy the block(s) of the modified FAT to the other copies of
410 * the FAT and write them out. This is faster than reading in the
411 * other FATs and then writing them back out. This could tie up
412 * the FAT for quite a while. Preventing others from accessing it.
413 * To prevent us from going after the FAT quite so much we use
414 * delayed writes, unless they specified "synchronous" when the
415 * filesystem was mounted. If synch is asked for then use
416 * bwrite()'s and really slow things down.
417 */
418 for (i = 1; i < pmp->pm_FATspm_bpb.bpbFATs; i++) {
419 fatbn += pmp->pm_FATsecs;
420 /* getblk() never fails */
421 bpn = getblk(pmp->pm_devvp, de_bn2kb(pmp, fatbn)((fatbn) << ((pmp)->pm_bnshift - 9)),
422 bp->b_bcount, 0, 0);
423 memcpy(bpn->b_data, bp->b_data, bp->b_bcount);
424 if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT0x40000000) {
425 error = bwrite(bpn);
426 if (error)
427 printf("%s: copy FAT %d (error=%d)\n",
428 __func__, i, error);
429 } else
430 bdwrite(bpn)bwrite(bpn);
431 }
432 }
433
434 /*
435 * Write out the first (or current) FAT last.
436 */
437 if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT0x40000000) {
438 error = bwrite(bp);
439 if (error)
440 printf("%s: write FAT (error=%d)\n",
441 __func__, error);
442 } else
443 bdwrite(bp)bwrite(bp);
444 /*
445 * Maybe update fsinfo sector here?
446 */
447}
448
449/*
450 * Updating entries in 12 bit FATs is a pain in the butt.
451 *
452 * The following picture shows where nibbles go when moving from a 12 bit
453 * cluster number into the appropriate bytes in the FAT.
454 *
455 * byte m byte m+1 byte m+2
456 * +----+----+ +----+----+ +----+----+
457 * | 0 1 | | 2 3 | | 4 5 | FAT bytes
458 * +----+----+ +----+----+ +----+----+
459 *
460 * +----+----+----+ +----+----+----+
461 * | 3 0 1 | | 4 5 2 |
462 * +----+----+----+ +----+----+----+
463 * cluster n cluster n+1
464 *
465 * Where n is even. m = n + (n >> 2)
466 *
467 */
468static inline void
469usemap_alloc(struct msdosfsmount *pmp, u_long cn)
470{
471
472 pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))] |= 1 << (cn % N_INUSEBITS(8 * sizeof(u_int)));
473 pmp->pm_freeclustercount--;
474}
475
476static inline void
477usemap_free(struct msdosfsmount *pmp, u_long cn)
478{
479
480 pmp->pm_freeclustercount++;
481 pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))] &= ~(1 << (cn % N_INUSEBITS(8 * sizeof(u_int))));
482}
16
Returning without writing to 'pmp->pm_fatmask', which participates in a condition later
483
484int
485clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
486{
487 int error;
488 u_long oldcn;
489
490 usemap_free(pmp, cluster);
491 error = fatentry(FAT_GET_AND_SET(0x0001 | 0x0002), pmp, cluster, &oldcn, MSDOSFSFREE0);
492 if (error) {
493 usemap_alloc(pmp, cluster);
494 return (error);
495 }
496 /*
497 * If the cluster was successfully marked free, then update
498 * the count of free clusters, and turn off the "allocated"
499 * bit in the "in use" cluster bit map.
500 */
501 if (oldcnp)
502 *oldcnp = oldcn;
503 return (0);
504}
505
506/*
507 * Get or Set or 'Get and Set' the cluster'th entry in the FAT.
508 *
509 * function - whether to get or set a fat entry
510 * pmp - address of the msdosfsmount structure for the filesystem
511 * whose FAT is to be manipulated.
512 * cn - which cluster is of interest
513 * oldcontents - address of a word that is to receive the contents of the
514 * cluster'th entry if this is a get function
515 * newcontents - the new value to be written into the cluster'th element of
516 * the FAT if this is a set function.
517 *
518 * This function can also be used to free a cluster by setting the FAT entry
519 * for a cluster to 0.
520 *
521 * All copies of the FAT are updated if this is a set function. NOTE: If
522 * fatentry() marks a cluster as free it does not update the inusemap in
523 * the msdosfsmount structure. This is left to the caller.
524 */
525int
526fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents, u_long newcontents)
527{
528 int error;
529 u_long readcn;
530 u_long bn, bo, bsize, byteoffset;
531 struct mkfsbuf *bp;
532
533 DPRINTF(("%s(func %d, pmp %p, clust %lu, oldcon %p, newcon " "%lx)\n",
534 __func__, function, pmp, cn, oldcontents, newcontents));
535
536#ifdef DIAGNOSTIC
537 /*
538 * Be sure they asked us to do something.
539 */
540 if ((function & (FAT_SET0x0002 | FAT_GET0x0001)) == 0) {
541 DPRINTF(("%s(): function code doesn't specify get or set\n",
542 __func__));
543 return (EINVAL22);
544 }
545
546 /*
547 * If they asked us to return a cluster number but didn't tell us
548 * where to put it, give them an error.
549 */
550 if ((function & FAT_GET0x0001) && oldcontents == NULL((void*)0)) {
551 DPRINTF(("%s(): get function with no place to put result\n",
552 __func__));
553 return (EINVAL22);
554 }
555#endif
556
557 /*
558 * Be sure the requested cluster is in the filesystem.
559 */
560 if (cn < CLUST_FIRST2 || cn > pmp->pm_maxcluster)
561 return (EINVAL22);
562
563 byteoffset = FATOFS(pmp, cn)((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv);
564 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
565 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn)((bn) << ((pmp)->pm_bnshift - 9)), bsize,
566 0, &bp)) != 0) {
567 return (error);
568 }
569
570 if (function & FAT_GET0x0001) {
571 if (FAT32(pmp)(pmp->pm_fatmask == 0x0fffffff))
572 readcn = getulong((char *)bp->b_data + bo)*((u_int32_t *)((char *)bp->b_data + bo));
573 else
574 readcn = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
575 if (FAT12(pmp)(pmp->pm_fatmask == 0x00000fff) & (cn & 1))
576 readcn >>= 4;
577 readcn &= pmp->pm_fatmask;
578 *oldcontents = readcn;
579 }
580 if (function & FAT_SET0x0002) {
581 switch (pmp->pm_fatmask) {
582 case FAT12_MASK0x00000fff:
583 readcn = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
584 if (cn & 1) {
585 readcn &= 0x000f;
586 readcn |= newcontents << 4;
587 } else {
588 readcn &= 0xf000;
589 readcn |= newcontents & 0xfff;
590 }
591 putushort((char *)bp->b_data + bo, readcn)(*((u_int16_t *)((char *)bp->b_data + bo)) = (readcn));
592 break;
593 case FAT16_MASK0x0000ffff:
594 putushort((char *)bp->b_data + bo, newcontents)(*((u_int16_t *)((char *)bp->b_data + bo)) = (newcontents)
)
;
595 break;
596 case FAT32_MASK0x0fffffff:
597 /*
598 * According to spec we have to retain the
599 * high order bits of the FAT entry.
600 */
601 readcn = getulong((char *)bp->b_data + bo)*((u_int32_t *)((char *)bp->b_data + bo));
602 readcn &= ~FAT32_MASK0x0fffffff;
603 readcn |= newcontents & FAT32_MASK0x0fffffff;
604 putulong((char *)bp->b_data + bo, readcn)(*((u_int32_t *)((char *)bp->b_data + bo)) = (readcn));
605 break;
606 }
607 updatefats(pmp, bp, bn);
608 bp = NULL((void*)0);
609 pmp->pm_fmod = 1;
610 }
611 if (bp)
612 brelse(bp, 0);
613 return (0);
614}
615
616/*
617 * Update a contiguous cluster chain
618 *
619 * pmp - mount point
620 * start - first cluster of chain
621 * count - number of clusters in chain
622 * fillwith - what to write into FAT entry of last cluster
623 */
624static int
625fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith)
626{
627 int error;
628 u_long bn, bo, bsize, byteoffset, readcn, newc;
629 struct mkfsbuf *bp;
630
631 DPRINTF(("%s(pmp %p, start %lu, count %lu, fillwith %lx)\n", __func__,
632 pmp, start, count, fillwith));
633 /*
634 * Be sure the clusters are in the filesystem.
635 */
636 if (start < CLUST_FIRST2 || start + count - 1 > pmp->pm_maxcluster)
637 return (EINVAL22);
638
639 while (count > 0) {
640 byteoffset = FATOFS(pmp, start)((start) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv);
641 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
642 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn)((bn) << ((pmp)->pm_bnshift - 9)), bsize,
643 B_MODIFY0, &bp);
644 if (error) {
645 return (error);
646 }
647 while (count > 0) {
648 start++;
649 newc = --count > 0 ? start : fillwith;
650 switch (pmp->pm_fatmask) {
651 case FAT12_MASK0x00000fff:
652 readcn = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
653 if (start & 1) {
654 readcn &= 0xf000;
655 readcn |= newc & 0xfff;
656 } else {
657 readcn &= 0x000f;
658 readcn |= newc << 4;
659 }
660 putushort((char *)bp->b_data + bo, readcn)(*((u_int16_t *)((char *)bp->b_data + bo)) = (readcn));
661 bo++;
662 if (!(start & 1))
663 bo++;
664 break;
665 case FAT16_MASK0x0000ffff:
666 putushort((char *)bp->b_data + bo, newc)(*((u_int16_t *)((char *)bp->b_data + bo)) = (newc));
667 bo += 2;
668 break;
669 case FAT32_MASK0x0fffffff:
670 readcn = getulong((char *)bp->b_data + bo)*((u_int32_t *)((char *)bp->b_data + bo));
671 readcn &= ~pmp->pm_fatmask;
672 readcn |= newc & pmp->pm_fatmask;
673 putulong((char *)bp->b_data + bo, readcn)(*((u_int32_t *)((char *)bp->b_data + bo)) = (readcn));
674 bo += 4;
675 break;
676 }
677 if (bo >= bsize)
678 break;
679 }
680 updatefats(pmp, bp, bn);
681 }
682 pmp->pm_fmod = 1;
683 return (0);
684}
685
686/*
687 * Check the length of a free cluster chain starting at start.
688 *
689 * pmp - mount point
690 * start - start of chain
691 * count - maximum interesting length
692 */
693int
694chainlength(struct msdosfsmount *pmp, u_long start, u_long count)
695{
696 u_long idx, max_idx;
697 u_int map;
698 u_long len;
699
700 max_idx = pmp->pm_maxcluster / N_INUSEBITS(8 * sizeof(u_int));
701 idx = start / N_INUSEBITS(8 * sizeof(u_int));
702 start %= N_INUSEBITS(8 * sizeof(u_int));
703 map = pmp->pm_inusemap[idx];
704 map &= ~((1 << start) - 1);
705 if (map) {
706 len = ffs(map) - 1 - start;
707 return (len > count ? count : len);
708 }
709 len = N_INUSEBITS(8 * sizeof(u_int)) - start;
710 if (len >= count)
711 return (count);
712 while (++idx <= max_idx) {
713 if (len >= count)
714 break;
715 if ((map = pmp->pm_inusemap[idx]) != 0) {
716 len += ffs(map) - 1;
717 break;
718 }
719 len += N_INUSEBITS(8 * sizeof(u_int));
720 }
721 return (len > count ? count : len);
722}
723
724/*
725 * Allocate contiguous free clusters.
726 *
727 * pmp - mount point.
728 * start - start of cluster chain.
729 * count - number of clusters to allocate.
730 * fillwith - put this value into the FAT entry for the
731 * last allocated cluster.
732 * retcluster - put the first allocated cluster's number here.
733 * got - how many clusters were actually allocated.
734 */
735int
736chainalloc(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got)
737{
738 int error;
739 u_long cl, n;
740
741 for (cl = start, n = count; n-- > 0;)
742 usemap_alloc(pmp, cl++);
743 if ((error = fatchain(pmp, start, count, fillwith)) != 0)
744 return (error);
745
746 DPRINTF(("%s(): allocated cluster chain at %lu (%lu clusters)\n",
747 __func__, start, count));
748 if (retcluster)
749 *retcluster = start;
750 if (got)
751 *got = count;
752 return (0);
753}
754
755/*
756 * Allocate contiguous free clusters.
757 *
758 * pmp - mount point.
759 * start - preferred start of cluster chain.
760 * count - number of clusters requested.
761 * fillwith - put this value into the FAT entry for the
762 * last allocated cluster.
763 * retcluster - put the first allocated cluster's number here.
764 * got - how many clusters were actually allocated.
765 */
766int
767clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, u_long *retcluster, u_long *got)
768{
769 u_long idx;
770 u_long len, newst, foundl, cn, l;
771 u_long foundcn = 0; /* XXX: foundcn could be used uninitialized */
772 u_long fillwith = CLUST_EOFE0xffffffff;
773 u_int map;
774
775 DPRINTF(("%s(): find %lu clusters\n", __func__, count));
776 if (start) {
777 if ((len = chainlength(pmp, start, count)) >= count)
778 return (chainalloc(pmp, start, count, fillwith, retcluster, got));
779 } else {
780 /*
781 * This is a new file, initialize start
782 */
783 struct timeval tv;
784
785 microtime(&tv)gettimeofday((&tv), ((void*)0));
786 start = (tv.tv_usec >> 10) | tv.tv_usec;
787 len = 0;
788 }
789
790 /*
791 * Start at a (pseudo) random place to maximize cluster runs
792 * under multiple writers.
793 */
794 newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
795 foundl = 0;
796
797 for (cn = newst; cn <= pmp->pm_maxcluster;) {
798 idx = cn / N_INUSEBITS(8 * sizeof(u_int));
799 map = pmp->pm_inusemap[idx];
800 map |= (1 << (cn % N_INUSEBITS(8 * sizeof(u_int)))) - 1;
801 if (map != (u_int)-1) {
802 cn = idx * N_INUSEBITS(8 * sizeof(u_int)) + ffs(map^(u_int)-1) - 1;
803 if ((l = chainlength(pmp, cn, count)) >= count)
804 return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
805 if (l > foundl) {
806 foundcn = cn;
807 foundl = l;
808 }
809 cn += l + 1;
810 continue;
811 }
812 cn += N_INUSEBITS(8 * sizeof(u_int)) - cn % N_INUSEBITS(8 * sizeof(u_int));
813 }
814 for (cn = 0; cn < newst;) {
815 idx = cn / N_INUSEBITS(8 * sizeof(u_int));
816 map = pmp->pm_inusemap[idx];
817 map |= (1 << (cn % N_INUSEBITS(8 * sizeof(u_int)))) - 1;
818 if (map != (u_int)-1) {
819 cn = idx * N_INUSEBITS(8 * sizeof(u_int)) + ffs(map^(u_int)-1) - 1;
820 if ((l = chainlength(pmp, cn, count)) >= count)
821 return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
822 if (l > foundl) {
823 foundcn = cn;
824 foundl = l;
825 }
826 cn += l + 1;
827 continue;
828 }
829 cn += N_INUSEBITS(8 * sizeof(u_int)) - cn % N_INUSEBITS(8 * sizeof(u_int));
830 }
831
832 if (!foundl)
833 return (ENOSPC28);
834
835 if (len)
836 return (chainalloc(pmp, start, len, fillwith, retcluster, got));
837 else
838 return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got));
839}
840
841
842/*
843 * Free a chain of clusters.
844 *
845 * pmp - address of the msdosfs mount structure for the filesystem
846 * containing the cluster chain to be freed.
847 * startcluster - number of the 1st cluster in the chain of clusters to be
848 * freed.
849 */
850int
851freeclusterchain(struct msdosfsmount *pmp, u_long cluster)
852{
853 int error;
854 struct mkfsbuf *bp = NULL((void*)0);
1
'bp' initialized to a null pointer value
855 u_long bn, bo, bsize, byteoffset;
856 u_long readcn, lbn = -1;
857
858 while (cluster >= CLUST_FIRST2 && cluster <= pmp->pm_maxcluster) {
2
Assuming 'cluster' is >= CLUST_FIRST
3
Assuming 'cluster' is <= field 'pm_maxcluster'
4
Loop condition is true. Entering loop body
859 byteoffset = FATOFS(pmp, cluster)((cluster) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv);
860 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
5
Calling 'fatblock'
12
Returning from 'fatblock'
861 if (lbn != bn) {
13
Assuming 'lbn' is equal to 'bn'
14
Taking false branch
862 if (bp)
863 updatefats(pmp, bp, lbn);
864 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn)((bn) << ((pmp)->pm_bnshift - 9)), bsize,
865 B_MODIFY0, &bp);
866 if (error) {
867 return (error);
868 }
869 lbn = bn;
870 }
871 usemap_free(pmp, cluster);
15
Calling 'usemap_free'
17
Returning from 'usemap_free'
872 KASSERT(bp != NULL);
873 switch (pmp->pm_fatmask) {
18
Control jumps to 'case 4095:' at line 874
874 case FAT12_MASK0x00000fff:
875 readcn = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
19
Access to field 'b_data' results in a dereference of a null pointer (loaded from variable 'bp')
876 if (cluster & 1) {
877 cluster = readcn >> 4;
878 readcn &= 0x000f;
879 readcn |= MSDOSFSFREE0 << 4;
880 } else {
881 cluster = readcn;
882 readcn &= 0xf000;
883 readcn |= MSDOSFSFREE0 & 0xfff;
884 }
885 putushort((char *)bp->b_data + bo, readcn)(*((u_int16_t *)((char *)bp->b_data + bo)) = (readcn));
886 break;
887 case FAT16_MASK0x0000ffff:
888 cluster = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
889 putushort((char *)bp->b_data + bo, MSDOSFSFREE)(*((u_int16_t *)((char *)bp->b_data + bo)) = (0));
890 break;
891 case FAT32_MASK0x0fffffff:
892 cluster = getulong((char *)bp->b_data + bo)*((u_int32_t *)((char *)bp->b_data + bo));
893 putulong((char *)bp->b_data + bo,(*((u_int32_t *)((char *)bp->b_data + bo)) = ((0 & 0x0fffffff
) | (cluster & ~0x0fffffff)))
894 (MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK))(*((u_int32_t *)((char *)bp->b_data + bo)) = ((0 & 0x0fffffff
) | (cluster & ~0x0fffffff)))
;
895 break;
896 }
897 cluster &= pmp->pm_fatmask;
898 }
899 if (bp)
900 updatefats(pmp, bp, bn);
901 return (0);
902}
903
904/*
905 * Read in FAT blocks looking for free clusters. For every free cluster
906 * found turn off its corresponding bit in the pm_inusemap.
907 */
908int
909fillinusemap(struct msdosfsmount *pmp)
910{
911 struct mkfsbuf *bp = NULL((void*)0);
912 u_long cn, readcn;
913 int error;
914 u_long bn, bo, bsize, byteoffset;
915
916 /*
917 * Mark all clusters in use, we mark the free ones in the FAT scan
918 * loop further down.
919 */
920 for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS(8 * sizeof(u_int))) / N_INUSEBITS(8 * sizeof(u_int)); cn++)
921 pmp->pm_inusemap[cn] = (u_int)-1;
922
923 /*
924 * Figure how many free clusters are in the filesystem by ripping
925 * through the FAT counting the number of entries whose content is
926 * zero. These represent free clusters.
927 */
928 pmp->pm_freeclustercount = 0;
929 for (cn = CLUST_FIRST2; cn <= pmp->pm_maxcluster; cn++) {
930 byteoffset = FATOFS(pmp, cn)((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv);
931 bo = byteoffset % pmp->pm_fatblocksize;
932 if (!bo || !bp) {
933 /* Read new FAT block */
934 if (bp)
935 brelse(bp, 0);
936 fatblock(pmp, byteoffset, &bn, &bsize, NULL((void*)0));
937 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn)((bn) << ((pmp)->pm_bnshift - 9)), bsize,
938 0, &bp);
939 if (error) {
940 return (error);
941 }
942 }
943 if (FAT32(pmp)(pmp->pm_fatmask == 0x0fffffff))
944 readcn = getulong((char *)bp->b_data + bo)*((u_int32_t *)((char *)bp->b_data + bo));
945 else
946 readcn = getushort((char *)bp->b_data + bo)*((u_int16_t *)((char *)bp->b_data + bo));
947 if (FAT12(pmp)(pmp->pm_fatmask == 0x00000fff) && (cn & 1))
948 readcn >>= 4;
949 readcn &= pmp->pm_fatmask;
950
951 if (readcn == 0)
952 usemap_free(pmp, cn);
953 }
954 if (bp)
955 brelse(bp, 0);
956 return (0);
957}
958
959/*
960 * Allocate a new cluster and chain it onto the end of the file.
961 *
962 * dep - the file to extend
963 * count - number of clusters to allocate
964 * bpp - where to return the address of the buf header for the first new
965 * file block
966 * ncp - where to put cluster number of the first newly allocated cluster
967 * If this pointer is 0, do not return the cluster number.
968 * flags - see fat.h
969 *
970 * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
971 * the de_flag field of the denode and it does not change the de_FileSize
972 * field. This is left for the caller to do.
973 */
974
975int
976extendfile(struct denode *dep, u_long count, struct mkfsbuf **bpp, u_long *ncp, int flags)
977{
978 int error;
979 u_long frcn = 0, cn, got;
980 struct msdosfsmount *pmp = dep->de_pmp;
981 struct mkfsbuf *bp;
982
983 /*
984 * Don't try to extend the root directory
985 */
986 if (dep->de_StartCluster == MSDOSFSROOT0
987 && (dep->de_Attributes & ATTR_DIRECTORY0x10)) {
988 DPRINTF(("%s(): attempt to extend root directory\n", __func__));
989 return (ENOSPC28);
990 }
991
992 /*
993 * If the "file's last cluster" cache entry is empty, and the file
994 * is not empty, then fill the cache entry by calling pcbmap().
995 */
996 fc_fileextends++;
997 if (dep->de_fc[FC_LASTFC1].fc_frcn == FCE_EMPTY0xffffffff &&
998 dep->de_StartCluster != 0) {
999 fc_lfcempty++;
1000 error = pcbmap(dep, CLUST_END0xffffffff, 0, &cn, 0);
1001 /* we expect it to return E2BIG */
1002 if (error != E2BIG7)
1003 return (error);
1004 }
1005
1006 fc_last_to_nexttolast(dep)do { (dep)->de_fc[2].fc_frcn = (dep)->de_fc[1].fc_frcn;
(dep)->de_fc[2].fc_fsrcn = (dep)->de_fc[1].fc_fsrcn; }
while (0)
;
1007
1008 while (count > 0) {
1009
1010 /*
1011 * Allocate a new cluster chain and cat onto the end of the
1012 * file. If the file is empty we make de_StartCluster point
1013 * to the new block. Note that de_StartCluster being 0 is
1014 * sufficient to be sure the file is empty since we exclude
1015 * attempts to extend the root directory above, and the root
1016 * dir is the only file with a startcluster of 0 that has
1017 * blocks allocated (sort of).
1018 */
1019
1020 if (dep->de_StartCluster == 0)
1021 cn = 0;
1022 else
1023 cn = dep->de_fc[FC_LASTFC1].fc_fsrcn + 1;
1024 error = clusteralloc(pmp, cn, count, &cn, &got);
1025 if (error)
1026 return (error);
1027
1028 count -= got;
1029
1030 /*
1031 * Give them the filesystem relative cluster number if they want
1032 * it.
1033 */
1034 if (ncp) {
1035 *ncp = cn;
1036 ncp = NULL((void*)0);
1037 }
1038
1039 if (dep->de_StartCluster == 0) {
1040 dep->de_StartCluster = cn;
1041 frcn = 0;
1042 } else {
1043 error = fatentry(FAT_SET0x0002, pmp,
1044 dep->de_fc[FC_LASTFC1].fc_fsrcn,
1045 0, cn);
1046 if (error) {
1047 clusterfree(pmp, cn, NULL((void*)0));
1048 return (error);
1049 }
1050 frcn = dep->de_fc[FC_LASTFC1].fc_frcn + 1;
1051 }
1052
1053 /*
1054 * Update the "last cluster of the file" entry in the
1055 * denode's FAT cache.
1056 */
1057
1058 fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1)(dep)->de_fc[1].fc_frcn = frcn + got - 1; (dep)->de_fc[
1].fc_fsrcn = cn + got - 1;
;
1059 if ((flags & DE_CLEAR1) &&
1060 (dep->de_Attributes & ATTR_DIRECTORY0x10)) {
1061 while (got-- > 0) {
1062 bp = getblk(pmp->pm_devvp,
1063 de_bn2kb(pmp, cntobn(pmp, cn++))((((((cn++)-2) << (((pmp))->pm_cnshift - ((pmp))->
pm_bnshift)) + (pmp)->pm_firstcluster)) << ((pmp)->
pm_bnshift - 9))
,
1064 pmp->pm_bpcluster, 0, 0);
1065 clrbuf(bp)memset((bp)->b_data, 0, (u_int)(bp)->b_bcount);
1066 if (bpp) {
1067 *bpp = bp;
1068 bpp = NULL((void*)0);
1069 } else {
1070 bdwrite(bp)bwrite(bp);
1071 }
1072 }
1073 }
1074 }
1075
1076 return (0);
1077}