FreeBSD/sys/fs/msdosfs/msdosfs_denode.c
/*
 * Truncate the file described by dep to the length specified by length.
 */
Truncate the file described by dep to the length specified by length.
Truncate the file described by dep to the length specified by length .
int
detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred)
{
	int error;
	int allerror;
	u_long eofentry;
	u_long chaintofree;
	daddr_t bn;
	int boff;
	int isadir = dep->de_Attributes & ATTR_DIRECTORY;
	struct buf *bp;
	struct msdosfsmount *pmp = dep->de_pmp;
#ifdef MSDOSFS_DEBUG
	printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
#endif
	if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) {
#ifdef MSDOSFS_DEBUG
		printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
		    dep->de_dirclust, dep->de_diroffset);
#endif
		return (EINVAL);
	}
	if (dep->de_FileSize < length) {
		vnode_pager_setsize(DETOV(dep), length);
		return deextend(dep, length, cred);
	}
	if (length == 0) {
		chaintofree = dep->de_StartCluster;
		dep->de_StartCluster = 0;
		eofentry = ~0;
	} else {
		error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, 
			       &eofentry, 0);
		if (error) {
#ifdef MSDOSFS_DEBUG
			printf("detrunc(): pcbmap fails %d\n", error);
#endif
			return (error);
		}
	}
	fc_purge(dep, de_clcount(pmp, length));
	if ((boff = length & pmp->pm_crbomask) != 0) {
		if (isadir) {
			bn = cntobn(pmp, eofentry);
			error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
			    NOCRED, &bp);
			if (error) {
				brelse(bp);
#ifdef MSDOSFS_DEBUG
				printf("detrunc(): bread fails %d\n", error);
#endif
				return (error);
			}
			bzero(bp->b_data + boff, pmp->pm_bpcluster - boff);
			if (flags & IO_SYNC)
				bwrite(bp);
			else
				bdwrite(bp);
		}
	}
	dep->de_FileSize = length;
	if (!isadir)
		dep->de_flag |= DE_UPDATE | DE_MODIFIED;
	allerror = vtruncbuf(DETOV(dep), cred, length, pmp->pm_bpcluster);
#ifdef MSDOSFS_DEBUG
	if (allerror)
		printf("detrunc(): vtruncbuf error %d\n", allerror);
#endif
	error = deupdat(dep, !DOINGASYNC((DETOV(dep))));
	if (error != 0 && allerror == 0)
		allerror = error;
#ifdef MSDOSFS_DEBUG
	printf("detrunc(): allerror %d, eofentry %lu\n",
	       allerror, eofentry);
#endif
	if (eofentry != ~0) {
		error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
				 &chaintofree, CLUST_EOFE);
		if (error) {
#ifdef MSDOSFS_DEBUG
			printf("detrunc(): fatentry errors %d\n", error);
#endif
			return (error);
		}
		fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
			    eofentry);
	}
	if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
		freeclusterchain(pmp, chaintofree);
	return (allerror);
}
int detrunc ( struct denode * dep , u_long length , int flags , struct ucred * cred ) { int error ; int allerror ; u_long eofentry ; u_long chaintofree ; daddr_t bn ; int boff ; int isadir = dep -> de_Attributes & ATTR_DIRECTORY ; struct buf * bp ; struct msdosfsmount * pmp = dep -> de_pmp ; #ifdef MSDOSFS_DEBUG printf ( " \n " , dep -> de_Name , length , flags ) ; #endif if ( ( DETOV ( dep ) -> v_vflag & VV_ROOT ) && ! FAT32 ( pmp ) ) { #ifdef MSDOSFS_DEBUG printf ( " \n " , dep -> de_dirclust , dep -> de_diroffset ) ; #endif return ( EINVAL ) ; } if ( dep -> de_FileSize < length ) { vnode_pager_setsize ( DETOV ( dep ) , length ) ; return deextend ( dep , length , cred ) ; } if ( length == 0 ) { chaintofree = dep -> de_StartCluster ; dep -> de_StartCluster = 0 ; eofentry = ~ 0 ; } else { error = pcbmap ( dep , de_clcount ( pmp , length ) - 1 , 0 , & eofentry , 0 ) ; if ( error ) { #ifdef MSDOSFS_DEBUG printf ( " \n " , error ) ; #endif return ( error ) ; } } fc_purge ( dep , de_clcount ( pmp , length ) ) ; if ( ( boff = length & pmp -> pm_crbomask ) != 0 ) { if ( isadir ) { bn = cntobn ( pmp , eofentry ) ; error = bread ( pmp -> pm_devvp , bn , pmp -> pm_bpcluster , NOCRED , & bp ) ; if ( error ) { brelse ( bp ) ; #ifdef MSDOSFS_DEBUG printf ( " \n " , error ) ; #endif return ( error ) ; } bzero ( bp -> b_data + boff , pmp -> pm_bpcluster - boff ) ; if ( flags & IO_SYNC ) bwrite ( bp ) ; else bdwrite ( bp ) ; } } dep -> de_FileSize = length ; if ( ! isadir ) dep -> de_flag |= DE_UPDATE | DE_MODIFIED ; allerror = vtruncbuf ( DETOV ( dep ) , cred , length , pmp -> pm_bpcluster ) ; #ifdef MSDOSFS_DEBUG if ( allerror ) printf ( " \n " , allerror ) ; #endif error = deupdat ( dep , ! DOINGASYNC ( ( DETOV ( dep ) ) ) ) ; if ( error != 0 && allerror == 0 ) allerror = error ; #ifdef MSDOSFS_DEBUG printf ( " \n " , allerror , eofentry ) ; #endif if ( eofentry != ~ 0 ) { error = fatentry ( FAT_GET_AND_SET , pmp , eofentry , & chaintofree , CLUST_EOFE ) ; if ( error ) { #ifdef MSDOSFS_DEBUG printf ( " \n " , error ) ; #endif return ( error ) ; } fc_setcache ( dep , FC_LASTFC , de_cluster ( pmp , length - 1 ) , eofentry ) ; } if ( chaintofree != 0 && ! MSDOSFSEOF ( pmp , chaintofree ) ) freeclusterchain ( pmp , chaintofree ) ; return ( allerror ) ; }
Truncate the file described by dep to the length specified by length.
Truncate the file described by dep to the length specified by length .
/*
	 * Disallow attempts to truncate the root directory since it is of
	 * fixed size.  That's just the way dos filesystems are.  We use
	 * the VROOT bit in the vnode because checking for the directory
	 * bit and a startcluster of 0 in the denode is not adequate to
	 * recognize the root directory at this point in a file or
	 * directory's life.
	 */ /*
	 * If the desired length is 0 then remember the starting cluster of
	 * the file and set the StartCluster field in the directory entry
	 * to 0.  If the desired length is not zero, then get the number of
	 * the last cluster in the shortened file.  Then get the number of
	 * the first cluster in the part of the file that is to be freed.
	 * Then set the next cluster pointer in the last cluster of the
	 * file to CLUST_EOFE.
	 */ /*
	 * If the new length is not a multiple of the cluster size then we
	 * must zero the tail end of the new last cluster in case it
	 * becomes part of the file again because of a seek.
	 */ /*
	 * Write out the updated directory entry.  Even if the update fails
	 * we free the trailing clusters.
	 */ /*
	 * If we need to break the cluster chain for the file then do it
	 * now.
	 */ /*
	 * Now free the clusters removed from the file because of the
	 * truncation.
	 */