Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/makefs/msdos/msdosfs_fat.c
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <strings.h> | #include <strings.h> | ||||
#include "ffs/buf.h" | |||||
#include <fs/msdosfs/bpb.h> | #include <fs/msdosfs/bpb.h> | ||||
#include "msdos/direntry.h" | #include "msdos/direntry.h" | ||||
#include <fs/msdosfs/denode.h> | #include <fs/msdosfs/denode.h> | ||||
#include <fs/msdosfs/fat.h> | #include <fs/msdosfs/fat.h> | ||||
#include <fs/msdosfs/msdosfsmount.h> | #include <fs/msdosfs/msdosfsmount.h> | ||||
#undef clrbuf | |||||
#include "ffs/buf.h" | |||||
#include "makefs.h" | #include "makefs.h" | ||||
#include "msdos.h" | #include "msdos.h" | ||||
#define FULL_RUN ((u_int)0xffffffff) | #define FULL_RUN ((u_int)0xffffffff) | ||||
#define SYNCHRONOUS_WRITES(pmp) 1 | #define SYNCHRONOUS_WRITES(pmp) 1 | ||||
static int chainalloc(struct msdosfsmount *pmp, u_long start, | static int chainalloc(struct msdosfsmount *pmp, u_long start, | ||||
u_long count, u_long fillwith, u_long *retcluster, | u_long count, u_long fillwith, u_long *retcluster, | ||||
u_long *got); | u_long *got); | ||||
static int chainlength(struct msdosfsmount *pmp, u_long start, | static int chainlength(struct msdosfsmount *pmp, u_long start, | ||||
u_long count); | u_long count); | ||||
static void fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, | static void fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, | ||||
u_long *sizep, u_long *bop); | u_long *sizep, u_long *bop); | ||||
static int fatchain(struct msdosfsmount *pmp, u_long start, u_long count, | static int fatchain(struct msdosfsmount *pmp, u_long start, u_long count, | ||||
u_long fillwith); | u_long fillwith); | ||||
static void fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, | static void fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, | ||||
u_long *fsrcnp); | u_long *fsrcnp); | ||||
static void updatefats(struct msdosfsmount *pmp, struct buf *bp, | static void updatefats(struct msdosfsmount *pmp, struct m_buf *bp, | ||||
u_long fatbn); | u_long fatbn); | ||||
static __inline void | static __inline void | ||||
usemap_alloc(struct msdosfsmount *pmp, u_long cn); | usemap_alloc(struct msdosfsmount *pmp, u_long cn); | ||||
static __inline void | static __inline void | ||||
usemap_free(struct msdosfsmount *pmp, u_long cn); | usemap_free(struct msdosfsmount *pmp, u_long cn); | ||||
static int clusteralloc1(struct msdosfsmount *pmp, u_long start, | static int clusteralloc1(struct msdosfsmount *pmp, u_long start, | ||||
u_long count, u_long fillwith, u_long *retcluster, | u_long count, u_long fillwith, u_long *retcluster, | ||||
u_long *got); | u_long *got); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int error; | int error; | ||||
u_long i; | u_long i; | ||||
u_long cn; | u_long cn; | ||||
u_long prevcn = 0; /* XXX: prevcn could be used unititialized */ | u_long prevcn = 0; /* XXX: prevcn could be used unititialized */ | ||||
u_long byteoffset; | u_long byteoffset; | ||||
u_long bn; | u_long bn; | ||||
u_long bo; | u_long bo; | ||||
struct buf *bp = NULL; | struct m_buf *bp = NULL; | ||||
u_long bp_bn = -1; | u_long bp_bn = -1; | ||||
struct msdosfsmount *pmp = dep->de_pmp; | struct msdosfsmount *pmp = dep->de_pmp; | ||||
u_long bsize; | u_long bsize; | ||||
assert(bnp != NULL || cnp != NULL || sp != NULL); | assert(bnp != NULL || cnp != NULL || sp != NULL); | ||||
cn = dep->de_StartCluster; | cn = dep->de_StartCluster; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | for (; i < findcn; i++) { | ||||
*/ | */ | ||||
if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD) | if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD) | ||||
goto hiteof; | goto hiteof; | ||||
byteoffset = FATOFS(pmp, cn); | byteoffset = FATOFS(pmp, cn); | ||||
fatblock(pmp, byteoffset, &bn, &bsize, &bo); | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
if (bn != bp_bn) { | if (bn != bp_bn) { | ||||
if (bp) | if (bp) | ||||
brelse(bp); | brelse(bp); | ||||
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | error = bread((void *)pmp->pm_devvp, bn, bsize, | ||||
NOCRED, &bp); | |||||
if (error) { | if (error) { | ||||
brelse(bp); | brelse(bp); | ||||
return (error); | return (error); | ||||
} | } | ||||
bp_bn = bn; | bp_bn = bn; | ||||
} | } | ||||
prevcn = cn; | prevcn = cn; | ||||
if (bo >= bsize) { | if (bo >= bsize) { | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | |||||
* If mirroring the FAT, update all copies, with the first copy as last. | * If mirroring the FAT, update all copies, with the first copy as last. | ||||
* Else update only the current FAT (ignoring the others). | * Else update only the current FAT (ignoring the others). | ||||
* | * | ||||
* pmp - msdosfsmount structure for filesystem to update | * pmp - msdosfsmount structure for filesystem to update | ||||
* bp - addr of modified FAT block | * bp - addr of modified FAT block | ||||
* fatbn - block number relative to begin of filesystem of the modified FAT block. | * fatbn - block number relative to begin of filesystem of the modified FAT block. | ||||
*/ | */ | ||||
static void | static void | ||||
updatefats(struct msdosfsmount *pmp, struct buf *bp, u_long fatbn) | updatefats(struct msdosfsmount *pmp, struct m_buf *bp, u_long fatbn) | ||||
{ | { | ||||
struct buf *bpn; | struct m_buf *bpn; | ||||
int cleanfat, i; | int cleanfat, i; | ||||
#ifdef MSDOSFS_DEBUG | #ifdef MSDOSFS_DEBUG | ||||
printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp, bp, fatbn); | printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp, bp, fatbn); | ||||
#endif | #endif | ||||
if (pmp->pm_flags & MSDOSFS_FATMIRROR) { | if (pmp->pm_flags & MSDOSFS_FATMIRROR) { | ||||
/* | /* | ||||
Show All 10 Lines | if (fatbn != pmp->pm_fatblk || FAT12(pmp)) | ||||
cleanfat = 0; | cleanfat = 0; | ||||
else if (FAT16(pmp)) | else if (FAT16(pmp)) | ||||
cleanfat = 16; | cleanfat = 16; | ||||
else | else | ||||
cleanfat = 32; | cleanfat = 32; | ||||
for (i = 1; i < pmp->pm_FATs; i++) { | for (i = 1; i < pmp->pm_FATs; i++) { | ||||
fatbn += pmp->pm_FATsecs; | fatbn += pmp->pm_FATsecs; | ||||
/* getblk() never fails */ | /* getblk() never fails */ | ||||
bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, | bpn = getblk((void *)pmp->pm_devvp, fatbn, | ||||
0, 0, 0); | bp->b_bcount, 0, 0, 0); | ||||
memcpy(bpn->b_data, bp->b_data, bp->b_bcount); | memcpy(bpn->b_data, bp->b_data, bp->b_bcount); | ||||
/* Force the clean bit on in the other copies. */ | /* Force the clean bit on in the other copies. */ | ||||
if (cleanfat == 16) | if (cleanfat == 16) | ||||
((uint8_t *)bpn->b_data)[3] |= 0x80; | ((uint8_t *)bpn->b_data)[3] |= 0x80; | ||||
else if (cleanfat == 32) | else if (cleanfat == 32) | ||||
((uint8_t *)bpn->b_data)[7] |= 0x08; | ((uint8_t *)bpn->b_data)[7] |= 0x08; | ||||
if (SYNCHRONOUS_WRITES(pmp)) | if (SYNCHRONOUS_WRITES(pmp)) | ||||
bwrite(bpn); | bwrite(bpn); | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
int | int | ||||
fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents, | fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents, | ||||
u_long newcontents) | u_long newcontents) | ||||
{ | { | ||||
int error; | int error; | ||||
u_long readcn; | u_long readcn; | ||||
u_long bn, bo, bsize, byteoffset; | u_long bn, bo, bsize, byteoffset; | ||||
struct buf *bp; | struct m_buf *bp; | ||||
#ifdef MSDOSFS_DEBUG | #ifdef MSDOSFS_DEBUG | ||||
printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n", | printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n", | ||||
function, pmp, cn, oldcontents, newcontents); | function, pmp, cn, oldcontents, newcontents); | ||||
#endif | #endif | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
/* | /* | ||||
Show All 21 Lines | #endif | ||||
/* | /* | ||||
* Be sure the requested cluster is in the filesystem. | * Be sure the requested cluster is in the filesystem. | ||||
*/ | */ | ||||
if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) | if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) | ||||
return (EINVAL); | return (EINVAL); | ||||
byteoffset = FATOFS(pmp, cn); | byteoffset = FATOFS(pmp, cn); | ||||
fatblock(pmp, byteoffset, &bn, &bsize, &bo); | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | error = bread((void *)pmp->pm_devvp, bn, bsize, NOCRED, &bp); | ||||
if (error) { | if (error) { | ||||
brelse(bp); | brelse(bp); | ||||
return (error); | return (error); | ||||
} | } | ||||
if (function & FAT_GET) { | if (function & FAT_GET) { | ||||
if (FAT32(pmp)) | if (FAT32(pmp)) | ||||
readcn = getulong(bp->b_data + bo); | readcn = getulong(bp->b_data + bo); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
* count - number of clusters in chain | * count - number of clusters in chain | ||||
* fillwith - what to write into FAT entry of last cluster | * fillwith - what to write into FAT entry of last cluster | ||||
*/ | */ | ||||
static int | static int | ||||
fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith) | fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith) | ||||
{ | { | ||||
int error; | int error; | ||||
u_long bn, bo, bsize, byteoffset, readcn, newc; | u_long bn, bo, bsize, byteoffset, readcn, newc; | ||||
struct buf *bp; | struct m_buf *bp; | ||||
#ifdef MSDOSFS_DEBUG | #ifdef MSDOSFS_DEBUG | ||||
printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n", | printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n", | ||||
pmp, start, count, fillwith); | pmp, start, count, fillwith); | ||||
#endif | #endif | ||||
/* | /* | ||||
* Be sure the clusters are in the filesystem. | * Be sure the clusters are in the filesystem. | ||||
*/ | */ | ||||
if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster) | if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster) | ||||
return (EINVAL); | return (EINVAL); | ||||
while (count > 0) { | while (count > 0) { | ||||
byteoffset = FATOFS(pmp, start); | byteoffset = FATOFS(pmp, start); | ||||
fatblock(pmp, byteoffset, &bn, &bsize, &bo); | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | error = bread((void *)pmp->pm_devvp, bn, bsize, NOCRED, &bp); | ||||
if (error) { | if (error) { | ||||
brelse(bp); | brelse(bp); | ||||
return (error); | return (error); | ||||
} | } | ||||
while (count > 0) { | while (count > 0) { | ||||
start++; | start++; | ||||
newc = --count > 0 ? start : fillwith; | newc = --count > 0 ? start : fillwith; | ||||
switch (pmp->pm_fatmask) { | switch (pmp->pm_fatmask) { | ||||
▲ Show 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | |||||
* containing the cluster chain to be freed. | * containing the cluster chain to be freed. | ||||
* startcluster - number of the 1st cluster in the chain of clusters to be | * startcluster - number of the 1st cluster in the chain of clusters to be | ||||
* freed. | * freed. | ||||
*/ | */ | ||||
int | int | ||||
freeclusterchain(struct msdosfsmount *pmp, u_long cluster) | freeclusterchain(struct msdosfsmount *pmp, u_long cluster) | ||||
{ | { | ||||
int error; | int error; | ||||
struct buf *bp = NULL; | struct m_buf *bp = NULL; | ||||
u_long bn, bo, bsize, byteoffset; | u_long bn, bo, bsize, byteoffset; | ||||
u_long readcn, lbn = -1; | u_long readcn, lbn = -1; | ||||
while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) { | while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) { | ||||
byteoffset = FATOFS(pmp, cluster); | byteoffset = FATOFS(pmp, cluster); | ||||
fatblock(pmp, byteoffset, &bn, &bsize, &bo); | fatblock(pmp, byteoffset, &bn, &bsize, &bo); | ||||
if (lbn != bn) { | if (lbn != bn) { | ||||
if (bp) | if (bp) | ||||
updatefats(pmp, bp, lbn); | updatefats(pmp, bp, lbn); | ||||
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | error = bread((void *)pmp->pm_devvp, bn, bsize, | ||||
NOCRED, &bp); | |||||
if (error) { | if (error) { | ||||
brelse(bp); | brelse(bp); | ||||
return (error); | return (error); | ||||
} | } | ||||
lbn = bn; | lbn = bn; | ||||
} | } | ||||
usemap_free(pmp, cluster); | usemap_free(pmp, cluster); | ||||
switch (pmp->pm_fatmask) { | switch (pmp->pm_fatmask) { | ||||
Show All 31 Lines | |||||
/* | /* | ||||
* Read in FAT blocks looking for free clusters. For every free cluster | * Read in FAT blocks looking for free clusters. For every free cluster | ||||
* found turn off its corresponding bit in the pm_inusemap. | * found turn off its corresponding bit in the pm_inusemap. | ||||
*/ | */ | ||||
int | int | ||||
fillinusemap(struct msdosfsmount *pmp) | fillinusemap(struct msdosfsmount *pmp) | ||||
{ | { | ||||
struct buf *bp; | struct m_buf *bp; | ||||
u_long bn, bo, bsize, byteoffset, cn, readcn; | u_long bn, bo, bsize, byteoffset, cn, readcn; | ||||
int error; | int error; | ||||
bp = NULL; | bp = NULL; | ||||
/* | /* | ||||
* Mark all clusters in use, we mark the free ones in the FAT scan | * Mark all clusters in use, we mark the free ones in the FAT scan | ||||
* loop further down. | * loop further down. | ||||
Show All 10 Lines | fillinusemap(struct msdosfsmount *pmp) | ||||
for (cn = 0; cn <= pmp->pm_maxcluster; cn++) { | for (cn = 0; cn <= pmp->pm_maxcluster; cn++) { | ||||
byteoffset = FATOFS(pmp, cn); | byteoffset = FATOFS(pmp, cn); | ||||
bo = byteoffset % pmp->pm_fatblocksize; | bo = byteoffset % pmp->pm_fatblocksize; | ||||
if (bo == 0) { | if (bo == 0) { | ||||
/* Read new FAT block */ | /* Read new FAT block */ | ||||
if (bp != NULL) | if (bp != NULL) | ||||
brelse(bp); | brelse(bp); | ||||
fatblock(pmp, byteoffset, &bn, &bsize, NULL); | fatblock(pmp, byteoffset, &bn, &bsize, NULL); | ||||
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); | error = bread((void *)pmp->pm_devvp, bn, bsize, | ||||
NOCRED, &bp); | |||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
} | } | ||||
if (FAT32(pmp)) | if (FAT32(pmp)) | ||||
readcn = getulong(bp->b_data + bo); | readcn = getulong(bp->b_data + bo); | ||||
else | else | ||||
readcn = getushort(bp->b_data + bo); | readcn = getushort(bp->b_data + bo); | ||||
if (FAT12(pmp) && (cn & 1)) | if (FAT12(pmp) && (cn & 1)) | ||||
Show All 36 Lines | |||||
* If this pointer is 0, do not return the cluster number. | * If this pointer is 0, do not return the cluster number. | ||||
* flags - see fat.h | * flags - see fat.h | ||||
* | * | ||||
* NOTE: This function is not responsible for turning on the DE_UPDATE bit of | * NOTE: This function is not responsible for turning on the DE_UPDATE bit of | ||||
* the de_flag field of the denode and it does not change the de_FileSize | * the de_flag field of the denode and it does not change the de_FileSize | ||||
* field. This is left for the caller to do. | * field. This is left for the caller to do. | ||||
*/ | */ | ||||
int | int | ||||
extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, | m_extendfile(struct denode *dep, u_long count, struct m_buf **bpp, u_long *ncp, | ||||
int flags) | int flags) | ||||
{ | { | ||||
int error; | int error; | ||||
u_long frcn; | u_long frcn; | ||||
u_long cn, got; | u_long cn, got; | ||||
struct msdosfsmount *pmp = dep->de_pmp; | struct msdosfsmount *pmp = dep->de_pmp; | ||||
struct buf *bp; | struct m_buf *bp; | ||||
/* | /* | ||||
* Don't try to extend the root directory | * Don't try to extend the root directory | ||||
*/ | */ | ||||
if (dep->de_StartCluster == MSDOSFSROOT | if (dep->de_StartCluster == MSDOSFSROOT | ||||
&& (dep->de_Attributes & ATTR_DIRECTORY)) { | && (dep->de_Attributes & ATTR_DIRECTORY)) { | ||||
#ifdef MSDOSFS_DEBUG | #ifdef MSDOSFS_DEBUG | ||||
printf("extendfile(): attempt to extend root directory\n"); | printf("extendfile(): attempt to extend root directory\n"); | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | while (count > 0) { | ||||
* Update the "last cluster of the file" entry in the | * Update the "last cluster of the file" entry in the | ||||
* denode's FAT cache. | * denode's FAT cache. | ||||
*/ | */ | ||||
fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1); | fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1); | ||||
if ((flags & DE_CLEAR) && | if ((flags & DE_CLEAR) && | ||||
(dep->de_Attributes & ATTR_DIRECTORY)) { | (dep->de_Attributes & ATTR_DIRECTORY)) { | ||||
while (got-- > 0) { | while (got-- > 0) { | ||||
bp = getblk(pmp->pm_devvp, | bp = getblk((void *)pmp->pm_devvp, | ||||
cntobn(pmp, cn++), | cntobn(pmp, cn++), | ||||
pmp->pm_bpcluster, 0, 0, 0); | pmp->pm_bpcluster, 0, 0, 0); | ||||
clrbuf(bp); | clrbuf(bp); | ||||
if (bpp) { | if (bpp) { | ||||
*bpp = bp; | *bpp = bp; | ||||
bpp = NULL; | bpp = NULL; | ||||
} else { | } else { | ||||
bdwrite(bp); | bdwrite(bp); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } |