1/*
2 * Copyright (c) 2000-2001, Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35#ifndef _FS_SMBFS_NODE_H_
36#define _FS_SMBFS_NODE_H_
37
38/*
39 * OS X semantics expect that node id of 2 is the root of the share.
40 * If File IDs are supported by the SMB 2/3 server, then we need to return 2
41 * for the root vnode File ID . If some other item on the server has the
42 * File ID of 2, then we return the actual root File ID instead.
43 * When vget is supported, then if they ask for File ID of 2, we return the
44 * root vnode.  If they ask for File ID that matches the actual root File ID,
45 * then we return the vnode that has the File ID of 2 on the server.
46 */
47#define	SMBFS_ROOT_INO		2	/* just like in UFS */
48#define	SMBFS_ROOT_PAR_INO	1	/* Maps to root vnode just like SMBFS_ROOT_INO */
49
50/* Bits for smbnode.n_flag */
51#define	NREFPARENT		0x00001	/* node holds parent from recycling */
52#define	N_ISSTREAM		0x00002	/* Node is a stream */
53#define	N_ISRSRCFRK		0x00004	/* Special stream node! */
54#define	NISMAPPED		0x00008 /* This file has been mmapped */
55#define NNEEDS_FLUSH	0x00010 /* Need to flush the file */
56#define	NNEEDS_EOF_SET	0x00020	/* Need to set the eof, ignore the eof from the server */
57#define	NATTRCHANGED	0x00040	/* Did we change the size of the file, clear cache on close */
58#define	NALLOC			0x00080	/* being created */
59#define	NWALLOC			0x00100	/* awaiting creation */
60#define	NTRANSIT		0x00200	/* being reclaimed */
61#define	NWTRANSIT		0x00400	/* awaiting reclaim */
62#define	NDELETEONCLOSE	0x00800	/* We need to delete this item on close */
63#define	NMARKEDFORDLETE	0x01000	/* This item will has been marked for deletion */
64#define	NNEGNCENTRIES	0x02000	/* Directory has negative name cache entries */
65#define NWINDOWSYMLNK	0x04000 /* This is a Conrad/Steve Window's symbolic links */
66#define N_POLLNOTIFY	0x08000 /* Change notify is not support, poll */
67#define NO_EXTENDEDOPEN 0x10000 /* The server doesn't support the extended open reply */
68#define NHAS_POSIXMODES 0x20000 /* This node has a Windows NFS ACE that contains posix modes */
69
70#define UNKNOWNUID ((uid_t)99)
71#define UNKNOWNGID ((gid_t)99)
72
73struct smbfs_fctx;
74
75enum smbfslocktype {SMBFS_SHARED_LOCK = 1, SMBFS_EXCLUSIVE_LOCK = 2, SMBFS_RECLAIM_LOCK = 3};
76
77/* Used in reconnect for open files. Look at openState. */
78#define kNeedRevoke	0x01
79#define kNeedReopen	0x02
80#define kInReopen   0x04  // Reopen in progress, don't update metadata
81
82enum {
83    kAnyMatch = 1,
84    kCheckDenyOrLocks = 2,
85    kExactMatch = 3,
86    kPreflightOpen = 4
87};
88
89/* Carbon Read/Write and Deny bits */
90enum {
91	kAccessRead = 0x01,
92	kAccessWrite = 0x02,
93	kDenyRead = 0x10,
94	kDenyWrite = 0x20,
95	kOpenMask = 0x03,
96	kDenyMask = 0x30,
97	kAccessMask = 0x33
98};
99
100struct ByteRangeLockEntry {
101	int64_t		offset;
102	int64_t		length;
103	uint32_t	lck_pid;
104	struct ByteRangeLockEntry *next;
105};
106
107/* Used for Open Deny */
108struct fileRefEntry {
109    uint32_t        refcnt;     /* open file reference count */
110    uint32_t        mmapped;    /* This entry has been mmaped */
111    pid_t           p_pid;      /* proc that did the open */
112    SMBFID          fid;        /* file handle, SMB 1 fid in volatile */
113    uint16_t        accessMode; /* access mode for this open */
114    uint32_t        rights;     /* nt granted rights */
115    struct proc     *proc;      /* used in cluster IO strategy function */
116    struct ByteRangeLockEntry *lockList;
117    struct smb2_durable_handle dur_handle;
118    struct fileRefEntry	*next;
119};
120
121struct smb_open_dir {
122	uint32_t		refcnt;
123	uint32_t		kq_refcnt;
124	SMBFID          fid;			/* directory handle, SMB 1 fid in volatile */
125	struct smbfs_fctx *fctx;		/* ff context */
126	void			*nextEntry;		/* directory entry that didn't fit */
127	int32_t			nextEntryLen;	/* size of directory entry that didn't fit */
128	int32_t			nextEntryFlags; /* flags that the next entry was create with */
129	off_t			offset;			/* last ff offset */
130	uint32_t		needReopen;		/* Need to reopen the notification */
131	uint32_t		needsUpdate;
132    u_int32_t       dirchangecnt;	/* changes each insert/delete. used by readdirattr */
133};
134
135struct smb_open_file {
136	int32_t         refcnt;		/* open file reference count */
137	SMBFID          fid;		/* file handle, SMB 1 fid in volatile */
138	uint32_t		rights;		/* nt granted rights */
139	uint16_t		accessMode;	/* access mode used when opening  */
140	uint32_t		mmapMode;	/* The mode we used when opening from mmap */
141	int32_t			needClose;	/* we opened it in the read call */
142	int32_t			openRWCnt;	/* number of rw opens */
143	int32_t			openRCnt;	/* number of r opens */
144	int32_t			openWCnt;	/* number of w opens */
145	int32_t			openTotalWriteCnt; /* nbr of w opens (shared and nonshared) */
146	int32_t			clusterCloseError;	/* Error to be return on user close */
147	uint32_t		openState;	/* Do we need to revoke or reopen the file */
148	lck_mtx_t		openStateLock;	/* Locks the openState */
149	lck_mtx_t		clusterWriteLock; /* Used for cluster writes */
150	lck_mtx_t		openDenyListLock;	/* Locks the open deny list */
151	struct fileRefEntry	*openDenyList;
152	struct smbfs_flock	*smbflock;	/*  Our flock structure */
153};
154
155struct smbnode {
156	lck_rw_t			n_rwlock;
157	void *				n_lastvop;	/* tracks last operation that locked the smbnode */
158	void *				n_activation;
159	uint32_t			n_lockState;	/* current lock state */
160	uint32_t			n_flag;
161	struct smbnode		*n_parent;
162	vnode_t				n_vnode;
163	struct smbmount		*n_mount;
164	time_t				attribute_cache_timer;	/* attributes cache time */
165	struct timespec		n_crtime;	/* create time */
166	struct timespec		n_mtime;	/* modify time */
167	struct timespec		n_atime;	/* last access time */
168	struct timespec		n_chtime;	/* change time */
169	struct timespec		n_sizetime;
170	struct timespec		n_rename_time;  /* last rename time */
171	u_quad_t			n_size;         /* stream size */
172	uint8_t				waitOnClusterWrite;
173	u_quad_t			n_data_alloc;	/* stream allocation size */
174	int					n_dosattr;
175	uint32_t			n_flags_mask;	/* When doing unix extensions the va_flags mask */
176	uid_t				n_uid;
177	gid_t				n_gid;
178	mode_t				n_mode;
179	mode_t				create_va_mode;
180	uid_t				n_nfs_uid;
181	gid_t				n_nfs_gid;
182	int					set_create_va_mode;
183	time_t				finfo_cache_timer;	/* finder info cache timer, only used by the data node */
184	uint8_t				finfo[FINDERINFOSIZE];	/* finder info , only used by the data node */
185	time_t				rfrk_cache_timer;		/* resource stream size cache timer, only used by the data node */
186	u_quad_t			rfrk_size;		/* resource stream size, only used by the data node */
187	u_quad_t			rfrk_alloc_size;/* resource stream alloc size */
188	lck_mtx_t			rfrkMetaLock;	/* Locks the resource size and resource cache timer */
189	uint64_t			n_ino;
190	uint64_t			n_nlinks;		/* Currently only supported when using the new UNIX Extensions */
191    SInt32              n_child_refcnt; /* Each child node holds a refcnt */
192	union {
193		struct smb_open_dir	dir;
194		struct smb_open_file file;
195	}open_type;
196	void				*acl_cache_data;
197	time_t				acl_cache_timer;
198	int					acl_error;
199	size_t				acl_cache_len;
200	lck_mtx_t			f_ACLCacheLock;     /* Locks the ACL Cache */
201	lck_rw_t			n_name_rwlock;      /* Read/Write lock for n_name */
202	lck_rw_t			n_parent_rwlock;    /* Read/Write lock for n_parent */
203	char				*n_name;	/* node's file or directory name */
204	size_t				n_nmlen;	/* node's name length */
205	size_t				n_snmlen;	/* if a stream then the legnth of the stream name */
206	char				*n_sname;	/* if a stream then the the name of the stream */
207	LIST_ENTRY(smbnode)	n_hash;
208	uint32_t			maxAccessRights;
209	struct timespec		maxAccessRightChTime;	/* change time */
210	uint32_t			n_reparse_tag;
211	uint16_t			n_fstatus;				/* Does the node have any named streams */
212	char				*n_symlink_target;
213	size_t				n_symlink_target_len;
214	time_t				n_symlink_cache_timer;
215	struct timespec		n_last_write_time;
216};
217
218/* Directory items */
219#define d_refcnt open_type.dir.refcnt
220#define d_kqrefcnt open_type.dir.kq_refcnt
221#define d_fctx open_type.dir.fctx
222#define d_nextEntry open_type.dir.nextEntry
223#define d_nextEntryFlags open_type.dir.nextEntryFlags
224#define d_nextEntryLen open_type.dir.nextEntryLen
225#define d_offset open_type.dir.offset
226#define d_needReopen open_type.dir.needReopen
227#define d_fid open_type.dir.fid
228#define d_needsUpdate open_type.dir.needsUpdate
229#define d_changecnt open_type.dir.dirchangecnt
230
231/* File items */
232#define f_refcnt open_type.file.refcnt
233#define f_fid open_type.file.fid
234#define f_rights open_type.file.rights
235#define f_accessMode open_type.file.accessMode
236#define f_mmapMode open_type.file.mmapMode
237#define f_needClose open_type.file.needClose
238#define f_openRWCnt open_type.file.openRWCnt
239#define f_openRCnt open_type.file.openRCnt
240#define f_openWCnt open_type.file.openWCnt
241#define f_openTotalWCnt open_type.file.openTotalWriteCnt
242#define f_openDenyList open_type.file.openDenyList
243#define f_smbflock open_type.file.smbflock
244#define f_openState open_type.file.openState
245#define f_openStateLock open_type.file.openStateLock
246#define f_clusterWriteLock open_type.file.clusterWriteLock
247#define f_openDenyListLock open_type.file.openDenyListLock
248#define f_clusterCloseError open_type.file.clusterCloseError
249
250/* Attribute cache timeouts in seconds */
251#define	SMB_MINATTRTIMO 2
252#define	SMB_MAXATTRTIMO 30
253
254/*
255 * Determine attrtimeo. It will be something between SMB_MINATTRTIMO and
256 * SMB_MAXATTRTIMO where recently modified files have a short timeout
257 * and files that haven't been modified in a long time have a long
258 * timeout. This is the same algorithm used by NFS.
259 */
260#define SMB_CACHE_TIME(ts, np, attrtimeo) { \
261	nanotime(&ts);	\
262	attrtimeo = (ts.tv_sec - np->n_mtime.tv_sec) / 10; \
263	if (attrtimeo < SMB_MINATTRTIMO)	\
264		attrtimeo = SMB_MINATTRTIMO;	\
265	else if (attrtimeo > SMB_MAXATTRTIMO) \
266	attrtimeo = SMB_MAXATTRTIMO; \
267	nanouptime(&ts);	\
268}
269
270#define VTOSMB(vp)	((struct smbnode *)vnode_fsnode(vp))
271#define SMBTOV(np)	((vnode_t )(np)->n_vnode)
272
273/* smbfs_nget flags */
274typedef enum _SMBFS_NGET_FLAGS
275{
276    SMBFS_NGET_CREATE_VNODE = 0x0001,
277    SMBFS_NGET_LOOKUP_ONLY = 0x0002,
278    SMBFS_NGET_NO_CACHE_UPDATE = 0x0004
279} _SMBFS_NGET_FLAGS;
280
281/* smb_get_uid_gid_mode flags */
282typedef enum _SMBFS_GET_UGM_FLAGS
283{
284    SMBFS_GET_UGM_IS_DIR = 0x0001,
285    SMBFS_GET_UGM_REMOVE_POSIX_MODES = 0x0002
286} _SMBFS_GET_UGM_FLAGS;
287
288extern lck_attr_t *smbfs_lock_attr;
289extern lck_grp_t *smbfs_mutex_group;
290extern lck_grp_t *smbfs_rwlock_group;
291
292struct smbfattr;
293
294int smbnode_lock(struct smbnode *np, enum smbfslocktype);
295int smbnode_lockpair(struct smbnode *np1, struct smbnode *np2, enum smbfslocktype);
296void smbnode_unlock(struct smbnode *np);
297void smbnode_unlockpair(struct smbnode *np1, struct smbnode *np2);
298uint64_t smbfs_hash(struct smb_share *share, uint64_t ino,
299                    const char *name, size_t nmlen);
300void smb_vhashrem (struct smbnode *np);
301void smb_vhashadd(struct smbnode *np, uint64_t hashval);
302int smbfs_nget(struct smb_share *share, struct mount *mp,
303               vnode_t dvp, const char *name, size_t nmlen,
304               struct smbfattr *fap, vnode_t *vpp,
305               uint32_t cnflags, uint32_t flags,
306               vfs_context_t context);
307vnode_t smbfs_find_vgetstrm(struct smbmount *smp, struct smbnode *np, const char *sname,
308							size_t maxfilenamelen);
309int smbfs_vgetstrm(struct smb_share *share, struct smbmount *smp, vnode_t vp,
310				   vnode_t *svpp, struct smbfattr *fap, const char *sname);
311int smb_get_rsrcfrk_size(struct smb_share *share, vnode_t vp, vfs_context_t context);
312vnode_t smb_update_rsrc_and_getparent(vnode_t vp, int setsize);
313int smb_check_posix_access(vfs_context_t context, struct smbnode * np,
314						   mode_t rq_mode);
315Boolean node_isimmutable(struct smb_share *share, vnode_t vp, struct smbfattr *fap);
316void smbfs_attr_cacheenter(struct smb_share *share, vnode_t vp, struct smbfattr *fap,
317						   int UpdateResourceParent, vfs_context_t context);
318int smbfs_attr_cachelookup(struct smb_share *share, vnode_t vp, struct vnode_attr *va,
319						   vfs_context_t context, int useCacheDataOnly);
320void smbfs_attr_touchdir(struct smbnode *dnp, int fatShare);
321
322int smbfsIsCacheable(vnode_t vp);
323void smbfs_setsize(vnode_t vp, off_t size);
324int smbfs_update_size(struct smbnode *np, struct timespec * reqtime, u_quad_t new_size);
325int smbfs_update_name_par(struct smb_share *share, vnode_t dvp, vnode_t vp,
326                          struct timespec *reqtime,
327                          const char *new_name, size_t name_len);
328
329int FindByteRangeLockEntry(struct fileRefEntry *fndEntry, int64_t offset,
330						int64_t length, uint32_t lck_pid);
331void AddRemoveByteRangeLockEntry(struct fileRefEntry *fndEntry, int64_t offset,
332							  int64_t length, int8_t unLock, uint32_t lck_pid);
333void AddFileRef(vnode_t vp, struct proc *p, uint16_t accessMode, uint32_t rights,
334                SMBFID fid, struct smb2_durable_handle dur_handle, struct fileRefEntry **fndEntry);
335int32_t FindFileEntryByFID(vnode_t vp, SMBFID fid, struct fileRefEntry **fndEntry);
336int32_t FindFileEntryByLeaseKey(vnode_t vp, uint64_t lease_key_hi, uint64_t lease_key_low, struct fileRefEntry **fndEntry);
337int32_t FindMappedFileRef(vnode_t vp, struct fileRefEntry **fndEntry, SMBFID *fid);
338int32_t FindFileRef(vnode_t vp, proc_t p, uint16_t accessMode, int32_t flags,
339                    int64_t offset, int64_t length,
340                    struct fileRefEntry **fndEntry,
341                    SMBFID *fid);
342void RemoveFileRef(vnode_t vp, struct fileRefEntry *inEntry);
343void smb_get_uid_gid_mode(struct smb_share *share, struct smbmount *smp,
344                          struct smbfattr *fap, uint32_t flags,
345                          uid_t *uid, gid_t *gid, mode_t *mode);
346
347/* smbfs_io.c prototypes */
348int smbfs_readvdir(vnode_t vp, uio_t uio, vfs_context_t context, int flags,
349				   int32_t *numdirent);
350int smbfs_0extend(struct smb_share *share, SMBFID fid, u_quad_t from,
351                  u_quad_t to, int ioflag, vfs_context_t context);
352int smbfs_doread(struct smb_share *share, off_t endOfFile, uio_t uiop,
353                 SMBFID fid, vfs_context_t context);
354int smbfs_dowrite(struct smb_share *share, off_t endOfFile, uio_t uiop,
355				  SMBFID fid, int ioflag, vfs_context_t context);
356void smbfs_reconnect(struct smbmount *smp);
357int32_t smbfs_IObusy(struct smbmount *smp);
358void smbfs_ClearChildren(struct smbmount *smp, struct smbnode * parent);
359int smbfs_handle_lease_break(struct smbmount *smp, uint64_t lease_key_hi,
360                             uint64_t lease_key_low, uint32_t new_lease_state);
361
362#define smb_ubc_getsize(v) (vnode_vtype(v) == VREG ? ubc_getsize(v) : (off_t)0)
363
364#endif /* _FS_SMBFS_NODE_H_ */
365