コード例 #1
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;
}
コード例 #2
0
ファイル: msdosfs_lookup.c プロジェクト: kusumi/DragonFlyBSD
/*
 * 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;
}