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