Home | History | Annotate | Line # | Download | only in msdos
msdosfs_vnops.c revision 1.17.2.1
      1  1.17.2.1  pgoyette /*	$NetBSD: msdosfs_vnops.c,v 1.17.2.1 2017/03/20 06:58:08 pgoyette Exp $ */
      2       1.1  christos 
      3       1.1  christos /*-
      4       1.1  christos  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
      5       1.1  christos  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
      6       1.1  christos  * All rights reserved.
      7       1.1  christos  * Original code by Paul Popelka (paulp (at) uts.amdahl.com) (see below).
      8       1.1  christos  *
      9       1.1  christos  * Redistribution and use in source and binary forms, with or without
     10       1.1  christos  * modification, are permitted provided that the following conditions
     11       1.1  christos  * are met:
     12       1.1  christos  * 1. Redistributions of source code must retain the above copyright
     13       1.1  christos  *    notice, this list of conditions and the following disclaimer.
     14       1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     15       1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     16       1.1  christos  *    documentation and/or other materials provided with the distribution.
     17       1.1  christos  * 3. All advertising materials mentioning features or use of this software
     18       1.1  christos  *    must display the following acknowledgement:
     19       1.1  christos  *	This product includes software developed by TooLs GmbH.
     20       1.1  christos  * 4. The name of TooLs GmbH may not be used to endorse or promote products
     21       1.1  christos  *    derived from this software without specific prior written permission.
     22       1.1  christos  *
     23       1.1  christos  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
     24       1.1  christos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25       1.1  christos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26       1.1  christos  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     27       1.1  christos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     28       1.1  christos  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     29       1.1  christos  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     30       1.1  christos  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     31       1.1  christos  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     32       1.1  christos  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33       1.1  christos  */
     34       1.1  christos /*
     35       1.1  christos  * Written by Paul Popelka (paulp (at) uts.amdahl.com)
     36       1.1  christos  *
     37       1.1  christos  * You can do anything you want with this software, just don't say you wrote
     38       1.1  christos  * it, and don't remove this notice.
     39       1.1  christos  *
     40       1.1  christos  * This software is provided "as is".
     41       1.1  christos  *
     42       1.1  christos  * The author supplies this software to be publicly redistributed on the
     43       1.1  christos  * understanding that the author is not responsible for the correct
     44       1.1  christos  * functioning of this software in any circumstances and is not liable for
     45       1.1  christos  * any damages caused by this software.
     46       1.1  christos  *
     47       1.1  christos  * October 1992
     48       1.1  christos  */
     49       1.3  christos #if HAVE_NBTOOL_CONFIG_H
     50       1.3  christos #include "nbtool_config.h"
     51       1.3  christos #endif
     52       1.1  christos 
     53       1.1  christos #include <sys/cdefs.h>
     54  1.17.2.1  pgoyette __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.17.2.1 2017/03/20 06:58:08 pgoyette Exp $");
     55       1.1  christos 
     56       1.1  christos #include <sys/param.h>
     57       1.1  christos #include <sys/mman.h>
     58       1.1  christos #include <fcntl.h>
     59       1.1  christos #include <unistd.h>
     60       1.1  christos 
     61       1.1  christos #include <ffs/buf.h>
     62       1.1  christos 
     63       1.1  christos #include <fs/msdosfs/bpb.h>
     64       1.1  christos #include <fs/msdosfs/direntry.h>
     65       1.1  christos #include <fs/msdosfs/denode.h>
     66       1.1  christos #include <fs/msdosfs/msdosfsmount.h>
     67       1.1  christos #include <fs/msdosfs/fat.h>
     68       1.1  christos 
     69       1.1  christos #include "makefs.h"
     70       1.1  christos #include "msdos.h"
     71       1.1  christos 
     72       1.9  christos #ifdef MSDOSFS_DEBUG
     73       1.9  christos #define DPRINTF(a) printf a
     74       1.9  christos #else
     75       1.9  christos #define DPRINTF(a)
     76       1.9  christos #endif
     77       1.1  christos /*
     78       1.1  christos  * Some general notes:
     79       1.1  christos  *
     80       1.1  christos  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
     81       1.1  christos  * read/written using the vnode for the filesystem. Blocks that represent
     82       1.1  christos  * the contents of a file are read/written using the vnode for the file
     83       1.1  christos  * (including directories when they are read/written as files). This
     84       1.1  christos  * presents problems for the dos filesystem because data that should be in
     85       1.7  christos  * an inode (if dos had them) resides in the directory itself.	Since we
     86       1.1  christos  * must update directory entries without the benefit of having the vnode
     87       1.7  christos  * for the directory we must use the vnode for the filesystem.	This means
     88       1.1  christos  * that when a directory is actually read/written (via read, write, or
     89       1.1  christos  * readdir, or seek) we must use the vnode for the filesystem instead of
     90       1.1  christos  * the vnode for the directory as would happen in ufs. This is to insure we
     91       1.1  christos  * retrieve the correct block from the buffer cache since the hash value is
     92       1.1  christos  * based upon the vnode address and the desired block number.
     93       1.1  christos  */
     94       1.1  christos 
     95       1.1  christos static int msdosfs_wfile(const char *, struct denode *, fsnode *);
     96       1.1  christos 
     97       1.1  christos static void
     98       1.1  christos msdosfs_times(struct msdosfsmount *pmp, struct denode *dep,
     99       1.1  christos     const struct stat *st)
    100       1.1  christos {
    101  1.17.2.1  pgoyette 	struct timespec at;
    102  1.17.2.1  pgoyette 	struct timespec mt;
    103  1.17.2.1  pgoyette 
    104  1.17.2.1  pgoyette 	if (stampst.st_ino)
    105  1.17.2.1  pgoyette 	    st = &stampst;
    106  1.17.2.1  pgoyette 
    107       1.4  christos #ifndef HAVE_NBTOOL_CONFIG_H
    108  1.17.2.1  pgoyette 	at = st->st_atimespec;
    109  1.17.2.1  pgoyette 	mt = st->st_mtimespec;
    110       1.3  christos #else
    111  1.17.2.1  pgoyette 	at.tv_sec = st->st_atime;
    112  1.17.2.1  pgoyette 	at.tv_nsec = 0;
    113  1.17.2.1  pgoyette 	mt.tv_sec = st->st_mtime;
    114  1.17.2.1  pgoyette 	mt.tv_nsec = 0;
    115       1.3  christos #endif
    116       1.3  christos 	unix2dostime(&at, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL);
    117       1.3  christos 	unix2dostime(&mt, pmp->pm_gmtoff, &dep->de_MDate, &dep->de_MTime, NULL);
    118       1.1  christos }
    119       1.1  christos 
    120       1.1  christos /*
    121       1.7  christos  * When we search a directory the blocks containing directory entries are
    122       1.7  christos  * read and examined.  The directory entries contain information that would
    123       1.7  christos  * normally be in the inode of a unix filesystem.  This means that some of
    124       1.7  christos  * a directory's contents may also be in memory resident denodes (sort of
    125       1.7  christos  * an inode).  This can cause problems if we are searching while some other
    126       1.7  christos  * process is modifying a directory.  To prevent one process from accessing
    127       1.7  christos  * incompletely modified directory information we depend upon being the
    128       1.7  christos  * sole owner of a directory block.  bread/brelse provide this service.
    129       1.7  christos  * This being the case, when a process modifies a directory it must first
    130       1.7  christos  * acquire the disk block that contains the directory entry to be modified.
    131       1.7  christos  * Then update the disk block and the denode, and then write the disk block
    132       1.7  christos  * out to disk.	 This way disk blocks containing directory entries and in
    133       1.7  christos  * memory denode's will be in synch.
    134       1.7  christos  */
    135       1.7  christos static int
    136       1.7  christos msdosfs_findslot(struct denode *dp, struct componentname *cnp)
    137       1.7  christos {
    138       1.7  christos 	daddr_t bn;
    139       1.7  christos 	int error;
    140       1.7  christos 	int slotcount;
    141       1.7  christos 	int slotoffset = 0;
    142       1.7  christos 	int frcn;
    143       1.7  christos 	u_long cluster;
    144       1.7  christos 	int blkoff;
    145       1.7  christos 	u_int diroff;
    146       1.7  christos 	int blsize;
    147       1.7  christos 	struct msdosfsmount *pmp;
    148       1.7  christos 	struct buf *bp = 0;
    149       1.7  christos 	struct direntry *dep;
    150       1.7  christos 	u_char dosfilename[12];
    151       1.7  christos 	int wincnt = 1;
    152       1.7  christos 	int chksum = -1, chksum_ok;
    153       1.7  christos 	int olddos = 1;
    154       1.7  christos 
    155       1.7  christos 	pmp = dp->de_pmp;
    156      1.12  christos 
    157       1.7  christos 	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
    158       1.7  christos 	    cnp->cn_namelen, 0)) {
    159       1.7  christos 	case 0:
    160       1.7  christos 		return (EINVAL);
    161       1.7  christos 	case 1:
    162       1.7  christos 		break;
    163       1.7  christos 	case 2:
    164       1.7  christos 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
    165      1.17   mlelstv 		    cnp->cn_namelen, pmp->pm_flags & MSDOSFSMNT_UTF8) + 1;
    166       1.7  christos 		break;
    167       1.7  christos 	case 3:
    168       1.7  christos 		olddos = 0;
    169       1.7  christos 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
    170      1.17   mlelstv 		    cnp->cn_namelen, pmp->pm_flags & MSDOSFSMNT_UTF8) + 1;
    171       1.7  christos 		break;
    172       1.7  christos 	}
    173       1.7  christos 
    174       1.7  christos 	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
    175       1.7  christos 		wincnt = 1;
    176       1.7  christos 
    177       1.7  christos 	/*
    178       1.7  christos 	 * Suppress search for slots unless creating
    179       1.7  christos 	 * file and at end of pathname, in which case
    180       1.7  christos 	 * we watch for a place to put the new file in
    181       1.7  christos 	 * case it doesn't already exist.
    182       1.7  christos 	 */
    183       1.7  christos 	slotcount = 0;
    184       1.9  christos 	DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename));
    185       1.7  christos 	/*
    186       1.7  christos 	 * Search the directory pointed at by vdp for the name pointed at
    187       1.7  christos 	 * by cnp->cn_nameptr.
    188       1.7  christos 	 */
    189       1.7  christos 	/*
    190       1.7  christos 	 * The outer loop ranges over the clusters that make up the
    191       1.7  christos 	 * directory.  Note that the root directory is different from all
    192       1.7  christos 	 * other directories.  It has a fixed number of blocks that are not
    193       1.7  christos 	 * part of the pool of allocatable clusters.  So, we treat it a
    194       1.7  christos 	 * little differently. The root directory starts at "cluster" 0.
    195       1.7  christos 	 */
    196       1.7  christos 	diroff = 0;
    197       1.7  christos 	for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
    198       1.7  christos 		if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
    199       1.7  christos 			if (error == E2BIG)
    200       1.7  christos 				break;
    201       1.7  christos 			return (error);
    202       1.7  christos 		}
    203      1.16       agc 		error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
    204       1.7  christos 		    0, &bp);
    205       1.7  christos 		if (error) {
    206       1.7  christos 			return (error);
    207       1.7  christos 		}
    208       1.7  christos 		for (blkoff = 0; blkoff < blsize;
    209       1.7  christos 		     blkoff += sizeof(struct direntry),
    210       1.7  christos 		     diroff += sizeof(struct direntry)) {
    211       1.7  christos 			dep = (struct direntry *)((char *)bp->b_data + blkoff);
    212       1.7  christos 			/*
    213       1.7  christos 			 * If the slot is empty and we are still looking
    214       1.7  christos 			 * for an empty then remember this one.	 If the
    215       1.7  christos 			 * slot is not empty then check to see if it
    216       1.7  christos 			 * matches what we are looking for.  If the slot
    217       1.7  christos 			 * has never been filled with anything, then the
    218       1.7  christos 			 * remainder of the directory has never been used,
    219       1.7  christos 			 * so there is no point in searching it.
    220       1.7  christos 			 */
    221       1.7  christos 			if (dep->deName[0] == SLOT_EMPTY ||
    222       1.7  christos 			    dep->deName[0] == SLOT_DELETED) {
    223       1.7  christos 				/*
    224       1.7  christos 				 * Drop memory of previous long matches
    225       1.7  christos 				 */
    226       1.7  christos 				chksum = -1;
    227       1.7  christos 
    228       1.7  christos 				if (slotcount < wincnt) {
    229       1.7  christos 					slotcount++;
    230       1.7  christos 					slotoffset = diroff;
    231       1.7  christos 				}
    232       1.7  christos 				if (dep->deName[0] == SLOT_EMPTY) {
    233       1.7  christos 					brelse(bp, 0);
    234       1.7  christos 					goto notfound;
    235       1.7  christos 				}
    236       1.7  christos 			} else {
    237       1.7  christos 				/*
    238       1.7  christos 				 * If there wasn't enough space for our
    239       1.7  christos 				 * winentries, forget about the empty space
    240       1.7  christos 				 */
    241       1.7  christos 				if (slotcount < wincnt)
    242       1.7  christos 					slotcount = 0;
    243       1.7  christos 
    244       1.7  christos 				/*
    245       1.7  christos 				 * Check for Win95 long filename entry
    246       1.7  christos 				 */
    247       1.7  christos 				if (dep->deAttributes == ATTR_WIN95) {
    248       1.7  christos 					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
    249       1.7  christos 						continue;
    250       1.7  christos 
    251       1.7  christos 					chksum = winChkName((const u_char *)cnp->cn_nameptr,
    252       1.7  christos 							    cnp->cn_namelen,
    253       1.7  christos 							    (struct winentry *)dep,
    254      1.17   mlelstv 							    chksum,
    255      1.17   mlelstv 							    pmp->pm_flags & MSDOSFSMNT_UTF8);
    256       1.7  christos 					continue;
    257       1.7  christos 				}
    258       1.7  christos 
    259       1.7  christos 				/*
    260       1.7  christos 				 * Ignore volume labels (anywhere, not just
    261       1.7  christos 				 * the root directory).
    262       1.7  christos 				 */
    263       1.7  christos 				if (dep->deAttributes & ATTR_VOLUME) {
    264       1.7  christos 					chksum = -1;
    265       1.7  christos 					continue;
    266       1.7  christos 				}
    267       1.7  christos 
    268       1.7  christos 				/*
    269       1.7  christos 				 * Check for a checksum or name match
    270       1.7  christos 				 */
    271       1.7  christos 				chksum_ok = (chksum == winChksum(dep->deName));
    272       1.7  christos 				if (!chksum_ok
    273       1.7  christos 				    && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
    274       1.7  christos 					chksum = -1;
    275       1.7  christos 					continue;
    276       1.7  christos 				}
    277       1.9  christos 				DPRINTF(("%s(): match blkoff %d, diroff %d\n",
    278       1.9  christos 				    __func__, blkoff, diroff));
    279       1.7  christos 				/*
    280       1.7  christos 				 * Remember where this directory
    281       1.7  christos 				 * entry came from for whoever did
    282       1.7  christos 				 * this lookup.
    283       1.7  christos 				 */
    284       1.7  christos 				dp->de_fndoffset = diroff;
    285       1.7  christos 				dp->de_fndcnt = 0;
    286       1.7  christos 
    287       1.7  christos 				return EEXIST;
    288       1.7  christos 			}
    289       1.7  christos 		}	/* for (blkoff = 0; .... */
    290       1.7  christos 		/*
    291       1.7  christos 		 * Release the buffer holding the directory cluster just
    292       1.7  christos 		 * searched.
    293       1.7  christos 		 */
    294       1.7  christos 		brelse(bp, 0);
    295       1.7  christos 	}	/* for (frcn = 0; ; frcn++) */
    296       1.7  christos 
    297       1.7  christos notfound:
    298       1.7  christos 	/*
    299       1.7  christos 	 * We hold no disk buffers at this point.
    300       1.7  christos 	 */
    301       1.7  christos 
    302       1.7  christos 	/*
    303       1.7  christos 	 * If we get here we didn't find the entry we were looking for. But
    304       1.7  christos 	 * that's ok if we are creating or renaming and are at the end of
    305       1.7  christos 	 * the pathname and the directory hasn't been removed.
    306       1.7  christos 	 */
    307       1.9  christos 	DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n",
    308       1.9  christos 	    __func__, dp->de_refcnt, slotcount, slotoffset));
    309       1.7  christos 	/*
    310       1.7  christos 	 * Fixup the slot description to point to the place where
    311       1.7  christos 	 * we might put the new DOS direntry (putting the Win95
    312       1.7  christos 	 * long name entries before that)
    313       1.7  christos 	 */
    314       1.7  christos 	if (!slotcount) {
    315       1.7  christos 		slotcount = 1;
    316       1.7  christos 		slotoffset = diroff;
    317       1.7  christos 	}
    318       1.7  christos 	if (wincnt > slotcount) {
    319       1.7  christos 		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
    320       1.7  christos 	}
    321       1.7  christos 
    322       1.7  christos 	/*
    323       1.7  christos 	 * Return an indication of where the new directory
    324       1.7  christos 	 * entry should be put.
    325       1.7  christos 	 */
    326       1.7  christos 	dp->de_fndoffset = slotoffset;
    327       1.7  christos 	dp->de_fndcnt = wincnt - 1;
    328       1.7  christos 
    329       1.7  christos 	/*
    330       1.7  christos 	 * We return with the directory locked, so that
    331       1.7  christos 	 * the parameters we set up above will still be
    332       1.7  christos 	 * valid if we actually decide to do a direnter().
    333       1.7  christos 	 * We return ni_vp == NULL to indicate that the entry
    334       1.7  christos 	 * does not currently exist; we leave a pointer to
    335       1.7  christos 	 * the (locked) directory inode in ndp->ni_dvp.
    336       1.7  christos 	 *
    337       1.7  christos 	 * NB - if the directory is unlocked, then this
    338       1.7  christos 	 * information cannot be used.
    339       1.7  christos 	 */
    340       1.7  christos 	return 0;
    341       1.7  christos }
    342       1.7  christos 
    343       1.7  christos /*
    344       1.1  christos  * Create a regular file. On entry the directory to contain the file being
    345       1.1  christos  * created is locked.  We must release before we return.
    346       1.1  christos  */
    347       1.1  christos struct denode *
    348       1.1  christos msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
    349       1.1  christos {
    350       1.1  christos 	struct componentname cn;
    351       1.1  christos 	struct denode ndirent;
    352       1.1  christos 	struct denode *dep;
    353       1.1  christos 	int error;
    354       1.1  christos 	struct stat *st = &node->inode->st;
    355       1.1  christos 	struct msdosfsmount *pmp = pdep->de_pmp;
    356       1.1  christos 
    357       1.1  christos 	cn.cn_nameptr = node->name;
    358       1.1  christos 	cn.cn_namelen = strlen(node->name);
    359       1.1  christos 
    360       1.9  christos 	DPRINTF(("%s(name %s, mode 0%o size %zu)\n", __func__, node->name,
    361       1.9  christos 	    st->st_mode, (size_t)st->st_size));
    362       1.1  christos 
    363       1.1  christos 	/*
    364       1.1  christos 	 * If this is the root directory and there is no space left we
    365       1.1  christos 	 * can't do anything.  This is because the root directory can not
    366       1.1  christos 	 * change size.
    367       1.1  christos 	 */
    368       1.1  christos 	if (pdep->de_StartCluster == MSDOSFSROOT
    369       1.1  christos 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
    370       1.1  christos 		error = ENOSPC;
    371       1.1  christos 		goto bad;
    372       1.1  christos 	}
    373       1.1  christos 
    374       1.1  christos 	/*
    375       1.1  christos 	 * Create a directory entry for the file, then call createde() to
    376       1.1  christos 	 * have it installed. NOTE: DOS files are always executable.  We
    377       1.1  christos 	 * use the absence of the owner write bit to make the file
    378       1.1  christos 	 * readonly.
    379       1.1  christos 	 */
    380       1.1  christos 	memset(&ndirent, 0, sizeof(ndirent));
    381       1.1  christos 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
    382       1.1  christos 		goto bad;
    383       1.1  christos 
    384       1.1  christos 	ndirent.de_Attributes = (st->st_mode & S_IWUSR) ?
    385       1.1  christos 				ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
    386       1.1  christos 	ndirent.de_StartCluster = 0;
    387       1.1  christos 	ndirent.de_FileSize = 0;
    388       1.1  christos 	ndirent.de_dev = pdep->de_dev;
    389       1.1  christos 	ndirent.de_devvp = pdep->de_devvp;
    390       1.1  christos 	ndirent.de_pmp = pdep->de_pmp;
    391       1.1  christos 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
    392       1.1  christos 	msdosfs_times(pmp, &ndirent, st);
    393       1.7  christos 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
    394       1.7  christos 		goto bad;
    395       1.1  christos 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
    396       1.1  christos 		goto bad;
    397       1.7  christos 	if ((error = msdosfs_wfile(path, dep, node)) != 0)
    398       1.1  christos 		goto bad;
    399       1.1  christos 	return dep;
    400       1.1  christos 
    401       1.1  christos bad:
    402       1.1  christos 	errno = error;
    403       1.1  christos 	return NULL;
    404       1.1  christos }
    405       1.9  christos static int
    406       1.9  christos msdosfs_updatede(struct denode *dep)
    407       1.9  christos {
    408       1.9  christos 	struct buf *bp;
    409       1.9  christos 	struct direntry *dirp;
    410       1.9  christos 	int error;
    411       1.9  christos 
    412       1.9  christos 	dep->de_flag &= ~DE_MODIFIED;
    413       1.9  christos 	error = readde(dep, &bp, &dirp);
    414       1.9  christos 	if (error)
    415       1.9  christos 		return error;
    416       1.9  christos 	DE_EXTERNALIZE(dirp, dep);
    417       1.9  christos 	error = bwrite(bp);
    418       1.9  christos 	return error;
    419       1.9  christos }
    420       1.1  christos 
    421       1.1  christos /*
    422       1.1  christos  * Write data to a file or directory.
    423       1.1  christos  */
    424       1.1  christos static int
    425       1.1  christos msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
    426       1.1  christos {
    427       1.1  christos 	int error, fd;
    428       1.1  christos 	size_t osize = dep->de_FileSize;
    429       1.1  christos 	struct stat *st = &node->inode->st;
    430      1.11  christos 	size_t nsize, offs;
    431       1.1  christos 	struct msdosfsmount *pmp = dep->de_pmp;
    432       1.1  christos 	struct buf *bp;
    433       1.1  christos 	char *dat;
    434      1.13  christos 	u_long cn = 0;
    435       1.1  christos 
    436      1.14  christos 	error = 0;	/* XXX: gcc/vax */
    437       1.9  christos 	DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", __func__,
    438       1.9  christos 	    dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster));
    439       1.6    martin 	if (st->st_size == 0)
    440       1.1  christos 		return 0;
    441       1.1  christos 
    442       1.1  christos 	/* Don't bother to try to write files larger than the fs limit */
    443       1.8  christos 	if (st->st_size > MSDOSFS_FILESIZE_MAX) {
    444       1.1  christos 		errno = EFBIG;
    445       1.1  christos 		return -1;
    446       1.1  christos 	}
    447       1.1  christos 
    448       1.6    martin 	nsize = st->st_size;
    449       1.9  christos 	DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize));
    450       1.1  christos 	if (nsize > osize) {
    451       1.1  christos 		if ((error = deextend(dep, nsize, NULL)) != 0) {
    452       1.1  christos 			errno = error;
    453       1.1  christos 			return -1;
    454       1.1  christos 		}
    455       1.9  christos 		if ((error = msdosfs_updatede(dep)) != 0) {
    456       1.9  christos 			errno = error;
    457       1.9  christos 			return -1;
    458       1.9  christos 		}
    459       1.1  christos 	}
    460       1.1  christos 
    461       1.1  christos 	if ((fd = open(path, O_RDONLY)) == -1)
    462       1.1  christos 		err(1, "open %s", path);
    463       1.1  christos 
    464       1.7  christos 	if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0))
    465       1.7  christos 	    == MAP_FAILED) {
    466       1.9  christos 		DPRINTF(("%s: mmap %s %s", __func__, node->name,
    467       1.9  christos 		    strerror(errno)));
    468       1.9  christos 		close(fd);
    469       1.7  christos 		goto out;
    470       1.7  christos 	}
    471       1.1  christos 	close(fd);
    472       1.1  christos 
    473      1.11  christos 	for (offs = 0; offs < nsize;) {
    474       1.1  christos 		int blsize, cpsize;
    475       1.1  christos 		daddr_t bn;
    476       1.9  christos 		u_long on = offs & pmp->pm_crbomask;
    477      1.13  christos #ifdef HACK
    478      1.13  christos 		cn = dep->de_StartCluster;
    479      1.13  christos 		if (cn == MSDOSFSROOT) {
    480      1.13  christos 			DPRINTF(("%s: bad lbn %lu", __func__, cn));
    481       1.1  christos 			goto out;
    482       1.1  christos 		}
    483      1.13  christos 		bn = cntobn(pmp, cn);
    484       1.9  christos 		blsize = pmp->pm_bpcluster;
    485      1.13  christos #else
    486      1.13  christos 		if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) {
    487      1.13  christos 			DPRINTF(("%s: pcbmap %lu", __func__, bn));
    488      1.13  christos 			goto out;
    489      1.13  christos 		}
    490      1.13  christos #endif
    491      1.13  christos 		DPRINTF(("%s(cn=%lu, bn=%llu/%llu, blsize=%d)\n", __func__,
    492      1.13  christos 		    cn, (unsigned long long)bn,
    493       1.9  christos 		    (unsigned long long)de_bn2kb(pmp, bn), blsize));
    494       1.7  christos 		if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize,
    495      1.16       agc 		    0, &bp)) != 0) {
    496       1.9  christos 			DPRINTF(("bread %d\n", error));
    497       1.7  christos 			goto out;
    498       1.7  christos 		}
    499       1.9  christos 		cpsize = MIN((nsize - offs), blsize - on);
    500       1.9  christos 		memcpy((char *)bp->b_data + on, dat + offs, cpsize);
    501       1.1  christos 		bwrite(bp);
    502       1.9  christos 		offs += cpsize;
    503       1.1  christos 	}
    504       1.1  christos 
    505       1.1  christos 	munmap(dat, nsize);
    506       1.1  christos 	return 0;
    507       1.1  christos out:
    508       1.1  christos 	munmap(dat, nsize);
    509       1.7  christos 	return error;
    510       1.1  christos }
    511       1.1  christos 
    512       1.1  christos 
    513       1.1  christos static const struct {
    514       1.1  christos 	struct direntry dot;
    515       1.1  christos 	struct direntry dotdot;
    516       1.1  christos } dosdirtemplate = {
    517      1.12  christos 	{	".       ", "   ",			/* the . entry */
    518       1.1  christos 		ATTR_DIRECTORY,				/* file attribute */
    519       1.7  christos 		0,					/* reserved */
    520       1.1  christos 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
    521       1.1  christos 		{ 0, 0 },				/* access date */
    522       1.1  christos 		{ 0, 0 },				/* high bits of start cluster */
    523       1.1  christos 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
    524       1.1  christos 		{ 0, 0 },				/* startcluster */
    525       1.7  christos 		{ 0, 0, 0, 0 }				/* filesize */
    526       1.1  christos 	},
    527      1.12  christos 	{	"..      ", "   ",			/* the .. entry */
    528       1.1  christos 		ATTR_DIRECTORY,				/* file attribute */
    529       1.7  christos 		0,					/* reserved */
    530       1.1  christos 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
    531       1.1  christos 		{ 0, 0 },				/* access date */
    532       1.1  christos 		{ 0, 0 },				/* high bits of start cluster */
    533       1.1  christos 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
    534       1.1  christos 		{ 0, 0 },				/* startcluster */
    535       1.1  christos 		{ 0, 0, 0, 0 }				/* filesize */
    536       1.1  christos 	}
    537       1.1  christos };
    538       1.1  christos 
    539       1.1  christos struct denode *
    540       1.1  christos msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
    541       1.1  christos 	struct denode ndirent;
    542       1.1  christos 	struct denode *dep;
    543       1.1  christos 	struct componentname cn;
    544       1.1  christos 	struct stat *st = &node->inode->st;
    545       1.1  christos 	struct msdosfsmount *pmp = pdep->de_pmp;
    546       1.1  christos 	int error;
    547       1.1  christos 	u_long newcluster, pcl, bn;
    548       1.1  christos 	daddr_t lbn;
    549       1.1  christos 	struct direntry *denp;
    550       1.1  christos 	struct buf *bp;
    551       1.1  christos 
    552       1.1  christos 	cn.cn_nameptr = node->name;
    553       1.1  christos 	cn.cn_namelen = strlen(node->name);
    554       1.1  christos 	/*
    555       1.1  christos 	 * If this is the root directory and there is no space left we
    556       1.1  christos 	 * can't do anything.  This is because the root directory can not
    557       1.1  christos 	 * change size.
    558       1.1  christos 	 */
    559       1.1  christos 	if (pdep->de_StartCluster == MSDOSFSROOT
    560       1.1  christos 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
    561       1.1  christos 		error = ENOSPC;
    562       1.1  christos 		goto bad2;
    563       1.1  christos 	}
    564       1.1  christos 
    565       1.1  christos 	/*
    566       1.1  christos 	 * Allocate a cluster to hold the about to be created directory.
    567       1.1  christos 	 */
    568       1.1  christos 	error = clusteralloc(pmp, 0, 1, &newcluster, NULL);
    569       1.1  christos 	if (error)
    570       1.1  christos 		goto bad2;
    571       1.1  christos 
    572       1.1  christos 	memset(&ndirent, 0, sizeof(ndirent));
    573       1.1  christos 	ndirent.de_pmp = pmp;
    574       1.1  christos 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
    575       1.1  christos 	msdosfs_times(pmp, &ndirent, st);
    576       1.1  christos 
    577       1.1  christos 	/*
    578       1.1  christos 	 * Now fill the cluster with the "." and ".." entries. And write
    579       1.7  christos 	 * the cluster to disk.	 This way it is there for the parent
    580       1.1  christos 	 * directory to be pointing at if there were a crash.
    581       1.1  christos 	 */
    582       1.1  christos 	bn = cntobn(pmp, newcluster);
    583       1.1  christos 	lbn = de_bn2kb(pmp, bn);
    584      1.10  christos 	DPRINTF(("%s(newcluster %lu, bn=%lu, lbn=%lu)\n", __func__, newcluster,
    585      1.10  christos 	    bn, lbn));
    586       1.1  christos 	/* always succeeds */
    587       1.1  christos 	bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0);
    588       1.1  christos 	memset(bp->b_data, 0, pmp->pm_bpcluster);
    589       1.1  christos 	memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
    590       1.1  christos 	denp = (struct direntry *)bp->b_data;
    591       1.1  christos 	putushort(denp[0].deStartCluster, newcluster);
    592       1.1  christos 	putushort(denp[0].deCDate, ndirent.de_CDate);
    593       1.1  christos 	putushort(denp[0].deCTime, ndirent.de_CTime);
    594       1.1  christos 	denp[0].deCHundredth = ndirent.de_CHun;
    595       1.1  christos 	putushort(denp[0].deADate, ndirent.de_ADate);
    596       1.1  christos 	putushort(denp[0].deMDate, ndirent.de_MDate);
    597       1.1  christos 	putushort(denp[0].deMTime, ndirent.de_MTime);
    598       1.1  christos 	pcl = pdep->de_StartCluster;
    599      1.12  christos 	DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl,
    600      1.12  christos 	    pmp->pm_rootdirblk));
    601       1.1  christos 	if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
    602       1.1  christos 		pcl = 0;
    603       1.1  christos 	putushort(denp[1].deStartCluster, pcl);
    604       1.1  christos 	putushort(denp[1].deCDate, ndirent.de_CDate);
    605       1.1  christos 	putushort(denp[1].deCTime, ndirent.de_CTime);
    606       1.1  christos 	denp[1].deCHundredth = ndirent.de_CHun;
    607       1.1  christos 	putushort(denp[1].deADate, ndirent.de_ADate);
    608       1.1  christos 	putushort(denp[1].deMDate, ndirent.de_MDate);
    609       1.1  christos 	putushort(denp[1].deMTime, ndirent.de_MTime);
    610       1.1  christos 	if (FAT32(pmp)) {
    611       1.1  christos 		putushort(denp[0].deHighClust, newcluster >> 16);
    612       1.1  christos 		putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
    613       1.1  christos 	} else {
    614       1.1  christos 		putushort(denp[0].deHighClust, 0);
    615       1.1  christos 		putushort(denp[1].deHighClust, 0);
    616       1.1  christos 	}
    617       1.1  christos 
    618       1.1  christos 	if ((error = bwrite(bp)) != 0)
    619       1.1  christos 		goto bad;
    620       1.1  christos 
    621       1.1  christos 	/*
    622       1.1  christos 	 * Now build up a directory entry pointing to the newly allocated
    623       1.1  christos 	 * cluster.  This will be written to an empty slot in the parent
    624       1.1  christos 	 * directory.
    625       1.1  christos 	 */
    626       1.1  christos 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
    627       1.1  christos 		goto bad;
    628       1.1  christos 
    629       1.1  christos 	ndirent.de_Attributes = ATTR_DIRECTORY;
    630       1.1  christos 	ndirent.de_StartCluster = newcluster;
    631       1.1  christos 	ndirent.de_FileSize = 0;
    632       1.1  christos 	ndirent.de_dev = pdep->de_dev;
    633       1.1  christos 	ndirent.de_devvp = pdep->de_devvp;
    634      1.12  christos 	ndirent.de_pmp = pdep->de_pmp;
    635       1.7  christos 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
    636       1.7  christos 		goto bad;
    637       1.1  christos 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
    638       1.1  christos 		goto bad;
    639      1.10  christos 	if ((error = msdosfs_updatede(dep)) != 0)
    640      1.10  christos 		goto bad;
    641       1.1  christos 	return dep;
    642       1.1  christos 
    643       1.1  christos bad:
    644       1.1  christos 	clusterfree(pmp, newcluster, NULL);
    645       1.1  christos bad2:
    646       1.1  christos 	errno = error;
    647       1.1  christos 	return NULL;
    648       1.1  christos }
    649