File: | msdosfs/msdosfs_fat.c |
Warning: | line 236, column 9 Access to field 'b_data' results in a dereference of a null pointer (loaded from variable 'bp') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: msdosfs_fat.c,v 1.34 2021/03/11 13:31:35 jsg Exp $ */ | ||||
2 | /* $NetBSD: msdosfs_fat.c,v 1.26 1997/10/17 11:24:02 ws 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 | /* | ||||
52 | * kernel include files. | ||||
53 | */ | ||||
54 | #include <sys/param.h> | ||||
55 | #include <sys/systm.h> | ||||
56 | #include <sys/buf.h> | ||||
57 | #include <sys/namei.h> | ||||
58 | #include <sys/mount.h> /* to define statfs structure */ | ||||
59 | #include <sys/vnode.h> /* to define vattr structure */ | ||||
60 | #include <sys/lock.h> | ||||
61 | #include <sys/errno.h> | ||||
62 | #include <sys/dirent.h> | ||||
63 | |||||
64 | /* | ||||
65 | * msdosfs include files. | ||||
66 | */ | ||||
67 | #include <msdosfs/bpb.h> | ||||
68 | #include <msdosfs/msdosfsmount.h> | ||||
69 | #include <msdosfs/direntry.h> | ||||
70 | #include <msdosfs/denode.h> | ||||
71 | #include <msdosfs/fat.h> | ||||
72 | |||||
73 | /* | ||||
74 | * Fat cache stats. | ||||
75 | */ | ||||
76 | int fc_fileextends; /* # of file extends */ | ||||
77 | int fc_lfcempty; /* # of time last file cluster cache entry | ||||
78 | * was empty */ | ||||
79 | int fc_bmapcalls; /* # of times pcbmap was called */ | ||||
80 | |||||
81 | #define LMMAX20 20 | ||||
82 | int fc_lmdistance[LMMAX20]; /* counters for how far off the last | ||||
83 | * cluster mapped entry was. */ | ||||
84 | int fc_largedistance; /* off by more than LMMAX */ | ||||
85 | |||||
86 | static void fatblock(struct msdosfsmount *, uint32_t, uint32_t *, uint32_t *, | ||||
87 | uint32_t *); | ||||
88 | void updatefats(struct msdosfsmount *, struct buf *, uint32_t); | ||||
89 | static __inline void usemap_free(struct msdosfsmount *, uint32_t); | ||||
90 | static __inline void usemap_alloc(struct msdosfsmount *, uint32_t); | ||||
91 | static int fatchain(struct msdosfsmount *, uint32_t, uint32_t, uint32_t); | ||||
92 | int chainlength(struct msdosfsmount *, uint32_t, uint32_t); | ||||
93 | int chainalloc(struct msdosfsmount *, uint32_t, uint32_t, uint32_t, uint32_t *, | ||||
94 | uint32_t *); | ||||
95 | |||||
96 | static void | ||||
97 | fatblock(struct msdosfsmount *pmp, uint32_t ofs, uint32_t *bnp, uint32_t *sizep, | ||||
98 | uint32_t *bop) | ||||
99 | { | ||||
100 | uint32_t bn, size; | ||||
101 | |||||
102 | bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec; | ||||
103 | size = min(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn) * DEV_BSIZE(1 << 9); | ||||
104 | bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs; | ||||
105 | |||||
106 | if (bnp) | ||||
107 | *bnp = bn; | ||||
108 | if (sizep) | ||||
109 | *sizep = size; | ||||
110 | if (bop) | ||||
111 | *bop = ofs % pmp->pm_fatblocksize; | ||||
112 | } | ||||
113 | |||||
114 | /* | ||||
115 | * Map the logical cluster number of a file into a physical disk sector | ||||
116 | * that is filesystem relative. | ||||
117 | * | ||||
118 | * dep - address of denode representing the file of interest | ||||
119 | * findcn - file relative cluster whose filesystem relative cluster number | ||||
120 | * and/or block number are/is to be found | ||||
121 | * bnp - address of where to place the file system relative block number. | ||||
122 | * If this pointer is null then don't return this quantity. | ||||
123 | * cnp - address of where to place the file system relative cluster number. | ||||
124 | * If this pointer is null then don't return this quantity. | ||||
125 | * sp - address of where to place the block size for the file/dir | ||||
126 | * If this pointer is null then don't return this quantity. | ||||
127 | * | ||||
128 | * NOTE: Either bnp or cnp must be non-null. | ||||
129 | * This function has one side effect. If the requested file relative cluster | ||||
130 | * is beyond the end of file, then the actual number of clusters in the file | ||||
131 | * is returned in *cnp. This is useful for determining how long a directory is. | ||||
132 | * If cnp is null, nothing is returned. | ||||
133 | */ | ||||
134 | int | ||||
135 | pcbmap(struct denode *dep, uint32_t findcn, daddr_t *bnp, uint32_t *cnp, | ||||
136 | int *sp) | ||||
137 | { | ||||
138 | int error; | ||||
139 | uint32_t i; | ||||
140 | uint32_t cn; | ||||
141 | uint32_t prevcn = 0; /* XXX: prevcn could be used uninitialized */ | ||||
142 | uint32_t byteoffset; | ||||
143 | uint32_t bn; | ||||
144 | uint32_t bo; | ||||
145 | struct buf *bp = NULL((void *)0); | ||||
146 | uint32_t bp_bn = -1; | ||||
147 | struct msdosfsmount *pmp = dep->de_pmp; | ||||
148 | uint32_t bsize; | ||||
149 | |||||
150 | fc_bmapcalls++; | ||||
151 | |||||
152 | /* | ||||
153 | * If they don't give us someplace to return a value then don't | ||||
154 | * bother doing anything. | ||||
155 | */ | ||||
156 | if (bnp
| ||||
157 | return (0); | ||||
158 | |||||
159 | cn = dep->de_StartCluster; | ||||
160 | /* | ||||
161 | * The "file" that makes up the root directory is contiguous, | ||||
162 | * permanently allocated, of fixed size, and is not made up of | ||||
163 | * clusters. If the cluster number is beyond the end of the root | ||||
164 | * directory, then return the number of clusters in the file. | ||||
165 | */ | ||||
166 | if (cn
| ||||
167 | if (dep->de_Attributes & ATTR_DIRECTORY0x10) { | ||||
168 | if (de_cn2off(pmp, findcn)((findcn) << (pmp)->pm_cnshift) >= dep->de_FileSize) { | ||||
169 | if (cnp) | ||||
170 | *cnp = de_bn2cn(pmp, pmp->pm_rootdirsize)((pmp->pm_rootdirsize) >> ((pmp)->pm_cnshift - (pmp )->pm_bnshift)); | ||||
171 | return (E2BIG7); | ||||
172 | } | ||||
173 | if (bnp) | ||||
174 | *bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn)((findcn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift )); | ||||
175 | if (cnp) | ||||
176 | *cnp = MSDOSFSROOT0; | ||||
177 | if (sp) | ||||
178 | *sp = min(pmp->pm_bpcluster, | ||||
179 | dep->de_FileSize - de_cn2off(pmp, findcn)((findcn) << (pmp)->pm_cnshift)); | ||||
180 | return (0); | ||||
181 | } else { /* just an empty file */ | ||||
182 | if (cnp) | ||||
183 | *cnp = 0; | ||||
184 | return (E2BIG7); | ||||
185 | } | ||||
186 | } | ||||
187 | |||||
188 | /* | ||||
189 | * All other files do I/O in cluster sized blocks | ||||
190 | */ | ||||
191 | if (sp
| ||||
192 | *sp = pmp->pm_bpcluster; | ||||
193 | |||||
194 | /* | ||||
195 | * Rummage around in the fat cache, maybe we can avoid tromping | ||||
196 | * thru every fat entry for the file. And, keep track of how far | ||||
197 | * off the cache was from where we wanted to be. | ||||
198 | */ | ||||
199 | i = 0; | ||||
200 | fc_lookup(dep, findcn, &i, &cn); | ||||
201 | if ((bn = findcn - i) >= LMMAX20) | ||||
202 | fc_largedistance++; | ||||
203 | else | ||||
204 | fc_lmdistance[bn]++; | ||||
205 | |||||
206 | /* | ||||
207 | * Handle all other files or directories the normal way. | ||||
208 | */ | ||||
209 | for (; i < findcn; i++) { | ||||
210 | /* | ||||
211 | * Stop with all reserved clusters, not just with EOF. | ||||
212 | */ | ||||
213 | if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD0xfffffff6) | ||||
214 | goto hiteof; | ||||
215 | byteoffset = FATOFS(pmp, cn)((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv); | ||||
216 | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
217 | if (bn != bp_bn) { | ||||
218 | if (bp) | ||||
219 | brelse(bp); | ||||
220 | error = bread(pmp->pm_devvp, bn, bsize, &bp); | ||||
221 | if (error) { | ||||
222 | brelse(bp); | ||||
223 | return (error); | ||||
224 | } | ||||
225 | bp_bn = bn; | ||||
226 | } | ||||
227 | prevcn = cn; | ||||
228 | if (bo >= bsize) { | ||||
229 | if (bp) | ||||
230 | brelse(bp); | ||||
231 | return (EIO5); | ||||
232 | } | ||||
233 | if (FAT32(pmp)(pmp->pm_fatmask == 0x0fffffff)) | ||||
234 | cn = getulong(&bp->b_data[bo])*((u_int32_t *)(&bp->b_data[bo])); | ||||
235 | else | ||||
236 | cn = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
| |||||
237 | if (FAT12(pmp)(pmp->pm_fatmask == 0x00000fff) && (prevcn & 1)) | ||||
238 | cn >>= 4; | ||||
239 | cn &= pmp->pm_fatmask; | ||||
240 | |||||
241 | /* | ||||
242 | * Force the special cluster numbers | ||||
243 | * to be the same for all cluster sizes | ||||
244 | * to let the rest of msdosfs handle | ||||
245 | * all cases the same. | ||||
246 | */ | ||||
247 | if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD0xfffffff6) | ||||
248 | cn |= ~pmp->pm_fatmask; | ||||
249 | } | ||||
250 | |||||
251 | if (!MSDOSFSEOF(pmp, cn)((((cn) | ~(pmp)->pm_fatmask) & 0xfffffff8) == 0xfffffff8 )) { | ||||
252 | if (bp) | ||||
253 | brelse(bp); | ||||
254 | if (bnp) | ||||
255 | *bnp = cntobn(pmp, cn)((((cn)-2) << (((pmp))->pm_cnshift - ((pmp))->pm_bnshift )) + (pmp)->pm_firstcluster); | ||||
256 | if (cnp) | ||||
257 | *cnp = cn; | ||||
258 | fc_setcache(dep, FC_LASTMAP, i, cn)(dep)->de_fc[0].fc_frcn = i; (dep)->de_fc[0].fc_fsrcn = cn;; | ||||
259 | return (0); | ||||
260 | } | ||||
261 | |||||
262 | hiteof: | ||||
263 | if (cnp) | ||||
264 | *cnp = i; | ||||
265 | if (bp) | ||||
266 | brelse(bp); | ||||
267 | /* update last file cluster entry in the fat cache */ | ||||
268 | fc_setcache(dep, FC_LASTFC, i - 1, prevcn)(dep)->de_fc[1].fc_frcn = i - 1; (dep)->de_fc[1].fc_fsrcn = prevcn;; | ||||
269 | return (E2BIG7); | ||||
270 | } | ||||
271 | |||||
272 | /* | ||||
273 | * Find the closest entry in the fat cache to the cluster we are looking | ||||
274 | * for. | ||||
275 | */ | ||||
276 | void | ||||
277 | fc_lookup(struct denode *dep, uint32_t findcn, uint32_t *frcnp, uint32_t *fsrcnp) | ||||
278 | { | ||||
279 | int i; | ||||
280 | uint32_t cn; | ||||
281 | struct fatcache *closest = 0; | ||||
282 | |||||
283 | for (i = 0; i < FC_SIZE3; i++) { | ||||
284 | cn = dep->de_fc[i].fc_frcn; | ||||
285 | if (cn != FCE_EMPTY0xffffffff && cn <= findcn) { | ||||
286 | if (closest == 0 || cn > closest->fc_frcn) | ||||
287 | closest = &dep->de_fc[i]; | ||||
288 | } | ||||
289 | } | ||||
290 | if (closest) { | ||||
291 | *frcnp = closest->fc_frcn; | ||||
292 | *fsrcnp = closest->fc_fsrcn; | ||||
293 | } | ||||
294 | } | ||||
295 | |||||
296 | /* | ||||
297 | * Purge the fat cache in denode dep of all entries relating to file | ||||
298 | * relative cluster frcn and beyond. | ||||
299 | */ | ||||
300 | void | ||||
301 | fc_purge(struct denode *dep, u_int frcn) | ||||
302 | { | ||||
303 | int i; | ||||
304 | struct fatcache *fcp; | ||||
305 | |||||
306 | fcp = dep->de_fc; | ||||
307 | for (i = 0; i < FC_SIZE3; i++, fcp++) { | ||||
308 | if (fcp->fc_frcn >= frcn) | ||||
309 | fcp->fc_frcn = FCE_EMPTY0xffffffff; | ||||
310 | } | ||||
311 | } | ||||
312 | |||||
313 | /* | ||||
314 | * Update the fat. | ||||
315 | * If mirroring the fat, update all copies, with the first copy as last. | ||||
316 | * Else update only the current fat (ignoring the others). | ||||
317 | * | ||||
318 | * pmp - msdosfsmount structure for filesystem to update | ||||
319 | * bp - addr of modified fat block | ||||
320 | * fatbn - block number relative to begin of filesystem of the modified fat block. | ||||
321 | */ | ||||
322 | void | ||||
323 | updatefats(struct msdosfsmount *pmp, struct buf *bp, uint32_t fatbn) | ||||
324 | { | ||||
325 | int i; | ||||
326 | struct buf *bpn; | ||||
327 | |||||
328 | #ifdef MSDOSFS_DEBUG | ||||
329 | printf("updatefats(pmp %p, buf %p, fatbn %d)\n", pmp, bp, fatbn); | ||||
330 | #endif | ||||
331 | |||||
332 | /* | ||||
333 | * If we have an FSInfo block, update it. | ||||
334 | */ | ||||
335 | if (pmp->pm_fsinfo) { | ||||
336 | if (bread(pmp->pm_devvp, pmp->pm_fsinfo, fsi_size(pmp)(1024 << ((pmp)->pm_BlkPerSec >> 2)), | ||||
337 | &bpn) != 0) { | ||||
338 | /* | ||||
339 | * Ignore the error, but turn off FSInfo update for the future. | ||||
340 | */ | ||||
341 | pmp->pm_fsinfo = 0; | ||||
342 | brelse(bpn); | ||||
343 | } else { | ||||
344 | struct fsinfo *fp = (struct fsinfo *)bpn->b_data; | ||||
345 | |||||
346 | putulong(fp->fsinfree, pmp->pm_freeclustercount)(*((u_int32_t *)(fp->fsinfree)) = (pmp->pm_freeclustercount )); | ||||
347 | if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT0x40000000) | ||||
348 | bwrite(bpn); | ||||
349 | else | ||||
350 | bdwrite(bpn); | ||||
351 | } | ||||
352 | } | ||||
353 | |||||
354 | if (pmp->pm_flags & MSDOSFS_FATMIRROR0x20000000) { | ||||
355 | /* | ||||
356 | * Now copy the block(s) of the modified fat to the other copies of | ||||
357 | * the fat and write them out. This is faster than reading in the | ||||
358 | * other fats and then writing them back out. This could tie up | ||||
359 | * the fat for quite a while. Preventing others from accessing it. | ||||
360 | * To prevent us from going after the fat quite so much we use | ||||
361 | * delayed writes, unless they specified "synchronous" when the | ||||
362 | * filesystem was mounted. If synch is asked for then use | ||||
363 | * bwrite()'s and really slow things down. | ||||
364 | */ | ||||
365 | for (i = 1; i < pmp->pm_FATspm_bpb.bpbFATs; i++) { | ||||
366 | fatbn += pmp->pm_FATsecs; | ||||
367 | /* getblk() never fails */ | ||||
368 | bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, 0, | ||||
369 | INFSLP0xffffffffffffffffULL); | ||||
370 | bcopy(bp->b_data, bpn->b_data, bp->b_bcount); | ||||
371 | if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT0x40000000) | ||||
372 | bwrite(bpn); | ||||
373 | else | ||||
374 | bdwrite(bpn); | ||||
375 | } | ||||
376 | } | ||||
377 | |||||
378 | /* | ||||
379 | * Write out the first (or current) fat last. | ||||
380 | */ | ||||
381 | if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT0x40000000) | ||||
382 | bwrite(bp); | ||||
383 | else | ||||
384 | bdwrite(bp); | ||||
385 | /* | ||||
386 | * Maybe update fsinfo sector here? | ||||
387 | */ | ||||
388 | } | ||||
389 | |||||
390 | /* | ||||
391 | * Updating entries in 12 bit fats is a pain in the butt. | ||||
392 | * | ||||
393 | * The following picture shows where nibbles go when moving from a 12 bit | ||||
394 | * cluster number into the appropriate bytes in the FAT. | ||||
395 | * | ||||
396 | * byte m byte m+1 byte m+2 | ||||
397 | * +----+----+ +----+----+ +----+----+ | ||||
398 | * | 0 1 | | 2 3 | | 4 5 | FAT bytes | ||||
399 | * +----+----+ +----+----+ +----+----+ | ||||
400 | * | ||||
401 | * +----+----+----+ +----+----+----+ | ||||
402 | * | 3 0 1 | | 4 5 2 | | ||||
403 | * +----+----+----+ +----+----+----+ | ||||
404 | * cluster n cluster n+1 | ||||
405 | * | ||||
406 | * Where n is even. m = n + (n >> 2) | ||||
407 | * | ||||
408 | */ | ||||
409 | static __inline void | ||||
410 | usemap_alloc(struct msdosfsmount *pmp, uint32_t cn) | ||||
411 | { | ||||
412 | |||||
413 | pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))] |= 1 << (cn % N_INUSEBITS(8 * sizeof(u_int))); | ||||
414 | pmp->pm_freeclustercount--; | ||||
415 | } | ||||
416 | |||||
417 | static __inline void | ||||
418 | usemap_free(struct msdosfsmount *pmp, uint32_t cn) | ||||
419 | { | ||||
420 | |||||
421 | pmp->pm_freeclustercount++; | ||||
422 | pmp->pm_inusemap[cn / N_INUSEBITS(8 * sizeof(u_int))] &= ~(1 << (cn % N_INUSEBITS(8 * sizeof(u_int)))); | ||||
423 | } | ||||
424 | |||||
425 | int | ||||
426 | clusterfree(struct msdosfsmount *pmp, uint32_t cluster, uint32_t *oldcnp) | ||||
427 | { | ||||
428 | int error; | ||||
429 | uint32_t oldcn; | ||||
430 | |||||
431 | usemap_free(pmp, cluster); | ||||
432 | error = fatentry(FAT_GET_AND_SET(0x0001 | 0x0002), pmp, cluster, &oldcn, MSDOSFSFREE0); | ||||
433 | if (error) { | ||||
434 | usemap_alloc(pmp, cluster); | ||||
435 | return (error); | ||||
436 | } | ||||
437 | /* | ||||
438 | * If the cluster was successfully marked free, then update | ||||
439 | * the count of free clusters, and turn off the "allocated" | ||||
440 | * bit in the "in use" cluster bit map. | ||||
441 | */ | ||||
442 | if (oldcnp) | ||||
443 | *oldcnp = oldcn; | ||||
444 | return (0); | ||||
445 | } | ||||
446 | |||||
447 | /* | ||||
448 | * Get or Set or 'Get and Set' the cluster'th entry in the fat. | ||||
449 | * | ||||
450 | * function - whether to get or set a fat entry | ||||
451 | * pmp - address of the msdosfsmount structure for the filesystem | ||||
452 | * whose fat is to be manipulated. | ||||
453 | * cn - which cluster is of interest | ||||
454 | * oldcontents - address of a word that is to receive the contents of the | ||||
455 | * cluster'th entry if this is a get function | ||||
456 | * newcontents - the new value to be written into the cluster'th element of | ||||
457 | * the fat if this is a set function. | ||||
458 | * | ||||
459 | * This function can also be used to free a cluster by setting the fat entry | ||||
460 | * for a cluster to 0. | ||||
461 | * | ||||
462 | * All copies of the fat are updated if this is a set function. NOTE: If | ||||
463 | * fatentry() marks a cluster as free it does not update the inusemap in | ||||
464 | * the msdosfsmount structure. This is left to the caller. | ||||
465 | */ | ||||
466 | int | ||||
467 | fatentry(int function, struct msdosfsmount *pmp, uint32_t cn, uint32_t *oldcontents, | ||||
468 | uint32_t newcontents) | ||||
469 | { | ||||
470 | int error; | ||||
471 | uint32_t readcn; | ||||
472 | uint32_t bn, bo, bsize, byteoffset; | ||||
473 | struct buf *bp; | ||||
474 | |||||
475 | #ifdef MSDOSFS_DEBUG | ||||
476 | printf("fatentry(func %d, pmp %p, clust %d, oldcon %p, " | ||||
477 | "newcon %d)\n", function, pmp, cn, oldcontents, newcontents); | ||||
478 | #endif | ||||
479 | |||||
480 | #ifdef DIAGNOSTIC1 | ||||
481 | /* | ||||
482 | * Be sure they asked us to do something. | ||||
483 | */ | ||||
484 | if ((function & (FAT_SET0x0002 | FAT_GET0x0001)) == 0) { | ||||
485 | printf("fatentry(): function code doesn't specify get or set\n"); | ||||
486 | return (EINVAL22); | ||||
487 | } | ||||
488 | |||||
489 | /* | ||||
490 | * If they asked us to return a cluster number but didn't tell us | ||||
491 | * where to put it, give them an error. | ||||
492 | */ | ||||
493 | if ((function & FAT_GET0x0001) && oldcontents == NULL((void *)0)) { | ||||
494 | printf("fatentry(): get function with no place to put result\n"); | ||||
495 | return (EINVAL22); | ||||
496 | } | ||||
497 | #endif | ||||
498 | |||||
499 | /* | ||||
500 | * Be sure the requested cluster is in the filesystem. | ||||
501 | */ | ||||
502 | if (cn < CLUST_FIRST2 || cn > pmp->pm_maxcluster) | ||||
503 | return (EINVAL22); | ||||
504 | |||||
505 | byteoffset = FATOFS(pmp, cn)((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv); | ||||
506 | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
507 | if ((error = bread(pmp->pm_devvp, bn, bsize, &bp)) != 0) { | ||||
508 | brelse(bp); | ||||
509 | return (error); | ||||
510 | } | ||||
511 | |||||
512 | if (function & FAT_GET0x0001) { | ||||
513 | if (FAT32(pmp)(pmp->pm_fatmask == 0x0fffffff)) | ||||
514 | readcn = getulong(&bp->b_data[bo])*((u_int32_t *)(&bp->b_data[bo])); | ||||
515 | else | ||||
516 | readcn = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
517 | if (FAT12(pmp)(pmp->pm_fatmask == 0x00000fff) && (cn & 1)) | ||||
518 | readcn >>= 4; | ||||
519 | readcn &= pmp->pm_fatmask; | ||||
520 | /* map reserved fat entries to same values for all fats */ | ||||
521 | if ((readcn | ~pmp->pm_fatmask) >= CLUST_RSRVD0xfffffff6) | ||||
522 | readcn |= ~pmp->pm_fatmask; | ||||
523 | *oldcontents = readcn; | ||||
524 | } | ||||
525 | if (function & FAT_SET0x0002) { | ||||
526 | switch (pmp->pm_fatmask) { | ||||
527 | case FAT12_MASK0x00000fff: | ||||
528 | readcn = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
529 | if (cn & 1) { | ||||
530 | readcn &= 0x000f; | ||||
531 | readcn |= newcontents << 4; | ||||
532 | } else { | ||||
533 | readcn &= 0xf000; | ||||
534 | readcn |= newcontents & 0xfff; | ||||
535 | } | ||||
536 | putushort(&bp->b_data[bo], readcn)(*((u_int16_t *)(&bp->b_data[bo])) = (readcn)); | ||||
537 | break; | ||||
538 | case FAT16_MASK0x0000ffff: | ||||
539 | putushort(&bp->b_data[bo], newcontents)(*((u_int16_t *)(&bp->b_data[bo])) = (newcontents)); | ||||
540 | break; | ||||
541 | case FAT32_MASK0x0fffffff: | ||||
542 | /* | ||||
543 | * According to spec we have to retain the | ||||
544 | * high order bits of the fat entry. | ||||
545 | */ | ||||
546 | readcn = getulong(&bp->b_data[bo])*((u_int32_t *)(&bp->b_data[bo])); | ||||
547 | readcn &= ~FAT32_MASK0x0fffffff; | ||||
548 | readcn |= newcontents & FAT32_MASK0x0fffffff; | ||||
549 | putulong(&bp->b_data[bo], readcn)(*((u_int32_t *)(&bp->b_data[bo])) = (readcn)); | ||||
550 | break; | ||||
551 | } | ||||
552 | updatefats(pmp, bp, bn); | ||||
553 | bp = NULL((void *)0); | ||||
554 | pmp->pm_fmod = 1; | ||||
555 | } | ||||
556 | if (bp) | ||||
557 | brelse(bp); | ||||
558 | return (0); | ||||
559 | } | ||||
560 | |||||
561 | /* | ||||
562 | * Update a contiguous cluster chain | ||||
563 | * | ||||
564 | * pmp - mount point | ||||
565 | * start - first cluster of chain | ||||
566 | * count - number of clusters in chain | ||||
567 | * fillwith - what to write into fat entry of last cluster | ||||
568 | */ | ||||
569 | static int | ||||
570 | fatchain(struct msdosfsmount *pmp, uint32_t start, uint32_t count, uint32_t fillwith) | ||||
571 | { | ||||
572 | int error; | ||||
573 | uint32_t bn, bo, bsize, byteoffset, readcn, newc; | ||||
574 | struct buf *bp; | ||||
575 | |||||
576 | #ifdef MSDOSFS_DEBUG | ||||
577 | printf("fatchain(pmp %p, start %d, count %d, fillwith %d)\n", | ||||
578 | pmp, start, count, fillwith); | ||||
579 | #endif | ||||
580 | /* | ||||
581 | * Be sure the clusters are in the filesystem. | ||||
582 | */ | ||||
583 | if (start < CLUST_FIRST2 || start + count - 1 > pmp->pm_maxcluster) | ||||
584 | return (EINVAL22); | ||||
585 | |||||
586 | while (count > 0) { | ||||
587 | byteoffset = FATOFS(pmp, start)((start) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv); | ||||
588 | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
589 | error = bread(pmp->pm_devvp, bn, bsize, &bp); | ||||
590 | if (error) { | ||||
591 | brelse(bp); | ||||
592 | return (error); | ||||
593 | } | ||||
594 | while (count > 0) { | ||||
595 | start++; | ||||
596 | newc = --count > 0 ? start : fillwith; | ||||
597 | switch (pmp->pm_fatmask) { | ||||
598 | case FAT12_MASK0x00000fff: | ||||
599 | readcn = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
600 | if (start & 1) { | ||||
601 | readcn &= 0xf000; | ||||
602 | readcn |= newc & 0xfff; | ||||
603 | } else { | ||||
604 | readcn &= 0x000f; | ||||
605 | readcn |= newc << 4; | ||||
606 | } | ||||
607 | putushort(&bp->b_data[bo], readcn)(*((u_int16_t *)(&bp->b_data[bo])) = (readcn)); | ||||
608 | bo++; | ||||
609 | if (!(start & 1)) | ||||
610 | bo++; | ||||
611 | break; | ||||
612 | case FAT16_MASK0x0000ffff: | ||||
613 | putushort(&bp->b_data[bo], newc)(*((u_int16_t *)(&bp->b_data[bo])) = (newc)); | ||||
614 | bo += 2; | ||||
615 | break; | ||||
616 | case FAT32_MASK0x0fffffff: | ||||
617 | readcn = getulong(&bp->b_data[bo])*((u_int32_t *)(&bp->b_data[bo])); | ||||
618 | readcn &= ~pmp->pm_fatmask; | ||||
619 | readcn |= newc & pmp->pm_fatmask; | ||||
620 | putulong(&bp->b_data[bo], readcn)(*((u_int32_t *)(&bp->b_data[bo])) = (readcn)); | ||||
621 | bo += 4; | ||||
622 | break; | ||||
623 | } | ||||
624 | if (bo >= bsize) | ||||
625 | break; | ||||
626 | } | ||||
627 | updatefats(pmp, bp, bn); | ||||
628 | } | ||||
629 | pmp->pm_fmod = 1; | ||||
630 | return (0); | ||||
631 | } | ||||
632 | |||||
633 | /* | ||||
634 | * Check the length of a free cluster chain starting at start. | ||||
635 | * | ||||
636 | * pmp - mount point | ||||
637 | * start - start of chain | ||||
638 | * count - maximum interesting length | ||||
639 | */ | ||||
640 | int | ||||
641 | chainlength(struct msdosfsmount *pmp, uint32_t start, uint32_t count) | ||||
642 | { | ||||
643 | uint32_t idx, max_idx; | ||||
644 | u_int map; | ||||
645 | uint32_t len; | ||||
646 | |||||
647 | max_idx = pmp->pm_maxcluster / N_INUSEBITS(8 * sizeof(u_int)); | ||||
648 | idx = start / N_INUSEBITS(8 * sizeof(u_int)); | ||||
649 | start %= N_INUSEBITS(8 * sizeof(u_int)); | ||||
650 | map = pmp->pm_inusemap[idx]; | ||||
651 | map &= ~((1 << start) - 1); | ||||
652 | if (map) { | ||||
653 | len = ffs(map) - 1 - start; | ||||
654 | return (len > count ? count : len); | ||||
655 | } | ||||
656 | len = N_INUSEBITS(8 * sizeof(u_int)) - start; | ||||
657 | if (len >= count) | ||||
658 | return (count); | ||||
659 | while (++idx <= max_idx) { | ||||
660 | if (len >= count) | ||||
661 | break; | ||||
662 | if ((map = pmp->pm_inusemap[idx]) != 0) { | ||||
663 | len += ffs(map) - 1; | ||||
664 | break; | ||||
665 | } | ||||
666 | len += N_INUSEBITS(8 * sizeof(u_int)); | ||||
667 | } | ||||
668 | return (len > count ? count : len); | ||||
669 | } | ||||
670 | |||||
671 | /* | ||||
672 | * Allocate contiguous free clusters. | ||||
673 | * | ||||
674 | * pmp - mount point. | ||||
675 | * start - start of cluster chain. | ||||
676 | * count - number of clusters to allocate. | ||||
677 | * fillwith - put this value into the fat entry for the | ||||
678 | * last allocated cluster. | ||||
679 | * retcluster - put the first allocated cluster's number here. | ||||
680 | * got - how many clusters were actually allocated. | ||||
681 | */ | ||||
682 | int | ||||
683 | chainalloc(struct msdosfsmount *pmp, uint32_t start, uint32_t count, | ||||
684 | uint32_t fillwith, uint32_t *retcluster, uint32_t *got) | ||||
685 | { | ||||
686 | int error; | ||||
687 | uint32_t cl, n; | ||||
688 | |||||
689 | for (cl = start, n = count; n-- > 0;) | ||||
690 | usemap_alloc(pmp, cl++); | ||||
691 | if ((error = fatchain(pmp, start, count, fillwith)) != 0) | ||||
692 | return (error); | ||||
693 | #ifdef MSDOSFS_DEBUG | ||||
694 | printf("clusteralloc(): allocated cluster chain at %d (%d clusters)\n", | ||||
695 | start, count); | ||||
696 | #endif | ||||
697 | if (retcluster) | ||||
698 | *retcluster = start; | ||||
699 | if (got) | ||||
700 | *got = count; | ||||
701 | return (0); | ||||
702 | } | ||||
703 | |||||
704 | /* | ||||
705 | * Allocate contiguous free clusters. | ||||
706 | * | ||||
707 | * pmp - mount point. | ||||
708 | * start - preferred start of cluster chain. | ||||
709 | * count - number of clusters requested. | ||||
710 | * fillwith - put this value into the fat entry for the | ||||
711 | * last allocated cluster. | ||||
712 | * retcluster - put the first allocated cluster's number here. | ||||
713 | * got - how many clusters were actually allocated. | ||||
714 | */ | ||||
715 | int | ||||
716 | clusteralloc(struct msdosfsmount *pmp, uint32_t start, uint32_t count, | ||||
717 | uint32_t *retcluster, uint32_t *got) | ||||
718 | { | ||||
719 | uint32_t idx; | ||||
720 | uint32_t len, newst, foundl, cn, l; | ||||
721 | uint32_t foundcn = 0; /* XXX: foundcn could be used uninitialized */ | ||||
722 | uint32_t fillwith = CLUST_EOFE0xffffffff; | ||||
723 | u_int map; | ||||
724 | |||||
725 | #ifdef MSDOSFS_DEBUG | ||||
726 | printf("clusteralloc(): find %d clusters\n",count); | ||||
727 | #endif | ||||
728 | if (start) { | ||||
729 | if ((len = chainlength(pmp, start, count)) >= count) | ||||
730 | return (chainalloc(pmp, start, count, fillwith, retcluster, got)); | ||||
731 | } else { | ||||
732 | /* | ||||
733 | * This is a new file, initialize start | ||||
734 | */ | ||||
735 | struct timeval tv; | ||||
736 | |||||
737 | microtime(&tv); | ||||
738 | start = (tv.tv_usec >> 10) | tv.tv_usec; | ||||
739 | len = 0; | ||||
740 | } | ||||
741 | |||||
742 | /* | ||||
743 | * Start at a (pseudo) random place to maximize cluster runs | ||||
744 | * under multiple writers. | ||||
745 | */ | ||||
746 | newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1); | ||||
747 | foundl = 0; | ||||
748 | |||||
749 | for (cn = newst; cn <= pmp->pm_maxcluster;) { | ||||
750 | idx = cn / N_INUSEBITS(8 * sizeof(u_int)); | ||||
751 | map = pmp->pm_inusemap[idx]; | ||||
752 | map |= (1 << (cn % N_INUSEBITS(8 * sizeof(u_int)))) - 1; | ||||
753 | if (map != (u_int)-1) { | ||||
754 | cn = idx * N_INUSEBITS(8 * sizeof(u_int)) + ffs(map^(u_int)-1) - 1; | ||||
755 | if ((l = chainlength(pmp, cn, count)) >= count) | ||||
756 | return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); | ||||
757 | if (l > foundl) { | ||||
758 | foundcn = cn; | ||||
759 | foundl = l; | ||||
760 | } | ||||
761 | cn += l + 1; | ||||
762 | continue; | ||||
763 | } | ||||
764 | cn += N_INUSEBITS(8 * sizeof(u_int)) - cn % N_INUSEBITS(8 * sizeof(u_int)); | ||||
765 | } | ||||
766 | for (cn = 0; cn < newst;) { | ||||
767 | idx = cn / N_INUSEBITS(8 * sizeof(u_int)); | ||||
768 | map = pmp->pm_inusemap[idx]; | ||||
769 | map |= (1 << (cn % N_INUSEBITS(8 * sizeof(u_int)))) - 1; | ||||
770 | if (map != (u_int)-1) { | ||||
771 | cn = idx * N_INUSEBITS(8 * sizeof(u_int)) + ffs(map^(u_int)-1) - 1; | ||||
772 | if ((l = chainlength(pmp, cn, count)) >= count) | ||||
773 | return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); | ||||
774 | if (l > foundl) { | ||||
775 | foundcn = cn; | ||||
776 | foundl = l; | ||||
777 | } | ||||
778 | cn += l + 1; | ||||
779 | continue; | ||||
780 | } | ||||
781 | cn += N_INUSEBITS(8 * sizeof(u_int)) - cn % N_INUSEBITS(8 * sizeof(u_int)); | ||||
782 | } | ||||
783 | |||||
784 | if (!foundl) | ||||
785 | return (ENOSPC28); | ||||
786 | |||||
787 | if (len) | ||||
788 | return (chainalloc(pmp, start, len, fillwith, retcluster, got)); | ||||
789 | else | ||||
790 | return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got)); | ||||
791 | } | ||||
792 | |||||
793 | |||||
794 | /* | ||||
795 | * Free a chain of clusters. | ||||
796 | * | ||||
797 | * pmp - address of the msdosfs mount structure for the filesystem | ||||
798 | * containing the cluster chain to be freed. | ||||
799 | * startcluster - number of the 1st cluster in the chain of clusters to be | ||||
800 | * freed. | ||||
801 | */ | ||||
802 | int | ||||
803 | freeclusterchain(struct msdosfsmount *pmp, uint32_t cluster) | ||||
804 | { | ||||
805 | int error; | ||||
806 | struct buf *bp = NULL((void *)0); | ||||
807 | uint32_t bn, bo, bsize, byteoffset; | ||||
808 | uint32_t readcn, lbn = -1; | ||||
809 | |||||
810 | while (cluster >= CLUST_FIRST2 && cluster <= pmp->pm_maxcluster) { | ||||
811 | byteoffset = FATOFS(pmp, cluster)((cluster) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv); | ||||
812 | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
813 | if (lbn != bn) { | ||||
814 | if (bp) | ||||
815 | updatefats(pmp, bp, lbn); | ||||
816 | error = bread(pmp->pm_devvp, bn, bsize, &bp); | ||||
817 | if (error) { | ||||
818 | brelse(bp); | ||||
819 | return (error); | ||||
820 | } | ||||
821 | lbn = bn; | ||||
822 | } | ||||
823 | usemap_free(pmp, cluster); | ||||
824 | switch (pmp->pm_fatmask) { | ||||
825 | case FAT12_MASK0x00000fff: | ||||
826 | readcn = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
827 | if (cluster & 1) { | ||||
828 | cluster = readcn >> 4; | ||||
829 | readcn &= 0x000f; | ||||
830 | readcn |= MSDOSFSFREE0 << 4; | ||||
831 | } else { | ||||
832 | cluster = readcn; | ||||
833 | readcn &= 0xf000; | ||||
834 | readcn |= MSDOSFSFREE0 & 0xfff; | ||||
835 | } | ||||
836 | putushort(&bp->b_data[bo], readcn)(*((u_int16_t *)(&bp->b_data[bo])) = (readcn)); | ||||
837 | break; | ||||
838 | case FAT16_MASK0x0000ffff: | ||||
839 | cluster = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
840 | putushort(&bp->b_data[bo], MSDOSFSFREE)(*((u_int16_t *)(&bp->b_data[bo])) = (0)); | ||||
841 | break; | ||||
842 | case FAT32_MASK0x0fffffff: | ||||
843 | cluster = getulong(&bp->b_data[bo])*((u_int32_t *)(&bp->b_data[bo])); | ||||
844 | putulong(&bp->b_data[bo],(*((u_int32_t *)(&bp->b_data[bo])) = ((0 & 0x0fffffff ) | (cluster & ~0x0fffffff))) | ||||
845 | (MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK))(*((u_int32_t *)(&bp->b_data[bo])) = ((0 & 0x0fffffff ) | (cluster & ~0x0fffffff))); | ||||
846 | break; | ||||
847 | } | ||||
848 | cluster &= pmp->pm_fatmask; | ||||
849 | if ((cluster | ~pmp->pm_fatmask) >= CLUST_RSRVD0xfffffff6) | ||||
850 | cluster |= pmp->pm_fatmask; | ||||
851 | } | ||||
852 | if (bp) | ||||
853 | updatefats(pmp, bp, bn); | ||||
854 | return (0); | ||||
855 | } | ||||
856 | |||||
857 | /* | ||||
858 | * Read in fat blocks looking for free clusters. For every free cluster | ||||
859 | * found turn off its corresponding bit in the pm_inusemap. | ||||
860 | */ | ||||
861 | int | ||||
862 | fillinusemap(struct msdosfsmount *pmp) | ||||
863 | { | ||||
864 | struct buf *bp = NULL((void *)0); | ||||
865 | uint32_t cn, readcn; | ||||
866 | int error; | ||||
867 | uint32_t bn, bo, bsize, byteoffset; | ||||
868 | |||||
869 | /* | ||||
870 | * Mark all clusters in use, we mark the free ones in the fat scan | ||||
871 | * loop further down. | ||||
872 | */ | ||||
873 | for (cn = 0; cn < howmany(pmp->pm_maxcluster + 1, N_INUSEBITS)(((pmp->pm_maxcluster + 1) + (((8 * sizeof(u_int))) - 1)) / ((8 * sizeof(u_int)))); cn++) | ||||
874 | pmp->pm_inusemap[cn] = (u_int)-1; | ||||
875 | |||||
876 | /* | ||||
877 | * Figure how many free clusters are in the filesystem by ripping | ||||
878 | * through the fat counting the number of entries whose content is | ||||
879 | * zero. These represent free clusters. | ||||
880 | */ | ||||
881 | pmp->pm_freeclustercount = 0; | ||||
882 | for (cn = CLUST_FIRST2; cn <= pmp->pm_maxcluster; cn++) { | ||||
883 | byteoffset = FATOFS(pmp, cn)((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv); | ||||
884 | bo = byteoffset % pmp->pm_fatblocksize; | ||||
885 | if (!bo || !bp) { | ||||
886 | /* Read new FAT block */ | ||||
887 | if (bp) | ||||
888 | brelse(bp); | ||||
889 | fatblock(pmp, byteoffset, &bn, &bsize, NULL((void *)0)); | ||||
890 | error = bread(pmp->pm_devvp, bn, bsize, &bp); | ||||
891 | if (error) { | ||||
892 | brelse(bp); | ||||
893 | return (error); | ||||
894 | } | ||||
895 | } | ||||
896 | if (FAT32(pmp)(pmp->pm_fatmask == 0x0fffffff)) | ||||
897 | readcn = getulong(&bp->b_data[bo])*((u_int32_t *)(&bp->b_data[bo])); | ||||
898 | else | ||||
899 | readcn = getushort(&bp->b_data[bo])*((u_int16_t *)(&bp->b_data[bo])); | ||||
900 | if (FAT12(pmp)(pmp->pm_fatmask == 0x00000fff) && (cn & 1)) | ||||
901 | readcn >>= 4; | ||||
902 | readcn &= pmp->pm_fatmask; | ||||
903 | |||||
904 | if (readcn == 0) | ||||
905 | usemap_free(pmp, cn); | ||||
906 | } | ||||
907 | brelse(bp); | ||||
908 | return (0); | ||||
909 | } | ||||
910 | |||||
911 | /* | ||||
912 | * Allocate a new cluster and chain it onto the end of the file. | ||||
913 | * | ||||
914 | * dep - the file to extend | ||||
915 | * count - number of clusters to allocate | ||||
916 | * bpp - where to return the address of the buf header for the first new | ||||
917 | * file block | ||||
918 | * ncp - where to put cluster number of the first newly allocated cluster | ||||
919 | * If this pointer is 0, do not return the cluster number. | ||||
920 | * flags - see fat.h | ||||
921 | * | ||||
922 | * NOTE: This function is not responsible for turning on the DE_UPDATE bit of | ||||
923 | * the de_flag field of the denode and it does not change the de_FileSize | ||||
924 | * field. This is left for the caller to do. | ||||
925 | */ | ||||
926 | int | ||||
927 | extendfile(struct denode *dep, uint32_t count, struct buf **bpp, uint32_t *ncp, | ||||
928 | int flags) | ||||
929 | { | ||||
930 | int error; | ||||
931 | uint32_t frcn; | ||||
932 | uint32_t cn, got; | ||||
933 | struct msdosfsmount *pmp = dep->de_pmp; | ||||
934 | struct buf *bp; | ||||
935 | |||||
936 | /* | ||||
937 | * Don't try to extend the root directory | ||||
938 | */ | ||||
939 | if (dep->de_StartCluster == MSDOSFSROOT0 | ||||
| |||||
940 | && (dep->de_Attributes & ATTR_DIRECTORY0x10)) { | ||||
941 | printf("extendfile(): attempt to extend root directory\n"); | ||||
942 | return (ENOSPC28); | ||||
943 | } | ||||
944 | |||||
945 | /* | ||||
946 | * If the "file's last cluster" cache entry is empty, and the file | ||||
947 | * is not empty, then fill the cache entry by calling pcbmap(). | ||||
948 | */ | ||||
949 | fc_fileextends++; | ||||
950 | if (dep->de_fc[FC_LASTFC1].fc_frcn == FCE_EMPTY0xffffffff && | ||||
951 | dep->de_StartCluster
| ||||
952 | fc_lfcempty++; | ||||
953 | error = pcbmap(dep, CLUST_END0xffffffff, 0, &cn, 0); | ||||
954 | /* we expect it to return E2BIG */ | ||||
955 | if (error != E2BIG7) | ||||
956 | return (error); | ||||
957 | } | ||||
958 | |||||
959 | /* | ||||
960 | * Preserve value for the last cluster before extending the file | ||||
961 | * to speed up further lookups. | ||||
962 | */ | ||||
963 | fc_setcache(dep, FC_OLASTFC, dep->de_fc[FC_LASTFC].fc_frcn,(dep)->de_fc[2].fc_frcn = dep->de_fc[1].fc_frcn; (dep)-> de_fc[2].fc_fsrcn = dep->de_fc[1].fc_fsrcn; | ||||
964 | dep->de_fc[FC_LASTFC].fc_fsrcn)(dep)->de_fc[2].fc_frcn = dep->de_fc[1].fc_frcn; (dep)-> de_fc[2].fc_fsrcn = dep->de_fc[1].fc_fsrcn;; | ||||
965 | |||||
966 | while (count > 0) { | ||||
967 | /* | ||||
968 | * Allocate a new cluster chain and cat onto the end of the | ||||
969 | * file. * If the file is empty we make de_StartCluster point | ||||
970 | * to the new block. Note that de_StartCluster being 0 is | ||||
971 | * sufficient to be sure the file is empty since we exclude | ||||
972 | * attempts to extend the root directory above, and the root | ||||
973 | * dir is the only file with a startcluster of 0 that has | ||||
974 | * blocks allocated (sort of). | ||||
975 | */ | ||||
976 | if (dep->de_StartCluster == 0) | ||||
977 | cn = 0; | ||||
978 | else | ||||
979 | cn = dep->de_fc[FC_LASTFC1].fc_fsrcn + 1; | ||||
980 | error = clusteralloc(pmp, cn, count, &cn, &got); | ||||
981 | if (error) | ||||
982 | return (error); | ||||
983 | |||||
984 | count -= got; | ||||
985 | |||||
986 | /* | ||||
987 | * Give them the filesystem relative cluster number if they want | ||||
988 | * it. | ||||
989 | */ | ||||
990 | if (ncp) { | ||||
991 | *ncp = cn; | ||||
992 | ncp = NULL((void *)0); | ||||
993 | } | ||||
994 | |||||
995 | if (dep->de_StartCluster == 0) { | ||||
996 | dep->de_StartCluster = cn; | ||||
997 | frcn = 0; | ||||
998 | } else { | ||||
999 | error = fatentry(FAT_SET0x0002, pmp, | ||||
1000 | dep->de_fc[FC_LASTFC1].fc_fsrcn, | ||||
1001 | 0, cn); | ||||
1002 | if (error) { | ||||
1003 | clusterfree(pmp, cn, NULL((void *)0)); | ||||
1004 | return (error); | ||||
1005 | } | ||||
1006 | frcn = dep->de_fc[FC_LASTFC1].fc_frcn + 1; | ||||
1007 | } | ||||
1008 | |||||
1009 | /* | ||||
1010 | * Update the "last cluster of the file" entry in the denode's fat | ||||
1011 | * cache. | ||||
1012 | */ | ||||
1013 | 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;; | ||||
1014 | |||||
1015 | if (flags & DE_CLEAR1) { | ||||
1016 | while (got-- > 0) { | ||||
1017 | /* | ||||
1018 | * Get the buf header for the new block of the file. | ||||
1019 | */ | ||||
1020 | if (dep->de_Attributes & ATTR_DIRECTORY0x10) | ||||
1021 | bp = getblk(pmp->pm_devvp, cntobn(pmp, cn++)((((cn++)-2) << (((pmp))->pm_cnshift - ((pmp))->pm_bnshift )) + (pmp)->pm_firstcluster), | ||||
1022 | pmp->pm_bpcluster, 0, INFSLP0xffffffffffffffffULL); | ||||
1023 | else { | ||||
1024 | bp = getblk(DETOV(dep)((dep)->de_vnode), frcn++, | ||||
1025 | pmp->pm_bpcluster, 0, INFSLP0xffffffffffffffffULL); | ||||
1026 | /* | ||||
1027 | * Do the bmap now, as in msdosfs_write | ||||
1028 | */ | ||||
1029 | if (pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0, 0)) | ||||
1030 | bp->b_blkno = -1; | ||||
1031 | if (bp->b_blkno == -1) | ||||
1032 | panic("extendfile: pcbmap"); | ||||
1033 | } | ||||
1034 | clrbuf(bp){ __builtin_bzero(((bp)->b_data), ((bp)->b_bcount)); (bp )->b_resid = 0; }; | ||||
1035 | if (bpp) { | ||||
1036 | *bpp = bp; | ||||
1037 | bpp = NULL((void *)0); | ||||
1038 | } else | ||||
1039 | bdwrite(bp); | ||||
1040 | } | ||||
1041 | } | ||||
1042 | } | ||||
1043 | |||||
1044 | return (0); | ||||
1045 | } |