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.x 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, smb1 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, smb1 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	uint32_t		refcnt;		/* open file reference count */
137	SMBFID         fid;		/* file handle, smb1 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;	/* 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	struct timespec		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;	/* ReadWrite lock for name changes */
202	char				*n_name;	/* node's file or directory name */
203	size_t				n_nmlen;	/* node's name length */
204	size_t				n_snmlen;	/* if a stream then the legnth of the stream name */
205	char				*n_sname;	/* if a stream then the the name of the stream */
206	LIST_ENTRY(smbnode)	n_hash;
207	uint32_t			maxAccessRights;
208	struct timespec		maxAccessRightChTime;	/* change time */
209	uint32_t			n_reparse_tag;
210	uint16_t			n_fstatus;				/* Does the node have any named streams */
211	char				*n_symlink_target;
212	size_t				n_symlink_target_len;
213	time_t				n_symlink_cache_timer;
214	struct timespec		n_last_write_time;
215};
216
217/* Directory items */
218#define d_refcnt open_type.dir.refcnt
219#define d_kqrefcnt open_type.dir.kq_refcnt
220#define d_fctx open_type.dir.fctx
221#define d_nextEntry open_type.dir.nextEntry
222#define d_nextEntryFlags open_type.dir.nextEntryFlags
223#define d_nextEntryLen open_type.dir.nextEntryLen
224#define d_offset open_type.dir.offset
225#define d_needReopen open_type.dir.needReopen
226#define d_fid open_type.dir.fid
227#define d_needsUpdate open_type.dir.needsUpdate
228#define d_changecnt open_type.dir.dirchangecnt
229
230/* File items */
231#define f_refcnt open_type.file.refcnt
232#define f_fid open_type.file.fid
233#define f_rights open_type.file.rights
234#define f_accessMode open_type.file.accessMode
235#define f_mmapMode open_type.file.mmapMode
236#define f_needClose open_type.file.needClose
237#define f_openRWCnt open_type.file.openRWCnt
238#define f_openRCnt open_type.file.openRCnt
239#define f_openWCnt open_type.file.openWCnt
240#define f_openTotalWCnt open_type.file.openTotalWriteCnt
241#define f_openDenyList open_type.file.openDenyList
242#define f_smbflock open_type.file.smbflock
243#define f_openState open_type.file.openState
244#define f_openStateLock open_type.file.openStateLock
245#define f_clusterWriteLock open_type.file.clusterWriteLock
246#define f_openDenyListLock open_type.file.openDenyListLock
247#define f_clusterCloseError open_type.file.clusterCloseError
248
249/* Attribute cache timeouts in seconds */
250#define	SMB_MINATTRTIMO 2
251#define	SMB_MAXATTRTIMO 30
252
253/*
254 * Determine attrtimeo. It will be something between SMB_MINATTRTIMO and
255 * SMB_MAXATTRTIMO where recently modified files have a short timeout
256 * and files that haven't been modified in a long time have a long
257 * timeout. This is the same algorithm used by NFS.
258 */
259#define SMB_CACHE_TIME(ts, np, attrtimeo) { \
260	nanotime(&ts);	\
261	attrtimeo = (ts.tv_sec - np->n_mtime.tv_sec) / 10; \
262	if (attrtimeo < SMB_MINATTRTIMO)	\
263		attrtimeo = SMB_MINATTRTIMO;	\
264	else if (attrtimeo > SMB_MAXATTRTIMO) \
265	attrtimeo = SMB_MAXATTRTIMO; \
266	nanouptime(&ts);	\
267}
268
269/* ACL cache timeouts in seconds */
270#define	SMB_ACL_MINTIMO 1
271#define	SMB_ACL_MAXTIMO 30
272
273/*
274 * If we are negative caching ( got an error back) then set our cache time
275 * to a longer value than normal caching. Remember that the vfs will help
276 * us with cache, but not in the negative case.
277 */
278#define SET_ACL_CACHE_TIME(np) { \
279	struct timespec waittime;	\
280								\
281	nanouptime(&np->acl_cache_timer);	\
282	if (np->acl_error) { \
283		waittime.tv_sec = SMB_ACL_MAXTIMO;	\
284		waittime.tv_nsec = 0;	\
285	} else {	\
286		waittime.tv_sec = SMB_ACL_MINTIMO;	\
287		waittime.tv_nsec = 0;	\
288	}\
289	timespecadd(&np->acl_cache_timer, &waittime);	\
290}
291
292
293#define VTOSMB(vp)	((struct smbnode *)vnode_fsnode(vp))
294#define SMBTOV(np)	((vnode_t )(np)->n_vnode)
295
296/* smbfs_nget flags */
297typedef enum _SMBFS_NGET_FLAGS
298{
299    SMBFS_NGET_CREATE_VNODE = 0x0001,
300    SMBFS_NGET_LOOKUP_ONLY = 0x0002,
301    SMBFS_NGET_NO_CACHE_UPDATE = 0x0004
302} _SMBFS_NGET_FLAGS;
303
304/* smb_get_uid_gid_mode flags */
305typedef enum _SMBFS_GET_UGM_FLAGS
306{
307    SMBFS_GET_UGM_IS_DIR = 0x0001,
308    SMBFS_GET_UGM_REMOVE_POSIX_MODES = 0x0002
309} _SMBFS_GET_UGM_FLAGS;
310
311extern lck_attr_t *smbfs_lock_attr;
312extern lck_grp_t *smbfs_mutex_group;
313extern lck_grp_t *smbfs_rwlock_group;
314
315struct smbfattr;
316
317int smbnode_lock(struct smbnode *np, enum smbfslocktype);
318int smbnode_lockpair(struct smbnode *np1, struct smbnode *np2, enum smbfslocktype);
319void smbnode_unlock(struct smbnode *np);
320void smbnode_unlockpair(struct smbnode *np1, struct smbnode *np2);
321uint64_t smbfs_hash(struct smb_share *share, uint64_t ino,
322                    const char *name, size_t nmlen);
323void smb_vhashrem (struct smbnode *np);
324void smb_vhashadd(struct smbnode *np, uint64_t hashval);
325int smbfs_nget(struct smb_share *share, struct mount *mp,
326               vnode_t dvp, const char *name, size_t nmlen,
327               struct smbfattr *fap, vnode_t *vpp,
328               uint32_t cnflags, uint32_t flags,
329               vfs_context_t context);
330vnode_t smbfs_find_vgetstrm(struct smbmount *smp, struct smbnode *np, const char *sname,
331							size_t maxfilenamelen);
332int smbfs_vgetstrm(struct smb_share *share, struct smbmount *smp, vnode_t vp,
333				   vnode_t *svpp, struct smbfattr *fap, const char *sname);
334int smb_get_rsrcfrk_size(struct smb_share *share, vnode_t vp, vfs_context_t context);
335vnode_t smb_update_rsrc_and_getparent(vnode_t vp, int setsize);
336int smb_check_posix_access(vfs_context_t context, struct smbnode * np,
337						   mode_t rq_mode);
338Boolean node_isimmutable(struct smb_share *share, vnode_t vp);
339void smbfs_attr_cacheenter(struct smb_share *share, vnode_t vp, struct smbfattr *fap,
340						   int UpdateResourceParent, vfs_context_t context);
341int smbfs_attr_cachelookup(struct smb_share *share, vnode_t vp, struct vnode_attr *va,
342						   vfs_context_t context, int useCacheDataOnly);
343void smbfs_attr_touchdir(struct smbnode *dnp, int fatShare);
344
345int smbfsIsCacheable(vnode_t vp);
346void smbfs_setsize(vnode_t vp, off_t size);
347int smbfs_update_size(struct smbnode *np, struct timespec * reqtime, u_quad_t new_size);
348int smbfs_update_name_par(struct smb_share *share, vnode_t dvp, vnode_t vp,
349                          struct timespec *reqtime,
350                          const char *new_name, size_t name_len);
351
352int FindByteRangeLockEntry(struct fileRefEntry *fndEntry, int64_t offset,
353						int64_t length, uint32_t lck_pid);
354void AddRemoveByteRangeLockEntry(struct fileRefEntry *fndEntry, int64_t offset,
355							  int64_t length, int8_t unLock, uint32_t lck_pid);
356void AddFileRef(vnode_t vp, struct proc *p, uint16_t accessMode, uint32_t rights,
357                SMBFID fid, struct smb2_durable_handle dur_handle, struct fileRefEntry **fndEntry);
358int32_t FindFileEntryByFID(vnode_t vp, SMBFID fid, struct fileRefEntry **fndEntry);
359int32_t FindFileEntryByLeaseKey(vnode_t vp, uint64_t lease_key_hi, uint64_t lease_key_low, struct fileRefEntry **fndEntry);
360int32_t FindMappedFileRef(vnode_t vp, struct fileRefEntry **fndEntry, SMBFID *fid);
361int32_t FindFileRef(vnode_t vp, proc_t p, uint16_t accessMode, int32_t flags,
362                    int64_t offset, int64_t length,
363                    struct fileRefEntry **fndEntry,
364                    SMBFID *fid);
365void RemoveFileRef(vnode_t vp, struct fileRefEntry *inEntry);
366void smb_get_uid_gid_mode(struct smb_share *share, struct smbmount *smp,
367                          struct smbfattr *fap, uint32_t flags,
368                          uid_t *uid, gid_t *gid, mode_t *mode);
369
370/* smbfs_io.c prototypes */
371int smbfs_readvdir(vnode_t vp, uio_t uio, vfs_context_t context, int flags,
372				   int32_t *numdirent);
373int smbfs_0extend(struct smb_share *share, SMBFID fid, u_quad_t from,
374                  u_quad_t to, int ioflag, vfs_context_t context);
375int smbfs_doread(struct smb_share *share, off_t endOfFile, uio_t uiop,
376                 SMBFID fid, vfs_context_t context);
377int smbfs_dowrite(struct smb_share *share, off_t endOfFile, uio_t uiop,
378				  SMBFID fid, int ioflag, vfs_context_t context);
379void smbfs_reconnect(struct smbmount *smp);
380int32_t smbfs_IObusy(struct smbmount *smp);
381void smbfs_ClearChildren(struct smbmount *smp, struct smbnode * parent);
382int smbfs_handle_lease_break(struct smbmount *smp, uint64_t lease_key_hi,
383                             uint64_t lease_key_low, uint32_t new_lease_state);
384
385#define smb_ubc_getsize(v) (vnode_vtype(v) == VREG ? ubc_getsize(v) : (off_t)0)
386
387#endif /* _FS_SMBFS_NODE_H_ */
388