Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Written by Paul Popelka (paulp@uts.amdahl.com) | |
3 | * | |
4 | * You can do anything you want with this software, | |
5 | * just don't say you wrote it, | |
6 | * and don't remove this notice. | |
7 | * | |
8 | * This software is provided "as is". | |
9 | * | |
10 | * The author supplies this software to be publicly | |
11 | * redistributed on the understanding that the author | |
12 | * is not responsible for the correct functioning of | |
13 | * this software in any circumstances and is not liable | |
14 | * for any damages caused by this software. | |
15 | * | |
16 | * October 1992 | |
17 | * | |
4c45483e | 18 | * $Id: pcfs_fat.c,v 1.2 1993/10/16 19:29:34 rgrimes Exp $ |
15637ed4 RG |
19 | */ |
20 | ||
21 | /* | |
22 | * kernel include files. | |
23 | */ | |
24 | #include "param.h" | |
25 | #include "systm.h" | |
26 | #include "buf.h" | |
27 | #include "file.h" | |
28 | #include "namei.h" | |
29 | #include "mount.h" /* to define statfs structure */ | |
30 | #include "vnode.h" /* to define vattr structure */ | |
31 | #include "errno.h" | |
32 | ||
33 | /* | |
34 | * pcfs include files. | |
35 | */ | |
36 | #include "bpb.h" | |
37 | #include "pcfsmount.h" | |
38 | #include "direntry.h" | |
39 | #include "denode.h" | |
40 | #include "fat.h" | |
41 | ||
4c45483e GW |
42 | static void fc_lookup(struct denode *, u_long, u_long *, u_long *); |
43 | ||
15637ed4 RG |
44 | /* |
45 | * Fat cache stats. | |
46 | */ | |
47 | int fc_fileextends; /* # of file extends */ | |
48 | int fc_lfcempty; /* # of time last file cluster cache entry | |
49 | * was empty */ | |
50 | int fc_bmapcalls; /* # of times pcbmap was called */ | |
51 | #define LMMAX 20 | |
52 | int fc_lmdistance[LMMAX]; /* counters for how far off the last cluster | |
53 | * mapped entry was. */ | |
54 | int fc_largedistance; /* off by more than LMMAX */ | |
55 | ||
56 | /* Byte offset in FAT on filesystem pmp, cluster cn */ | |
57 | #define FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2) | |
58 | ||
59 | ||
60 | static void fatblock (pmp, ofs, bnp, sizep, bop) | |
61 | struct pcfsmount *pmp; | |
62 | u_long ofs; | |
63 | u_long *bnp; | |
64 | u_long *sizep; | |
65 | u_long *bop; | |
66 | { | |
67 | u_long bn, size; | |
68 | ||
69 | bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec; | |
70 | size = min (pmp->pm_fatblocksec, pmp->pm_FATsecs - bn) | |
71 | * pmp->pm_BytesPerSec; | |
72 | bn += pmp->pm_fatblk; | |
73 | if (bnp) | |
74 | *bnp = bn; | |
75 | if (sizep) | |
76 | *sizep = size; | |
77 | if (bop) | |
78 | *bop = ofs % pmp->pm_fatblocksize; | |
79 | } | |
80 | ||
81 | /* | |
82 | * Map the logical cluster number of a file into | |
83 | * a physical disk sector that is filesystem relative. | |
84 | * dep - address of denode representing the file of interest | |
85 | * findcn - file relative cluster whose filesystem relative | |
86 | * cluster number and/or block number are/is to be found | |
87 | * bnp - address of where to place the file system relative | |
88 | * block number. If this pointer is null then don't return | |
89 | * this quantity. | |
90 | * cnp - address of where to place the file system relative | |
91 | * cluster number. If this pointer is null then don't return | |
92 | * this quantity. | |
93 | * NOTE: | |
94 | * Either bnp or cnp must be non-null. | |
95 | * This function has one side effect. If the requested | |
96 | * file relative cluster is beyond the end of file, then | |
97 | * the actual number of clusters in the file is returned | |
98 | * in *cnp. This is useful for determining how long a | |
99 | * directory is. If cnp is null, nothing is returned. | |
100 | */ | |
101 | int | |
102 | pcbmap(dep, findcn, bnp, cnp) | |
103 | struct denode *dep; | |
104 | u_long findcn; /* file relative cluster to get */ | |
105 | daddr_t *bnp; /* returned filesys relative blk number */ | |
106 | u_long *cnp; /* returned cluster number */ | |
107 | { | |
108 | int error; | |
109 | u_long i; | |
110 | u_long cn; | |
4c45483e | 111 | u_long prevcn = 0; |
15637ed4 RG |
112 | u_long byteoffset; |
113 | u_long bn; | |
114 | u_long bo; | |
115 | struct buf *bp = NULL; | |
116 | u_long bp_bn = -1; | |
117 | struct pcfsmount *pmp = dep->de_pmp; | |
118 | u_long bsize; | |
119 | int fat12 = FAT12(pmp); /* 12 bit fat */ | |
120 | ||
121 | fc_bmapcalls++; | |
122 | ||
123 | /* | |
124 | * If they don't give us someplace to return a value | |
125 | * then don't bother doing anything. | |
126 | */ | |
127 | if (bnp == NULL && cnp == NULL) | |
128 | return 0; | |
129 | ||
130 | cn = dep->de_StartCluster; | |
131 | /* | |
132 | * The "file" that makes up the root directory is contiguous, | |
133 | * permanently allocated, of fixed size, and is not made up | |
134 | * of clusters. If the cluster number is beyond the end of | |
135 | * the root directory, then return the number of clusters in | |
136 | * the file. | |
137 | */ | |
138 | if (cn == PCFSROOT) { | |
139 | if (dep->de_Attributes & ATTR_DIRECTORY) { | |
140 | if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) { | |
141 | if (cnp) | |
142 | *cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust; | |
143 | return E2BIG; | |
144 | } | |
145 | if (bnp) | |
146 | *bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust); | |
147 | if (cnp) | |
148 | *cnp = PCFSROOT; | |
149 | return 0; | |
150 | } | |
151 | else { /* just an empty file */ | |
152 | if (cnp) | |
153 | *cnp = 0; | |
154 | return E2BIG; | |
155 | } | |
156 | } | |
157 | ||
158 | /* | |
159 | * Rummage around in the fat cache, maybe we can avoid | |
160 | * tromping thru every fat entry for the file. | |
161 | * And, keep track of how far off the cache was from | |
162 | * where we wanted to be. | |
163 | */ | |
164 | i = 0; | |
165 | fc_lookup(dep, findcn, &i, &cn); | |
166 | if ((bn = findcn - i) >= LMMAX) | |
167 | fc_largedistance++; | |
168 | else | |
169 | fc_lmdistance[bn]++; | |
170 | ||
171 | /* | |
172 | * Handle all other files or directories the normal way. | |
173 | */ | |
174 | for (; i < findcn; i++) { | |
175 | if (PCFSEOF(cn)) | |
176 | goto hiteof; | |
177 | byteoffset = FATOFS(pmp, cn); | |
178 | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | |
179 | if (bn != bp_bn) { | |
180 | if (bp) | |
181 | brelse(bp); | |
182 | error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | |
183 | if (error) | |
184 | return error; | |
185 | bp_bn = bn; | |
186 | } | |
187 | prevcn = cn; | |
188 | cn = getushort(&bp->b_un.b_addr[bo]); | |
189 | if (fat12) { | |
190 | if (prevcn & 1) | |
191 | cn >>= 4; | |
192 | cn &= 0x0fff; | |
193 | /* | |
194 | * Force the special cluster numbers in the range | |
195 | * 0x0ff0-0x0fff to be the same as for 16 bit cluster | |
196 | * numbers to let the rest of pcfs think it is always | |
197 | * dealing with 16 bit fats. | |
198 | */ | |
199 | if ((cn & 0x0ff0) == 0x0ff0) | |
200 | cn |= 0xf000; | |
201 | } | |
202 | } | |
203 | ||
204 | if (!PCFSEOF(cn)) { | |
205 | if (bp) | |
206 | brelse(bp); | |
207 | if (bnp) | |
208 | *bnp = cntobn(pmp, cn); | |
209 | if (cnp) | |
210 | *cnp = cn; | |
211 | fc_setcache(dep, FC_LASTMAP, i, cn); | |
212 | return 0; | |
213 | } | |
214 | ||
215 | hiteof:; | |
216 | if (cnp) | |
217 | *cnp = i; | |
218 | if (bp) | |
219 | brelse(bp); | |
220 | /* update last file cluster entry in the fat cache */ | |
221 | fc_setcache(dep, FC_LASTFC, i-1, prevcn); | |
222 | return E2BIG; | |
223 | } | |
224 | ||
225 | /* | |
226 | * Find the closest entry in the fat cache to the | |
227 | * cluster we are looking for. | |
228 | */ | |
4c45483e | 229 | static void |
15637ed4 RG |
230 | fc_lookup(dep, findcn, frcnp, fsrcnp) |
231 | struct denode *dep; | |
232 | u_long findcn; | |
233 | u_long *frcnp; | |
234 | u_long *fsrcnp; | |
235 | { | |
236 | int i; | |
237 | u_long cn; | |
238 | struct fatcache *closest = 0; | |
239 | ||
240 | for (i = 0; i < FC_SIZE; i++) { | |
241 | cn = dep->de_fc[i].fc_frcn; | |
242 | if (cn != FCE_EMPTY && cn <= findcn) { | |
243 | if (closest == 0 || cn > closest->fc_frcn) | |
244 | closest = &dep->de_fc[i]; | |
245 | } | |
246 | } | |
247 | if (closest) { | |
248 | *frcnp = closest->fc_frcn; | |
249 | *fsrcnp = closest->fc_fsrcn; | |
250 | } | |
251 | } | |
252 | ||
253 | /* | |
254 | * Purge the fat cache in denode dep of all entries | |
255 | * relating to file relative cluster frcn and beyond. | |
256 | */ | |
4c45483e | 257 | void |
15637ed4 RG |
258 | fc_purge(dep, frcn) |
259 | struct denode *dep; | |
260 | u_int frcn; | |
261 | { | |
262 | int i; | |
263 | struct fatcache *fcp; | |
264 | ||
265 | fcp = dep->de_fc; | |
266 | for (i = 0; i < FC_SIZE; i++, fcp++) { | |
267 | if (fcp->fc_frcn != FCE_EMPTY && fcp->fc_frcn >= frcn) | |
268 | fcp->fc_frcn = FCE_EMPTY; | |
269 | } | |
270 | } | |
271 | ||
272 | /* | |
273 | * Once the first fat is updated the other copies of | |
274 | * the fat must also be updated. This function does | |
275 | * this. | |
276 | * pmp - pcfsmount structure for filesystem to update | |
277 | * bp - addr of modified fat block | |
278 | * fatbn - block number relative to begin of filesystem | |
279 | * of the modified fat block. | |
280 | */ | |
281 | void | |
282 | updateotherfats(pmp, bp, fatbn) | |
283 | struct pcfsmount *pmp; | |
284 | struct buf *bp; | |
285 | u_long fatbn; | |
286 | { | |
287 | int i; | |
288 | struct buf *bpn; | |
289 | ||
290 | #if defined(PCFSDEBUG) | |
291 | printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n", | |
292 | pmp, bp, fatbn); | |
293 | #endif /* defined(PCFSDEBUG) */ | |
294 | ||
295 | /* | |
296 | * Now copy the block(s) of the modified fat to the other | |
297 | * copies of the fat and write them out. This is faster | |
298 | * than reading in the other fats and then writing them | |
299 | * back out. This could tie up the fat for quite a while. | |
300 | * Preventing others from accessing it. To prevent us | |
301 | * from going after the fat quite so much we use delayed | |
302 | * writes, unless they specfied "synchronous" when the | |
303 | * filesystem was mounted. If synch is asked for then | |
304 | * use bwrite()'s and really slow things down. | |
305 | */ | |
306 | for (i = 1; i < pmp->pm_FATs; i++) { | |
307 | fatbn += pmp->pm_FATsecs; | |
308 | /* getblk() never fails */ | |
309 | bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount); | |
310 | bcopy(bp->b_un.b_addr, bpn->b_un.b_addr, | |
311 | bp->b_bcount); | |
312 | if (pmp->pm_waitonfat) | |
313 | bwrite(bpn); | |
314 | else | |
315 | bdwrite(bpn); | |
316 | } | |
317 | } | |
318 | ||
319 | /* | |
320 | * Updating entries in 12 bit fats is a pain in the butt. | |
321 | * | |
322 | * The following picture shows where nibbles go when | |
323 | * moving from a 12 bit cluster number into the appropriate | |
324 | * bytes in the FAT. | |
325 | * | |
326 | * byte m byte m+1 byte m+2 | |
327 | * +----+----+ +----+----+ +----+----+ | |
328 | * | 0 1 | | 2 3 | | 4 5 | FAT bytes | |
329 | * +----+----+ +----+----+ +----+----+ | |
330 | * | |
331 | * +----+----+----+ +----+----+----+ | |
332 | * | 3 0 1 | | 4 5 2 | | |
333 | * +----+----+----+ +----+----+----+ | |
334 | * cluster n cluster n+1 | |
335 | * | |
336 | * Where n is even. | |
337 | * m = n + (n >> 2) | |
338 | * | |
339 | * (Function no longer used) | |
340 | */ | |
341 | ||
342 | ||
343 | extern inline void | |
344 | usemap_alloc (struct pcfsmount *pmp, u_long cn) | |
345 | { | |
346 | pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8); | |
347 | pmp->pm_freeclustercount--; | |
348 | /* This assumes that the lowest available cluster was allocated */ | |
349 | pmp->pm_lookhere = cn + 1; | |
350 | } | |
351 | ||
352 | extern inline void | |
353 | usemap_free (struct pcfsmount *pmp, u_long cn) | |
354 | { | |
355 | pmp->pm_freeclustercount++; | |
356 | pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8)); | |
357 | if (pmp->pm_lookhere > cn) | |
358 | pmp->pm_lookhere = cn; | |
359 | } | |
360 | ||
361 | int | |
362 | clusterfree(pmp, cluster, oldcnp) | |
363 | struct pcfsmount *pmp; | |
364 | u_long cluster; | |
365 | u_long *oldcnp; | |
366 | { | |
367 | int error; | |
368 | u_long oldcn; | |
369 | ||
370 | error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, PCFSFREE); | |
371 | if (error == 0) { | |
372 | /* | |
373 | * If the cluster was successfully marked free, then update the count of | |
374 | * free clusters, and turn off the "allocated" bit in the | |
375 | * "in use" cluster bit map. | |
376 | */ | |
377 | usemap_free(pmp, cluster); | |
378 | if (oldcnp) | |
379 | *oldcnp = oldcn; | |
380 | } | |
381 | return error; | |
382 | } | |
383 | ||
384 | /* | |
385 | * Get or Set or 'Get and Set' the cluster'th entry in the | |
386 | * fat. | |
387 | * function - whether to get or set a fat entry | |
388 | * pmp - address of the pcfsmount structure for the | |
389 | * filesystem whose fat is to be manipulated. | |
390 | * cluster - which cluster is of interest | |
391 | * oldcontents - address of a word that is to receive | |
392 | * the contents of the cluster'th entry if this is | |
393 | * a get function | |
394 | * newcontents - the new value to be written into the | |
395 | * cluster'th element of the fat if this is a set | |
396 | * function. | |
397 | * | |
398 | * This function can also be used to free a cluster | |
399 | * by setting the fat entry for a cluster to 0. | |
400 | * | |
401 | * All copies of the fat are updated if this is a set | |
402 | * function. | |
403 | * NOTE: | |
404 | * If fatentry() marks a cluster as free it does not | |
405 | * update the inusemap in the pcfsmount structure. | |
406 | * This is left to the caller. | |
407 | */ | |
408 | int | |
409 | fatentry(function, pmp, cn, oldcontents, newcontents) | |
410 | int function; | |
411 | struct pcfsmount *pmp; | |
412 | u_long cn; | |
413 | u_long *oldcontents; | |
414 | u_long newcontents; | |
415 | { | |
416 | int error; | |
417 | u_long readcn; | |
418 | u_long bn, bo, bsize, byteoffset; | |
419 | struct buf *bp; | |
420 | /*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n", | |
421 | function, pmp, cluster, oldcontents, newcontents);*/ | |
422 | ||
423 | #ifdef DIAGNOSTIC | |
424 | /* | |
425 | * Be sure they asked us to do something. | |
426 | */ | |
427 | if ((function & (FAT_SET | FAT_GET)) == 0) { | |
428 | printf("fatentry(): function code doesn't specify get or set\n"); | |
429 | return EINVAL; | |
430 | } | |
431 | ||
432 | /* | |
433 | * If they asked us to return a cluster number | |
434 | * but didn't tell us where to put it, give them | |
435 | * an error. | |
436 | */ | |
437 | if ((function & FAT_GET) && oldcontents == NULL) { | |
438 | printf("fatentry(): get function with no place to put result\n"); | |
439 | return EINVAL; | |
440 | } | |
441 | #endif | |
442 | ||
443 | /* | |
444 | * Be sure the requested cluster is in the filesystem. | |
445 | */ | |
446 | if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) | |
447 | return EINVAL; | |
448 | ||
449 | byteoffset = FATOFS(pmp, cn); | |
450 | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | |
451 | error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | |
452 | if (function & FAT_GET) { | |
453 | readcn = getushort(&bp->b_un.b_addr[bo]); | |
454 | if (FAT12(pmp)) { | |
455 | if (cn & 1) | |
456 | readcn >>= 4; | |
457 | readcn &= 0x0fff; | |
458 | /* map certain 12 bit fat entries to 16 bit */ | |
459 | if ((readcn & 0x0ff0) == 0x0ff0) | |
460 | readcn |= 0xf000; | |
461 | } | |
462 | *oldcontents = readcn; | |
463 | } | |
464 | if (function & FAT_SET) { | |
465 | if (FAT12(pmp)) { | |
466 | readcn = getushort(&bp->b_un.b_addr[bo]); | |
467 | if (cn & 1) { | |
468 | readcn &= 0x000f; | |
469 | readcn |= (newcontents << 4); | |
470 | } | |
471 | else { | |
472 | readcn &= 0xf000; | |
473 | readcn |= (newcontents << 0); | |
474 | } | |
475 | putushort(&bp->b_un.b_addr[bo], readcn); | |
476 | } | |
477 | else | |
478 | putushort(&bp->b_un.b_addr[bo], newcontents); | |
479 | updateotherfats(pmp, bp, bn); | |
480 | /* | |
481 | * Write out the first fat last. | |
482 | */ | |
483 | if (pmp->pm_waitonfat) | |
484 | bwrite(bp); | |
485 | else | |
486 | bdwrite(bp); | |
487 | bp = NULL; | |
488 | pmp->pm_fmod++; | |
489 | } | |
490 | if (bp) | |
491 | brelse(bp); | |
492 | return 0; | |
493 | } | |
494 | ||
495 | /* | |
496 | * Allocate a free cluster. | |
497 | * pmp - | |
498 | * retcluster - put the allocated cluster's number here. | |
499 | * fillwith - put this value into the fat entry for the | |
500 | * allocated cluster. | |
501 | */ | |
502 | int | |
503 | clusteralloc(pmp, retcluster, fillwith) | |
504 | struct pcfsmount *pmp; | |
505 | u_long *retcluster; | |
506 | u_long fillwith; | |
507 | { | |
508 | int error; | |
509 | u_long cn; | |
510 | u_long idx, max_idx, bit, map; | |
511 | ||
512 | max_idx = pmp->pm_maxcluster / 8; | |
513 | for (idx = pmp->pm_lookhere / 8; idx <= max_idx; idx++) { | |
514 | map = pmp->pm_inusemap[idx]; | |
515 | if (map != 0xff) { | |
516 | for (bit = 0; bit < 8; bit++) { | |
517 | if ((map & (1 << bit)) == 0) { | |
518 | cn = idx * 8 + bit; | |
519 | goto found_one; | |
520 | } | |
521 | } | |
522 | } | |
523 | } | |
524 | return ENOSPC; | |
525 | ||
526 | found_one:; | |
527 | error = fatentry(FAT_SET, pmp, cn, 0, fillwith); | |
528 | if (error == 0) { | |
529 | usemap_alloc(pmp, cn); | |
530 | *retcluster = cn; | |
531 | } | |
532 | #if defined(PCFSDEBUG) | |
533 | printf("clusteralloc(): allocated cluster %d\n", cn); | |
534 | #endif /* defined(PCFSDEBUG) */ | |
535 | return error; | |
536 | } | |
537 | ||
538 | /* | |
539 | * Free a chain of clusters. | |
540 | * pmp - address of the pcfs mount structure for the | |
541 | * filesystem containing the cluster chain to be freed. | |
542 | * startcluster - number of the 1st cluster in the chain | |
543 | * of clusters to be freed. | |
544 | */ | |
545 | int | |
546 | freeclusterchain(pmp, startcluster) | |
547 | struct pcfsmount *pmp; | |
548 | u_long startcluster; | |
549 | { | |
550 | u_long nextcluster; | |
551 | int error = 0; | |
552 | ||
553 | while (startcluster >= CLUST_FIRST && startcluster <= pmp->pm_maxcluster) { | |
554 | error = clusterfree(pmp, startcluster, &nextcluster); | |
555 | if (error) { | |
556 | printf("freeclusterchain(): free failed, cluster %d\n", | |
557 | startcluster); | |
558 | break; | |
559 | } | |
560 | startcluster = nextcluster; | |
561 | } | |
562 | return error; | |
563 | } | |
564 | ||
565 | /* | |
566 | * Read in fat blocks looking for free clusters. | |
567 | * For every free cluster found turn off its | |
568 | * corresponding bit in the pm_inusemap. | |
569 | */ | |
570 | int | |
571 | fillinusemap(pmp) | |
572 | struct pcfsmount *pmp; | |
573 | { | |
574 | struct buf *bp = NULL; | |
575 | u_long cn, readcn; | |
576 | int error; | |
577 | int fat12 = FAT12(pmp); | |
578 | u_long bn, bo, bsize, byteoffset; | |
579 | ||
580 | /* | |
581 | * Mark all clusters in use, we mark the free ones in the | |
582 | * fat scan loop further down. | |
583 | */ | |
584 | for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++) | |
585 | pmp->pm_inusemap[cn] = 0xff; | |
586 | ||
587 | /* | |
588 | * Figure how many free clusters are in the filesystem | |
589 | * by ripping thougth the fat counting the number of | |
590 | * entries whose content is zero. These represent free | |
591 | * clusters. | |
592 | */ | |
593 | pmp->pm_freeclustercount = 0; | |
594 | pmp->pm_lookhere = pmp->pm_maxcluster + 1; | |
595 | for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) { | |
596 | byteoffset = FATOFS(pmp, cn); | |
597 | bo = byteoffset % pmp->pm_fatblocksize; | |
598 | if (!bo || !bp) { | |
599 | /* Read new FAT block */ | |
600 | if (bp) | |
601 | brelse(bp); | |
602 | fatblock(pmp, byteoffset, &bn, &bsize, NULL); | |
603 | error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | |
604 | if (error) | |
605 | return error; | |
606 | } | |
607 | readcn = getushort(&bp->b_un.b_addr[bo]); | |
608 | if (fat12) { | |
609 | if (cn & 1) | |
610 | readcn >>= 4; | |
611 | readcn &= 0x0fff; | |
612 | } | |
613 | ||
614 | if (readcn == 0) | |
615 | usemap_free(pmp, cn); | |
616 | } | |
617 | brelse(bp); | |
618 | return 0; | |
619 | } | |
620 | ||
621 | /* | |
622 | * Allocate a new cluster and chain it onto the end of the | |
623 | * file. | |
624 | * dep - the file to extend | |
625 | * bpp - where to return the address of the buf header for the | |
626 | * new file block | |
627 | * ncp - where to put cluster number of the newly allocated file block | |
628 | * If this pointer is 0, do not return the cluster number. | |
629 | * | |
630 | * NOTE: | |
631 | * This function is not responsible for turning on the DEUPD | |
632 | * bit if the de_flag field of the denode and it does not | |
633 | * change the de_FileSize field. This is left for the caller | |
634 | * to do. | |
635 | */ | |
636 | int | |
637 | extendfile(dep, bpp, ncp) | |
638 | struct denode *dep; | |
639 | struct buf **bpp; | |
640 | u_int *ncp; | |
641 | { | |
642 | int error = 0; | |
643 | u_long frcn; | |
644 | u_long cn; | |
645 | struct pcfsmount *pmp = dep->de_pmp; | |
646 | ||
647 | /* | |
648 | * Don't try to extend the root directory | |
649 | */ | |
650 | if (DETOV(dep)->v_flag & VROOT) { | |
651 | printf("extendfile(): attempt to extend root directory\n"); | |
652 | return ENOSPC; | |
653 | } | |
654 | ||
655 | /* | |
656 | * If the "file's last cluster" cache entry is empty, | |
657 | * and the file is not empty, | |
658 | * then fill the cache entry by calling pcbmap(). | |
659 | */ | |
660 | fc_fileextends++; | |
661 | if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY && | |
662 | dep->de_StartCluster != 0) { | |
663 | fc_lfcempty++; | |
664 | error = pcbmap(dep, 0xffff, 0, &cn); | |
665 | /* we expect it to return E2BIG */ | |
666 | if (error != E2BIG) | |
667 | return error; | |
668 | error = 0; | |
669 | } | |
670 | ||
671 | /* | |
672 | * Allocate another cluster and chain onto the end of the file. | |
673 | * If the file is empty we make de_StartCluster point to the | |
674 | * new block. Note that de_StartCluster being 0 is sufficient | |
675 | * to be sure the file is empty since we exclude attempts to | |
676 | * extend the root directory above, and the root dir is the | |
677 | * only file with a startcluster of 0 that has blocks allocated | |
678 | * (sort of). | |
679 | */ | |
680 | if (error = clusteralloc(pmp, &cn, CLUST_EOFE)) | |
681 | return error; | |
682 | if (dep->de_StartCluster == 0) { | |
683 | dep->de_StartCluster = cn; | |
684 | frcn = 0; | |
685 | } else { | |
686 | error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn, | |
687 | 0, cn); | |
688 | if (error) { | |
689 | clusterfree(pmp, cn, NULL); | |
690 | return error; | |
691 | } | |
692 | ||
693 | frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1; | |
694 | } | |
695 | ||
696 | /* | |
697 | * Update the "last cluster of the file" entry in the denode's | |
698 | * fat cache. | |
699 | */ | |
700 | fc_setcache(dep, FC_LASTFC, frcn, cn); | |
701 | ||
702 | /* | |
703 | * Get the buf header for the new block of the file. | |
704 | */ | |
705 | if (dep->de_Attributes & ATTR_DIRECTORY) { | |
706 | *bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn), | |
707 | pmp->pm_bpcluster); | |
708 | } else { | |
709 | *bpp = getblk(DETOV(dep), frcn, | |
710 | pmp->pm_bpcluster); | |
711 | } | |
712 | clrbuf(*bpp); | |
713 | ||
714 | /* | |
715 | * Give them the filesystem relative cluster number | |
716 | * if they want it. | |
717 | */ | |
718 | if (ncp) | |
719 | *ncp = cn; | |
720 | return 0; | |
721 | } |