1/*
2 * Copyright (c) 2000, 2002-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* $FreeBSD: src/sys/msdosfs/denode.h,v 1.20 1999/12/29 04:54:52 peter Exp $ */
24/*	$NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $	*/
25
26/*-
27 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
28 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
29 * All rights reserved.
30 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 *    notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 *    notice, this list of conditions and the following disclaimer in the
39 *    documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 *    must display the following acknowledgement:
42 *	This product includes software developed by TooLs GmbH.
43 * 4. The name of TooLs GmbH may not be used to endorse or promote products
44 *    derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57/*
58 * Written by Paul Popelka (paulp@uts.amdahl.com)
59 *
60 * You can do anything you want with this software, just don't say you wrote
61 * it, and don't remove this notice.
62 *
63 * This software is provided "as is".
64 *
65 * The author supplies this software to be publicly redistributed on the
66 * understanding that the author is not responsible for the correct
67 * functioning of this software in any circumstances and is not liable for
68 * any damages caused by this software.
69 *
70 * October 1992
71 */
72
73/*
74 * This is the pc filesystem specific portion of the vnode structure.
75 *
76 * To describe a file uniquely the de_dirclust, de_diroffset, and
77 * de_StartCluster fields are used.
78 *
79 * de_dirclust contains the cluster number of the directory cluster
80 *	containing the entry for a file or directory.
81 * de_diroffset is the index into the parent directory (relative to the start
82 *  of the directory, not the start of de_dirclust!) for the entry describing
83 *	a file or directory.  Use de_diroffset modulo cluster size to find the
84 *  offset of the directory entry from the start of de_dirclust.
85 * de_StartCluster is the number of the first cluster of the file or directory.
86 *
87 * Now to describe the quirks of the pc filesystem.
88 * - Clusters 0 and 1 are reserved.
89 * - The first allocatable cluster is 2.
90 * - The root directory is of fixed size and all blocks that make it up
91 *   are contiguous.  (FAT12 and FAT16; in FAT32, the root directory is an
92 *   ordinary directory)
93 * - Cluster 0 refers to the root directory when it is found in the
94 *   startcluster field of a directory entry that points to another directory.
95 * - Cluster 0 implies a 0 length file when found in the start cluster field
96 *   of a directory entry that points to a file.
97 * - You can't use the cluster number 0 to derive the address of the root
98 *   directory.
99 * - Multiple directory entries can point to a directory. The entry in the
100 *   parent directory points to a child directory.  Any directories in the
101 *   child directory contain a ".." entry that points back to the parent.
102 *   The child directory itself contains a "." entry that points to itself.
103 * - The root directory does not contain a "." or ".." entry.
104 * - The de_dirclust and de_diroffset for a directory point at the directory's
105 *   own "." entry.  Since that is always the first entry, de_dirclust is the
106 *   first cluster of the directory, and de_diroffset is zero.
107 * - Directory entries for directories are never changed once they are created
108 *   (except when removed).  The size stays 0, and the last modification time
109 *   is never changed.  This is because so many directory entries can point to
110 *   the physical clusters that make up a directory.  It would lead to an
111 *   update nightmare.
112 * - For the POSIX/BSD APIs, the dates for a directory come from the "." entry
113 *   in the directory.
114 * - The length field in a directory entry pointing to a directory contains 0
115 *   (always).  The only way to find the end of a directory is to follow the
116 *   cluster chain until the "last cluster" marker is found.
117 *
118 * My extensions to make this house of cards work.  These apply only to the in
119 * memory copy of the directory entry.
120 * - A reference count for each denode will be kept since dos doesn't keep such
121 *   things.
122 */
123
124/*
125 * Internal pseudo-offset for (nonexistent) directory entry for the root
126 * dir in the root dir
127 */
128#define	MSDOSFSROOT_OFS	0x1fffffff
129
130/*
131 * This is the in memory variant of a dos directory entry.  It is the file
132 * system specific data pointed to by a vnode.
133 */
134struct denode {
135	lck_mtx_t *de_lock;			/* denode lock */
136	struct denode *de_next;		/* Hash chain forward */
137	struct denode **de_prev;	/* Hash chain back */
138	vnode_t de_vnode;			/* addr of vnode we are part of */
139	vnode_t de_devvp;			/* vnode of blk dev we live on */
140	uint32_t de_flag;				/* flag bits */
141	dev_t de_dev;				/* device where direntry lives */
142	uint32_t de_dirclust;			/* cluster of the directory file containing this entry */
143	uint32_t de_diroffset;		/* offset of this entry from the start of parent directory */
144	int de_refcnt;				/* reference count */
145	struct msdosfsmount *de_pmp;	/* addr of our mount struct */
146	u_char de_Name[12];			/* name, from DOS directory entry */
147	u_char de_Attributes;		/* attributes, from directory entry */
148	u_char de_LowerCase;		/* NT VFAT lower case flags */
149	u_char de_CHun;				/* Hundredth of second of CTime*/
150	uint16_t de_CTime;			/* creation time */
151	uint16_t de_CDate;			/* creation date */
152	uint16_t de_ADate;			/* access date */
153	uint16_t de_MTime;			/* modification time */
154	uint16_t de_MDate;			/* modification date */
155	uint32_t de_StartCluster;		/* starting cluster of file */
156	uint32_t de_FileSize;			/* size of file, or length of symlink, in bytes */
157	uint32_t de_LastCluster;		/* The last cluster of the file, or zero for empty files */
158	u_quad_t de_modrev;			/* Revision level for lease. */
159	struct msdosfs_lockf *de_lockf; /* Head of byte range lock list. */
160	struct denode *de_parent;	/* Parent directory denode */
161
162	/*
163	 * A hack for caching the results of logical-to-physical block mapping.
164	 * Basically, just cache the most recently used extent (contiguous run).
165	 *
166	 * Note that the lock below should really also protect the start cluster
167	 * and file size fields (i.e. anything that might be affected by truncation
168	 * or used in msdosfs_pcbmap).
169	 */
170	lck_mtx_t *de_cluster_lock;	/* Protects the cached extent fields */
171	uint32_t de_cluster_physical;	/* First physical cluster of cached extent */
172	uint32_t de_cluster_logical;	/* First logical cluster of cached extent */
173	uint32_t de_cluster_count;	/* Size of cached extent, in clusters; 0 => no cached extent */
174};
175
176/*
177 * Values for the de_flag field of the denode.
178 */
179#define DE_ROOT		0x0001	/* This node is the root directory */
180#define DE_SYMLINK	0x0002	/* This node is a symlink */
181#define	DE_UPDATE	0x0004	/* Modification time update request */
182#define	DE_CREATE	0x0008	/* Creation time update */
183#define	DE_ACCESS	0x0010	/* Access time update */
184#define	DE_MODIFIED	0x0020	/* Denode (directory entry) has been modified */
185#define DE_ATTR_MOD	0x0040	/* de_Attributes field has been modified */
186#define DE_INIT		0x0080	/* Denode is in the process of being initialized */
187#define DE_WAITINIT	0x0100	/* Someone is sleeping (on denode) waiting for initialization to finish */
188
189
190#define DE_EXTERNALIZE(dp, dep)				\
191	 ((dp)->deAttributes = (dep)->de_Attributes,	\
192	 (dp)->deCHundredth = (dep)->de_CHun,		\
193	 putuint16((dp)->deCTime, (dep)->de_CTime),	\
194	 putuint16((dp)->deCDate, (dep)->de_CDate),	\
195	 putuint16((dp)->deADate, (dep)->de_ADate),	\
196	 putuint16((dp)->deMTime, (dep)->de_MTime),	\
197	 putuint16((dp)->deMDate, (dep)->de_MDate),	\
198	 putuint16((dp)->deStartCluster, (dep)->de_StartCluster), \
199	 putuint32((dp)->deFileSize,			\
200	     ((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 :	\
201			((dep)->de_flag & DE_SYMLINK) ? sizeof(struct symlink) : (dep)->de_FileSize), \
202	 putuint16((dp)->deHighClust, (dep)->de_StartCluster >> 16))
203
204/*
205 * DE_EXTERNALIZE_ROOT is used to write the root directory's dates to the
206 * volume label entry (if any).
207 */
208#define DE_EXTERNALIZE_ROOT(dp, dep)				\
209	((dp)->deCHundredth = (dep)->de_CHun,		\
210	 putuint16((dp)->deCTime, (dep)->de_CTime),	\
211	 putuint16((dp)->deCDate, (dep)->de_CDate),	\
212	 putuint16((dp)->deADate, (dep)->de_ADate),	\
213	 putuint16((dp)->deMTime, (dep)->de_MTime),	\
214	 putuint16((dp)->deMDate, (dep)->de_MDate))
215
216#define	de_forw		de_chain[0]
217#define	de_back		de_chain[1]
218
219#ifdef KERNEL
220
221#define	VTODE(vp)	((struct denode *)vnode_fsnode((vp)))
222#define	DETOV(de)	((de)->de_vnode)
223
224#define	DETIMES(dep, acc, mod, cre) do {				\
225	if ((dep)->de_flag & DE_UPDATE) { 				\
226		(dep)->de_flag |= DE_MODIFIED;				\
227		msdosfs_unix2dostime((mod), &(dep)->de_MDate, &(dep)->de_MTime,	\
228		    NULL);						\
229		(dep)->de_Attributes |= ATTR_ARCHIVE; 			\
230	}								\
231	if ((dep)->de_flag & DE_ACCESS) {				\
232	    	u_int16_t adate;					\
233									\
234		msdosfs_unix2dostime((acc), &adate, NULL, NULL);		\
235		if (adate != (dep)->de_ADate) {				\
236			(dep)->de_flag |= DE_MODIFIED;			\
237			(dep)->de_ADate = adate;			\
238		}							\
239	}								\
240	if ((dep)->de_flag & DE_CREATE) {				\
241		msdosfs_unix2dostime((cre), &(dep)->de_CDate, &(dep)->de_CTime,	\
242		    &(dep)->de_CHun);					\
243		    (dep)->de_flag |= DE_MODIFIED;			\
244	}								\
245	(dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS);		\
246} while (0);
247
248
249extern int (**msdosfs_vnodeop_p)(void *);
250
251int msdosfs_vnop_lookup(struct vnop_lookup_args *ap);
252int msdosfs_lookup_name(
253	struct denode *dep,					/* parent directory */
254	struct componentname *cnp,			/* the name to look up */
255	uint32_t *dirclust,					/* cluster containing short name entry */
256	uint32_t *diroffset,				/* byte offset from start of directory */
257	struct dosdirentry *direntry,		/* copy of found directory entry */
258	u_int16_t *found_name,
259	u_int16_t *found_name_length,
260	boolean_t *case_folded,
261	vfs_context_t context);
262int msdosfs_vnop_inactive(struct vnop_inactive_args *ap);
263int msdosfs_vnop_reclaim(struct vnop_reclaim_args *ap);
264int msdosfs_vnop_blktooff(struct vnop_blktooff_args *ap);
265int msdosfs_vnop_offtoblk(struct vnop_offtoblk_args *ap);
266int msdosfs_vnop_blockmap(struct vnop_blockmap_args *ap);
267
268/*
269 * Internal service routine prototypes.
270 */
271void msdosfs_hash_init(void);
272void msdosfs_hash_uninit(void);
273int msdosfs_deget(struct msdosfsmount *pmp, uint32_t dirclust, uint32_t diroffset, vnode_t dvp, struct componentname *cnp, struct denode **, vfs_context_t context);
274int msdosfs_scan_dir_for_short_name(struct denode *dep, u_char short_name[SHORT_NAME_LEN], vfs_context_t context);
275int msdosfs_uniqdosname(struct denode *dep, u_char short_name[SHORT_NAME_LEN], uint32_t dir_offset, vfs_context_t context);
276
277int msdosfs_readep(struct msdosfsmount *pmp, uint32_t dirclu, uint32_t dirofs,  struct buf **bpp, struct dosdirentry **epp, vfs_context_t context);
278int readde(struct denode *dep, struct buf **bpp, struct dosdirentry **epp, vfs_context_t context);
279int msdosfs_deextend(struct denode *dep, uint32_t length, int flags, vfs_context_t context);
280void msdosfs_hash_reinsert(struct denode *dep);
281int msdosfs_dosdirempty(struct denode *dep, vfs_context_t context);
282int msdosfs_createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp, uint32_t offset, uint32_t long_count, vfs_context_t context);
283int msdosfs_deupdat(struct denode *dep, int waitfor, vfs_context_t context);
284int msdosfs_removede(struct denode *pdep, uint32_t offset, vfs_context_t context);
285int msdosfs_detrunc(struct denode *dep, uint32_t length, int flags, vfs_context_t context);
286int msdosfs_doscheckpath( struct denode *source, struct denode *target, vfs_context_t context);
287int msdosfs_findslots(struct denode *dep, struct componentname *cnp, uint8_t short_name[SHORT_NAME_LEN], int *needs_generation, uint8_t *lower_case, uint32_t *offset, uint32_t *long_count, vfs_context_t context);
288uint32_t msdosfs_defileid(struct denode *dep);
289int msdosfs_dir_flush(struct denode *dep, int sync);
290int msdosfs_dir_invalidate(struct denode *dep);
291#endif	/* KERNEL */
292