int deupdat(struct denode *dep, int waitfor) { struct buf *bp; struct direntry *dirp; int error; struct timespec ts; if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY) return (0); getnanotime(&ts); DETIMES(dep, &ts, &ts, &ts); if ((dep->de_flag & DE_MODIFIED) == 0) return (0); dep->de_flag &= ~DE_MODIFIED; if (dep->de_Attributes & ATTR_DIRECTORY) return (0); if (dep->de_refcnt <= 0) return (0); error = readde(dep, &bp, &dirp); if (error) return (error); DE_EXTERNALIZE(dirp, dep); if (waitfor) return (bwrite(bp)); else { bdwrite(bp); return (0); } }
int msdosfs_close(void *v) { struct vop_close_args *ap = v; struct vnode *vp = ap->a_vp; struct denode *dep = VTODE(vp); struct timespec ts; if (vp->v_usecount > 1 && !VOP_ISLOCKED(vp)) { getnanotime(&ts); DETIMES(dep, &ts, &ts, &ts); } return (0); }
int deupdat(struct denode *dep, int waitfor) { struct direntry dir; struct timespec ts; struct buf *bp; struct direntry *dirp; int error; if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY) { dep->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS | DE_MODIFIED); return (0); } getnanotime(&ts); DETIMES(dep, &ts, &ts, &ts); if ((dep->de_flag & DE_MODIFIED) == 0 && waitfor == 0) return (0); dep->de_flag &= ~DE_MODIFIED; if (DETOV(dep)->v_vflag & VV_ROOT) return (EINVAL); if (dep->de_refcnt <= 0) return (0); error = readde(dep, &bp, &dirp); if (error) return (error); DE_EXTERNALIZE(&dir, dep); if (bcmp(dirp, &dir, sizeof(dir)) == 0) { if (waitfor == 0 || (bp->b_flags & B_DELWRI) == 0) { brelse(bp); return (0); } } else *dirp = dir; if ((DETOV(dep)->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) bp->b_flags |= B_CLUSTEROK; if (waitfor) error = bwrite(bp); else if (vm_page_count_severe() || buf_dirty_count_severe()) bawrite(bp); else bdwrite(bp); return (error); }
int xtaf_deupdat(struct denode *dep, int waitfor) { int error; struct buf *bp; struct direntry *ep; struct timespec ts; if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY) return (0); getnanotime(&ts); DETIMES(dep, &ts, &ts, &ts); if ((dep->de_flag & DE_MODIFIED) == 0) return (0); dep->de_flag &= ~DE_MODIFIED; if (dep->de_Attributes & ATTR_DIRECTORY) return (0); /* * NOTE: The check for de_refcnt > 0 below ensures the denode being * examined does not represent an unlinked but still open file. * These files are not to be accessible even when the directory * entry that represented the file happens to be reused while the * deleted file is still open. */ if (dep->de_refcnt <= 0) return (0); error = xtaf_readde(dep, &bp, &ep); if (error) return (error); DE_EXTERNALIZE(ep, dep); if (waitfor) return (bwrite(bp)); else { bdwrite(bp); return (0); } }
int msdosfs_getattr(void *v) { struct vop_getattr_args *ap = v; struct denode *dep = VTODE(ap->a_vp); struct msdosfsmount *pmp = dep->de_pmp; struct vattr *vap = ap->a_vap; struct timespec ts; uint32_t fileid; getnanotime(&ts); DETIMES(dep, &ts, &ts, &ts); vap->va_fsid = dep->de_dev; /* * The following computation of the fileid must be the same as * that used in msdosfs_readdir() to compute d_fileno. If not, * pwd doesn't work. * * We now use the starting cluster number as the fileid/fileno. * This works for both files and directories (including the root * directory, on FAT32). Even on FAT32, this will at most be a * 28-bit number, as the high 4 bits of FAT32 cluster numbers * are reserved. * * However, we do need to do something for 0-length files, which * will not have a starting cluster number. * * These files cannot be directories, since (except for /, which * is special-cased anyway) directories contain entries for . and * .., so must have non-zero length. * * In this case, we just create a non-cryptographic hash of the * original fileid calculation, and set the top bit. * * This algorithm has the benefit that all directories, and all * non-zero-length files, will have fileids that are persistent * across mounts and reboots, and that cannot collide (as long * as the filesystem is not corrupt). Zero-length files will * have fileids that are persistent, but that may collide. We * will just have to live with that. */ fileid = dep->de_StartCluster; if (dep->de_Attributes & ATTR_DIRECTORY) { /* Special-case root */ if (dep->de_StartCluster == MSDOSFSROOT) fileid = FAT32(pmp) ? pmp->pm_rootdirblk : 1; } else { if (dep->de_FileSize == 0) { uint32_t dirsperblk; uint64_t fileid64; dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry); fileid64 = (dep->de_dirclust == MSDOSFSROOT) ? roottobn(pmp, 0) : cntobn(pmp, dep->de_dirclust); fileid64 *= dirsperblk; fileid64 += dep->de_diroffset / sizeof(struct direntry); fileid = fileidhash(fileid64); } } vap->va_fileid = fileid; vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) | ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH)); vap->va_mode &= dep->de_pmp->pm_mask; if (dep->de_Attributes & ATTR_DIRECTORY) { vap->va_mode |= S_IFDIR; if (pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) { vap->va_mode |= (vap->va_mode & S_IRUSR) ? S_IXUSR : 0; vap->va_mode |= (vap->va_mode & S_IRGRP) ? S_IXGRP : 0; vap->va_mode |= (vap->va_mode & S_IROTH) ? S_IXOTH : 0; } } vap->va_nlink = 1; vap->va_gid = dep->de_pmp->pm_gid; vap->va_uid = dep->de_pmp->pm_uid; vap->va_rdev = 0; vap->va_size = dep->de_FileSize; dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime); if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) { dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime); dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CTimeHundredth, &vap->va_ctime); } else { vap->va_atime = vap->va_mtime; vap->va_ctime = vap->va_mtime; } vap->va_flags = 0; if ((dep->de_Attributes & ATTR_ARCHIVE) == 0) vap->va_flags |= SF_ARCHIVED; vap->va_gen = 0; vap->va_blocksize = dep->de_pmp->pm_bpcluster; vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) & ~(dep->de_pmp->pm_crbomask); vap->va_type = ap->a_vp->v_type; return (0); }
int msdosfs_mkdir(void *v) { struct vop_mkdir_args *ap = v; struct componentname *cnp = ap->a_cnp; struct denode ndirent; struct denode *dep; struct denode *pdep = VTODE(ap->a_dvp); int error; daddr64_t bn; uint32_t newcluster, pcl; struct direntry *denp; struct msdosfsmount *pmp = pdep->de_pmp; struct buf *bp; struct timespec ts; /* * If this is the root directory and there is no space left we * can't do anything. This is because the root directory can not * change size. */ if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndoffset >= pdep->de_FileSize) { error = ENOSPC; goto bad2; } /* * Allocate a cluster to hold the about to be created directory. */ error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL); if (error) goto bad2; bzero(&ndirent, sizeof(ndirent)); ndirent.de_pmp = pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; getnanotime(&ts); DETIMES(&ndirent, &ts, &ts, &ts); /* * Now fill the cluster with the "." and ".." entries. And write * the cluster to disk. This way it is there for the parent * directory to be pointing at if there were a crash. */ bn = cntobn(pmp, newcluster); /* always succeeds */ bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0); bzero(bp->b_data, pmp->pm_bpcluster); bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate); denp = (struct direntry *)bp->b_data; putushort(denp[0].deStartCluster, newcluster); putushort(denp[0].deCDate, ndirent.de_CDate); putushort(denp[0].deCTime, ndirent.de_CTime); denp[0].deCTimeHundredth = ndirent.de_CTimeHundredth; putushort(denp[0].deADate, ndirent.de_ADate); putushort(denp[0].deMDate, ndirent.de_MDate); putushort(denp[0].deMTime, ndirent.de_MTime); pcl = pdep->de_StartCluster; if (FAT32(pmp) && pcl == pmp->pm_rootdirblk) pcl = 0; putushort(denp[1].deStartCluster, pcl); putushort(denp[1].deCDate, ndirent.de_CDate); putushort(denp[1].deCTime, ndirent.de_CTime); denp[1].deCTimeHundredth = ndirent.de_CTimeHundredth; putushort(denp[1].deADate, ndirent.de_ADate); putushort(denp[1].deMDate, ndirent.de_MDate); putushort(denp[1].deMTime, ndirent.de_MTime); if (FAT32(pmp)) { putushort(denp[0].deHighClust, newcluster >> 16); putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16); } if ((error = bwrite(bp)) != 0) goto bad; /* * Now build up a directory entry pointing to the newly allocated * cluster. This will be written to an empty slot in the parent * directory. */ #ifdef DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) panic("msdosfs_mkdir: no name"); #endif if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0) goto bad; ndirent.de_Attributes = ATTR_DIRECTORY; ndirent.de_StartCluster = newcluster; ndirent.de_FileSize = 0; ndirent.de_dev = pdep->de_dev; ndirent.de_devvp = pdep->de_devvp; if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0) goto bad; if ((cnp->cn_flags & SAVESTART) == 0) pool_put(&namei_pool, cnp->cn_pnbuf); vput(ap->a_dvp); *ap->a_vpp = DETOV(dep); return (0); bad: clusterfree(pmp, newcluster, NULL); bad2: pool_put(&namei_pool, cnp->cn_pnbuf); vput(ap->a_dvp); return (error); }
/* * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. We must also free * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or * only if the SAVESTART bit in cn_flags is clear on success. */ int msdosfs_create(void *v) { struct vop_create_args *ap = v; struct componentname *cnp = ap->a_cnp; struct denode ndirent; struct denode *dep; struct denode *pdep = VTODE(ap->a_dvp); int error; struct timespec ts; #ifdef MSDOSFS_DEBUG printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap); #endif /* * If this is the root directory and there is no space left we * can't do anything. This is because the root directory can not * change size. */ if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndoffset >= pdep->de_FileSize) { error = ENOSPC; goto bad; } /* * Create a directory entry for the file, then call createde() to * have it installed. NOTE: DOS files are always executable. We * use the absence of the owner write bit to make the file * readonly. */ #ifdef DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) panic("msdosfs_create: no name"); #endif bzero(&ndirent, sizeof(ndirent)); if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0) goto bad; ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ? ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY; ndirent.de_StartCluster = 0; ndirent.de_FileSize = 0; ndirent.de_dev = pdep->de_dev; ndirent.de_devvp = pdep->de_devvp; ndirent.de_pmp = pdep->de_pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; getnanotime(&ts); DETIMES(&ndirent, &ts, &ts, &ts); if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0) goto bad; if ((cnp->cn_flags & SAVESTART) == 0) pool_put(&namei_pool, cnp->cn_pnbuf); vput(ap->a_dvp); *ap->a_vpp = DETOV(dep); return (0); bad: pool_put(&namei_pool, cnp->cn_pnbuf); vput(ap->a_dvp); return (error); }