/* * Read in the disk block containing the directory entry (dirclu, dirofs) * and return the address of the buf header, and the address of the * directory entry within the block. */ int readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct buf **bpp, struct direntry **epp) { int error; daddr_t bn; int blsize; blsize = pmp->pm_bpcluster; if (dirclust == MSDOSFSROOT && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; bn = detobn(pmp, dirclust, diroffset); if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 0, bpp)) != 0) { *bpp = NULL; return (error); } if (epp) *epp = bptoep(pmp, *bpp, diroffset); return (0); }
/* * Remove a directory entry. At this point the file represented by the * directory entry to be removed is still full length until noone has it * open. When the file no longer being used msdosfs_inactive() is called * and will truncate the file to 0 length. When the vnode containing the * denode is needed for some other purpose by VFS it will call * msdosfs_reclaim() which will remove the denode from the denode cache. */ int removede(struct denode *pdep, struct denode *dep) /* pdep: directory where the entry is removed */ /* dep: file to be removed */ { int error; struct direntry *ep; struct buf *bp; daddr_t bn; int blsize; struct msdosfsmount *pmp = pdep->de_pmp; u_long offset = pdep->de_fndoffset; #ifdef _KERNEL int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; #else #define async 0 #endif #ifdef MSDOSFS_DEBUG printf("removede(): filename %s, dep %p, offset %08lx\n", dep->de_Name, dep, offset); #endif dep->de_refcnt--; offset += sizeof(struct direntry); do { offset -= sizeof(struct direntry); error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); if (error) return error; error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, B_MODIFY, &bp); if (error) { return error; } ep = bptoep(pmp, bp, offset); /* * Check whether, if we came here the second time, i.e. * when underflowing into the previous block, the last * entry in this block is a longfilename entry, too. */ if (ep->deAttributes != ATTR_WIN95 && offset != pdep->de_fndoffset) { brelse(bp, 0); break; } offset += sizeof(struct direntry); while (1) { /* * We are a bit agressive here in that we delete any Win95 * entries preceding this entry, not just the ones we "own". * Since these presumably aren't valid anyway, * there should be no harm. */ offset -= sizeof(struct direntry); ep--->deName[0] = SLOT_DELETED; if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) || !(offset & pmp->pm_crbomask) || ep->deAttributes != ATTR_WIN95) break; } if (async) bdwrite(bp); else if ((error = bwrite(bp)) != 0) return error; } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) && !(offset & pmp->pm_crbomask) && offset); return 0; }
/* * dep - directory entry to copy into the directory * ddep - directory to add to * depp - return the address of the denode for the created directory entry * if depp != 0 * cnp - componentname needed for Win95 long filenames */ int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp) { int error, rberror; u_long dirclust, clusoffset; u_long fndoffset, havecnt = 0, wcnt = 1, i; struct direntry *ndep; struct msdosfsmount *pmp = ddep->de_pmp; struct buf *bp; daddr_t bn; int blsize; #ifdef _KERNEL int async = ddep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; #else #define async 0 #endif #ifdef MSDOSFS_DEBUG printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", dep, ddep, depp, cnp); #endif /* * If no space left in the directory then allocate another cluster * and chain it onto the end of the file. There is one exception * to this. That is, if the root directory has no more space it * can NOT be expanded. extendfile() checks for and fails attempts * to extend the root directory. We just return an error in that * case. */ if (ddep->de_fndoffset >= ddep->de_FileSize) { u_long needlen = ddep->de_fndoffset + sizeof(struct direntry) - ddep->de_FileSize; dirclust = de_clcount(pmp, needlen); if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) { (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); goto err_norollback; } /* * Update the size of the directory */ ddep->de_FileSize += de_cn2off(pmp, dirclust); } /* * We just read in the cluster with space. Copy the new directory * entry in. Then write it to disk. NOTE: DOS directories * do not get smaller as clusters are emptied. */ error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), &bn, &dirclust, &blsize); if (error) goto err_norollback; clusoffset = ddep->de_fndoffset; if (dirclust != MSDOSFSROOT) clusoffset &= pmp->pm_crbomask; if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, B_MODIFY, &bp)) != 0) { goto err_norollback; } ndep = bptoep(pmp, bp, clusoffset); DE_EXTERNALIZE(ndep, dep); /* * Now write the Win95 long name */ if (ddep->de_fndcnt > 0) { u_int8_t chksum = winChksum(ndep->deName); const u_char *un = (const u_char *)cnp->cn_nameptr; int unlen = cnp->cn_namelen; u_long xhavecnt; fndoffset = ddep->de_fndoffset; xhavecnt = ddep->de_fndcnt + 1; for(; wcnt < xhavecnt; wcnt++) { if ((fndoffset & pmp->pm_crbomask) == 0) { /* we should never get here if ddep is root * directory */ if (async) (void) bdwrite(bp); else if ((error = bwrite(bp)) != 0) goto rollback; fndoffset -= sizeof(struct direntry); error = pcbmap(ddep, de_cluster(pmp, fndoffset), &bn, 0, &blsize); if (error) goto rollback; error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, B_MODIFY, &bp); if (error) { goto rollback; } ndep = bptoep(pmp, bp, fndoffset & pmp->pm_crbomask); } else { ndep--; fndoffset -= sizeof(struct direntry); } if (!unix2winfn(un, unlen, (struct winentry *)ndep, wcnt, chksum)) break; } } if (async) bdwrite(bp); else if ((error = bwrite(bp)) != 0) goto rollback; /* * If they want us to return with the denode gotten. */ if (depp) { u_long diroffset = clusoffset; if (dep->de_Attributes & ATTR_DIRECTORY) { dirclust = dep->de_StartCluster; if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) dirclust = MSDOSFSROOT; if (dirclust == MSDOSFSROOT) diroffset = MSDOSFSROOT_OFS; else diroffset = 0; } error = deget(pmp, dirclust, diroffset, depp); #ifndef MAKEFS if (error == 0) VOP_UNLOCK(DETOV(*depp)); #endif return error; } return 0; rollback: /* * Mark all slots modified so far as deleted. Note that we * can't just call removede(), since directory is not in * consistent state. */ fndoffset = ddep->de_fndoffset; rberror = pcbmap(ddep, de_cluster(pmp, fndoffset), &bn, NULL, &blsize); if (rberror) goto err_norollback; if ((rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, B_MODIFY, &bp)) != 0) { goto err_norollback; } ndep = bptoep(pmp, bp, clusoffset); havecnt = ddep->de_fndcnt + 1; for(i = wcnt; i <= havecnt; i++) { /* mark entry as deleted */ ndep->deName[0] = SLOT_DELETED; if ((fndoffset & pmp->pm_crbomask) == 0) { /* we should never get here if ddep is root * directory */ if (async) bdwrite(bp); else if ((rberror = bwrite(bp)) != 0) goto err_norollback; fndoffset -= sizeof(struct direntry); rberror = pcbmap(ddep, de_cluster(pmp, fndoffset), &bn, 0, &blsize); if (rberror) goto err_norollback; rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, B_MODIFY, &bp); if (rberror) { goto err_norollback; } ndep = bptoep(pmp, bp, fndoffset); } else { ndep--; fndoffset -= sizeof(struct direntry); } } /* ignore any further error */ if (async) (void) bdwrite(bp); else (void) bwrite(bp); err_norollback: return error; }
/* * dep - directory entry to copy into the directory * ddep - directory to add to * depp - return the address of the denode for the created directory entry * if depp != 0 * cnp - componentname needed for Win95 long filenames */ int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp) { int error; u_long dirclust, diroffset; struct direntry *ndep; struct msdosfsmount *pmp = ddep->de_pmp; struct buf *bp; daddr_t bn; int blsize; #ifdef MSDOSFS_DEBUG kprintf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", dep, ddep, depp, cnp); #endif /* * If no space left in the directory then allocate another cluster * and chain it onto the end of the file. There is one exception * to this. That is, if the root directory has no more space it * can NOT be expanded. extendfile() checks for and fails attempts * to extend the root directory. We just return an error in that * case. */ if (ddep->de_fndoffset >= ddep->de_FileSize) { diroffset = ddep->de_fndoffset + sizeof(struct direntry) - ddep->de_FileSize; dirclust = de_clcount(pmp, diroffset); error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); if (error) { detrunc(ddep, ddep->de_FileSize, 0); return error; } /* * Update the size of the directory */ ddep->de_FileSize += de_cn2off(pmp, dirclust); } /* * We just read in the cluster with space. Copy the new directory * entry in. Then write it to disk. NOTE: DOS directories * do not get smaller as clusters are emptied. */ error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), &bn, &dirclust, &blsize); if (error) return error; diroffset = ddep->de_fndoffset; if (dirclust != MSDOSFSROOT) diroffset &= pmp->pm_crbomask; if ((error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp)) != 0) { brelse(bp); return error; } ndep = bptoep(pmp, bp, ddep->de_fndoffset); DE_EXTERNALIZE(ndep, dep); /* * Now write the Win95 long name */ if (ddep->de_fndcnt > 0) { u_int8_t chksum = winChksum(ndep->deName); const u_char *un = (const u_char *)cnp->cn_nameptr; int unlen = cnp->cn_namelen; int cnt = 1; while (--ddep->de_fndcnt >= 0) { if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { if ((error = bwrite(bp)) != 0) return error; ddep->de_fndoffset -= sizeof(struct direntry); error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), &bn, NULL, &blsize); if (error) return error; error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp); if (error) { brelse(bp); return error; } ndep = bptoep(pmp, bp, ddep->de_fndoffset); } else { ndep--; ddep->de_fndoffset -= sizeof(struct direntry); } if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum, pmp)) break; } } if ((error = bwrite(bp)) != 0) return error; /* * If they want us to return with the denode gotten. */ if (depp) { if (dep->de_Attributes & ATTR_DIRECTORY) { dirclust = dep->de_StartCluster; if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) dirclust = MSDOSFSROOT; if (dirclust == MSDOSFSROOT) diroffset = MSDOSFSROOT_OFS; else diroffset = 0; } return deget(pmp, dirclust, diroffset, depp); } return 0; }