summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authoramw <none@none>2007-10-25 16:34:29 -0700
committeramw <none@none>2007-10-25 16:34:29 -0700
commitda6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch)
tree65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/uts/common
parente845e33dd0d1aea22db7edaa8c7d43955d24609b (diff)
downloadillumos-gate-da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0.tar.gz
PSARC/2007/218 caller_context_t in all VOPs
PSARC/2007/227 VFS Feature Registration and ACL on Create PSARC/2007/244 ZFS Case-insensitive support PSARC/2007/315 Extensible Attribute Interfaces PSARC/2007/394 ls(1) new command line options '-/' and '-%': CIFS system attributes support PSARC/2007/403 Modified Access Checks for CIFS PSARC/2007/410 Add system attribute support to chmod(1) PSARC/2007/432 CIFS system attributes support for cp(1), pack(1), unpack(1), compress(1) and uncompress(1) PSARC/2007/444 Rescind SETTABLE Attribute PSARC/2007/459 CIFS system attributes support for cpio(1), pax(1), tar(1) PSARC/2007/546 Update utilities to match CIFS system attributes changes. PSARC/2007/560 ZFS sharesmb property 4890717 want append-only files 6417428 Case-insensitive file system name lookup to support CIFS 6417435 DOS attributes and additional timestamps to support for CIFS 6417442 File system quarantined and modified attributes to support an integrated Anti-Virus service 6417453 FS boolean property for rejecting/allowing invalid UTF-8 sequences in file names 6473733 RFE: Need support for open-deny modes 6473755 RFE: Need ability to reconcile oplock and delegation conflicts 6494624 sharemgr needs to support CIFS shares better 6546705 All vnode operations need to pass caller_context_t 6546706 Need VOP_SETATTR/VOP_GETATTR to support new, optional attributes 6546893 Solaris system attribute support 6550962 ZFS ACL inheritance needs to be enhanced to support Automatic Inheritance 6553589 RFE: VFS Feature Registration facility 6553770 RFE: ZFS support for ACL-on-CREATE (PSARC 2007/227) 6565581 ls(1) should support file system attributes proposed in PSARC/2007/315 6566784 NTFS streams are not copied along with the files. 6576205 cp(1), pack(1) and compress(1) should support file system attributes proposed in PSARC/2007/315 6578875 RFE: kernel interfaces for nbmand need improvement 6578883 RFE: VOP_SHRLOCK needs additional access types 6578885 chmod(1) should support file system attributes proposed in PSARC/2007/315 6578886 RFE: disallow nbmand state to change on remount 6583349 ACL parser needs to support audit/alarm ACE types 6590347 tar(1) should support filesystem attributes proposed in PSARC/2007/315 6597357 *tar* xv@ doesn't show the hidden directory even though it is restored 6597360 *tar* should re-init xattr info if openat() fails during extraction of and extended attribute 6597368 *tar* cannot restore hard linked extended attributes 6597374 *tar* doesn't display "x " when hard linked attributes are restored 6597375 *tar* extended attribute header off by one 6614861 *cpio* incorrectly archives extended system attributes with -@ 6614896 *pax* incorrectly archives extended system attributes with -@ 6615225 *tar* incorrectly archives extended system attributes with -@ 6617183 CIFS Service - PSARC 2006/715
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/Makefile.files121
-rw-r--r--usr/src/uts/common/Makefile.rules21
-rw-r--r--usr/src/uts/common/brand/lx/autofs/lx_autofs.c74
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c71
-rw-r--r--usr/src/uts/common/c2/audit.c29
-rw-r--r--usr/src/uts/common/c2/audit_event.c9
-rw-r--r--usr/src/uts/common/cpr/cpr_dump.c5
-rw-r--r--usr/src/uts/common/cpr/cpr_main.c10
-rw-r--r--usr/src/uts/common/cpr/cpr_misc.c18
-rw-r--r--usr/src/uts/common/fs/autofs/auto_vnops.c177
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_cnode.c26
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_cod.c15
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_dir.c25
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_dlog.c25
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_filegrp.c57
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_fscache.c38
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_ioctl.c85
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_log.c20
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_noopc.c13
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_resource.c19
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_strict.c17
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_subr.c54
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_vfsops.c13
-rw-r--r--usr/src/uts/common/fs/cachefs/cachefs_vnops.c311
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_all.c14
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_cdir.c9
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_ctl.c39
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_event.c69
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_latest.c30
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_root.c40
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_sym.c11
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_tdir.c14
-rw-r--r--usr/src/uts/common/fs/ctfs/ctfs_tmpl.c21
-rw-r--r--usr/src/uts/common/fs/dev/sdev_profile.c20
-rw-r--r--usr/src/uts/common/fs/dev/sdev_ptsops.c16
-rw-r--r--usr/src/uts/common/fs/dev/sdev_subr.c48
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/dev/sdev_vnops.c173
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_subr.c35
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_vnops.c71
-rw-r--r--usr/src/uts/common/fs/doorfs/door_sys.c26
-rw-r--r--usr/src/uts/common/fs/doorfs/door_vnops.c31
-rw-r--r--usr/src/uts/common/fs/fd/fdops.c21
-rw-r--r--usr/src/uts/common/fs/fem.c432
-rw-r--r--usr/src/uts/common/fs/fifofs/fifosubr.c17
-rw-r--r--usr/src/uts/common/fs/fifofs/fifovnops.c129
-rw-r--r--usr/src/uts/common/fs/fs_subr.c245
-rw-r--r--usr/src/uts/common/fs/fs_subr.h46
-rw-r--r--usr/src/uts/common/fs/fsflush.c6
-rw-r--r--usr/src/uts/common/fs/gfs.c74
-rw-r--r--usr/src/uts/common/fs/hsfs/hsfs_vfsops.c14
-rw-r--r--usr/src/uts/common/fs/hsfs/hsfs_vnops.c97
-rw-r--r--usr/src/uts/common/fs/lofs/lofs_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/lofs/lofs_vnops.c242
-rw-r--r--usr/src/uts/common/fs/lookup.c75
-rw-r--r--usr/src/uts/common/fs/mntfs/mntvnops.c27
-rw-r--r--usr/src/uts/common/fs/namefs/namevfs.c8
-rw-r--r--usr/src/uts/common/fs/namefs/namevno.c57
-rw-r--r--usr/src/uts/common/fs/nbmlock.c18
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_srv.c297
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_vnops.c274
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_acl.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_callback.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_client.c12
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c54
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_rnode.c6
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv.c368
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_attr.c38
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c81
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_ns.c17
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c29
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_state.c59
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c133
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_subr.c4
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c319
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_xdr.c5
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_acl_srv.c36
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_client.c23
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_common.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_dump.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_export.c26
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_log.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_server.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_srv.c127
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_subr.c10
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_vnops.c332
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_common.c18
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_data.c14
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_odir.c3
-rw-r--r--usr/src/uts/common/fs/objfs/objfs_root.c15
-rw-r--r--usr/src/uts/common/fs/pathname.c9
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_dir.c20
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_node.c3
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vfsops.c8
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vnops.c147
-rw-r--r--usr/src/uts/common/fs/portfs/port_fd.c6
-rw-r--r--usr/src/uts/common/fs/portfs/port_fop.c119
-rw-r--r--usr/src/uts/common/fs/portfs/port_vnops.c34
-rw-r--r--usr/src/uts/common/fs/proc/prcontrol.c2
-rw-r--r--usr/src/uts/common/fs/proc/prioctl.c51
-rw-r--r--usr/src/uts/common/fs/proc/prsubr.c16
-rw-r--r--usr/src/uts/common/fs/proc/prvnops.c83
-rw-r--r--usr/src/uts/common/fs/sharefs/sharefs_vnops.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_acl.c1310
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_alloc.c117
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_books.c170
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_check_directory.c126
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_close.c148
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_lock.c424
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c982
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_search.c344
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c2485
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_tree.c397
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_copy.c121
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create.c224
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create_directory.c272
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete.c354
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete_directory.c114
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c1574
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_echo.c132
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fem.c285
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find.c440
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c78
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find_unique.c286
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_flush.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_forward.c148
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsd.c276
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c2595
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_init.c796
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c137
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c266
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c159
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c217
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c100
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_svc.c709
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_locking_andx.c378
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c78
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mangle_name.c777
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c1659
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c334
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_memory_manager.c107
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_move.c114
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_negotiate.c478
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_net.c281
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_node.c770
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c77
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c373
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c255
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c110
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c613
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c213
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_odir.c456
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c726
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c431
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c539
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_print.c253
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_process_exit.c84
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information.c128
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information2.c111
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_read.c456
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rename.c347
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rpc.c532
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_sd.c862
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_search.c289
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_seek.c129
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c1252
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c516
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information.c128
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information2.c123
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c730
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_signing.c418
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_svc_sm.c1301
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c97
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c205
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c1142
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c137
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c559
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c434
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c588
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c163
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c414
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c179
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c733
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_connect.c107
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c213
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c110
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c87
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_upcalls.c104
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_user.c619
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_util.c2172
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vfs.c161
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vops.c1878
-rwxr-xr-xusr/src/uts/common/fs/smbsrv/smb_winpipe.c431
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write.c565
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write_raw.c606
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_xlate.c250
-rw-r--r--usr/src/uts/common/fs/smbsrv/smbsrv.conf27
-rw-r--r--usr/src/uts/common/fs/sockfs/nl7c.c26
-rw-r--r--usr/src/uts/common/fs/sockfs/nl7clogd.c25
-rw-r--r--usr/src/uts/common/fs/sockfs/socksctp.c8
-rw-r--r--usr/src/uts/common/fs/sockfs/socksctpvnops.c38
-rwxr-xr-xusr/src/uts/common/fs/sockfs/socksdp.c4
-rwxr-xr-xusr/src/uts/common/fs/sockfs/socksdpvnops.c38
-rw-r--r--usr/src/uts/common/fs/sockfs/socksubr.c2
-rw-r--r--usr/src/uts/common/fs/sockfs/socksyscalls.c35
-rw-r--r--usr/src/uts/common/fs/sockfs/socktpi.c10
-rw-r--r--usr/src/uts/common/fs/sockfs/sockvnops.c65
-rw-r--r--usr/src/uts/common/fs/specfs/specsubr.c6
-rw-r--r--usr/src/uts/common/fs/specfs/specvfsops.c12
-rw-r--r--usr/src/uts/common/fs/specfs/specvnops.c226
-rw-r--r--usr/src/uts/common/fs/swapfs/swap_subr.c2
-rw-r--r--usr/src/uts/common/fs/swapfs/swap_vnops.c40
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_dir.c5
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vfsops.c5
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vnops.c190
-rw-r--r--usr/src/uts/common/fs/udfs/udf_dir.c32
-rw-r--r--usr/src/uts/common/fs/udfs/udf_subr.c129
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vfsops.c19
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vnops.c383
-rw-r--r--usr/src/uts/common/fs/ufs/quotacalls.c4
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_directio.c8
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_extvnops.c11
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_filio.c4
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_lockfs.c2
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_subr.c3
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vfsops.c30
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vnops.c233
-rw-r--r--usr/src/uts/common/fs/vfs.c180
-rw-r--r--usr/src/uts/common/fs/vnode.c724
-rw-r--r--usr/src/uts/common/fs/xattr.c1428
-rw-r--r--usr/src/uts/common/fs/zfs/dmu.c8
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_deleg.c4
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_prop.c20
-rw-r--r--usr/src/uts/common/fs/zfs/spa_config.c4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu.h9
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_deleg.h1
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap.h51
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap_impl.h38
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zap_leaf.h20
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_acl.h148
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h3
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_dir.h12
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_fuid.h131
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_i18n.h71
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h9
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h10
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_znode.h88
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zil.h122
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_file.c10
-rw-r--r--usr/src/uts/common/fs/zfs/zap.c95
-rw-r--r--usr/src/uts/common/fs/zfs/zap_leaf.c176
-rw-r--r--usr/src/uts/common/fs/zfs/zap_micro.c357
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_acl.c2291
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_byteswap.c98
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ctldir.c60
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_dir.c210
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_fuid.c724
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c414
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_log.c359
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_replay.c544
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c174
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c923
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_znode.c126
-rw-r--r--usr/src/uts/common/fs/zfs/zil.c10
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c3
-rw-r--r--usr/src/uts/common/idmap/idmap_cache.c6
-rw-r--r--usr/src/uts/common/io/cons.c10
-rw-r--r--usr/src/uts/common/io/devinfo.c6
-rw-r--r--usr/src/uts/common/io/devpoll.c12
-rw-r--r--usr/src/uts/common/io/fssnap.c10
-rw-r--r--usr/src/uts/common/io/gentty.c8
-rw-r--r--usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c2
-rw-r--r--usr/src/uts/common/io/iwscons.c19
-rw-r--r--usr/src/uts/common/io/l_strplumb.c6
-rw-r--r--usr/src/uts/common/io/lofi.c11
-rw-r--r--usr/src/uts/common/io/lvm/trans/trans_ioctl.c17
-rw-r--r--usr/src/uts/common/io/physmem.c18
-rw-r--r--usr/src/uts/common/io/rsm/rsmops.c11
-rw-r--r--usr/src/uts/common/io/sysmsg.c19
-rw-r--r--usr/src/uts/common/ipp/ipgpc/classifier.c2
-rw-r--r--usr/src/uts/common/ipp/ipgpc/filters.c8
-rw-r--r--usr/src/uts/common/krtld/kobj.c12
-rw-r--r--usr/src/uts/common/ktli/t_kopen.c10
-rw-r--r--usr/src/uts/common/nfs/nfs.h8
-rw-r--r--usr/src/uts/common/nfs/nfs4.h13
-rw-r--r--usr/src/uts/common/nfs/rnode.h4
-rw-r--r--usr/src/uts/common/os/acct.c14
-rw-r--r--usr/src/uts/common/os/core.c17
-rw-r--r--usr/src/uts/common/os/cred.c53
-rw-r--r--usr/src/uts/common/os/devcache.c7
-rw-r--r--usr/src/uts/common/os/driver.c6
-rw-r--r--usr/src/uts/common/os/driver_lyr.c14
-rw-r--r--usr/src/uts/common/os/dumpsubr.c29
-rw-r--r--usr/src/uts/common/os/exacct.c2
-rw-r--r--usr/src/uts/common/os/exec.c12
-rw-r--r--usr/src/uts/common/os/fio.c11
-rw-r--r--usr/src/uts/common/os/flock.c39
-rw-r--r--usr/src/uts/common/os/grow.c31
-rw-r--r--usr/src/uts/common/os/inst_sync.c11
-rw-r--r--usr/src/uts/common/os/mem_config.c6
-rw-r--r--usr/src/uts/common/os/modctl.c4
-rw-r--r--usr/src/uts/common/os/policy.c153
-rw-r--r--usr/src/uts/common/os/priv_defs12
-rw-r--r--usr/src/uts/common/os/session.c20
-rw-r--r--usr/src/uts/common/os/share.c194
-rw-r--r--usr/src/uts/common/os/sid.c2
-rw-r--r--usr/src/uts/common/os/tlabel.c2
-rw-r--r--usr/src/uts/common/os/urw.c11
-rw-r--r--usr/src/uts/common/os/vm_pageout.c4
-rw-r--r--usr/src/uts/common/os/zone.c7
-rw-r--r--usr/src/uts/common/smbsrv/Makefile131
-rw-r--r--usr/src/uts/common/smbsrv/alloc.h89
-rw-r--r--usr/src/uts/common/smbsrv/cifs.h1161
-rw-r--r--usr/src/uts/common/smbsrv/codepage.h85
-rw-r--r--usr/src/uts/common/smbsrv/cp_cyrillic.h312
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin1.h317
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin2.h314
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin3.h311
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin4.h312
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin5.h311
-rw-r--r--usr/src/uts/common/smbsrv/cp_latin6.h309
-rw-r--r--usr/src/uts/common/smbsrv/cp_unicode.h6639
-rw-r--r--usr/src/uts/common/smbsrv/cp_usascii.h310
-rw-r--r--usr/src/uts/common/smbsrv/crypt.h45
-rw-r--r--usr/src/uts/common/smbsrv/ctype.h76
-rw-r--r--usr/src/uts/common/smbsrv/doserror.h145
-rwxr-xr-xusr/src/uts/common/smbsrv/hash_table.h192
-rw-r--r--usr/src/uts/common/smbsrv/lm.h47
-rw-r--r--usr/src/uts/common/smbsrv/lmdfs.h67
-rw-r--r--usr/src/uts/common/smbsrv/lmerr.h536
-rw-r--r--usr/src/uts/common/smbsrv/lmshare.h195
-rw-r--r--usr/src/uts/common/smbsrv/lmshare_door.h116
-rw-r--r--usr/src/uts/common/smbsrv/lsalib.h164
-rw-r--r--usr/src/uts/common/smbsrv/mac_cifs.h112
-rw-r--r--usr/src/uts/common/smbsrv/mailslot.h76
-rw-r--r--usr/src/uts/common/smbsrv/mbuf.h269
-rw-r--r--usr/src/uts/common/smbsrv/mlrpc.h414
-rw-r--r--usr/src/uts/common/smbsrv/mlsvc.h233
-rw-r--r--usr/src/uts/common/smbsrv/mlsvc_util.h244
-rw-r--r--usr/src/uts/common/smbsrv/msgbuf.h124
-rw-r--r--usr/src/uts/common/smbsrv/ndl/dssetup.ndl168
-rw-r--r--usr/src/uts/common/smbsrv/ndl/eventlog.ndl204
-rw-r--r--usr/src/uts/common/smbsrv/ndl/llsrpc.ndl110
-rw-r--r--usr/src/uts/common/smbsrv/ndl/lsarpc.ndl801
-rw-r--r--usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl166
-rw-r--r--usr/src/uts/common/smbsrv/ndl/netdfs.ndl493
-rw-r--r--usr/src/uts/common/smbsrv/ndl/netlogon.ndl395
-rw-r--r--usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl552
-rw-r--r--usr/src/uts/common/smbsrv/ndl/samrpc.ndl1314
-rw-r--r--usr/src/uts/common/smbsrv/ndl/spoolss.ndl489
-rw-r--r--usr/src/uts/common/smbsrv/ndl/srvsvc.ndl1331
-rw-r--r--usr/src/uts/common/smbsrv/ndl/svcctl.ndl287
-rw-r--r--usr/src/uts/common/smbsrv/ndl/winreg.ndl288
-rw-r--r--usr/src/uts/common/smbsrv/ndr.h468
-rw-r--r--usr/src/uts/common/smbsrv/netbios.h147
-rw-r--r--usr/src/uts/common/smbsrv/netrauth.h162
-rw-r--r--usr/src/uts/common/smbsrv/nmpipes.h165
-rw-r--r--usr/src/uts/common/smbsrv/ntaccess.h237
-rw-r--r--usr/src/uts/common/smbsrv/nterror.h941
-rw-r--r--usr/src/uts/common/smbsrv/ntifs.h216
-rw-r--r--usr/src/uts/common/smbsrv/ntlocale.h330
-rw-r--r--usr/src/uts/common/smbsrv/ntsid.h304
-rw-r--r--usr/src/uts/common/smbsrv/ntstatus.h595
-rw-r--r--usr/src/uts/common/smbsrv/oem.h106
-rw-r--r--usr/src/uts/common/smbsrv/samlib.h159
-rw-r--r--usr/src/uts/common/smbsrv/smb.h272
-rw-r--r--usr/src/uts/common/smbsrv/smb_common_door.h130
-rw-r--r--usr/src/uts/common/smbsrv/smb_door_svc.h202
-rw-r--r--usr/src/uts/common/smbsrv/smb_fsd.h90
-rw-r--r--usr/src/uts/common/smbsrv/smb_fsops.h153
-rw-r--r--usr/src/uts/common/smbsrv/smb_i18n.h41
-rw-r--r--usr/src/uts/common/smbsrv/smb_idmap.h100
-rw-r--r--usr/src/uts/common/smbsrv/smb_incl.h121
-rwxr-xr-xusr/src/uts/common/smbsrv/smb_ioctl.h45
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h602
-rw-r--r--usr/src/uts/common/smbsrv/smb_privilege.h197
-rw-r--r--usr/src/uts/common/smbsrv/smb_secdesc.h397
-rw-r--r--usr/src/uts/common/smbsrv/smb_svc_sm.h162
-rw-r--r--usr/src/uts/common/smbsrv/smb_token.h224
-rw-r--r--usr/src/uts/common/smbsrv/smb_vops.h386
-rwxr-xr-xusr/src/uts/common/smbsrv/smb_winpipe.h84
-rw-r--r--usr/src/uts/common/smbsrv/smb_xdr.h111
-rw-r--r--usr/src/uts/common/smbsrv/smbfmt.h56
-rw-r--r--usr/src/uts/common/smbsrv/smbinfo.h181
-rw-r--r--usr/src/uts/common/smbsrv/smbtrans.h70
-rw-r--r--usr/src/uts/common/smbsrv/smbvar.h1402
-rw-r--r--usr/src/uts/common/smbsrv/string.h75
-rw-r--r--usr/src/uts/common/smbsrv/svrapi.h263
-rw-r--r--usr/src/uts/common/smbsrv/winioctl.h475
-rw-r--r--usr/src/uts/common/smbsrv/winsvc.h217
-rw-r--r--usr/src/uts/common/smbsrv/wintypes.h62
-rw-r--r--usr/src/uts/common/sys/Makefile4
-rw-r--r--usr/src/uts/common/sys/acl.h49
-rw-r--r--usr/src/uts/common/sys/acl_impl.h61
-rw-r--r--usr/src/uts/common/sys/attr.h148
-rw-r--r--usr/src/uts/common/sys/byteorder.h64
-rw-r--r--usr/src/uts/common/sys/cred.h2
-rw-r--r--usr/src/uts/common/sys/ctfs_impl.h22
-rw-r--r--usr/src/uts/common/sys/epm.h13
-rw-r--r--usr/src/uts/common/sys/extdirent.h77
-rw-r--r--usr/src/uts/common/sys/fcntl.h3
-rw-r--r--usr/src/uts/common/sys/fem.h208
-rw-r--r--usr/src/uts/common/sys/file.h14
-rw-r--r--usr/src/uts/common/sys/fs/fifonode.h11
-rw-r--r--usr/src/uts/common/sys/fs/pc_node.h6
-rw-r--r--usr/src/uts/common/sys/fs/snode.h3
-rw-r--r--usr/src/uts/common/sys/fs/tmp.h9
-rw-r--r--usr/src/uts/common/sys/fs/udf_inode.h11
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h30
-rw-r--r--usr/src/uts/common/sys/gfs.h24
-rw-r--r--usr/src/uts/common/sys/modctl.h2
-rw-r--r--usr/src/uts/common/sys/nbmlock.h17
-rw-r--r--usr/src/uts/common/sys/objfs_impl.h15
-rw-r--r--usr/src/uts/common/sys/policy.h2
-rw-r--r--usr/src/uts/common/sys/sid.h2
-rw-r--r--usr/src/uts/common/sys/socketvar.h25
-rw-r--r--usr/src/uts/common/sys/tzfile.h166
-rw-r--r--usr/src/uts/common/sys/unistd.h10
-rw-r--r--usr/src/uts/common/sys/vfs.h68
-rw-r--r--usr/src/uts/common/sys/vnode.h681
-rw-r--r--usr/src/uts/common/syscall/access.c2
-rw-r--r--usr/src/uts/common/syscall/acctctl.c14
-rw-r--r--usr/src/uts/common/syscall/acl.c28
-rw-r--r--usr/src/uts/common/syscall/chdir.c8
-rw-r--r--usr/src/uts/common/syscall/fcntl.c21
-rw-r--r--usr/src/uts/common/syscall/fdsync.c11
-rw-r--r--usr/src/uts/common/syscall/fsat.c36
-rw-r--r--usr/src/uts/common/syscall/getdents.c11
-rw-r--r--usr/src/uts/common/syscall/ioctl.c11
-rw-r--r--usr/src/uts/common/syscall/lseek.c31
-rw-r--r--usr/src/uts/common/syscall/open.c77
-rw-r--r--usr/src/uts/common/syscall/pathconf.c8
-rw-r--r--usr/src/uts/common/syscall/pipe.c9
-rw-r--r--usr/src/uts/common/syscall/poll.c8
-rw-r--r--usr/src/uts/common/syscall/readlink.c6
-rw-r--r--usr/src/uts/common/syscall/rw.c32
-rw-r--r--usr/src/uts/common/syscall/sendfile.c2
-rw-r--r--usr/src/uts/common/syscall/stat.c9
-rw-r--r--usr/src/uts/common/syscall/symlink.c4
-rw-r--r--usr/src/uts/common/syscall/ucredsys.c4
-rw-r--r--usr/src/uts/common/vm/seg_dev.c14
-rw-r--r--usr/src/uts/common/vm/seg_kp.c8
-rw-r--r--usr/src/uts/common/vm/seg_map.c16
-rw-r--r--usr/src/uts/common/vm/seg_vn.c56
-rw-r--r--usr/src/uts/common/vm/vm_anon.c19
-rw-r--r--usr/src/uts/common/vm/vm_as.c4
-rw-r--r--usr/src/uts/common/vm/vm_page.c32
-rw-r--r--usr/src/uts/common/vm/vm_rm.c10
-rw-r--r--usr/src/uts/common/vm/vm_swap.c25
-rw-r--r--usr/src/uts/common/vm/vpm.c8
452 files changed, 89986 insertions, 5361 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index c86259c8b1..a4d01364f1 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -175,9 +175,9 @@ GENUNIX_OBJS += \
ioctl.o \
issetugid.o \
ippconf.o \
- kiconv.o \
- kdi.o \
kcpc.o \
+ kdi.o \
+ kiconv.o \
kmem.o \
ksyms_snapshot.o \
l_strplumb.o \
@@ -359,6 +359,8 @@ GENUNIX_OBJS += \
watchpoint.o \
yield.o \
scsi_confdata.o \
+ xattr.o \
+ xattr_common.o \
xdr_mblk.o \
xdr_mem.o \
xdr.o \
@@ -878,6 +880,120 @@ NFSSRV_OBJS += nfs_server.o nfs_srv.o nfs3_srv.o \
nfs4_srv_ns.o nfs4_db.o nfs4_srv_deleg.o \
nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o
+SMBSRV_SHARED_OBJS += \
+ smb_match.o \
+ smb_msgbuf.o \
+ smb_oem.o \
+ smb_opmlang.o \
+ smb_strcase.o \
+ smb_string.o \
+ smb_utf8.o \
+ smb_common_door_decode.o \
+ smb_xdr_utils.o \
+ smb_token.o \
+ smb_token_xdr.o \
+ smb_sid.o \
+ smb_status_xlat.o \
+ smb_native.o \
+ smb_netbios_util.o \
+ smb_share_door_decode.o
+
+SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
+ smb_acl.o \
+ smb_alloc.o \
+ smb_books.o \
+ smb_check_directory.o \
+ smb_close.o \
+ smb_common_lock.o \
+ smb_common_open.o \
+ smb_common_search.o \
+ smb_common_transact.o \
+ smb_common_tree.o \
+ smb_copy.o \
+ smb_create.o \
+ smb_create_directory.o \
+ smb_delete.o \
+ smb_delete_directory.o \
+ smb_dispatch.o \
+ smb_echo.o \
+ smb_fem.o \
+ smb_find.o \
+ smb_find_notify_close.o \
+ smb_find_unique.o \
+ smb_flush.o \
+ smb_forward.o \
+ smb_fsd.o \
+ smb_fsops.o \
+ smb_init.o \
+ smb_kdoor_encdec.o \
+ smb_kdoor_ops.o \
+ smb_kdoor_clnt.o \
+ smb_kdoor_srv.o \
+ smb_lock_byte_range.o \
+ smb_lock_svc.o \
+ smb_locking_andx.o \
+ smb_logoff_andx.o \
+ smb_mangle_name.o \
+ smb_mbuf_marshaling.o \
+ smb_memory_manager.o \
+ smb_mbuf_util.o \
+ smb_move.o \
+ smb_negotiate.o \
+ smb_net.o \
+ smb_node.o \
+ smb_nt_cancel.o \
+ smb_nt_create_andx.o \
+ smb_nt_transact_create.o \
+ smb_nt_transact_ioctl.o \
+ smb_nt_transact_notify_change.o \
+ smb_nt_transact_security.o \
+ smb_odir.o \
+ smb_ofile.o \
+ smb_open_andx.o \
+ smb_path_name_reduction.o \
+ smb_print.o \
+ smb_process_exit.o \
+ smb_query_information.o \
+ smb_query_information2.o \
+ smb_query_information_disk.o \
+ smb_read.o \
+ smb_rename.o \
+ smb_rpc.o \
+ smb_sd.o \
+ smb_search.o \
+ smb_seek.o \
+ smb_session.o \
+ smb_session_setup_andx.o \
+ smb_svc_sm.o \
+ smb_set_information.o \
+ smb_set_information2.o \
+ smb_signing.o \
+ smb_share_kdoor_client.o \
+ smb_tree.o \
+ smb_trans2_create_directory.o \
+ smb_trans2_dfs.o \
+ smb_trans2_find.o \
+ smb_trans2_open2.o \
+ smb_trans2_query_file_info.o \
+ smb_trans2_query_fs_information.o \
+ smb_trans2_query_path_info.o \
+ smb_trans2_set_file_information.o \
+ smb_trans2_set_information.o \
+ smb_trans2_set_path_information.o \
+ smb_tree_connect.o \
+ smb_tree_connect_andx.o \
+ smb_tree_disconnect.o \
+ smb_unlock_byte_range.o \
+ smb_upcalls.o \
+ smb_user.o \
+ smb_util.o \
+ smb_vfs.o \
+ smb_vops.o \
+ smb_winpipe.o \
+ smb_write.o \
+ smb_write_raw.o \
+ smb_xlate.o
+
PCFS_OBJS += pc_alloc.o pc_dir.o pc_node.o pc_subr.o \
pc_vfsops.o pc_vnops.o
@@ -1006,6 +1122,7 @@ ZFS_OBJS += \
zfs_acl.o \
zfs_ctldir.o \
zfs_dir.o \
+ zfs_fuid.o \
zfs_ioctl.o \
zfs_log.o \
zfs_replay.o \
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index d843b1b9b4..9e7f6a84a5 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -222,6 +222,14 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/nfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/smbsrv/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/smbsrv/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/objfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -270,6 +278,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/zfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(COMMONBASE)/xattr/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(COMMONBASE)/zfs/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1142,6 +1154,12 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/mntfs/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/namefs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(COMMONBASE)/smbsrv/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/smbsrv/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/nfs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
@@ -1184,6 +1202,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/ufs_log/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/zfs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(COMMONBASE)/xattr/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(COMMONBASE)/zfs/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/brand/lx/autofs/lx_autofs.c b/usr/src/uts/common/brand/lx/autofs/lx_autofs.c
index b40b508625..c4c9e96815 100644
--- a/usr/src/uts/common/brand/lx/autofs/lx_autofs.c
+++ b/usr/src/uts/common/brand/lx/autofs/lx_autofs.c
@@ -442,7 +442,7 @@ i_fifo_lookup(pid_t pgrp, int fd, file_t **fpp_wr, file_t **fpp_rd)
}
/*
- * We need to drop fi_lock before we can try to aquire f_tlock
+ * We need to drop fi_lock before we can try to acquire f_tlock
* the good news is that the file pointers are protected because
* we're still holding uf_lock.
*/
@@ -707,7 +707,7 @@ i_bs_readdir(vnode_t *dvp, list_t *dir_stack, list_t *file_stack)
iov.iov_len = dlen;
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- if (VOP_READDIR(dvp, &uio, kcred, &eof) != 0) {
+ if (VOP_READDIR(dvp, &uio, kcred, &eof, NULL, 0) != 0) {
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
kmem_free(dbuf, dlen);
return (-1);
@@ -727,8 +727,8 @@ i_bs_readdir(vnode_t *dvp, list_t *dir_stack, list_t *file_stack)
if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
continue;
- if (VOP_LOOKUP(dvp,
- nm, &vp, NULL, 0, NULL, kcred) != 0) {
+ if (VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) != 0) {
kmem_free(dbuf, dlen);
return (-1);
}
@@ -763,7 +763,8 @@ i_bs_destroy(vnode_t *dvp, char *path)
char *dpath, *fpath;
int ret;
- if (VOP_LOOKUP(dvp, path, &vp, NULL, 0, NULL, kcred) != 0) {
+ if (VOP_LOOKUP(dvp, path, &vp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) != 0) {
/* A directory entry with this name doesn't actually exist. */
return;
}
@@ -771,7 +772,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
if ((vp->v_type & VDIR) == 0) {
/* Easy, the directory entry is a file so delete it. */
VN_RELE(vp);
- (void) VOP_REMOVE(dvp, path, kcred);
+ (void) VOP_REMOVE(dvp, path, kcred, NULL, 0);
return;
}
@@ -796,7 +797,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
if (i_bs_readdir(dvp, &search_stack, NULL) != 0)
goto exit;
- /* Save the current directory a seperate stack. */
+ /* Save the current directory a separate stack. */
i_stack_push(&dir_stack, (caddr_t)pdvp, (caddr_t)dvp, dpath);
}
@@ -818,7 +819,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
while (i_stack_pop(&file_stack,
NULL, (caddr_t *)&vp, &fpath) == 0) {
VN_RELE(vp)
- ret = VOP_REMOVE(dvp, fpath, kcred);
+ ret = VOP_REMOVE(dvp, fpath, kcred, NULL, 0);
i_strfree(fpath);
if (ret != 0) {
i_strfree(dpath);
@@ -828,7 +829,7 @@ i_bs_destroy(vnode_t *dvp, char *path)
/* Delete this directory. */
VN_RELE(dvp);
- ret = VOP_RMDIR(pdvp, dpath, pdvp, kcred);
+ ret = VOP_RMDIR(pdvp, dpath, pdvp, kcred, NULL, 0);
i_strfree(dpath);
if (ret != 0)
goto exit;
@@ -862,7 +863,7 @@ i_bs_create(vnode_t *dvp, char *bs_name)
vattr.va_mode = 0755; /* u+rwx,og=rx */
vattr.va_mask = AT_TYPE|AT_MODE;
- if (VOP_MKDIR(dvp, bs_name, &vattr, &vp, kcred) != 0)
+ if (VOP_MKDIR(dvp, bs_name, &vattr, &vp, kcred, NULL, 0, NULL) != 0)
return (NULL);
return (vp);
}
@@ -1220,24 +1221,27 @@ static const fs_operation_def_t lx_autofs_vfstops[] = {
* the underlying filesystem we're mounted on.
*/
static int
-lx_autofs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+lx_autofs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
- return (VOP_CLOSE(uvp, flag, count, offset, cr));
+ return (VOP_CLOSE(uvp, flag, count, offset, cr, ctp));
}
static int
-lx_autofs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+lx_autofs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ctp, int flags)
{
vnode_t *uvp = vp->v_data;
- return (VOP_READDIR(uvp, uiop, cr, eofp));
+ return (VOP_READDIR(uvp, uiop, cr, eofp, ctp, flags));
}
static int
-lx_autofs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+lx_autofs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
- return (VOP_ACCESS(uvp, mode, flags, cr));
+ return (VOP_ACCESS(uvp, mode, flags, cr, ctp));
}
static int
@@ -1256,7 +1260,8 @@ lx_autofs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
/*ARGSUSED*/
static int
-lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ctp, int flags)
{
vnode_t *udvp = dvp->v_data;
@@ -1269,10 +1274,10 @@ lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
*/
if (vn_matchops(cdir, lx_autofs_vn_ops)) {
vnode_t *ucdir = cdir->v_data;
- return (VOP_RMDIR(udvp, nm, ucdir, cr));
+ return (VOP_RMDIR(udvp, nm, ucdir, cr, ctp, flags));
}
- return (VOP_RMDIR(udvp, nm, cdir, cr));
+ return (VOP_RMDIR(udvp, nm, cdir, cr, ctp, flags));
}
/*
@@ -1280,17 +1285,17 @@ lx_autofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
*
* For some VOP entry points we will first pass the request on to
* the underlying filesystem we're mounted on. If there's an error
- * then we immediatly return the error, but if the request succeedes
+ * then we immediately return the error, but if the request succeeds
* we have to do some extra work before returning.
*/
static int
-lx_autofs_open(vnode_t **vpp, int flag, cred_t *cr)
+lx_autofs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ctp)
{
vnode_t *ovp = *vpp;
vnode_t *uvp = ovp->v_data;
int error;
- if ((error = VOP_OPEN(&uvp, flag, cr)) != 0)
+ if ((error = VOP_OPEN(&uvp, flag, cr, ctp)) != 0)
return (error);
/* Check for clone opens. */
@@ -1304,12 +1309,13 @@ lx_autofs_open(vnode_t **vpp, int flag, cred_t *cr)
}
static int
-lx_autofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+lx_autofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
int error;
- if ((error = VOP_GETATTR(uvp, vap, flags, cr)) != 0)
+ if ((error = VOP_GETATTR(uvp, vap, flags, cr, ctp)) != 0)
return (error);
/* Update the attributes with our filesystem id. */
@@ -1319,13 +1325,14 @@ lx_autofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
static int
lx_autofs_mkdir(vnode_t *dvp, char *nm, struct vattr *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ctp, int flags, vsecattr_t *vsecp)
{
vnode_t *udvp = dvp->v_data;
vnode_t *uvp = NULL;
int error;
- if ((error = VOP_MKDIR(udvp, nm, vap, &uvp, cr)) != 0)
+ if ((error = VOP_MKDIR(udvp, nm, vap, &uvp, cr,
+ ctp, flags, vsecp)) != 0)
return (error);
/* Update the attributes with our filesystem id. */
@@ -1341,7 +1348,7 @@ lx_autofs_mkdir(vnode_t *dvp, char *nm, struct vattr *vap, vnode_t **vpp,
*/
/*ARGSUSED*/
static void
-lx_autofs_inactive(struct vnode *vp, struct cred *cr)
+lx_autofs_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ctp)
{
lx_autofs_vfs_t *data = vp->v_vfsp->vfs_data;
@@ -1374,14 +1381,16 @@ lx_autofs_inactive(struct vnode *vp, struct cred *cr)
static int
lx_autofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ctp,
+ int *direntflags, pathname_t *realpnp)
{
vnode_t *udvp = dvp->v_data;
vnode_t *uvp = NULL;
int error;
/* First try to lookup if this path component already exitst. */
- if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr)) == 0) {
+ if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr, ctp,
+ direntflags, realpnp)) == 0) {
*vpp = i_vn_alloc(dvp->v_vfsp, uvp);
return (0);
}
@@ -1395,7 +1404,8 @@ lx_autofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
return (error);
/* Retry the lookup operation. */
- if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr)) == 0) {
+ if ((error = VOP_LOOKUP(udvp, nm, &uvp, pnp, flags, rdir, cr, ctp,
+ direntflags, realpnp)) == 0) {
*vpp = i_vn_alloc(dvp->v_vfsp, uvp);
return (0);
}
@@ -1405,7 +1415,7 @@ lx_autofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
/*ARGSUSED*/
static int
lx_autofs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ctp)
{
vnode_t *uvp = vp->v_data;
@@ -1421,7 +1431,7 @@ lx_autofs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr,
}
/* Pass any remaining ioctl on. */
- return (VOP_IOCTL(uvp, cmd, arg, mode, cr, rvalp));
+ return (VOP_IOCTL(uvp, cmd, arg, mode, cr, rvalp, ctp));
}
/*
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index a09f9fb2b7..588ca2e422 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -32,7 +32,7 @@
*
* In order to preserve Solaris' security policy. This file system's
* functionality does not override Solaris' security policies even if
- * that means breaking Linux compatability.
+ * that means breaking Linux compatibility.
*
* Linux has no concept of lwps so we only implement procs here as in the
* old /proc interface.
@@ -75,19 +75,23 @@ extern time_t boot_time;
*/
vnodeops_t *lxpr_vnodeops;
-static int lxpr_open(vnode_t **, int, cred_t *);
-static int lxpr_close(vnode_t *, int, int, offset_t, cred_t *);
+static int lxpr_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int lxpr_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int lxpr_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
-static int lxpr_getattr(vnode_t *, vattr_t *, int, cred_t *);
-static int lxpr_access(vnode_t *, int, int, cred_t *);
+static int lxpr_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
+static int lxpr_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int lxpr_lookup(vnode_t *, char *, vnode_t **,
- pathname_t *, int, vnode_t *, cred_t *);
-static int lxpr_readdir(vnode_t *, uio_t *, cred_t *, int *);
-static int lxpr_readlink(vnode_t *, uio_t *, cred_t *);
-static int lxpr_cmp(vnode_t *, vnode_t *);
-static int lxpr_realvp(vnode_t *, vnode_t **);
+ pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
+ pathname_t *);
+static int lxpr_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+static int lxpr_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
+static int lxpr_cmp(vnode_t *, vnode_t *, caller_context_t *);
+static int lxpr_realvp(vnode_t *, vnode_t **, caller_context_t *);
static int lxpr_sync(void);
-static void lxpr_inactive(vnode_t *, cred_t *);
+static void lxpr_inactive(vnode_t *, cred_t *, caller_context_t *);
static vnode_t *lxpr_lookup_procdir(vnode_t *, char *);
static vnode_t *lxpr_lookup_piddir(vnode_t *, char *);
@@ -243,7 +247,7 @@ static lxpr_dirent_t netdir[] = {
* lxpr_open(): Vnode operation for VOP_OPEN()
*/
static int
-lxpr_open(vnode_t **vpp, int flag, cred_t *cr)
+lxpr_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
lxpr_node_t *lxpnp = VTOLXP(vp);
@@ -272,7 +276,7 @@ lxpr_open(vnode_t **vpp, int flag, cred_t *cr)
* Need to hold rvp since VOP_OPEN() may release it.
*/
VN_HOLD(rvp);
- error = VOP_OPEN(&rvp, flag, cr);
+ error = VOP_OPEN(&rvp, flag, cr, ct);
if (error) {
VN_RELE(rvp);
} else {
@@ -317,7 +321,8 @@ lxpr_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static int
-lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+lxpr_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
lxpr_node_t *lxpr = VTOLXP(vp);
lxpr_nodetype_t type = lxpr->lxpr_type;
@@ -705,7 +710,8 @@ lxpr_read_pid_maps(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
*buf = '\0';
if (pbuf->vp != NULL) {
vattr.va_mask = AT_FSID | AT_NODEID;
- if (VOP_GETATTR(pbuf->vp, &vattr, 0, CRED()) == 0) {
+ if (VOP_GETATTR(pbuf->vp, &vattr, 0, CRED(),
+ NULL) == 0) {
maj = getmajor(vattr.va_fsid);
min = getminor(vattr.va_fsid);
inode = vattr.va_nodeid;
@@ -2042,7 +2048,8 @@ lxpr_read_fd(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
* lxpr_getattr(): Vnode operation for VOP_GETATTR()
*/
static int
-lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
register lxpr_node_t *lxpnp = VTOLXP(vp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -2060,14 +2067,14 @@ lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/*
* withold attribute information to owner or root
*/
- if ((error = VOP_ACCESS(rvp, 0, 0, cr)) != 0) {
+ if ((error = VOP_ACCESS(rvp, 0, 0, cr, ct)) != 0) {
return (error);
}
/*
* now its attributes
*/
- if ((error = VOP_GETATTR(rvp, vap, flags, cr)) != 0) {
+ if ((error = VOP_GETATTR(rvp, vap, flags, cr, ct)) != 0) {
return (error);
}
@@ -2122,7 +2129,7 @@ lxpr_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
* lxpr_access(): Vnode operation for VOP_ACCESS()
*/
static int
-lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
lxpr_node_t *lxpnp = VTOLXP(vp);
int shift = 0;
@@ -2162,7 +2169,7 @@ lxpr_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/*
* For these we use the underlying vnode's accessibility.
*/
- return (VOP_ACCESS(lxpnp->lxpr_realvp, mode, flags, cr));
+ return (VOP_ACCESS(lxpnp->lxpr_realvp, mode, flags, cr, ct));
}
/* If user is root allow access regardless of permission bits */
@@ -2207,7 +2214,8 @@ lxpr_lookup_not_a_dir(vnode_t *dp, char *comp)
/* ARGSUSED */
static int
lxpr_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
lxpr_node_t *lxpnp = VTOLXP(dp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -2227,7 +2235,7 @@ lxpr_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
/*
* restrict lookup permission to owner or root
*/
- if ((error = lxpr_access(dp, VEXEC, 0, cr)) != 0) {
+ if ((error = lxpr_access(dp, VEXEC, 0, cr, ct)) != 0) {
return (error);
}
@@ -2477,7 +2485,8 @@ lxpr_lookup_procdir(vnode_t *dp, char *comp)
*/
/* ARGSUSED */
static int
-lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp)
+lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
lxpr_node_t *lxpnp = VTOLXP(dp);
lxpr_nodetype_t type = lxpnp->lxpr_type;
@@ -2499,7 +2508,7 @@ lxpr_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp)
/*
* restrict readdir permission to owner or root
*/
- if ((error = lxpr_access(dp, VREAD, 0, cr)) != 0)
+ if ((error = lxpr_access(dp, VREAD, 0, cr, ct)) != 0)
return (error);
uoffset = uiop->uio_offset;
@@ -2909,7 +2918,7 @@ out:
*/
/* ARGSUSED */
static int
-lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
char bp[MAXPATHLEN + 1];
size_t buflen = sizeof (bp);
@@ -2924,7 +2933,7 @@ lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
/* Try to produce a symlink name for anything that has a realvp */
if (rvp != NULL) {
- if ((error = lxpr_access(vp, VREAD, 0, CRED())) != 0)
+ if ((error = lxpr_access(vp, VREAD, 0, CRED(), ct)) != 0)
return (error);
if ((error = vnodetopath(NULL, rvp, bp, buflen, CRED())) != 0)
return (error);
@@ -2971,7 +2980,7 @@ lxpr_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
*/
/* ARGSUSED */
static void
-lxpr_inactive(vnode_t *vp, cred_t *cr)
+lxpr_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
lxpr_freenode(VTOLXP(vp));
}
@@ -2995,7 +3004,7 @@ lxpr_sync()
* lxpr_cmp(): Vnode operation for VOP_CMP()
*/
static int
-lxpr_cmp(vnode_t *vp1, vnode_t *vp2)
+lxpr_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
vnode_t *rvp;
@@ -3007,7 +3016,7 @@ lxpr_cmp(vnode_t *vp1, vnode_t *vp2)
vp2 = rvp;
if (vn_matchops(vp1, lxpr_vnodeops) || vn_matchops(vp2, lxpr_vnodeops))
return (vp1 == vp2);
- return (VOP_CMP(vp1, vp2));
+ return (VOP_CMP(vp1, vp2, ct));
}
@@ -3015,13 +3024,13 @@ lxpr_cmp(vnode_t *vp1, vnode_t *vp2)
* lxpr_realvp(): Vnode operation for VOP_REALVP()
*/
static int
-lxpr_realvp(vnode_t *vp, vnode_t **vpp)
+lxpr_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
vnode_t *rvp;
if ((rvp = VTOLXP(vp)->lxpr_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
diff --git a/usr/src/uts/common/c2/audit.c b/usr/src/uts/common/c2/audit.c
index 944c1e8a28..a01733a956 100644
--- a/usr/src/uts/common/c2/audit.c
+++ b/usr/src/uts/common/c2/audit.c
@@ -468,7 +468,7 @@ audit_addcomponent(struct pathname *pnp)
* flag = 1, path is absolute. Free any saved path and set flag to PAD_ABSPATH.
*
* If the (new) path is absolute, then we have to throw away whatever we have
- * already accumulated since it is being superceeded by new path which is
+ * already accumulated since it is being superseded by new path which is
* anchored at the root.
* Note that if the path is relative, this function does nothing
* TODO:
@@ -641,7 +641,7 @@ file_is_public(struct vattr *attr)
/*
* ROUTINE: AUDIT_ATTRIBUTES
- * PURPOSE: Audit the attributes so we can tell why the error occured
+ * PURPOSE: Audit the attributes so we can tell why the error occurred
* CALLBY: AUDIT_SAVEPATH
* AUDIT_VNCREATE_FINISH
* AUS_FCHOWN...audit_event.c...audit_path.c
@@ -659,7 +659,7 @@ audit_attributes(struct vnode *vp)
if (vp) {
attr.va_mask = AT_ALL;
- if (VOP_GETATTR(vp, &attr, 0, CRED()) != 0)
+ if (VOP_GETATTR(vp, &attr, 0, CRED(), NULL) != 0)
return;
if (file_is_public(&attr) && (tad->tad_ctrl & PAD_PUBLIC_EV)) {
@@ -1047,7 +1047,7 @@ audit_closef(struct file *fp)
*/
if ((vp = fp->f_vnode) != NULL) {
attr.va_mask = AT_ALL;
- getattr_ret = VOP_GETATTR(vp, &attr, 0, CRED());
+ getattr_ret = VOP_GETATTR(vp, &attr, 0, CRED(), NULL);
}
/*
@@ -1294,7 +1294,14 @@ audit_setfsat_path(int argnum)
t_audit_data_t *tad;
struct f_audit_data *fad;
p_audit_data_t *pad; /* current process */
-
+ struct a {
+ long id;
+ long arg1;
+ long arg2;
+ long arg3;
+ long arg4;
+ long arg5;
+ } *uap;
struct b {
long arg1;
long arg2;
@@ -1306,6 +1313,7 @@ audit_setfsat_path(int argnum)
if (clwp == NULL)
return;
uap1 = (struct b *)&clwp->lwp_ap[1];
+ uap = (struct a *)clwp->lwp_ap;
tad = U2A(u);
@@ -1334,6 +1342,10 @@ audit_setfsat_path(int argnum)
return;
}
+ if (uap->id == 9 && tad->tad_atpath != NULL) { /* openattrdir */
+ tad->tad_ctrl |= PAD_ATPATH;
+ return;
+ }
if (tad->tad_atpath != NULL) {
au_pathrele(tad->tad_atpath);
tad->tad_atpath = NULL;
@@ -1373,7 +1385,8 @@ audit_symlink_create(vnode_t *dvp, char *sname, char *target, int error)
if (error)
return;
- error = VOP_LOOKUP(dvp, sname, &vp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(dvp, sname, &vp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == 0) {
audit_attributes(vp);
VN_RELE(vp);
@@ -1648,7 +1661,7 @@ audit_chdirec(vnode_t *vp, vnode_t **vpp)
* the same object, it will not panic our system
* QUESTION:
* where to decrement the f_count?????????????????
- * seems like I need to set a flag if f_count incrmented through audit_getf
+ * seems like I need to set a flag if f_count incremented through audit_getf
*/
/*ARGSUSED*/
@@ -1898,7 +1911,7 @@ audit_fdsend(fd, fp, error)
}
/*
- * Record privileges sucessfully used and we attempted to use but
+ * Record privileges successfully used and we attempted to use but
* didn't have.
*/
void
diff --git a/usr/src/uts/common/c2/audit_event.c b/usr/src/uts/common/c2/audit_event.c
index d9be55d304..e1ffc61c81 100644
--- a/usr/src/uts/common/c2/audit_event.c
+++ b/usr/src/uts/common/c2/audit_event.c
@@ -1040,6 +1040,9 @@ aui_fsat(au_event_t e)
case 7: /* renameat */
e = AUE_RENAMEAT;
break;
+ case 9: /* __openattrdirat */
+ tad->tad_ctrl |= PAD_SAVPATH;
+ /*FALLTHROUGH*/
default:
e = AUE_NULL;
break;
@@ -1866,7 +1869,7 @@ aus_close(struct t_audit_data *tad)
au_uwrite(au_to_path(fad->fad_aupath));
if ((vp = fp->f_vnode) != NULL) {
attr.va_mask = AT_ALL;
- if (VOP_GETATTR(vp, &attr, 0, CRED()) == 0) {
+ if (VOP_GETATTR(vp, &attr, 0, CRED(), NULL) == 0) {
/*
* When write was not used and the file can be
* considered public, skip the audit.
@@ -4585,7 +4588,7 @@ auf_sendto(struct t_audit_data *tad, int error, rval_t *rval)
}
/*
- * XXX socket(2) may be equivilent to open(2) on a unix domain
+ * XXX socket(2) may be equivalent to open(2) on a unix domain
* socket. This needs investigation.
*/
@@ -4910,7 +4913,7 @@ au_door_lookup(int did)
/*
* Use the underlying vnode (we may be namefs mounted)
*/
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp == NULL || vp->v_type != VDOOR) {
diff --git a/usr/src/uts/common/cpr/cpr_dump.c b/usr/src/uts/common/cpr/cpr_dump.c
index 28fee49bf9..709b50631e 100644
--- a/usr/src/uts/common/cpr/cpr_dump.c
+++ b/usr/src/uts/common/cpr/cpr_dump.c
@@ -1015,7 +1015,8 @@ cpr_write(vnode_t *vp, caddr_t buffer, size_t size)
}
do_polled_io = 1;
- error = VOP_DUMP(vp, cpr_buf, cpr_file_bn, cpr_buf_blocks);
+ error = VOP_DUMP(vp, cpr_buf, cpr_file_bn, cpr_buf_blocks,
+ NULL);
do_polled_io = 0;
CPR_DEBUG(CPR_DEBUG3, "done\n");
@@ -1045,7 +1046,7 @@ cpr_flush_write(vnode_t *vp)
nblk = btod(cpr_wptr - cpr_buf);
do_polled_io = 1;
- error = VOP_DUMP(vp, (caddr_t)cpr_buf, cpr_file_bn, nblk);
+ error = VOP_DUMP(vp, (caddr_t)cpr_buf, cpr_file_bn, nblk, NULL);
do_polled_io = 0;
cpr_file_bn += nblk;
diff --git a/usr/src/uts/common/cpr/cpr_main.c b/usr/src/uts/common/cpr/cpr_main.c
index 65e911cb11..96b1d29534 100644
--- a/usr/src/uts/common/cpr/cpr_main.c
+++ b/usr/src/uts/common/cpr/cpr_main.c
@@ -259,7 +259,7 @@ cpr_log_status(int enable, int *svstat, vnode_t *vp)
*/
if (enable == 0) {
if (error = VOP_IOCTL(vp, _FIOISLOG,
- (uintptr_t)&status, FKIOCTL, CRED(), NULL)) {
+ (uintptr_t)&status, FKIOCTL, CRED(), NULL, NULL)) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
prom_printf("%s: \"%s\", cant get logging "
"status, error %d\n", str, refstr_value(mntpt),
@@ -287,7 +287,7 @@ cpr_log_status(int enable, int *svstat, vnode_t *vp)
*/
if (*svstat == 1) {
error = VOP_IOCTL(vp, cmd, (uintptr_t)&fl,
- FKIOCTL, CRED(), NULL);
+ FKIOCTL, CRED(), NULL, NULL);
if (error) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
prom_printf("%s: \"%s\", cant %s logging, error %d\n",
@@ -338,7 +338,7 @@ cpr_ufs_logging(int enable)
return (error);
cpr_log_status(enable, &def_status, vp);
vfsp = vp->v_vfsp;
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
fname = cpr_build_statefile_path();
@@ -357,7 +357,7 @@ cpr_ufs_logging(int enable)
*/
if (vp->v_vfsp != vfsp && vp->v_type == VREG)
cpr_log_status(enable, &sf_status, vp);
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (0);
@@ -739,7 +739,7 @@ alloc_statefile:
rc = cpr_dump(C_VP);
/*
- * if any error occured during dump, more
+ * if any error occurred during dump, more
* special handling for reusable:
*/
if (rc && cpr_reusable_mode) {
diff --git a/usr/src/uts/common/cpr/cpr_misc.c b/usr/src/uts/common/cpr/cpr_misc.c
index 1ec0452c81..e35789b4a9 100644
--- a/usr/src/uts/common/cpr/cpr_misc.c
+++ b/usr/src/uts/common/cpr/cpr_misc.c
@@ -189,7 +189,7 @@ cpr_get_config(void)
}
err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf));
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (err) {
cpr_err(CE_CONT, fmt, "read", config_path, err);
@@ -455,7 +455,7 @@ cpr_alloc_statefile(int alloc_retry)
if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG7))
prom_printf(str);
if (C_VP->v_type != VBLK)
- (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL);
+ (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
} else {
/*
* Open an exiting file for writing, the state file needs to be
@@ -501,7 +501,7 @@ cpr_alloc_statefile(int alloc_retry)
* Validate disk blocks allocation for the state file.
* Ask the file system prepare itself for the dump operation.
*/
- if (rc = VOP_DUMPCTL(C_VP, DUMP_ALLOC, NULL)) {
+ if (rc = VOP_DUMPCTL(C_VP, DUMP_ALLOC, NULL, NULL)) {
cpr_err(CE_CONT, "Error allocating "
"blocks for cpr statefile.");
return (rc);
@@ -730,8 +730,8 @@ cpr_statef_close(void)
{
if (C_VP) {
if (!cpr_reusable_mode)
- (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL);
- (void) VOP_CLOSE(C_VP, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
+ (void) VOP_CLOSE(C_VP, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(C_VP);
C_VP = 0;
}
@@ -771,9 +771,9 @@ cpr_write_deffile(cdef_t *cdef)
if (rc = cpr_rdwr(UIO_WRITE, vp, cdef, sizeof (*cdef)))
str = "write";
- else if (rc = VOP_FSYNC(vp, FSYNC, CRED()))
+ else if (rc = VOP_FSYNC(vp, FSYNC, CRED(), NULL))
str = "fsync";
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (rc) {
@@ -799,7 +799,7 @@ cpr_clear_definfo(void)
return;
mini.magic = mini.reusable = 0;
(void) cpr_rdwr(UIO_WRITE, vp, &mini, sizeof (mini));
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -818,7 +818,7 @@ cpr_get_reusable_mode(void)
return (0);
rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (rc == 0 && mini.magic == CPR_DEFAULT_MAGIC)
return (mini.reusable);
diff --git a/usr/src/uts/common/fs/autofs/auto_vnops.c b/usr/src/uts/common/fs/autofs/auto_vnops.c
index 5ffcf57d83..9e1a6ef387 100644
--- a/usr/src/uts/common/fs/autofs/auto_vnops.c
+++ b/usr/src/uts/common/fs/autofs/auto_vnops.c
@@ -53,29 +53,39 @@
/*
* Vnode ops for autofs
*/
-static int auto_open(vnode_t **, int, cred_t *);
-static int auto_close(vnode_t *, int, int, offset_t, cred_t *);
-static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *);
+static int auto_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int auto_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *,
caller_context_t *);
-static int auto_access(vnode_t *, int, int, cred_t *);
+static int auto_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int auto_lookup(vnode_t *, char *, vnode_t **,
- pathname_t *, int, vnode_t *, cred_t *);
+ pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
+ pathname_t *);
static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t,
- int, vnode_t **, cred_t *, int);
-static int auto_remove(vnode_t *, char *, cred_t *);
-static int auto_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *);
-static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
-static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *);
-static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *);
-static int auto_readlink(vnode_t *, struct uio *, cred_t *);
-static int auto_fsync(vnode_t *, int, cred_t *);
-static void auto_inactive(vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
+static int auto_remove(vnode_t *, char *, cred_t *, caller_context_t *, int);
+static int auto_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
+ caller_context_t *, int, vsecattr_t *);
+static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int auto_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int auto_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void auto_inactive(vnode_t *, cred_t *, caller_context_t *);
static int auto_rwlock(vnode_t *, int, caller_context_t *);
static void auto_rwunlock(vnode_t *vp, int, caller_context_t *);
-static int auto_seek(vnode_t *vp, offset_t, offset_t *);
+static int auto_seek(vnode_t *vp, offset_t, offset_t *, caller_context_t *);
static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **);
@@ -113,7 +123,7 @@ const fs_operation_def_t auto_vnodeops_template[] = {
/* ARGSUSED */
static int
-auto_open(vnode_t **vpp, int flag, cred_t *cred)
+auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
{
vnode_t *newvp;
int error;
@@ -130,9 +140,9 @@ auto_open(vnode_t **vpp, int flag, cred_t *cred)
*/
VN_RELE(*vpp);
*vpp = newvp;
- error = VOP_ACCESS(*vpp, VREAD, 0, cred);
+ error = VOP_ACCESS(*vpp, VREAD, 0, cred, ct);
if (!error)
- error = VOP_OPEN(vpp, flag, cred);
+ error = VOP_OPEN(vpp, flag, cred, ct);
}
done:
@@ -143,13 +153,24 @@ done:
/* ARGSUSED */
static int
-auto_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cred)
+auto_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cred,
+ caller_context_t *ct)
{
return (0);
}
static int
-auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred)
+auto_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cred,
+ caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
vnode_t *newvp;
@@ -211,7 +232,7 @@ auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred)
fnp->fn_thread = curthread;
fnp->fn_seen = newvp;
mutex_exit(&fnp->fn_lock);
- error = VOP_GETATTR(newvp, vap, flags, cred);
+ error = VOP_GETATTR(newvp, vap, flags, cred, ct);
VN_RELE(newvp);
mutex_enter(&fnp->fn_lock);
fnp->fn_seen = 0;
@@ -272,7 +293,7 @@ auto_setattr(
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_SETATTR(newvp, vap, flags, cred, NULL);
+ error = VOP_SETATTR(newvp, vap, flags, cred, ct);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -284,7 +305,12 @@ done:
/* ARGSUSED */
static int
-auto_access(vnode_t *vp, int mode, int flags, cred_t *cred)
+auto_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cred,
+ caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
vnode_t *newvp;
@@ -299,7 +325,7 @@ auto_access(vnode_t *vp, int mode, int flags, cred_t *cred)
/*
* Node is mounted on.
*/
- error = VOP_ACCESS(newvp, mode, 0, cred);
+ error = VOP_ACCESS(newvp, mode, 0, cred, ct);
VN_RELE(newvp);
} else {
int shift = 0;
@@ -333,7 +359,10 @@ auto_lookup(
pathname_t *pnp,
int flags,
vnode_t *rdir,
- cred_t *cred)
+ cred_t *cred,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
int error = 0;
vnode_t *newvp = NULL;
@@ -354,7 +383,7 @@ auto_lookup(
return (0);
}
- if (error = VOP_ACCESS(dvp, VEXEC, 0, cred))
+ if (error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct))
return (error);
if (nm[0] == '.' && nm[1] == 0) {
@@ -387,7 +416,8 @@ auto_lookup(
vp = dvp->v_vfsp->vfs_vnodecovered;
VN_HOLD(vp);
vfs_unlock(dvp->v_vfsp);
- error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred);
+ error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred,
+ ct, direntflags, realpnp);
VN_RELE(vp);
return (error);
} else {
@@ -434,7 +464,7 @@ top:
vn_vfsunlock(dvp);
if (!error) {
error = VOP_LOOKUP(newvp, nm, vpp, pnp,
- flags, rdir, cred);
+ flags, rdir, cred, ct, direntflags, realpnp);
VN_RELE(newvp);
}
return (error);
@@ -640,7 +670,9 @@ auto_create(
int mode,
vnode_t **vpp,
cred_t *cred,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
vnode_t *newvp;
int error;
@@ -658,7 +690,7 @@ auto_create(
error = EROFS;
else
error = VOP_CREATE(newvp, nm, va, excl,
- mode, vpp, cred, flag);
+ mode, vpp, cred, flag, ct, vsecp);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -669,7 +701,12 @@ done:
}
static int
-auto_remove(vnode_t *dvp, char *nm, cred_t *cred)
+auto_remove(
+ vnode_t *dvp,
+ char *nm,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -686,7 +723,7 @@ auto_remove(vnode_t *dvp, char *nm, cred_t *cred)
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_REMOVE(newvp, nm, cred);
+ error = VOP_REMOVE(newvp, nm, cred, ct, flags);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -697,7 +734,13 @@ done:
}
static int
-auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred)
+auto_link(
+ vnode_t *tdvp,
+ vnode_t *svp,
+ char *nm,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -731,7 +774,7 @@ auto_link(vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred)
goto done;
}
- error = VOP_LINK(newvp, svp, nm, cred);
+ error = VOP_LINK(newvp, svp, nm, cred, ct, flags);
VN_RELE(newvp);
done:
@@ -740,7 +783,14 @@ done:
}
static int
-auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+auto_rename(
+ vnode_t *odvp,
+ char *onm,
+ vnode_t *ndvp,
+ char *nnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *o_newvp, *n_newvp;
int error;
@@ -801,7 +851,7 @@ auto_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
goto done;
}
- error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr);
+ error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
VN_RELE(o_newvp);
if (n_newvp != ndvp)
VN_RELE(n_newvp);
@@ -812,7 +862,15 @@ done:
}
static int
-auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred)
+auto_mkdir(
+ vnode_t *dvp,
+ char *nm,
+ vattr_t *va,
+ vnode_t **vpp,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
vnode_t *newvp;
int error;
@@ -829,7 +887,8 @@ auto_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cred)
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_MKDIR(newvp, nm, va, vpp, cred);
+ error = VOP_MKDIR(newvp, nm, va, vpp, cred, ct,
+ flags, vsecp);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -840,7 +899,13 @@ done:
}
static int
-auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred)
+auto_rmdir(
+ vnode_t *dvp,
+ char *nm,
+ vnode_t *cdir,
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -857,7 +922,7 @@ auto_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred)
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_RMDIR(newvp, nm, cdir, cred);
+ error = VOP_RMDIR(newvp, nm, cdir, cred, ct, flags);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -874,8 +939,15 @@ static int autofs_nobrowse = 0;
#endif
#define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
+/* ARGSUSED */
static int
-auto_readdir(vnode_t *vp, uio_t *uiop, cred_t *cred, int *eofp)
+auto_readdir(
+ vnode_t *vp,
+ uio_t *uiop,
+ cred_t *cred,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct autofs_rddirargs rda;
autofs_rddirres rd;
@@ -1161,7 +1233,9 @@ auto_symlink(
char *lnknm, /* new entry */
vattr_t *tva,
char *tnm, /* existing entry */
- cred_t *cred)
+ cred_t *cred,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *newvp;
int error;
@@ -1179,7 +1253,8 @@ auto_symlink(
if (vn_is_readonly(newvp))
error = EROFS;
else
- error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred);
+ error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred,
+ ct, flags);
VN_RELE(newvp);
} else
error = ENOSYS;
@@ -1191,7 +1266,7 @@ done:
/* ARGSUSED */
static int
-auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
int error;
@@ -1217,14 +1292,14 @@ auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
/* ARGSUSED */
static int
-auto_fsync(vnode_t *cp, int syncflag, cred_t *cred)
+auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static void
-auto_inactive(vnode_t *vp, cred_t *cred)
+auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
{
fnnode_t *fnp = vntofn(vp);
fnnode_t *dfnp = fnp->fn_parent;
@@ -1287,7 +1362,11 @@ auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
/* ARGSUSED */
static int
-auto_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+auto_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
/*
* Return 0 unconditionally, since we expect
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_cnode.c b/usr/src/uts/common/fs/cachefs/cachefs_cnode.c
index 2036c59f20..f57b732eb0 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_cnode.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_cnode.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,7 +132,7 @@ cachefs_cnode_idle(struct vnode *vp, cred_t *cr)
unlname, unlcred, vp);
}
- /* reaquire cnode lock */
+ /* reacquire cnode lock */
mutex_enter(&cp->c_statelock);
/* if a timeout occurred */
@@ -1340,7 +1339,7 @@ cachefs_cnode_move(cnode_t *cp)
make_ascii_name(&cp->c_id, oname);
make_ascii_name(&cid, nname);
error = VOP_RENAME(ofgp->fg_dirvp, oname, fgp->fg_dirvp,
- nname, kcred);
+ nname, kcred, NULL, 0);
if (error) {
ffnuke = 1;
#ifdef CFSDEBUG
@@ -1470,7 +1469,8 @@ cachefs_cnode_sync(cnode_t *cp)
cp->c_backvp) {
mutex_enter(&cp->c_statelock);
if (cp->c_backvp) {
- error = VOP_FSYNC(cp->c_backvp, FSYNC, kcred);
+ error = VOP_FSYNC(cp->c_backvp, FSYNC, kcred,
+ NULL);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -1554,7 +1554,7 @@ cachefs_cnode_lostfound(cnode_t *cp, char *rname)
else
namep = "lostfile";
error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0)
VN_RELE(nvp);
if (error != ENOENT) {
@@ -1569,7 +1569,7 @@ cachefs_cnode_lostfound(cnode_t *cp, char *rname)
else
namep = namebuf;
error = VOP_LOOKUP(cachep->c_lostfoundvp, namep, &nvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0)
VN_RELE(nvp);
if (error == ENOENT)
@@ -1587,7 +1587,7 @@ cachefs_cnode_lostfound(cnode_t *cp, char *rname)
/* rename the file into the lost+found directory */
error = VOP_RENAME(fgp->fg_dirvp, oname, cachep->c_lostfoundvp,
- namep, kcred);
+ namep, kcred, NULL, 0);
if (error) {
mutex_exit(&cachep->c_contentslock);
goto out;
@@ -1675,7 +1675,7 @@ cachefs_cnode_traverse(fscache_t *fscp, void (*routinep)(cnode_t *))
*/
(routinep)(cp);
- /* reaquire the cnode list lock */
+ /* reacquire the cnode list lock */
mutex_enter(&fgp->fg_cnodelock);
}
@@ -1687,7 +1687,7 @@ cachefs_cnode_traverse(fscache_t *fscp, void (*routinep)(cnode_t *))
VN_RELE(CTOV(ocp));
}
- /* reaquire the fscache lock */
+ /* reacquire the fscache lock */
mutex_enter(&fscp->fs_fslock);
}
@@ -1730,7 +1730,7 @@ cnode_enable_caching(struct cnode *cp)
iovp = cp->c_backvp;
if (iovp) {
(void) VOP_PUTPAGE(iovp, (offset_t)0,
- (uint_t)0, B_INVAL, kcred);
+ (uint_t)0, B_INVAL, kcred, NULL);
}
mutex_enter(&cp->c_statelock);
if (cp->c_backvp) {
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_cod.c b/usr/src/uts/common/fs/cachefs/cachefs_cod.c
index fac80de284..be60ec4f40 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_cod.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_cod.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -93,7 +92,7 @@ c_cod_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
/* get the attributes */
cp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
if (error)
return (error);
} else {
@@ -170,7 +169,7 @@ again:
/* get the file attributes from the back fs */
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
backhit = 1;
if (error)
goto out;
@@ -210,7 +209,7 @@ again:
}
if ((CTOV(cp))->v_type == VREG) {
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
goto out;
}
@@ -295,7 +294,7 @@ c_cod_modify_cached_object(struct fscache *fscp, struct cnode *cp, cred_t *cr)
}
attrs.va_mask = AT_ALL;
ASSERT(cp->c_backvp != NULL);
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error) {
mdp->md_vattr.va_mtime.tv_sec = 0;
goto out;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_dir.c b/usr/src/uts/common/fs/cachefs/cachefs_dir.c
index 8e586946a6..d77b4ab36a 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_dir.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_dir.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -108,7 +107,7 @@ cachefs_dir_look(cnode_t *dcp, char *nm, fid_t *cookiep, uint_t *flagp,
dvp = dcp->c_frontvp;
va.va_mask = AT_SIZE; /* XXX should save dir size */
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
cachefs_inval_object(dcp);
error = ENOTDIR;
@@ -201,7 +200,7 @@ cachefs_dir_new(cnode_t *dcp, cnode_t *cp)
#ifdef CFSDEBUG
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred);
+ error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
if (error)
goto out;
ASSERT(va.va_size == 0);
@@ -307,7 +306,7 @@ cachefs_dir_enter(cnode_t *dcp, char *nm, fid_t *cookiep, cfs_cid_t *cidp,
* Get the current EOF for the directory(data file)
*/
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
cachefs_inval_object(dcp);
error = ENOTDIR;
@@ -465,7 +464,7 @@ cachefs_dir_rmentry(cnode_t *dcp, char *nm)
ASSERT((dcp->c_flags & CN_NOCACHE) == 0);
ASSERT(dvp != NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
cachefs_inval_object(dcp);
error = ENOTDIR;
@@ -624,7 +623,7 @@ cachefs_dir_getentrys(struct cnode *dcp, u_offset_t beg_off,
gdp = (struct dirent64 *)buf;
*cntp = bufsize;
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error) {
*cntp = 0;
*last_offp = 0;
@@ -950,7 +949,7 @@ cachefs_dir_fill_common(cnode_t *dcp, cred_t *cr,
iov.iov_base = buf;
iov.iov_len = MAXBSIZE;
(void) VOP_RWLOCK(backvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(backvp, &uio, cr, &eof);
+ error = VOP_READDIR(backvp, &uio, cr, &eof, NULL, 0);
VOP_RWUNLOCK(backvp, V_WRITELOCK_FALSE, NULL);
if (error)
goto out;
@@ -1017,7 +1016,7 @@ cachefs_dir_empty(cnode_t *dcp)
return (ENOTDIR);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dvp, &va, 0, kcred);
+ error = VOP_GETATTR(dvp, &va, 0, kcred, NULL);
if (error)
return (ENOTDIR);
@@ -1258,7 +1257,7 @@ cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp, vnode_t *frontvp,
*/
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(frontvp, &va, 0, cr);
+ error = VOP_GETATTR(frontvp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -1296,7 +1295,7 @@ cachefs_dir_complete(fscache_t *fscp, vnode_t *backvp, vnode_t *frontvp,
error = VOP_LOOKUP(backvp, dep->d_name,
&entry_vp, (struct pathname *)NULL, 0,
- (vnode_t *)NULL, cr);
+ (vnode_t *)NULL, cr, NULL, NULL, NULL);
if (error) {
/* lookup on .. in / on coc gets ENOENT */
if (error == ENOENT) {
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_dlog.c b/usr/src/uts/common/fs/cachefs/cachefs_dlog.c
index e3ad1bc9de..5781d7a4d1 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_dlog.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_dlog.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -203,7 +202,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
/* see if the log file exists */
error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
- &fscp->fs_dlogfile, NULL, 0, NULL, kcred);
+ &fscp->fs_dlogfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error && (createfile == 0))
goto out;
@@ -217,7 +216,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
vattr.va_type = VREG;
vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
- &vattr, 0, 0666, &fscp->fs_dlogfile, kcred, 0);
+ &vattr, 0, 0666, &fscp->fs_dlogfile, kcred, 0, NULL, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -246,7 +245,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
vattr.va_type = VREG;
vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
- &vattr, 0, 0666, &fscp->fs_dmapfile, kcred, 0);
+ &vattr, 0, 0666, &fscp->fs_dmapfile, kcred, 0, NULL, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -272,7 +271,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
/* find the end of the log file */
vattr.va_mask = AT_ALL;
- error = VOP_GETATTR(fscp->fs_dlogfile, &vattr, 0, kcred);
+ error = VOP_GETATTR(fscp->fs_dlogfile, &vattr, 0, kcred, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -328,7 +327,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
- &fscp->fs_dmapfile, NULL, 0, NULL, kcred);
+ &fscp->fs_dmapfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -339,7 +338,7 @@ cachefs_dlog_setup(fscache_t *fscp, int createfile)
}
vattr.va_mask = AT_ALL;
- error = VOP_GETATTR(fscp->fs_dmapfile, &vattr, 0, kcred);
+ error = VOP_GETATTR(fscp->fs_dmapfile, &vattr, 0, kcred, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_DLOG)
@@ -359,13 +358,13 @@ out:
VN_RELE(fscp->fs_dlogfile);
fscp->fs_dlogfile = NULL;
(void) VOP_REMOVE(fscp->fs_fscdirvp,
- CACHEFS_DLOG_FILE, kcred);
+ CACHEFS_DLOG_FILE, kcred, NULL, 0);
}
if (fscp->fs_dmapfile) {
VN_RELE(fscp->fs_dmapfile);
fscp->fs_dmapfile = NULL;
(void) VOP_REMOVE(fscp->fs_fscdirvp,
- CACHEFS_DMAP_FILE, kcred);
+ CACHEFS_DMAP_FILE, kcred, NULL, 0);
}
}
if (lookupdone) {
@@ -528,7 +527,7 @@ out:
}
/*
- * Commmits a previously written dlog message.
+ * Commits a previously written dlog message.
*/
int
cachefs_dlog_commit(fscache_t *fscp, off_t offset, int error)
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c b/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c
index 2da9b2bfda..9e430fa0fb 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_filegrp.c
@@ -224,12 +224,12 @@ filegrp_create(struct fscache *fscp, cfs_cid_t *cidp)
fgp->fg_offsets = NULL;
fgp->fg_alloclist = NULL;
- fgp->fg_headersize = (u_int)sizeof (struct attrcache_header) +
- (fgsize * (u_int)sizeof (struct attrcache_index)) +
+ fgp->fg_headersize = (uint_t)sizeof (struct attrcache_header) +
+ (fgsize * (uint_t)sizeof (struct attrcache_index)) +
((fgsize + 7) >> 3);
fgp->fg_filesize = fgp->fg_headersize +
- (fgsize * (u_int)sizeof (struct cfs_cachefs_metadata));
+ (fgsize * (uint_t)sizeof (struct cfs_cachefs_metadata));
flags = fscp->fs_flags;
if (flags & CFS_FS_READ) {
@@ -324,7 +324,8 @@ filegrp_destroy(filegrp_t *fgp)
/* remove the attrcache file */
make_ascii_name(&fgp->fg_id, name);
fname = name;
- error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred);
+ error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
+ NULL, 0);
if (error) {
cmn_err(CE_WARN,
"cachefs: error in cache, run fsck");
@@ -452,7 +453,7 @@ filegrp_hold(filegrp_t *fgp)
* Returns:
* Preconditions:
* precond(fgp is a valid filegrp object)
- * precond(number of refrences to filegrp is > 0)
+ * precond(number of references to filegrp is > 0)
*/
void
@@ -498,7 +499,7 @@ filegrp_rele(filegrp_t *fgp)
* Returns 0 for success or a non-zero errno.
* Preconditions:
* precond(fgp is a valid filegrp object)
- * precond(number of refrences to filegrp is > 0)
+ * precond(number of references to filegrp is > 0)
* precond(filegrp is writable)
*/
@@ -586,7 +587,7 @@ out:
* Preconditions:
* precond(fgp is a valid filegrp object)
* precond(filegrp is writable)
- * precond(number of refrences to filegrp is > 0)
+ * precond(number of references to filegrp is > 0)
* precond(number of front file references is > 0)
*/
@@ -620,7 +621,7 @@ filegrp_ffrele(filegrp_t *fgp)
make_ascii_name(&fgp->fg_id, name);
fname = name;
error = VOP_RMDIR(fscp->fs_fscdirvp, fname,
- fscp->fs_fscdirvp, kcred);
+ fscp->fs_fscdirvp, kcred, NULL, 0);
if (error == 0) {
cachefs_freefile(fscp->fs_cache);
cachefs_freeblocks(fscp->fs_cache, 1,
@@ -687,7 +688,7 @@ filegrp_sync(filegrp_t *fgp)
kcred, NULL);
if (error == 0)
- error = VOP_FSYNC(fgp->fg_attrvp, FSYNC, kcred);
+ error = VOP_FSYNC(fgp->fg_attrvp, FSYNC, kcred, NULL);
if (error == 0)
fgp->fg_flags &= ~CFS_FG_UPDATED;
@@ -746,7 +747,7 @@ filegrp_read_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
/* see if metadata was ever written */
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
if (fgp->fg_offsets[index].ach_written == 0) {
mutex_exit(&fgp->fg_mutex);
return (ENOENT);
@@ -794,7 +795,7 @@ filegrp_create_metadata(filegrp_t *fgp, struct cachefs_metadata *md,
cachefscache_t *cachep = fscp->fs_cache;
int slot;
int bitno;
- u_char mask;
+ uchar_t mask;
int last;
int xx;
int index;
@@ -816,13 +817,13 @@ filegrp_create_metadata(filegrp_t *fgp, struct cachefs_metadata *md,
return (0);
}
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
ASSERT(index < fgp->fg_fscp->fs_info.fi_fgsize);
last = (((fgp->fg_fscp->fs_info.fi_fgsize + 7) & ~(7)) / 8);
for (xx = 0; xx < last; xx++) {
- if (fgp->fg_alloclist[xx] != (u_char)0xff) {
+ if (fgp->fg_alloclist[xx] != (uchar_t)0xff) {
for (mask = 1, bitno = 0; bitno < 8; bitno++) {
if ((mask & fgp->fg_alloclist[xx]) == 0) {
slot = (xx * 8) + bitno;
@@ -948,7 +949,7 @@ filegrp_write_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
}
/* mark metadata as having been written */
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
fgp->fg_offsets[index].ach_written = 1;
/* update number of blocks used by the attrcache file */
@@ -983,7 +984,7 @@ filegrp_destroy_metadata(filegrp_t *fgp, cfs_cid_t *cidp)
{
int i;
int bitno;
- u_char mask = 1;
+ uchar_t mask = 1;
int slot;
@@ -1064,7 +1065,7 @@ filegrp_list_find(struct fscache *fscp, cfs_cid_t *cidp)
fileno = fxx * fgsize;
/* hash into array of file groups */
- findex = (int) (fxx & (CFS_FS_FGP_BUCKET_SIZE - 1));
+ findex = (int)(fxx & (CFS_FS_FGP_BUCKET_SIZE - 1));
/* search set of file groups for this hash bucket */
for (fgp = fscp->fs_filegrp[findex];
@@ -1106,7 +1107,7 @@ filegrp_list_add(struct fscache *fscp, filegrp_t *fgp)
ASSERT(fgp->fg_next == NULL);
/* hash into array of file groups */
- findex = (int) ((fgp->fg_id.cid_fileno / fgsize) &
+ findex = (int)((fgp->fg_id.cid_fileno / fgsize) &
(CFS_FS_FGP_BUCKET_SIZE - 1));
fgp->fg_next = fscp->fs_filegrp[findex];
@@ -1144,7 +1145,7 @@ filegrp_list_remove(struct fscache *fscp, filegrp_t *fgp)
ASSERT(MUTEX_HELD(&fscp->fs_fslock));
/* hash into array of file groups */
- findex = (int) ((fgp->fg_id.cid_fileno / fgsize) &
+ findex = (int)((fgp->fg_id.cid_fileno / fgsize) &
(CFS_FS_FGP_BUCKET_SIZE - 1));
fp = fscp->fs_filegrp[findex];
pfgp = &fscp->fs_filegrp[findex];
@@ -1360,7 +1361,7 @@ filegrpdir_find(filegrp_t *fgp)
make_ascii_name(&fgp->fg_id, name);
fname = name;
error = VOP_LOOKUP(fscp->fs_fscdirvp, fname, &dirvp, NULL,
- 0, NULL, kcred);
+ 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0) {
fgp->fg_dirvp = dirvp;
fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
@@ -1421,7 +1422,7 @@ filegrpattr_find(struct filegrp *fgp)
make_ascii_name(&fgp->fg_id, name);
fname = name;
error = VOP_LOOKUP(fscp->fs_fsattrdir, fname,
- &attrvp, NULL, 0, NULL, kcred);
+ &attrvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
return (error);
}
@@ -1442,7 +1443,7 @@ filegrpattr_find(struct filegrp *fgp)
fgp->fg_attrvp = attrvp;
fgp->fg_header = ahp;
fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
- fgp->fg_alloclist = ((u_char *)fgp->fg_offsets) +
+ fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
(fscp->fs_info.fi_fgsize *
sizeof (struct attrcache_index));
fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
@@ -1565,7 +1566,8 @@ filegrpdir_create(filegrp_t *fgp)
attrp->va_gid = 0;
attrp->va_type = VDIR;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
- error = VOP_MKDIR(fscp->fs_fscdirvp, fname, attrp, &dirvp, kcred);
+ error = VOP_MKDIR(fscp->fs_fscdirvp, fname, attrp, &dirvp, kcred, NULL,
+ 0, NULL);
if (error) {
fgp->fg_flags |= CFS_FG_NOCACHE;
cachefs_freefile(fscp->fs_cache);
@@ -1637,7 +1639,7 @@ filegrpattr_create(struct filegrp *fgp)
attrp->va_type = VREG;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
error = VOP_CREATE(fscp->fs_fsattrdir, fname, attrp, EXCL, 0666,
- &attrvp, kcred, 0);
+ &attrvp, kcred, 0, NULL, NULL);
if (error) {
cachefs_freefile(fscp->fs_cache);
goto out;
@@ -1664,7 +1666,7 @@ filegrpattr_create(struct filegrp *fgp)
(nblks * MAXBSIZE) - fgp->fg_headersize);
if (error)
goto out;
- error = VOP_FSYNC(attrvp, FSYNC, kcred);
+ error = VOP_FSYNC(attrvp, FSYNC, kcred, NULL);
if (error)
goto out;
@@ -1694,7 +1696,8 @@ out:
fgp->fg_flags |= CFS_FG_NOCACHE;
if (attrvp) {
VN_RELE(attrvp);
- (void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred);
+ (void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
+ NULL, 0);
cachefs_freefile(fscp->fs_cache);
}
if (nblks)
@@ -1709,7 +1712,7 @@ out:
fgp->fg_attrvp = attrvp;
fgp->fg_header = ahp;
fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
- fgp->fg_alloclist = ((u_char *)fgp->fg_offsets) +
+ fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
(fscp->fs_info.fi_fgsize *
sizeof (struct attrcache_index));
ahp->ach_count = 0;
@@ -1751,7 +1754,7 @@ filegrp_cid_to_slot(filegrp_t *fgp, cfs_cid_t *cidp)
int slot;
int index;
- index = (int) (cidp->cid_fileno - fgp->fg_id.cid_fileno);
+ index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
if (index > fgp->fg_fscp->fs_info.fi_fgsize) {
cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_fscache.c b/usr/src/uts/common/fs/cachefs/cachefs_fscache.c
index 28c3f1c36d..6dcb5430f2 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_fscache.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_fscache.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -257,7 +256,7 @@ fscache_setup(fscache_t *fscp, ino64_t fsid, char *namep,
return (error);
}
} else if (optp) {
- /* compare the options to make sure they are compatable */
+ /* compare the options to make sure they are compatible */
error = fscache_compare_options(fscp, optp);
if (error) {
cmn_err(CE_WARN,
@@ -507,8 +506,8 @@ out:
/*
* Compares fscache state with new mount options
- * to make sure compatable.
- * Returns ESRCH if not compatable or 0 for success.
+ * to make sure compatible.
+ * Returns ESRCH if not compatible or 0 for success.
*/
int
fscache_compare_options(fscache_t *fscp, struct cachefsoptions *optp)
@@ -811,7 +810,8 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_gid = 0;
attrp->va_type = VDIR;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
- error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred);
+ error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred,
+ NULL, 0, NULL);
if (error) {
cmn_err(CE_WARN, "Can't create fs cache directory");
goto out;
@@ -821,7 +821,7 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
* Created the directory. Get the fileno. That'll be the cachefs_fsid.
*/
attrp->va_mask = AT_NODEID;
- error = VOP_GETATTR(fscdirvp, attrp, 0, kcred);
+ error = VOP_GETATTR(fscdirvp, attrp, 0, kcred, NULL);
if (error) {
goto out;
}
@@ -832,7 +832,7 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_type = VREG;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL,
- 0600, &infovp, kcred, 0);
+ 0600, &infovp, kcred, 0, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "Can't create fs option file");
goto out;
@@ -858,7 +858,7 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
cid.cid_fileno = fsid;
make_ascii_name(&cid, name);
error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp,
- name, kcred);
+ name, kcred, NULL, 0);
if (error) {
cmn_err(CE_WARN, "Can't rename cache directory");
goto out;
@@ -866,7 +866,8 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_mask = AT_MODE | AT_TYPE;
attrp->va_mode = 0777;
attrp->va_type = VLNK;
- error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred);
+ error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred, NULL,
+ 0);
if (error) {
cmn_err(CE_WARN, "Can't create cache directory symlink");
goto out;
@@ -880,7 +881,8 @@ fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
attrp->va_gid = 0;
attrp->va_type = VDIR;
attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
- error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred);
+ error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred, NULL,
+ 0, NULL);
if (error) {
cmn_err(CE_WARN, "Can't create attrcache dir for fscache");
goto out;
@@ -939,7 +941,7 @@ fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
/* try to find the directory */
error = VOP_LOOKUP(cachep->c_dirvp, dirname, &fscdirvp, NULL,
- 0, NULL, kcred);
+ 0, NULL, kcred, NULL, NULL, NULL);
if (error)
goto out;
@@ -953,7 +955,7 @@ fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
/* try to find the info file */
error = VOP_LOOKUP(fscdirvp, CACHEFS_FSINFO, &infovp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: fscdir_find_b: cache corruption"
" run fsck, %s", dirname);
@@ -975,7 +977,7 @@ fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
/* try to find the attrcache directory */
error = VOP_LOOKUP(fscdirvp, ATTRCACHE_NAME,
- &attrvp, NULL, 0, NULL, kcred);
+ &attrvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: fscdir_find_d: cache corruption"
" run fsck, %s", dirname);
@@ -1076,7 +1078,7 @@ fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp)
/* get the vnode of the name */
error = VOP_LOOKUP(cachep->c_dirvp, namep, &linkvp, NULL, 0, NULL,
- kcred);
+ kcred, NULL, NULL, NULL);
if (error)
goto out;
@@ -1096,7 +1098,7 @@ fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp)
uio.uio_loffset = 0;
uio.uio_fmode = 0;
uio.uio_extflg = UIO_COPY_CACHED;
- error = VOP_READLINK(linkvp, &uio, kcred);
+ error = VOP_READLINK(linkvp, &uio, kcred, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: Can't read filesystem cache link");
goto out;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c b/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c
index 62c15fc35e..2a6b60a7a0 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -1123,7 +1122,7 @@ cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp)
/* Get the length of the directory */
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred);
+ error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
if (error) {
error = 0;
goto out;
@@ -1248,7 +1247,7 @@ cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp)
cr = conj_cred(&gafid->cg_cred);
CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t);
tmpvap->va_mask = AT_ALL;
- error = VOP_GETATTR(backvp, tmpvap, 0, cr);
+ error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL);
CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error);
crfree(cr);
@@ -1298,7 +1297,7 @@ cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
/* lookup the file name */
cr = conj_cred(&gap->cg_cred);
error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp,
- (struct pathname *)NULL, 0, (vnode_t *)NULL, cr);
+ (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
if (error) {
crfree(cr);
VN_RELE(pbackvp);
@@ -1307,12 +1306,12 @@ cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t);
tmpvap->va_mask = AT_ALL;
- error = VOP_GETATTR(cbackvp, tmpvap, 0, cr);
+ error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL);
CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error);
if (!error) {
CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(cbackvp, tmpfidp);
+ error = VOP_FID(cbackvp, tmpfidp, NULL);
CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid);
}
@@ -1415,7 +1414,7 @@ cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
}
/* do open so NFS gets correct creds on writes */
- error = VOP_OPEN(&backvp, FWRITE, cr);
+ error = VOP_OPEN(&backvp, FWRITE, cr, NULL);
if (error) {
mutex_exit(&cp->c_statelock);
goto out;
@@ -1450,9 +1449,9 @@ cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
off += amt;
}
- error = VOP_FSYNC(backvp, FSYNC, cr);
+ error = VOP_FSYNC(backvp, FSYNC, cr, NULL);
if (error == 0)
- error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr);
+ error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL);
if (error) {
mutex_exit(&cp->c_statelock);
goto out;
@@ -1469,7 +1468,7 @@ cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
* new ctime and mtimes.
*/
va.va_mask = AT_ALL;
- error = VOP_GETATTR(backvp, &va, 0, cr);
+ error = VOP_GETATTR(backvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error);
@@ -1527,21 +1526,21 @@ cachefs_io_create(vnode_t *vp, void *dinp, void *doutp)
CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t);
CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap);
error = VOP_CREATE(dvp, crp->cr_name, tmpvap,
- crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0);
+ crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL);
if (error)
goto out;
/* get the fid of the file */
CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, tmpfidp);
+ error = VOP_FID(cvp, tmpfidp, NULL);
if (error)
goto out;
CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid);
/* get attributes for the file */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error);
@@ -1614,10 +1613,11 @@ cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
/* if the caller wants the ctime after the remove */
if (ctimep) {
- error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error == 0) {
child_fid.fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, &child_fid);
+ error = VOP_FID(cvp, &child_fid, NULL);
VN_RELE(cvp);
}
if (error)
@@ -1625,7 +1625,7 @@ cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
}
/* do the remove */
- error = VOP_REMOVE(dvp, rmp->rm_name, cr);
+ error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0);
if (error)
goto out;
@@ -1634,7 +1634,7 @@ cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
if (error == 0) {
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error == 0) {
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime,
ctimep, error);
@@ -1697,13 +1697,13 @@ cachefs_io_link(vnode_t *vp, void *dinp, void *doutp)
cr = conj_cred(&linkp->ln_cred);
/* do the link */
- error = VOP_LINK(dvp, lvp, linkp->ln_name, cr);
+ error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0);
if (error)
goto out;
/* get the ctime */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(lvp, &va, 0, cr);
+ error = VOP_GETATTR(lvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error);
@@ -1771,14 +1771,14 @@ cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
/* if the caller wants the ctime of the target after deletion */
if (rnp->rn_del_getctime) {
error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error) {
cvp = NULL; /* paranoia */
goto out;
}
child_fid.fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, &child_fid);
+ error = VOP_FID(cvp, &child_fid, NULL);
if (error)
goto out;
VN_RELE(cvp);
@@ -1786,17 +1786,19 @@ cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
}
/* do the rename */
- error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr);
+ error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr,
+ NULL, 0);
if (error)
goto out;
/* get the new ctime on the renamed file */
- error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
goto out;
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error);
@@ -1815,7 +1817,7 @@ cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
goto out;
}
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime,
@@ -1878,14 +1880,14 @@ cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
/* make the directory */
CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t);
CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap);
- error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr);
+ error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL);
if (error) {
if (error != EEXIST)
goto out;
/* if the directory already exists, then use it */
error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
if (error) {
cvp = NULL;
goto out;
@@ -1899,14 +1901,14 @@ cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
/* get the fid of the directory */
CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(cvp, tmpfidp);
+ error = VOP_FID(cvp, tmpfidp, NULL);
if (error)
goto out;
CACHEFS_FID_COPYOUT(tmpfidp, fidp);
/* get attributes of the directory */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -1969,7 +1971,7 @@ cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp)
}
cr = conj_cred(&rdp->rd_cred);
- error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr);
+ error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0);
crfree(cr);
VN_RELE(dvp);
@@ -2019,18 +2021,19 @@ cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t);
CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap);
error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap,
- symp->sy_link, cr);
+ symp->sy_link, cr, NULL, 0);
if (error)
goto out;
/* get the vnode for the symlink */
- error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
goto out;
/* get the attributes of the symlink */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(svp, &va, 0, cr);
+ error = VOP_GETATTR(svp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error);
@@ -2041,7 +2044,7 @@ cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
/* get the fid */
CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t);
tmpfidp->fid_len = MAXFIDSZ;
- error = VOP_FID(svp, tmpfidp);
+ error = VOP_FID(svp, tmpfidp, NULL);
if (error)
goto out;
CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid);
@@ -2120,7 +2123,7 @@ cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp)
/* get the new ctime and mtime */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(cvp, &va, 0, cr);
+ error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error);
@@ -2181,14 +2184,14 @@ cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp)
/* set the ACL */
(void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(tvp, &vsec, 0, cr);
+ error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL);
VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL);
if (error != 0)
goto out;
/* get the new ctime and mtime */
va.va_mask = AT_ALL;
- error = VOP_GETATTR(tvp, &va, 0, cr);
+ error = VOP_GETATTR(tvp, &va, 0, cr, NULL);
if (error)
goto out;
CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error);
@@ -2223,7 +2226,7 @@ drop_backvp(cnode_t *cp)
if (cp->c_backvp) {
/* dump any pages, may be a dirty one */
(void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0,
- B_INVAL | B_TRUNC, kcred);
+ B_INVAL | B_TRUNC, kcred, NULL);
}
mutex_exit(&cp->c_statelock);
}
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_log.c b/usr/src/uts/common/fs/cachefs/cachefs_log.c
index 8d0103cd39..76a6453ba6 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_log.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_log.c
@@ -57,7 +57,7 @@
/*
* cfs_time_t is an int in both LP64 and ILP32. To avoid compiler warnings
- * define its xdr here explicitely
+ * define its xdr here explicitly
*/
#define xdr_cfs_time_t(xdrs, p) xdr_int((xdrs), (int *)(p))
@@ -198,7 +198,8 @@ cachefs_log_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
bzero(lc, sizeof (*lc));
lc->lc_magic = CACHEFS_LOG_MAGIC;
lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
- (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred);
+ (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred, NULL,
+ 0);
return (0);
}
@@ -246,9 +247,9 @@ cachefs_log_save_lc(cachefscache_t *cachep)
attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
if (((error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &savevp,
- NULL, 0, NULL, kcred)) != 0) &&
+ NULL, 0, NULL, kcred, NULL, NULL, NULL)) != 0) &&
((error = VOP_CREATE(cachep->c_dirvp, LOG_STATUS_NAME, &attr, EXCL,
- 0600, &savevp, kcred, 0)) != 0))
+ 0600, &savevp, kcred, 0, NULL, NULL)) != 0))
return (error);
ASSERT(savevp != NULL);
if (savevp == NULL)
@@ -322,7 +323,7 @@ cachefs_log_destroy_cookie(cachefs_log_cookie_t *cl)
*
* opens the logfile, and stores the path string if its successful.
*
- * returns an errno if one occured.
+ * returns an errno if one occurred.
*
*/
@@ -406,7 +407,7 @@ out:
}
/*
- * called when an error occured during logging. send the error to
+ * called when an error occurred during logging. send the error to
* syslog, invalidate the logfile, and stop logging.
*/
@@ -437,7 +438,8 @@ cachefs_log_error(cachefscache_t *cachep, int error, int getlock)
lc->lc_magic = CACHEFS_LOG_MAGIC;
lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
if (writable)
- (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred);
+ (void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred, NULL,
+ 0);
if (getlock)
mutex_exit(&cachep->c_log_mutex);
@@ -454,7 +456,7 @@ cachefs_log_write_header(struct vnode *vp, cachefscache_t *cachep, int error)
XDR xdrm;
attr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &attr, 0, kcred)) != 0)
+ if ((error = VOP_GETATTR(vp, &attr, 0, kcred, NULL)) != 0)
goto out;
if (attr.va_size != 0) {
error = vn_rdwr(UIO_READ, vp, buffy,
@@ -664,7 +666,7 @@ out:
cachefs_kmem_free(buffy, CACHEFS_LOG_ENCODE_SIZE);
/*
- * if an error occured, we need to free the buffers ourselves.
+ * if an error occurred, we need to free the buffers ourselves.
* cachefs_destory_cookie() can't do it.
*/
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_noopc.c b/usr/src/uts/common/fs/cachefs/cachefs_noopc.c
index 5b9c3d7062..245025bf0a 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_noopc.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_noopc.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -81,7 +80,7 @@ c_nop_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
/* get the attributes */
cp->c_attr.va_mask = AT_ALL;
ASSERT(cp->c_backvp != NULL);
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
if (error)
return (error);
} else {
@@ -127,7 +126,7 @@ c_nop_check_cached_object(struct fscache *fscp, struct cnode *cp,
/* get the file attributes from the back fs */
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
backhit = 1;
if (error)
goto out;
@@ -181,7 +180,7 @@ c_nop_modify_cached_object(struct fscache *fscp, struct cnode *cp, cred_t *cr)
return;
}
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
return;
nlink = cp->c_attr.va_nlink;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_resource.c b/usr/src/uts/common/fs/cachefs/cachefs_resource.c
index c250f7cef1..796d352237 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_resource.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_resource.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -76,7 +75,7 @@ static void cachefs_packed_pending(cachefscache_t *cachep);
(&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
/*
- * This function moves an RL entry from whereever it currently is to
+ * This function moves an RL entry from wherever it currently is to
* the back of the requested list.
*/
void
@@ -989,7 +988,7 @@ cachefs_cachep_worker_thread(cachefscache_t *cachep)
fl.l_sysid = 0;
fl.l_pid = 0;
error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl, FWRITE,
- (offset_t)0, NULL, kcred);
+ (offset_t)0, NULL, kcred, NULL);
if (error) {
cmn_err(CE_WARN,
"cachefs: Can't lock Cache Lock File(r); Error %d\n",
@@ -1058,7 +1057,7 @@ cachefs_cachep_worker_thread(cachefscache_t *cachep)
fl.l_sysid = 0;
fl.l_pid = 0;
error = VOP_FRLOCK(cachep->c_lockvp, F_SETLK, &fl,
- FWRITE, (offset_t)0, NULL, kcred);
+ FWRITE, (offset_t)0, NULL, kcred, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: Can't unlock lock file\n");
}
@@ -1407,7 +1406,7 @@ cachefs_gc_front_atime(cachefscache_t *cachep)
make_ascii_name(&dircid, namebuf);
if (VOP_LOOKUP(fscp->fs_fscdirvp, namebuf,
&dirvp, (struct pathname *)NULL, 0,
- (vnode_t *)NULL, kcred) == 0) {
+ (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) {
make_ascii_name(&cid, namebuf);
reledir++;
} else {
@@ -1417,7 +1416,7 @@ cachefs_gc_front_atime(cachefscache_t *cachep)
}
if (dirvp && VOP_LOOKUP(dirvp, namebuf, &filevp,
(struct pathname *)NULL, 0,
- (vnode_t *)NULL, kcred) == 0) {
+ (vnode_t *)NULL, kcred, NULL, NULL, NULL) == 0) {
gotfile = 1;
}
if (reledir)
@@ -1426,7 +1425,7 @@ cachefs_gc_front_atime(cachefscache_t *cachep)
if (gotfile) {
va.va_mask = AT_ATIME;
- if (VOP_GETATTR(filevp, &va, 0, kcred) == 0)
+ if (VOP_GETATTR(filevp, &va, 0, kcred, NULL) == 0)
rc = va.va_atime.tv_sec;
VN_RELE(filevp);
}
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_strict.c b/usr/src/uts/common/fs/cachefs/cachefs_strict.c
index 75fd305760..9a4011b459 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_strict.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_strict.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -93,7 +92,7 @@ c_strict_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
/* get the attributes */
cp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
if (error)
return (error);
} else {
@@ -146,7 +145,7 @@ c_strict_check_cached_object(struct fscache *fscp, struct cnode *cp,
if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
backhit = 1;
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
goto out;
cp->c_attr = attrs;
@@ -194,7 +193,7 @@ again:
/* get the file attributes from the back fs */
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
backhit = 1;
if (error)
goto out;
@@ -239,7 +238,7 @@ again:
}
if ((CTOV(cp))->v_type == VREG) {
attrs.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error)
goto out;
}
@@ -335,7 +334,7 @@ c_strict_modify_cached_object(struct fscache *fscp, struct cnode *cp,
attrs.va_mask = AT_ALL;
ASSERT(cp->c_backvp != NULL);
- error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
if (error) {
mdp->md_vattr.va_mtime.tv_sec = 0;
goto out;
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_subr.c b/usr/src/uts/common/fs/cachefs/cachefs_subr.c
index b3aac88a35..1f82e638e6 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_subr.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_subr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -277,7 +276,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* get the mode bits of the cache directory */
attrp->va_mask = AT_ALL;
- error = VOP_GETATTR(cdvp, attrp, 0, kcred);
+ error = VOP_GETATTR(cdvp, attrp, 0, kcred, NULL);
if (error)
goto out;
@@ -290,7 +289,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* Get the lock file */
error = VOP_LOOKUP(cdvp, CACHEFS_LOCK_FILE, &lockvp, NULL, 0, NULL,
- kcred);
+ kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_a: cache corruption"
" run fsck.\n");
@@ -299,7 +298,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* Get the label file */
error = VOP_LOOKUP(cdvp, CACHELABEL_NAME, &labelvp, NULL, 0, NULL,
- kcred);
+ kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_b: cache corruption"
" run fsck.\n");
@@ -324,7 +323,8 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
}
/* Open the resource file */
- error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred);
+ error = VOP_LOOKUP(cdvp, RESOURCE_NAME, &rifvp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_d: cache corruption"
" run fsck.\n");
@@ -360,7 +360,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* Open the lost+found directory */
error = VOP_LOOKUP(cdvp, CACHEFS_LOSTFOUND_NAME, &lostfoundvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: activate_g: cache corruption"
" run fsck.\n");
@@ -389,7 +389,7 @@ cachefs_cache_activate_ro(cachefscache_t *cachep, vnode_t *cdvp)
/* if the LOG_STATUS_NAME file exists, read it in and set up logging */
error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &statevp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0) {
int vnrw_error;
@@ -738,7 +738,7 @@ cachefs_cache_rssync(struct cachefscache *cachep)
if (error) {
cmn_err(CE_WARN, "cachefs: Can't Write Cache RL Info\n");
}
- error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred);
+ error = VOP_FSYNC(cachep->c_resfilevp, FSYNC, kcred, NULL);
return (error);
}
@@ -974,11 +974,11 @@ cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
if (cp->c_flags & CN_ASYNC_POP_WORKING) {
/* lookup the already created front file */
error = VOP_LOOKUP(fgp->fg_dirvp, name, &cp->c_frontvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
} else {
/* create the front file */
error = VOP_CREATE(fgp->fg_dirvp, name, attrp, EXCL, mode,
- &cp->c_frontvp, kcred, 0);
+ &cp->c_frontvp, kcred, 0, NULL, NULL);
}
if (error) {
#ifdef CFSDEBUG
@@ -992,7 +992,7 @@ cachefs_createfrontfile(cnode_t *cp, struct filegrp *fgp)
/* get a copy of the fid of the front file */
cp->c_metadata.md_fid.fid_len = MAXFIDSZ;
- error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid);
+ error = VOP_FID(cp->c_frontvp, &cp->c_metadata.md_fid, NULL);
if (error) {
/*
* If we get back ENOSPC then the fid we passed in was too
@@ -1013,7 +1013,7 @@ out:
if (error) {
if (cp->c_frontvp) {
VN_RELE(cp->c_frontvp);
- (void) VOP_REMOVE(fgp->fg_dirvp, name, kcred);
+ (void) VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
cp->c_frontvp = NULL;
}
if (ffrele)
@@ -1064,7 +1064,7 @@ cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
return;
}
make_ascii_name(cidp, name);
- error = VOP_REMOVE(fgp->fg_dirvp, name, kcred);
+ error = VOP_REMOVE(fgp->fg_dirvp, name, kcred, NULL, 0);
if (error == ENOENT)
enoent = 1;
if ((error) && (error != ENOENT)) {
@@ -1074,7 +1074,7 @@ cachefs_removefrontfile(cachefs_metadata_t *mdp, cfs_cid_t *cidp,
if (mdp->md_flags & MD_ACLDIR) {
(void) strcat(name, ".d");
error = VOP_RMDIR(fgp->fg_dirvp, name, fgp->fg_dirvp,
- kcred);
+ kcred, NULL, 0);
if ((error) && (error != ENOENT)) {
cmn_err(CE_WARN, "frontfs rmdir error %s %d"
"; run fsck\n", name, error);
@@ -1210,7 +1210,7 @@ cachefs_getfrontfile(cnode_t *cp)
/* get modify time of the front file */
va.va_mask = AT_MTIME;
- error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred);
+ error = VOP_GETATTR(cp->c_frontvp, &va, 0, kcred, NULL);
if (error) {
cmn_err(CE_WARN, "cachefs: gff2: front file"
" system error %d", error);
@@ -1721,7 +1721,7 @@ out:
/*
* due to compiler error we shifted cnode to the last argument slot.
- * occured during large files project - XXX.
+ * occurred during large files project - XXX.
*/
void
cachefs_cluster_allocmap(u_offset_t off, u_offset_t *popoffp,
@@ -1911,7 +1911,7 @@ cachefs_readlink_back(cnode_t *cp, cred_t *cr, caddr_t *bufp, int *buflenp)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_readlink (nfsv4): cnode %p, backvp %p\n",
cp, cp->c_backvp));
- error = VOP_READLINK(cp->c_backvp, &uio, cr);
+ error = VOP_READLINK(cp->c_backvp, &uio, cr, NULL);
if (error) {
cachefs_kmem_free(buf, MAXPATHLEN);
} else {
@@ -1980,7 +1980,7 @@ cachefs_getbackvp(struct fscache *fscp, struct cnode *cp)
flag |= FWRITE;
}
}
- error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred);
+ error = VOP_OPEN(&cp->c_backvp, flag, cp->c_cred, NULL);
if (error) {
VN_RELE(cp->c_backvp);
cp->c_backvp = NULL;
@@ -2028,7 +2028,7 @@ cachefs_getcookie(
* variable length fids we will need to change this.
*/
cookiep->fid_len = MAXFIDSZ;
- error = VOP_FID(vp, cookiep);
+ error = VOP_FID(vp, cookiep, NULL);
} else {
bzero(cookiep, sizeof (*cookiep));
}
@@ -2037,7 +2037,7 @@ cachefs_getcookie(
if (attrp) {
ASSERT(attrp != NULL);
attrp->va_mask = AT_ALL;
- error = VOP_GETATTR(vp, attrp, 0, cr);
+ error = VOP_GETATTR(vp, attrp, 0, cr, NULL);
}
} else {
if (error == ENOSPC) {
@@ -2254,7 +2254,7 @@ cachefs_async_putpage(struct cachefs_putpage_req *prp, cred_t *cr)
ASSERT(CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)) == 0);
(void) VOP_PUTPAGE(prp->cp_vp, prp->cp_off, prp->cp_len,
- prp->cp_flags, cr);
+ prp->cp_flags, cr, NULL);
mutex_enter(&cp->c_iomutex);
if (--cp->c_nio == 0)
@@ -2378,7 +2378,7 @@ cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
make_ascii_name(&cid, name);
(void) VOP_CREATE(fgp->fg_dirvp, name, attrp,
- EXCL, 0666, &frontvp, kcred, 0);
+ EXCL, 0666, &frontvp, kcred, 0, NULL, NULL);
cachefs_kmem_free(attrp,
sizeof (struct vattr));
@@ -2433,7 +2433,7 @@ cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
if (error != 0)
goto out;
- error = VOP_FSYNC(frontvp, FSYNC, cr);
+ error = VOP_FSYNC(frontvp, FSYNC, cr, NULL);
if (error != 0) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_ASYNCPOP)
@@ -2453,7 +2453,7 @@ cachefs_async_populate(struct cachefs_populate_req *pop, cred_t *cr)
}
va.va_mask = AT_MTIME;
- error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr);
+ error = VOP_GETATTR(cp->c_frontvp, &va, 0, cr, NULL);
if (error) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_ASYNCPOP)
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c b/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c
index fd1ee0b4d8..26631b3380 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_vfsops.c
@@ -403,7 +403,7 @@ again:
}
fscache_list_add(cachep, fscp);
} else {
- /* compare the options to make sure they are compatable */
+ /* compare the options to make sure they are compatible */
error = fscache_compare_options(fscp, cfs_options);
if (error) {
cmn_err(CE_WARN,
@@ -426,7 +426,7 @@ again:
error = 0;
if (fscp->fs_fscdirvp) {
error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
- &tmpdirvp, NULL, 0, NULL, kcred);
+ &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
/*
* If a log file exists and the cache is being mounted without
@@ -550,7 +550,7 @@ again:
*/
error = VOP_PATHCONF(backrootvp, _PC_FILESIZEBITS, &maxfilesizebits,
- kcred);
+ kcred, NULL);
if (error) {
cmn_err(CE_WARN,
@@ -562,7 +562,8 @@ again:
mutex_exit(&fscp->fs_fslock);
/* remove the unmount file if it is there */
- (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred);
+ (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred, NULL,
+ 0);
/* wake up the cache worker if ANY packed pending work */
mutex_enter(&cachep->c_contentslock);
@@ -957,7 +958,7 @@ cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
if (fscp->fs_fscdirvp != NULL)
xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
- NONEXCL, 0600, &nmvp, kcred, 0);
+ NONEXCL, 0600, &nmvp, kcred, 0, NULL, NULL);
else
xx = ENOENT; /* for unmounting when NOCACHE */
if (xx == 0) {
@@ -1207,7 +1208,7 @@ cachefs_remount(struct vfs *vfsp, struct mounta *uap)
error = 0;
if (cachedirvp) {
error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
- &tmpdirvp, NULL, 0, NULL, kcred);
+ &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
}
cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
diff --git a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c
index 5451c20467..795c70dc3d 100644
--- a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c
+++ b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c
@@ -136,60 +136,71 @@ static int cachefs_readback_translate(cnode_t *cp, uio_t *uiop,
static int cachefs_setattr_common(vnode_t *vp, vattr_t *vap, int flags,
cred_t *cr, caller_context_t *ct);
-static int cachefs_open(struct vnode **, int, cred_t *);
+static int cachefs_open(struct vnode **, int, cred_t *,
+ caller_context_t *);
static int cachefs_close(struct vnode *, int, int, offset_t,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_read(struct vnode *, struct uio *, int, cred_t *,
caller_context_t *);
static int cachefs_write(struct vnode *, struct uio *, int, cred_t *,
caller_context_t *);
static int cachefs_ioctl(struct vnode *, int, intptr_t, int, cred_t *,
- int *);
+ int *, caller_context_t *);
static int cachefs_getattr(struct vnode *, struct vattr *, int,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_setattr(struct vnode *, struct vattr *,
int, cred_t *, caller_context_t *);
-static int cachefs_access(struct vnode *, int, int, cred_t *);
+static int cachefs_access(struct vnode *, int, int, cred_t *,
+ caller_context_t *);
static int cachefs_lookup(struct vnode *, char *, struct vnode **,
- struct pathname *, int, struct vnode *, cred_t *);
+ struct pathname *, int, struct vnode *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
static int cachefs_create(struct vnode *, char *, struct vattr *,
- enum vcexcl, int, struct vnode **, cred_t *, int);
+ enum vcexcl, int, struct vnode **, cred_t *, int,
+ caller_context_t *, vsecattr_t *);
static int cachefs_create_connected(vnode_t *dvp, char *nm,
vattr_t *vap, enum vcexcl exclusive, int mode,
vnode_t **vpp, cred_t *cr);
static int cachefs_create_disconnected(vnode_t *dvp, char *nm,
vattr_t *vap, enum vcexcl exclusive, int mode,
vnode_t **vpp, cred_t *cr);
-static int cachefs_remove(struct vnode *, char *, cred_t *);
+static int cachefs_remove(struct vnode *, char *, cred_t *,
+ caller_context_t *, int);
static int cachefs_link(struct vnode *, struct vnode *, char *,
- cred_t *);
+ cred_t *, caller_context_t *, int);
static int cachefs_rename(struct vnode *, char *, struct vnode *,
- char *, cred_t *);
+ char *, cred_t *, caller_context_t *, int);
static int cachefs_mkdir(struct vnode *, char *, struct
- vattr *, struct vnode **, cred_t *);
+ vattr *, struct vnode **, cred_t *, caller_context_t *,
+ int, vsecattr_t *);
static int cachefs_rmdir(struct vnode *, char *, struct vnode *,
- cred_t *);
+ cred_t *, caller_context_t *, int);
static int cachefs_readdir(struct vnode *, struct uio *,
- cred_t *, int *);
+ cred_t *, int *, caller_context_t *, int);
static int cachefs_symlink(struct vnode *, char *, struct vattr *,
- char *, cred_t *);
-static int cachefs_readlink(struct vnode *, struct uio *, cred_t *);
+ char *, cred_t *, caller_context_t *, int);
+static int cachefs_readlink(struct vnode *, struct uio *, cred_t *,
+ caller_context_t *);
static int cachefs_readlink_connected(vnode_t *vp, uio_t *uiop, cred_t *cr);
static int cachefs_readlink_disconnected(vnode_t *vp, uio_t *uiop);
-static int cachefs_fsync(struct vnode *, int, cred_t *);
-static void cachefs_inactive(struct vnode *, cred_t *);
-static int cachefs_fid(struct vnode *, struct fid *);
+static int cachefs_fsync(struct vnode *, int, cred_t *,
+ caller_context_t *);
+static void cachefs_inactive(struct vnode *, cred_t *, caller_context_t *);
+static int cachefs_fid(struct vnode *, struct fid *, caller_context_t *);
static int cachefs_rwlock(struct vnode *, int, caller_context_t *);
static void cachefs_rwunlock(struct vnode *, int, caller_context_t *);
-static int cachefs_seek(struct vnode *, offset_t, offset_t *);
+static int cachefs_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
static int cachefs_frlock(struct vnode *, int, struct flock64 *,
- int, offset_t, struct flk_callback *, cred_t *);
+ int, offset_t, struct flk_callback *, cred_t *,
+ caller_context_t *);
static int cachefs_space(struct vnode *, int, struct flock64 *, int,
offset_t, cred_t *, caller_context_t *);
-static int cachefs_realvp(struct vnode *, struct vnode **);
+static int cachefs_realvp(struct vnode *, struct vnode **,
+ caller_context_t *);
static int cachefs_getpage(struct vnode *, offset_t, size_t, uint_t *,
struct page *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
static int cachefs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
struct page *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
@@ -197,37 +208,42 @@ static int cachefs_getapage_back(struct vnode *, u_offset_t, size_t,
uint_t *, struct page *[], size_t, struct seg *, caddr_t,
enum seg_rw, cred_t *);
static int cachefs_putpage(struct vnode *, offset_t, size_t, int,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_map(struct vnode *, offset_t, struct as *,
- caddr_t *, size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ caddr_t *, size_t, uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
static int cachefs_addmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ caddr_t, size_t, uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
static int cachefs_delmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uint_t, uint_t, uint_t, cred_t *);
+ caddr_t, size_t, uint_t, uint_t, uint_t, cred_t *,
+ caller_context_t *);
static int cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec,
- int flag, cred_t *cr);
+ int flag, cred_t *cr, caller_context_t *);
static int cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec,
- int flag, cred_t *cr);
+ int flag, cred_t *cr, caller_context_t *);
static int cachefs_shrlock(vnode_t *, int, struct shrlock *, int,
- cred_t *);
+ cred_t *, caller_context_t *);
static int cachefs_getsecattr_connected(vnode_t *vp, vsecattr_t *vsec, int flag,
cred_t *cr);
static int cachefs_getsecattr_disconnected(vnode_t *vp, vsecattr_t *vsec,
int flag, cred_t *cr);
-static int cachefs_dump(struct vnode *, caddr_t, int, int);
+static int cachefs_dump(struct vnode *, caddr_t, int, int,
+ caller_context_t *);
static int cachefs_pageio(struct vnode *, page_t *,
- u_offset_t, size_t, int, cred_t *);
+ u_offset_t, size_t, int, cred_t *, caller_context_t *);
static int cachefs_writepage(struct vnode *vp, caddr_t base,
int tcount, struct uio *uiop);
-static int cachefs_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+static int cachefs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
static int cachefs_read_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag,
cred_t *cr, caller_context_t *ct);
static int cachefs_write_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag,
cred_t *cr, caller_context_t *ct);
static int cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
- int flags, cred_t *cr);
+ int flags, cred_t *cr, caller_context_t *ct);
static int cachefs_remove_backfs_nfsv4(vnode_t *dvp, char *nm, cred_t *cr,
vnode_t *vp);
static int cachefs_getpage_backfs_nfsv4(struct vnode *vp, offset_t off,
@@ -305,7 +321,7 @@ cachefs_getvnodeops(void)
}
static int
-cachefs_open(vnode_t **vpp, int flag, cred_t *cr)
+cachefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error = 0;
cnode_t *cp = VTOC(*vpp);
@@ -413,7 +429,7 @@ cachefs_open(vnode_t **vpp, int flag, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_open (nfsv4): cnode %p, "
"backvp %p\n", cp, cp->c_backvp));
- error = VOP_OPEN(&cp->c_backvp, flag, cr);
+ error = VOP_OPEN(&cp->c_backvp, flag, cr, ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -469,7 +485,8 @@ out:
/* ARGSUSED */
static int
-cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
cnode_t *cp = VTOC(vp);
@@ -552,7 +569,7 @@ cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
("cachefs_close (nfsv4): cnode %p, "
"backvp %p\n", cp, cp->c_backvp));
error = VOP_CLOSE(cp->c_backvp, flag, count,
- offset, cr);
+ offset, cr, ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -627,7 +644,7 @@ cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
if (cp->c_backvp &&
(fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
error = VOP_CLOSE(cp->c_backvp, flag, close_cnt,
- offset, cr);
+ offset, cr, ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -1706,7 +1723,8 @@ out:
/*ARGSUSED*/
static int
-cachefs_dump(struct vnode *vp, caddr_t foo1, int foo2, int foo3)
+cachefs_dump(struct vnode *vp, caddr_t foo1, int foo2, int foo3,
+ caller_context_t *ct)
{
return (ENOSYS); /* should we panic if we get here? */
}
@@ -1714,7 +1732,7 @@ cachefs_dump(struct vnode *vp, caddr_t foo1, int foo2, int foo3)
/*ARGSUSED*/
static int
cachefs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, cred_t *cred,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
int error;
struct cnode *cp = VTOC(vp);
@@ -1989,7 +2007,8 @@ cachefs_fileno_conflict(fscache_t *fscp, ino64_t old)
/*ARGSUSED*/
static int
-cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
struct cnode *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -2007,7 +2026,7 @@ cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* Call backfilesystem getattr if NFSv4 */
if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
- error = cachefs_getattr_backfs_nfsv4(vp, vap, flags, cr);
+ error = cachefs_getattr_backfs_nfsv4(vp, vap, flags, cr, ct);
goto out;
}
@@ -2175,7 +2194,7 @@ out:
*/
static int
cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -2198,7 +2217,7 @@ cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
CFS_DPRINT_BACKFS_NFSV4(fscp, ("cachefs_getattr_backfs_nfsv4: cnode %p,"
" backvp %p\n", cp, backvp));
- error = VOP_GETATTR(backvp, vap, flags, cr);
+ error = VOP_GETATTR(backvp, vap, flags, cr, ct);
/* Update attributes */
cp->c_attr = *vap;
@@ -2252,7 +2271,7 @@ cachefs_setattr(
held = 0;
}
- /* aquire access to the file system */
+ /* acquire access to the file system */
error = cachefs_cd_access(fscp, connected, 1);
if (error)
break;
@@ -2461,7 +2480,7 @@ cachefs_setattr_connected(
/* XXX bob: given what modify_cobject does this seems unnecessary */
cp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr);
+ error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, ct);
if (error)
goto out;
@@ -2719,7 +2738,8 @@ out:
/* ARGSUSED */
static int
-cachefs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+cachefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -2842,7 +2862,7 @@ cachefs_access_connected(struct vnode *vp, int mode, int flags, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_access (nfsv4): cnode %p, backvp %p\n",
cp, cp->c_backvp));
- error = VOP_ACCESS(cp->c_backvp, mode, flags, cr);
+ error = VOP_ACCESS(cp->c_backvp, mode, flags, cr, NULL);
/*
* even though we don't `need' the ACL to do access
@@ -2873,8 +2893,9 @@ out:
* CFS has a fastsymlink scheme. If the size of the link is < C_FSL_SIZE, then
* the link is placed in the metadata itself (no front file is allocated).
*/
+/*ARGSUSED*/
static int
-cachefs_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+cachefs_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
int error = 0;
cnode_t *cp = VTOC(vp);
@@ -3125,7 +3146,7 @@ out:
/*ARGSUSED*/
static int
-cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
int error = 0;
@@ -3215,7 +3236,8 @@ cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_fsync (nfsv4): cnode %p, "
"backvp %p\n", cp, cp->c_backvp));
- error = VOP_FSYNC(cp->c_backvp, syncflag, cr);
+ error = VOP_FSYNC(cp->c_backvp, syncflag, cr,
+ ct);
if (CFS_TIMEOUT(fscp, error)) {
mutex_exit(&cp->c_statelock);
cachefs_cd_release(fscp);
@@ -3304,13 +3326,13 @@ cachefs_sync_metadata(cnode_t *cp)
if (cp->c_flags & CN_NEED_FRONT_SYNC) {
if (cp->c_frontvp != NULL) {
- error = VOP_FSYNC(cp->c_frontvp, FSYNC, kcred);
+ error = VOP_FSYNC(cp->c_frontvp, FSYNC, kcred, NULL);
if (error) {
cp->c_metadata.md_timestamp.tv_sec = 0;
} else {
va.va_mask = AT_MTIME;
error = VOP_GETATTR(cp->c_frontvp, &va, 0,
- kcred);
+ kcred, NULL);
if (error)
goto out;
cp->c_metadata.md_timestamp = va.va_mtime;
@@ -3376,8 +3398,9 @@ out:
* calls cachefs_inactive.
* Because of the dnlc, it is not safe to grab most locks here.
*/
+/*ARGSUSED*/
static void
-cachefs_inactive(struct vnode *vp, cred_t *cr)
+cachefs_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp;
struct cachefs_req *rp;
@@ -3425,7 +3448,9 @@ cachefs_inactive(struct vnode *vp, cred_t *cr)
/* ARGSUSED */
static int
cachefs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp,
- struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr)
+ struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
+
{
int error = 0;
cnode_t *dcp = VTOC(dvp);
@@ -3740,13 +3765,13 @@ cachefs_lookup_back(vnode_t *dvp, char *nm, vnode_t **vpp,
("cachefs_lookup (nfsv4): dcp %p, dbackvp %p, name %s\n",
dcp, dcp->c_backvp, nm));
error = VOP_LOOKUP(dcp->c_backvp, nm, &backvp, (struct pathname *)NULL,
- 0, (vnode_t *)NULL, cr);
+ 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
if (error)
goto out;
if (IS_DEVVP(backvp)) {
struct vnode *devvp = backvp;
- if (VOP_REALVP(devvp, &backvp) == 0) {
+ if (VOP_REALVP(devvp, &backvp, NULL) == 0) {
VN_HOLD(backvp);
VN_RELE(devvp);
}
@@ -3793,7 +3818,9 @@ out:
/*ARGSUSED7*/
static int
cachefs_create(vnode_t *dvp, char *nm, vattr_t *vap,
- vcexcl_t exclusive, int mode, vnode_t **vpp, cred_t *cr, int flag)
+ vcexcl_t exclusive, int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
+
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -3942,9 +3969,8 @@ cachefs_create_connected(vnode_t *dvp, char *nm, vattr_t *vap,
cachefs_access_connected(vp, mode, 0, cr)) == 0) {
if ((vap->va_mask & AT_SIZE) && (vp->v_type == VREG)) {
vap->va_mask = AT_SIZE;
- error =
- cachefs_setattr_common(vp, vap,
- 0, cr, NULL);
+ error = cachefs_setattr_common(vp, vap, 0,
+ cr, NULL);
}
}
if (error) {
@@ -3978,11 +4004,11 @@ cachefs_create_connected(vnode_t *dvp, char *nm, vattr_t *vap,
("cachefs_create (nfsv4): dcp %p, dbackvp %p,"
"name %s\n", dcp, dcp->c_backvp, nm));
error = VOP_CREATE(dcp->c_backvp, nm, vap, exclusive, mode,
- &devvp, cr, 0);
+ &devvp, cr, 0, NULL, NULL);
mutex_exit(&dcp->c_statelock);
if (error)
goto out;
- if (VOP_REALVP(devvp, &tvp) == 0) {
+ if (VOP_REALVP(devvp, &tvp, NULL) == 0) {
VN_HOLD(tvp);
VN_RELE(devvp);
} else {
@@ -4096,9 +4122,8 @@ cachefs_create_disconnected(vnode_t *dvp, char *nm, vattr_t *vap,
if ((vap->va_mask & AT_SIZE) &&
(vp->v_type == VREG)) {
vap->va_mask = AT_SIZE;
- error =
- cachefs_setattr_common(vp, vap,
- 0, cr, NULL);
+ error = cachefs_setattr_common(vp,
+ vap, 0, cr, NULL);
}
}
}
@@ -4264,8 +4289,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_remove(vnode_t *dvp, char *nm, cred_t *cr)
+cachefs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -4511,7 +4538,7 @@ cachefs_remove_connected(vnode_t *dvp, char *nm, cred_t *cr, vnode_t *vp)
}
/* perform the remove on the back fs */
- error = VOP_REMOVE(dcp->c_backvp, nm, cr);
+ error = VOP_REMOVE(dcp->c_backvp, nm, cr, NULL, 0);
if (error) {
mutex_exit(&dcp->c_statelock);
goto out;
@@ -4641,7 +4668,7 @@ cachefs_remove_backfs_nfsv4(vnode_t *dvp, char *nm, cred_t *cr, vnode_t *vp)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_remove (nfsv4): dcp %p, dbackvp %p, name %s\n",
dcp, dbackvp, nm));
- error = VOP_REMOVE(dbackvp, nm, cr);
+ error = VOP_REMOVE(dbackvp, nm, cr, NULL, 0);
if (error) {
mutex_exit(&cp->c_statelock);
goto out;
@@ -4789,8 +4816,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
+cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
fscache_t *fscp = VFS_TO_FSCACHE(tdvp->v_vfsp);
cnode_t *tdcp = VTOC(tdvp);
@@ -4813,7 +4842,7 @@ cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
ASSERT(tdcp->c_flags & CN_NOCACHE);
- if (VOP_REALVP(fvp, &realvp) == 0) {
+ if (VOP_REALVP(fvp, &realvp, ct) == 0) {
fvp = realvp;
}
@@ -4939,7 +4968,7 @@ cachefs_link_connected(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_link (nfsv4): tdcp %p, tdbackvp %p, "
"name %s\n", tdcp, tdcp->c_backvp, tnm));
- error = VOP_LINK(tdcp->c_backvp, backvp, tnm, cr);
+ error = VOP_LINK(tdcp->c_backvp, backvp, tnm, cr, NULL, 0);
if (error) {
mutex_exit(&tdcp->c_statelock);
goto out;
@@ -4973,7 +5002,7 @@ cachefs_link_connected(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
/* XXX bob: given what modify_cobject does this seems unnecessary */
fcp->c_attr.va_mask = AT_ALL;
- error = VOP_GETATTR(fcp->c_backvp, &fcp->c_attr, 0, cr);
+ error = VOP_GETATTR(fcp->c_backvp, &fcp->c_attr, 0, cr, NULL);
mutex_exit(&fcp->c_statelock);
out:
if (backvp)
@@ -5108,9 +5137,10 @@ out:
*/
kmutex_t cachefs_rename_lock;
+/*ARGSUSED*/
static int
cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
- char *nnm, cred_t *cr)
+ char *nnm, cred_t *cr, caller_context_t *ct, int flags)
{
fscache_t *fscp = C_TO_FSCACHE(VTOC(odvp));
cachefscache_t *cachep = fscp->fs_cache;
@@ -5125,7 +5155,7 @@ cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
if (getzoneid() != GLOBAL_ZONEID)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
/*
@@ -5286,7 +5316,7 @@ cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
bzero(&gone, sizeof (gone));
gone.fid_len = MAXFIDSZ;
if (delvp != NULL)
- (void) VOP_FID(delvp, &gone);
+ (void) VOP_FID(delvp, &gone, ct);
cachefs_log_rename(cachep, error, fscp->fs_cfsvfsp,
&gone, 0, (delvp != NULL), crgetuid(cr));
@@ -5407,7 +5437,8 @@ cachefs_rename_connected(vnode_t *odvp, char *onm, vnode_t *ndvp,
("cachefs_rename (nfsv4): odcp %p, odbackvp %p, "
" ndcp %p, ndbackvp %p, onm %s, nnm %s\n",
odcp, odcp->c_backvp, ndcp, ndcp->c_backvp, onm, nnm));
- error = VOP_RENAME(odcp->c_backvp, onm, ndcp->c_backvp, nnm, cr);
+ error = VOP_RENAME(odcp->c_backvp, onm, ndcp->c_backvp, nnm, cr, NULL,
+ 0);
if (error)
goto out;
@@ -5780,9 +5811,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
cachefs_mkdir(vnode_t *dvp, char *nm, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -5926,7 +5958,7 @@ cachefs_mkdir_connected(vnode_t *dvp, char *nm, vattr_t *vap,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_mkdir (nfsv4): dcp %p, dbackvp %p, "
"name %s\n", dcp, dcp->c_backvp, nm));
- error = VOP_MKDIR(dcp->c_backvp, nm, vap, &vp, cr);
+ error = VOP_MKDIR(dcp->c_backvp, nm, vap, &vp, cr, NULL, 0, NULL);
mutex_exit(&dcp->c_statelock);
if (error) {
goto out;
@@ -6150,8 +6182,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -6269,7 +6303,7 @@ cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
}
/* must not be current dir */
- if (VOP_CMP(vp, cdir)) {
+ if (VOP_CMP(vp, cdir, ct)) {
error = EINVAL;
break;
}
@@ -6372,7 +6406,7 @@ cachefs_rmdir_connected(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_rmdir (nfsv4): dcp %p, dbackvp %p, "
"name %s\n", dcp, dcp->c_backvp, nm));
- error = VOP_RMDIR(dcp->c_backvp, nm, cdir, cr);
+ error = VOP_RMDIR(dcp->c_backvp, nm, cdir, cr, NULL, 0);
if (error)
goto out;
@@ -6507,9 +6541,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
cachefs_symlink(vnode_t *dvp, char *lnm, vattr_t *tva,
- char *tnm, cred_t *cr)
+ char *tnm, cred_t *cr, caller_context_t *ct, int flags)
{
cnode_t *dcp = VTOC(dvp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -6635,7 +6670,7 @@ cachefs_symlink_connected(vnode_t *dvp, char *lnm, vattr_t *tva,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_symlink (nfsv4): dcp %p, dbackvp %p, "
"lnm %s, tnm %s\n", dcp, dcp->c_backvp, lnm, tnm));
- error = VOP_SYMLINK(dcp->c_backvp, lnm, tva, tnm, cr);
+ error = VOP_SYMLINK(dcp->c_backvp, lnm, tva, tnm, cr, NULL, 0);
if (error) {
mutex_exit(&dcp->c_statelock);
goto out;
@@ -6650,7 +6685,8 @@ cachefs_symlink_connected(vnode_t *dvp, char *lnm, vattr_t *tva,
CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
/* lookup the symlink we just created and get its fid and attrs */
- (void) VOP_LOOKUP(dcp->c_backvp, lnm, &backvp, NULL, 0, NULL, cr);
+ (void) VOP_LOOKUP(dcp->c_backvp, lnm, &backvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (backvp == NULL) {
if (CFS_ISFS_BACKFS_NFSV4(fscp) == 0)
cachefs_nocache(dcp);
@@ -6891,8 +6927,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+cachefs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
cnode_t *dcp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(dcp);
@@ -7087,7 +7125,8 @@ cachefs_readdir_connected(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_readdir (nfsv4): "
"dcp %p, dbackvp %p\n", dcp, dcp->c_backvp));
- error = VOP_READDIR(dcp->c_backvp, uiop, cr, eofp);
+ error = VOP_READDIR(dcp->c_backvp, uiop, cr, eofp,
+ NULL, 0);
VOP_RWUNLOCK(dcp->c_backvp, V_WRITELOCK_FALSE, NULL);
}
@@ -7132,7 +7171,7 @@ cachefs_readback_translate(cnode_t *cp, uio_t *uiop, cred_t *cr, int *eofp)
uioin.uio_resid = buffysize;
(void) VOP_RWLOCK(cp->c_backvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(cp->c_backvp, &uioin, cr, eofp);
+ error = VOP_READDIR(cp->c_backvp, &uioin, cr, eofp, NULL, 0);
VOP_RWUNLOCK(cp->c_backvp, V_WRITELOCK_FALSE, NULL);
if (error != 0)
@@ -7186,8 +7225,9 @@ cachefs_readdir_disconnected(vnode_t *vp, uio_t *uiop, cred_t *cr,
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_fid(struct vnode *vp, struct fid *fidp)
+cachefs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
int error = 0;
struct cnode *cp = VTOC(vp);
@@ -7257,7 +7297,8 @@ cachefs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-cachefs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+cachefs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
return (0);
}
@@ -7266,10 +7307,11 @@ static int cachefs_lostpage = 0;
/*
* Return all the pages from [off..off+len] in file
*/
+/*ARGSUSED*/
static int
cachefs_getpage(struct vnode *vp, offset_t off, size_t len,
uint_t *protp, struct page *pl[], size_t plsz, struct seg *seg,
- caddr_t addr, enum seg_rw rw, cred_t *cr)
+ caddr_t addr, enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
int error;
@@ -7441,7 +7483,7 @@ cachefs_getpage_backfs_nfsv4(struct vnode *vp, offset_t off, size_t len,
("cachefs_getpage_backfs_nfsv4: cnode %p, backvp %p\n",
cp, backvp));
error = VOP_GETPAGE(backvp, off, len, protp, pl, plsz, seg,
- addr, rw, cr);
+ addr, rw, cr, NULL);
return (error);
}
@@ -7507,7 +7549,7 @@ again:
}
error = VOP_GETPAGE(cp->c_backvp, off,
PAGESIZE, protp, ourpl, PAGESIZE, seg,
- addr, S_READ, cr);
+ addr, S_READ, cr, NULL);
/*
* backfs returns EFAULT when we are trying for a
* page beyond EOF but cachefs has the knowledge that
@@ -7588,13 +7630,14 @@ again:
/* else XXX assert CN_NOCACHE? */
error = VOP_GETPAGE(cp->c_backvp, (offset_t)off,
PAGESIZE, protp, ourpl, popsize,
- seg, addr, S_READ, cr);
+ seg, addr, S_READ, cr, NULL);
if (error)
goto out;
fscp->fs_stats.st_misses++;
} else {
if (cp->c_flags & CN_POPULATION_PENDING) {
- error = VOP_FSYNC(cp->c_frontvp, FSYNC, cr);
+ error = VOP_FSYNC(cp->c_frontvp, FSYNC, cr,
+ NULL);
cp->c_flags &= ~CN_POPULATION_PENDING;
if (error) {
cachefs_nocache(cp);
@@ -7608,7 +7651,7 @@ again:
*/
error = VOP_GETPAGE(cp->c_frontvp, (offset_t)off,
PAGESIZE, protp, ourpl, PAGESIZE, seg, addr,
- rw, cr);
+ rw, cr, NULL);
if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_GPFRONT))
cachefs_log_gpfront(cachep, error,
fscp->fs_cfsvfsp,
@@ -7718,7 +7761,7 @@ again:
}
error = VOP_GETPAGE(cp->c_backvp, (offset_t)off,
PAGESIZE, protp, ourpl, PAGESIZE, seg,
- addr, S_READ, cr);
+ addr, S_READ, cr, NULL);
if (error)
goto out;
@@ -7776,8 +7819,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+cachefs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
int error = 0;
@@ -7874,7 +7919,7 @@ cachefs_putpage_backfs_nfsv4(vnode_t *vp, offset_t off, size_t len, int flags,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_putpage_backfs_nfsv4: cnode %p, backvp %p\n",
cp, backvp));
- error = VOP_PUTPAGE(backvp, off, len, flags, cr);
+ error = VOP_PUTPAGE(backvp, off, len, flags, cr, NULL);
return (error);
}
@@ -8046,7 +8091,8 @@ again:
/*ARGSUSED*/
static int
cachefs_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8224,7 +8270,8 @@ cachefs_map_backfs_nfsv4(struct vnode *vp, offset_t off, struct as *as,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_map_backfs_nfsv4: cnode %p, backvp %p\n",
cp, backvp));
- error = VOP_MAP(backvp, off, as, addrp, len, prot, maxprot, flags, cr);
+ error = VOP_MAP(backvp, off, as, addrp, len, prot, maxprot, flags, cr,
+ NULL);
return (error);
}
@@ -8233,7 +8280,7 @@ cachefs_map_backfs_nfsv4(struct vnode *vp, offset_t off, struct as *as,
static int
cachefs_addmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8261,7 +8308,7 @@ cachefs_addmap(struct vnode *vp, offset_t off, struct as *as,
static int
cachefs_delmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8346,7 +8393,8 @@ cachefs_delmap(struct vnode *vp, offset_t off, struct as *as,
/* ARGSUSED */
static int
cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
struct cnode *cp = VTOC(vp);
int error;
@@ -8382,7 +8430,7 @@ cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
/* XXX bob: nfs does a bunch more checks than we do */
if (CFS_ISFS_LLOCK(fscp)) {
ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
for (;;) {
@@ -8441,7 +8489,7 @@ cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
if (bfp->l_type != F_UNLCK && cmd != F_GETLK &&
!CFS_ISFS_BACKFS_NFSV4(fscp)) {
error = cachefs_putpage(
- vp, (offset_t)0, 0, B_INVAL, cr);
+ vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
error = ENOLCK;
VN_RELE(backvp);
@@ -8453,7 +8501,8 @@ cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_frlock (nfsv4): cp %p, backvp %p\n",
cp, backvp));
- error = VOP_FRLOCK(backvp, cmd, bfp, flag, offset, NULL, cr);
+ error = VOP_FRLOCK(backvp, cmd, bfp, flag, offset, NULL, cr,
+ ct);
VN_RELE(backvp);
if (CFS_TIMEOUT(fscp, error)) {
connected = 1;
@@ -8571,7 +8620,7 @@ cachefs_space_backfs_nfsv4(struct vnode *vp, int cmd, struct flock64 *bfp,
/*ARGSUSED*/
static int
-cachefs_realvp(struct vnode *vp, struct vnode **vpp)
+cachefs_realvp(struct vnode *vp, struct vnode **vpp, caller_context_t *ct)
{
return (EINVAL);
}
@@ -8579,7 +8628,7 @@ cachefs_realvp(struct vnode *vp, struct vnode **vpp)
/*ARGSUSED*/
static int
cachefs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
return (ENOSYS);
}
@@ -8618,7 +8667,7 @@ cachefs_setsecattr_connected(cnode_t *cp,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_setsecattr (nfsv4): cp %p, backvp %p",
cp, cp->c_backvp));
- error = VOP_SETSECATTR(cp->c_backvp, vsec, flag, cr);
+ error = VOP_SETSECATTR(cp->c_backvp, vsec, flag, cr, NULL);
if (error) {
goto out;
}
@@ -8742,8 +8791,10 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
-cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
+cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8791,7 +8842,7 @@ cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
held = 0;
}
- /* aquire access to the file system */
+ /* acquire access to the file system */
error = cachefs_cd_access(fscp, connected, 1);
if (error)
break;
@@ -8883,7 +8934,8 @@ cachefs_acl2perm(cnode_t *cp, vsecattr_t *vsec)
}
static int
-cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
+cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -8913,7 +8965,7 @@ cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr)
CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
if (fscp->fs_info.fi_mntflags & CFS_NOACL) {
- error = fs_fab_acl(vp, vsec, flag, cr);
+ error = fs_fab_acl(vp, vsec, flag, cr, ct);
goto out;
}
@@ -8974,7 +9026,8 @@ out:
}
static int
-cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
cnode_t *cp = VTOC(vp);
fscache_t *fscp = C_TO_FSCACHE(cp);
@@ -9014,7 +9067,7 @@ cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_shrlock (nfsv4): cp %p, backvp %p",
cp, backvp));
- error = VOP_SHRLOCK(backvp, cmd, shr, flag, cr);
+ error = VOP_SHRLOCK(backvp, cmd, shr, flag, cr, ct);
}
out:
@@ -9065,7 +9118,7 @@ cachefs_getsecattr_connected(vnode_t *vp, vsecattr_t *vsec, int flag,
CFS_DPRINT_BACKFS_NFSV4(fscp,
("cachefs_getsecattr (nfsv4): cp %p, backvp %p",
cp, cp->c_backvp));
- error = VOP_GETSECATTR(cp->c_backvp, vsec, flag, cr);
+ error = VOP_GETSECATTR(cp->c_backvp, vsec, flag, cr, NULL);
if (error)
goto out;
@@ -9178,7 +9231,7 @@ cachefs_cacheacl(cnode_t *cp, vsecattr_t *vsecp)
bzero(&vsec, sizeof (vsec));
vsecp->vsa_mask =
VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT;
- error = VOP_GETSECATTR(cp->c_backvp, vsecp, 0, kcred);
+ error = VOP_GETSECATTR(cp->c_backvp, vsecp, 0, kcred, NULL);
if (error != 0) {
goto out;
}
@@ -9256,7 +9309,7 @@ cachefs_cacheacl(cnode_t *cp, vsecattr_t *vsecp)
ASSERT(vp != NULL);
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(vp, vsecp, 0, kcred);
+ error = VOP_SETSECATTR(vp, vsecp, 0, kcred, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
if (error != 0) {
#ifdef CFSDEBUG
@@ -9320,7 +9373,7 @@ cachefs_purgeacl(cnode_t *cp)
(void) strcat(name, ".d");
(void) VOP_RMDIR(cp->c_filegrp->fg_dirvp, name,
- cp->c_filegrp->fg_dirvp, kcred);
+ cp->c_filegrp->fg_dirvp, kcred, NULL, 0);
}
cp->c_metadata.md_flags &= ~(MD_ACL | MD_ACLDIR);
@@ -9345,7 +9398,7 @@ cachefs_getacldirvp(cnode_t *cp)
make_ascii_name(&cp->c_id, name);
(void) strcat(name, ".d");
error = VOP_LOOKUP(cp->c_filegrp->fg_dirvp,
- name, &cp->c_acldirvp, NULL, 0, NULL, kcred);
+ name, &cp->c_acldirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
if ((error != 0) && (error != ENOENT))
goto out;
@@ -9360,7 +9413,7 @@ cachefs_getacldirvp(cnode_t *cp)
AT_UID | AT_GID;
error =
VOP_MKDIR(cp->c_filegrp->fg_dirvp,
- name, &va, &cp->c_acldirvp, kcred);
+ name, &va, &cp->c_acldirvp, kcred, NULL, 0, NULL);
if (error != 0)
goto out;
}
@@ -9432,7 +9485,7 @@ cachefs_getaclfromcache(cnode_t *cp, vsecattr_t *vsec)
}
if (vp != NULL) {
- if ((error = VOP_GETSECATTR(vp, vsec, 0, kcred)) != 0) {
+ if ((error = VOP_GETSECATTR(vp, vsec, 0, kcred, NULL)) != 0) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_VOPS)
printf("cachefs_getaclfromcache: error %d\n",
@@ -9858,7 +9911,8 @@ again:
error = ETIMEDOUT;
}
if (error == 0)
- error = VOP_GETSECATTR(cp->c_backvp, &vsec, 0, cr);
+ error = VOP_GETSECATTR(cp->c_backvp, &vsec, 0, cr,
+ NULL);
if (error != 0) {
#ifdef CFSDEBUG
CFS_DEBUG(CFSDEBUG_VOPS)
@@ -10104,8 +10158,8 @@ cachefs_modified(cnode_t *cp)
/* identify file so fsck knows it is modified */
va.va_mode = 0766;
va.va_mask = AT_MODE;
- error = VOP_SETATTR(cp->c_frontvp, &va,
- 0, kcred, NULL);
+ error = VOP_SETATTR(cp->c_frontvp,
+ &va, 0, kcred, NULL);
if (error) {
cmn_err(CE_WARN,
"Cannot change ff mode.\n");
@@ -10184,7 +10238,8 @@ cachefs_vtype_aclok(vnode_t *vp)
}
static int
-cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
@@ -10202,7 +10257,7 @@ cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
}
(*valp)++;
} else
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
return (error);
}
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_all.c b/usr/src/uts/common/fs/ctfs/ctfs_all.c
index 382f66da8a..6a0d080e56 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_all.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_all.c
@@ -50,7 +50,8 @@
static int ctfs_adir_do_readdir(vnode_t *, struct dirent64 *, int *, offset_t *,
offset_t *, void *);
-static int ctfs_adir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *);
+static int ctfs_adir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
/*
* ctfs_create_adirnode
@@ -71,7 +72,12 @@ ctfs_create_adirnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_adir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_adir_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
int i, total;
@@ -89,8 +95,10 @@ ctfs_adir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
return (0);
}
+/* ARGSUSED */
static int
-ctfs_adir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop)
+ctfs_adir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
{
int i;
contract_t *ct;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_cdir.c b/usr/src/uts/common/fs/ctfs/ctfs_cdir.c
index 4861f73244..0de17d43eb 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_cdir.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_cdir.c
@@ -95,7 +95,12 @@ ctfs_create_cdirnode(vnode_t *pvp, contract_t *ct)
*/
/* ARGSUSED */
static int
-ctfs_cdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_cdir_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_cdirnode_t *cdirnode = vp->v_data;
@@ -129,7 +134,7 @@ ctfs_cdir_do_inode(vnode_t *vp, int index)
*/
/* ARGSUSED */
static void
-ctfs_cdir_inactive(vnode_t *vp, cred_t *cr)
+ctfs_cdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *cct)
{
ctfs_cdirnode_t *cdirnode = vp->v_data;
contract_t *ct = cdirnode->ctfs_cn_contract;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_ctl.c b/usr/src/uts/common/fs/ctfs/ctfs_ctl.c
index da293cbb21..da2ac0b9c7 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_ctl.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_ctl.c
@@ -81,7 +81,12 @@ ctfs_create_ctlnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_ctl_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_ctl_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *cct)
{
ctfs_ctlnode_t *ctlnode = vp->v_data;
contract_t *ct = ctlnode->ctfs_ctl_contract;
@@ -108,17 +113,17 @@ ctfs_ctl_access(vnode_t *vp, int mode, int flags, cred_t *cr)
* constraints imposed by ctfs_ctl_access are met.
*/
static int
-ctfs_ctl_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_ctl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
if (flag != (FWRITE | FOFFMAX))
return (EINVAL);
- return (ctfs_ctl_access(*vpp, VWRITE, 0, cr));
+ return (ctfs_ctl_access(*vpp, VWRITE, 0, cr, ct));
}
/*
* ctfs_ctl_common_getattr
- * Implements fucntionality common to ctl and status ctfs VOP_GETATTR
+ * Implements functionality common to ctl and status ctfs VOP_GETATTR
* entry points. It assumes vp->v_data is set
*/
static int
@@ -144,7 +149,8 @@ ctfs_ctl_common_getattr(vnode_t *vp, vattr_t *vap)
*/
/* ARGSUSED */
static int
-ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags,
+ cred_t *cr, caller_context_t *ct)
{
vap->va_mode = 0222;
@@ -156,7 +162,8 @@ ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
vap->va_mode = 0444;
@@ -170,8 +177,14 @@ ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ctl_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_ctl_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *cct)
{
ctfs_ctlnode_t *ctlnode = vp->v_data;
contract_t *ct = ctlnode->ctfs_ctl_contract;
@@ -257,8 +270,14 @@ ctfs_create_statnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_stat_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_stat_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *cct)
{
ctfs_ctlnode_t *statnode = vp->v_data;
contract_t *ct = statnode->ctfs_ctl_contract;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_event.c b/usr/src/uts/common/fs/ctfs/ctfs_event.c
index ac4447e493..c9a99e85fb 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_event.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_event.c
@@ -191,7 +191,12 @@ ctfs_create_evnode(vnode_t *pvp)
*/
/*ARGSUSED*/
static int
-ctfs_ev_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_ev_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *cct)
{
ctfs_evnode_t *evnode = vp->v_data;
contract_t *ct = evnode->ctfs_ev_contract;
@@ -214,7 +219,7 @@ ctfs_ev_access(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *cct)
{
ctfs_evnode_t *evnode = (*vpp)->v_data;
contract_t *ct = evnode->ctfs_ev_contract;
@@ -235,7 +240,7 @@ ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static void
-ctfs_ev_inactive(vnode_t *vp, cred_t *cr)
+ctfs_ev_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_evnode_t *evnode;
vnode_t *pvp = gfs_file_parent(vp);
@@ -258,7 +263,12 @@ ctfs_ev_inactive(vnode_t *vp, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ev_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_ev_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_evnode_t *evnode = vp->v_data;
@@ -281,8 +291,14 @@ ctfs_ev_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_ev_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_ev_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
ctfs_evnode_t *evnode = vp->v_data;
@@ -293,9 +309,15 @@ ctfs_ev_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
/*
* ctfs_ev_poll - VOP_POLL entry point
*/
+/*ARGSUSED*/
static int
-ctfs_ev_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **php)
+ctfs_ev_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ pollhead_t **php,
+ caller_context_t *ct)
{
ctfs_evnode_t *evnode = vp->v_data;
@@ -361,7 +383,7 @@ ctfs_create_bundle(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
ctfs_bunode_t *bunode = (*vpp)->v_data;
@@ -379,7 +401,7 @@ ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static void
-ctfs_bu_inactive(vnode_t *vp, cred_t *cr)
+ctfs_bu_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_bunode_t *bunode;
vnode_t *pvp = gfs_file_parent(vp);
@@ -400,7 +422,12 @@ ctfs_bu_inactive(vnode_t *vp, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_bu_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_bu_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_bunode_t *bunode = vp->v_data;
@@ -424,8 +451,14 @@ ctfs_bu_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_bu_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_bu_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
ctfs_bunode_t *bunode = vp->v_data;
@@ -436,9 +469,15 @@ ctfs_bu_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
/*
* ctfs_bu_poll - VOP_POLL entry point
*/
+/*ARGSUSED*/
static int
-ctfs_bu_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **php)
+ctfs_bu_poll(
+ vnode_t *vp,
+ short events,
+ int anyyet,
+ short *reventsp,
+ pollhead_t **php,
+ caller_context_t *ct)
{
ctfs_bunode_t *bunode = vp->v_data;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_latest.c b/usr/src/uts/common/fs/ctfs/ctfs_latest.c
index 7d15dd494a..6a2bfc80f1 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_latest.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_latest.c
@@ -65,7 +65,7 @@ ctfs_create_latenode(vnode_t *pvp)
* ctfs_latest_getattr to obtain that file.
*/
static vnode_t *
-ctfs_latest_nested_open(vnode_t *vp)
+ctfs_latest_nested_open(vnode_t *vp, cred_t *cr)
{
contract_t *ct = ttolwp(curthread)->lwp_ct_latest[
gfs_file_index(gfs_file_parent(vp))];
@@ -77,7 +77,7 @@ ctfs_latest_nested_open(vnode_t *vp)
gfs_file_set_index(cvp, -1);
- VERIFY(gfs_dir_lookup(cvp, "status", &svp) == 0);
+ VERIFY(gfs_dir_lookup(cvp, "status", &svp, cr) == 0);
VN_RELE(cvp);
@@ -94,14 +94,19 @@ ctfs_latest_nested_open(vnode_t *vp)
*/
/* ARGSUSED */
static int
-ctfs_latest_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_latest_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vnode_t *nvp;
if (mode & (VEXEC | VWRITE))
return (EACCES);
- if (nvp = ctfs_latest_nested_open(vp)) {
+ if (nvp = ctfs_latest_nested_open(vp, cr)) {
VN_RELE(nvp);
return (0);
}
@@ -116,17 +121,17 @@ ctfs_latest_access(vnode_t *vp, int mode, int flags, cred_t *cr)
* the LWP's latest contract.
*/
static int
-ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *nvp;
if (flag != (FREAD | FOFFMAX))
return (EINVAL);
- if (nvp = ctfs_latest_nested_open(*vpp)) {
+ if (nvp = ctfs_latest_nested_open(*vpp, cr)) {
VN_RELE(*vpp);
*vpp = nvp;
- return (VOP_OPEN(vpp, flag, cr));
+ return (VOP_OPEN(vpp, flag, cr, ct));
}
return (ESRCH);
@@ -139,12 +144,17 @@ ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr)
* latest contract. Otherwise it fakes up something bland.
*/
static int
-ctfs_latest_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_latest_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vnode_t *nvp;
- if (nvp = ctfs_latest_nested_open(vp)) {
- int res = VOP_GETATTR(nvp, vap, flags, cr);
+ if (nvp = ctfs_latest_nested_open(vp, cr)) {
+ int res = VOP_GETATTR(nvp, vap, flags, cr, ct);
VN_RELE(nvp);
return (res);
}
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_root.c b/usr/src/uts/common/fs/ctfs/ctfs_root.c
index 1616a986cd..8861b6d73b 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_root.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_root.c
@@ -55,7 +55,7 @@
/*
* ctfs, the contract filesystem.
*
- * Exposes the constract subsystem to userland. The structure of the
+ * Exposes the construct subsystem to userland. The structure of the
* filesytem is a public interface, but the behavior of the files is
* private and unstable. Contract consumers are expected to use
* libcontract(3lib) to operate on ctfs file descriptors.
@@ -399,7 +399,7 @@ ctfs_common_getattr(vnode_t *vp, vattr_t *vap)
*/
/* ARGSUSED */
int
-ctfs_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
return (EINVAL);
@@ -414,7 +414,13 @@ ctfs_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+ctfs_close(
+ vnode_t *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -424,7 +430,12 @@ ctfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_access_dir(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_access_dir(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VWRITE)
return (EACCES);
@@ -437,7 +448,12 @@ ctfs_access_dir(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_access_readonly(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_access_readonly(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
if (mode & (VWRITE | VEXEC))
return (EACCES);
@@ -450,7 +466,12 @@ ctfs_access_readonly(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_access_readwrite(vnode_t *vp, int mode, int flags, cred_t *cr)
+ctfs_access_readwrite(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VEXEC)
return (EACCES);
@@ -463,7 +484,12 @@ ctfs_access_readwrite(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_root_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VDIR;
vap->va_mode = 0555;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_sym.c b/usr/src/uts/common/fs/ctfs/ctfs_sym.c
index bf825ab366..571f8903b8 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_sym.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_sym.c
@@ -81,7 +81,12 @@ ctfs_create_symnode(vnode_t *pvp, contract_t *ct)
*/
/* ARGSUSED */
static int
-ctfs_sym_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_sym_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
ctfs_symnode_t *symnode = vp->v_data;
@@ -104,7 +109,7 @@ ctfs_sym_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
int
-ctfs_sym_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+ctfs_sym_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
ctfs_symnode_t *symnode = vp->v_data;
@@ -117,7 +122,7 @@ ctfs_sym_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
*/
/* ARGSUSED */
static void
-ctfs_sym_inactive(vnode_t *vp, cred_t *cr)
+ctfs_sym_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_symnode_t *symnode;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_tdir.c b/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
index 2d47c72339..fd3c229c0f 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_tdir.c
@@ -58,7 +58,8 @@ static gfs_dirent_t ctfs_tdir_dirents[] = {
static int ctfs_tdir_do_readdir(vnode_t *, struct dirent64 *, int *, offset_t *,
offset_t *, void *);
-static int ctfs_tdir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *);
+static int ctfs_tdir_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
static ino64_t ctfs_tdir_do_inode(vnode_t *, int);
/*
@@ -77,7 +78,12 @@ ctfs_create_tdirnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_tdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_tdir_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VDIR;
vap->va_mode = 0555;
@@ -124,8 +130,10 @@ ctfs_tdir_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
return (0);
}
+/* ARGSUSED */
static int
-ctfs_tdir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop)
+ctfs_tdir_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
{
int i;
contract_t *ct;
diff --git a/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c b/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
index d99b8f56e8..1786d1d79f 100644
--- a/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
+++ b/usr/src/uts/common/fs/ctfs/ctfs_tmpl.c
@@ -75,7 +75,7 @@ ctfs_create_tmplnode(vnode_t *pvp)
*/
/* ARGSUSED */
static int
-ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr)
+ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
if (flag != (FREAD | FWRITE | FOFFMAX))
return (EINVAL);
@@ -88,7 +88,12 @@ ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_tmpl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+ctfs_tmpl_getattr(
+ vnode_t *vp,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VREG;
vap->va_mode = 0666;
@@ -109,8 +114,14 @@ ctfs_tmpl_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static int
-ctfs_tmpl_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ctfs_tmpl_ioctl(
+ vnode_t *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
ctfs_tmplnode_t *tmplnode = vp->v_data;
ct_param_t param;
@@ -158,7 +169,7 @@ ctfs_tmpl_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
*/
/* ARGSUSED */
static void
-ctfs_tmpl_inactive(vnode_t *vp, cred_t *cr)
+ctfs_tmpl_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
ctfs_tmplnode_t *tmplnode;
diff --git a/usr/src/uts/common/fs/dev/sdev_profile.c b/usr/src/uts/common/fs/dev/sdev_profile.c
index 290cce18ee..1756ac7115 100644
--- a/usr/src/uts/common/fs/dev/sdev_profile.c
+++ b/usr/src/uts/common/fs/dev/sdev_profile.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -75,13 +75,14 @@ prof_getattr(struct sdev_node *dir, char *name, struct vnode *gdv,
/* get attribute from shadow, if present; else get default */
advp = dir->sdev_attrvp;
- if (advp && VOP_LOOKUP(advp, name, avpp, NULL, 0, NULL, kcred) == 0) {
- (void) VOP_GETATTR(*avpp, vap, 0, kcred);
+ if (advp && VOP_LOOKUP(advp, name, avpp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) == 0) {
+ (void) VOP_GETATTR(*avpp, vap, 0, kcred, NULL);
} else if (gdv == NULL || gdv->v_type == VDIR) {
/* always create shadow directory */
*vap = sdev_vattr_dir;
- if (advp && VOP_MKDIR(advp, name,
- &sdev_vattr_dir, avpp, kcred) != 0) {
+ if (advp && VOP_MKDIR(advp, name, &sdev_vattr_dir,
+ avpp, kcred, NULL, 0, NULL) != 0) {
*avpp = NULLVP;
sdcmn_err10(("prof_getattr: failed to create "
"shadow directory %s/%s\n", dir->sdev_path, name));
@@ -95,7 +96,7 @@ prof_getattr(struct sdev_node *dir, char *name, struct vnode *gdv,
* attr for device nodes.
*/
struct vnode *rvp;
- if (VOP_REALVP(gdv, &rvp) != 0)
+ if (VOP_REALVP(gdv, &rvp, NULL) != 0)
rvp = gdv;
devfs_get_defattr(rvp, vap, no_fs_perm);
*avpp = NULLVP;
@@ -209,7 +210,7 @@ prof_make_dir(char *name, struct sdev_node **gdirp, struct sdev_node **dirp)
/* find corresponding dir node in global dev */
if (gdir) {
error = VOP_LOOKUP(SDEVTOV(gdir), name, &gnewdir,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error == 0) {
*gdirp = VTOSDEV(gnewdir);
} else { /* it's ok if there no global dir */
@@ -390,7 +391,8 @@ is_nonempty_dir(char *name, char *pathleft, struct sdev_node *dir)
struct vnode *gvp;
struct sdev_node *gdir = dir->sdev_origin;
- if (VOP_LOOKUP(SDEVTOV(gdir), name, &gvp, NULL, 0, NULL, kcred) != 0)
+ if (VOP_LOOKUP(SDEVTOV(gdir), name, &gvp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL) != 0)
return (0);
if (gvp->v_type != VDIR) {
@@ -502,7 +504,7 @@ walk_dir(struct vnode *dvp, void *arg, int (*callback)(char *, void *))
iov.iov_base = (char *)dbuf;
iov.iov_len = dlen;
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
diff --git a/usr/src/uts/common/fs/dev/sdev_ptsops.c b/usr/src/uts/common/fs/dev/sdev_ptsops.c
index 4ee3a52857..f6d1fda64e 100644
--- a/usr/src/uts/common/fs/dev/sdev_ptsops.c
+++ b/usr/src/uts/common/fs/dev/sdev_ptsops.c
@@ -294,7 +294,8 @@ devpts_prunedir(struct sdev_node *ddv)
/*ARGSUSED3*/
static int
devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
struct sdev_node *sdvp = VTOSDEV(dvp);
struct sdev_node *dv;
@@ -308,7 +309,7 @@ devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
switch ((*vpp)->v_type) {
case VCHR:
dv = VTOSDEV(VTOS(*vpp)->s_realvp);
- ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp) == ENOSYS);
+ ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
break;
case VDIR:
dv = VTOSDEV(*vpp);
@@ -333,21 +334,23 @@ devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
/*ARGSUSED2*/
static int
devpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
- int mode, struct vnode **vpp, struct cred *cred, int flag)
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
struct vnode *vp;
*vpp = NULL;
- error = devpts_lookup(dvp, nm, &vp, NULL, 0, NULL, cred);
+ error = devpts_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
+ NULL);
if (error == 0) {
if (excl == EXCL)
error = EEXIST;
else if (vp->v_type == VDIR && (mode & VWRITE))
error = EISDIR;
else
- error = VOP_ACCESS(vp, mode, 0, cred);
+ error = VOP_ACCESS(vp, mode, 0, cred, ct);
if (error) {
VN_RELE(vp);
@@ -365,9 +368,10 @@ devpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
* A /dev/pts entry will be created only after the first lookup of the slave
* device succeeds.
*/
+/*ARGSUSED4*/
static int
devpts_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
- int *eofp)
+ int *eofp, caller_context_t *ct, int flags)
{
struct sdev_node *sdvp = VTOSDEV(dvp);
if (uiop->uio_offset == 0) {
diff --git a/usr/src/uts/common/fs/dev/sdev_subr.c b/usr/src/uts/common/fs/dev/sdev_subr.c
index d6d92c2621..1075391d17 100644
--- a/usr/src/uts/common/fs/dev/sdev_subr.c
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c
@@ -715,7 +715,7 @@ sdev_getlink(struct vnode *linkvp, char **link)
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_llimit = MAXOFFSET_T;
- err = VOP_READLINK(linkvp, &uio, kcred);
+ err = VOP_READLINK(linkvp, &uio, kcred, NULL);
if (err) {
cmn_err(CE_WARN, "readlink %s failed in dev\n", buf);
kmem_free(buf, MAXPATHLEN);
@@ -1155,7 +1155,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
timestruc_t now;
vattr.va_mask = AT_MODE|AT_UID|AT_GID;
- error = VOP_GETATTR(ovp, &vattr, 0, cred);
+ error = VOP_GETATTR(ovp, &vattr, 0, cred, NULL);
if (error)
return (error);
@@ -1227,7 +1227,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
(void) sdev_dirdelete(nddv, *ndvp);
*ndvp = NULL;
error = VOP_RMDIR(nddv->sdev_attrvp, nnm,
- nddv->sdev_attrvp, cred);
+ nddv->sdev_attrvp, cred, NULL, 0);
if (error)
goto err_out;
} else {
@@ -1249,7 +1249,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
*ndvp = NULL;
if (bkstore) {
error = VOP_REMOVE(nddv->sdev_attrvp,
- nnm, cred);
+ nnm, cred, NULL, 0);
if (error)
goto err_out;
}
@@ -1419,7 +1419,7 @@ devname_find_by_devpath(char *devpath, struct vattr *vattr)
}
if (vattr)
- (void) VOP_GETATTR(vp, vattr, 0, kcred);
+ (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL);
return (vp);
}
@@ -1447,7 +1447,7 @@ devname_configure_by_path(char *physpath, struct vattr *vattr)
}
if (vattr)
- (void) VOP_GETATTR(vp, vattr, 0, kcred);
+ (void) VOP_GETATTR(vp, vattr, 0, kcred, NULL);
return (vp);
}
@@ -1462,7 +1462,8 @@ devname_backstore_lookup(struct sdev_node *ddv, char *nm, struct vnode **rvp)
ASSERT(rdvp);
- rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred);
+ rval = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, kcred, NULL, NULL,
+ NULL);
return (rval);
}
@@ -1507,7 +1508,7 @@ sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred)
iov.iov_base = (char *)dbuf;
iov.iov_len = dlen;
(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dirvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -1552,7 +1553,7 @@ sdev_filldir_from_store(struct sdev_node *ddv, int dlen, struct cred *cred)
continue;
vattr.va_mask = AT_MODE|AT_UID|AT_GID;
- error = VOP_GETATTR(vp, &vattr, 0, cred);
+ error = VOP_GETATTR(vp, &vattr, 0, cred, NULL);
if (error)
continue;
@@ -1644,9 +1645,10 @@ sdev_shadow_node(struct sdev_node *dv, struct cred *cred)
lookup:
/* try to find it in the backing store */
- error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred);
+ error = VOP_LOOKUP(rdvp, nm, rvp, NULL, 0, NULL, cred, NULL, NULL,
+ NULL);
if (error == 0) {
- if (VOP_REALVP(*rvp, &rrvp) == 0) {
+ if (VOP_REALVP(*rvp, &rrvp, NULL) == 0) {
VN_HOLD(rrvp);
VN_RELE(*rvp);
*rvp = rrvp;
@@ -1665,7 +1667,7 @@ lookup:
vap->va_mask |= AT_TYPE|AT_MODE;
switch (vap->va_type) {
case VDIR:
- error = VOP_MKDIR(rdvp, nm, vap, rvp, cred);
+ error = VOP_MKDIR(rdvp, nm, vap, rvp, cred, NULL, 0, NULL);
sdcmn_err9(("sdev_shadow_node: mkdir vp %p error %d\n",
(void *)(*rvp), error));
break;
@@ -1674,7 +1676,7 @@ lookup:
case VREG:
case VDOOR:
error = VOP_CREATE(rdvp, nm, vap, NONEXCL, VREAD|VWRITE,
- rvp, cred, 0);
+ rvp, cred, 0, NULL, NULL);
sdcmn_err9(("sdev_shadow_node: create vp %p, error %d\n",
(void *)(*rvp), error));
if (!error)
@@ -1682,7 +1684,8 @@ lookup:
break;
case VLNK:
ASSERT(dv->sdev_symlink);
- error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred);
+ error = VOP_SYMLINK(rdvp, nm, vap, dv->sdev_symlink, cred,
+ NULL, 0);
sdcmn_err9(("sdev_shadow_node: create symlink error %d\n",
error));
break;
@@ -1770,7 +1773,7 @@ sdev_cache_update(struct sdev_node *ddv, struct sdev_node **dv, char *nm,
}
/*
- * retrive the named entry from the directory cache
+ * retrieve the named entry from the directory cache
*/
struct sdev_node *
sdev_cache_lookup(struct sdev_node *ddv, char *nm)
@@ -2224,7 +2227,7 @@ tryagain:
"found attrvp %p for %s\n", (void *)rvp, nm));
vattr.va_mask = AT_MODE|AT_UID|AT_GID;
- error = VOP_GETATTR(rvp, &vattr, 0, cred);
+ error = VOP_GETATTR(rvp, &vattr, 0, cred, NULL);
if (error) {
rw_exit(&ddv->sdev_contents);
if (dv)
@@ -2583,10 +2586,10 @@ sdev_cleandir(struct sdev_node *ddv, char *expr, uint_t flags)
if (bkstore == 1) {
error = VOP_REMOVE(ddv->sdev_attrvp,
- bks_name, kcred);
+ bks_name, kcred, NULL, 0);
} else if (bkstore == 2) {
error = VOP_RMDIR(ddv->sdev_attrvp,
- bks_name, ddv->sdev_attrvp, kcred);
+ bks_name, ddv->sdev_attrvp, kcred, NULL, 0);
}
/* do not propagate the backing store errors */
@@ -2953,7 +2956,8 @@ sdev_modctl_lookup(const char *path, vnode_t **r_vp)
while (pn_pathleft(&pn)) {
ASSERT(vp->v_type == VDIR);
(void) pn_getcomponent(&pn, nm);
- error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred);
+ error = VOP_LOOKUP(vp, nm, &cvp, NULL, 0, NULL, kcred, NULL,
+ NULL, NULL);
VN_RELE(vp);
if (error)
@@ -3065,7 +3069,7 @@ sdev_modctl_readdir(const char *dir, char ***dirlistp,
iov.iov_len = dlen;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(vp, &uio, kcred, &eof);
+ error = VOP_READDIR(vp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -3659,8 +3663,8 @@ devname_setattr_func(struct vnode *vp, struct vattr *vap, int flags,
* sdev_attr was allocated in sdev_mknode
*/
rw_enter(&dv->sdev_contents, RW_WRITER);
- error = secpolicy_vnode_setattr(cred, vp, vap, dv->sdev_attr,
- flags, sdev_unlocked_access, dv);
+ error = secpolicy_vnode_setattr(cred, vp, vap,
+ dv->sdev_attr, flags, sdev_unlocked_access, dv);
if (error) {
rw_exit(&dv->sdev_contents);
rw_exit(&parent->sdev_contents);
diff --git a/usr/src/uts/common/fs/dev/sdev_vfsops.c b/usr/src/uts/common/fs/dev/sdev_vfsops.c
index ca971fe30c..bde50de8a2 100644
--- a/usr/src/uts/common/fs/dev/sdev_vfsops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vfsops.c
@@ -324,7 +324,7 @@ sdev_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
/* get acl flavor from attribute dir */
if (VOP_PATHCONF(avp, _PC_ACL_ENABLED, &sdev_data->sdev_acl_flavor,
- kcred) != 0 || sdev_data->sdev_acl_flavor == 0)
+ kcred, NULL) != 0 || sdev_data->sdev_acl_flavor == 0)
sdev_data->sdev_acl_flavor = _ACL_ACLENT_ENABLED;
args = NULL; /* so it won't be freed below */
diff --git a/usr/src/uts/common/fs/dev/sdev_vnops.c b/usr/src/uts/common/fs/dev/sdev_vnops.c
index 1d086c168a..de1d83e75a 100644
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c
+++ b/usr/src/uts/common/fs/dev/sdev_vnops.c
@@ -76,7 +76,7 @@
/*ARGSUSED*/
static int
-sdev_open(struct vnode **vpp, int flag, struct cred *cred)
+sdev_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(*vpp);
struct sdev_node *ddv = dv->sdev_dotdot;
@@ -98,7 +98,7 @@ sdev_open(struct vnode **vpp, int flag, struct cred *cred)
rw_exit(&ddv->sdev_contents);
return (ENOENT);
}
- error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred);
+ error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred, ct);
rw_exit(&ddv->sdev_contents);
return (error);
}
@@ -106,7 +106,7 @@ sdev_open(struct vnode **vpp, int flag, struct cred *cred)
/*ARGSUSED1*/
static int
sdev_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cred)
+ offset_t offset, struct cred *cred, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
@@ -124,7 +124,7 @@ sdev_close(struct vnode *vp, int flag, int count,
return (ENOTSUP);
ASSERT(dv->sdev_attrvp);
- return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred));
+ return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred, ct));
}
/*ARGSUSED*/
@@ -148,9 +148,9 @@ sdev_read(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
ASSERT(RW_READ_HELD(&VTOSDEV(vp)->sdev_contents));
ASSERT(dv->sdev_attrvp);
- (void) VOP_RWLOCK(dv->sdev_attrvp, 0, NULL);
+ (void) VOP_RWLOCK(dv->sdev_attrvp, 0, ct);
error = VOP_READ(dv->sdev_attrvp, uio, ioflag, cred, ct);
- VOP_RWUNLOCK(dv->sdev_attrvp, 0, NULL);
+ VOP_RWUNLOCK(dv->sdev_attrvp, 0, ct);
return (error);
}
@@ -175,9 +175,9 @@ sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
ASSERT(dv->sdev_attrvp);
- (void) VOP_RWLOCK(dv->sdev_attrvp, 1, NULL);
+ (void) VOP_RWLOCK(dv->sdev_attrvp, 1, ct);
error = VOP_WRITE(dv->sdev_attrvp, uio, ioflag, cred, ct);
- VOP_RWUNLOCK(dv->sdev_attrvp, 1, NULL);
+ VOP_RWUNLOCK(dv->sdev_attrvp, 1, ct);
if (error == 0) {
sdev_update_timestamps(dv->sdev_attrvp, kcred,
AT_MTIME);
@@ -188,7 +188,7 @@ sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred,
/*ARGSUSED*/
static int
sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- struct cred *cred, int *rvalp)
+ struct cred *cred, int *rvalp, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
@@ -200,11 +200,12 @@ sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
return (EINVAL);
ASSERT(dv->sdev_attrvp);
- return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp));
+ return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp, ct));
}
static int
-sdev_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+sdev_getattr(struct vnode *vp, struct vattr *vap, int flags,
+ struct cred *cr, caller_context_t *ct)
{
int error = 0;
struct sdev_node *dv = VTOSDEV(vp);
@@ -229,7 +230,7 @@ sdev_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
*/
if (dv->sdev_attrvp) {
rw_exit(&parent->sdev_contents);
- error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr);
+ error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr, ct);
sdev_vattr_merge(dv, vap);
} else if (dirops && (fn = dirops->devnops_getattr)) {
sdev_vattr_merge(dv, vap);
@@ -255,7 +256,7 @@ sdev_setattr(struct vnode *vp, struct vattr *vap, int flags,
static int
sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
int error;
struct sdev_node *dv = VTOSDEV(vp);
@@ -267,20 +268,20 @@ sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
(vsap->vsa_mask & (VSA_ACLCNT | VSA_DFACLCNT))) ||
(SDEV_ACL_FLAVOR(vp) == _ACL_ACE_ENABLED &&
(vsap->vsa_mask & (VSA_ACECNT | VSA_ACE))))
- return (fs_fab_acl(vp, vsap, flags, cr));
+ return (fs_fab_acl(vp, vsap, flags, cr, ct));
return (ENOSYS);
}
- (void) VOP_RWLOCK(avp, 1, NULL);
- error = VOP_GETSECATTR(avp, vsap, flags, cr);
- VOP_RWUNLOCK(avp, 1, NULL);
+ (void) VOP_RWLOCK(avp, 1, ct);
+ error = VOP_GETSECATTR(avp, vsap, flags, cr, ct);
+ VOP_RWUNLOCK(avp, 1, ct);
return (error);
}
static int
sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
int error;
struct sdev_node *dv = VTOSDEV(vp);
@@ -301,7 +302,7 @@ sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
*/
ASSERT(RW_WRITE_HELD(&dv->sdev_contents));
sdev_vattr_merge(dv, dv->sdev_attr);
- error = sdev_shadow_node(dv, cr);
+ error = sdev_shadow_node(dv, cr);
if (error) {
return (fs_nosys());
}
@@ -316,9 +317,9 @@ sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
}
ASSERT(avp);
- (void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(avp, vsap, flags, cr);
- VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, NULL);
+ (void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, ct);
+ error = VOP_SETSECATTR(avp, vsap, flags, cr, ct);
+ VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, ct);
return (error);
}
@@ -343,7 +344,8 @@ sdev_unlocked_access(void *vdv, int mode, struct cred *cr)
}
static int
-sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
int ret = 0;
@@ -351,7 +353,7 @@ sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr)
ASSERT(dv->sdev_attr || dv->sdev_attrvp);
if (dv->sdev_attrvp) {
- ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr);
+ ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr, ct);
} else if (dv->sdev_attr) {
rw_enter(&dv->sdev_contents, RW_READER);
ret = sdev_unlocked_access(dv, mode, cr);
@@ -369,7 +371,8 @@ sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr)
/*ARGSUSED3*/
static int
sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
struct sdev_node *parent;
int error;
@@ -378,7 +381,7 @@ sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
ASSERT(parent);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
if (!SDEV_IS_GLOBAL(parent))
@@ -389,7 +392,8 @@ sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
/*ARGSUSED2*/
static int
sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
- int mode, struct vnode **vpp, struct cred *cred, int flag)
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
struct vnode *vp = NULL;
struct vnode *avp;
@@ -421,11 +425,12 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred, ct)) != 0)
return (error);
/* check existing name */
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
/* name found */
if (error == 0) {
@@ -436,7 +441,7 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
/* allowing create/read-only an existing directory */
error = EISDIR;
} else {
- error = VOP_ACCESS(vp, mode, flag, cred);
+ error = VOP_ACCESS(vp, mode, flag, cred, ct);
}
if (error) {
@@ -449,7 +454,7 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
(vap->va_size == 0)) {
ASSERT(parent->sdev_attrvp);
error = VOP_CREATE(parent->sdev_attrvp,
- nm, vap, excl, mode, &avp, cred, flag);
+ nm, vap, excl, mode, &avp, cred, flag, ct, vsecp);
if (error) {
VN_RELE(vp);
@@ -505,7 +510,8 @@ sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
}
static int
-sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
+sdev_remove(struct vnode *dvp, char *nm, struct cred *cred,
+ caller_context_t *ct, int flags)
{
int error;
struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
@@ -535,7 +541,7 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
}
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
rw_exit(&parent->sdev_contents);
return (error);
}
@@ -556,7 +562,7 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
}
/* write access is required to remove an entry */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
rw_exit(&parent->sdev_contents);
VN_RELE(vp);
return (error);
@@ -601,7 +607,8 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
*/
if (bkstore) {
ASSERT(parent->sdev_attrvp);
- error = VOP_REMOVE(parent->sdev_attrvp, nm, cred);
+ error = VOP_REMOVE(parent->sdev_attrvp, nm, cred,
+ ct, flags);
/*
* do not report BUSY error
* because the backing store ref count is released
@@ -627,9 +634,10 @@ sdev_remove(struct vnode *dvp, char *nm, struct cred *cred)
* - both oldnm and newnm are in the scope of /dev file system,
* to simply the namespace management model.
*/
+/*ARGSUSED6*/
static int
sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct, int flags)
{
struct sdev_node *fromparent = NULL;
struct vattr vattr;
@@ -690,7 +698,9 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
mutex_enter(&sdev_lock);
/* check existence of the source node */
- error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred, ct,
+ NULL, NULL);
if (error) {
sdcmn_err2(("sdev_rename: the source node %s exists\n",
onm));
@@ -698,21 +708,23 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
return (error);
}
- if (VOP_REALVP(ovp, &realvp) == 0) {
+ if (VOP_REALVP(ovp, &realvp, ct) == 0) {
VN_HOLD(realvp);
VN_RELE(ovp);
ovp = realvp;
}
/* check existence of destination */
- error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred, ct,
+ NULL, NULL);
if (error && (error != ENOENT)) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
return (error);
}
- if (nvp && (VOP_REALVP(nvp, &realvp) == 0)) {
+ if (nvp && (VOP_REALVP(nvp, &realvp, ct) == 0)) {
VN_HOLD(realvp);
VN_RELE(nvp);
nvp = realvp;
@@ -724,14 +736,14 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
*/
if (odvp != ndvp) {
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(odvp, &vattr, 0, cred)) {
+ if (error = VOP_GETATTR(odvp, &vattr, 0, cred, ct)) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
return (error);
}
fsid = vattr.va_fsid;
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(ndvp, &vattr, 0, cred)) {
+ if (error = VOP_GETATTR(ndvp, &vattr, 0, cred, ct)) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
return (error);
@@ -744,7 +756,7 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
}
/* make sure the old entry can be deleted */
- error = VOP_ACCESS(odvp, VWRITE, 0, cred);
+ error = VOP_ACCESS(odvp, VWRITE, 0, cred, ct);
if (error) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
@@ -754,7 +766,7 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
/* make sure the destination allows creation */
samedir = (fromparent == toparent);
if (!samedir) {
- error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred);
+ error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred, ct);
if (error) {
mutex_exit(&sdev_lock);
VN_RELE(ovp);
@@ -856,11 +868,13 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
if (bkstore) {
ASSERT(fromparent->sdev_attrvp);
if (type != VDIR) {
+/* XXXci - We may need to translate the C-I flags on VOP_REMOVE */
error = VOP_REMOVE(fromparent->sdev_attrvp,
- onm, kcred);
+ onm, kcred, ct, 0);
} else {
+/* XXXci - We may need to translate the C-I flags on VOP_RMDIR */
error = VOP_RMDIR(fromparent->sdev_attrvp,
- onm, fromparent->sdev_attrvp, kcred);
+ onm, fromparent->sdev_attrvp, kcred, ct, 0);
}
if (error) {
@@ -882,9 +896,10 @@ sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm,
* tnm - path, e.g. /devices/... or /dev/...
* lnm - dev_name
*/
+/*ARGSUSED6*/
static int
sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
- char *tnm, struct cred *cred)
+ char *tnm, struct cred *cred, caller_context_t *ct, int flags)
{
int error;
struct vnode *vp = NULL;
@@ -907,11 +922,12 @@ sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search a directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
/* find existing name */
- error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags here */
+ error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
if (error == 0) {
ASSERT(vp);
VN_RELE(vp);
@@ -922,7 +938,7 @@ sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
return (error);
/* write access is required to create a symlink */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0)
return (error);
/* put it into memory cache */
@@ -955,9 +971,10 @@ sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva,
return (0);
}
+/*ARGSUSED6*/
static int
sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
@@ -979,12 +996,13 @@ sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) {
return (error);
}
/* find existing name */
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred);
+/* XXXci - We may need to translate the C-I flags on VOP_LOOKUP */
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
if (error == 0) {
VN_RELE(vp);
return (EEXIST);
@@ -993,7 +1011,7 @@ sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
return (error);
/* require write access to create a directory */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
return (error);
}
@@ -1030,7 +1048,8 @@ sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp,
*/
/*ARGSUSED*/
static int
-sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
+sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred,
+ caller_context_t *ct, int flags)
{
int error = 0;
struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp);
@@ -1053,7 +1072,7 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
rw_exit(&parent->sdev_dotdot->sdev_contents);
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
/* check existing name */
@@ -1073,7 +1092,7 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
}
/* write access is required to remove a directory */
- if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) {
+ if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred, ct)) != 0) {
rw_exit(&parent->sdev_contents);
VN_RELE(vp);
return (error);
@@ -1132,7 +1151,7 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
if (SDEV_IS_PERSIST(parent)) {
ASSERT(parent->sdev_attrvp);
error = VOP_RMDIR(parent->sdev_attrvp, nm,
- parent->sdev_attrvp, kcred);
+ parent->sdev_attrvp, kcred, ct, flags);
sdcmn_err2(("sdev_rmdir: cleaning device %s is on"
" disk error %d\n", parent->sdev_path, error));
}
@@ -1148,7 +1167,8 @@ sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred)
* read the contents of a symbolic link
*/
static int
-sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
+sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred,
+ caller_context_t *ct)
{
struct sdev_node *dv;
int error = 0;
@@ -1159,7 +1179,7 @@ sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
if (dv->sdev_attrvp) {
/* non-NULL attrvp implys a persisted node at READY state */
- return (VOP_READLINK(dv->sdev_attrvp, uiop, cred));
+ return (VOP_READLINK(dv->sdev_attrvp, uiop, cred, ct));
} else if (dv->sdev_symlink != NULL) {
/* memory nodes, e.g. local nodes */
rw_enter(&dv->sdev_contents, RW_READER);
@@ -1173,14 +1193,16 @@ sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
return (ENOENT);
}
+/*ARGSUSED4*/
static int
-sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
+sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
+ caller_context_t *ct, int flags)
{
struct sdev_node *parent = VTOSDEV(dvp);
int error;
/* execute access is required to search the directory */
- if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0)
+ if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0)
return (error);
ASSERT(parent);
@@ -1191,7 +1213,7 @@ sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
/*ARGSUSED1*/
static void
-sdev_inactive(struct vnode *vp, struct cred *cred)
+sdev_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
{
int clean;
struct sdev_node *dv = VTOSDEV(vp);
@@ -1250,8 +1272,9 @@ sdev_inactive(struct vnode *vp, struct cred *cred)
rw_exit(&ddv->sdev_contents);
}
+/*ARGSUSED2*/
static int
-sdev_fid(struct vnode *vp, struct fid *fidp)
+sdev_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
struct sdev_fid *sdev_fid;
@@ -1293,7 +1316,8 @@ sdev_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ctp)
/*ARGSUSED1*/
static int
-sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
struct vnode *attrvp = VTOSDEV(vp)->sdev_attrvp;
@@ -1301,16 +1325,17 @@ sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
vp->v_type != VBLK && vp->v_type != VLNK);
if (vp->v_type == VDIR)
- return (fs_seek(vp, ooff, noffp));
+ return (fs_seek(vp, ooff, noffp, ct));
ASSERT(attrvp);
- return (VOP_SEEK(attrvp, ooff, noffp));
+ return (VOP_SEEK(attrvp, ooff, noffp, ct));
}
/*ARGSUSED1*/
static int
sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, struct cred *cr)
+ offset_t offset, struct flk_callback *flk_cbp, struct cred *cr,
+ caller_context_t *ct)
{
int error;
struct sdev_node *dv = VTOSDEV(vp);
@@ -1318,23 +1343,25 @@ sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
ASSERT(dv);
ASSERT(dv->sdev_attrvp);
error = VOP_FRLOCK(dv->sdev_attrvp, cmd, bfp, flag, offset,
- flk_cbp, cr);
+ flk_cbp, cr, ct);
return (error);
}
static int
-sdev_setfl(struct vnode *vp, int oflags, int nflags, cred_t *cr)
+sdev_setfl(struct vnode *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sdev_node *dv = VTOSDEV(vp);
ASSERT(dv);
ASSERT(dv->sdev_attrvp);
- return (VOP_SETFL(dv->sdev_attrvp, oflags, nflags, cr));
+ return (VOP_SETFL(dv->sdev_attrvp, oflags, nflags, cr, ct));
}
static int
-sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
switch (cmd) {
case _PC_ACL_ENABLED:
@@ -1342,7 +1369,7 @@ sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
return (0);
}
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
vnodeops_t *sdev_vnodeops;
diff --git a/usr/src/uts/common/fs/devfs/devfs_subr.c b/usr/src/uts/common/fs/devfs/devfs_subr.c
index 4aa95bc321..eeaac94430 100644
--- a/usr/src/uts/common/fs/devfs/devfs_subr.c
+++ b/usr/src/uts/common/fs/devfs/devfs_subr.c
@@ -694,10 +694,11 @@ dv_shadow_node(
create_tried = 0;
lookup:
if (rdvp && (dv->dv_flags & DV_NO_FSPERM) == 0) {
- error = VOP_LOOKUP(rdvp, nm, &rvp, pnp, LOOKUP_DIR, rdir, cred);
+ error = VOP_LOOKUP(rdvp, nm, &rvp, pnp, LOOKUP_DIR, rdir, cred,
+ NULL, NULL, NULL);
/* factor out the snode since we only want the attribute node */
- if ((error == 0) && (VOP_REALVP(rvp, &rrvp) == 0)) {
+ if ((error == 0) && (VOP_REALVP(rvp, &rrvp, NULL) == 0)) {
VN_HOLD(rrvp);
VN_RELE(rvp);
rvp = rrvp;
@@ -760,7 +761,8 @@ lookup:
if ((error == ENOENT) && !create_tried) {
switch (vp->v_type) {
case VDIR:
- error = VOP_MKDIR(rdvp, nm, &vattr, &rvp, kcred);
+ error = VOP_MKDIR(rdvp, nm, &vattr, &rvp, kcred,
+ NULL, 0, NULL);
dsysdebug(error, ("vop_mkdir %s %s %d\n",
VTODV(dvp)->dv_name, nm, error));
create_tried = 1;
@@ -773,7 +775,7 @@ lookup:
*/
if (flags & DV_SHADOW_CREATE) {
error = VOP_CREATE(rdvp, nm, &vattr, NONEXCL,
- VREAD|VWRITE, &rvp, kcred, 0);
+ VREAD|VWRITE, &rvp, kcred, 0, NULL, NULL);
dsysdebug(error, ("vop_create %s %s %d\n",
VTODV(dvp)->dv_name, nm, error));
create_tried = 1;
@@ -1566,7 +1568,7 @@ devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rvp)
iov.iov_len = dlen;
(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dirvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -1582,8 +1584,8 @@ devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rvp)
if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
continue;
- error = VOP_LOOKUP(dirvp,
- nm, &vp, NULL, 0, NULL, kcred);
+ error = VOP_LOOKUP(dirvp, nm,
+ &vp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
dsysdebug(error,
("rem_drv %s/%s lookup (%d)\n",
@@ -1599,13 +1601,14 @@ devfs_remdrv_rmdir(vnode_t *dirvp, const char *dir, vnode_t *rvp)
error = devfs_remdrv_rmdir(vp, nm, rvp);
if (error == 0) {
error = VOP_RMDIR(dirvp,
- (char *)nm, rvp, kcred);
+ (char *)nm, rvp, kcred, NULL, 0);
dsysdebug(error,
("rem_drv %s/%s rmdir (%d)\n",
dir, nm, error));
}
} else {
- error = VOP_REMOVE(dirvp, (char *)nm, kcred);
+ error = VOP_REMOVE(dirvp, (char *)nm, kcred,
+ NULL, 0);
dsysdebug(error,
("rem_drv %s/%s remove (%d)\n",
dir, nm, error));
@@ -1663,7 +1666,8 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
ASSERT(dirvp->v_type == VDIR);
(void) pn_getcomponent(&pn, nm);
ASSERT((strcmp(nm, ".") != 0) && (strcmp(nm, "..") != 0));
- error = VOP_LOOKUP(dirvp, nm, &vp, NULL, 0, rvp, kcred);
+ error = VOP_LOOKUP(dirvp, nm, &vp, NULL, 0, rvp, kcred,
+ NULL, NULL, NULL);
if (error) {
dcmn_err5(("remdrv_cleanup %s lookup error %d\n",
nm, error));
@@ -1704,7 +1708,7 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
iov.iov_len = dlen;
(void) VOP_RWLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dirvp, &uio, kcred, &eof);
+ error = VOP_READDIR(dirvp, &uio, kcred, &eof, NULL, 0);
VOP_RWUNLOCK(dirvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -1724,7 +1728,7 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
continue;
error = VOP_LOOKUP(dirvp, nm, &vp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
dsysdebug(error,
("rem_drv %s/%s lookup (%d)\n",
@@ -1739,14 +1743,15 @@ devfs_remdrv_cleanup(const char *dir, const char *nodename)
if (vp->v_type == VDIR) {
error = devfs_remdrv_rmdir(vp, nm, rvp);
if (error == 0) {
- error = VOP_RMDIR(dirvp,
- (char *)nm, rvp, kcred);
+ error = VOP_RMDIR(dirvp, (char *)nm,
+ rvp, kcred, NULL, 0);
dsysdebug(error,
("rem_drv %s/%s rmdir (%d)\n",
dir, nm, error));
}
} else {
- error = VOP_REMOVE(dirvp, (char *)nm, kcred);
+ error = VOP_REMOVE(dirvp, (char *)nm, kcred,
+ NULL, 0);
dsysdebug(error,
("rem_drv %s/%s remove (%d)\n",
dir, nm, error));
diff --git a/usr/src/uts/common/fs/devfs/devfs_vfsops.c b/usr/src/uts/common/fs/devfs/devfs_vfsops.c
index ddd006ab70..c6a6a2a896 100644
--- a/usr/src/uts/common/fs/devfs/devfs_vfsops.c
+++ b/usr/src/uts/common/fs/devfs/devfs_vfsops.c
@@ -556,7 +556,7 @@ devfs_devpolicy(vnode_t *vp, devplcy_t **dpp)
if (devfs_mntinfo == NULL)
return (rval);
- if (VOP_REALVP(vp, &rvp) == 0 && vn_matchops(rvp, dv_vnodeops)) {
+ if (VOP_REALVP(vp, &rvp, NULL) == 0 && vn_matchops(rvp, dv_vnodeops)) {
dvp = VTODV(rvp);
rw_enter(&dvp->dv_contents, RW_READER);
if (dvp->dv_priv) {
diff --git a/usr/src/uts/common/fs/devfs/devfs_vnops.c b/usr/src/uts/common/fs/devfs/devfs_vnops.c
index c55295b0f6..d459929000 100644
--- a/usr/src/uts/common/fs/devfs/devfs_vnops.c
+++ b/usr/src/uts/common/fs/devfs/devfs_vnops.c
@@ -72,7 +72,8 @@ extern dev_t rconsdev;
*/
/*ARGSUSED*/
static int
-devfs_open(struct vnode **vpp, int flag, struct cred *cred)
+devfs_open(struct vnode **vpp, int flag, struct cred *cred,
+ caller_context_t *ct)
{
struct dv_node *dv = VTODV(*vpp);
@@ -88,7 +89,7 @@ devfs_open(struct vnode **vpp, int flag, struct cred *cred)
/*ARGSUSED1*/
static int
devfs_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cred)
+ offset_t offset, struct cred *cred, caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
@@ -137,7 +138,7 @@ devfs_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
/*ARGSUSED*/
static int
devfs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- struct cred *cred, int *rvalp)
+ struct cred *cred, int *rvalp, caller_context_t *ct)
{
dcmn_err2(("devfs_ioctl %s\n", VTODV(vp)->dv_name));
ASSERT(vp->v_type == VDIR);
@@ -159,7 +160,8 @@ devfs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
* memory based attributes.
*/
static int
-devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
int error = 0;
@@ -189,7 +191,7 @@ devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
vap->va_mask = mask;
} else {
/* obtain from attribute store and merge */
- error = VOP_GETATTR(dv->dv_attrvp, vap, flags, cr);
+ error = VOP_GETATTR(dv->dv_attrvp, vap, flags, cr, ct);
dsysdebug(error, ("vop_getattr %s %d\n", dv->dv_name, error));
dv_vattr_merge(dv, vap);
}
@@ -238,8 +240,8 @@ devfs_setattr_dir(
again: if (dv->dv_attr) {
- error = secpolicy_vnode_setattr(cr, vp, vap, dv->dv_attr,
- flags, devfs_unlocked_access, dv);
+ error = secpolicy_vnode_setattr(cr, vp, vap,
+ dv->dv_attr, flags, devfs_unlocked_access, dv);
if (error)
goto out;
@@ -296,8 +298,8 @@ again: if (dv->dv_attr) {
* read/write.
*/
vattr = dv_vattr_dir;
- if (VOP_GETATTR(dv->dv_attrvp, &vattr,
- flags, cr) == 0) {
+ if (VOP_GETATTR(dv->dv_attrvp,
+ &vattr, flags, cr, NULL) == 0) {
dv->dv_attr = kmem_alloc(
sizeof (struct vattr), KM_SLEEP);
*dv->dv_attr = vattr;
@@ -456,7 +458,7 @@ devfs_setattr(
ASSERT(dv->dv_attrvp);
ASSERT(vp->v_type != VDIR);
*vattrp = dv_vattr_file;
- error = VOP_GETATTR(dv->dv_attrvp, vattrp, 0, cr);
+ error = VOP_GETATTR(dv->dv_attrvp, vattrp, 0, cr, ct);
dsysdebug(error, ("vop_getattr %s %d\n",
dv->dv_name, error));
if (error)
@@ -514,7 +516,7 @@ devfs_setattr(
ddv = dv->dv_dotdot;
ASSERT(ddv->dv_attrvp);
error = VOP_REMOVE(ddv->dv_attrvp,
- dv->dv_name, cr);
+ dv->dv_name, cr, ct, 0);
dsysdebug(error,
("vop_remove %s %s %d\n",
ddv->dv_name, dv->dv_name, error));
@@ -573,7 +575,8 @@ out:
}
static int
-devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
switch (cmd) {
case _PC_ACL_ENABLED:
@@ -587,11 +590,11 @@ devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
*/
ASSERT(dvroot);
ASSERT(dvroot->dv_attrvp);
- return (VOP_PATHCONF(dvroot->dv_attrvp, cmd, valp, cr));
+ return (VOP_PATHCONF(dvroot->dv_attrvp, cmd, valp, cr, ct));
/*NOTREACHED*/
}
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
/*
@@ -599,7 +602,7 @@ devfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
*/
static int
devfs_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
dvnode_t *dv = VTODV(vp);
struct vnode *avp;
@@ -614,12 +617,12 @@ devfs_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
/* fabricate the acl */
if (avp == NULL) {
- error = fs_fab_acl(vp, vsap, flags, cr);
+ error = fs_fab_acl(vp, vsap, flags, cr, ct);
rw_exit(&dv->dv_contents);
return (error);
}
- error = VOP_GETSECATTR(avp, vsap, flags, cr);
+ error = VOP_GETSECATTR(avp, vsap, flags, cr, ct);
dsysdebug(error, ("vop_getsecattr %s %d\n", VTODV(vp)->dv_name, error));
rw_exit(&dv->dv_contents);
return (error);
@@ -633,7 +636,7 @@ devfs_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
*/
static int
devfs_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
dvnode_t *dv = VTODV(vp);
struct vnode *avp;
@@ -672,7 +675,7 @@ devfs_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags,
* store before forwarding the ACL.
*/
(void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(avp, vsap, flags, cr);
+ error = VOP_SETSECATTR(avp, vsap, flags, cr, ct);
dsysdebug(error, ("vop_setsecattr %s %d\n", VTODV(vp)->dv_name, error));
VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, NULL);
@@ -717,7 +720,8 @@ devfs_unlocked_access(void *vdv, int mode, struct cred *cr)
}
static int
-devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
int res;
@@ -739,7 +743,7 @@ devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
}
rw_exit(&dv->dv_contents);
}
- return (VOP_ACCESS(dv->dv_attrvp, mode, flags, cr));
+ return (VOP_ACCESS(dv->dv_attrvp, mode, flags, cr, ct));
}
/*
@@ -801,7 +805,8 @@ devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
/*ARGSUSED3*/
static int
devfs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
ASSERT(dvp->v_type == VDIR);
dcmn_err2(("devfs_lookup: %s\n", nm));
@@ -820,7 +825,8 @@ devfs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
/*ARGSUSED2*/
static int
devfs_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
- int mode, struct vnode **vpp, struct cred *cred, int flag)
+ int mode, struct vnode **vpp, struct cred *cred, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
struct vnode *vp;
@@ -833,7 +839,7 @@ devfs_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
else if (vp->v_type == VDIR && (mode & VWRITE))
error = EISDIR;
else
- error = VOP_ACCESS(vp, mode, 0, cred);
+ error = VOP_ACCESS(vp, mode, 0, cred, ct);
if (error) {
VN_RELE(vp);
@@ -850,8 +856,10 @@ devfs_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
* Otherwise, simply return cached dv_node's. Hotplug code always call
* devfs_clean() to invalid the dv_node cache.
*/
+/*ARGSUSED5*/
static int
-devfs_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
+devfs_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp,
+ caller_context_t *ct, int flags)
{
struct dv_node *ddv, *dv;
struct dirent64 *de, *bufp;
@@ -994,7 +1002,7 @@ full: dcmn_err3(("devfs_readdir: moving %lu bytes: "
va.va_mask = AT_ATIME;
gethrestime(&va.va_atime);
rw_exit(&ddv->dv_contents);
- (void) devfs_setattr(dvp, &va, 0, cred, NULL);
+ (void) devfs_setattr(dvp, &va, 0, cred, ct);
rw_enter(&ddv->dv_contents, RW_READER);
}
@@ -1004,7 +1012,8 @@ full: dcmn_err3(("devfs_readdir: moving %lu bytes: "
/*ARGSUSED*/
static int
-devfs_fsync(struct vnode *vp, int syncflag, struct cred *cred)
+devfs_fsync(struct vnode *vp, int syncflag, struct cred *cred,
+ caller_context_t *ct)
{
/*
* Message goes to console only. Otherwise, the message
@@ -1024,7 +1033,7 @@ devfs_fsync(struct vnode *vp, int syncflag, struct cred *cred)
*/
/*ARGSUSED1*/
static void
-devfs_inactive(struct vnode *vp, struct cred *cred)
+devfs_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
{
int destroy;
struct dv_node *dv = VTODV(vp);
@@ -1045,8 +1054,9 @@ devfs_inactive(struct vnode *vp, struct cred *cred)
* XXX Why do we need this? NFS mounted /dev directories?
* XXX Talk to peter staubach about this.
*/
+/*ARGSUSED2*/
static int
-devfs_fid(struct vnode *vp, struct fid *fidp)
+devfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct dv_node *dv = VTODV(vp);
struct dv_fid *dv_fid;
@@ -1095,7 +1105,8 @@ devfs_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ct)
*/
/*ARGSUSED1*/
static int
-devfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+devfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
ASSERT(vp->v_type == VDIR);
dcmn_err2(("devfs_seek %s\n", VTODV(vp)->dv_name));
diff --git a/usr/src/uts/common/fs/doorfs/door_sys.c b/usr/src/uts/common/fs/doorfs/door_sys.c
index c139032e70..ec9d650d99 100644
--- a/usr/src/uts/common/fs/doorfs/door_sys.c
+++ b/usr/src/uts/common/fs/doorfs/door_sys.c
@@ -69,14 +69,14 @@
#include <sys/rctl.h>
/*
- * The maximum amount of data (in bytes) that will be transfered using
+ * The maximum amount of data (in bytes) that will be transferred using
* an intermediate kernel buffer. For sizes greater than this we map
* in the destination pages and perform a 1-copy transfer.
*/
size_t door_max_arg = 16 * 1024;
/*
- * Maximum amount of data that will be transfered in a reply to a
+ * Maximum amount of data that will be transferred in a reply to a
* door_upcall. Need to guard against a process returning huge amounts
* of data and getting the kernel stuck in kmem_alloc.
*/
@@ -168,7 +168,7 @@ _init(void)
cmn_err(CE_WARN, "door init: bad vfs ops");
return (error);
}
- vfs_setops(&door_vfs, door_vfsops);
+ VFS_INIT(&door_vfs, door_vfsops, NULL);
door_vfs.vfs_flag = VFS_RDONLY;
door_vfs.vfs_dev = doordev;
vfs_make_fsid(&(door_vfs.vfs_fsid), doordev, 0);
@@ -1726,7 +1726,7 @@ door_insert(struct file *fp, door_desc_t *dp)
dp->d_data.d_desc.d_descriptor = fd;
/* Fill in the attributes */
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp && vp->v_type == VDOOR) {
if (VTOD(vp)->door_target == curproc)
@@ -1796,7 +1796,7 @@ door_get_server(door_node_t *dp)
if (!cv_wait_sig_swap_core(&pool->dp_cv, &door_knob,
&signalled)) {
/*
- * If we were signalled and the door is still
+ * If we were signaled and the door is still
* valid, pass the signal on to another waiter.
*/
if (signalled && !DOOR_INVALID(dp))
@@ -1905,7 +1905,7 @@ door_lookup(int did, file_t **fpp)
/*
* Use the underlying vnode (we may be namefs mounted)
*/
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp == NULL || vp->v_type != VDOOR) {
@@ -2562,7 +2562,7 @@ door_translate_in(void)
(void) closeandsetf(fd, NULL);
}
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
/* Set attributes */
@@ -3217,7 +3217,7 @@ shuttle_return:
struct file *fp;
fp = *fpp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
didpp->d_attributes = DOOR_HANDLE |
@@ -3297,7 +3297,7 @@ door_ki_upcall(door_handle_t dh, door_arg_t *param)
file_t *fp = DHTOF(dh);
vnode_t *realvp;
- if (VOP_REALVP(fp->f_vnode, &realvp))
+ if (VOP_REALVP(fp->f_vnode, &realvp, NULL))
realvp = fp->f_vnode;
return (door_upcall(realvp, param));
}
@@ -3365,7 +3365,7 @@ door_ki_open(char *pathname, door_handle_t *dhp)
if ((err = lookupname(pathname, UIO_SYSSPACE, FOLLOW, NULL, &vp)) != 0)
return (err);
- if (err = VOP_OPEN(&vp, FREAD, kcred)) {
+ if (err = VOP_OPEN(&vp, FREAD, kcred, NULL)) {
VN_RELE(vp);
return (err);
}
@@ -3389,7 +3389,7 @@ door_ki_info(door_handle_t dh, struct door_info *dip)
file_t *fp = DHTOF(dh);
vnode_t *vp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp->v_type != VDOOR)
return (EINVAL);
@@ -3419,7 +3419,7 @@ door_ki_setparam(door_handle_t dh, int type, size_t val)
file_t *fp = DHTOF(dh);
vnode_t *vp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp->v_type != VDOOR)
return (EINVAL);
@@ -3432,7 +3432,7 @@ door_ki_getparam(door_handle_t dh, int type, size_t *out)
file_t *fp = DHTOF(dh);
vnode_t *vp;
- if (VOP_REALVP(fp->f_vnode, &vp))
+ if (VOP_REALVP(fp->f_vnode, &vp, NULL))
vp = fp->f_vnode;
if (vp->v_type != VDOOR)
return (EINVAL);
diff --git a/usr/src/uts/common/fs/doorfs/door_vnops.c b/usr/src/uts/common/fs/doorfs/door_vnops.c
index 6d61c34f30..b50465f9c8 100644
--- a/usr/src/uts/common/fs/doorfs/door_vnops.c
+++ b/usr/src/uts/common/fs/doorfs/door_vnops.c
@@ -38,15 +38,17 @@
#include <sys/tsol/label.h>
kmutex_t door_knob;
-static int door_open(struct vnode **vpp, int flag, struct cred *cr);
+static int door_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct);
static int door_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cr);
+ offset_t offset, struct cred *cr, caller_context_t *ct);
static int door_getattr(struct vnode *vp, struct vattr *vap,
- int flags, struct cred *cr);
-static void door_inactive(struct vnode *vp, struct cred *cr);
+ int flags, struct cred *cr, caller_context_t *ct);
+static void door_inactive(struct vnode *vp, struct cred *cr,
+ caller_context_t *ct);
static int door_access(struct vnode *vp, int mode, int flags,
- struct cred *cr);
-static int door_realvp(vnode_t *vp, vnode_t **vpp);
+ struct cred *cr, caller_context_t *ct);
+static int door_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct);
struct vfs door_vfs;
@@ -70,7 +72,7 @@ const fs_operation_def_t door_vnodeops_template[] = {
/* ARGSUSED */
static int
-door_open(struct vnode **vpp, int flag, struct cred *cr)
+door_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *ct)
{
/*
* MAC policy for doors. Restrict cross-zone open()s so that only
@@ -103,7 +105,8 @@ door_close(
int flag,
int count,
offset_t offset,
- struct cred *cr
+ struct cred *cr,
+ caller_context_t *ct
)
{
door_node_t *dp = VTOD(vp);
@@ -142,7 +145,8 @@ door_close(
/* ARGSUSED */
static int
-door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr,
+ caller_context_t *ct)
{
static timestruc_t tzero = {0, 0};
extern dev_t doordev;
@@ -169,7 +173,7 @@ door_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
/* ARGSUSED */
static void
-door_inactive(struct vnode *vp, struct cred *cr)
+door_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
door_node_t *dp = VTOD(vp);
@@ -231,19 +235,20 @@ door_unbind_thread(door_node_t *dp)
mutex_exit(&vp->v_lock);
if (do_inactive)
- door_inactive(vp, NULL);
+ door_inactive(vp, NULL, NULL);
}
/* ARGSUSED */
static int
-door_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+door_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static int
-door_realvp(vnode_t *vp, vnode_t **vpp)
+door_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
*vpp = vp;
return (0);
diff --git a/usr/src/uts/common/fs/fd/fdops.c b/usr/src/uts/common/fs/fd/fdops.c
index 3033d0ae06..3288872146 100644
--- a/usr/src/uts/common/fs/fd/fdops.c
+++ b/usr/src/uts/common/fs/fd/fdops.c
@@ -82,7 +82,7 @@ static int fdget(vnode_t *, char *, vnode_t **);
/* ARGSUSED */
static int
-fdopen(vnode_t **vpp, int mode, cred_t *cr)
+fdopen(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
{
if ((*vpp)->v_type != VDIR) {
mutex_enter(&(*vpp)->v_lock);
@@ -94,7 +94,8 @@ fdopen(vnode_t **vpp, int mode, cred_t *cr)
/* ARGSUSED */
static int
-fdclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+fdclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -163,7 +164,8 @@ fdread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
/* ARGSUSED */
static int
-fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
vfs_t *vfsp = vp->v_vfsp;
timestruc_t now;
@@ -195,7 +197,7 @@ fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static int
-fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
+fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -203,7 +205,8 @@ fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
static int
fdlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
if (comp[0] == 0 || strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) {
VN_HOLD(dp);
@@ -216,14 +219,16 @@ fdlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pnp,
/* ARGSUSED */
static int
fdcreate(vnode_t *dvp, char *comp, vattr_t *vap, enum vcexcl excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
return (fdget(dvp, comp, vpp));
}
/* ARGSUSED */
static int
-fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, caller_context_t *ct,
+ int flags)
{
/* bp holds one dirent structure */
u_offset_t bp[DIRENT64_RECLEN(FDNSIZE) / sizeof (u_offset_t)];
@@ -300,7 +305,7 @@ fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
/* ARGSUSED */
static void
-fdinactive(vnode_t *vp, cred_t *cr)
+fdinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
mutex_enter(&vp->v_lock);
ASSERT(vp->v_count >= 1);
diff --git a/usr/src/uts/common/fs/fem.c b/usr/src/uts/common/fs/fem.c
index 04886984e4..fec6c3575a 100644
--- a/usr/src/uts/common/fs/fem.c
+++ b/usr/src/uts/common/fs/fem.c
@@ -428,7 +428,7 @@ fem_release(struct fem_list *sp)
*/
static int
-vhead_open(vnode_t **vpp, int mode, cred_t *cr)
+vhead_open(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -440,21 +440,22 @@ vhead_open(vnode_t **vpp, int mode, cred_t *cr)
func = (int (*)()) ((*vpp)->v_op->vop_open);
arg0 = (void *)vpp;
fem_unlock((*vpp)->v_femhead);
- errc = (*func)(arg0, mode, cr);
+ errc = (*func)(arg0, mode, cr, ct);
} else {
fem_addref(femsp);
fem_unlock((*vpp)->v_femhead);
farg.fa_vnode.vpp = vpp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_open, femop_open);
- errc = (*func)(arg0, mode, cr);
+ errc = (*func)(arg0, mode, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -466,14 +467,14 @@ vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_close);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, flag, count, offset, cr);
+ errc = (*func)(arg0, flag, count, offset, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_close, femop_close);
- errc = (*func)(arg0, flag, count, offset, cr);
+ errc = (*func)(arg0, flag, count, offset, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -481,7 +482,7 @@ vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
static int
vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -508,7 +509,7 @@ vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
static int
vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -535,7 +536,7 @@ vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
static int
vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -547,21 +548,22 @@ vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
func = (int (*)()) (vp->v_op->vop_ioctl);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, arg, flag, cr, rvalp);
+ errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_ioctl, femop_ioctl);
- errc = (*func)(arg0, cmd, arg, flag, cr, rvalp);
+ errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -573,21 +575,22 @@ vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_setfl);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, oflags, nflags, cr);
+ errc = (*func)(arg0, oflags, nflags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_setfl, femop_setfl);
- errc = (*func)(arg0, oflags, nflags, cr);
+ errc = (*func)(arg0, oflags, nflags, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -599,7 +602,7 @@ vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_getattr);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vap, flags, cr);
+ errc = (*func)(arg0, vap, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -607,7 +610,7 @@ vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_getattr,
femop_getattr);
- errc = (*func)(arg0, vap, flags, cr);
+ errc = (*func)(arg0, vap, flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -642,7 +645,8 @@ vhead_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
}
static int
-vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -654,7 +658,7 @@ vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_access);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, mode, flags, cr);
+ errc = (*func)(arg0, mode, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -662,7 +666,7 @@ vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_access,
femop_access);
- errc = (*func)(arg0, mode, flags, cr);
+ errc = (*func)(arg0, mode, flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -670,7 +674,8 @@ vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr)
static int
vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
femarg_t farg;
struct fem_list *femsp;
@@ -682,7 +687,8 @@ vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
func = (int (*)()) (dvp->v_op->vop_lookup);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr);
+ errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
+ direntflags, realpnp);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -690,7 +696,8 @@ vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_lookup,
femop_lookup);
- errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr);
+ errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
+ direntflags, realpnp);
fem_release(femsp);
}
return (errc);
@@ -698,7 +705,8 @@ vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
static int
vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
femarg_t farg;
struct fem_list *femsp;
@@ -710,7 +718,8 @@ vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
func = (int (*)()) (dvp->v_op->vop_create);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag);
+ errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -718,14 +727,16 @@ vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_create,
femop_create);
- errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag);
+ errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_remove(vnode_t *dvp, char *nm, cred_t *cr)
+vhead_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -737,7 +748,7 @@ vhead_remove(vnode_t *dvp, char *nm, cred_t *cr)
func = (int (*)()) (dvp->v_op->vop_remove);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, nm, cr);
+ errc = (*func)(arg0, nm, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -745,14 +756,15 @@ vhead_remove(vnode_t *dvp, char *nm, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_remove,
femop_remove);
- errc = (*func)(arg0, nm, cr);
+ errc = (*func)(arg0, nm, cr, ct, flags);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -764,14 +776,14 @@ vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
func = (int (*)()) (tdvp->v_op->vop_link);
arg0 = tdvp;
fem_unlock(tdvp->v_femhead);
- errc = (*func)(arg0, svp, tnm, cr);
+ errc = (*func)(arg0, svp, tnm, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(tdvp->v_femhead);
farg.fa_vnode.vp = tdvp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_link, femop_link);
- errc = (*func)(arg0, svp, tnm, cr);
+ errc = (*func)(arg0, svp, tnm, cr, ct, flags);
fem_release(femsp);
}
return (errc);
@@ -779,7 +791,7 @@ vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
static int
vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -791,7 +803,7 @@ vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
func = (int (*)()) (sdvp->v_op->vop_rename);
arg0 = sdvp;
fem_unlock(sdvp->v_femhead);
- errc = (*func)(arg0, snm, tdvp, tnm, cr);
+ errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(sdvp->v_femhead);
@@ -799,7 +811,7 @@ vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_rename,
femop_rename);
- errc = (*func)(arg0, snm, tdvp, tnm, cr);
+ errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
fem_release(femsp);
}
return (errc);
@@ -807,7 +819,7 @@ vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
static int
vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
femarg_t farg;
struct fem_list *femsp;
@@ -819,21 +831,22 @@ vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
func = (int (*)()) (dvp->v_op->vop_mkdir);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, dirname, vap, vpp, cr);
+ errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
farg.fa_vnode.vp = dvp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_mkdir, femop_mkdir);
- errc = (*func)(arg0, dirname, vap, vpp, cr);
+ errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -845,21 +858,22 @@ vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
func = (int (*)()) (dvp->v_op->vop_rmdir);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, nm, cdir, cr);
+ errc = (*func)(arg0, nm, cdir, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
farg.fa_vnode.vp = dvp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_rmdir, femop_rmdir);
- errc = (*func)(arg0, nm, cdir, cr);
+ errc = (*func)(arg0, nm, cdir, cr, ct, flags);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -871,7 +885,7 @@ vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
func = (int (*)()) (vp->v_op->vop_readdir);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, uiop, cr, eofp);
+ errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -879,7 +893,7 @@ vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_readdir,
femop_readdir);
- errc = (*func)(arg0, uiop, cr, eofp);
+ errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
fem_release(femsp);
}
return (errc);
@@ -887,7 +901,7 @@ vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
static int
vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
femarg_t farg;
struct fem_list *femsp;
@@ -899,7 +913,7 @@ vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
func = (int (*)()) (dvp->v_op->vop_symlink);
arg0 = dvp;
fem_unlock(dvp->v_femhead);
- errc = (*func)(arg0, linkname, vap, target, cr);
+ errc = (*func)(arg0, linkname, vap, target, cr, ct, flags);
} else {
fem_addref(femsp);
fem_unlock(dvp->v_femhead);
@@ -907,14 +921,14 @@ vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_symlink,
femop_symlink);
- errc = (*func)(arg0, linkname, vap, target, cr);
+ errc = (*func)(arg0, linkname, vap, target, cr, ct, flags);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -926,7 +940,7 @@ vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_readlink);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, uiop, cr);
+ errc = (*func)(arg0, uiop, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -934,14 +948,14 @@ vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_readlink,
femop_readlink);
- errc = (*func)(arg0, uiop, cr);
+ errc = (*func)(arg0, uiop, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -953,21 +967,21 @@ vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_fsync);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, syncflag, cr);
+ errc = (*func)(arg0, syncflag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_fsync, femop_fsync);
- errc = (*func)(arg0, syncflag, cr);
+ errc = (*func)(arg0, syncflag, cr, ct);
fem_release(femsp);
}
return (errc);
}
static void
-vhead_inactive(vnode_t *vp, cred_t *cr)
+vhead_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -978,7 +992,7 @@ vhead_inactive(vnode_t *vp, cred_t *cr)
func = (void (*)()) (vp->v_op->vop_inactive);
arg0 = vp;
fem_unlock(vp->v_femhead);
- (*func)(arg0, cr);
+ (*func)(arg0, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -986,13 +1000,13 @@ vhead_inactive(vnode_t *vp, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, void, &arg0, vop_inactive,
femop_inactive);
- (*func)(arg0, cr);
+ (*func)(arg0, cr, ct);
fem_release(femsp);
}
}
static int
-vhead_fid(vnode_t *vp, fid_t *fidp)
+vhead_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1004,14 +1018,14 @@ vhead_fid(vnode_t *vp, fid_t *fidp)
func = (int (*)()) (vp->v_op->vop_fid);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, fidp);
+ errc = (*func)(arg0, fidp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_fid, femop_fid);
- errc = (*func)(arg0, fidp);
+ errc = (*func)(arg0, fidp, ct);
fem_release(femsp);
}
return (errc);
@@ -1070,7 +1084,7 @@ vhead_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
}
static int
-vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1082,21 +1096,21 @@ vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
func = (int (*)()) (vp->v_op->vop_seek);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, ooff, noffp);
+ errc = (*func)(arg0, ooff, noffp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_seek, femop_seek);
- errc = (*func)(arg0, ooff, noffp);
+ errc = (*func)(arg0, ooff, noffp, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_cmp(vnode_t *vp1, vnode_t *vp2)
+vhead_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1108,14 +1122,14 @@ vhead_cmp(vnode_t *vp1, vnode_t *vp2)
func = (int (*)()) (vp1->v_op->vop_cmp);
arg0 = vp1;
fem_unlock(vp1->v_femhead);
- errc = (*func)(arg0, vp2);
+ errc = (*func)(arg0, vp2, ct);
} else {
fem_addref(femsp);
fem_unlock(vp1->v_femhead);
farg.fa_vnode.vp = vp1;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_cmp, femop_cmp);
- errc = (*func)(arg0, vp2);
+ errc = (*func)(arg0, vp2, ct);
fem_release(femsp);
}
return (errc);
@@ -1123,7 +1137,8 @@ vhead_cmp(vnode_t *vp1, vnode_t *vp2)
static int
vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1135,7 +1150,7 @@ vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
func = (int (*)()) (vp->v_op->vop_frlock);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr);
+ errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1143,7 +1158,7 @@ vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_frlock,
femop_frlock);
- errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr);
+ errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1177,7 +1192,7 @@ vhead_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
}
static int
-vhead_realvp(vnode_t *vp, vnode_t **vpp)
+vhead_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1189,7 +1204,7 @@ vhead_realvp(vnode_t *vp, vnode_t **vpp)
func = (int (*)()) (vp->v_op->vop_realvp);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vpp);
+ errc = (*func)(arg0, vpp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1197,7 +1212,7 @@ vhead_realvp(vnode_t *vp, vnode_t **vpp)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_realvp,
femop_realvp);
- errc = (*func)(arg0, vpp);
+ errc = (*func)(arg0, vpp, ct);
fem_release(femsp);
}
return (errc);
@@ -1206,7 +1221,7 @@ vhead_realvp(vnode_t *vp, vnode_t **vpp)
static int
vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1219,7 +1234,7 @@ vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, len, protp, plarr, plsz, seg,
- addr, rw, cr);
+ addr, rw, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1228,14 +1243,15 @@ vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
vsop_find(&farg, &func, int, &arg0, vop_getpage,
femop_getpage);
errc = (*func)(arg0, off, len, protp, plarr, plsz, seg,
- addr, rw, cr);
+ addr, rw, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1247,7 +1263,7 @@ vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_putpage);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, off, len, flags, cr);
+ errc = (*func)(arg0, off, len, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1255,7 +1271,7 @@ vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_putpage,
femop_putpage);
- errc = (*func)(arg0, off, len, flags, cr);
+ errc = (*func)(arg0, off, len, flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1264,7 +1280,7 @@ vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
static int
vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1277,7 +1293,7 @@ vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, as, addrp, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1285,7 +1301,7 @@ vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_map, femop_map);
errc = (*func)(arg0, off, as, addrp, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1294,7 +1310,7 @@ vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
static int
vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1307,7 +1323,7 @@ vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1316,7 +1332,7 @@ vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
vsop_find(&farg, &func, int, &arg0, vop_addmap,
femop_addmap);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1324,7 +1340,8 @@ vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
static int
vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1337,7 +1354,7 @@ vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
arg0 = vp;
fem_unlock(vp->v_femhead);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1346,7 +1363,7 @@ vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
vsop_find(&farg, &func, int, &arg0, vop_delmap,
femop_delmap);
errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
- flags, cr);
+ flags, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1354,7 +1371,7 @@ vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
static int
vhead_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1366,21 +1383,21 @@ vhead_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
func = (int (*)()) (vp->v_op->vop_poll);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, events, anyyet, reventsp, phpp);
+ errc = (*func)(arg0, events, anyyet, reventsp, phpp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_poll, femop_poll);
- errc = (*func)(arg0, events, anyyet, reventsp, phpp);
+ errc = (*func)(arg0, events, anyyet, reventsp, phpp, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks)
+vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1392,21 +1409,22 @@ vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks)
func = (int (*)()) (vp->v_op->vop_dump);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, addr, lbdn, dblks);
+ errc = (*func)(arg0, addr, lbdn, dblks, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
farg.fa_vnode.vp = vp;
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_dump, femop_dump);
- errc = (*func)(arg0, addr, lbdn, dblks);
+ errc = (*func)(arg0, addr, lbdn, dblks, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1418,7 +1436,7 @@ vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_pathconf);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, valp, cr);
+ errc = (*func)(arg0, cmd, valp, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1426,7 +1444,7 @@ vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_pathconf,
femop_pathconf);
- errc = (*func)(arg0, cmd, valp, cr);
+ errc = (*func)(arg0, cmd, valp, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1434,7 +1452,7 @@ vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
static int
vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
- size_t io_len, int flags, cred_t *cr)
+ size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1446,7 +1464,7 @@ vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
func = (int (*)()) (vp->v_op->vop_pageio);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, pp, io_off, io_len, flags, cr);
+ errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1454,14 +1472,14 @@ vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_pageio,
femop_pageio);
- errc = (*func)(arg0, pp, io_off, io_len, flags, cr);
+ errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_dumpctl(vnode_t *vp, int action, int *blkp)
+vhead_dumpctl(vnode_t *vp, int action, int *blkp, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1473,7 +1491,7 @@ vhead_dumpctl(vnode_t *vp, int action, int *blkp)
func = (int (*)()) (vp->v_op->vop_dumpctl);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, action, blkp);
+ errc = (*func)(arg0, action, blkp, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1481,14 +1499,15 @@ vhead_dumpctl(vnode_t *vp, int action, int *blkp)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_dumpctl,
femop_dumpctl);
- errc = (*func)(arg0, action, blkp);
+ errc = (*func)(arg0, action, blkp, ct);
fem_release(femsp);
}
return (errc);
}
static void
-vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr)
+vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1499,7 +1518,7 @@ vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr)
func = (void (*)()) (vp->v_op->vop_dispose);
arg0 = vp;
fem_unlock(vp->v_femhead);
- (*func)(arg0, pp, flag, dn, cr);
+ (*func)(arg0, pp, flag, dn, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1507,13 +1526,14 @@ vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, void, &arg0, vop_dispose,
femop_dispose);
- (*func)(arg0, pp, flag, dn, cr);
+ (*func)(arg0, pp, flag, dn, cr, ct);
fem_release(femsp);
}
}
static int
-vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
+vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1525,7 +1545,7 @@ vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_setsecattr);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1533,14 +1553,15 @@ vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_setsecattr,
femop_setsecattr);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
+vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1552,7 +1573,7 @@ vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
func = (int (*)()) (vp->v_op->vop_getsecattr);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1560,7 +1581,7 @@ vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_getsecattr,
femop_getsecattr);
- errc = (*func)(arg0, vsap, flag, cr);
+ errc = (*func)(arg0, vsap, flag, cr, ct);
fem_release(femsp);
}
return (errc);
@@ -1568,7 +1589,7 @@ vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr)
static int
vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1580,7 +1601,7 @@ vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
func = (int (*)()) (vp->v_op->vop_shrlock);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, cmd, shr, flag, cr);
+ errc = (*func)(arg0, cmd, shr, flag, cr, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1588,14 +1609,15 @@ vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_shrlock,
femop_shrlock);
- errc = (*func)(arg0, cmd, shr, flag, cr);
+ errc = (*func)(arg0, cmd, shr, flag, cr, ct);
fem_release(femsp);
}
return (errc);
}
static int
-vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
+vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname,
+ caller_context_t *ct)
{
femarg_t farg;
struct fem_list *femsp;
@@ -1607,7 +1629,7 @@ vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
func = (int (*)()) (vp->v_op->vop_vnevent);
arg0 = vp;
fem_unlock(vp->v_femhead);
- errc = (*func)(arg0, vnevent, dvp, cname);
+ errc = (*func)(arg0, vnevent, dvp, cname, ct);
} else {
fem_addref(femsp);
fem_unlock(vp->v_femhead);
@@ -1615,7 +1637,7 @@ vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
vsop_find(&farg, &func, int, &arg0, vop_vnevent,
femop_vnevent);
- errc = (*func)(arg0, vnevent, dvp, cname);
+ errc = (*func)(arg0, vnevent, dvp, cname, ct);
fem_release(femsp);
}
return (errc);
@@ -1958,7 +1980,7 @@ static struct fs_operation_def fshead_vfs_spec[] = {
*/
int
-vnext_open(femarg_t *vf, int mode, cred_t *cr)
+vnext_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -1968,11 +1990,12 @@ vnext_open(femarg_t *vf, int mode, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_open, femop_open);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, mode, cr));
+ return ((*func)(arg0, mode, cr, ct));
}
int
-vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr)
+vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -1982,12 +2005,12 @@ vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_close, femop_close);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, flag, count, offset, cr));
+ return ((*func)(arg0, flag, count, offset, cr, ct));
}
int
vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2002,7 +2025,7 @@ vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
int
vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2017,7 +2040,7 @@ vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
int
vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2027,11 +2050,12 @@ vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag, cred_t *cr,
vsop_find(vf, &func, int, &arg0, vop_ioctl, femop_ioctl);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, arg, flag, cr, rvalp));
+ return ((*func)(arg0, cmd, arg, flag, cr, rvalp, ct));
}
int
-vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr)
+vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2041,11 +2065,12 @@ vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_setfl, femop_setfl);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, oflags, nflags, cr));
+ return ((*func)(arg0, oflags, nflags, cr, ct));
}
int
-vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr)
+vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2055,7 +2080,7 @@ vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_getattr, femop_getattr);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vap, flags, cr));
+ return ((*func)(arg0, vap, flags, cr, ct));
}
int
@@ -2074,7 +2099,8 @@ vnext_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
}
int
-vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr)
+vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2084,12 +2110,13 @@ vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_access, femop_access);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, mode, flags, cr));
+ return ((*func)(arg0, mode, flags, cr, ct));
}
int
vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2099,12 +2126,14 @@ vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp, pathname_t *pnp,
vsop_find(vf, &func, int, &arg0, vop_lookup, femop_lookup);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, nm, vpp, pnp, flags, rdir, cr));
+ return ((*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
+ direntflags, realpnp));
}
int
vnext_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2114,11 +2143,12 @@ vnext_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
vsop_find(vf, &func, int, &arg0, vop_create, femop_create);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, name, vap, excl, mode, vpp, cr, flag));
+ return ((*func)(arg0, name, vap, excl, mode, vpp, cr, flag, ct, vsecp));
}
int
-vnext_remove(femarg_t *vf, char *nm, cred_t *cr)
+vnext_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2128,11 +2158,12 @@ vnext_remove(femarg_t *vf, char *nm, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_remove, femop_remove);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, nm, cr));
+ return ((*func)(arg0, nm, cr, ct, flags));
}
int
-vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
+vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2142,11 +2173,12 @@ vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_link, femop_link);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, svp, tnm, cr));
+ return ((*func)(arg0, svp, tnm, cr, ct, flags));
}
int
-vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
+vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2156,12 +2188,12 @@ vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_rename, femop_rename);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, snm, tdvp, tnm, cr));
+ return ((*func)(arg0, snm, tdvp, tnm, cr, ct, flags));
}
int
vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2171,11 +2203,12 @@ vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
vsop_find(vf, &func, int, &arg0, vop_mkdir, femop_mkdir);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, dirname, vap, vpp, cr));
+ return ((*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp));
}
int
-vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr)
+vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2185,11 +2218,12 @@ vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_rmdir, femop_rmdir);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, nm, cdir, cr));
+ return ((*func)(arg0, nm, cdir, cr, ct, flags));
}
int
-vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp)
+vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2199,12 +2233,12 @@ vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp)
vsop_find(vf, &func, int, &arg0, vop_readdir, femop_readdir);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, uiop, cr, eofp));
+ return ((*func)(arg0, uiop, cr, eofp, ct, flags));
}
int
vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2214,11 +2248,11 @@ vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
vsop_find(vf, &func, int, &arg0, vop_symlink, femop_symlink);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, linkname, vap, target, cr));
+ return ((*func)(arg0, linkname, vap, target, cr, ct, flags));
}
int
-vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr)
+vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2228,11 +2262,11 @@ vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_readlink, femop_readlink);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, uiop, cr));
+ return ((*func)(arg0, uiop, cr, ct));
}
int
-vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr)
+vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2242,11 +2276,11 @@ vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_fsync, femop_fsync);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, syncflag, cr));
+ return ((*func)(arg0, syncflag, cr, ct));
}
void
-vnext_inactive(femarg_t *vf, cred_t *cr)
+vnext_inactive(femarg_t *vf, cred_t *cr, caller_context_t *ct)
{
void (*func)() = NULL;
void *arg0 = NULL;
@@ -2256,11 +2290,11 @@ vnext_inactive(femarg_t *vf, cred_t *cr)
vsop_find(vf, &func, void, &arg0, vop_inactive, femop_inactive);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- (*func)(arg0, cr);
+ (*func)(arg0, cr, ct);
}
int
-vnext_fid(femarg_t *vf, fid_t *fidp)
+vnext_fid(femarg_t *vf, fid_t *fidp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2270,7 +2304,7 @@ vnext_fid(femarg_t *vf, fid_t *fidp)
vsop_find(vf, &func, int, &arg0, vop_fid, femop_fid);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, fidp));
+ return ((*func)(arg0, fidp, ct));
}
int
@@ -2302,7 +2336,7 @@ vnext_rwunlock(femarg_t *vf, int write_lock, caller_context_t *ct)
}
int
-vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp)
+vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2312,11 +2346,11 @@ vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp)
vsop_find(vf, &func, int, &arg0, vop_seek, femop_seek);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, ooff, noffp));
+ return ((*func)(arg0, ooff, noffp, ct));
}
int
-vnext_cmp(femarg_t *vf, vnode_t *vp2)
+vnext_cmp(femarg_t *vf, vnode_t *vp2, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2326,12 +2360,13 @@ vnext_cmp(femarg_t *vf, vnode_t *vp2)
vsop_find(vf, &func, int, &arg0, vop_cmp, femop_cmp);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vp2));
+ return ((*func)(arg0, vp2, ct));
}
int
vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2341,7 +2376,7 @@ vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
vsop_find(vf, &func, int, &arg0, vop_frlock, femop_frlock);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr));
+ return ((*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
int
@@ -2360,7 +2395,7 @@ vnext_space(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
}
int
-vnext_realvp(femarg_t *vf, vnode_t **vpp)
+vnext_realvp(femarg_t *vf, vnode_t **vpp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2370,13 +2405,13 @@ vnext_realvp(femarg_t *vf, vnode_t **vpp)
vsop_find(vf, &func, int, &arg0, vop_realvp, femop_realvp);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vpp));
+ return ((*func)(arg0, vpp, ct));
}
int
vnext_getpage(femarg_t *vf, offset_t off, size_t len, uint_t *protp,
struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2387,12 +2422,12 @@ vnext_getpage(femarg_t *vf, offset_t off, size_t len, uint_t *protp,
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
return ((*func)(arg0, off, len, protp, plarr, plsz, seg, addr, rw,
- cr));
+ cr, ct));
}
int
vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2402,13 +2437,13 @@ vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
vsop_find(vf, &func, int, &arg0, vop_putpage, femop_putpage);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, off, len, flags, cr));
+ return ((*func)(arg0, off, len, flags, cr, ct));
}
int
vnext_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2419,13 +2454,13 @@ vnext_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
return ((*func)(arg0, off, as, addrp, len, prot, maxprot, flags,
- cr));
+ cr, ct));
}
int
vnext_addmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2435,12 +2470,14 @@ vnext_addmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
vsop_find(vf, &func, int, &arg0, vop_addmap, femop_addmap);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags, cr));
+ return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
+ cr, ct));
}
int
vnext_delmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2450,12 +2487,13 @@ vnext_delmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
vsop_find(vf, &func, int, &arg0, vop_delmap, femop_delmap);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags, cr));
+ return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
+ cr, ct));
}
int
vnext_poll(femarg_t *vf, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2465,11 +2503,12 @@ vnext_poll(femarg_t *vf, short events, int anyyet, short *reventsp,
vsop_find(vf, &func, int, &arg0, vop_poll, femop_poll);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, events, anyyet, reventsp, phpp));
+ return ((*func)(arg0, events, anyyet, reventsp, phpp, ct));
}
int
-vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks)
+vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2479,11 +2518,12 @@ vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks)
vsop_find(vf, &func, int, &arg0, vop_dump, femop_dump);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, addr, lbdn, dblks));
+ return ((*func)(arg0, addr, lbdn, dblks, ct));
}
int
-vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr)
+vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2493,12 +2533,12 @@ vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_pathconf, femop_pathconf);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, valp, cr));
+ return ((*func)(arg0, cmd, valp, cr, ct));
}
int
vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
- size_t io_len, int flags, cred_t *cr)
+ size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2508,11 +2548,11 @@ vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
vsop_find(vf, &func, int, &arg0, vop_pageio, femop_pageio);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, pp, io_off, io_len, flags, cr));
+ return ((*func)(arg0, pp, io_off, io_len, flags, cr, ct));
}
int
-vnext_dumpctl(femarg_t *vf, int action, int *blkp)
+vnext_dumpctl(femarg_t *vf, int action, int *blkp, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2522,11 +2562,12 @@ vnext_dumpctl(femarg_t *vf, int action, int *blkp)
vsop_find(vf, &func, int, &arg0, vop_dumpctl, femop_dumpctl);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, action, blkp));
+ return ((*func)(arg0, action, blkp, ct));
}
void
-vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr)
+vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr,
+ caller_context_t *ct)
{
void (*func)() = NULL;
void *arg0 = NULL;
@@ -2536,11 +2577,12 @@ vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr)
vsop_find(vf, &func, void, &arg0, vop_dispose, femop_dispose);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- (*func)(arg0, pp, flag, dn, cr);
+ (*func)(arg0, pp, flag, dn, cr, ct);
}
int
-vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
+vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2550,11 +2592,12 @@ vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_setsecattr, femop_setsecattr);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vsap, flag, cr));
+ return ((*func)(arg0, vsap, flag, cr, ct));
}
int
-vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
+vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2564,12 +2607,12 @@ vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr)
vsop_find(vf, &func, int, &arg0, vop_getsecattr, femop_getsecattr);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vsap, flag, cr));
+ return ((*func)(arg0, vsap, flag, cr, ct));
}
int
vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2579,11 +2622,12 @@ vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag,
vsop_find(vf, &func, int, &arg0, vop_shrlock, femop_shrlock);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, cmd, shr, flag, cr));
+ return ((*func)(arg0, cmd, shr, flag, cr, ct));
}
int
-vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname)
+vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname,
+ caller_context_t *ct)
{
int (*func)() = NULL;
void *arg0 = NULL;
@@ -2593,7 +2637,7 @@ vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname)
vsop_find(vf, &func, int, &arg0, vop_vnevent, femop_vnevent);
ASSERT(func != NULL);
ASSERT(arg0 != NULL);
- return ((*func)(arg0, vnevent, dvp, cname));
+ return ((*func)(arg0, vnevent, dvp, cname, ct));
}
int
diff --git a/usr/src/uts/common/fs/fifofs/fifosubr.c b/usr/src/uts/common/fs/fifofs/fifosubr.c
index f44b8b3874..0d3d802370 100644
--- a/usr/src/uts/common/fs/fifofs/fifosubr.c
+++ b/usr/src/uts/common/fs/fifofs/fifosubr.c
@@ -29,7 +29,7 @@
/*
* The routines defined in this file are supporting routines for FIFOFS
- * file sytem type.
+ * file system type.
*/
#include <sys/types.h>
#include <sys/param.h>
@@ -164,7 +164,7 @@ static void fifo_reinit_vp(vnode_t *);
* we can determine the fifodata address from any of its member fnodes.
* This is essential for fifo_inactive.
*
- * The fnode constructor is designed to handle any fifodata struture,
+ * The fnode constructor is designed to handle any fifodata structure,
* deducing the number of fnodes from the total size. Thus, the fnode
* constructor does most of the work for the pipe constructor.
*/
@@ -410,8 +410,9 @@ fifovp(vnode_t *vp, cred_t *crp)
* This way different fifo nodes sharing the same real vnode
* can use realvp for communication.
*/
- if (VOP_REALVP(vp, &rvp) == 0)
- vp = rvp;
+
+ if (VOP_REALVP(vp, &rvp, NULL) == 0)
+ vp = rvp;
fnp->fn_realvp = vp;
fnp->fn_wcnt = 0;
@@ -431,7 +432,7 @@ fifovp(vnode_t *vp, cred_t *crp)
* initialize the times from vp.
*/
va.va_mask = AT_TIMES;
- if (VOP_GETATTR(vp, &va, 0, crp) == 0) {
+ if (VOP_GETATTR(vp, &va, 0, crp, NULL) == 0) {
fnp->fn_atime = va.va_atime.tv_sec;
fnp->fn_mtime = va.va_mtime.tv_sec;
fnp->fn_ctime = va.va_ctime.tv_sec;
@@ -652,7 +653,7 @@ fifo_stropen(vnode_t **vpp, int flag, cred_t *crp, int dotwist, int lockheld)
* Create new pipe on behalf of connld
*/
if (error = fifo_connld(vpp, flag, crp)) {
- (void) fifo_close(oldvp, flag, 1, 0, crp);
+ (void) fifo_close(oldvp, flag, 1, 0, crp, NULL);
mutex_enter(&fn_lock->flk_lock);
goto out;
}
@@ -663,7 +664,7 @@ fifo_stropen(vnode_t **vpp, int flag, cred_t *crp, int dotwist, int lockheld)
* we were in fifo_connld(), so
* we want to make sure the close completes (yuk)
*/
- (void) fifo_close(oldvp, flag, 1, 0, crp);
+ (void) fifo_close(oldvp, flag, 1, 0, crp, NULL);
/*
* fifo_connld has changed the vp, so we
* need to re-initialize locals
@@ -1006,7 +1007,7 @@ out:
crhold(c);
(void) closef(filep);
VTOF(vp2)->fn_flag &= ~FIFOOPEN;
- (void) fifo_close(vp2, flag, 1, (offset_t)0, c);
+ (void) fifo_close(vp2, flag, 1, (offset_t)0, c, NULL);
crfree(c);
VN_RELE(vp2);
return (error);
diff --git a/usr/src/uts/common/fs/fifofs/fifovnops.c b/usr/src/uts/common/fs/fifofs/fifovnops.c
index afa01bb3ab..9756d13705 100644
--- a/usr/src/uts/common/fs/fifofs/fifovnops.c
+++ b/usr/src/uts/common/fs/fifofs/fifovnops.c
@@ -73,26 +73,33 @@
*/
static int fifo_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
static int fifo_write(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
-static int fifo_getattr(vnode_t *, vattr_t *, int, cred_t *);
+static int fifo_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
static int fifo_setattr(vnode_t *, vattr_t *, int, cred_t *,
caller_context_t *);
-static int fifo_realvp(vnode_t *, vnode_t **);
-static int fifo_access(vnode_t *, int, int, cred_t *);
+static int fifo_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int fifo_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int fifo_create(struct vnode *, char *, vattr_t *, enum vcexcl,
- int, struct vnode **, struct cred *, int);
-static int fifo_fid(vnode_t *, fid_t *);
-static int fifo_fsync(vnode_t *, int, cred_t *);
-static int fifo_seek(vnode_t *, offset_t, offset_t *);
-static int fifo_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+ int, struct vnode **, struct cred *, int, caller_context_t *,
+ vsecattr_t *);
+static int fifo_fid(vnode_t *, fid_t *, caller_context_t *);
+static int fifo_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static int fifo_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+static int fifo_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
static int fifo_fastioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
static int fifo_strioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-static int fifo_poll(vnode_t *, short, int, short *, pollhead_t **);
-static int fifo_pathconf(vnode_t *, int, ulong_t *, cred_t *);
-static void fifo_inactive(vnode_t *, cred_t *);
+static int fifo_poll(vnode_t *, short, int, short *, pollhead_t **,
+ caller_context_t *);
+static int fifo_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+static void fifo_inactive(vnode_t *, cred_t *, caller_context_t *);
static int fifo_rwlock(vnode_t *, int, caller_context_t *);
static void fifo_rwunlock(vnode_t *, int, caller_context_t *);
-static int fifo_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int fifo_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
+static int fifo_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int fifo_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
/* functions local to this file */
static boolean_t fifo_stayfast_enter(fifonode_t *);
@@ -210,7 +217,7 @@ tsol_fifo_access(vnode_t *vp, int flag, cred_t *crp)
* Note: namefs pipes come through this routine too.
*/
int
-fifo_open(vnode_t **vpp, int flag, cred_t *crp)
+fifo_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
{
vnode_t *vp = *vpp;
fifonode_t *fnp = VTOF(vp);
@@ -280,7 +287,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
* If we are opening for read (or writer)
* indicate that the reader (or writer) is done with open
* if there is a writer (or reader) waiting for us, wake them up
- * and indicate that at least 1 read (or write) open has occured
+ * and indicate that at least 1 read (or write) open has occurred
* this is need in the event the read (or write) side closes
* before the writer (or reader) has a chance to wake up
* i.e. it sees that a reader (or writer) was once there
@@ -289,7 +296,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
fnp->fn_rsynccnt--; /* reader done with open */
if (fnp->fn_flag & FIFOSYNC) {
/*
- * This indicates that a read open has occured
+ * This indicates that a read open has occurred
* Only need to set if writer is actually asleep
* Flag will be consumed by writer.
*/
@@ -301,7 +308,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
fnp->fn_wsynccnt--; /* writer done with open */
if (fnp->fn_flag & FIFOSYNC) {
/*
- * This indicates that a write open has occured
+ * This indicates that a write open has occurred
* Only need to set if reader is actually asleep
* Flag will be consumed by reader.
*/
@@ -347,20 +354,20 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
/*
* Last reader to wakeup clear writer
* Clear both writer and reader open
- * occured flag incase other end is O_RDWR
+ * occurred flag incase other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
fnp->fn_flag & FIFOWOCR) {
fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
}
mutex_exit(&fnp->fn_lock->flk_lock);
- (void) fifo_close(*vpp, flag, 1, 0, crp);
+ (void) fifo_close(*vpp, flag, 1, 0, crp, ct);
error = EINTR;
goto done;
}
/*
- * Last reader to wakeup clear writer open occured flag
- * Clear both writer and reader open occured flag
+ * Last reader to wakeup clear writer open occurred flag
+ * Clear both writer and reader open occurred flag
* incase other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
@@ -374,7 +381,7 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
fnp->fn_rcnt == fnp->fn_rsynccnt) {
if ((flag & (FNDELAY|FNONBLOCK)) && fnp->fn_rcnt == 0) {
mutex_exit(&fnp->fn_lock->flk_lock);
- (void) fifo_close(*vpp, flag, 1, 0, crp);
+ (void) fifo_close(*vpp, flag, 1, 0, crp, ct);
error = ENXIO;
goto done;
}
@@ -385,21 +392,21 @@ fifo_open(vnode_t **vpp, int flag, cred_t *crp)
/*
* Last writer to wakeup clear
* Clear both writer and reader open
- * occured flag in case other end is O_RDWR
+ * occurred flag in case other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
(fnp->fn_flag & FIFOROCR) != 0) {
fnp->fn_flag &= ~(FIFOWOCR|FIFOROCR);
}
mutex_exit(&fnp->fn_lock->flk_lock);
- (void) fifo_close(*vpp, flag, 1, 0, crp);
+ (void) fifo_close(*vpp, flag, 1, 0, crp, ct);
error = EINTR;
goto done;
}
/*
- * Last writer to wakeup clear reader open occured flag
+ * Last writer to wakeup clear reader open occurred flag
* Clear both writer and reader open
- * occured flag in case other end is O_RDWR
+ * occurred flag in case other end is O_RDWR
*/
if (--fnp->fn_insync == 0 &&
(fnp->fn_flag & FIFOROCR) != 0) {
@@ -425,7 +432,8 @@ done:
*/
/*ARGSUSED*/
int
-fifo_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp)
+fifo_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
+ caller_context_t *ct)
{
fifonode_t *fnp = VTOF(vp);
fifonode_t *fn_dest = fnp->fn_dest;
@@ -1079,7 +1087,7 @@ stream_mode:
done:
/*
* update vnode modification and change times
- * make sure there were no errors and some data was transfered
+ * make sure there were no errors and some data was transferred
*/
if (error == 0 && write_size != uiop->uio_resid) {
time_t now = gethrestime_sec();
@@ -1105,9 +1113,10 @@ epipe:
return (error);
}
+/*ARGSUSED6*/
static int
fifo_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
- cred_t *cr, int *rvalp)
+ cred_t *cr, int *rvalp, caller_context_t *ct)
{
/*
* Just a quick check
@@ -1430,7 +1439,8 @@ fifo_strioctl(vnode_t *vp, int cmd, intptr_t arg, int mode,
* the node information from the credentials structure.
*/
int
-fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
+fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
+ caller_context_t *ct)
{
int error = 0;
fifonode_t *fnp = VTOF(vp);
@@ -1442,7 +1452,7 @@ fifo_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
/*
* for FIFOs or mounted pipes
*/
- if (error = VOP_GETATTR(fnp->fn_realvp, vap, flags, crp))
+ if (error = VOP_GETATTR(fnp->fn_realvp, vap, flags, crp, ct))
return (error);
mutex_enter(&fn_lock->flk_lock);
/* set current times from fnode, even if older than vnode */
@@ -1537,10 +1547,10 @@ fifo_setattr(
* Otherwise, return 0 (allow all access).
*/
int
-fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp)
+fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp, caller_context_t *ct)
{
if (VTOF(vp)->fn_realvp)
- return (VOP_ACCESS(VTOF(vp)->fn_realvp, mode, flags, crp));
+ return (VOP_ACCESS(VTOF(vp)->fn_realvp, mode, flags, crp, ct));
else
return (0);
}
@@ -1552,13 +1562,14 @@ fifo_access(vnode_t *vp, int mode, int flags, cred_t *crp)
/*ARGSUSED*/
static int
fifo_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
- int mode, struct vnode **vpp, struct cred *cr, int flag)
+ int mode, struct vnode **vpp, struct cred *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
ASSERT(dvp && (dvp->v_flag & VROOT) && *name == '\0');
if (excl == NONEXCL) {
- if (mode && (error = fifo_access(dvp, mode, 0, cr)))
+ if (mode && (error = fifo_access(dvp, mode, 0, cr, ct)))
return (error);
VN_HOLD(dvp);
return (0);
@@ -1571,7 +1582,7 @@ fifo_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
* Otherwise, return 0.
*/
int
-fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
+fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
{
fifonode_t *fnp = VTOF(vp);
vattr_t va;
@@ -1581,7 +1592,7 @@ fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
bzero((caddr_t)&va, sizeof (va));
va.va_mask = AT_MTIME | AT_ATIME;
- if (VOP_GETATTR(fnp->fn_realvp, &va, 0, crp) == 0) {
+ if (VOP_GETATTR(fnp->fn_realvp, &va, 0, crp, ct) == 0) {
va.va_mask = 0;
if (fnp->fn_mtime > va.va_mtime.tv_sec) {
va.va_mtime.tv_sec = fnp->fn_mtime;
@@ -1592,9 +1603,9 @@ fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
va.va_mask |= AT_ATIME;
}
if (va.va_mask != 0)
- (void) VOP_SETATTR(fnp->fn_realvp, &va, 0, crp, NULL);
+ (void) VOP_SETATTR(fnp->fn_realvp, &va, 0, crp, ct);
}
- return (VOP_FSYNC(fnp->fn_realvp, syncflag, crp));
+ return (VOP_FSYNC(fnp->fn_realvp, syncflag, crp, ct));
}
/*
@@ -1602,7 +1613,7 @@ fifo_fsync(vnode_t *vp, int syncflag, cred_t *crp)
* vnode. Sync the file system and free the fifonode.
*/
void
-fifo_inactive(vnode_t *vp, cred_t *crp)
+fifo_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
{
fifonode_t *fnp;
fifolock_t *fn_lock;
@@ -1630,7 +1641,7 @@ fifo_inactive(vnode_t *vp, cred_t *crp)
if (fnp->fn_realvp) {
(void) fiforemove(fnp);
mutex_exit(&ftable_lock);
- (void) fifo_fsync(vp, FSYNC, crp);
+ (void) fifo_fsync(vp, FSYNC, crp, ct);
VN_RELE(fnp->fn_realvp);
vp->v_vfsp = NULL;
} else
@@ -1684,10 +1695,10 @@ fifo_inactive(vnode_t *vp, cred_t *crp)
* Otherwise, return EINVAL.
*/
int
-fifo_fid(vnode_t *vp, fid_t *fidfnp)
+fifo_fid(vnode_t *vp, fid_t *fidfnp, caller_context_t *ct)
{
if (VTOF(vp)->fn_realvp)
- return (VOP_FID(VTOF(vp)->fn_realvp, fidfnp));
+ return (VOP_FID(VTOF(vp)->fn_realvp, fidfnp, ct));
else
return (EINVAL);
}
@@ -1716,7 +1727,7 @@ fifo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
*/
/*ARGSUSED*/
int
-fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return (ESPIPE);
}
@@ -1725,13 +1736,13 @@ fifo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
* If there is a realvp associated with vp, return it.
*/
int
-fifo_realvp(vnode_t *vp, vnode_t **vpp)
+fifo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
vnode_t *rvp;
if ((rvp = VTOF(vp)->fn_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
@@ -1742,9 +1753,10 @@ fifo_realvp(vnode_t *vp, vnode_t **vpp)
/*
* Poll for interesting events on a stream pipe
*/
+/* ARGSUSED */
int
fifo_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **phpp)
+ pollhead_t **phpp, caller_context_t *ct)
{
fifonode_t *fnp, *fn_dest;
fifolock_t *fn_lock;
@@ -1854,7 +1866,8 @@ stream_mode:
*/
/* ARGSUSED */
int
-fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
ulong_t val;
int error = 0;
@@ -1911,7 +1924,7 @@ fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
default:
if (VTOF(vp)->fn_realvp)
error = VOP_PATHCONF(VTOF(vp)->fn_realvp, cmd,
- &val, cr);
+ &val, cr, ct);
else
error = EINVAL;
break;
@@ -1927,7 +1940,8 @@ fifo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
* Otherwise, return NOSYS.
*/
int
-fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
+fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp,
+ caller_context_t *ct)
{
int error;
@@ -1937,9 +1951,10 @@ fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
* VOP_RWLOCK or VOP_RWUNLOCK, so we do it here instead.
*/
if (VTOF(vp)->fn_realvp) {
- (void) VOP_RWLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(VTOF(vp)->fn_realvp, vsap, flag, crp);
- VOP_RWUNLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, NULL);
+ (void) VOP_RWLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, ct);
+ error = VOP_SETSECATTR(VTOF(vp)->fn_realvp, vsap, flag,
+ crp, ct);
+ VOP_RWUNLOCK(VTOF(vp)->fn_realvp, V_WRITELOCK_TRUE, ct);
return (error);
} else
return (fs_nosys());
@@ -1950,12 +1965,14 @@ fifo_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
* an ACL from the permission bits that fifo_getattr() makes up.
*/
int
-fifo_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp)
+fifo_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *crp,
+ caller_context_t *ct)
{
if (VTOF(vp)->fn_realvp)
- return (VOP_GETSECATTR(VTOF(vp)->fn_realvp, vsap, flag, crp));
+ return (VOP_GETSECATTR(VTOF(vp)->fn_realvp, vsap, flag,
+ crp, ct));
else
- return (fs_fab_acl(vp, vsap, flag, crp));
+ return (fs_fab_acl(vp, vsap, flag, crp, ct));
}
diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c
index c88e8b3268..5afbced148 100644
--- a/usr/src/uts/common/fs/fs_subr.c
+++ b/usr/src/uts/common/fs/fs_subr.c
@@ -113,7 +113,8 @@ fs_nosys_map(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (ENOSYS);
}
@@ -128,7 +129,8 @@ fs_nosys_addmap(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (ENOSYS);
}
@@ -139,7 +141,8 @@ fs_nosys_poll(vnode_t *vp,
register short events,
int anyyet,
register short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
return (ENOSYS);
}
@@ -157,6 +160,38 @@ fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
}
/*
+ * Does nothing but VOP_FSYNC must not fail.
+ */
+/* ARGSUSED */
+int
+fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_PUTPAGE must not fail.
+ */
+/* ARGSUSED */
+int
+fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ctp)
+{
+ return (0);
+}
+
+/*
+ * Does nothing but VOP_IOCTL must not fail.
+ */
+/* ARGSUSED */
+int
+fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
+ int *rvalp)
+{
+ return (0);
+}
+
+/*
* Read/write lock/unlock. Does nothing.
*/
/* ARGSUSED */
@@ -175,8 +210,9 @@ fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/*
* Compare two vnodes.
*/
+/*ARGSUSED2*/
int
-fs_cmp(vnode_t *vp1, vnode_t *vp2)
+fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
return (vp1 == vp2);
}
@@ -186,7 +222,7 @@ fs_cmp(vnode_t *vp1, vnode_t *vp2)
*/
/* ARGSUSED */
int
-fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -197,13 +233,15 @@ fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
/* ARGSUSED */
int
fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, flk_callback_t *flk_cbp, cred_t *cr)
+ offset_t offset, flk_callback_t *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
int frcmd;
int nlmid;
int error = 0;
flk_callback_t serialize_callback;
int serialize = 0;
+ v_mode_t mode;
switch (cmd) {
@@ -211,15 +249,13 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
case F_O_GETLK:
if (flag & F_REMOTELOCK) {
frcmd = RCMDLCK;
- break;
- }
- if (flag & F_PXFSLOCK) {
+ } else if (flag & F_PXFSLOCK) {
frcmd = PCMDLCK;
- break;
+ } else {
+ frcmd = 0;
+ bfp->l_pid = ttoproc(curthread)->p_pid;
+ bfp->l_sysid = 0;
}
- bfp->l_pid = ttoproc(curthread)->p_pid;
- bfp->l_sysid = 0;
- frcmd = 0;
break;
case F_SETLK_NBMAND:
@@ -238,6 +274,19 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/*FALLTHROUGH*/
case F_SETLK:
+ if (flag & F_REMOTELOCK) {
+ frcmd = SETFLCK|RCMDLCK;
+ } else if (flag & F_PXFSLOCK) {
+ frcmd = SETFLCK|PCMDLCK;
+ } else {
+ frcmd = SETFLCK;
+ bfp->l_pid = ttoproc(curthread)->p_pid;
+ bfp->l_sysid = 0;
+ }
+ if (cmd == F_SETLK_NBMAND &&
+ (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
+ frcmd |= NBMLCK;
+ }
/*
* Check whether there is an NBMAND share reservation that
* conflicts with the lock request.
@@ -245,30 +294,31 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_WRITER);
serialize = 1;
+ if (frcmd & NBMLCK) {
+ mode = (bfp->l_type == F_RDLCK) ?
+ V_READ : V_RDANDWR;
+ if (vn_is_mapped(vp, mode)) {
+ error = EAGAIN;
+ goto done;
+ }
+ }
if (share_blocks_lock(vp, bfp)) {
error = EAGAIN;
goto done;
}
}
- if (flag & F_REMOTELOCK) {
- frcmd = SETFLCK|RCMDLCK;
- break;
- }
- if (flag & F_PXFSLOCK) {
- frcmd = SETFLCK|PCMDLCK;
- break;
- }
- bfp->l_pid = ttoproc(curthread)->p_pid;
- bfp->l_sysid = 0;
- frcmd = SETFLCK;
- if (cmd == F_SETLK_NBMAND &&
- (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
- /* would check here for conflict with mapped region */
- frcmd |= NBMLCK;
- }
break;
case F_SETLKW:
+ if (flag & F_REMOTELOCK) {
+ frcmd = SETFLCK|SLPFLCK|RCMDLCK;
+ } else if (flag & F_PXFSLOCK) {
+ frcmd = SETFLCK|SLPFLCK|PCMDLCK;
+ } else {
+ frcmd = SETFLCK|SLPFLCK;
+ bfp->l_pid = ttoproc(curthread)->p_pid;
+ bfp->l_sysid = 0;
+ }
/*
* If there is an NBMAND share reservation that conflicts
* with the lock request, block until the conflicting share
@@ -283,24 +333,13 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
goto done;
}
}
- if (flag & F_REMOTELOCK) {
- frcmd = SETFLCK|SLPFLCK|RCMDLCK;
- break;
- }
- if (flag & F_PXFSLOCK) {
- frcmd = SETFLCK|SLPFLCK|PCMDLCK;
- break;
- }
- bfp->l_pid = ttoproc(curthread)->p_pid;
- bfp->l_sysid = 0;
- frcmd = SETFLCK|SLPFLCK;
break;
case F_HASREMOTELOCKS:
nlmid = GETNLMID(bfp->l_sysid);
if (nlmid != 0) { /* booted as a cluster */
l_has_rmt(bfp) =
- cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
+ cl_flk_has_remote_locks_for_nlmid(vp, nlmid);
} else { /* not booted as a cluster */
l_has_rmt(bfp) = flk_has_remote_locks(vp);
}
@@ -320,7 +359,7 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (serialize && (frcmd & SLPFLCK) != 0) {
flk_add_callback(&serialize_callback,
- frlock_serialize_blocked, vp, flk_cbp);
+ frlock_serialize_blocked, vp, flk_cbp);
flk_cbp = &serialize_callback;
}
@@ -358,7 +397,12 @@ frlock_serialize_blocked(flk_cb_when_t when, void *infop)
*/
/* ARGSUSED */
int
-fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+fs_setfl(
+ vnode_t *vp,
+ int oflags,
+ int nflags,
+ cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -375,7 +419,8 @@ fs_poll(vnode_t *vp,
register short events,
int anyyet,
register short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
*reventsp = 0;
if (events & POLLIN)
@@ -397,7 +442,12 @@ fs_poll(vnode_t *vp,
*/
/* ARGSUSED */
int
-fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+fs_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
{
register ulong_t val;
register int error = 0;
@@ -467,6 +517,19 @@ fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
val = 0;
break;
+ case _PC_CASE_BEHAVIOR:
+ val = _CASE_SENSITIVE;
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1)
+ val |= _CASE_INSENSITIVE;
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1)
+ val &= ~_CASE_SENSITIVE;
+ break;
+
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ val = 0;
+ break;
+
default:
error = EINVAL;
break;
@@ -482,7 +545,13 @@ fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
*/
/* ARGSUSED */
void
-fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
+fs_dispose(
+ struct vnode *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ struct cred *cr,
+ caller_context_t *ct)
{
ASSERT(fl == B_FREE || fl == B_INVAL);
@@ -495,7 +564,13 @@ fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
/* ARGSUSED */
void
-fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
+fs_nodispose(
+ struct vnode *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ struct cred *cr,
+ caller_context_t *ct)
{
cmn_err(CE_PANIC, "fs_nodispose invoked");
}
@@ -505,30 +580,33 @@ fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr)
*/
/* ARGSUSED */
int
-fs_fab_acl(vp, vsecattr, flag, cr)
-vnode_t *vp;
-vsecattr_t *vsecattr;
-int flag;
-cred_t *cr;
+fs_fab_acl(
+ vnode_t *vp,
+ vsecattr_t *vsecattr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
aclent_t *aclentp;
ace_t *acep;
struct vattr vattr;
int error;
+ size_t aclsize;
vsecattr->vsa_aclcnt = 0;
+ vsecattr->vsa_aclentsz = 0;
vsecattr->vsa_aclentp = NULL;
vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
vsecattr->vsa_dfaclentp = NULL;
vattr.va_mask = AT_MODE | AT_UID | AT_GID;
- if (error = VOP_GETATTR(vp, &vattr, 0, cr))
+ if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
return (error);
if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
+ aclsize = 4 * sizeof (aclent_t);
vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */
- vsecattr->vsa_aclentp = kmem_zalloc(4 * sizeof (aclent_t),
- KM_SLEEP);
+ vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
aclentp = vsecattr->vsa_aclentp;
aclentp->a_type = USER_OBJ; /* Owner */
@@ -550,9 +628,10 @@ cred_t *cr;
aclentp->a_perm = (ushort_t)(0007);
aclentp->a_id = (gid_t)-1; /* Really undefined */
} else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
+ aclsize = 6 * sizeof (ace_t);
vsecattr->vsa_aclcnt = 6;
- vsecattr->vsa_aclentp = kmem_zalloc(6 * sizeof (ace_t),
- KM_SLEEP);
+ vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP);
+ vsecattr->vsa_aclentsz = aclsize;
acep = vsecattr->vsa_aclentp;
(void) memcpy(acep, trivial_acl, sizeof (ace_t) * 6);
adjust_ace_pair(acep, (vattr.va_mode & 0700) >> 6);
@@ -568,7 +647,13 @@ cred_t *cr;
*/
/* ARGSUSED4 */
int
-fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+fs_shrlock(
+ struct vnode *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
int error;
@@ -581,13 +666,12 @@ fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
((shr->s_access & F_WRACC) && (flag & FWRITE) == 0))
return (EBADF);
- if (shr->s_deny & F_MANDDNY)
+ if (shr->s_access & (F_RMACC | F_MDACC))
+ return (EINVAL);
+ if (shr->s_deny & (F_MANDDNY | F_RMDNY))
return (EINVAL);
}
if (cmd == F_SHARE_NBMAND) {
- /* must have write permission to deny read access */
- if ((shr->s_deny & F_RDDNY) && (flag & FWRITE) == 0)
- return (EBADF);
/* make sure nbmand is allowed on the file */
if (!vp->v_vfsp ||
!(vp->v_vfsp->vfs_flag & VFS_NBMAND)) {
@@ -633,7 +717,8 @@ fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
/*ARGSUSED1*/
int
-fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
+fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
{
ASSERT(vp != NULL);
return (ENOTSUP);
@@ -641,7 +726,8 @@ fs_vnevent_nosupport(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
/*ARGSUSED1*/
int
-fs_vnevent_support(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname)
+fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
{
ASSERT(vp != NULL);
return (0);
@@ -667,7 +753,7 @@ fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
int isnontrivial;
/* determine the forms of ACLs maintained */
- error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr);
+ error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL);
/* clear bits we don't understand and establish default acl_style */
acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED);
@@ -691,7 +777,7 @@ fs_acl_nontrivial(vnode_t *vp, cred_t *cr)
}
ASSERT(vsecattr.vsa_mask && acl_flavor);
- error = VOP_GETSECATTR(vp, &vsecattr, 0, cr);
+ error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL);
if (error == 0)
break;
@@ -739,3 +825,30 @@ fs_need_estale_retry(int retry_count)
else
return (0);
}
+
+
+static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL;
+
+/*
+ * Routine for anti-virus scanner to call to register its scanning routine.
+ */
+void
+fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int))
+{
+ fs_av_scan = av_scan;
+}
+
+/*
+ * Routine for file systems to call to initiate anti-virus scanning.
+ * Scanning will only be done on REGular files (currently).
+ */
+int
+fs_vscan(vnode_t *vp, cred_t *cr, int async)
+{
+ int ret = 0;
+
+ if (fs_av_scan && vp->v_type == VREG)
+ ret = (*fs_av_scan)(vp, cr, async);
+
+ return (ret);
+}
diff --git a/usr/src/uts/common/fs/fs_subr.h b/usr/src/uts/common/fs/fs_subr.h
index f0b536d0f0..a39e6ec764 100644
--- a/usr/src/uts/common/fs/fs_subr.h
+++ b/usr/src/uts/common/fs/fs_subr.h
@@ -56,32 +56,46 @@ extern int fs_nosys();
extern int fs_inval();
extern int fs_notdir();
extern int fs_nosys_map(struct vnode *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, struct cred *);
+ size_t, uchar_t, uchar_t, uint_t, struct cred *,
+ caller_context_t *);
extern int fs_nosys_addmap(struct vnode *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, struct cred *);
+ size_t, uchar_t, uchar_t, uint_t, struct cred *,
+ caller_context_t *);
extern int fs_nosys_poll(struct vnode *, short, int, short *,
- struct pollhead **);
-
+ struct pollhead **, caller_context_t *);
+extern int fs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+extern int fs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+extern int fs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
extern int fs_sync(struct vfs *, short, cred_t *);
extern int fs_rwlock(vnode_t *, int, caller_context_t *);
extern void fs_rwunlock(vnode_t *, int, caller_context_t *);
-extern int fs_cmp(vnode_t *, vnode_t *);
-extern int fs_seek(vnode_t *, offset_t, offset_t *);
+extern int fs_cmp(vnode_t *, vnode_t *, caller_context_t *);
+extern int fs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
extern int fs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
-extern int fs_setfl(vnode_t *, int, int, cred_t *);
-extern int fs_poll(vnode_t *, short, int, short *, struct pollhead **);
-extern int fs_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+ struct flk_callback *, cred_t *, caller_context_t *);
+extern int fs_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fs_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+extern int fs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
extern void clkset(time_t);
-extern void fs_dispose(struct vnode *, page_t *, int, int, struct cred *);
-extern void fs_nodispose(struct vnode *, page_t *, int, int, struct cred *);
-extern int fs_fab_acl(struct vnode *, vsecattr_t *, int flag, cred_t *);
+extern void fs_dispose(struct vnode *, page_t *, int, int, struct cred *,
+ caller_context_t *);
+extern void fs_nodispose(struct vnode *, page_t *, int, int, struct cred *,
+ caller_context_t *);
+extern int fs_fab_acl(struct vnode *, vsecattr_t *, int flag, cred_t *,
+ caller_context_t *);
extern int fs_shrlock(struct vnode *, int, struct shrlock *, int,
- cred_t *);
-extern int fs_vnevent_nosupport(vnode_t *, vnevent_t, vnode_t *, char *);
-extern int fs_vnevent_support(vnode_t *, vnevent_t, vnode_t *, char *);
+ cred_t *, caller_context_t *);
+extern int fs_vnevent_nosupport(vnode_t *, vnevent_t, vnode_t *dvp,
+ char *fnm, caller_context_t *);
+extern int fs_vnevent_support(vnode_t *, vnevent_t, vnode_t *dvp,
+ char *fnm, caller_context_t *);
extern int fs_acl_nontrivial(struct vnode *vp, struct cred *cr);
extern int fs_need_estale_retry(int);
+extern void fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int));
+extern int fs_vscan(vnode_t *, cred_t *, int);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/fs/fsflush.c b/usr/src/uts/common/fs/fsflush.c
index d7b3ae1071..50b196ac17 100644
--- a/usr/src/uts/common/fs/fsflush.c
+++ b/usr/src/uts/common/fs/fsflush.c
@@ -100,7 +100,7 @@ fsf_stat_t fsf_total; /* total of counts */
ulong_t fsf_cycles; /* number of runs refelected in fsf_total */
/*
- * data used to determine when we can coalese consecutive free pages
+ * data used to determine when we can coalesce consecutive free pages
* into larger pages.
*/
#define MAX_PAGESIZES 32
@@ -131,7 +131,7 @@ fsflush_do_pages()
u_offset_t offset;
uint_t szc;
- page_t *coal_page = NULL; /* 1st page in group to coalese */
+ page_t *coal_page = NULL; /* 1st page in group to coalesce */
uint_t coal_szc = 0; /* size code, coal_page->p_szc */
uint_t coal_cnt = 0; /* count of pages seen */
@@ -288,7 +288,7 @@ fsflush_do_pages()
page_unlock(pp);
(void) VOP_PUTPAGE(vp, offset, PAGESIZE, B_ASYNC,
- kcred);
+ kcred, NULL);
VN_RELE(vp);
} else {
diff --git a/usr/src/uts/common/fs/gfs.c b/usr/src/uts/common/fs/gfs.c
index c3e05aeced..24f2ad2a7a 100644
--- a/usr/src/uts/common/fs/gfs.c
+++ b/usr/src/uts/common/fs/gfs.c
@@ -62,7 +62,7 @@
*
* These routines are designed to play a support role for existing
* pseudo-filesystems (such as procfs). They simplify common tasks,
- * without enforcing the filesystem to hand over management to GFS. The
+ * without forcing the filesystem to hand over management to GFS. The
* routines covered are:
*
* gfs_readdir_init()
@@ -538,7 +538,7 @@ gfs_file_inactive(vnode_t *vp)
gfs_dir_t *dp = NULL;
void *data;
- if (fp->gfs_parent == NULL)
+ if (fp->gfs_parent == NULL || (vp->v_flag & V_XATTRDIR))
goto found;
dp = fp->gfs_parent->v_data;
@@ -564,6 +564,9 @@ gfs_file_inactive(vnode_t *vp)
ge = NULL;
found:
+ if (vp->v_flag & V_XATTRDIR) {
+ mutex_enter(&fp->gfs_parent->v_lock);
+ }
mutex_enter(&vp->v_lock);
if (vp->v_count == 1) {
/*
@@ -577,13 +580,19 @@ found:
*/
ge->gfse_vnode = NULL;
}
+ if (vp->v_flag & V_XATTRDIR) {
+ fp->gfs_parent->v_xattrdir = NULL;
+ mutex_exit(&fp->gfs_parent->v_lock);
+ }
mutex_exit(&vp->v_lock);
/*
* Free vnode and release parent
*/
if (fp->gfs_parent) {
- gfs_dir_unlock(dp);
+ if (dp) {
+ gfs_dir_unlock(dp);
+ }
VN_RELE(fp->gfs_parent);
} else {
ASSERT(vp->v_vfsp != NULL);
@@ -594,6 +603,9 @@ found:
vp->v_count--;
data = NULL;
mutex_exit(&vp->v_lock);
+ if (vp->v_flag & V_XATTRDIR) {
+ mutex_exit(&fp->gfs_parent->v_lock);
+ }
if (dp)
gfs_dir_unlock(dp);
}
@@ -637,16 +649,17 @@ gfs_dir_inactive(vnode_t *vp)
* If no static entry is found, we invoke the lookup callback, if any. The
* arguments to this callback are:
*
- * int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp);
+ * int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp, cred_t *cr);
*
* pvp - parent vnode
* nm - name of entry
* vpp - pointer to resulting vnode
+ * cr - pointer to cred
*
* Returns 0 on success, non-zero on error.
*/
int
-gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp)
+gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cred_t *cr)
{
int i;
gfs_dirent_t *ge;
@@ -732,14 +745,22 @@ gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp)
* directory.
*/
gfs_dir_unlock(dp);
- ret = dp->gfsd_lookup(dvp, nm, &vp, &ino);
+ ret = dp->gfsd_lookup(dvp, nm, &vp, &ino, cr);
gfs_dir_lock(dp);
if (ret != 0)
goto out;
- fp = (gfs_file_t *)vp->v_data;
- fp->gfs_index = -1;
- fp->gfs_ino = ino;
+ /*
+ * The lookup_cb might be returning a non-GFS vnode.
+ * Currently this is true for extended attributes,
+ * where we're returning a vnode with v_data from an
+ * underlying fs.
+ */
+ if ((dvp->v_flag & V_XATTRDIR) == 0) {
+ fp = (gfs_file_t *)vp->v_data;
+ fp->gfs_index = -1;
+ fp->gfs_ino = ino;
+ }
} else {
/*
* No static entry found, and there is no lookup callback, so
@@ -803,21 +824,31 @@ out:
* Return 0 on success, or error on failure.
*/
int
-gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data)
+gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data, cred_t *cr,
+ caller_context_t *ct)
{
gfs_readdir_state_t gstate;
int error, eof = 0;
ino64_t ino, pino;
offset_t off, next;
gfs_dir_t *dp = dvp->v_data;
+ vnode_t *parent;
ino = dp->gfsd_file.gfs_ino;
+ parent = dp->gfsd_file.gfs_parent;
- if (dp->gfsd_file.gfs_parent == NULL)
+ if (parent == NULL)
pino = ino; /* root of filesystem */
- else
- pino = ((gfs_file_t *)
- (dp->gfsd_file.gfs_parent->v_data))->gfs_ino;
+ else if (dvp->v_flag & V_XATTRDIR) {
+ vattr_t va;
+
+ va.va_mask = AT_NODEID;
+ error = VOP_GETATTR(parent, &va, 0, cr, ct);
+ if (error)
+ return (error);
+ pino = va.va_nodeid;
+ } else
+ pino = ((gfs_file_t *)(parent->v_data))->gfs_ino;
if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop,
pino, ino)) != 0)
@@ -870,9 +901,10 @@ gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, void *data)
/* ARGSUSED */
int
gfs_vop_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
- return (gfs_dir_lookup(dvp, nm, vpp));
+ return (gfs_dir_lookup(dvp, nm, vpp, cr));
}
/*
@@ -883,9 +915,10 @@ gfs_vop_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
*/
/* ARGSUSED */
int
-gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
- return (gfs_dir_readdir(vp, uiop, eofp, NULL));
+ return (gfs_dir_readdir(vp, uiop, eofp, NULL, cr, ct));
}
@@ -901,7 +934,8 @@ gfs_vop_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
/* ARGSUSED */
int
gfs_vop_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cred)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cred,
+ caller_context_t *ct)
{
int rv;
ssize_t resid = len;
@@ -972,7 +1006,7 @@ gfs_vop_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
*/
/* ARGSUSED */
void
-gfs_vop_inactive(vnode_t *vp, cred_t *cr)
+gfs_vop_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
gfs_file_t *fp = vp->v_data;
void *data;
diff --git a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
index 132dc9f544..9c25cc5249 100644
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
@@ -407,7 +407,7 @@ hsfs_unmount(
mutex_exit(&hs_mounttab_lock);
hsfs_fini_kstats(fsp);
- (void) VOP_CLOSE(fsp->hsfs_devvp, FREAD, 1, (offset_t)0, cr);
+ (void) VOP_CLOSE(fsp->hsfs_devvp, FREAD, 1, (offset_t)0, cr, NULL);
VN_RELE(fsp->hsfs_devvp);
/* free path table space */
if (fsp->hsfs_ptbl != NULL)
@@ -626,7 +626,7 @@ hs_mountfs(
/*
* Open the target device (file) for read only.
*/
- if (error = VOP_OPEN(&devvp, FREAD, cr)) {
+ if (error = VOP_OPEN(&devvp, FREAD, cr, NULL)) {
VN_RELE(devvp);
return (error);
}
@@ -641,7 +641,7 @@ hs_mountfs(
}
vap.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(devvp, &vap, ATTR_COMM, cr)) != 0) {
+ if ((error = VOP_GETATTR(devvp, &vap, ATTR_COMM, cr, NULL)) != 0) {
cmn_err(CE_NOTE, "Cannot get attributes of the CD-ROM driver");
goto cleanup;
}
@@ -937,7 +937,7 @@ hs_mountfs(
return (0);
cleanup:
- (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr);
+ (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr, NULL);
VN_RELE(devvp);
if (fsp)
kmem_free(fsp, sizeof (*fsp));
@@ -1365,14 +1365,14 @@ hs_getmdev(struct vfs *vfsp, char *fspec, int flags, dev_t *pdev, mode_t *mode,
/*
* Can we read from the device?
*/
- if ((error = VOP_ACCESS(vp, VREAD, 0, cr)) != 0 ||
+ if ((error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, vp, FREAD)) != 0) {
VN_RELE(vp);
return (error);
}
vap.va_mask = AT_MODE; /* get protection mode */
- (void) VOP_GETATTR(vp, &vap, 0, CRED());
+ (void) VOP_GETATTR(vp, &vap, 0, CRED(), NULL);
*mode = vap.va_mode;
dev = *pdev = vp->v_rdev;
@@ -1507,7 +1507,7 @@ hsfs_mountroot(struct vfs *vfsp, enum whymountroot why)
* multisession cd's.
*
* desc_sec is the same for high-sierra and iso 9660 formats, why
- * there are two differnt #defines used in the code for this is
+ * there are two different #defines used in the code for this is
* beyond me. These are standards, cast in concrete, right?
* To be general, however, this function supports passing in different
* values.
diff --git a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c
index 29645bfe3e..bbd8afdd5a 100644
--- a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c
@@ -157,7 +157,10 @@ int hsched_invoke_strategy(struct hsfs *fsp);
/* ARGSUSED */
static int
-hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred)
+hsfs_fsync(vnode_t *cp,
+ int syncflag,
+ cred_t *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -165,7 +168,10 @@ hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred)
/*ARGSUSED*/
static int
-hsfs_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
+hsfs_read(struct vnode *vp,
+ struct uio *uiop,
+ int ioflag,
+ struct cred *cred,
struct caller_context *ct)
{
caddr_t base;
@@ -299,7 +305,8 @@ hsfs_getattr(
struct vnode *vp,
struct vattr *vap,
int flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct hsnode *hp;
struct vfs *vfsp;
@@ -342,7 +349,10 @@ hsfs_getattr(
/*ARGSUSED*/
static int
-hsfs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
+hsfs_readlink(struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct hsnode *hp;
@@ -361,7 +371,9 @@ hsfs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
/*ARGSUSED*/
static void
-hsfs_inactive(struct vnode *vp, struct cred *cred)
+hsfs_inactive(struct vnode *vp,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct hsnode *hp;
struct hsfs *fsp;
@@ -427,7 +439,10 @@ hsfs_lookup(
struct pathname *pnp,
int flags,
struct vnode *rdir,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
int error;
int namelen = (int)strlen(nm);
@@ -456,10 +471,12 @@ hsfs_lookup(
/*ARGSUSED*/
static int
hsfs_readdir(
- struct vnode *vp,
- struct uio *uiop,
- struct cred *cred,
- int *eofp)
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct hsnode *dhp;
struct hsfs *fsp;
@@ -634,8 +651,9 @@ done:
return (error);
}
+/*ARGSUSED2*/
static int
-hsfs_fid(struct vnode *vp, struct fid *fidp)
+hsfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct hsnode *hp;
struct hsfid *fid;
@@ -658,7 +676,10 @@ hsfs_fid(struct vnode *vp, struct fid *fidp)
/*ARGSUSED*/
static int
-hsfs_open(struct vnode **vpp, int flag, struct cred *cred)
+hsfs_open(struct vnode **vpp,
+ int flag,
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -670,7 +691,8 @@ hsfs_close(
int flag,
int count,
offset_t offset,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
@@ -679,7 +701,11 @@ hsfs_close(
/*ARGSUSED2*/
static int
-hsfs_access(struct vnode *vp, int mode, int flags, cred_t *cred)
+hsfs_access(struct vnode *vp,
+ int mode,
+ int flags,
+ cred_t *cred,
+ caller_context_t *ct)
{
return (hs_access(vp, (mode_t)mode, cred));
}
@@ -1531,6 +1557,7 @@ again:
return (err);
}
+/*ARGSUSED*/
static int
hsfs_getpage(
struct vnode *vp,
@@ -1542,7 +1569,8 @@ hsfs_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
int err;
uint_t filsiz;
@@ -1671,11 +1699,12 @@ hsfs_putapage(
/*ARGSUSED*/
static int
hsfs_putpage(
- struct vnode *vp,
- offset_t off,
- size_t len,
- int flags,
- struct cred *cr)
+ struct vnode *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
int error = 0;
@@ -1755,7 +1784,8 @@ hsfs_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -1821,7 +1851,8 @@ hsfs_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct hsnode *hp;
@@ -1846,7 +1877,8 @@ hsfs_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct hsnode *hp;
@@ -1863,7 +1895,11 @@ hsfs_delmap(
/* ARGSUSED */
static int
-hsfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+hsfs_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -1877,7 +1913,8 @@ hsfs_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
struct hsnode *hp = VTOH(vp);
@@ -1892,7 +1929,7 @@ hsfs_frlock(
if (hp->hs_mapcnt > 0 && MANDLOCK(vp, hp->hs_dirent.mode))
return (EAGAIN);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
static int
@@ -2360,7 +2397,11 @@ hsched_enqueue_io(struct hsfs *fsp, struct hio *hsio, int ra)
/* ARGSUSED */
static int
-hsfs_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
+hsfs_pathconf(struct vnode *vp,
+ int cmd,
+ ulong_t *valp,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct hsfs *fsp;
@@ -2378,7 +2419,7 @@ hsfs_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
break;
default:
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
return (error);
diff --git a/usr/src/uts/common/fs/lofs/lofs_vfsops.c b/usr/src/uts/common/fs/lofs/lofs_vfsops.c
index 8616e90cd6..8d654bcaeb 100644
--- a/usr/src/uts/common/fs/lofs/lofs_vfsops.c
+++ b/usr/src/uts/common/fs/lofs/lofs_vfsops.c
@@ -287,7 +287,7 @@ lo_mount(struct vfs *vfsp,
* intended filesystem, so we loopback mount the intended
* filesystem instead of the AUTOFS filesystem.
*/
- (void) VOP_ACCESS(realrootvp, 0, 0, cr);
+ (void) VOP_ACCESS(realrootvp, 0, 0, cr, NULL);
/*
* We're interested in the top most filesystem.
diff --git a/usr/src/uts/common/fs/lofs/lofs_vnops.c b/usr/src/uts/common/fs/lofs/lofs_vnops.c
index 85138187c1..dbe2c7a8b9 100644
--- a/usr/src/uts/common/fs/lofs/lofs_vnops.c
+++ b/usr/src/uts/common/fs/lofs/lofs_vnops.c
@@ -48,7 +48,7 @@
*/
static int
-lo_open(vnode_t **vpp, int flag, struct cred *cr)
+lo_open(vnode_t **vpp, int flag, struct cred *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
vnode_t *rvp;
@@ -67,7 +67,7 @@ lo_open(vnode_t **vpp, int flag, struct cred *cr)
* decide to release it.
*/
VN_HOLD(vp);
- error = VOP_OPEN(&rvp, flag, cr);
+ error = VOP_OPEN(&rvp, flag, cr, ct);
if (!error && rvp != vp) {
/*
@@ -106,13 +106,14 @@ lo_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_CLOSE(vp, flag, count, offset, cr));
+ return (VOP_CLOSE(vp, flag, count, offset, cr, ct));
}
static int
@@ -144,20 +145,21 @@ lo_ioctl(
intptr_t arg,
int flag,
struct cred *cr,
- int *rvalp)
+ int *rvalp,
+ caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_ioctl vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp));
+ return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp, ct));
}
static int
-lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_SETFL(vp, oflags, nflags, cr));
+ return (VOP_SETFL(vp, oflags, nflags, cr, ct));
}
static int
@@ -165,14 +167,15 @@ lo_getattr(
vnode_t *vp,
struct vattr *vap,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
int error;
#ifdef LODEBUG
lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp));
#endif
- if (error = VOP_GETATTR(realvp(vp), vap, flags, cr))
+ if (error = VOP_GETATTR(realvp(vp), vap, flags, cr, ct))
return (error);
return (0);
@@ -194,7 +197,12 @@ lo_setattr(
}
static int
-lo_access(vnode_t *vp, int mode, int flags, struct cred *cr)
+lo_access(
+ vnode_t *vp,
+ int mode,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp));
@@ -204,22 +212,22 @@ lo_access(vnode_t *vp, int mode, int flags, struct cred *cr)
return (EROFS);
}
vp = realvp(vp);
- return (VOP_ACCESS(vp, mode, flags, cr));
+ return (VOP_ACCESS(vp, mode, flags, cr, ct));
}
static int
-lo_fsync(vnode_t *vp, int syncflag, struct cred *cr)
+lo_fsync(vnode_t *vp, int syncflag, struct cred *cr, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_FSYNC(vp, syncflag, cr));
+ return (VOP_FSYNC(vp, syncflag, cr, ct));
}
/*ARGSUSED*/
static void
-lo_inactive(vnode_t *vp, struct cred *cr)
+lo_inactive(vnode_t *vp, struct cred *cr, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp));
@@ -229,13 +237,13 @@ lo_inactive(vnode_t *vp, struct cred *cr)
/* ARGSUSED */
static int
-lo_fid(vnode_t *vp, struct fid *fidp)
+lo_fid(vnode_t *vp, struct fid *fidp, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_FID(vp, fidp));
+ return (VOP_FID(vp, fidp, ct));
}
/*
@@ -288,7 +296,10 @@ lo_lookup(
struct pathname *pnp,
int flags,
vnode_t *rdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
vnode_t *vp = NULL, *tvp = NULL, *nonlovp;
int error, is_indirectloop;
@@ -327,7 +338,8 @@ lo_lookup(
/*
* Do the normal lookup
*/
- if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr)) {
+ if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr,
+ ct, direntflags, realpnp)) {
vp = NULL;
goto out;
}
@@ -657,7 +669,9 @@ lo_create(
int mode,
vnode_t **vpp,
struct cred *cr,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
vnode_t *vp = NULL;
@@ -670,7 +684,8 @@ lo_create(
vp = realvp(*vpp);
}
- error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag);
+ error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag,
+ ct, vsecp);
if (!error) {
*vpp = makelonode(vp, vtoli(dvp->v_vfsp), 0);
if (IS_DEVVP(*vpp)) {
@@ -688,17 +703,28 @@ lo_create(
}
static int
-lo_remove(vnode_t *dvp, char *nm, struct cred *cr)
+lo_remove(
+ vnode_t *dvp,
+ char *nm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
#ifdef LODEBUG
lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp));
#endif
dvp = realvp(dvp);
- return (VOP_REMOVE(dvp, nm, cr));
+ return (VOP_REMOVE(dvp, nm, cr, ct, flags));
}
static int
-lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
+lo_link(
+ vnode_t *tdvp,
+ vnode_t *vp,
+ char *tnm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *realvp;
@@ -737,7 +763,7 @@ lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
*
* We use VOP_REALVP here to continue the search.
*/
- if (VOP_REALVP(vp, &realvp) == 0)
+ if (VOP_REALVP(vp, &realvp, ct) == 0)
vp = realvp;
while (vn_matchops(tdvp, lo_vnodeops)) {
@@ -745,7 +771,7 @@ lo_link(vnode_t *tdvp, vnode_t *vp, char *tnm, struct cred *cr)
}
if (vp->v_vfsp != tdvp->v_vfsp)
return (EXDEV);
- return (VOP_LINK(tdvp, vp, tnm, cr));
+ return (VOP_LINK(tdvp, vp, tnm, cr, ct, flags));
}
static int
@@ -754,7 +780,9 @@ lo_rename(
char *onm,
vnode_t *ndvp,
char *nnm,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *tnvp;
@@ -789,7 +817,13 @@ lo_rename(
*/
if (vn_matchops(ndvp, lo_vnodeops)) /* Not our problem. */
goto rename;
- if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr) != 0)
+
+ /*
+ * XXXci - Once case-insensitive behavior is implemented, it should
+ * be added here.
+ */
+ if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr,
+ ct, NULL, NULL) != 0)
goto rename;
if (tnvp->v_type != VDIR) {
VN_RELE(tnvp);
@@ -822,7 +856,7 @@ rename:
if (odvp->v_vfsp != ndvp->v_vfsp)
return (EXDEV);
}
- return (VOP_RENAME(odvp, onm, ndvp, nnm, cr));
+ return (VOP_RENAME(odvp, onm, ndvp, nnm, cr, ct, flags));
}
static int
@@ -831,21 +865,24 @@ lo_mkdir(
char *nm,
struct vattr *va,
vnode_t **vpp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
int error;
#ifdef LODEBUG
lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp));
#endif
- error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr);
+ error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr, ct, flags, vsecp);
if (!error)
*vpp = makelonode(*vpp, vtoli(dvp->v_vfsp), 0);
return (error);
}
static int
-lo_realvp(vnode_t *vp, vnode_t **vpp)
+lo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
#ifdef LODEBUG
lo_dprint(4, "lo_realvp %p\n", vp);
@@ -853,7 +890,7 @@ lo_realvp(vnode_t *vp, vnode_t **vpp)
while (vn_matchops(vp, lo_vnodeops))
vp = realvp(vp);
- if (VOP_REALVP(vp, vpp) != 0)
+ if (VOP_REALVP(vp, vpp, ct) != 0)
*vpp = vp;
return (0);
}
@@ -863,7 +900,9 @@ lo_rmdir(
vnode_t *dvp,
char *nm,
vnode_t *cdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
vnode_t *rvp = cdir;
@@ -872,9 +911,9 @@ lo_rmdir(
#endif
/* if cdir is lofs vnode ptr get its real vnode ptr */
if (vn_matchops(dvp, vn_getops(rvp)))
- (void) lo_realvp(cdir, &rvp);
+ (void) lo_realvp(cdir, &rvp, ct);
dvp = realvp(dvp);
- return (VOP_RMDIR(dvp, nm, rvp, cr));
+ return (VOP_RMDIR(dvp, nm, rvp, cr, ct, flags));
}
static int
@@ -883,30 +922,42 @@ lo_symlink(
char *lnm,
struct vattr *tva,
char *tnm,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
#ifdef LODEBUG
lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp));
#endif
dvp = realvp(dvp);
- return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr));
+ return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr, ct, flags));
}
static int
-lo_readlink(vnode_t *vp, struct uio *uiop, struct cred *cr)
+lo_readlink(
+ vnode_t *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_READLINK(vp, uiop, cr));
+ return (VOP_READLINK(vp, uiop, cr, ct));
}
static int
-lo_readdir(vnode_t *vp, struct uio *uiop, struct cred *cr, int *eofp)
+lo_readdir(
+ vnode_t *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
#ifdef LODEBUG
lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp));
#endif
vp = realvp(vp);
- return (VOP_READDIR(vp, uiop, cr, eofp));
+ return (VOP_READDIR(vp, uiop, cr, eofp, ct, flags));
}
static int
@@ -924,20 +975,20 @@ lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
}
static int
-lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_SEEK(vp, ooff, noffp));
+ return (VOP_SEEK(vp, ooff, noffp, ct));
}
static int
-lo_cmp(vnode_t *vp1, vnode_t *vp2)
+lo_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
while (vn_matchops(vp1, lo_vnodeops))
vp1 = realvp(vp1);
while (vn_matchops(vp2, lo_vnodeops))
vp2 = realvp(vp2);
- return (VOP_CMP(vp1, vp2));
+ return (VOP_CMP(vp1, vp2, ct));
}
static int
@@ -948,10 +999,11 @@ lo_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
static int
@@ -979,17 +1031,25 @@ lo_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr));
+ return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr,
+ ct));
}
static int
-lo_putpage(vnode_t *vp, offset_t off, size_t len, int flags, struct cred *cr)
+lo_putpage(
+ vnode_t *vp,
+ offset_t off,
+ size_t len,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_PUTPAGE(vp, off, len, flags, cr));
+ return (VOP_PUTPAGE(vp, off, len, flags, cr, ct));
}
static int
@@ -1002,10 +1062,11 @@ lo_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr));
+ return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr, ct));
}
static int
@@ -1018,10 +1079,12 @@ lo_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
+ return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
+ ct));
}
static int
@@ -1034,10 +1097,12 @@ lo_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr));
+ return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
+ ct));
}
static int
@@ -1046,24 +1111,30 @@ lo_poll(
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_POLL(vp, events, anyyet, reventsp, phpp));
+ return (VOP_POLL(vp, events, anyyet, reventsp, phpp, ct));
}
static int
-lo_dump(vnode_t *vp, caddr_t addr, int bn, int count)
+lo_dump(vnode_t *vp, caddr_t addr, int bn, int count, caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_DUMP(vp, addr, bn, count));
+ return (VOP_DUMP(vp, addr, bn, count, ct));
}
static int
-lo_pathconf(vnode_t *vp, int cmd, ulong_t *valp, struct cred *cr)
+lo_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_PATHCONF(vp, cmd, valp, cr));
+ return (VOP_PATHCONF(vp, cmd, valp, cr, ct));
}
static int
@@ -1073,41 +1144,64 @@ lo_pageio(
u_offset_t io_off,
size_t io_len,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr));
+ return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct));
}
static void
-lo_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+lo_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
if (vp != NULL && !VN_ISKAS(vp))
- VOP_DISPOSE(vp, pp, fl, dn, cr);
+ VOP_DISPOSE(vp, pp, fl, dn, cr, ct);
}
static int
-lo_setsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
+lo_setsecattr(
+ vnode_t *vp,
+ vsecattr_t *secattr,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
if (vn_is_readonly(vp))
return (EROFS);
vp = realvp(vp);
- return (VOP_SETSECATTR(vp, secattr, flags, cr));
+ return (VOP_SETSECATTR(vp, secattr, flags, cr, ct));
}
static int
-lo_getsecattr(vnode_t *vp, vsecattr_t *secattr, int flags, struct cred *cr)
+lo_getsecattr(
+ vnode_t *vp,
+ vsecattr_t *secattr,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_GETSECATTR(vp, secattr, flags, cr));
+ return (VOP_GETSECATTR(vp, secattr, flags, cr, ct));
}
static int
-lo_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+lo_shrlock(
+ vnode_t *vp,
+ int cmd,
+ struct shrlock *shr,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
vp = realvp(vp);
- return (VOP_SHRLOCK(vp, cmd, shr, flag, cr));
+ return (VOP_SHRLOCK(vp, cmd, shr, flag, cr, ct));
}
/*
diff --git a/usr/src/uts/common/fs/lookup.c b/usr/src/uts/common/fs/lookup.c
index 8ef37c4313..d30a358283 100644
--- a/usr/src/uts/common/fs/lookup.c
+++ b/usr/src/uts/common/fs/lookup.c
@@ -209,6 +209,8 @@ lookuppnvp(
int error;
int nlink;
int lookup_flags;
+ struct pathname presrvd; /* case preserved name */
+ struct pathname *pp = NULL;
vnode_t *startvp;
vnode_t *zonevp = curproc->p_zone->zone_rootvp; /* zone root */
int must_be_directory = 0;
@@ -219,7 +221,14 @@ lookuppnvp(
cvp = NULL;
if (rpnp)
rpnp->pn_pathlen = 0;
+
lookup_flags = dirvpp ? LOOKUP_DIR : 0;
+ if (flags & FIGNORECASE) {
+ lookup_flags |= FIGNORECASE;
+ pn_alloc(&presrvd);
+ pp = &presrvd;
+ }
+
#ifdef C2_AUDIT
if (audit_active)
audit_anchorpath(pnp, vp == rootvp);
@@ -319,6 +328,8 @@ checkforroot:
(cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
vfs_unlock(vfsp);
VN_RELE(cvp);
+ if (pp)
+ pn_free(pp);
return (EIO);
}
VN_HOLD(vp);
@@ -346,14 +357,14 @@ checkforroot:
* be found.
*/
if ((flags & LOOKUP_CHECKREAD) &&
- (error = VOP_ACCESS(vp, VREAD, 0, cr)) != 0)
+ (error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0)
goto bad;
/*
* Perform a lookup in the current directory.
*/
error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags,
- rootvp, cr);
+ rootvp, cr, NULL, NULL, pp);
/*
* Retry with kcred - If crossing mount points & error is EACCES.
@@ -371,7 +382,7 @@ checkforroot:
*/
if ((error == EACCES) && retry_with_kcred)
error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags,
- rootvp, zone_kcred());
+ rootvp, zone_kcred(), NULL, NULL, pp);
cvp = tvp;
if (error) {
@@ -402,6 +413,8 @@ checkforroot:
*compvpp = NULL;
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (0);
}
@@ -521,9 +534,19 @@ checkforroot:
if (rpnp->pn_pathlen != 0 &&
rpnp->pn_path[rpnp->pn_pathlen-1] != '/')
rpnp->pn_path[rpnp->pn_pathlen++] = '/';
- error = copystr(component,
- rpnp->pn_path + rpnp->pn_pathlen,
- rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
+ if (flags & FIGNORECASE) {
+ /*
+ * Return the case-preserved name
+ * within the resolved path.
+ */
+ error = copystr(pp->pn_path,
+ rpnp->pn_path + rpnp->pn_pathlen,
+ rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
+ } else {
+ error = copystr(component,
+ rpnp->pn_path + rpnp->pn_pathlen,
+ rpnp->pn_bufsize - rpnp->pn_pathlen, &len);
+ }
if (error) /* copystr() returns ENAMETOOLONG */
goto bad;
rpnp->pn_pathlen += (len - 1);
@@ -560,6 +583,8 @@ checkforroot:
VN_RELE(cvp);
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (EINVAL);
}
#ifdef C2_AUDIT
@@ -592,6 +617,8 @@ checkforroot:
VN_RELE(cvp);
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (0);
}
@@ -649,6 +676,8 @@ bad_noaudit:
VN_RELE(vp);
if (rootvp != rootdir)
VN_RELE(rootvp);
+ if (pp)
+ pn_free(pp);
return (error);
}
@@ -791,15 +820,15 @@ vnode_match(vnode_t *v1, vnode_t *v2, cred_t *cr)
* are currently in '/proc/self/fd', then '/proc/self/cwd' will compare
* as the same vnode.
*/
- if (VOP_GETATTR(v1, &v1attr, 0, cr) != 0 ||
- VOP_GETATTR(v2, &v2attr, 0, cr) != 0 ||
+ if (VOP_GETATTR(v1, &v1attr, 0, cr, NULL) != 0 ||
+ VOP_GETATTR(v2, &v2attr, 0, cr, NULL) != 0 ||
v1attr.va_type == VLNK || v2attr.va_type == VLNK)
return (0);
v1attr.va_mask = v2attr.va_mask = AT_TYPE | AT_FSID | AT_NODEID;
- if (VOP_GETATTR(v1, &v1attr, ATTR_REAL, cr) != 0 ||
- VOP_GETATTR(v2, &v2attr, ATTR_REAL, cr) != 0)
+ if (VOP_GETATTR(v1, &v1attr, ATTR_REAL, cr, NULL) != 0 ||
+ VOP_GETATTR(v2, &v2attr, ATTR_REAL, cr, NULL) != 0)
return (0);
return (v1attr.va_fsid == v2attr.va_fsid &&
@@ -839,7 +868,7 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
uio.uio_extflg = UIO_COPY_CACHED;
uio.uio_loffset = 0;
- if ((error = VOP_ACCESS(dvp, VREAD, 0, cr)) != 0)
+ if ((error = VOP_ACCESS(dvp, VREAD, 0, cr, NULL)) != 0)
return (error);
while (!eof) {
@@ -848,7 +877,7 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
iov.iov_len = dlen;
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dvp, &uio, cr, &eof);
+ error = VOP_READDIR(dvp, &uio, cr, &eof, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
dbuflen = dlen - uio.uio_resid;
@@ -869,7 +898,7 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
}
error = VOP_LOOKUP(dvp, dp->d_name, &cmpvp, &pnp, 0,
- vrootp, cr);
+ vrootp, cr, NULL, NULL, NULL);
/*
* We only want to bail out if there was an error other
@@ -900,7 +929,8 @@ dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf,
* rare conditions (races and the special .zfs directory).
*/
if (error == 0) {
- error = VOP_LOOKUP(dvp, ".zfs", &cmpvp, &pnp, 0, vrootp, cr);
+ error = VOP_LOOKUP(dvp, ".zfs", &cmpvp, &pnp, 0, vrootp, cr,
+ NULL, NULL, NULL);
if (error == 0) {
if (vnode_match(tvp, cmpvp, cr)) {
(void) strcpy(dp->d_name, ".zfs");
@@ -955,7 +985,8 @@ localpath(char *path, struct vnode *vrootp, cred_t *cr)
if (vn_ismntpt(vp) && traverse(&vp) != 0)
break;
- if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr) != 0)
+ if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr,
+ NULL, NULL, NULL) != 0)
break;
VN_RELE(vp);
@@ -1087,8 +1118,8 @@ dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr)
*/
if (vp->v_flag & VROOT)
vp = vn_under(vp);
- if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr))
- != 0)
+ if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr,
+ NULL, NULL, NULL)) != 0)
goto out;
/*
@@ -1210,10 +1241,10 @@ vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
* lofs. The only difference between procfs and lofs is that opening
* the file will return the underling vnode in the case of procfs.
*/
- if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp) == 0 &&
+ if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp, NULL) == 0 &&
realvp != vp) {
VN_HOLD(vp);
- if (VOP_OPEN(&vp, FREAD, cr) == 0)
+ if (VOP_OPEN(&vp, FREAD, cr, NULL) == 0)
doclose = 1;
else
VN_RELE(vp);
@@ -1314,7 +1345,7 @@ vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen,
pn_free(&rpn);
VN_RELE(vrootp);
if (doclose) {
- (void) VOP_CLOSE(vp, FREAD, 1, 0, cr);
+ (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
VN_RELE(vp);
}
return (0);
@@ -1356,7 +1387,7 @@ notcached:
VN_RELE(vrootp);
if (doclose) {
- (void) VOP_CLOSE(vp, FREAD, 1, 0, cr);
+ (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL);
VN_RELE(vp);
}
@@ -1394,7 +1425,7 @@ dogetcwd(char *buf, size_t buflen)
/*
* Make sure we have permission to access the current directory.
*/
- if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED())) != 0) {
+ if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) != 0) {
if (cwd != NULL)
refstr_rele(cwd);
VN_RELE(vp);
diff --git a/usr/src/uts/common/fs/mntfs/mntvnops.c b/usr/src/uts/common/fs/mntfs/mntvnops.c
index 9083d5c5b2..9e519167cf 100644
--- a/usr/src/uts/common/fs/mntfs/mntvnops.c
+++ b/usr/src/uts/common/fs/mntfs/mntvnops.c
@@ -670,7 +670,7 @@ mntfs_getmntopts(struct vfs *vfsp, char **bufp, size_t *lenp)
/* ARGSUSED */
static int
-mntopen(vnode_t **vpp, int flag, cred_t *cr)
+mntopen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
mntnode_t *nmnp;
@@ -694,7 +694,8 @@ mntopen(vnode_t **vpp, int flag, cred_t *cr)
/* ARGSUSED */
static int
-mntclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+mntclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
@@ -767,7 +768,8 @@ mntread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, caller_context_t *ct)
static int
-mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
int error;
@@ -786,7 +788,7 @@ mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/*
* Attributes are same as underlying file with modifications
*/
- if (error = VOP_GETATTR(rvp, vap, flags, cr))
+ if (error = VOP_GETATTR(rvp, vap, flags, cr, ct))
return (error);
/*
@@ -830,7 +832,8 @@ mntgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
static int
-mntaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
+mntaccess(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
@@ -840,7 +843,7 @@ mntaccess(vnode_t *vp, int mode, int flags, cred_t *cr)
/*
* Do access check on the underlying directory vnode.
*/
- return (VOP_ACCESS(mnp->mnt_mountvp, mode, flags, cr));
+ return (VOP_ACCESS(mnp->mnt_mountvp, mode, flags, cr, ct));
}
@@ -882,14 +885,14 @@ mntfreenode(mntnode_t *mnp)
/* ARGSUSED */
static int
-mntfsync(vnode_t *vp, int syncflag, cred_t *cr)
+mntfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static void
-mntinactive(vnode_t *vp, cred_t *cr)
+mntinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
@@ -898,7 +901,8 @@ mntinactive(vnode_t *vp, cred_t *cr)
/* ARGSUSED */
static int
-mntseek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+mntseek(vnode_t *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
if (*noffp == 0)
VTOM(vp)->mnt_offset = 0;
@@ -913,7 +917,8 @@ mntseek(vnode_t *vp, offset_t ooff, offset_t *noffp)
*/
/* ARGSUSED */
static int
-mntpoll(vnode_t *vp, short ev, int any, short *revp, pollhead_t **phpp)
+mntpoll(vnode_t *vp, short ev, int any, short *revp, pollhead_t **phpp,
+ caller_context_t *ct)
{
mntnode_t *mnp = VTOM(vp);
mntsnap_t *snap = &mnp->mnt_read;
@@ -951,7 +956,7 @@ mntpoll(vnode_t *vp, short ev, int any, short *revp, pollhead_t **phpp)
/* ARGSUSED */
static int
mntioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+ cred_t *cr, int *rvalp, caller_context_t *ct)
{
uint_t *up = (uint_t *)arg;
mntnode_t *mnp = VTOM(vp);
diff --git a/usr/src/uts/common/fs/namefs/namevfs.c b/usr/src/uts/common/fs/namefs/namevfs.c
index 88bafaa135..a6a4e083a6 100644
--- a/usr/src/uts/common/fs/namefs/namevfs.c
+++ b/usr/src/uts/common/fs/namefs/namevfs.c
@@ -357,7 +357,7 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
*/
rvp = NULLVP;
if (vn_matchops(mvp, spec_getvnodeops()) &&
- VOP_REALVP(mvp, &rvp) == 0 && rvp &&
+ VOP_REALVP(mvp, &rvp, NULL) == 0 && rvp &&
vn_matchops(rvp, devpts_getvnodeops())) {
releasef(namefdp.fd);
return (ENOTSUP);
@@ -397,11 +397,11 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp)
mutex_init(&nodep->nm_lock, NULL, MUTEX_DEFAULT, NULL);
vattrp = &nodep->nm_vattr;
vattrp->va_mask = AT_ALL;
- if (error = VOP_GETATTR(mvp, vattrp, 0, crp))
+ if (error = VOP_GETATTR(mvp, vattrp, 0, crp, NULL))
goto out;
filevattr.va_mask = AT_ALL;
- if (error = VOP_GETATTR(filevp, &filevattr, 0, crp))
+ if (error = VOP_GETATTR(filevp, &filevattr, 0, crp, NULL))
goto out;
/*
* Make sure the user is the owner of the mount point
@@ -652,7 +652,7 @@ nm_sync(vfs_t *vfsp, short flag, cred_t *crp)
if (flag & SYNC_CLOSE)
return (nm_umountall(nodep->nm_filevp, crp));
- return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp));
+ return (VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, NULL));
}
/*
diff --git a/usr/src/uts/common/fs/namefs/namevno.c b/usr/src/uts/common/fs/namefs/namevno.c
index ab4767e578..f62af2b7f2 100644
--- a/usr/src/uts/common/fs/namefs/namevno.c
+++ b/usr/src/uts/common/fs/namefs/namevno.c
@@ -77,7 +77,7 @@
* file system, with the parent being the initial mount.
*/
int
-nm_open(vnode_t **vpp, int flag, cred_t *crp)
+nm_open(vnode_t **vpp, int flag, cred_t *crp, caller_context_t *ct)
{
struct namenode *nodep = VTONM(*vpp);
int error = 0;
@@ -95,7 +95,7 @@ nm_open(vnode_t **vpp, int flag, cred_t *crp)
infilevp = outfilevp = nodep->nm_filevp;
VN_HOLD(outfilevp);
- if ((error = VOP_OPEN(&outfilevp, flag, crp)) != 0) {
+ if ((error = VOP_OPEN(&outfilevp, flag, crp, ct)) != 0) {
VN_RELE(outfilevp);
return (error);
}
@@ -163,16 +163,17 @@ gotit:
* the file descriptor.
*/
static int
-nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp)
+nm_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *crp,
+ caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
int error = 0;
(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
- error = VOP_CLOSE(nodep->nm_filevp, flag, count, offset, crp);
+ error = VOP_CLOSE(nodep->nm_filevp, flag, count, offset, crp, ct);
if (count == 1) {
- (void) VOP_FSYNC(nodep->nm_filevp, FSYNC, crp);
+ (void) VOP_FSYNC(nodep->nm_filevp, FSYNC, crp, ct);
/*
* Before VN_RELE() we need to remove the vnode from
* the hash table. We should only do so in the NMNMNT case.
@@ -205,9 +206,10 @@ nm_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *crp,
}
static int
-nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp)
+nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
- return (VOP_IOCTL(VTONM(vp)->nm_filevp, cmd, arg, mode, cr, rvalp));
+ return (VOP_IOCTL(VTONM(vp)->nm_filevp, cmd, arg, mode, cr, rvalp, ct));
}
/*
@@ -216,7 +218,8 @@ nm_ioctl(vnode_t *vp, int cmd, intptr_t arg, int mode, cred_t *cr, int *rvalp)
*/
/* ARGSUSED */
static int
-nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
+nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp,
+ caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
struct vattr va;
@@ -227,7 +230,7 @@ nm_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *crp)
mutex_exit(&nodep->nm_lock);
if ((va.va_mask = vap->va_mask & AT_SIZE) != 0) {
- if (error = VOP_GETATTR(nodep->nm_filevp, &va, flags, crp))
+ if (error = VOP_GETATTR(nodep->nm_filevp, &va, flags, crp, ct))
return (error);
vap->va_size = va.va_size;
}
@@ -336,7 +339,8 @@ out:
*/
/* ARGSUSED */
static int
-nm_access(vnode_t *vp, int mode, int flags, cred_t *crp)
+nm_access(vnode_t *vp, int mode, int flags, cred_t *crp,
+ caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
int error;
@@ -345,7 +349,7 @@ nm_access(vnode_t *vp, int mode, int flags, cred_t *crp)
error = nm_access_unlocked(nodep, mode, crp);
mutex_exit(&nodep->nm_lock);
if (error == 0)
- return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp));
+ return (VOP_ACCESS(nodep->nm_filevp, mode, flags, crp, ct));
else
return (error);
}
@@ -358,13 +362,14 @@ nm_access(vnode_t *vp, int mode, int flags, cred_t *crp)
/*ARGSUSED*/
static int
nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
ASSERT(dvp && *name == '\0');
if (excl == NONEXCL) {
- if (mode && (error = nm_access(dvp, mode, 0, cr)) != 0)
+ if (mode && (error = nm_access(dvp, mode, 0, cr, ct)) != 0)
return (error);
VN_HOLD(dvp);
return (0);
@@ -377,21 +382,22 @@ nm_create(vnode_t *dvp, char *name, vattr_t *vap, enum vcexcl excl,
*/
/*ARGSUSED*/
static int
-nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp)
+nm_link(vnode_t *tdvp, vnode_t *vp, char *tnm, cred_t *crp,
+ caller_context_t *ct, int flags)
{
return (EXDEV);
}
static int
-nm_fsync(vnode_t *vp, int syncflag, cred_t *crp)
+nm_fsync(vnode_t *vp, int syncflag, cred_t *crp, caller_context_t *ct)
{
- return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp));
+ return (VOP_FSYNC(VTONM(vp)->nm_filevp, syncflag, crp, ct));
}
/* Free the namenode */
/* ARGSUSED */
static void
-nm_inactive(vnode_t *vp, cred_t *crp)
+nm_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
{
struct namenode *nodep = VTONM(vp);
@@ -413,9 +419,9 @@ nm_inactive(vnode_t *vp, cred_t *crp)
}
static int
-nm_fid(vnode_t *vp, struct fid *fidnodep)
+nm_fid(vnode_t *vp, struct fid *fidnodep, caller_context_t *ct)
{
- return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep));
+ return (VOP_FID(VTONM(vp)->nm_filevp, fidnodep, ct));
}
static int
@@ -431,21 +437,21 @@ nm_rwunlock(vnode_t *vp, int write, caller_context_t *ctp)
}
static int
-nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nm_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
- return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp));
+ return (VOP_SEEK(VTONM(vp)->nm_filevp, ooff, noffp, ct));
}
/*
* Return the vnode representing the file descriptor in vpp.
*/
static int
-nm_realvp(vnode_t *vp, vnode_t **vpp)
+nm_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
struct vnode *rvp;
vp = VTONM(vp)->nm_filevp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
*vpp = vp;
return (0);
@@ -453,9 +459,10 @@ nm_realvp(vnode_t *vp, vnode_t **vpp)
static int
nm_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **phpp)
+ pollhead_t **phpp, caller_context_t *ct)
{
- return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp, phpp));
+ return (VOP_POLL(VTONM(vp)->nm_filevp, events, anyyet, reventsp,
+ phpp, ct));
}
struct vnodeops *nm_vnodeops;
diff --git a/usr/src/uts/common/fs/nbmlock.c b/usr/src/uts/common/fs/nbmlock.c
index bb9dd88722..add00c6b1f 100644
--- a/usr/src/uts/common/fs/nbmlock.c
+++ b/usr/src/uts/common/fs/nbmlock.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -133,13 +132,14 @@ nbl_conflict(vnode_t *vp,
nbl_op_t op, /* attempted operation */
u_offset_t offset, /* ignore if not I/O */
ssize_t length, /* ignore if not I/O */
- int svmand) /* System V mandatory locking */
+ int svmand, /* System V mandatory locking */
+ caller_context_t *ct) /* caller context */
{
ASSERT(nbl_in_crit(vp));
ASSERT(op == NBL_READ || op == NBL_WRITE || op == NBL_RENAME ||
op == NBL_REMOVE || op == NBL_READWRITE);
- if (nbl_share_conflict(vp, op)) {
+ if (nbl_share_conflict(vp, op, ct)) {
return (1);
}
@@ -150,7 +150,7 @@ nbl_conflict(vnode_t *vp,
if (op == NBL_REMOVE || op == NBL_RENAME)
return (0);
- return (nbl_lock_conflict(vp, op, offset, length, svmand));
+ return (nbl_lock_conflict(vp, op, offset, length, svmand, ct));
}
/*
@@ -167,7 +167,7 @@ nbl_svmand(vnode_t *vp, cred_t *cr, int *svp)
int error;
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error != 0)
return (error);
diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index 4f8276d75f..0660a85e59 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -262,7 +262,8 @@ rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
offset = bva.va_size;
length = ava.va_size - bva.va_size;
}
- if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -298,7 +299,7 @@ rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
if (error)
goto out;
@@ -369,11 +370,11 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
}
#else
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
#endif
if (args->what.name == nfs3nametoolong) {
@@ -438,7 +439,7 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
}
} else {
error = VOP_LOOKUP(dvp, args->what.name, &vp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
}
if (is_system_labeled() && error == 0) {
@@ -463,12 +464,12 @@ rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
} else
dvap = NULL;
#else
dva.va_mask = AT_ALL;
- dvap = VOP_GETATTR(dvp, &dva, 0, cr) ? NULL : &dva;
+ dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
#endif
if (error)
@@ -585,7 +586,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
* as well be reflected to the server during the open.
*/
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -618,7 +619,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
}
if (args->access & ACCESS3_READ) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -628,7 +629,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
resp->resok.access |= ACCESS3_READ;
}
if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -638,7 +639,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
}
if (checkwriteperm &&
(args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -650,7 +651,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
}
if (checkwriteperm &&
(args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -659,7 +660,7 @@ rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
resp->resok.access |= ACCESS3_DELETE;
}
if (args->access & ACCESS3_EXECUTE) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
@@ -726,7 +727,7 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
}
va.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error)
goto out;
@@ -773,17 +774,17 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
uio.uio_loffset = 0;
uio.uio_resid = MAXPATHLEN;
- error = VOP_READLINK(vp, &uio, cr);
+ error = VOP_READLINK(vp, &uio, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
#if 0 /* notyet */
@@ -795,7 +796,7 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
if (error) {
@@ -895,7 +896,8 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0)) {
+ if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -905,7 +907,7 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
need_rwunlock = 1;
va.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -927,11 +929,11 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
}
if (crgetuid(cr) != va.va_uid) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error) {
if (curthread->t_flag & T_WOULDBLOCK)
goto out;
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (error)
goto out;
}
@@ -1008,7 +1010,7 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
}
va.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
@@ -1036,7 +1038,7 @@ rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
if (in_crit)
@@ -1160,7 +1162,8 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -1169,7 +1172,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
bva.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -1201,7 +1204,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
}
if (crgetuid(cr) != bva.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cr)))
+ (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
goto out;
if (MANDLOCK(vp, bva.va_mode)) {
@@ -1282,7 +1285,7 @@ rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
kmem_free(iovp, sizeof (*iovp) * iovcnt);
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#ifdef DEBUG
if (!rfs3_do_post_op_attr)
@@ -1375,12 +1378,12 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -1452,7 +1455,7 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
* Does file already exist?
*/
error = VOP_LOOKUP(dvp, args->where.name, &tvp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
/*
* Check to see if the file has been delegated
@@ -1479,7 +1482,8 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
in_crit = 1;
tva.va_mask = AT_SIZE;
- error = VOP_GETATTR(tvp, &tva, 0, cr);
+ error = VOP_GETATTR(tvp, &tva, 0, cr,
+ NULL);
/*
* Can't check for conflicts, so return
* error.
@@ -1493,7 +1497,7 @@ rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
va.va_size - tva.va_size :
tva.va_size - va.va_size;
if (nbl_conflict(tvp, NBL_WRITE,
- offset, len, 0)) {
+ offset, len, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1530,17 +1534,17 @@ tryagain:
* passed as part of the arguments.
*/
error = VOP_CREATE(dvp, args->where.name, &va, excl, VWRITE,
- &vp, cr, 0);
+ &vp, cr, 0, NULL, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
if (error) {
@@ -1561,7 +1565,7 @@ tryagain:
* Lookup the file so that we can get a vnode for it.
*/
error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error) {
/*
* We couldn't find the file that we thought that
@@ -1586,7 +1590,7 @@ tryagain:
}
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
mtime = (nfstime3 *)&args->how.createhow3_u.verf;
/* % with INT32_MAX to prevent overflows */
@@ -1615,7 +1619,7 @@ tryagain:
}
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
/*
* We need to check to make sure that the file got
@@ -1638,7 +1642,7 @@ tryagain:
va.va_size = reqsize;
(void) VOP_SETATTR(vp, &va, 0, cr, NULL);
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
}
}
@@ -1664,8 +1668,8 @@ tryagain:
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
VN_RELE(vp);
VN_RELE(dvp);
@@ -1730,12 +1734,12 @@ rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -1781,23 +1785,23 @@ rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
va.va_mask |= AT_TYPE;
va.va_type = VDIR;
- error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr);
+ error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr, NULL, 0, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (error)
goto out;
@@ -1821,18 +1825,18 @@ rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -1886,12 +1890,12 @@ rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -1943,28 +1947,29 @@ rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
va.va_type = VLNK;
error = VOP_SYMLINK(dvp, args->where.name, &va,
- args->symlink.symlink_data, cr);
+ args->symlink.symlink_data, cr, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
if (error)
goto out;
- error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
VN_RELE(dvp);
@@ -1993,18 +1998,18 @@ rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2059,12 +2064,12 @@ rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
} else
dbvap = NULL;
#else
dbva.va_mask = AT_ALL;
- dbvap = VOP_GETATTR(dvp, &dbva, 0, cr) ? NULL : &dbva;
+ dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
#endif
davap = dbvap;
@@ -2152,23 +2157,23 @@ rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
mode = 0;
error = VOP_CREATE(dvp, args->where.name, &va, excl, mode,
- &vp, cr, 0);
+ &vp, cr, 0, NULL, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
} else
davap = NULL;
#else
dava.va_mask = AT_ALL;
- davap = VOP_GETATTR(dvp, &dava, 0, cr) ? NULL : &dava;
+ davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (error)
goto out;
@@ -2194,18 +2199,18 @@ rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
VN_RELE(vp);
@@ -2256,12 +2261,12 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
} else
bvap = NULL;
#else
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
#endif
avap = bvap;
@@ -2305,7 +2310,7 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
* reservation and V4 delegations
*/
error = VOP_LOOKUP(vp, args->object.name, &targvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error != 0)
goto out;
@@ -2315,13 +2320,13 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
}
if (!nbl_need_check(targvp)) {
- error = VOP_REMOVE(vp, args->object.name, cr);
+ error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
} else {
nbl_start_crit(targvp, RW_READER);
- if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
error = EACCES;
} else {
- error = VOP_REMOVE(vp, args->object.name, cr);
+ error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
}
nbl_end_crit(targvp);
}
@@ -2331,18 +2336,18 @@ rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
} else
avap = NULL;
#else
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
if (error)
goto out;
@@ -2395,12 +2400,12 @@ rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
} else
bvap = NULL;
#else
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(vp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
#endif
avap = bvap;
@@ -2439,23 +2444,23 @@ rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
}
}
- error = VOP_RMDIR(vp, args->object.name, rootdir, cr);
+ error = VOP_RMDIR(vp, args->object.name, rootdir, cr, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
} else
avap = NULL;
#else
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
if (error) {
/*
@@ -2544,12 +2549,12 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
fbva.va_mask = AT_ALL;
- fbvap = VOP_GETATTR(fvp, &fbva, 0, cr) ? NULL : &fbva;
+ fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
} else
fbvap = NULL;
#else
fbva.va_mask = AT_ALL;
- fbvap = VOP_GETATTR(fvp, &fbva, 0, cr) ? NULL : &fbva;
+ fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
#endif
favap = fbvap;
@@ -2575,12 +2580,12 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
tbva.va_mask = AT_ALL;
- tbvap = VOP_GETATTR(tvp, &tbva, 0, cr) ? NULL : &tbva;
+ tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
} else
tbvap = NULL;
#else
tbva.va_mask = AT_ALL;
- tbvap = VOP_GETATTR(tvp, &tbva, 0, cr) ? NULL : &tbva;
+ tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
#endif
tavap = tbvap;
@@ -2619,7 +2624,7 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
* reservation or V4 delegations.
*/
error = VOP_LOOKUP(fvp, args->from.name, &srcvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error != 0)
goto out;
@@ -2638,7 +2643,8 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
* first to avoid VOP_LOOKUP if possible.
*/
if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
- VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr) == 0) {
+ VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL) == 0) {
if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
VN_RELE(targvp);
@@ -2650,14 +2656,14 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
if (!nbl_need_check(srcvp)) {
error = VOP_RENAME(fvp, args->from.name, tvp,
- args->to.name, cr);
+ args->to.name, cr, NULL, 0);
} else {
nbl_start_crit(srcvp, RW_READER);
- if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) {
+ if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
error = EACCES;
} else {
error = VOP_RENAME(fvp, args->from.name, tvp,
- args->to.name, cr);
+ args->to.name, cr, NULL, 0);
}
nbl_end_crit(srcvp);
}
@@ -2680,25 +2686,25 @@ rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
fava.va_mask = AT_ALL;
- favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava;
+ favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
tava.va_mask = AT_ALL;
- tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava;
+ tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
} else {
favap = NULL;
tavap = NULL;
}
#else
fava.va_mask = AT_ALL;
- favap = VOP_GETATTR(fvp, &fava, 0, cr) ? NULL : &fava;
+ favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
tava.va_mask = AT_ALL;
- tavap = VOP_GETATTR(tvp, &tava, 0, cr) ? NULL : &tava;
+ tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(fvp, 0, cr);
- (void) VOP_FSYNC(tvp, 0, cr);
+ (void) VOP_FSYNC(fvp, 0, cr, NULL);
+ (void) VOP_FSYNC(tvp, 0, cr, NULL);
if (error)
goto out;
@@ -2764,12 +2770,12 @@ rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
fh3 = &args->link.dir;
@@ -2809,12 +2815,12 @@ rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
} else
bvap = NULL;
#else
bva.va_mask = AT_ALL;
- bvap = VOP_GETATTR(dvp, &bva, 0, cr) ? NULL : &bva;
+ bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
#endif
if (dvp->v_type != VDIR) {
@@ -2849,30 +2855,30 @@ rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
}
}
- error = VOP_LINK(dvp, vp, args->link.name, cr);
+ error = VOP_LINK(dvp, vp, args->link.name, cr, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
} else {
vap = NULL;
avap = NULL;
}
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(dvp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (error)
goto out;
@@ -2925,7 +2931,7 @@ rfs3_link_getfh(LINK3args *args)
* attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
* boolean - 1 * BYTES_PER_XDR_UNIT
* file id - 2 * BYTES_PER_XDR_UNIT
- * direcotory name length - 1 * BYTES_PER_XDR_UNIT
+ * directory name length - 1 * BYTES_PER_XDR_UNIT
* cookie - 2 * BYTES_PER_XDR_UNIT
* end of list - 1 * BYTES_PER_XDR_UNIT
* end of file - 1 * BYTES_PER_XDR_UNIT
@@ -2981,12 +2987,12 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
if (vp->v_type != VDIR) {
@@ -2994,7 +3000,7 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
goto out1;
}
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error)
goto out;
@@ -3025,17 +3031,17 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
uio.uio_loffset = (offset_t)args->cookie;
uio.uio_resid = count;
- error = VOP_READDIR(vp, &uio, cr, &iseof);
+ error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
if (error) {
@@ -3108,7 +3114,7 @@ rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -3173,7 +3179,7 @@ rfs3_readdir_free(READDIR3res *resp)
* attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
* status byte for file handle - 1 * BYTES_PER_XDR_UNIT
* length of a file handle - 1 * BYTES_PER_XDR_UNIT
- * Maxmum length of a file handle (NFS3_MAXFHSIZE)
+ * Maximum length of a file handle (NFS3_MAXFHSIZE)
* name length of the entry to the nearest bytes
*/
#define NFS3_READDIRPLUS_ENTRY(namelen) \
@@ -3241,12 +3247,12 @@ rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
if (vp->v_type != VDIR) {
@@ -3254,7 +3260,7 @@ rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
goto out;
}
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (error)
goto out;
@@ -3323,7 +3329,7 @@ getmoredents:
uio.uio_resid = rd_unit;
prev_len = rd_unit;
- error = VOP_READDIR(vp, &uio, cr, &iseof);
+ error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
if (error) {
kmem_free(data, args->dircount);
@@ -3412,12 +3418,12 @@ good:
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
@@ -3437,7 +3443,8 @@ good:
infop[i].namelen = namlen[i];
- error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error) {
infop[i].attr.attributes = FALSE;
infop[i].fh.handle_follows = FALSE;
@@ -3485,7 +3492,7 @@ good:
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -3577,12 +3584,12 @@ rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
VN_RELE(vp);
@@ -3673,12 +3680,12 @@ rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
resp->status = NFS3_OK;
@@ -3696,7 +3703,7 @@ rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
* Large file spec: want maxfilesize based on limit of
* underlying filesystem. We can guess 2^31-1 if need be.
*/
- error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr);
+ error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
VN_RELE(vp);
@@ -3755,25 +3762,25 @@ rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
} else
vap = NULL;
#else
va.va_mask = AT_ALL;
- vap = VOP_GETATTR(vp, &va, 0, cr) ? NULL : &va;
+ vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
- error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
if (error)
goto out;
resp->resok.info.link_max = (uint32)val;
- error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
if (error)
goto out;
resp->resok.info.name_max = (uint32)val;
- error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
if (error)
goto out;
if (val == 1)
@@ -3781,7 +3788,7 @@ rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
else
resp->resok.info.no_trunc = FALSE;
- error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
if (error)
goto out;
if (val == 1)
@@ -3837,7 +3844,7 @@ rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
}
bva.va_mask = AT_ALL;
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -3881,22 +3888,22 @@ rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
}
if (crgetuid(cr) != bva.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cr)))
+ (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
goto out;
- error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr);
+ error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
if (!error)
- error = VOP_FSYNC(vp, FNODSYNC, cr);
+ error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
} else
avap = NULL;
#else
ava.va_mask = AT_ALL;
- avap = VOP_GETATTR(vp, &ava, 0, cr) ? NULL : &ava;
+ avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
#endif
if (error)
diff --git a/usr/src/uts/common/fs/nfs/nfs3_vnops.c b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
index 39bdc1aa00..51306f52e8 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
@@ -101,7 +101,8 @@ static int nfs3create(vnode_t *, char *, struct vattr *, enum vcexcl,
static int nfs3excl_create_settimes(vnode_t *, struct vattr *, cred_t *);
static int nfs3mknod(vnode_t *, char *, struct vattr *, enum vcexcl,
int, vnode_t **, cred_t *);
-static int nfs3rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
+static int nfs3rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *);
static int do_nfs3readdir(vnode_t *, rddir_cache *, cred_t *);
static void nfs3readdir(vnode_t *, rddir_cache *, cred_t *);
static void nfs3readdirplus(vnode_t *, rddir_cache *, cred_t *);
@@ -160,59 +161,76 @@ static void nfs3_delmap_callback(struct as *, void *, uint_t);
* more details on rnode locking.
*/
-static int nfs3_open(vnode_t **, int, cred_t *);
-static int nfs3_close(vnode_t *, int, int, offset_t, cred_t *);
+static int nfs3_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs3_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int nfs3_read(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
static int nfs3_write(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
-static int nfs3_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-static int nfs3_getattr(vnode_t *, struct vattr *, int, cred_t *);
+static int nfs3_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+static int nfs3_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
static int nfs3_setattr(vnode_t *, struct vattr *, int, cred_t *,
caller_context_t *);
-static int nfs3_access(vnode_t *, int, int, cred_t *);
-static int nfs3_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs3_fsync(vnode_t *, int, cred_t *);
-static void nfs3_inactive(vnode_t *, cred_t *);
+static int nfs3_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+static int nfs3_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs3_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void nfs3_inactive(vnode_t *, cred_t *, caller_context_t *);
static int nfs3_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
+ struct pathname *, int, vnode_t *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
static int nfs3_create(vnode_t *, char *, struct vattr *, enum vcexcl,
- int, vnode_t **, cred_t *, int);
-static int nfs3_remove(vnode_t *, char *, cred_t *);
-static int nfs3_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs3_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int nfs3_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs3_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs3_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs3_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs3_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs3_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+static int nfs3_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
static int nfs3_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs3_readdir(vnode_t *, struct uio *, cred_t *, int *);
-static int nfs3_fid(vnode_t *, fid_t *);
+ cred_t *, caller_context_t *, int);
+static int nfs3_readdir(vnode_t *, struct uio *, cred_t *, int *,
+ caller_context_t *, int);
+static int nfs3_fid(vnode_t *, fid_t *, caller_context_t *);
static int nfs3_rwlock(vnode_t *, int, caller_context_t *);
static void nfs3_rwunlock(vnode_t *, int, caller_context_t *);
-static int nfs3_seek(vnode_t *, offset_t, offset_t *);
+static int nfs3_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
static int nfs3_getpage(vnode_t *, offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
-static int nfs3_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
-static int nfs3_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs3_addmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
+static int nfs3_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+static int nfs3_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs3_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
static int nfs3_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *, caller_context_t *);
static int nfs3_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-static int nfs3_realvp(vnode_t *, vnode_t **);
-static int nfs3_delmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, cred_t *);
-static int nfs3_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+static int nfs3_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int nfs3_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
+static int nfs3_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
static int nfs3_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static void nfs3_dispose(vnode_t *, page_t *, int, int, cred_t *);
-static int nfs3_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs3_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs3_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
+ cred_t *, caller_context_t *);
+static void nfs3_dispose(vnode_t *, page_t *, int, int, cred_t *,
+ caller_context_t *);
+static int nfs3_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs3_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs3_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
struct vnodeops *nfs3_vnodeops;
@@ -272,7 +290,7 @@ nfs3_getvnodeops(void)
/* ARGSUSED */
static int
-nfs3_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs3_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error;
struct vattr va;
@@ -321,8 +339,10 @@ nfs3_open(vnode_t **vpp, int flag, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+nfs3_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -396,7 +416,8 @@ nfs3_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
*/
if ((flag & FWRITE) && vn_has_cached_data(vp)) {
if (VTOMI(vp)->mi_flags & MI_NOCTO) {
- error = nfs3_putpage(vp, (offset_t)0, 0, B_ASYNC, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, B_ASYNC,
+ cr, ct);
if (error == EAGAIN)
error = 0;
} else
@@ -1160,7 +1181,8 @@ nfs3read(vnode_t *vp, caddr_t base, offset_t offset, int count,
/* ARGSUSED */
static int
-nfs3_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+nfs3_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
if (nfs_zone() != VTOMI(vp)->mi_zone)
@@ -1173,8 +1195,10 @@ nfs3_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
}
+/* ARGSUSED */
static int
-nfs3_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs3_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -1217,7 +1241,7 @@ nfs3_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
mutex_enter(&rp->r_statelock);
rp->r_gcount++;
mutex_exit(&rp->r_statelock);
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr, ct);
mutex_enter(&rp->r_statelock);
if (error && (error == ENOSPC || error == EDQUOT)) {
if (!rp->r_error)
@@ -1293,7 +1317,7 @@ nfs3setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1446,12 +1470,12 @@ static int
nfs3_accessx(void *vp, int mode, cred_t *cr)
{
ASSERT(nfs_zone() == VTOMI((vnode_t *)vp)->mi_zone);
- return (nfs3_access(vp, mode, 0, cr));
+ return (nfs3_access(vp, mode, 0, cr, NULL));
}
/* ARGSUSED */
static int
-nfs3_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs3_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
int error;
ACCESS3args args;
@@ -1584,8 +1608,9 @@ tryagain:
static int nfs3_do_symlink_cache = 1;
+/* ARGSUSED */
static int
-nfs3_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs3_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
int error;
READLINK3args args;
@@ -1693,8 +1718,9 @@ nfs3_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
* metadata changes are not cached on the client before being
* sent to the server.
*/
+/* ARGSUSED */
static int
-nfs3_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+nfs3_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
int error;
@@ -1714,8 +1740,9 @@ nfs3_fsync(vnode_t *vp, int syncflag, cred_t *cr)
* operation while it was open, it got renamed instead. Here we
* remove the renamed file.
*/
+/* ARGSUSED */
static void
-nfs3_inactive(vnode_t *vp, cred_t *cr)
+nfs3_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
@@ -1775,7 +1802,8 @@ redo:
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0,
+ cr, ct);
if (error) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1832,9 +1860,11 @@ redo:
* Remote file system operations having to do with directory manipulation.
*/
+/* ARGSUSED */
static int
nfs3_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int error;
vnode_t *vp;
@@ -1957,7 +1987,7 @@ nfs3lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* just need to check access.
*/
if (strcmp(nm, ".") == 0) {
- error = nfs3_access(dvp, VEXEC, 0, cr);
+ error = nfs3_access(dvp, VEXEC, 0, cr, NULL);
if (error)
return (error);
VN_HOLD(dvp);
@@ -2018,7 +2048,7 @@ nfs3lookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
return (error);
vp = dnlc_lookup(dvp, nm);
if (vp != NULL) {
- error = nfs3_access(dvp, VEXEC, 0, cr);
+ error = nfs3_access(dvp, VEXEC, 0, cr, NULL);
if (error) {
VN_RELE(vp);
return (error);
@@ -2134,7 +2164,8 @@ static int nfs3_create_misses = 0;
/* ARGSUSED */
static int
nfs3_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
- int mode, vnode_t **vpp, cred_t *cr, int lfaware)
+ int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
vnode_t *vp;
@@ -2171,7 +2202,7 @@ top:
* just need to check access.
*/
} else if (strcmp(nm, ".") == 0) {
- error = nfs3_access(dvp, VEXEC, 0, cr);
+ error = nfs3_access(dvp, VEXEC, 0, cr, ct);
if (error) {
nfs_rw_exit(&drp->r_rwlock);
return (error);
@@ -2200,7 +2231,7 @@ top:
vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
VN_RELE(tempvp);
}
- if (!(error = VOP_ACCESS(vp, mode, 0, cr))) {
+ if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
if ((vattr.va_mask & AT_SIZE) &&
vp->v_type == VREG) {
rp = VTOR(vp);
@@ -2230,7 +2261,7 @@ top:
/*
* existing file got truncated, notify.
*/
- vnevent_create(vp);
+ vnevent_create(vp, ct);
*vpp = vp;
}
return (error);
@@ -2438,7 +2469,7 @@ nfs3create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
*/
VN_RELE(vp);
(void) nfs3_remove(dvp,
- nm, cr);
+ nm, cr, NULL, 0);
return (error);
}
}
@@ -2515,7 +2546,7 @@ nfs3create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* application.
*/
VN_RELE(vp);
- (void) nfs3_remove(dvp, nm, cr);
+ (void) nfs3_remove(dvp, nm, cr, NULL, 0);
return (error);
}
}
@@ -2737,8 +2768,9 @@ nfs3mknod(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* we rename it instead of removing it and nfs_inactive
* will remove the new name.
*/
+/* ARGSUSED */
static int
-nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
{
int error;
REMOVE3args args;
@@ -2792,7 +2824,7 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
(rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
mutex_exit(&rp->r_statelock);
tmpname = newname();
- error = nfs3rename(dvp, nm, dvp, tmpname, cr);
+ error = nfs3rename(dvp, nm, dvp, tmpname, cr, ct);
if (error)
kmem_free(tmpname, MAXNAMELEN);
else {
@@ -2821,7 +2853,7 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
*/
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
- error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -2868,7 +2900,7 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
}
if (error == 0) {
- vnevent_remove(vp, dvp, nm);
+ vnevent_remove(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -2877,8 +2909,10 @@ nfs3_remove(vnode_t *dvp, char *nm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
LINK3args args;
@@ -2891,7 +2925,7 @@ nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
if (nfs_zone() != VTOMI(tdvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
mi = VTOMI(svp);
@@ -2949,29 +2983,32 @@ nfs3_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
/*
* Notify the source file of this link operation.
*/
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
return (error);
}
+/* ARGSUSED */
static int
-nfs3_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs3_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
vnode_t *realvp;
if (nfs_zone() != VTOMI(odvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
- return (nfs3rename(odvp, onm, ndvp, nnm, cr));
+ return (nfs3rename(odvp, onm, ndvp, nnm, cr, ct));
}
/*
* nfs3rename does the real work of renaming in NFS Version 3.
*/
static int
-nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct)
{
int error;
RENAME3args args;
@@ -3106,10 +3143,10 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
* the server removing the file completely.
*/
tmpname = newname();
- error = nfs3_link(ndvp, nvp, tmpname, cr);
+ error = nfs3_link(ndvp, nvp, tmpname, cr, NULL, 0);
if (error == EOPNOTSUPP) {
error = nfs3_rename(ndvp, nnm, ndvp, tmpname,
- cr);
+ cr, NULL, 0);
}
if (error) {
kmem_free(tmpname, MAXNAMELEN);
@@ -3253,12 +3290,12 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
if (error == 0) {
if (nvp)
- vnevent_rename_dest(nvp, ndvp, nnm);
+ vnevent_rename_dest(nvp, ndvp, nnm, ct);
if (odvp != ndvp)
- vnevent_rename_dest_dir(ndvp);
+ vnevent_rename_dest_dir(ndvp, ct);
ASSERT(ovp != NULL);
- vnevent_rename_src(ovp, odvp, onm);
+ vnevent_rename_src(ovp, odvp, onm, ct);
}
if (nvp) {
@@ -3272,8 +3309,10 @@ nfs3rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
+nfs3_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
MKDIR3args args;
@@ -3375,8 +3414,10 @@ nfs3_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
RMDIR3args args;
@@ -3469,7 +3510,7 @@ nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
}
if (error == 0) {
- vnevent_rmdir(vp, dvp, nm);
+ vnevent_rmdir(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -3478,8 +3519,10 @@ nfs3_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
+nfs3_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
SYMLINK3args args;
@@ -3607,8 +3650,10 @@ static int nfs3_shrinkreaddir = 0;
* may return only one block's worth of entries. Entries may be compressed
* on the server.
*/
+/* ARGSUSED */
static int
-nfs3_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
+nfs3_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int error;
size_t count;
@@ -4335,8 +4380,9 @@ nfs3_bio(struct buf *bp, stable_how *stab_comm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs3_fid(vnode_t *vp, fid_t *fidp)
+nfs3_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
rnode_t *rp;
@@ -4386,7 +4432,7 @@ nfs3_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-nfs3_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nfs3_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
/*
@@ -4413,10 +4459,11 @@ static int nfs3_lostpage = 0; /* number of times we lost original page */
/*
* Return all the pages from [off..off+len) in file
*/
+/* ARGSUSED */
static int
nfs3_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -4879,8 +4926,10 @@ nfs3_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/* ARGSUSED */
static int
-nfs3_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+nfs3_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -5078,7 +5127,7 @@ nfs3_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
*/
if (!(flags & B_ASYNC)) {
error = nfs3_putpage(vp, io_off, io_len,
- B_INVAL | B_FORCE, cr);
+ B_INVAL | B_FORCE, cr, NULL);
}
} else {
if (error)
@@ -5096,9 +5145,11 @@ nfs3_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs3_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -5197,7 +5248,8 @@ done:
/* ARGSUSED */
static int
nfs3_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
@@ -5220,9 +5272,11 @@ nfs3_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
return (0);
}
+/* ARGSUSED */
static int
nfs3_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
netobj lm_fh3;
int rc;
@@ -5277,7 +5331,7 @@ nfs3_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (!lm_safelock(vp, bfp, cr))
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
rp = VTOR(vp);
@@ -5326,7 +5380,7 @@ nfs3_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
mutex_exit(&rp->r_statelock);
if (rc != 0)
goto done;
- error = nfs3_putpage(vp, (offset_t)0, 0, B_INVAL, cr);
+ error = nfs3_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
@@ -5407,7 +5461,7 @@ nfs3_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/* ARGSUSED */
static int
-nfs3_realvp(vnode_t *vp, vnode_t **vpp)
+nfs3_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
return (EINVAL);
@@ -5426,7 +5480,8 @@ nfs3_realvp(vnode_t *vp, vnode_t **vpp)
/* ARGSUSED */
static int
nfs3_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags,
+ cred_t *cr, caller_context_t *ct)
{
int caller_found;
int error;
@@ -5556,7 +5611,7 @@ nfs3_delmap_callback(struct as *as, void *arg, uint_t event)
if ((mi->mi_flags & MI_NOCTO) ||
nfs_zone() != mi->mi_zone)
error = nfs3_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_ASYNC, dmapp->cr);
+ B_ASYNC, dmapp->cr, NULL);
else
error = nfs3_putpage_commit(dmapp->vp, dmapp->off,
dmapp->len, dmapp->cr);
@@ -5571,7 +5626,7 @@ nfs3_delmap_callback(struct as *as, void *arg, uint_t event)
if ((rp->r_flags & RDIRECTIO) || (mi->mi_flags & MI_DIRECTIO))
(void) nfs3_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_INVAL, dmapp->cr);
+ B_INVAL, dmapp->cr, NULL);
dmapp->caller->error = error;
(void) as_delete_callback(as, arg);
@@ -5585,8 +5640,10 @@ static int nfs3_pathconf_cache_hits = 0;
static int nfs3_pathconf_cache_misses = 0;
#endif
+/* ARGSUSED */
static int
-nfs3_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+nfs3_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error;
PATHCONF3args args;
@@ -5795,9 +5852,10 @@ nfs3_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs3_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -5824,8 +5882,10 @@ nfs3_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static void
-nfs3_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+nfs3_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -6362,7 +6422,7 @@ top:
write_verf = rp->r_verf;
mutex_exit(&rp->r_statelock);
- error = nfs3_putpage(vp, poff, plen, B_ASYNC, cr);
+ error = nfs3_putpage(vp, poff, plen, B_ASYNC, cr, NULL);
if (error == EAGAIN)
error = 0;
@@ -6373,7 +6433,7 @@ top:
* the asynchronous i/o's in that range are done as well.
*/
if (!error)
- error = nfs3_putpage(vp, poff, plen, 0, cr);
+ error = nfs3_putpage(vp, poff, plen, 0, cr, NULL);
if (error)
return (error);
@@ -6510,8 +6570,10 @@ nfs3_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count,
(void) nfs3_sync_commit(vp, plist, offset, count, cr);
}
+/* ARGSUSED */
static int
-nfs3_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs3_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -6530,8 +6592,10 @@ nfs3_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (ENOSYS);
}
+/* ARGSUSED */
static int
-nfs3_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs3_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -6547,11 +6611,13 @@ nfs3_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (error);
}
- return (fs_fab_acl(vp, vsecattr, flag, cr));
+ return (fs_fab_acl(vp, vsecattr, flag, cr, ct));
}
+/* ARGSUSED */
static int
-nfs3_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+nfs3_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
struct shrlock nshr;
@@ -6580,7 +6646,7 @@ nfs3_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
* request off to the local share code.
*/
if (VTOMI(vp)->mi_flags & MI_LLOCK)
- return (fs_shrlock(vp, cmd, shr, flag, cr));
+ return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
switch (cmd) {
case F_SHARE:
diff --git a/usr/src/uts/common/fs/nfs/nfs4_acl.c b/usr/src/uts/common/fs/nfs/nfs4_acl.c
index 77c9506dcb..7f5d28f037 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_acl.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_acl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -782,6 +782,7 @@ vs_aent_to_ace4(vsecattr_t *aclentacl, vsecattr_t *vs_ace4,
vs_ace4->vsa_aclcnt = 0;
vs_ace4->vsa_dfaclentp = NULL;
vs_ace4->vsa_dfaclcnt = 0;
+ vs_ace4->vsa_aclentsz = 0;
if (! (aclentacl->vsa_mask & (VSA_ACL | VSA_ACLCNT |
VSA_DFACL | VSA_DFACLCNT))) {
@@ -1922,10 +1923,11 @@ vs_ace4_to_acet(vsecattr_t *vs_ace4, vsecattr_t *vs_acet,
if ((vs_ace4->vsa_aclcnt == 0) || (vs_ace4->vsa_aclentp == NULL))
return (0);
- if (vs_ace4->vsa_aclcnt > 0)
+ if (vs_ace4->vsa_aclcnt > 0) {
vs_acet->vsa_aclentp = kmem_alloc(vs_ace4->vsa_aclcnt *
sizeof (ace_t), KM_SLEEP);
- else
+ vs_acet->vsa_aclentsz = vs_ace4->vsa_aclcnt * sizeof (ace_t);
+ } else
vs_acet->vsa_aclentp = NULL;
vs_acet->vsa_aclcnt = vs_ace4->vsa_aclcnt;
vs_acet->vsa_mask = VSA_ACE | VSA_ACECNT;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_callback.c b/usr/src/uts/common/fs/nfs/nfs4_callback.c
index 2bc2249e12..4c7d4e9b8c 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_callback.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_callback.c
@@ -1628,7 +1628,7 @@ nfs4delegreturn_impl(rnode4_t *rp, int flags, struct nfs4_callback_globals *ncg)
* before doing DELEGRETURN.
*/
if (flags & NFS4_DR_PUSH)
- (void) VOP_PUTPAGE(vp, 0, 0, 0, cr);
+ (void) VOP_PUTPAGE(vp, 0, 0, 0, cr, NULL);
/*
* Take r_deleg_recall_lock in WRITE mode, this will prevent
@@ -1989,7 +1989,7 @@ retry:
* We have already taken the 'r_deleg_recall_lock' as WRITER, which
* prevents new OPENs from going OTW (as start_fop takes this
* lock in READ mode); thus, no new open streams can be created
- * (which inheretly means no new delegation open streams are
+ * (which inherently means no new delegation open streams are
* being created).
*/
@@ -2096,7 +2096,7 @@ nfs4delegreturn_thread(struct cb_recall_pass *args)
mutex_exit(&rp->r_statelock);
if (rdirty) {
- error = VOP_PUTPAGE(vp, 0, 0, 0, cr);
+ error = VOP_PUTPAGE(vp, 0, 0, 0, cr, NULL);
if (error)
CB_WARN1("nfs4delegreturn_thread:"
@@ -2114,7 +2114,7 @@ nfs4delegreturn_thread(struct cb_recall_pass *args)
if (rip) {
- error = VOP_PUTPAGE(vp, 0, 0, B_INVAL, cr);
+ error = VOP_PUTPAGE(vp, 0, 0, B_INVAL, cr, NULL);
if (error)
CB_WARN1("nfs4delegreturn_thread: VOP_PUTPAGE: %d\n",
diff --git a/usr/src/uts/common/fs/nfs/nfs4_client.c b/usr/src/uts/common/fs/nfs/nfs4_client.c
index 85f68c5123..f18e46d3c3 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_client.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_client.c
@@ -351,7 +351,7 @@ flush_pages(vnode_t *vp, cred_t *cr)
int error;
rnode4_t *rp = VTOR4(vp);
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -858,7 +858,7 @@ nfs4_getattr_otw_norecovery(vnode_t *vp, nfs4_ga_res_t *garp,
/* getattr */
/*
* Unlike nfs version 2 and 3, where getattr returns all the
- * attributes, nfs version 4 returns only the ones explicitely
+ * attributes, nfs version 4 returns only the ones explicitly
* asked for. This creates problems, as some system functions
* (e.g. cache check) require certain attributes and if the
* cached node lacks some attributes such as uid/gid, it can
@@ -1566,7 +1566,7 @@ nfs4_async_stop(struct vfs *vfsp)
* Wait for all outstanding putpage operations and the inactive thread to
* complete. If a signal is delivered we will abort and return non-zero;
* otherwise return 0. Since this routine is called from nfs4_unmount, we
- * need to make it interruptable.
+ * need to make it interruptible.
*/
int
nfs4_async_stop_sig(struct vfs *vfsp)
@@ -2086,7 +2086,7 @@ nfs4_async_inactive(vnode_t *vp, cred_t *cr)
* set nfs4_max_threads to zero in /etc/system.
*
* The manager thread knows about this and is willing to create
- * at least one thread to accomodate us.
+ * at least one thread to accommodate us.
*/
mutex_enter(&mi->mi_async_lock);
if (mi->mi_inactive_thread == NULL) {
@@ -2404,7 +2404,7 @@ nfs4_putpages(vnode_t *vp, u_offset_t off, size_t len, int flags, cred_t *cr)
flags, cr);
/*
- * If an error occured and the file was marked as dirty
+ * If an error occurred and the file was marked as dirty
* before and we aren't forcibly invalidating pages, then
* reset the R4DIRTY flag.
*/
@@ -2716,7 +2716,7 @@ nfs4_map_lost_lock_conflict(vnode_t *vp)
if (lrp->lr_op != OP_LOCK && lrp->lr_op != OP_LOCKU)
continue;
ASSERT(lrp->lr_vp != NULL);
- if (!VOP_CMP(lrp->lr_vp, vp))
+ if (!VOP_CMP(lrp->lr_vp, vp, NULL))
continue; /* different file */
if (!SAFE_LOCK(*lrp->lr_flk)) {
conflict = TRUE;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c b/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c
index 27c9a9f300..b285807b3f 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_deleg_ops.c
@@ -54,16 +54,21 @@ int
deleg_rdopen(
femarg_t *arg,
int mode,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
/*
+ * Now that the NFSv4 server calls VOP_OPEN, we need to check to
+ * to make sure it is not us calling open (like for DELEG_CUR) or
+ * we will end up panicing the system.
* Since this monitor is for a read delegated file, we know that
* only an open for write will cause a conflict.
*/
- if (mode & (FWRITE|FTRUNC)) {
+ if ((ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) &&
+ (mode & (FWRITE|FTRUNC))) {
fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
rfs4_recall_deleg(fp, FALSE, NULL);
rfs4_dbe_lock(fp->dbe);
@@ -79,7 +84,7 @@ deleg_rdopen(
rfs4_dbe_unlock(fp->dbe);
}
- return (vnext_open(arg, mode, cr));
+ return (vnext_open(arg, mode, cr, ct));
}
/* monitor for open on write delegated file */
@@ -87,31 +92,36 @@ int
deleg_wropen(
femarg_t *arg,
int mode,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
- fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
-
/*
+ * Now that the NFSv4 server calls VOP_OPEN, we need to check to
+ * to make sure it is not us calling open (like for DELEG_CUR) or
+ * we will end up panicing the system.
* Since this monitor is for a write delegated file, we know that
* any open will cause a conflict.
*/
- rfs4_recall_deleg(fp, FALSE, NULL);
- rfs4_dbe_lock(fp->dbe);
- while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
- rc = rfs4_dbe_twait(fp->dbe,
- lbolt + SEC_TO_TICK(rfs4_lease_time));
- if (rc == -1) { /* timed out */
- rfs4_dbe_unlock(fp->dbe);
- rfs4_recall_deleg(fp, FALSE, NULL);
- rfs4_dbe_lock(fp->dbe);
+ if (ct == NULL || ct->cc_caller_id != nfs4_srv_caller_id) {
+ fp = (rfs4_file_t *)arg->fa_fnode->fn_available;
+ rfs4_recall_deleg(fp, FALSE, NULL);
+ rfs4_dbe_lock(fp->dbe);
+ while (fp->dinfo->dtype != OPEN_DELEGATE_NONE) {
+ rc = rfs4_dbe_twait(fp->dbe,
+ lbolt + SEC_TO_TICK(rfs4_lease_time));
+ if (rc == -1) { /* timed out */
+ rfs4_dbe_unlock(fp->dbe);
+ rfs4_recall_deleg(fp, FALSE, NULL);
+ rfs4_dbe_lock(fp->dbe);
+ }
}
+ rfs4_dbe_unlock(fp->dbe);
}
- rfs4_dbe_unlock(fp->dbe);
- return (vnext_open(arg, mode, cr));
+ return (vnext_open(arg, mode, cr, ct));
}
/*
@@ -319,7 +329,8 @@ deleg_setsecattr(
femarg_t *arg,
vsecattr_t *vsap,
int flag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
@@ -340,7 +351,7 @@ deleg_setsecattr(
}
rfs4_dbe_unlock(fp->dbe);
- return (vnext_setsecattr(arg, vsap, flag, cr));
+ return (vnext_setsecattr(arg, vsap, flag, cr, ct));
}
/* ARGSUSED */
@@ -349,7 +360,8 @@ deleg_vnevent(
femarg_t *arg,
vnevent_t vnevent,
vnode_t *dvp,
- char *name)
+ char *name,
+ caller_context_t *ct)
{
clock_t rc;
rfs4_file_t *fp;
@@ -380,5 +392,5 @@ deleg_vnevent(
default:
break;
}
- return (vnext_vnevent(arg, vnevent, dvp, name));
+ return (vnext_vnevent(arg, vnevent, dvp, name, ct));
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_rnode.c b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
index 35d48fd750..5ae6dce3c8 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_rnode.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
@@ -101,7 +101,7 @@
* freelist and then trying to place them back on the freelist
* when their reference is released. This means that the when an
* rnode is looked up in the hash queues, then either the rnode
- * is removed from the freelist and that reference is tranfered to
+ * is removed from the freelist and that reference is transferred to
* the new reference or the vnode reference count must be incremented
* accordingly. The mutex for the freelist must be held in order to
* accurately test to see if the rnode is on the freelist or not.
@@ -211,7 +211,7 @@ r4flushpages(rnode4_t *rp, cred_t *cr)
if (nfs4_has_pages(vp)) {
ASSERT(vp->v_type != VCHR);
if ((rp->r_flags & R4DIRTY) && !rp->r_error) {
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1324,7 +1324,7 @@ toomany:
*/
while (cnt-- > 0) {
vp = vplist[cnt];
- (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr, NULL);
VN_RELE(vp);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index 4857af785b..c830396935 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -922,7 +922,8 @@ do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
/*
* Get the vnode for the component "nm".
*/
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr);
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL);
if (error)
return (puterrno4(error));
@@ -1253,7 +1254,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* as well be reflected to the server during the open.
*/
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return;
@@ -1283,7 +1284,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (args->access & ACCESS4_READ) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode) &&
(!is_system_labeled() || admin_low_client ||
bldominates(clabel, slabel)))
@@ -1291,7 +1292,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
resp->supported |= ACCESS4_READ;
}
if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error && (!is_system_labeled() || admin_low_client ||
bldominates(clabel, slabel)))
resp->access |= ACCESS4_LOOKUP;
@@ -1299,7 +1300,7 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (checkwriteperm &&
(args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode) &&
(!is_system_labeled() || admin_low_client ||
blequal(clabel, slabel)))
@@ -1310,14 +1311,14 @@ rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (checkwriteperm &&
(args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error && (!is_system_labeled() || admin_low_client ||
blequal(clabel, slabel)))
resp->access |= ACCESS4_DELETE;
resp->supported |= ACCESS4_DELETE;
}
if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode) &&
(!is_system_labeled() || admin_low_client ||
bldominates(clabel, slabel)))
@@ -1358,7 +1359,7 @@ rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
va.va_mask = AT_UID;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
/*
* If we can't get the attributes, then we can't do the
@@ -1383,14 +1384,14 @@ rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (crgetuid(cr) != va.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr))) {
+ (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) {
*cs->statusp = resp->status = puterrno4(error);
return;
}
- error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr);
+ error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
if (!error)
- error = VOP_FSYNC(vp, FNODSYNC, cr);
+ error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -1455,7 +1456,7 @@ do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req,
mode = 0;
- error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0);
+ error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return (NULL);
@@ -1571,7 +1572,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get "before" change value */
bva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bva, 0, cr);
+ error = VOP_GETATTR(dvp, &bva, 0, cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
kmem_free(nm, len);
@@ -1604,7 +1605,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
vap->va_mode = 0700; /* default: owner rwx only */
vap->va_mask |= AT_MODE;
}
- error = VOP_MKDIR(dvp, nm, vap, &vp, cr);
+ error = VOP_MKDIR(dvp, nm, vap, &vp, cr, NULL, 0, NULL);
if (error)
break;
@@ -1613,7 +1614,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* set to zero
*/
iva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
iva.va_seq = 0;
break;
case NF4LNK:
@@ -1645,7 +1646,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
return;
}
- error = VOP_SYMLINK(dvp, nm, vap, lnm, cr);
+ error = VOP_SYMLINK(dvp, nm, vap, lnm, cr, NULL, 0);
if (lnm != NULL)
kmem_free(lnm, llen);
if (error)
@@ -1656,10 +1657,11 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* set to zero
*/
iva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
iva.va_seq = 0;
- error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
break;
@@ -1668,7 +1670,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* if it has changed zero out iva to force atomic = FALSE.
*/
iva2.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva2, 0, cs->cr) ||
+ if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) ||
iva2.va_seq != iva.va_seq)
iva.va_seq = 0;
break;
@@ -1698,7 +1700,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* set to zero
*/
iva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
iva.va_seq = 0;
break;
@@ -1712,7 +1714,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
if (resp->status != NFS4_OK) {
if (vp != NULL)
@@ -1728,7 +1730,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* before value.
*/
ava.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &ava, 0, cr)) {
+ if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) {
ava.va_ctime = bva.va_ctime;
ava.va_seq = 0;
}
@@ -1774,7 +1776,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
else
resp->cinfo.atomic = FALSE;
- (void) VOP_FSYNC(vp, syncval, cr);
+ (void) VOP_FSYNC(vp, syncval, cr, NULL);
if (resp->status != NFS4_OK) {
VN_RELE(vp);
@@ -2357,7 +2359,7 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get "before" change value */
bdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bdva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
kmem_free(nm, len);
@@ -2366,7 +2368,7 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
- error = VOP_LINK(dvp, vp, nm, cs->cr);
+ error = VOP_LINK(dvp, vp, nm, cs->cr, NULL, 0);
kmem_free(nm, len);
@@ -2374,14 +2376,14 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* Get the initial "after" sequence number, if it fails, set to zero
*/
idva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &idva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
idva.va_seq = 0;
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cs->cr);
- (void) VOP_FSYNC(dvp, 0, cs->cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
+ (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -2393,7 +2395,7 @@ rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* before value.
*/
adva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &adva, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
adva.va_ctime = bdva.va_ctime;
adva.va_seq = 0;
}
@@ -2484,7 +2486,8 @@ do_rfs4_op_lookup(char *nm, uint_t buflen, struct svc_req *req,
}
}
- error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr);
+ error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL);
if (error)
return (puterrno4(error));
@@ -2806,14 +2809,15 @@ rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* checks from copen).
*/
- if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0) {
+ if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 &&
+ !vfs_has_feature(cs->vp->v_vfsp, VFSFT_XVATTR)) {
error = ENOTSUP;
goto error_out;
}
- if ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr) != 0) &&
- (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr) != 0) &&
- (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr) != 0)) {
+ if ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) &&
+ (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr, NULL) != 0) &&
+ (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr, NULL) != 0)) {
error = EACCES;
goto error_out;
}
@@ -2835,7 +2839,8 @@ rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (args->createdir && ! (exp_ro = rdonly4(cs->exi, cs->vp, req)))
lookup_flags |= CREATE_XATTR_DIR;
- error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr);
+ error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr,
+ NULL, NULL, NULL);
if (error) {
if (error == ENOENT && args->createdir && exp_ro)
@@ -2873,12 +2878,12 @@ error_out:
}
static int
-do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred)
+do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred,
+ caller_context_t *ct)
{
int error;
int i;
clock_t delaytime;
- caller_context_t ct;
delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
@@ -2888,21 +2893,17 @@ do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred)
*/
uio->uio_fmode = FNONBLOCK;
- ct.cc_sysid = 0;
- ct.cc_pid = 0;
- ct.cc_caller_id = nfs4_srv_caller_id;
-
for (i = 0; i < rfs4_maxlock_tries; i++) {
if (direction == FREAD) {
- (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
- error = VOP_READ(vp, uio, ioflag, cred, &ct);
- VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, ct);
+ error = VOP_READ(vp, uio, ioflag, cred, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, ct);
} else {
- (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
- error = VOP_WRITE(vp, uio, ioflag, cred, &ct);
- VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, ct);
+ error = VOP_WRITE(vp, uio, ioflag, cred, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, ct);
}
if (error != EAGAIN)
@@ -2936,6 +2937,7 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
int in_crit = 0;
mblk_t *mp;
int alloc_err = 0;
+ caller_context_t ct;
vp = cs->vp;
if (vp == NULL) {
@@ -2947,6 +2949,12 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
return;
}
+ if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
+ deleg, TRUE, &ct)) != NFS4_OK) {
+ *cs->statusp = resp->status = stat;
+ goto out;
+ }
+
/*
* Enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with write requests.
@@ -2954,20 +2962,21 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0)) {
+ if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
+ &ct)) {
*cs->statusp = resp->status = NFS4ERR_LOCKED;
goto out;
}
}
if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
- deleg, TRUE)) != NFS4_OK) {
+ deleg, TRUE, &ct)) != NFS4_OK) {
*cs->statusp = resp->status = stat;
goto out;
}
va.va_mask = AT_MODE|AT_SIZE|AT_UID;
- verror = VOP_GETATTR(vp, &va, 0, cs->cr);
+ verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
/*
* If we can't get the attributes, then we can't do the
@@ -2985,8 +2994,8 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (crgetuid(cs->cr) != va.va_uid &&
- (error = VOP_ACCESS(vp, VREAD, 0, cs->cr)) &&
- (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr))) {
+ (error = VOP_ACCESS(vp, VREAD, 0, cs->cr, &ct)) &&
+ (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr, &ct))) {
*cs->statusp = resp->status = puterrno4(error);
goto out;
}
@@ -3051,10 +3060,10 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
uio.uio_loffset = args->offset;
uio.uio_resid = args->count;
- error = do_io(FREAD, vp, &uio, 0, cs->cr);
+ error = do_io(FREAD, vp, &uio, 0, cs->cr, &ct);
va.va_mask = AT_SIZE;
- verror = VOP_GETATTR(vp, &va, 0, cs->cr);
+ verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
if (error) {
freeb(mp);
@@ -3477,7 +3486,7 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cs->cr);
+ error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return;
@@ -3499,7 +3508,7 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
uio.uio_loffset = 0;
uio.uio_resid = MAXPATHLEN;
- error = VOP_READLINK(vp, &uio, cs->cr);
+ error = VOP_READLINK(vp, &uio, cs->cr, NULL);
if (error) {
kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
@@ -3683,7 +3692,8 @@ rfs4_lookup_and_findfile(vnode_t *dvp, char *nm, vnode_t **vpp,
if (vpp)
*vpp = NULL;
- if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr)) == 0) {
+ if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr, NULL, NULL,
+ NULL)) == 0) {
if (vp->v_type == VREG)
fp = rfs4_findfile(vp, NULL, &fcreate);
if (vpp)
@@ -3799,7 +3809,7 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
kmem_free(nm, len);
nbl_end_crit(vp);
@@ -3837,7 +3847,7 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get dir "before" change value */
bdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bdva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
kmem_free(nm, len);
@@ -3860,12 +3870,12 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* NFS4ERR_EXIST to NFS4ERR_NOTEMPTY to
* transmit over the wire.
*/
- if ((error = VOP_RMDIR(dvp, nm, rootdir, cs->cr))
- == EEXIST)
+ if ((error = VOP_RMDIR(dvp, nm, rootdir, cs->cr,
+ NULL, 0)) == EEXIST)
error = ENOTEMPTY;
}
} else {
- if ((error = VOP_REMOVE(dvp, nm, cs->cr)) == 0 &&
+ if ((error = VOP_REMOVE(dvp, nm, cs->cr, NULL, 0)) == 0 &&
fp != NULL) {
struct vattr va;
vnode_t *tvp;
@@ -3882,7 +3892,7 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* manipulating dvp.
*/
va.va_mask = AT_NLINK;
- if (!VOP_GETATTR(tvp, &va, 0, cs->cr) &&
+ if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
va.va_nlink == 0) {
/* Remove state on file remove */
if (in_crit) {
@@ -3915,20 +3925,20 @@ rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* Get the initial "after" sequence number, if it fails, set to zero
*/
idva.va_mask = AT_SEQ;
- if (VOP_GETATTR(dvp, &idva, 0, cs->cr))
+ if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
idva.va_seq = 0;
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cs->cr);
+ (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
/*
* Get "after" change value, if it fails, simply return the
* before value.
*/
adva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &adva, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
adva.va_ctime = bdva.va_ctime;
adva.va_seq = 0;
}
@@ -4120,7 +4130,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (nbl_need_check(srcvp)) {
nbl_start_crit(srcvp, RW_READER);
in_crit_src = 1;
- if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) {
+ if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
goto err_out;
}
@@ -4129,7 +4139,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (targvp && nbl_need_check(targvp)) {
nbl_start_crit(targvp, RW_READER);
in_crit_targ = 1;
- if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
goto err_out;
}
@@ -4137,10 +4147,10 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/* Get source "before" change value */
obdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(odvp, &obdva, 0, cs->cr);
+ error = VOP_GETATTR(odvp, &obdva, 0, cs->cr, NULL);
if (!error) {
nbdva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr);
+ error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr, NULL);
}
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -4150,7 +4160,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.before, obdva.va_ctime)
NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.before, nbdva.va_ctime)
- if ((error = VOP_RENAME(odvp, onm, ndvp, nnm, cs->cr)) == 0 &&
+ if ((error = VOP_RENAME(odvp, onm, ndvp, nnm, cs->cr, NULL, 0)) == 0 &&
fp != NULL) {
struct vattr va;
vnode_t *tvp;
@@ -4163,7 +4173,7 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
if (tvp) {
va.va_mask = AT_NLINK;
- if (!VOP_GETATTR(tvp, &va, 0, cs->cr) &&
+ if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
va.va_nlink == 0) {
/* The file is gone and so should the state */
if (in_crit_targ) {
@@ -4213,18 +4223,18 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* Get the initial "after" sequence number, if it fails, set to zero
*/
oidva.va_mask = AT_SEQ;
- if (VOP_GETATTR(odvp, &oidva, 0, cs->cr))
+ if (VOP_GETATTR(odvp, &oidva, 0, cs->cr, NULL))
oidva.va_seq = 0;
nidva.va_mask = AT_SEQ;
- if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr))
+ if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr, NULL))
nidva.va_seq = 0;
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(odvp, 0, cs->cr);
- (void) VOP_FSYNC(ndvp, 0, cs->cr);
+ (void) VOP_FSYNC(odvp, 0, cs->cr, NULL);
+ (void) VOP_FSYNC(ndvp, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
@@ -4236,13 +4246,13 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
* before value.
*/
oadva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(odvp, &oadva, 0, cs->cr)) {
+ if (VOP_GETATTR(odvp, &oadva, 0, cs->cr, NULL)) {
oadva.va_ctime = obdva.va_ctime;
oadva.va_seq = 0;
}
nadva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(odvp, &nadva, 0, cs->cr)) {
+ if (VOP_GETATTR(odvp, &nadva, 0, cs->cr, NULL)) {
nadva.va_ctime = nbdva.va_ctime;
nadva.va_seq = 0;
}
@@ -4282,7 +4292,8 @@ rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
/*
* Already know that nnm will be a valid string
*/
- error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr);
+ error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL);
kmem_free(nnm, nlen);
if (!error) {
add_volrnm_fh(cs->exi, vp);
@@ -4435,7 +4446,7 @@ rfs4_verify_attr(struct nfs4_svgetit_arg *sargp,
* on the incoming values.
*/
ret_error = VOP_GETATTR(sargp->cs->vp, sargp->vap, 0,
- sargp->cs->cr);
+ sargp->cs->cr, NULL);
if (ret_error) {
if (resp == NULL)
return (ret_error);
@@ -4710,7 +4721,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
vattr_t va;
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cs->cr);
+ error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
if (error) {
status = puterrno4(error);
goto done;
@@ -4726,15 +4737,15 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
if (sarg.vap->va_mask & AT_SIZE) {
trunc = (sarg.vap->va_size == 0);
status = rfs4_check_stateid(FWRITE, cs->vp, stateid,
- trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE);
+ trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct);
if (status != NFS4_OK)
goto done;
+ } else {
+ ct.cc_sysid = 0;
+ ct.cc_pid = 0;
+ ct.cc_caller_id = nfs4_srv_caller_id;
}
- ct.cc_sysid = 0;
- ct.cc_pid = 0;
- ct.cc_caller_id = nfs4_srv_caller_id;
-
/* XXX start of possible race with delegations */
/*
@@ -4776,7 +4787,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
}
bva.va_mask = AT_UID|AT_SIZE;
- if (error = VOP_GETATTR(vp, &bva, 0, cr)) {
+ if (error = VOP_GETATTR(vp, &bva, 0, cr, &ct)) {
status = puterrno4(error);
goto done;
}
@@ -4789,7 +4800,8 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
offset = bva.va_size;
length = sarg.vap->va_size - bva.va_size;
}
- if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
+ &ct)) {
status = NFS4ERR_LOCKED;
goto done;
}
@@ -4857,7 +4869,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
/*
* Set response bitmap
*/
@@ -5067,6 +5079,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
bool_t *deleg = &cs->deleg;
nfsstat4 stat;
int in_crit = 0;
+ caller_context_t ct;
vp = cs->vp;
if (vp == NULL) {
@@ -5080,6 +5093,12 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
cr = cs->cr;
+ if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
+ deleg, TRUE, &ct)) != NFS4_OK) {
+ *cs->statusp = resp->status = stat;
+ goto out;
+ }
+
/*
* We have to enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with ufs.
@@ -5088,20 +5107,14 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
nbl_start_crit(vp, RW_READER);
in_crit = 1;
if (nbl_conflict(vp, NBL_WRITE,
- args->offset, args->data_len, 0)) {
+ args->offset, args->data_len, 0, &ct)) {
*cs->statusp = resp->status = NFS4ERR_LOCKED;
goto out;
}
}
- if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
- deleg, TRUE)) != NFS4_OK) {
- *cs->statusp = resp->status = stat;
- goto out;
- }
-
bva.va_mask = AT_MODE | AT_UID;
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
/*
* If we can't get the attributes, then we can't do the
@@ -5124,7 +5137,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if (crgetuid(cr) != bva.va_uid &&
- (error = VOP_ACCESS(vp, VWRITE, 0, cr))) {
+ (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) {
*cs->statusp = resp->status = puterrno4(error);
goto out;
}
@@ -5210,7 +5223,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
*/
savecred = curthread->t_cred;
curthread->t_cred = cr;
- error = do_io(FWRITE, vp, &uio, ioflag, cr);
+ error = do_io(FWRITE, vp, &uio, ioflag, cr, &ct);
curthread->t_cred = savecred;
if (iovp != iov)
@@ -5478,6 +5491,8 @@ static void lock_print(char *str, int operation, struct flock64 *flk)
break;
case F_SETLK: op = "F_SETLK";
break;
+ case F_SETLK_NBMAND: op = "F_SETLK_NBMAND";
+ break;
default: op = "F_UNKNOWN";
break;
}
@@ -5562,7 +5577,7 @@ rfs4_lookupfile(component4 *component, struct svc_req *req,
/* Get "before" change value */
bva.va_mask = AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
if (error)
return (puterrno4(error));
@@ -5580,7 +5595,7 @@ rfs4_lookupfile(component4 *component, struct svc_req *req,
* before value.
*/
ava.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &ava, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
ava.va_ctime = bva.va_ctime;
ava.va_seq = 0;
}
@@ -5590,7 +5605,7 @@ rfs4_lookupfile(component4 *component, struct svc_req *req,
* Validate the file is a file
*/
fva.va_mask = AT_TYPE|AT_MODE;
- error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr);
+ error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr, NULL);
if (error)
return (puterrno4(error));
@@ -5638,7 +5653,7 @@ tryagain:
*/
*created = TRUE;
- error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0);
+ error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0, NULL, NULL);
if (error) {
*created = FALSE;
@@ -5659,7 +5674,8 @@ tryagain:
status = puterrno4(error);
return (status);
}
- error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error) {
/*
@@ -5693,7 +5709,7 @@ tryagain:
/* Check for duplicate request */
ASSERT(mtime != 0);
va.va_mask = AT_MTIME;
- error = VOP_GETATTR(*vpp, &va, 0, cr);
+ error = VOP_GETATTR(*vpp, &va, 0, cr, NULL);
if (!error) {
/* We found the file */
if (va.va_mtime.tv_sec != mtime->tv_sec ||
@@ -5740,14 +5756,14 @@ check_open_access(uint32_t access,
return (NFS4ERR_ROFS);
if (access & OPEN4_SHARE_ACCESS_READ) {
- if ((VOP_ACCESS(vp, VREAD, 0, cr) != 0) &&
- (VOP_ACCESS(vp, VEXEC, 0, cr) != 0)) {
+ if ((VOP_ACCESS(vp, VREAD, 0, cr, NULL) != 0) &&
+ (VOP_ACCESS(vp, VEXEC, 0, cr, NULL) != 0)) {
return (NFS4ERR_ACCESS);
}
}
if (access & OPEN4_SHARE_ACCESS_WRITE) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (error)
return (NFS4ERR_ACCESS);
}
@@ -5821,7 +5837,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
}
bva.va_mask = AT_TYPE|AT_CTIME|AT_SEQ;
- error = VOP_GETATTR(dvp, &bva, 0, cs->cr);
+ error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
if (error) {
kmem_free(nm, buflen);
return (puterrno4(error));
@@ -5968,7 +5984,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
* set to zero, time to before.
*/
iva.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &iva, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) {
iva.va_seq = 0;
iva.va_ctime = bva.va_ctime;
}
@@ -5992,14 +6008,14 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
* The entry was created, we need to sync the
* directory metadata.
*/
- (void) VOP_FSYNC(dvp, 0, cs->cr);
+ (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
/*
* Get "after" change value, if it fails, simply return the
* before value.
*/
ava.va_mask = AT_CTIME|AT_SEQ;
- if (VOP_GETATTR(dvp, &ava, 0, cs->cr)) {
+ if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
ava.va_ctime = bva.va_ctime;
ava.va_seq = 0;
}
@@ -6027,7 +6043,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
/* Assume the worst */
cs->mandlock = TRUE;
- if (VOP_GETATTR(vp, &cva, 0, cs->cr) == 0) {
+ if (VOP_GETATTR(vp, &cva, 0, cs->cr, NULL) == 0) {
cs->mandlock = MANDLOCK(cs->vp, cva.va_mode);
/*
@@ -6065,7 +6081,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
nbl_start_crit(vp, RW_READER);
if (nbl_conflict(vp, NBL_WRITE, 0,
- cva.va_size, 0)) {
+ cva.va_size, 0, NULL)) {
in_crit = 0;
nbl_end_crit(vp);
VN_RELE(vp);
@@ -6090,7 +6106,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cs->cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
if (error) {
VN_RELE(vp);
@@ -6127,7 +6143,7 @@ static void
rfs4_do_open(struct compound_state *cs, struct svc_req *req,
rfs4_openowner_t *oo, delegreq_t deleg,
uint32_t access, uint32_t deny,
- OPEN4res *resp)
+ OPEN4res *resp, int deleg_cur)
{
/* XXX Currently not using req */
rfs4_state_t *state;
@@ -6141,9 +6157,11 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
struct shr_locowner shr_loco;
sysid_t sysid;
nfsstat4 status;
+ caller_context_t ct;
int fflags = 0;
int recall = 0;
int err;
+ int cmd;
/* get the file struct and hold a lock on it during initial open */
file = rfs4_findfile_withlock(cs->vp, &cs->fh, &fcreate);
@@ -6175,6 +6193,12 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
return;
}
+ /* Calculate the fflags for this OPEN. */
+ if (access & OPEN4_SHARE_ACCESS_READ)
+ fflags |= FREAD;
+ if (access & OPEN4_SHARE_ACCESS_WRITE)
+ fflags |= FWRITE;
+
/*
* Calculate the new deny and access mode that this open is adding to
* the file for this open owner;
@@ -6203,13 +6227,8 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
shr.s_owner = (caddr_t)&shr_loco;
shr.s_own_len = sizeof (shr_loco);
- fflags = 0;
- if (access & OPEN4_SHARE_ACCESS_READ)
- fflags |= FREAD;
- if (access & OPEN4_SHARE_ACCESS_WRITE)
- fflags |= FWRITE;
-
- if ((err = vop_shrlock(cs->vp, F_SHARE, &shr, fflags)) != 0) {
+ cmd = nbl_need_check(cs->vp) ? F_SHARE_NBMAND : F_SHARE;
+ if ((err = vop_shrlock(cs->vp, cmd, &shr, fflags)) != 0) {
resp->status = err == EAGAIN ?
NFS4ERR_SHARE_DENIED : puterrno4(err);
@@ -6243,12 +6262,6 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
rfs4_dbe_unlock(state->dbe);
rfs4_file_rele(file);
rfs4_update_lease(state->owner->client);
- /* recalculate flags to match what was added */
- fflags = 0;
- if (amodes & OPEN4_SHARE_ACCESS_READ)
- fflags |= FREAD;
- if (amodes & OPEN4_SHARE_ACCESS_WRITE)
- fflags |= FWRITE;
(void) vop_shrlock(cs->vp, F_UNSHARE, &shr, fflags);
/* Not a fully formed open; "close" it */
if (screate == TRUE)
@@ -6258,6 +6271,49 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
return;
}
}
+ /*
+ * the share check passed and any delegation conflict has been
+ * taken care of, now call vop_open.
+ * if this is the first open then call vop_open with fflags.
+ * if not, call vn_open_upgrade with just the upgrade flags.
+ *
+ * if the file has been opened already, it will have the current
+ * access mode in the state struct. if it has no share access, then
+ * this is a new open.
+ *
+ * However, if this is open with CLAIM_DLEGATE_CUR, then don't
+ * call VOP_OPEN(), just do the open upgrade.
+ */
+ if (((state->share_access & OPEN4_SHARE_ACCESS_BOTH) == 0) &&
+ !deleg_cur) {
+ ct.cc_sysid = sysid;
+ ct.cc_pid = shr.s_pid;
+ ct.cc_caller_id = nfs4_srv_caller_id;
+ err = VOP_OPEN(&cs->vp, fflags, cs->cr, &ct);
+ if (err) {
+ rfs4_dbe_unlock(file->dbe);
+ rfs4_dbe_unlock(state->dbe);
+ rfs4_file_rele(file);
+ (void) vop_shrlock(cs->vp, F_UNSHARE, &shr, fflags);
+ /* Not a fully formed open; "close" it */
+ if (screate == TRUE)
+ rfs4_state_close(state, FALSE, FALSE, cs->cr);
+ rfs4_state_rele(state);
+ resp->status = NFS4ERR_SERVERFAULT;
+ return;
+ }
+ } else { /* open upgrade */
+ /*
+ * calculate the fflags for the new mode that is being added
+ * by this upgrade.
+ */
+ fflags = 0;
+ if (amodes & OPEN4_SHARE_ACCESS_READ)
+ fflags |= FREAD;
+ if (amodes & OPEN4_SHARE_ACCESS_WRITE)
+ fflags |= FWRITE;
+ vn_open_upgrade(cs->vp, fflags);
+ }
if (dmodes & OPEN4_SHARE_DENY_READ)
file->deny_read++;
@@ -6328,7 +6384,7 @@ rfs4_do_opennull(struct compound_state *cs, struct svc_req *req,
/* cs->vp cs->fh now reference the desired file */
rfs4_do_open(cs, req, oo, DELEG_ANY, args->share_access,
- args->share_deny, resp);
+ args->share_deny, resp, 0);
/*
* If rfs4_createfile set attrset, we must
@@ -6367,7 +6423,7 @@ rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
}
va.va_mask = AT_MODE|AT_UID;
- error = VOP_GETATTR(cs->vp, &va, 0, cs->cr);
+ error = VOP_GETATTR(cs->vp, &va, 0, cs->cr, NULL);
if (error) {
resp->status = puterrno4(error);
return;
@@ -6398,7 +6454,7 @@ rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
rfs4_do_open(cs, req, oo,
NFS4_DELEG4TYPE2REQTYPE(args->open_claim4_u.delegate_type),
- args->share_access, args->share_deny, resp);
+ args->share_access, args->share_deny, resp, 0);
}
static void
@@ -6452,7 +6508,7 @@ rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req,
dsp->finfo->dinfo->time_lastwrite = gethrestime_sec();
rfs4_deleg_state_rele(dsp);
rfs4_do_open(cs, req, oo, DELEG_NONE,
- args->share_access, args->share_deny, resp);
+ args->share_access, args->share_deny, resp, 1);
}
/*ARGSUSED*/
@@ -7043,6 +7099,7 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
nfsstat4 status;
rfs4_state_t *sp;
rfs4_file_t *fp;
+ int fflags = 0;
if (cs->vp == NULL) {
*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
@@ -7121,7 +7178,7 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
* Check that no invalid bits are set.
*/
if ((access & ~(OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) ||
- (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_READ))) {
+ (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_WRITE))) {
*cs->statusp = resp->status = NFS4ERR_INVAL;
rfs4_update_open_sequence(sp->owner);
rfs4_dbe_unlock(sp->dbe);
@@ -7193,26 +7250,30 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
* If the current mode has access read and the new mode
* does not, decrement the number of access read mode bits
* and if it goes to zero turn off the access read bit
- * on the file.
+ * on the file. set fflags to FREAD for the call to
+ * vn_open_downgrade().
*/
if ((sp->share_access & OPEN4_SHARE_ACCESS_READ) &&
(access & OPEN4_SHARE_ACCESS_READ) == 0) {
fp->access_read--;
if (fp->access_read == 0)
fp->share_access &= ~OPEN4_SHARE_ACCESS_READ;
+ fflags |= FREAD;
}
/*
* If the current mode has access write and the new mode
* does not, decrement the number of access write mode bits
* and if it goes to zero turn off the access write bit
- * on the file.
+ * on the file. set fflags to FWRITE for the call to
+ * vn_open_downgrade().
*/
if ((sp->share_access & OPEN4_SHARE_ACCESS_WRITE) &&
(access & OPEN4_SHARE_ACCESS_WRITE) == 0) {
fp->access_write--;
if (fp->access_write == 0)
fp->share_deny &= ~OPEN4_SHARE_ACCESS_WRITE;
+ fflags |= FWRITE;
}
/* Set the new access and deny modes */
@@ -7224,12 +7285,21 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
rfs4_dbe_unlock(fp->dbe);
rfs4_dbe_unlock(sp->dbe);
+
if ((status = rfs4_share(sp)) != NFS4_OK) {
*cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
rfs4_update_open_sequence(sp->owner);
goto end;
}
+ /*
+ * we successfully downgraded the share lock, now we need to downgrade
+ * the open. it is possible that the downgrade was only for a deny
+ * mode and we have nothing else to do.
+ */
+ if ((fflags & (FREAD|FWRITE)) != 0)
+ vn_open_downgrade(cs->vp, fflags);
+
rfs4_dbe_lock(sp->dbe);
/* Update the stateid */
@@ -7719,7 +7789,7 @@ rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr,
flk.l_pid = 0;
(void) VOP_FRLOCK(sp->finfo->vp, F_SETLK, &flk,
F_REMOTELOCK | FREAD | FWRITE,
- (u_offset_t)0, NULL, CRED());
+ (u_offset_t)0, NULL, CRED(), NULL);
}
sp->owner->client->unlksys_completed = TRUE;
@@ -7757,6 +7827,8 @@ rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr,
shr.s_own_len = sizeof (shr_loco);
(void) vop_shrlock(sp->finfo->vp, F_UNSHARE, &shr, fflags);
}
+
+ (void) VOP_CLOSE(fp->vp, fflags, 1, (offset_t)0, cr, NULL);
}
/*
@@ -7819,14 +7891,16 @@ setlock(vnode_t *vp, struct flock64 *flock, int flag, cred_t *cred)
struct flock64 flk;
int i;
clock_t delaytime;
+ int cmd;
+ cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
retry:
delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
for (i = 0; i < rfs4_maxlock_tries; i++) {
- LOCK_PRINT(rfs4_debug, "setlock", F_SETLK, flock);
- error = VOP_FRLOCK(vp, F_SETLK,
- flock, flag, (u_offset_t)0, NULL, cred);
+ LOCK_PRINT(rfs4_debug, "setlock", cmd, flock);
+ error = VOP_FRLOCK(vp, cmd,
+ flock, flag, (u_offset_t)0, NULL, cred, NULL);
if (error != EAGAIN && error != EACCES)
break;
@@ -7841,8 +7915,8 @@ retry:
/* Get the owner of the lock */
flk = *flock;
LOCK_PRINT(rfs4_debug, "setlock", F_GETLK, &flk);
- if (VOP_FRLOCK(vp, F_GETLK,
- &flk, flag, (u_offset_t)0, NULL, cred) == 0) {
+ if (VOP_FRLOCK(vp, F_GETLK, &flk, flag,
+ (u_offset_t)0, NULL, cred, NULL) == 0) {
if (flk.l_type == F_UNLCK) {
/* No longer locked, retry */
goto retry;
@@ -8618,7 +8692,7 @@ retry:
goto out;
}
error = VOP_FRLOCK(cs->vp, F_GETLK, &flk, flag, (u_offset_t)0,
- NULL, cs->cr);
+ NULL, cs->cr, NULL);
/*
* N.B. We map error values to nfsv4 errors. This is differrent
@@ -8661,11 +8735,11 @@ vop_shrlock(vnode_t *vp, int cmd, struct shrlock *sp, int fflags)
if (cmd == F_UNSHARE && sp->s_deny == 0 && sp->s_access == 0)
return (0);
- err = VOP_SHRLOCK(vp, cmd, sp, fflags, CRED());
+ err = VOP_SHRLOCK(vp, cmd, sp, fflags, CRED(), NULL);
NFS4_DEBUG(rfs4_shrlock_debug,
(CE_NOTE, "rfs4_shrlock %s vp=%p acc=%d dny=%d sysid=%d "
- "pid=%d err=%d\n", cmd == F_SHARE ? "SHARE" : "UNSHR",
+ "pid=%d err=%d\n", cmd == F_UNSHARE ? "UNSHR" : "SHARE",
(void *) vp, sp->s_access, sp->s_deny, sp->s_sysid, sp->s_pid,
err));
@@ -8706,7 +8780,9 @@ rfs4_shrlock(rfs4_state_t *sp, int cmd)
static int
rfs4_share(rfs4_state_t *sp)
{
- return (rfs4_shrlock(sp, F_SHARE));
+ int cmd;
+ cmd = nbl_need_check(sp->finfo->vp) ? F_SHARE_NBMAND : F_SHARE;
+ return (rfs4_shrlock(sp, cmd));
}
void
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
index 9b5d9e2301..11a940f199 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,7 +37,7 @@ void rfs4_init_compound_state(struct compound_state *);
bitmap4 rfs4_supported_attrs;
int MSG_PRT_DEBUG = FALSE;
-/* If building with DEBUG enabled, enable mandattr tuneable by default */
+/* If building with DEBUG enabled, enable mandattr tunable by default */
#ifdef DEBUG
#ifndef RFS4_SUPPORT_MANDATTR_ONLY
#define RFS4_SUPPORT_MANDATTR_ONLY
@@ -575,7 +575,7 @@ rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
*/
if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
error = VOP_PATHCONF(sarg->cs->vp, _PC_XATTR_EXISTS,
- &val, sarg->cs->cr);
+ &val, sarg->cs->cr, NULL);
if (error)
break;
} else
@@ -592,7 +592,7 @@ rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
ASSERT(sarg->cs->vp != NULL);
if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
error = VOP_PATHCONF(sarg->cs->vp, _PC_XATTR_EXISTS,
- &val, sarg->cs->cr);
+ &val, sarg->cs->cr, NULL);
if (error)
break;
} else
@@ -863,7 +863,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* see which ACLs fs supports */
error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error != 0) {
/*
* If we got an error, then the filesystem
@@ -902,7 +902,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* get the ACL, and translate it into nfsace4 style */
error = VOP_GETSECATTR(vp, &vs_native,
- 0, sarg->cs->cr);
+ 0, sarg->cs->cr, NULL);
if (error != 0)
break;
if (whichacl & _ACL_ACE_ENABLED) {
@@ -942,7 +942,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
-
+ vs_ace4.vsa_aclentsz = vs_ace4.vsa_aclcnt * sizeof (ace_t);
/* make sure we have correct owner/group */
if ((vap->va_mask & (AT_UID | AT_GID)) !=
(AT_UID | AT_GID)) {
@@ -956,7 +956,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* see which ACLs the fs supports */
error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error != 0) {
/*
* If we got an error, then the filesystem
@@ -991,7 +991,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
break;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(vp, &vs_native,
- 0, sarg->cs->cr);
+ 0, sarg->cs->cr, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
vs_acet_destroy(&vs_native);
} else if (whichacl & _ACL_ACLENT_ENABLED) {
@@ -1002,7 +1002,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
break;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
error = VOP_SETSECATTR(vp, &vs_native,
- 0, sarg->cs->cr);
+ 0, sarg->cs->cr, NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
vs_aent_destroy(&vs_native);
}
@@ -1097,7 +1097,7 @@ rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/*
* XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
- * case insenstive.
+ * case insensitive.
*/
/* ARGSUSED */
static int
@@ -1191,7 +1191,7 @@ rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp,
- _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
+ _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
if (error)
break;
@@ -1206,7 +1206,7 @@ rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp,
- _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
+ _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
if (error)
break;
if (na->chown_restricted != (val == 1))
@@ -1559,7 +1559,7 @@ rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error)
break;
if (val >= (sizeof (uint64_t) * 8))
@@ -1576,7 +1576,7 @@ rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error)
break;
if (val >= (sizeof (uint64_t) * 8))
@@ -1615,7 +1615,7 @@ rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error == 0) {
na->maxlink = val;
}
@@ -1629,7 +1629,7 @@ rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (!error && (na->maxlink != (uint32_t)val))
error = -1; /* no match */
break;
@@ -1662,7 +1662,7 @@ rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
}
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (error == 0) {
na->maxname = val;
}
@@ -1676,7 +1676,7 @@ rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
case NFS4ATTR_VERIT:
ASSERT(sarg->cs->vp != NULL);
error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
- sarg->cs->cr);
+ sarg->cs->cr, NULL);
if (!error && (na->maxname != val))
error = -1; /* no match */
break;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c b/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
index 691711e5a5..4c150e248f 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
@@ -805,7 +805,7 @@ rfs4_vop_getattr(vnode_t *vp, vattr_t *vap, int flag, cred_t *cr)
int error;
mask = vap->va_mask;
- error = VOP_GETATTR(vp, vap, flag, cr);
+ error = VOP_GETATTR(vp, vap, flag, cr, NULL);
/*
* Some file systems clobber va_mask. it is probably wrong of
* them to do so, nonethless we practice defensive coding.
@@ -825,7 +825,7 @@ rfs4_vop_getattr(vnode_t *vp, vattr_t *vap, int flag, cred_t *cr)
int
rfs4_delegated_getattr(vnode_t *vp, vattr_t *vap, int flag, cred_t *cr)
{
- return (VOP_GETATTR(vp, vap, flag, cr));
+ return (VOP_GETATTR(vp, vap, flag, cr, NULL));
}
/*
@@ -1547,6 +1547,8 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
rfs4_deleg_state_t *dsp;
vnode_t *vp;
int open_prev = *recall;
+ int ret;
+ int fflags = 0;
ASSERT(rfs4_dbe_islocked(sp->dbe));
ASSERT(rfs4_dbe_islocked(fp->dbe));
@@ -1605,14 +1607,27 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
vp = fp->vp;
/* vnevent_support returns 0 if file system supports vnevents */
- if (vnevent_support(vp)) {
+ if (vnevent_support(vp, NULL)) {
rfs4_deleg_state_rele(dsp);
return (NULL);
}
+ /* Calculate the fflags for this OPEN. */
+ if (sp->share_access & OPEN4_SHARE_ACCESS_READ)
+ fflags |= FREAD;
+ if (sp->share_access & OPEN4_SHARE_ACCESS_WRITE)
+ fflags |= FWRITE;
+
*recall = 0;
+ /*
+ * Before granting a delegation we need to know if anyone else has
+ * opened the file in a conflicting mode. However, first we need to
+ * know how we opened the file to check the counts properly.
+ */
if (dtype == OPEN_DELEGATE_READ) {
- if (vn_is_opened(vp, V_WRITE) || vn_is_mapped(vp, V_WRITE)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ vn_is_mapped(vp, V_WRITE)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1620,9 +1635,11 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
- (void) fem_install(vp, deleg_rdops, (void *)fp, OPUNIQ,
+ ret = fem_install(vp, deleg_rdops, (void *)fp, OPUNIQ,
rfs4_mon_hold, rfs4_mon_rele);
- if (vn_is_opened(vp, V_WRITE) || vn_is_mapped(vp, V_WRITE)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ vn_is_mapped(vp, V_WRITE)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1632,8 +1649,24 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
+ /*
+ * Because a client can hold onto a delegation after the
+ * file has been closed, we need to keep track of the
+ * access to this file. Otherwise the CIFS server would
+ * not know about the client accessing the file and could
+ * inappropriately grant an OPLOCK.
+ * fem_install() returns EBUSY when asked to install a
+ * OPUNIQ monitor more than once. Therefore, check the
+ * return code because we only want this done once.
+ */
+ if (ret == 0)
+ vn_open_upgrade(vp, FREAD);
} else { /* WRITE */
- if (vn_is_opened(vp, V_RDORWR) || vn_is_mapped(vp, V_RDORWR)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ ((fflags & FREAD) && vn_has_other_opens(vp, V_READ)) ||
+ (((fflags & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
+ vn_is_mapped(vp, V_RDORWR)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1641,9 +1674,13 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
- (void) fem_install(vp, deleg_wrops, (void *)fp, OPUNIQ,
+ ret = fem_install(vp, deleg_wrops, (void *)fp, OPUNIQ,
rfs4_mon_hold, rfs4_mon_rele);
- if (vn_is_opened(vp, V_RDORWR) || vn_is_mapped(vp, V_RDORWR)) {
+ if (((fflags & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
+ (((fflags & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
+ ((fflags & FREAD) && vn_has_other_opens(vp, V_READ)) ||
+ (((fflags & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
+ vn_is_mapped(vp, V_RDORWR)) {
if (open_prev) {
*recall = 1;
} else {
@@ -1653,6 +1690,18 @@ rfs4_deleg_state(rfs4_state_t *sp, open_delegation_type4 dtype, int *recall)
return (NULL);
}
}
+ /*
+ * Because a client can hold onto a delegation after the
+ * file has been closed, we need to keep track of the
+ * access to this file. Otherwise the CIFS server would
+ * not know about the client accessing the file and could
+ * inappropriately grant an OPLOCK.
+ * fem_install() returns EBUSY when asked to install a
+ * OPUNIQ monitor more than once. Therefore, check the
+ * return code because we only want this done once.
+ */
+ if (ret == 0)
+ vn_open_upgrade(vp, FREAD|FWRITE);
}
/* Place on delegation list for file */
insque(&dsp->delegationlist, fp->delegationlist.prev);
@@ -1697,12 +1746,22 @@ rfs4_return_deleg(rfs4_deleg_state_t *dsp, bool_t revoked)
/* if file system was unshared, the vp will be NULL */
if (fp->vp != NULL) {
- if (dtypewas == OPEN_DELEGATE_READ)
+ /*
+ * Once a delegation is no longer held by any client,
+ * the monitor is uninstalled. At this point, the
+ * client must send OPEN otw, so we don't need the
+ * reference on the vnode anymore. The open
+ * downgrade removes the reference put on earlier.
+ */
+ if (dtypewas == OPEN_DELEGATE_READ) {
(void) fem_uninstall(fp->vp, deleg_rdops,
(void *)fp);
- else
+ vn_open_downgrade(fp->vp, FREAD);
+ } else if (dtypewas == OPEN_DELEGATE_WRITE) {
(void) fem_uninstall(fp->vp, deleg_wrops,
(void *)fp);
+ vn_open_downgrade(fp->vp, FREAD|FWRITE);
+ }
}
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
index 2d3cd81fba..d10f010be0 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
@@ -53,7 +53,7 @@ vop_fid_pseudo(vnode_t *vp, fid_t *fidp)
struct vattr va;
int error;
- error = VOP_FID(vp, fidp);
+ error = VOP_FID(vp, fidp, NULL);
/*
* XXX nfs4_fid() does nothing and returns EREMOTE.
@@ -68,7 +68,7 @@ vop_fid_pseudo(vnode_t *vp, fid_t *fidp)
(error == 0 && fidp->fid_len > NFS_FH4MAXDATA)) {
va.va_mask = AT_NODEID;
- error = VOP_GETATTR(vp, &va, 0, CRED());
+ error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
if (error)
return (error);
@@ -449,7 +449,7 @@ less_visible(struct exportinfo *exi, struct exp_visible *vis_head)
* PSEUDO - a pseudo node
* vis - visible list
* f# - security flavor#
- * (f#) - security flavor# propagated from its decendents
+ * (f#) - security flavor# propagated from its descendents
* "" - covered vnode
*
*
@@ -557,7 +557,7 @@ treeclimb_export(struct exportinfo *exip)
* for this vnode.
*/
va.va_mask = AT_NODEID;
- error = VOP_GETATTR(vp, &va, 0, CRED());
+ error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
if (error)
break;
@@ -579,7 +579,8 @@ treeclimb_export(struct exportinfo *exip)
/*
* Now, do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == ENOTDIR && exportdir) {
dvp = exip->exi_dvp;
@@ -709,7 +710,8 @@ treeclimb_unexport(struct exportinfo *exip)
/*
* Do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == ENOTDIR && exportdir) {
dvp = exip->exi_dvp;
@@ -813,7 +815,8 @@ get_root_export(struct exportinfo *exip)
/*
* Now, do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error) {
exi = NULL;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
index 70852fbbe0..3f810b96b3 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -115,7 +114,8 @@ nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
*vpp = vp = NULL;
- if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr))
+ if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr,
+ NULL, NULL, NULL))
return (error);
/* Is this object mounted upon? */
@@ -152,7 +152,7 @@ nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
* etc.), then return attrs for stub instead of VROOT object.
* If it fails for any other reason, then return the error.
*/
- if (error = VOP_FID(vp, &fid)) {
+ if (error = VOP_FID(vp, &fid, NULL)) {
if (ismntpt == 0) {
VN_RELE(vp);
return (error);
@@ -232,7 +232,8 @@ rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr)
if (ar & FATTR4_MAXFILESIZE_MASK) {
/* Maximum File Size */
- if (error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr,
+ NULL))
return (error);
if (pc_val >= (sizeof (uint64_t) * 8))
@@ -243,7 +244,7 @@ rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr)
if (ar & FATTR4_MAXLINK_MASK) {
/* Maximum Link Count */
- if (error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr, NULL))
return (error);
pce->maxlink = pc_val;
@@ -251,7 +252,7 @@ rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr)
if (ar & FATTR4_MAXNAME_MASK) {
/* Maximum Name Length */
- if (error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr, NULL))
return (error);
pce->maxname = pc_val;
@@ -441,7 +442,7 @@ rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop,
return;
}
- error = VOP_ACCESS(dvp, VREAD, 0, cs->cr);
+ error = VOP_ACCESS(dvp, VREAD, 0, cs->cr, NULL);
if (error) {
*cs->statusp = resp->status = puterrno4(error);
return;
@@ -610,7 +611,7 @@ readagain:
(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir);
+ error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
@@ -788,7 +789,7 @@ reencode_attrs:
} else {
va.va_mask = AT_ALL;
rddirattr_error =
- VOP_GETATTR(vp, &va, 0, cs->cr);
+ VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
if (rddirattr_error)
ae = ar & (FATTR4_RDATTR_ERROR_MASK |
FATTR4_MOUNTED_ON_FILEID_MASK);
@@ -877,7 +878,7 @@ reencode_attrs:
} else {
(void) VOP_PATHCONF(vp,
_PC_XATTR_EXISTS,
- &pc_val, cs->cr);
+ &pc_val, cs->cr, NULL);
}
isit = (pc_val ? TRUE : FALSE);
IXDR_PUT_U_INT32(ptr, isit);
@@ -965,7 +966,7 @@ reencode_attrs:
pc_val = FALSE;
(void) VOP_PATHCONF(vp,
_PC_CHOWN_RESTRICTED,
- &pc_val, cs->cr);
+ &pc_val, cs->cr, NULL);
isit = (pc_val ? TRUE : FALSE);
IXDR_PUT_U_INT32(ptr, isit);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_state.c b/usr/src/uts/common/fs/nfs/nfs4_state.c
index 2674fa8de7..5417ab3326 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_state.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_state.c
@@ -41,6 +41,7 @@
#include <sys/sdt.h>
#include <sys/nvpair.h>
+extern u_longlong_t nfs4_srv_caller_id;
extern time_t rfs4_start_time;
extern uint_t nfs4_srv_vkey;
@@ -493,17 +494,17 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
}
if (vp->v_type != VREG) {
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (NULL);
}
- err = VOP_ACCESS(vp, VREAD, 0, CRED());
+ err = VOP_ACCESS(vp, VREAD, 0, CRED(), NULL);
if (err) {
/*
* We don't have read access? better get the heck out.
*/
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (NULL);
}
@@ -513,17 +514,17 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
* get the file size to do some basic validation
*/
va.va_mask = AT_SIZE;
- err = VOP_GETATTR(vp, &va, 0, CRED());
+ err = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
kill_file = (va.va_size == 0 || va.va_size <
(NFS4_VERIFIER_SIZE + sizeof (uint_t)+1));
if (err || kill_file) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (kill_file) {
- (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED());
+ (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED(), NULL, 0);
}
return (NULL);
}
@@ -548,7 +549,7 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
if (err = VOP_READ(vp, &uio, FREAD, CRED(), NULL)) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
return (NULL);
@@ -565,11 +566,11 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
if (err || kill_file) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
if (kill_file) {
- (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED());
+ (void) VOP_REMOVE(dvp, ss_pn->leaf, CRED(), NULL, 0);
}
return (NULL);
}
@@ -588,7 +589,7 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
if (err = VOP_READ(vp, &uio, FREAD, CRED(), NULL)) {
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
kmem_free(cl_ss->cl_id4.id_val, id_len);
kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
@@ -596,7 +597,7 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
}
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (cl_ss);
}
@@ -629,7 +630,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
if (vn_open(statedir, UIO_SYSSPACE, FREAD, 0, &dvp, 0, 0))
return;
- if (dvp->v_type != VDIR || VOP_ACCESS(dvp, VREAD, 0, CRED()))
+ if (dvp->v_type != VDIR || VOP_ACCESS(dvp, VREAD, 0, CRED(), NULL))
goto out;
dirt = kmem_alloc(RFS4_SS_DIRSIZE, KM_SLEEP);
@@ -647,7 +648,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
uio.uio_loffset = dirchunk_offset;
uio.uio_resid = RFS4_SS_DIRSIZE;
- err = VOP_READDIR(dvp, &uio, CRED(), &dir_eof);
+ err = VOP_READDIR(dvp, &uio, CRED(), &dir_eof, NULL, 0);
VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
if (err)
goto out;
@@ -690,7 +691,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
}
out:
- (void) VOP_CLOSE(dvp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(dvp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(dvp);
if (dirt)
kmem_free((caddr_t)dirt, RFS4_SS_DIRSIZE);
@@ -1047,7 +1048,7 @@ rfs4_ss_clid_write_one(rfs4_client_t *cp, char *dss_path, char *leaf)
(void) VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -3425,11 +3426,11 @@ out:
/*
* Given the I/O mode (FREAD or FWRITE), the vnode, the stateid and whether
- * the file is being truncated, return NFS4_OK if allowed or approriate
+ * the file is being truncated, return NFS4_OK if allowed or appropriate
* V4 error if not. Note NFS4ERR_DELAY will be returned and a recall on
* the associated file will be done if the I/O is not consistent with any
* delegation in effect on the file. Should be holding VOP_RWLOCK, either
- * as reader or writer as appropriate. rfs4_op_open will accquire the
+ * as reader or writer as appropriate. rfs4_op_open will acquire the
* VOP_RWLOCK as writer when setting up delegation. If the stateid is bad
* this routine will return NFS4ERR_BAD_STATEID. In addition, through the
* deleg parameter, we will return whether a write delegation is held by
@@ -3441,7 +3442,7 @@ out:
nfsstat4
rfs4_check_stateid(int mode, vnode_t *vp,
stateid4 *stateid, bool_t trunc, bool_t *deleg,
- bool_t do_access)
+ bool_t do_access, caller_context_t *ct)
{
rfs4_file_t *fp;
bool_t create = FALSE;
@@ -3451,6 +3452,12 @@ rfs4_check_stateid(int mode, vnode_t *vp,
stateid_t *id = (stateid_t *)stateid;
nfsstat4 stat = NFS4_OK;
+ if (ct != NULL) {
+ ct->cc_sysid = 0;
+ ct->cc_pid = 0;
+ ct->cc_caller_id = nfs4_srv_caller_id;
+ }
+
if (ISSPECIAL(stateid)) {
fp = rfs4_findfile(vp, NULL, &create);
if (fp == NULL)
@@ -3504,6 +3511,10 @@ rfs4_check_stateid(int mode, vnode_t *vp,
return (NFS4ERR_BAD_STATEID);
}
}
+ if (ct != NULL) {
+ ct->cc_sysid = lsp->locker->client->sysidt;
+ ct->cc_pid = lsp->locker->pid;
+ }
rfs4_lo_state_rele(lsp, FALSE);
}
@@ -3832,13 +3843,19 @@ rfs4_file_walk_callout(rfs4_entry_t u_entry, void *e)
if (fp->vp) {
vnode_t *vp = fp->vp;
- /* don't leak monitors */
- if (fp->dinfo->dtype == OPEN_DELEGATE_READ)
+ /*
+ * don't leak monitors and remove the reference
+ * put on the vnode when the delegation was granted.
+ */
+ if (fp->dinfo->dtype == OPEN_DELEGATE_READ) {
(void) fem_uninstall(vp, deleg_rdops,
(void *)fp);
- else if (fp->dinfo->dtype == OPEN_DELEGATE_WRITE)
+ vn_open_downgrade(vp, FREAD);
+ } else if (fp->dinfo->dtype == OPEN_DELEGATE_WRITE) {
(void) fem_uninstall(vp, deleg_wrops,
(void *)fp);
+ vn_open_downgrade(vp, FREAD|FWRITE);
+ }
mutex_enter(&vp->v_lock);
(void) vsd_set(vp, nfs4_srv_vkey, NULL);
mutex_exit(&vp->v_lock);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
index c6893a13f3..92686ef99d 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
@@ -152,40 +152,52 @@ typedef struct domount_args {
/*
* The vnode ops functions for a trigger stub vnode
*/
-static int nfs4_trigger_open(vnode_t **, int, cred_t *);
-static int nfs4_trigger_getattr(vnode_t *, struct vattr *, int, cred_t *);
-static int nfs4_trigger_setattr(vnode_t *, struct vattr *, int, cred_t *,
- caller_context_t *);
-static int nfs4_trigger_access(vnode_t *, int, int, cred_t *);
-static int nfs4_trigger_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs4_trigger_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
-static int nfs4_trigger_create(vnode_t *, char *, struct vattr *,
- enum vcexcl, int, vnode_t **, cred_t *, int);
-static int nfs4_trigger_remove(vnode_t *, char *, cred_t *);
-static int nfs4_trigger_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs4_trigger_rename(vnode_t *, char *, vnode_t *, char *,
- cred_t *);
-static int nfs4_trigger_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs4_trigger_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
-static int nfs4_trigger_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs4_trigger_cmp(vnode_t *, vnode_t *);
+static int nfs4_trigger_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs4_trigger_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_setattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_access(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs4_trigger_lookup(vnode_t *, char *, vnode_t **,
+ struct pathname *, int, vnode_t *, cred_t *, caller_context_t *,
+ int *, pathname_t *);
+static int nfs4_trigger_create(vnode_t *, char *, struct vattr *,
+ enum vcexcl, int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs4_trigger_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs4_trigger_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_trigger_rename(vnode_t *, char *, vnode_t *, char *,
+ cred_t *, caller_context_t *, int);
+static int nfs4_trigger_mkdir(vnode_t *, char *, struct vattr *,
+ vnode_t **, cred_t *, caller_context_t *, int, vsecattr_t *vsecp);
+static int nfs4_trigger_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_trigger_symlink(vnode_t *, char *, struct vattr *, char *,
+ cred_t *, caller_context_t *, int);
+static int nfs4_trigger_cmp(vnode_t *, vnode_t *, caller_context_t *);
/*
* Regular NFSv4 vnodeops that we need to reference directly
*/
-extern int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *);
-extern void nfs4_inactive(vnode_t *, cred_t *);
+extern int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+extern void nfs4_inactive(vnode_t *, cred_t *, caller_context_t *);
extern int nfs4_rwlock(vnode_t *, int, caller_context_t *);
extern void nfs4_rwunlock(vnode_t *, int, caller_context_t *);
extern int nfs4_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
-extern int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *);
-extern int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-extern int nfs4_fid(vnode_t *, fid_t *);
-extern int nfs4_realvp(vnode_t *, vnode_t **);
+ struct pathname *, int, vnode_t *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
+extern int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+extern int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int nfs4_fid(vnode_t *, fid_t *, caller_context_t *);
+extern int nfs4_realvp(vnode_t *, vnode_t **, caller_context_t *);
static int nfs4_trigger_mount(vnode_t *, vnode_t **);
static int nfs4_trigger_domount(vnode_t *, domount_args_t *, vfs_t **,
@@ -305,7 +317,7 @@ const fs_operation_def_t nfs4_trigger_vnodeops_template[] = {
*/
static int
-nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error;
vnode_t *newvp;
@@ -321,7 +333,7 @@ nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr)
*vpp = newvp;
/* return with VN_HELD(newvp) */
- return (VOP_OPEN(vpp, flag, cr));
+ return (VOP_OPEN(vpp, flag, cr, ct));
}
/*
@@ -332,7 +344,8 @@ nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr)
* testing.
*/
static int
-nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
@@ -343,10 +356,10 @@ nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
if (error)
return (error);
- error = VOP_GETATTR(newvp, vap, flags, cr);
+ error = VOP_GETATTR(newvp, vap, flags, cr, ct);
VN_RELE(newvp);
} else {
- error = nfs4_getattr(vp, vap, flags, cr);
+ error = nfs4_getattr(vp, vap, flags, cr, ct);
}
return (error);
@@ -370,7 +383,8 @@ nfs4_trigger_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
}
static int
-nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
vnode_t *newvp;
@@ -379,15 +393,16 @@ nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr)
if (error)
return (error);
- error = VOP_ACCESS(newvp, mode, flags, cr);
+ error = VOP_ACCESS(newvp, mode, flags, cr, ct);
VN_RELE(newvp);
return (error);
}
static int
-nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp,
+ struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr,
+ caller_context_t *ct, int *deflags, pathname_t *rpnp)
{
int error;
vnode_t *newdvp;
@@ -404,13 +419,15 @@ nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* we've triggered a mount.
*/
if (strcmp(nm, "..") == 0)
- return (nfs4_lookup(dvp, nm, vpp, pnp, flags, rdir, cr));
+ return (nfs4_lookup(dvp, nm, vpp, pnp, flags, rdir, cr,
+ ct, deflags, rpnp));
error = nfs4_trigger_mount(dvp, &newdvp);
if (error)
return (error);
- error = VOP_LOOKUP(newdvp, nm, vpp, pnp, flags, rdir, cr);
+ error = VOP_LOOKUP(newdvp, nm, vpp, pnp, flags, rdir, cr, ct,
+ deflags, rpnp);
VN_RELE(newdvp);
return (error);
@@ -418,8 +435,8 @@ nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
static int
nfs4_trigger_create(vnode_t *dvp, char *nm, struct vattr *va,
- enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr,
- int flags)
+ enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr,
+ int flags, caller_context_t *ct, vsecattr_t *vsecp)
{
int error;
vnode_t *newdvp;
@@ -428,14 +445,16 @@ nfs4_trigger_create(vnode_t *dvp, char *nm, struct vattr *va,
if (error)
return (error);
- error = VOP_CREATE(newdvp, nm, va, exclusive, mode, vpp, cr, flags);
+ error = VOP_CREATE(newdvp, nm, va, exclusive, mode, vpp, cr,
+ flags, ct, vsecp);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
int error;
vnode_t *newdvp;
@@ -444,14 +463,15 @@ nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr)
if (error)
return (error);
- error = VOP_REMOVE(newdvp, nm, cr);
+ error = VOP_REMOVE(newdvp, nm, cr, ct, flags);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
vnode_t *newtdvp;
@@ -464,7 +484,7 @@ nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
* We don't check whether svp is a stub. Let the NFSv4 code
* detect that error, and return accordingly.
*/
- error = VOP_LINK(newtdvp, svp, tnm, cr);
+ error = VOP_LINK(newtdvp, svp, tnm, cr, ct, flags);
VN_RELE(newtdvp);
return (error);
@@ -472,7 +492,7 @@ nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
static int
nfs4_trigger_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int error;
vnode_t *newsdvp;
@@ -501,16 +521,17 @@ nfs4_trigger_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
if (error)
return (error);
- error = VOP_RENAME(newsdvp, snm, tdvp, tnm, cr);
+ error = VOP_RENAME(newsdvp, snm, tdvp, tnm, cr, ct, flags);
VN_RELE(newsdvp);
return (error);
}
+/* ARGSUSED */
static int
nfs4_trigger_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
vnode_t *newdvp;
@@ -519,14 +540,15 @@ nfs4_trigger_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
if (error)
return (error);
- error = VOP_MKDIR(newdvp, nm, va, vpp, cr);
+ error = VOP_MKDIR(newdvp, nm, va, vpp, cr, ct, flags, vsecp);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
vnode_t *newdvp;
@@ -535,7 +557,7 @@ nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
if (error)
return (error);
- error = VOP_RMDIR(newdvp, nm, cdir, cr);
+ error = VOP_RMDIR(newdvp, nm, cdir, cr, ct, flags);
VN_RELE(newdvp);
return (error);
@@ -543,7 +565,7 @@ nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
static int
nfs4_trigger_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int error;
vnode_t *newdvp;
@@ -552,14 +574,15 @@ nfs4_trigger_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm,
if (error)
return (error);
- error = VOP_SYMLINK(newdvp, lnm, tva, tnm, cr);
+ error = VOP_SYMLINK(newdvp, lnm, tva, tnm, cr, ct, flags);
VN_RELE(newdvp);
return (error);
}
static int
-nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr,
+ caller_context_t *ct)
{
int error;
vnode_t *newvp;
@@ -568,7 +591,7 @@ nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
if (error)
return (error);
- error = VOP_READLINK(newvp, uiop, cr);
+ error = VOP_READLINK(newvp, uiop, cr, ct);
VN_RELE(newvp);
return (error);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_subr.c b/usr/src/uts/common/fs/nfs/nfs4_subr.c
index 16ce81e270..52a482f642 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_subr.c
@@ -2319,7 +2319,7 @@ nfs4_printfhandle(nfs4_fhandle_t *fhp)
* We provide a set of interfaces to allow the rest of the system to utilize
* a caching mechanism while encapsulating the details of the actual
* implementation. This should allow for better maintainability and
- * extensibilty by consolidating the implementation details in one location.
+ * extensibility by consolidating the implementation details in one location.
*/
/*
@@ -2875,7 +2875,7 @@ nfs4_directio(vnode_t *vp, int cmd, cred_t *cr)
if (nfs4_has_pages(vp) &&
((rp->r_flags & R4DIRTY) || rp->r_awcount > 0)) {
error = VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0,
- B_INVAL, cr);
+ B_INVAL, cr, NULL);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index f788f16bef..d945efe97a 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -126,7 +126,8 @@ static int nfs4mknod(vnode_t *, char *, struct vattr *, enum vcexcl,
int, vnode_t **, cred_t *);
static int nfs4open_otw(vnode_t *, char *, struct vattr *, vnode_t **,
cred_t *, int, int, enum createmode4, int);
-static int nfs4rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
+static int nfs4rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *);
static int nfs4rename_persistent_fh(vnode_t *, char *, vnode_t *,
vnode_t *, char *, cred_t *, nfsstat4 *);
static int nfs4rename_volatile_fh(vnode_t *, char *, vnode_t *,
@@ -197,65 +198,82 @@ static void nfs4args_write(nfs_argop4 *, stable_how4, rnode4_t *, cred_t *,
* These are the vnode ops functions that implement the vnode interface to
* the networked file system. See more comments below at nfs4_vnodeops.
*/
-static int nfs4_open(vnode_t **, int, cred_t *);
-static int nfs4_close(vnode_t *, int, int, offset_t, cred_t *);
+static int nfs4_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs4_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int nfs4_read(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
static int nfs4_write(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
-static int nfs4_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+static int nfs4_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
static int nfs4_setattr(vnode_t *, struct vattr *, int, cred_t *,
caller_context_t *);
-static int nfs4_access(vnode_t *, int, int, cred_t *);
-static int nfs4_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs4_fsync(vnode_t *, int, cred_t *);
+static int nfs4_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+static int nfs4_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs4_fsync(vnode_t *, int, cred_t *, caller_context_t *);
static int nfs4_create(vnode_t *, char *, struct vattr *, enum vcexcl,
- int, vnode_t **, cred_t *, int);
-static int nfs4_remove(vnode_t *, char *, cred_t *);
-static int nfs4_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs4_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int nfs4_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs4_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs4_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs4_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs4_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+static int nfs4_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
static int nfs4_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs4_readdir(vnode_t *, struct uio *, cred_t *, int *);
-static int nfs4_seek(vnode_t *, offset_t, offset_t *);
+ cred_t *, caller_context_t *, int);
+static int nfs4_readdir(vnode_t *, struct uio *, cred_t *, int *,
+ caller_context_t *, int);
+static int nfs4_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
static int nfs4_getpage(vnode_t *, offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
-static int nfs4_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
-static int nfs4_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs4_addmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs4_cmp(vnode_t *, vnode_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
+static int nfs4_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+static int nfs4_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs4_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs4_cmp(vnode_t *, vnode_t *, caller_context_t *);
static int nfs4_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *, caller_context_t *);
static int nfs4_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-static int nfs4_delmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, cred_t *);
+static int nfs4_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
static int nfs4_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static void nfs4_dispose(vnode_t *, page_t *, int, int, cred_t *);
-static int nfs4_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs4_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
+ cred_t *, caller_context_t *);
+static void nfs4_dispose(vnode_t *, page_t *, int, int, cred_t *,
+ caller_context_t *);
+static int nfs4_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
/*
* These vnode ops are required to be called from outside this source file,
* e.g. by ephemeral mount stub vnode ops, and so may not be declared
* as static.
*/
-int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *);
-void nfs4_inactive(vnode_t *, cred_t *);
+int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+void nfs4_inactive(vnode_t *, cred_t *, caller_context_t *);
int nfs4_lookup(vnode_t *, char *, vnode_t **,
- struct pathname *, int, vnode_t *, cred_t *);
-int nfs4_fid(vnode_t *, fid_t *);
+ struct pathname *, int, vnode_t *, cred_t *,
+ caller_context_t *, int *, pathname_t *);
+int nfs4_fid(vnode_t *, fid_t *, caller_context_t *);
int nfs4_rwlock(vnode_t *, int, caller_context_t *);
void nfs4_rwunlock(vnode_t *, int, caller_context_t *);
-int nfs4_realvp(vnode_t *, vnode_t **);
-int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *);
-int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
+int nfs4_realvp(vnode_t *, vnode_t **, caller_context_t *);
+int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
+int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+int nfs4_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
/*
* Used for nfs4_commit_vp() to indicate if we should
@@ -580,11 +598,10 @@ nfs4_getvnodeops(void)
/*
* The OPEN operation opens a regular file.
- *
- * ARGSUSED
*/
+/*ARGSUSED3*/
static int
-nfs4_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs4_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *dvp = NULL;
rnode4_t *rp, *drp;
@@ -862,10 +879,10 @@ nfs4open_otw(vnode_t *dvp, char *file_name, struct vattr *in_va,
*/
if (VTOR4(vpi)->r_deleg_type != OPEN_DELEGATE_NONE) {
if (open_flag & FREAD &&
- nfs4_access(vpi, VREAD, 0, cr) == 0)
+ nfs4_access(vpi, VREAD, 0, cr, NULL) == 0)
acc |= VREAD;
if (open_flag & FWRITE &&
- nfs4_access(vpi, VWRITE, 0, cr) == 0)
+ nfs4_access(vpi, VWRITE, 0, cr, NULL) == 0)
acc |= VWRITE;
}
}
@@ -1538,7 +1555,7 @@ recov_retry:
"nfs4open_otw: EXCLUSIVE4: error %d on SETATTR:"
" remove file", e.error));
VN_RELE(vp);
- (void) nfs4_remove(dvp, file_name, cr);
+ (void) nfs4_remove(dvp, file_name, cr, NULL, 0);
/*
* Since we've reled the vnode and removed
* the file we now need to return the error.
@@ -1635,7 +1652,7 @@ skip_update_dircaches:
* - failed_reopen : same as above, except that the file has already been
* marked dead, so no need to do it again.
* - bailout : reopen failed but we are able to recover and retry the reopen -
- * either within this function immediatley or via the calling function.
+ * either within this function immediately or via the calling function.
*/
void
@@ -2210,8 +2227,10 @@ nfs4_open_non_reg_file(vnode_t **vpp, int flag, cred_t *cr)
/*
* CLOSE a file
*/
+/* ARGSUSED */
static int
-nfs4_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+nfs4_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
rnode4_t *rp;
int error = 0;
@@ -3513,7 +3532,8 @@ recov_retry:
/* ARGSUSED */
static int
-nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
if (nfs_zone() != VTOMI4(vp)->mi_zone)
return (EIO);
@@ -3525,8 +3545,10 @@ nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
}
+/* ARGSUSED */
int
-nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode4_t *rp = VTOR4(vp);
@@ -3575,7 +3597,7 @@ nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
mutex_exit(&rp->r_statelock);
error =
nfs4_putpage(vp, (u_offset_t)0,
- 0, 0, cr);
+ 0, 0, cr, NULL);
mutex_enter(&rp->r_statelock);
if (error && (error == ENOSPC ||
error == EDQUOT)) {
@@ -3696,7 +3718,7 @@ nfs4setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
ASSERT(vp->v_type != VCHR);
- e.error = nfs4_putpage(vp, (offset_t)0, 0, 0, cr);
+ e.error = nfs4_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
if (e.error && (e.error == ENOSPC || e.error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -4144,7 +4166,7 @@ recov_retry:
/* ARGSUSED */
static int
-nfs4_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs4_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res;
@@ -4358,8 +4380,9 @@ out:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs4_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res;
@@ -4521,8 +4544,9 @@ recov_retry:
* metadata changes are not cached on the client before being
* sent to the server.
*/
+/* ARGSUSED */
static int
-nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
int error;
@@ -4541,8 +4565,9 @@ nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr)
* operation while it was open, it got renamed instead. Here we
* remove the renamed file.
*/
+/* ARGSUSED */
void
-nfs4_inactive(vnode_t *vp, cred_t *cr)
+nfs4_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
rnode4_t *rp;
@@ -4709,7 +4734,7 @@ redo:
if (nfs4_has_pages(vp) &&
((rp->r_flags & R4DIRTY) || rp->r_count > 0)) {
ASSERT(vp->v_type != VCHR);
- e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr);
+ e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr, NULL);
if (e.error) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -4827,7 +4852,8 @@ recov_retry_remove:
/* ARGSUSED3 */
int
nfs4_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int error;
vnode_t *vp, *avp = NULL;
@@ -4903,7 +4929,8 @@ nfs4lookup_xattr(vnode_t *dvp, char *nm, vnode_t **vpp, int flags, cred_t *cr)
mntinfo4_t *mi;
mi = VTOMI4(dvp);
- if (!(mi->mi_vfsp->vfs_flag & VFS_XATTR))
+ if (!(mi->mi_vfsp->vfs_flag & VFS_XATTR) &&
+ !vfs_has_feature(mi->mi_vfsp, VFSFT_XVATTR))
return (EINVAL);
drp = VTOR4(dvp);
@@ -4983,7 +5010,7 @@ nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc)
* just need to check access.
*/
if (nm[0] == '.' && nm[1] == '\0') {
- error = nfs4_access(dvp, VEXEC, 0, cr);
+ error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (error)
return (error);
VN_HOLD(dvp);
@@ -5046,7 +5073,7 @@ nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc)
/*
* The access cache should almost always hit
*/
- error = nfs4_access(dvp, VEXEC, 0, cr);
+ error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (error) {
VN_RELE(*vpp);
@@ -5346,7 +5373,7 @@ recov_retry:
* Somehow we must not have asked for enough
* so try a singleton ACCESS, should never happen.
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
VN_RELE(*vpp);
*vpp = NULL;
@@ -5488,7 +5515,7 @@ recov_retry:
* and dnlc entry, we may not have access.
* This should almost always hit the cache.
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
VN_RELE(*vpp);
*vpp = NULL;
@@ -5819,7 +5846,7 @@ recov_retry:
* Somehow we must not have asked for enough
* so try a singleton ACCESS should never happen
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
sfh4_rele(&sfhp);
goto exit;
@@ -5855,7 +5882,7 @@ recov_retry:
* we may not have access.
* This should almost always hit the cache.
*/
- e.error = nfs4_access(dvp, VEXEC, 0, cr);
+ e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
if (e.error) {
sfh4_rele(&sfhp);
goto exit;
@@ -6375,7 +6402,8 @@ recov_retry:
/* ARGSUSED */
static int
nfs4_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
- int mode, vnode_t **vpp, cred_t *cr, int flags)
+ int mode, vnode_t **vpp, cred_t *cr, int flags, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
vnode_t *vp = NULL;
@@ -6461,7 +6489,7 @@ top:
vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
VN_RELE(tempvp);
}
- if (!(error = VOP_ACCESS(vp, mode, 0, cr))) {
+ if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
if ((vattr.va_mask & AT_SIZE) &&
vp->v_type == VREG) {
rp = VTOR4(vp);
@@ -6500,7 +6528,8 @@ top:
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
error = nfs4_putpage(vp,
- (offset_t)0, 0, 0, cr);
+ (offset_t)0, 0, 0, cr,
+ ct);
if (error && (error == ENOSPC ||
error == EDQUOT)) {
mutex_enter(
@@ -6537,7 +6566,7 @@ top:
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
}
- vnevent_create(tvp);
+ vnevent_create(tvp, ct);
*vpp = vp;
}
return (error);
@@ -6642,7 +6671,7 @@ create_otw:
trp = VTOR4(tvp);
if (IS_SHADOW(tvp, trp))
tvp = RTOV4(trp);
- vnevent_create(tvp);
+ vnevent_create(tvp, ct);
}
return (error);
}
@@ -6695,7 +6724,7 @@ call_nfs4_create_req(vnode_t *dvp, char *nm, void *data, struct vattr *va,
va->va_mode &= ~VSGID;
dva.va_mask = AT_MODE | AT_GID;
- if (VOP_GETATTR(dvp, &dva, 0, cr) == 0) {
+ if (VOP_GETATTR(dvp, &dva, 0, cr, NULL) == 0) {
/*
* If the parent's directory has the setgid bit set
@@ -7073,8 +7102,9 @@ nfs4mknod(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* we rename it instead of removing it and nfs_inactive
* will remove the new name.
*/
+/* ARGSUSED */
static int
-nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res, *resp = NULL;
@@ -7152,7 +7182,7 @@ nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr)
(rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
mutex_exit(&rp->r_statelock);
tmpname = newname();
- e.error = nfs4rename(dvp, nm, dvp, tmpname, cr);
+ e.error = nfs4rename(dvp, nm, dvp, tmpname, cr, ct);
if (e.error)
kmem_free(tmpname, MAXNAMELEN);
else {
@@ -7188,7 +7218,7 @@ nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr)
*/
if (nfs4_has_pages(vp) &&
((rp->r_flags & R4DIRTY) || rp->r_count > 0)) {
- e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr);
+ e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr, ct);
if (e.error && (e.error == ENOSPC || e.error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -7293,7 +7323,7 @@ recov_retry:
tvp = vp;
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
- vnevent_remove(tvp, dvp, nm);
+ vnevent_remove(tvp, dvp, nm, ct);
}
VN_RELE(vp);
return (e.error);
@@ -7306,8 +7336,10 @@ recov_retry:
* PUTFH(file), SAVEFH, PUTFH(targetdir), LINK, RESTOREFH,
* GETATTR(file)
*/
+/* ARGSUSED */
static int
-nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
COMPOUND4args_clnt args;
COMPOUND4res_clnt res, *resp = NULL;
@@ -7332,7 +7364,7 @@ nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
if (nfs_zone() != VTOMI4(tdvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(svp, &realvp) == 0) {
+ if (VOP_REALVP(svp, &realvp, ct) == 0) {
svp = realvp;
ASSERT(nfs4_consistent_type(svp));
}
@@ -7514,7 +7546,7 @@ recov_retry:
tvp = svp;
if (IS_SHADOW(svp, trp))
tvp = RTOV4(trp);
- vnevent_link(tvp);
+ vnevent_link(tvp, ct);
}
out:
kmem_free(argop, argoplist_size);
@@ -7526,17 +7558,19 @@ out:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
vnode_t *realvp;
if (nfs_zone() != VTOMI4(odvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
- return (nfs4rename(odvp, onm, ndvp, nnm, cr));
+ return (nfs4rename(odvp, onm, ndvp, nnm, cr, ct));
}
/*
@@ -7547,7 +7581,8 @@ nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
* based on the likelihood of the filehandle to change during rename.
*/
static int
-nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo4_t *mi;
@@ -7712,11 +7747,12 @@ link_call:
error = 0;
if (do_link) {
- error = nfs4_link(ndvp, nvp, tmpname, cr);
+ error = nfs4_link(ndvp, nvp, tmpname, cr,
+ NULL, 0);
}
if (error == EOPNOTSUPP || !do_link) {
error = nfs4_rename(ndvp, nnm, ndvp, tmpname,
- cr);
+ cr, NULL, 0);
did_link = 0;
} else {
did_link = 1;
@@ -7843,7 +7879,7 @@ link_call:
*/
VN_HOLD(nvp);
- (void) nfs4_remove(ndvp, tmpname, cr);
+ (void) nfs4_remove(ndvp, tmpname, cr, NULL, 0);
/* Undo the unlinked file naming stuff we just did */
mutex_enter(&rp->r_statelock);
@@ -7924,7 +7960,7 @@ link_call:
tvp = nvp;
if (IS_SHADOW(nvp, trp))
tvp = RTOV4(trp);
- vnevent_rename_dest(tvp, ndvp, nnm);
+ vnevent_rename_dest(tvp, ndvp, nnm, ct);
}
/*
@@ -7936,14 +7972,14 @@ link_call:
tvp = ndvp;
if (IS_SHADOW(ndvp, trp))
tvp = RTOV4(trp);
- vnevent_rename_dest_dir(tvp);
+ vnevent_rename_dest_dir(tvp, ct);
}
trp = VTOR4(ovp);
tvp = ovp;
if (IS_SHADOW(ovp, trp))
tvp = RTOV4(trp);
- vnevent_rename_src(tvp, odvp, onm);
+ vnevent_rename_src(tvp, odvp, onm, ct);
}
if (nvp) {
@@ -7967,7 +8003,7 @@ link_call:
* The compound op structure for persistent fh rename is:
* PUTFH(sourcdir), SAVEFH, PUTFH(targetdir), RENAME
* Rather than bother with the directory postop args, we'll simply
- * update that a change occured in the cache, so no post-op getattrs.
+ * update that a change occurred in the cache, so no post-op getattrs.
*/
static int
nfs4rename_persistent_fh(vnode_t *odvp, char *onm, vnode_t *renvp,
@@ -8432,8 +8468,10 @@ out:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
+nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
vnode_t *vp;
@@ -8469,8 +8507,10 @@ nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
* The compound op structure is:
* PUTFH(targetdir), REMOVE
*/
+/*ARGSUSED4*/
static int
-nfs4_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs4_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int need_end_op = FALSE;
COMPOUND4args_clnt args;
@@ -8664,7 +8704,7 @@ recov_retry:
tvp = vp;
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
- vnevent_rmdir(tvp, dvp, nm);
+ vnevent_rmdir(tvp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -8672,8 +8712,10 @@ recov_retry:
return (e.error);
}
+/* ARGSUSED */
static int
-nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
+nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
vnode_t *vp;
@@ -8726,8 +8768,10 @@ nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
* may return only one block's worth of entries. Entries may be compressed
* on the server.
*/
+/* ARGSUSED */
static int
-nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
+nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int error;
uint_t count;
@@ -8809,7 +8853,7 @@ nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
nfs4readdir(vp, rdc, cr);
/*
- * Reaquire the lock, so that we can continue
+ * Reacquire the lock, so that we can continue
*/
mutex_enter(&rp->r_statelock);
/*
@@ -9483,7 +9527,7 @@ write_again:
/* ARGSUSED */
int
-nfs4_fid(vnode_t *vp, fid_t *fidp)
+nfs4_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
return (EREMOTE);
}
@@ -9522,7 +9566,7 @@ nfs4_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
if (nfs_zone() != VTOMI4(vp)->mi_zone)
return (EIO);
@@ -9543,10 +9587,11 @@ nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
/*
* Return all the pages from [off..off+len) in file
*/
+/* ARGSUSED */
static int
nfs4_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
rnode4_t *rp;
int error;
@@ -10022,8 +10067,10 @@ nfs4_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/* ARGSUSED */
static int
-nfs4_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+nfs4_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode4_t *rp;
@@ -10228,7 +10275,7 @@ nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
*/
if (!(flags & B_ASYNC)) {
error = nfs4_putpage(vp, io_off, io_len,
- B_INVAL | B_FORCE, cr);
+ B_INVAL | B_FORCE, cr, NULL);
}
} else {
if (error)
@@ -10251,9 +10298,11 @@ nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
int nfs4_force_open_before_mmap = 0;
#endif
+/* ARGSUSED */
static int
nfs4_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error = 0;
@@ -10529,7 +10578,8 @@ open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp)
/* ARGSUSED */
static int
nfs4_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
rnode4_t *rp;
int error = 0;
@@ -10633,16 +10683,19 @@ out:
return (error);
}
+/* ARGSUSED */
static int
-nfs4_cmp(vnode_t *vp1, vnode_t *vp2)
+nfs4_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
return (VTOR4(vp1) == VTOR4(vp2));
}
+/* ARGSUSED */
static int
nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+ offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct)
{
int rc;
u_offset_t start, end;
@@ -10698,7 +10751,7 @@ nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (!nfs4_safelock(vp, bfp, cr))
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
rp = VTOR4(vp);
@@ -10748,7 +10801,7 @@ nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
mutex_exit(&rp->r_statelock);
if (rc != 0)
goto done;
- error = nfs4_putpage(vp, (offset_t)0, 0, B_INVAL, cr);
+ error = nfs4_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
@@ -10820,7 +10873,7 @@ nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/* ARGSUSED */
int
-nfs4_realvp(vnode_t *vp, vnode_t **vpp)
+nfs4_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
rnode4_t *rp;
rp = VTOR4(vp);
@@ -10845,7 +10898,8 @@ nfs4_realvp(vnode_t *vp, vnode_t **vpp)
/* ARGSUSED */
static int
nfs4_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
int caller_found;
int error;
@@ -11043,7 +11097,7 @@ nfs4_delmap_callback(struct as *as, void *arg, uint_t event)
if ((rp->r_flags & R4DIRECTIO) || (mi->mi_flags & MI4_DIRECTIO))
(void) nfs4_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_INVAL, dmapp->cr);
+ B_INVAL, dmapp->cr, NULL);
if (e.error) {
e.stat = puterrno4(e.error);
@@ -11111,8 +11165,10 @@ fattr4_maxfilesize_to_bits(uint64_t ll)
return (l);
}
+/* ARGSUSED */
int
-nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error;
hrtime_t t;
@@ -11140,7 +11196,7 @@ nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
* going otw with GETATTR(FATTR4_NAMED_ATTR). For now
* just drive the OTW getattr. This is required because
* _PC_XATTR_EXISTS can only return true if attributes
- * exist -- simply checking for existance of the attrdir
+ * exist -- simply checking for existence of the attrdir
* is not sufficient.
*
* pc4_xattr_valid can be only be trusted when r_xattr_dir
@@ -11262,9 +11318,10 @@ nfs4_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs4_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
int error;
rnode4_t *rp;
@@ -11292,8 +11349,10 @@ nfs4_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static void
-nfs4_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+nfs4_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode4_t *rp;
@@ -11899,7 +11958,7 @@ top:
write_verf = rp->r_writeverf;
mutex_exit(&rp->r_statelock);
- error = nfs4_putpage(vp, poff, plen, B_ASYNC, cr);
+ error = nfs4_putpage(vp, poff, plen, B_ASYNC, cr, NULL);
if (error == EAGAIN)
error = 0;
@@ -11910,7 +11969,7 @@ top:
* the asynchronous i/o's in that range are done as well.
*/
if (!error)
- error = nfs4_putpage(vp, poff, plen, 0, cr);
+ error = nfs4_putpage(vp, poff, plen, 0, cr, NULL);
if (error)
return (error);
@@ -12067,7 +12126,8 @@ do_nfs4_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count,
/*ARGSUSED*/
static int
-nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
mntinfo4_t *mi;
@@ -12113,8 +12173,10 @@ nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (ENOSYS);
}
+/* ARGSUSED */
int
-nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo4_t *mi;
@@ -12167,7 +12229,7 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
if (error) {
vs_ace4_destroy(&gar.n4g_vsa);
if (error == ENOTSUP || error == EOPNOTSUPP)
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
return (error);
}
@@ -12177,7 +12239,7 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
* bitmap, neither was an acl.
*/
vs_ace4_destroy(&gar.n4g_vsa);
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
return (error);
}
@@ -12193,11 +12255,11 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
if ((error) && (vsecattr->vsa_mask &
(VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT)) &&
(error != EACCES)) {
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
}
return (error);
}
- error = fs_fab_acl(vp, vsecattr, flag, cr);
+ error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
return (error);
}
@@ -12322,8 +12384,10 @@ nfs4_create_getsecattr_return(vsecattr_t *filled_vsap, vsecattr_t *vsap,
return (0);
}
-static int
-nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+/* ARGSUSED */
+int
+nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
@@ -12348,7 +12412,7 @@ nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
* request off to the local share code.
*/
if (VTOMI4(vp)->mi_flags & MI4_LLOCK)
- return (fs_shrlock(vp, cmd, shr, flag, cr));
+ return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
switch (cmd) {
case F_SHARE:
@@ -13568,7 +13632,7 @@ nfs4frlock_recovery(int needrecov, nfs4_error_t *ep,
}
/*
- * Handles the succesful reply from the server for nfs4frlock.
+ * Handles the successful reply from the server for nfs4frlock.
*/
static void
nfs4frlock_results_ok(nfs4_lock_call_type_t ctype, int cmd, flock64_t *flk,
@@ -13855,7 +13919,7 @@ nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp,
int error;
error = VOP_PUTPAGE(vp, (u_offset_t)0,
- 0, B_INVAL, cred);
+ 0, B_INVAL, cred, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
rnode4_t *rp = VTOR4(vp);
@@ -14345,7 +14409,7 @@ nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr)
/* mandatory locking and mapping don't mix */
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error != 0) {
NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: "
"getattr error %d", error));
@@ -14502,7 +14566,8 @@ nfs4_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
ld.l_start = 0;
ld.l_len = 0; /* do entire file */
- ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL, cr);
+ ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL,
+ cr, NULL);
if (ret != 0) {
/*
@@ -15552,7 +15617,7 @@ locks_intersect(flock64_t *llfp, flock64_t *curfp)
}
/*
- * Determine what the interseting lock region is, and add that to the
+ * Determine what the intersecting lock region is, and add that to the
* 'nl_llpp' locklist in increasing order (by l_start).
*/
static void
diff --git a/usr/src/uts/common/fs/nfs/nfs4_xdr.c b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
index 34fd0f11dd..ac08add502 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved. Use is subject to license terms.
*/
@@ -190,7 +190,7 @@ xdr_inline_decode_nfs_fh4(uint32_t *ptr, nfs_fh4_fmt_t *fhp, uint32_t fhsize)
fhsize -= 2 * BYTES_PER_XDR_UNIT + sizeof (ushort_t);
/*
- * For backwards compatability, the fid length may be less than
+ * For backwards compatibility, the fid length may be less than
* NFS_FHMAXDATA, but it was always encoded as NFS_FHMAXDATA bytes.
*/
dsize = fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
@@ -849,6 +849,7 @@ xdr_ga_fattr_res(XDR *xdrs, struct nfs4_ga_res *garp, bitmap4 resbmap,
vsap->vsa_aclcnt = acl.fattr4_acl_len;
vsap->vsa_aclentp = acl.fattr4_acl_val;
vsap->vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsap->vsa_aclentsz = vsap->vsa_aclcnt * sizeof (ace_t);
}
if (resbmap & FATTR4_ACLSUPPORT_MASK) {
diff --git a/usr/src/uts/common/fs/nfs/nfs_acl_srv.c b/usr/src/uts/common/fs/nfs/nfs_acl_srv.c
index b8d90196ef..f2ccc525fa 100644
--- a/usr/src/uts/common/fs/nfs/nfs_acl_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_acl_srv.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved.
* Use is subject to license terms.
*/
@@ -94,7 +94,7 @@ acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi,
resp->resok.acl.vsa_mask = args->mask;
- error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr);
+ error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL);
if (error == ENOSYS) {
/*
@@ -112,7 +112,7 @@ acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi,
* Note: if the fs_fab_acl() fails, we have other problems.
* This error should be returned to the caller.
*/
- error = fs_fab_acl(vp, &resp->resok.acl, 0, cr);
+ error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL);
}
if (error) {
@@ -211,7 +211,7 @@ acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi,
}
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(vp, &args->acl, 0, cr);
+ error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
if (error) {
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
VN_RELE(vp);
@@ -317,7 +317,7 @@ acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi,
* as well be reflected to the server during the open.
*/
va.va_mask = AT_MODE;
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
if (error) {
VN_RELE(vp);
resp->status = puterrno(error);
@@ -327,30 +327,30 @@ acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi,
resp->resok.access = 0;
if (args->access & ACCESS2_READ) {
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode))
resp->resok.access |= ACCESS2_READ;
}
if ((args->access & ACCESS2_LOOKUP) && vp->v_type == VDIR) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error)
resp->resok.access |= ACCESS2_LOOKUP;
}
if (checkwriteperm &&
(args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND))) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode))
resp->resok.access |=
(args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND));
}
if (checkwriteperm &&
(args->access & ACCESS2_DELETE) && (vp->v_type == VDIR)) {
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
if (!error)
resp->resok.access |= ACCESS2_DELETE;
}
if (args->access & ACCESS2_EXECUTE) {
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
if (!error && !MANDLOCK(vp, va.va_mode))
resp->resok.access |= ACCESS2_EXECUTE;
}
@@ -399,7 +399,7 @@ acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp,
flags |= CREATE_XATTR_DIR;
else {
ulong_t val = 0;
- error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr, NULL);
if (!error && val == 0) {
VN_RELE(vp);
resp->status = NFSERR_NOENT;
@@ -407,7 +407,8 @@ acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp,
}
}
- error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr);
+ error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr,
+ NULL, NULL, NULL);
if (!error && avp == vp) { /* lookup of "" on old FS? */
error = EINVAL;
VN_RELE(avp);
@@ -472,7 +473,7 @@ acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi,
resp->resok.acl.vsa_mask = args->mask;
- error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr);
+ error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL);
if (error == ENOSYS) {
/*
@@ -490,7 +491,7 @@ acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi,
* Note: if the fs_fab_acl() fails, we have other problems.
* This error should be returned to the caller.
*/
- error = fs_fab_acl(vp, &resp->resok.acl, 0, cr);
+ error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL);
}
if (error)
@@ -602,7 +603,7 @@ acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi,
goto out1;
}
- error = VOP_SETSECATTR(vp, &args->acl, 0, cr);
+ error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
@@ -666,7 +667,7 @@ acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp,
flags |= CREATE_XATTR_DIR;
else {
ulong_t val = 0;
- error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr);
+ error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS, &val, cr, NULL);
if (!error && val == 0) {
VN_RELE(vp);
resp->status = NFS3ERR_NOENT;
@@ -674,7 +675,8 @@ acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp,
}
}
- error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr);
+ error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr,
+ NULL, NULL, NULL);
if (!error && avp == vp) { /* lookup of "" on old FS? */
error = EINVAL;
VN_RELE(avp);
diff --git a/usr/src/uts/common/fs/nfs/nfs_client.c b/usr/src/uts/common/fs/nfs/nfs_client.c
index b6a8a96f01..17ea954eea 100644
--- a/usr/src/uts/common/fs/nfs/nfs_client.c
+++ b/usr/src/uts/common/fs/nfs/nfs_client.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
@@ -232,7 +232,7 @@ nfs_purge_caches(vnode_t *vp, int purge_dnlc, cred_t *cr)
* Flush the page cache.
*/
if (vn_has_cached_data(vp)) {
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1807,7 +1807,7 @@ noasync:
void
nfs_async_inactive(vnode_t *vp, cred_t *cr,
- void (*inactive)(vnode_t *, cred_t *))
+ void (*inactive)(vnode_t *, cred_t *, caller_context_t *))
{
mntinfo_t *mi;
struct nfs_async_reqs *args;
@@ -1832,7 +1832,7 @@ nfs_async_inactive(vnode_t *vp, cred_t *cr,
* set nfs3_max_threads/nfs_max_threads to zero in /etc/system.
*
* The manager thread knows about this and is willing to create
- * at least one thread to accomodate us.
+ * at least one thread to accommodate us.
*/
mutex_enter(&mi->mi_async_lock);
if (mi->mi_manager_thread == NULL) {
@@ -2029,7 +2029,7 @@ nfs_async_start(struct vfs *vfsp)
args->a_nfs_offset, args->a_nfs_count,
args->a_cred);
} else if (args->a_io == NFS_INACTIVE) {
- (*args->a_nfs_inactive)(args->a_vp, args->a_cred);
+ (*args->a_nfs_inactive)(args->a_vp, args->a_cred, NULL);
}
/*
@@ -2066,7 +2066,7 @@ nfs_async_stop(struct vfs *vfsp)
* Wait for all outstanding putpage operation to complete. If a signal
* is deliver we will abort and return non-zero. If we can put all the
* pages we will return 0. This routine is called from nfs_unmount and
- * nfs3_unmount to make these operations interruptable.
+ * nfs3_unmount to make these operations interruptible.
*/
int
nfs_async_stop_sig(struct vfs *vfsp)
@@ -2329,7 +2329,7 @@ nfs_putpages(vnode_t *vp, u_offset_t off, size_t len, int flags, cred_t *cr)
flags, cr);
/*
- * If an error occured and the file was marked as dirty
+ * If an error occurred and the file was marked as dirty
* before and we aren't forcibly invalidating pages, then
* reset the RDIRTY flag.
*/
@@ -2762,7 +2762,8 @@ nfs_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
ld.l_whence = 0; /* unlock from start of file */
ld.l_start = 0;
ld.l_len = 0; /* do entire file */
- ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL, cr);
+ ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL, cr,
+ NULL);
if (ret != 0) {
/*
@@ -2802,7 +2803,7 @@ nfs_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
shr.s_sysid = 0;
shr.s_pid = curproc->p_pid;
- ret = VOP_SHRLOCK(vp, F_UNSHARE, &shr, flag, cr);
+ ret = VOP_SHRLOCK(vp, F_UNSHARE, &shr, flag, cr, NULL);
#ifdef DEBUG
if (ret != 0) {
nfs_perror(ret,
@@ -2975,7 +2976,7 @@ nfs_add_locking_id(vnode_t *vp, pid_t pid, int type, char *id, int len)
nowners++;
} else {
cmn_err(CE_PANIC, "nfs_add_locking_id: "
- "unrecognised lmpl_type %d",
+ "unrecognized lmpl_type %d",
cur->lmpl_type);
}
}
@@ -3055,7 +3056,7 @@ nfs_remove_locking_id(vnode_t *vp, int type, char *id, char *rid, int *rlen)
nowners++;
} else {
cmn_err(CE_PANIC,
- "nrli: unrecognised lmpl_type %d",
+ "nrli: unrecognized lmpl_type %d",
cur->lmpl_type);
}
}
diff --git a/usr/src/uts/common/fs/nfs/nfs_common.c b/usr/src/uts/common/fs/nfs/nfs_common.c
index ded7c5075c..c980d55aed 100644
--- a/usr/src/uts/common/fs/nfs/nfs_common.c
+++ b/usr/src/uts/common/fs/nfs/nfs_common.c
@@ -70,7 +70,7 @@
#include <rpc/svc.h>
/*
- * The psuedo NFS filesystem to allow diskless booting to dynamically
+ * The pseudo NFS filesystem to allow diskless booting to dynamically
* mount either a NFS V2, NFS V3, or NFS V4 filesystem. This only implements
* the VFS_MOUNTROOT op and is only intended to be used by the
* diskless booting code until the real root filesystem is mounted.
@@ -273,7 +273,7 @@ _info(struct modinfo *modinfop)
*/
/*
- * Returns the prefered transfer size in bytes based on
+ * Returns the preferred transfer size in bytes based on
* what network interfaces are available.
*/
int
@@ -287,7 +287,7 @@ nfstsize(void)
}
/*
- * Returns the prefered transfer size in bytes based on
+ * Returns the preferred transfer size in bytes based on
* what network interfaces are available.
*/
@@ -607,7 +607,7 @@ nfs_directio(vnode_t *vp, int cmd, cred_t *cr)
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_awcount > 0)) {
error = VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0,
- B_INVAL, cr);
+ B_INVAL, cr, NULL);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
diff --git a/usr/src/uts/common/fs/nfs/nfs_dump.c b/usr/src/uts/common/fs/nfs/nfs_dump.c
index 17cb8ba161..8fe224936d 100644
--- a/usr/src/uts/common/fs/nfs/nfs_dump.c
+++ b/usr/src/uts/common/fs/nfs/nfs_dump.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -96,8 +95,9 @@ nd_log(const char *fmt, ...)
}
}
+/* ARGSUSED */
int
-nfs_dump(vnode_t *dumpvp, caddr_t addr, int bn, int count)
+nfs_dump(vnode_t *dumpvp, caddr_t addr, int bn, int count, caller_context_t *ct)
{
static TIUSER *tiptr;
XDR xdrs;
diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c
index 3b7725dd34..377b5bad18 100644
--- a/usr/src/uts/common/fs/nfs/nfs_export.c
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c
@@ -617,7 +617,7 @@ pseudo_secinfo_remove(exportinfo_t *ancexi, exp_visible_t *ancpseudo)
*
* If there is more than 1 export reference to an old flavor (i.e. some
* of its children shared with this flavor), this flavor information
- * needs to be transfered to the new exportdata struct. A flavor in
+ * needs to be transferred to the new exportdata struct. A flavor in
* the old exportdata has descendant refs when s_refcnt > 1.
*
* Transferring descendant flavor refcnts happens in 2 passes:
@@ -749,7 +749,7 @@ srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
* When unsharing an old export node and the old node becomes a pseudo node,
* if there is more than 1 export reference to an old flavor (i.e. some of
* its children shared with this flavor), this flavor information needs to
- * be transfered to the new shared node.
+ * be transferred to the new shared node.
*
* This routine is used under the protection of exported_lock (RW_WRITER).
*/
@@ -928,7 +928,8 @@ srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
/*
* Now, do a ".." to find parent dir of vp.
*/
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
+ NULL, NULL, NULL);
if (error == ENOTDIR && exportdir) {
dvp = exip->exi_dvp;
@@ -1039,8 +1040,8 @@ nfs_exportinit(void)
}
/*
- * Finalization routine for export routines. Called to cleanup previoulsy
- * initializtion work when the NFS server module could not be loaded correctly.
+ * Finalization routine for export routines. Called to cleanup previously
+ * initialization work when the NFS server module could not be loaded correctly.
*/
void
nfs_exportfini(void)
@@ -1243,7 +1244,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
* intended filesystem, so we can share the intended
* filesystem instead of the AUTOFS filesystem.
*/
- (void) VOP_ACCESS(vp, 0, 0, cr);
+ (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
/*
* We're interested in the top most filesystem.
@@ -1266,7 +1267,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
*/
bzero(&fid, sizeof (fid));
fid.fid_len = MAXFIDSZ;
- error = VOP_FID(vp, &fid);
+ error = VOP_FID(vp, &fid, NULL);
fsid = vp->v_vfsp->vfs_fsid;
if (error) {
VN_RELE(vp);
@@ -1914,7 +1915,7 @@ nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
* intended filesystem, so we can share the intended
* filesystem instead of the AUTOFS filesystem.
*/
- (void) VOP_ACCESS(vp, 0, 0, cr);
+ (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
/*
* We're interested in the top most filesystem.
@@ -1952,7 +1953,7 @@ nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
i += sz;
/*
- * For backwards compatability, the
+ * For backwards compatibility, the
* fid length may be less than
* NFS_FHMAXDATA, but it was always
* encoded as NFS_FHMAXDATA bytes.
@@ -2091,7 +2092,8 @@ nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
* otherwise, look it up.
*/
if (dvp == NULL) {
- error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (error)
break;
}
@@ -2141,7 +2143,7 @@ makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
*fh = exi->exi_fh; /* struct copy */
- error = VOP_FID(vp, (fid_t *)&fh->fh_len);
+ error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
if (error) {
/*
* Should be something other than EREMOTE
@@ -2245,7 +2247,7 @@ makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
bzero(&fid, sizeof (fid));
fid.fid_len = MAXFIDSZ;
- error = VOP_FID(vp, &fid);
+ error = VOP_FID(vp, &fid, NULL);
if (error)
return (EREMOTE);
diff --git a/usr/src/uts/common/fs/nfs/nfs_log.c b/usr/src/uts/common/fs/nfs/nfs_log.c
index 49d9d78f10..a52a6937a9 100644
--- a/usr/src/uts/common/fs/nfs/nfs_log.c
+++ b/usr/src/uts/common/fs/nfs/nfs_log.c
@@ -461,7 +461,7 @@ log_file_create(caddr_t origname, struct log_file **lfpp)
rfsl_log_file++;
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &va, 0, CRED());
+ error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
if (error) {
nfs_cmn_err(error, CE_WARN,
"log_file_create: Can not stat %s - error = %m", name);
@@ -510,7 +510,7 @@ out:
if (vp != NULL) {
int error1;
error1 = VOP_CLOSE(vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
- CRED());
+ CRED(), NULL);
if (error1) {
nfs_cmn_err(error1, CE_WARN,
"log_file_create: Can not close %s - "
@@ -561,7 +561,7 @@ log_file_rele(struct log_file *lfp)
ASSERT(lfp->lf_writers == 0);
if (error = VOP_CLOSE(lfp->lf_vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
- CRED())) {
+ CRED(), NULL)) {
nfs_cmn_err(error, CE_WARN,
"NFS: Could not close log buffer %s - error = %m",
lfp->lf_path);
@@ -825,7 +825,7 @@ nfslog_write_logrecords(struct log_file *lfp,
va.va_mask = AT_SIZE;
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); /* UIO_WRITE */
- if ((error = VOP_GETATTR(vp, &va, 0, CRED())) == 0) {
+ if ((error = VOP_GETATTR(vp, &va, 0, CRED(), NULL)) == 0) {
if ((len + va.va_size) < (MAXOFF32_T)) {
error = VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
@@ -1173,7 +1173,7 @@ nfsl_flush(struct nfsl_flush_args *args, model_t model)
* This is where buffer flushing would occur, but there is no buffering
* at this time.
* Possibly rename the log buffer for processing.
- * Sets tparams->ta_error equal to the value of the error that occured,
+ * Sets tparams->ta_error equal to the value of the error that occurred,
* 0 otherwise.
* Returns ENOENT if the buffer is not found.
*/
diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c
index a65ae500d8..a99299aea3 100644
--- a/usr/src/uts/common/fs/nfs/nfs_server.c
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c
@@ -2555,7 +2555,7 @@ rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
* filesystem, so we can perform the lookup in the
* intended filesystem.
*/
- (void) VOP_ACCESS(*vpp, 0, 0, cr);
+ (void) VOP_ACCESS(*vpp, 0, 0, cr, NULL);
/*
* If vnode is covered, get the
@@ -2569,7 +2569,8 @@ rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
}
}
- if (VOP_REALVP(*vpp, &realvp) == 0 && realvp != *vpp) {
+ if (VOP_REALVP(*vpp, &realvp, NULL) == 0 &&
+ realvp != *vpp) {
/*
* If realvp is different from *vpp
* then release our reference on *vpp, so that
@@ -2603,7 +2604,8 @@ rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
}
}
- if (VOP_REALVP(mc_dvp, &realvp) == 0 && realvp != mc_dvp) {
+ if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 &&
+ realvp != mc_dvp) {
/*
* *vpp is a file, obtain realvp of the parent
* directory vnode.
@@ -2800,7 +2802,7 @@ MCLpath(char **path)
((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
/*
- * The implementation of URLparse gaurantees that the final string will
+ * The implementation of URLparse guarantees that the final string will
* fit in the original one. Replaces '%' occurrences followed by 2 characters
* with its corresponding hexadecimal character.
*/
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index e75bd68a7c..d2969930be 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -249,7 +249,7 @@ rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
bva.va_mask = AT_UID | AT_SIZE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &bva, 0, cr);
+ error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
if (in_crit)
@@ -272,7 +272,8 @@ rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
offset = bva.va_size;
length = va.va_size - bva.va_size;
}
- if (nbl_conflict(vp, NBL_WRITE, offset, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
+ NULL)) {
error = EACCES;
}
}
@@ -322,7 +323,7 @@ rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
VN_RELE(vp);
@@ -426,7 +427,8 @@ rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
* Do a normal single component lookup.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_START, "vop_lookup_start:");
- error = VOP_LOOKUP(dvp, da->da_name, &vp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, da->da_name, &vp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_END, "vop_lookup_end:");
}
@@ -512,7 +514,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
va.va_mask = AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
@@ -567,7 +569,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
* Do the readlink.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_READLINK_START, "vop_readlink_start:");
- error = VOP_READLINK(vp, &uio, cr);
+ error = VOP_READLINK(vp, &uio, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_READLINK_END, "vop_readlink_end:");
#if 0 /* notyet */
@@ -579,7 +581,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -673,7 +675,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
if (nbl_conflict(vp, NBL_READ, ra->ra_offset, ra->ra_count,
- 0)) {
+ 0, NULL)) {
nbl_end_crit(vp);
VN_RELE(vp);
rr->rr_data = NULL;
@@ -691,7 +693,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
va.va_mask = AT_ALL;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
@@ -716,7 +718,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
*/
if (crgetuid(cr) != va.va_uid) {
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START, "vop_access_start:");
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END, "vop_access_end:");
if (error) {
/*
@@ -725,7 +727,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
*/
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START,
"vop_access_start:");
- error = VOP_ACCESS(vp, VEXEC, 0, cr);
+ error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END,
"vop_access_end:");
}
@@ -824,7 +826,7 @@ rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
*/
va.va_mask = AT_ALL;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
freeb(mp);
@@ -868,7 +870,7 @@ done:
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -970,7 +972,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
va.va_mask = AT_UID|AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (error) {
@@ -988,7 +990,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
* is always allowed to write it.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START, "vop_access_start:");
- error = VOP_ACCESS(vp, VWRITE, 0, cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END, "vop_access_end:");
if (error) {
VN_RELE(vp);
@@ -1020,7 +1022,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
nbl_start_crit(vp, RW_READER);
in_crit = 1;
if (nbl_conflict(vp, NBL_WRITE, wa->wa_offset,
- wa->wa_count, 0)) {
+ wa->wa_count, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1125,7 +1127,7 @@ rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
*/
va.va_mask = AT_ALL; /* now we want everything */
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
/* check for overflows */
if (!error) {
@@ -1413,7 +1415,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
va.va_mask = AT_UID|AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, rp->cr);
+ error = VOP_GETATTR(vp, &va, 0, rp->cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
if (!error) {
if (crgetuid(rp->cr) != va.va_uid) {
@@ -1425,7 +1427,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
*/
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START,
"vop_access_start:");
- error = VOP_ACCESS(vp, VWRITE, 0, rp->cr);
+ error = VOP_ACCESS(vp, VWRITE, 0, rp->cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END,
"vop_access_end:");
}
@@ -1437,7 +1439,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
* Check for a conflict with a nbmand-locked region.
*/
if (in_crit && nbl_conflict(vp, NBL_WRITE, rp->wa->wa_offset,
- rp->wa->wa_count, 0)) {
+ rp->wa->wa_count, 0, NULL)) {
error = EACCES;
}
@@ -1598,7 +1600,7 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
va.va_mask = AT_ALL; /* now we want everything */
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START,
"vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, rp->cr);
+ error = VOP_GETATTR(vp, &va, 0, rp->cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END,
"vop_getattr_end:");
if (!error)
@@ -1629,12 +1631,12 @@ rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
*/
if (data_written) {
TRACE_0(TR_FAC_NFS, TR_VOP_PUTPAGE_START, "vop_putpage_start:");
- error = VOP_PUTPAGE(vp, (u_offset_t)off, len, 0, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)off, len, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_PUTPAGE_END, "vop_putpage_end:");
if (!error) {
TRACE_0(TR_FAC_NFS, TR_VOP_FSYNC_START,
"vop_fsync_start:");
- error = VOP_FSYNC(vp, FNODSYNC, cr);
+ error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_FSYNC_END, "vop_fsync_end:");
}
}
@@ -1777,7 +1779,8 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
mode = VWRITE;
if (!(va.va_mask & AT_SIZE) || va.va_type != VREG) {
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_START, "vop_lookup_start:");
- error = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_END, "vop_lookup_end:");
if (!error) {
struct vattr at;
@@ -1786,7 +1789,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
at.va_mask = AT_MODE;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START,
"vop_getattr_start:");
- error = VOP_GETATTR(tvp, &at, 0, cr);
+ error = VOP_GETATTR(tvp, &at, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END,
"vop_getattr_end:");
if (!error)
@@ -1814,7 +1817,8 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
* are conflicting locks.
*/
if (!error && (va.va_type == VREG) && (va.va_mask & AT_SIZE)) {
- lookuperr = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr);
+ lookuperr = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL);
if (!lookuperr &&
rfs4_check_delegated(FWRITE, tvp, va.va_size == 0)) {
@@ -1837,7 +1841,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
in_crit = 1;
bva.va_mask = AT_SIZE;
- error = VOP_GETATTR(tvp, &bva, 0, cr);
+ error = VOP_GETATTR(tvp, &bva, 0, cr, NULL);
if (!error) {
if (va.va_size < bva.va_size) {
offset = va.va_size;
@@ -1848,7 +1852,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
}
if (length) {
if (nbl_conflict(tvp, NBL_WRITE,
- offset, length, 0)) {
+ offset, length, 0, NULL)) {
error = EACCES;
}
}
@@ -1873,7 +1877,8 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
va.va_mode &= ~(VSUID | VSGID);
TRACE_0(TR_FAC_NFS, TR_VOP_CREATE_START, "vop_create_start:");
- error = VOP_CREATE(dvp, name, &va, NONEXCL, mode, &vp, cr, 0);
+ error = VOP_CREATE(dvp, name, &va, NONEXCL, mode, &vp, cr, 0,
+ NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_CREATE_END, "vop_create_end:");
if (!error) {
@@ -1891,7 +1896,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
va.va_mask = AT_ALL;
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START,
"vop_getattr_start:");
- error = VOP_GETATTR(vp, &va, 0, cr);
+ error = VOP_GETATTR(vp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END,
"vop_getattr_end:");
/* check for overflows */
@@ -1906,7 +1911,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
VN_RELE(vp);
}
@@ -1919,7 +1924,7 @@ rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
out:
@@ -1979,7 +1984,8 @@ rfs_remove(struct nfsdiropargs *da, enum nfsstat *status,
/*
* Check for a conflict with a non-blocking mandatory share reservation.
*/
- error = VOP_LOOKUP(vp, da->da_name, &targvp, NULL, 0, NULL, cr);
+ error = VOP_LOOKUP(vp, da->da_name, &targvp, NULL, 0,
+ NULL, cr, NULL, NULL, NULL);
if (error != 0) {
VN_RELE(vp);
*status = puterrno(error);
@@ -2004,20 +2010,20 @@ rfs_remove(struct nfsdiropargs *da, enum nfsstat *status,
if (nbl_need_check(targvp)) {
nbl_start_crit(targvp, RW_READER);
in_crit = 1;
- if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
}
TRACE_0(TR_FAC_NFS, TR_VOP_REMOVE_START, "vop_remove_start:");
- error = VOP_REMOVE(vp, da->da_name, cr);
+ error = VOP_REMOVE(vp, da->da_name, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_REMOVE_END, "vop_remove_end:");
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
out:
if (in_crit)
@@ -2126,7 +2132,7 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
* Check for a conflict with a non-blocking mandatory share reservation.
*/
error = VOP_LOOKUP(fromvp, args->rna_from.da_name, &srcvp, NULL, 0,
- NULL, cr);
+ NULL, cr, NULL, NULL, NULL);
if (error != 0) {
VN_RELE(tovp);
VN_RELE(fromvp);
@@ -2147,8 +2153,8 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
/* Check for delegation on the file being renamed over, if it exists */
if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
- VOP_LOOKUP(tovp, args->rna_to.da_name, &targvp, NULL, 0, NULL, cr)
- == 0) {
+ VOP_LOOKUP(tovp, args->rna_to.da_name, &targvp, NULL, 0, NULL, cr,
+ NULL, NULL, NULL) == 0) {
if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
VN_RELE(tovp);
@@ -2165,7 +2171,7 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
if (nbl_need_check(srcvp)) {
nbl_start_crit(srcvp, RW_READER);
in_crit = 1;
- if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0)) {
+ if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -2173,7 +2179,7 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
TRACE_0(TR_FAC_NFS, TR_VOP_RENAME_START, "vop_rename_start:");
error = VOP_RENAME(fromvp, args->rna_from.da_name,
- tovp, args->rna_to.da_name, cr);
+ tovp, args->rna_to.da_name, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_RENAME_END, "vop_rename_end:");
if (error == 0) {
@@ -2193,8 +2199,8 @@ rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(tovp, 0, cr);
- (void) VOP_FSYNC(fromvp, 0, cr);
+ (void) VOP_FSYNC(tovp, 0, cr, NULL);
+ (void) VOP_FSYNC(fromvp, 0, cr, NULL);
out:
if (in_crit)
@@ -2295,14 +2301,14 @@ rfs_link(struct nfslinkargs *args, enum nfsstat *status,
}
TRACE_0(TR_FAC_NFS, TR_VOP_LINK_START, "vop_link_start:");
- error = VOP_LINK(tovp, fromvp, args->la_to.da_name, cr);
+ error = VOP_LINK(tovp, fromvp, args->la_to.da_name, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_LINK_END, "vop_link_end:");
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(tovp, 0, cr);
- (void) VOP_FSYNC(fromvp, FNODSYNC, cr);
+ (void) VOP_FSYNC(tovp, 0, cr, NULL);
+ (void) VOP_FSYNC(fromvp, FNODSYNC, cr, NULL);
VN_RELE(tovp);
VN_RELE(fromvp);
@@ -2381,7 +2387,8 @@ rfs_symlink(struct nfsslargs *args, enum nfsstat *status,
va.va_mask |= AT_TYPE;
TRACE_0(TR_FAC_NFS, TR_VOP_SYMLINK_START, "vop_symlink_start:");
- error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, args->sla_tnm, cr);
+ error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, args->sla_tnm, cr,
+ NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_SYMLINK_END, "vop_symlink_end:");
/*
@@ -2389,17 +2396,17 @@ rfs_symlink(struct nfsslargs *args, enum nfsstat *status,
*/
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_START, "vop_lookup_start:");
lerror = VOP_LOOKUP(vp, args->sla_from.da_name, &svp, NULL,
- 0, NULL, cr);
+ 0, NULL, cr, NULL, NULL, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_LOOKUP_END, "vop_lookup_end:");
if (!lerror) {
- (void) VOP_FSYNC(svp, 0, cr);
+ (void) VOP_FSYNC(svp, 0, cr, NULL);
VN_RELE(svp);
}
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2477,7 +2484,7 @@ rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
va.va_mask |= AT_TYPE;
TRACE_0(TR_FAC_NFS, TR_VOP_MKDIR_START, "vop_mkdir_start:");
- error = VOP_MKDIR(vp, name, &va, &dvp, cr);
+ error = VOP_MKDIR(vp, name, &va, &dvp, cr, NULL, 0, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_MKDIR_END, "vop_mkdir_end:");
if (!error) {
@@ -2487,7 +2494,7 @@ rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
*/
va.va_mask = AT_ALL; /* We want everything */
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_START, "vop_getattr_start:");
- error = VOP_GETATTR(dvp, &va, 0, cr);
+ error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_GETATTR_END, "vop_getattr_end:");
/* check for overflows */
if (!error) {
@@ -2500,14 +2507,14 @@ rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
/*
* Force new data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(dvp, 0, cr);
+ (void) VOP_FSYNC(dvp, 0, cr, NULL);
VN_RELE(dvp);
}
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2570,13 +2577,13 @@ rfs_rmdir(struct nfsdiropargs *da, enum nfsstat *status,
* remove.
*/
TRACE_0(TR_FAC_NFS, TR_VOP_RMDIR_START, "vop_rmdir_start:");
- error = VOP_RMDIR(vp, da->da_name, rootdir, cr);
+ error = VOP_RMDIR(vp, da->da_name, rootdir, cr, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_RMDIR_END, "vop_rmdir_end:");
/*
* Force modified data and metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, 0, cr);
+ (void) VOP_FSYNC(vp, 0, cr, NULL);
VN_RELE(vp);
@@ -2635,7 +2642,7 @@ rfs_readdir(struct nfsrddirargs *rda, struct nfsrddirres *rd,
TRACE_0(TR_FAC_NFS, TR_VOP_RWLOCK_END, "vop_rwlock_end:");
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_START, "vop_access_start:");
- error = VOP_ACCESS(vp, VREAD, 0, cr);
+ error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
TRACE_0(TR_FAC_NFS, TR_VOP_ACCESS_END, "vop_access_end:");
if (error) {
rd->rd_entries = NULL;
@@ -2673,7 +2680,7 @@ rfs_readdir(struct nfsrddirargs *rda, struct nfsrddirres *rd,
* read directory
*/
TRACE_0(TR_FAC_NFS, TR_VOP_READDIR_START, "vop_readdir_start:");
- error = VOP_READDIR(vp, &uio, cr, &iseof);
+ error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
TRACE_0(TR_FAC_NFS, TR_VOP_READDIR_END, "vop_readdir_end:");
/*
@@ -2707,7 +2714,7 @@ bad:
/*
* Force modified metadata out to stable storage.
*/
- (void) VOP_FSYNC(vp, FNODSYNC, cr);
+ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
#endif
VN_RELE(vp);
@@ -2969,7 +2976,7 @@ acl_perm(struct vnode *vp, struct exportinfo *exi, struct vattr *va, cred_t *cr)
/* dont care default acl */
vsa.vsa_mask = (VSA_ACL | VSA_ACLCNT);
- error = VOP_GETSECATTR(vp, &vsa, 0, cr);
+ error = VOP_GETSECATTR(vp, &vsa, 0, cr, NULL);
if (!error) {
aclcnt = vsa.vsa_aclcnt;
diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c
index d9ae64ddf2..10391a7f42 100644
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c
@@ -105,7 +105,7 @@
* freelist and then trying to place them back on the freelist
* when their reference is released. This means that the when an
* rnode is looked up in the hash queues, then either the rnode
- * is removed from the freelist and that reference is tranfered to
+ * is removed from the freelist and that reference is transferred to
* the new reference or the vnode reference count must be incremented
* accordingly. The mutex for the freelist must be held in order to
* accurately test to see if the rnode is on the freelist or not.
@@ -2095,7 +2095,7 @@ setdirgid(vnode_t *dvp, gid_t *gidp, cred_t *cr)
struct vattr va;
va.va_mask = AT_MODE | AT_GID;
- error = VOP_GETATTR(dvp, &va, 0, cr);
+ error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
if (error)
return (error);
@@ -2123,7 +2123,7 @@ setdirmode(vnode_t *dvp, mode_t *omp, cred_t *cr)
struct vattr va;
va.va_mask = AT_MODE;
- error = VOP_GETATTR(dvp, &va, 0, cr);
+ error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
if (error)
return (error);
@@ -2189,7 +2189,7 @@ rinactive(rnode_t *rp, cred_t *cr)
if (vn_has_cached_data(vp)) {
ASSERT(vp->v_type != VCHR);
if ((rp->r_flags & RDIRTY) && !rp->r_error) {
- error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr);
+ error = VOP_PUTPAGE(vp, (u_offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -3084,7 +3084,7 @@ toomany:
*/
while (cnt-- > 0) {
vp = vplist[cnt];
- (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr, NULL);
VN_RELE(vp);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs_vnops.c b/usr/src/uts/common/fs/nfs/nfs_vnops.c
index 96b7044e6a..befefa580f 100644
--- a/usr/src/uts/common/fs/nfs/nfs_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c
@@ -91,7 +91,8 @@ static int nfsread(vnode_t *, caddr_t, uint_t, int, size_t *, cred_t *);
static int nfssetattr(vnode_t *, struct vattr *, int, cred_t *);
static int nfslookup_dnlc(vnode_t *, char *, vnode_t **, cred_t *);
static int nfslookup_otw(vnode_t *, char *, vnode_t **, cred_t *, int);
-static int nfsrename(vnode_t *, char *, vnode_t *, char *, cred_t *);
+static int nfsrename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *);
static int nfsreaddir(vnode_t *, rddir_cache *, cred_t *);
static int nfs_bio(struct buf *, cred_t *);
static int nfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
@@ -123,59 +124,75 @@ static void nfs_delmap_callback(struct as *, void *, uint_t);
* more details on rnode locking.
*/
-static int nfs_open(vnode_t **, int, cred_t *);
-static int nfs_close(vnode_t *, int, int, offset_t, cred_t *);
+static int nfs_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int nfs_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
static int nfs_read(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
static int nfs_write(vnode_t *, struct uio *, int, cred_t *,
caller_context_t *);
-static int nfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-static int nfs_getattr(vnode_t *, struct vattr *, int, cred_t *);
+static int nfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+static int nfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
+ caller_context_t *);
static int nfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
caller_context_t *);
-static int nfs_access(vnode_t *, int, int, cred_t *);
+static int nfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
static int nfs_accessx(void *, int, cred_t *);
-static int nfs_readlink(vnode_t *, struct uio *, cred_t *);
-static int nfs_fsync(vnode_t *, int, cred_t *);
-static void nfs_inactive(vnode_t *, cred_t *);
+static int nfs_readlink(vnode_t *, struct uio *, cred_t *,
+ caller_context_t *);
+static int nfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void nfs_inactive(vnode_t *, cred_t *, caller_context_t *);
static int nfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
- int, vnode_t *, cred_t *);
+ int, vnode_t *, cred_t *, caller_context_t *,
+ int *, pathname_t *);
static int nfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
- int, vnode_t **, cred_t *, int);
-static int nfs_remove(vnode_t *, char *, cred_t *);
-static int nfs_link(vnode_t *, vnode_t *, char *, cred_t *);
-static int nfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-static int nfs_mkdir(vnode_t *, char *, struct vattr *,
- vnode_t **, cred_t *);
-static int nfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
+ int, vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+static int nfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+ int);
+static int nfs_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+static int nfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+static int nfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
static int nfs_symlink(vnode_t *, char *, struct vattr *, char *,
- cred_t *);
-static int nfs_readdir(vnode_t *, struct uio *, cred_t *, int *);
-static int nfs_fid(vnode_t *, fid_t *);
+ cred_t *, caller_context_t *, int);
+static int nfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
+ caller_context_t *, int);
+static int nfs_fid(vnode_t *, fid_t *, caller_context_t *);
static int nfs_rwlock(vnode_t *, int, caller_context_t *);
static void nfs_rwunlock(vnode_t *, int, caller_context_t *);
-static int nfs_seek(vnode_t *, offset_t, offset_t *);
+static int nfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
static int nfs_getpage(vnode_t *, offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t,
- enum seg_rw, cred_t *);
-static int nfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
-static int nfs_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-static int nfs_addmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
+ enum seg_rw, cred_t *, caller_context_t *);
+static int nfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
+static int nfs_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+static int nfs_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
static int nfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *, caller_context_t *);
static int nfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-static int nfs_realvp(vnode_t *, vnode_t **);
-static int nfs_delmap(vnode_t *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, cred_t *);
-static int nfs_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+static int nfs_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int nfs_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
+ uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
+static int nfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
static int nfs_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
- cred_t *);
-static int nfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-static int nfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
+ cred_t *, caller_context_t *);
+static int nfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+static int nfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
struct vnodeops *nfs_vnodeops;
@@ -233,7 +250,7 @@ nfs_getvnodeops(void)
/* ARGSUSED */
static int
-nfs_open(vnode_t **vpp, int flag, cred_t *cr)
+nfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
int error;
struct vattr va;
@@ -282,8 +299,10 @@ nfs_open(vnode_t **vpp, int flag, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+nfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -357,11 +376,12 @@ nfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
*/
if ((flag & FWRITE) && vn_has_cached_data(vp)) {
if ((VTOMI(vp)->mi_flags & MI_NOCTO)) {
- error = nfs_putpage(vp, (offset_t)0, 0, B_ASYNC, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, B_ASYNC,
+ cr, ct);
if (error == EAGAIN)
error = 0;
} else
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (!error) {
mutex_enter(&rp->r_statelock);
error = rp->r_error;
@@ -478,10 +498,10 @@ nfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
* Copy data.
*/
error = vpm_data_copy(vp, off + on, n, uiop,
- 1, NULL, 0, S_READ);
+ 1, NULL, 0, S_READ);
} else {
base = segmap_getmapflt(segkmap, vp, off + on, n,
- 1, S_READ);
+ 1, S_READ);
error = uiomove(base + on, n, UIO_READ, uiop);
}
@@ -679,23 +699,23 @@ nfs_fwrite:
if (segmap_kpm) {
int pon = uiop->uio_loffset & PAGEOFFSET;
size_t pn = MIN(PAGESIZE - pon,
- uiop->uio_resid);
+ uiop->uio_resid);
int pagecreate;
mutex_enter(&rp->r_statelock);
pagecreate = (pon == 0) && (pn == PAGESIZE ||
- uiop->uio_loffset + pn >= rp->r_size);
+ uiop->uio_loffset + pn >= rp->r_size);
mutex_exit(&rp->r_statelock);
base = segmap_getmapflt(segkmap, vp, off + on,
- pn, !pagecreate, S_WRITE);
+ pn, !pagecreate, S_WRITE);
error = writerp(rp, base + pon, n, uiop,
- pagecreate);
+ pagecreate);
} else {
base = segmap_getmapflt(segkmap, vp, off + on,
- n, 0, S_READ);
+ n, 0, S_READ);
error = writerp(rp, base + on, n, uiop, 0);
}
}
@@ -856,9 +876,10 @@ nfswrite(vnode_t *vp, caddr_t base, uint_t offset, int count, cred_t *cr)
offset += tsize;
if (mi->mi_io_kstats) {
mutex_enter(&mi->mi_lock);
- KSTAT_IO_PTR(mi->mi_io_kstats)->writes++;
- KSTAT_IO_PTR(mi->mi_io_kstats)->nwritten +=
- tsize;
+ KSTAT_IO_PTR(mi->mi_io_kstats)->
+ writes++;
+ KSTAT_IO_PTR(mi->mi_io_kstats)->
+ nwritten += tsize;
mutex_exit(&mi->mi_lock);
}
lwp_stat_update(LWP_STAT_OUBLK, 1);
@@ -995,7 +1016,8 @@ nfsread(vnode_t *vp, caddr_t base, uint_t offset, int count, size_t *residp,
/* ARGSUSED */
static int
-nfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+nfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
+ caller_context_t *ct)
{
if (nfs_zone() != VTOMI(vp)->mi_zone)
@@ -1008,8 +1030,10 @@ nfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
}
+/* ARGSUSED */
static int
-nfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+nfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -1052,7 +1076,7 @@ nfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
mutex_enter(&rp->r_statelock);
rp->r_gcount++;
mutex_exit(&rp->r_statelock);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
mutex_enter(&rp->r_statelock);
if (error && (error == ENOSPC || error == EDQUOT)) {
if (!rp->r_error)
@@ -1096,7 +1120,7 @@ nfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
return (error);
error = secpolicy_vnode_setattr(cr, vp, vap, &va, flags, nfs_accessx,
- vp);
+ vp);
if (error)
return (error);
@@ -1141,7 +1165,7 @@ nfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
rp->r_count > 0 ||
rp->r_mapcnt > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1324,11 +1348,12 @@ static int
nfs_accessx(void *vp, int mode, cred_t *cr)
{
ASSERT(nfs_zone() == VTOMI((vnode_t *)vp)->mi_zone);
- return (nfs_access(vp, mode, 0, cr));
+ return (nfs_access(vp, mode, 0, cr, NULL));
}
+/* ARGSUSED */
static int
-nfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+nfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
struct vattr va;
int error;
@@ -1387,8 +1412,9 @@ found:
static int nfs_do_symlink_cache = 1;
+/* ARGSUSED */
static int
-nfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
+nfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
{
int error;
struct nfsrdlnres rl;
@@ -1483,8 +1509,9 @@ nfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr)
* metadata changes are not cached on the client before being
* sent to the server.
*/
+/* ARGSUSED */
static int
-nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
int error;
@@ -1494,7 +1521,7 @@ nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
if (nfs_zone() != VTOMI(vp)->mi_zone)
return (EIO);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (!error)
error = VTOR(vp)->r_error;
return (error);
@@ -1506,8 +1533,9 @@ nfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
* operation while it was open, it got renamed instead. Here we
* remove the renamed file.
*/
+/* ARGSUSED */
static void
-nfs_inactive(vnode_t *vp, cred_t *cr)
+nfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
@@ -1566,7 +1594,8 @@ redo:
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
ASSERT(vp->v_type != VCHR);
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0,
+ cr, ct);
if (error) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -1609,9 +1638,11 @@ redo:
* Remote file system operations having to do with directory manipulation.
*/
+/* ARGSUSED */
static int
nfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
int error;
vnode_t *vp;
@@ -1734,7 +1765,7 @@ nfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* just need to check access.
*/
if (strcmp(nm, ".") == 0) {
- error = nfs_access(dvp, VEXEC, 0, cr);
+ error = nfs_access(dvp, VEXEC, 0, cr, NULL);
if (error)
return (error);
VN_HOLD(dvp);
@@ -1789,7 +1820,7 @@ nfslookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
return (error);
vp = dnlc_lookup(dvp, nm);
if (vp != NULL) {
- error = nfs_access(dvp, VEXEC, 0, cr);
+ error = nfs_access(dvp, VEXEC, 0, cr, NULL);
if (error) {
VN_RELE(vp);
return (error);
@@ -1884,7 +1915,8 @@ nfslookup_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
/* ARGSUSED */
static int
nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
- int mode, vnode_t **vpp, cred_t *cr, int lfaware)
+ int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
struct nfscreatargs args;
@@ -1925,7 +1957,7 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* just need to check access.
*/
} else if (strcmp(nm, ".") == 0) {
- error = nfs_access(dvp, VEXEC, 0, cr);
+ error = nfs_access(dvp, VEXEC, 0, cr, ct);
if (error) {
nfs_rw_exit(&drp->r_rwlock);
return (error);
@@ -1954,7 +1986,7 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
VN_RELE(tempvp);
}
- if (!(error = VOP_ACCESS(vp, mode, 0, cr))) {
+ if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
if ((vattr.va_mask & AT_SIZE) &&
vp->v_type == VREG) {
vattr.va_mask = AT_SIZE;
@@ -1969,7 +2001,7 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
/*
* existing file got truncated, notify.
*/
- vnevent_create(vp);
+ vnevent_create(vp, ct);
*vpp = vp;
}
return (error);
@@ -2130,8 +2162,9 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
* we rename it instead of removing it and nfs_inactive
* will remove the new name.
*/
+/* ARGSUSED */
static int
-nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
+nfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
{
int error;
struct nfsdiropargs da;
@@ -2184,7 +2217,7 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
(rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
mutex_exit(&rp->r_statelock);
tmpname = newname();
- error = nfsrename(dvp, nm, dvp, tmpname, cr);
+ error = nfsrename(dvp, nm, dvp, tmpname, cr, ct);
if (error)
kmem_free(tmpname, MAXNAMELEN);
else {
@@ -2213,7 +2246,7 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
*/
if (vn_has_cached_data(vp) &&
((rp->r_flags & RDIRTY) || rp->r_count > 0)) {
- error = nfs_putpage(vp, (offset_t)0, 0, 0, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
if (error && (error == ENOSPC || error == EDQUOT)) {
mutex_enter(&rp->r_statelock);
if (!rp->r_error)
@@ -2253,7 +2286,7 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
}
if (error == 0) {
- vnevent_remove(vp, dvp, nm);
+ vnevent_remove(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -2262,8 +2295,10 @@ nfs_remove(vnode_t *dvp, char *nm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
+nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
struct nfslinkargs args;
@@ -2274,7 +2309,7 @@ nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
if (nfs_zone() != VTOMI(tdvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
args.la_from = VTOFH(svp);
@@ -2310,29 +2345,32 @@ nfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr)
/*
* Notify the source file of this link operation.
*/
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
return (error);
}
+/* ARGSUSED */
static int
-nfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
vnode_t *realvp;
if (nfs_zone() != VTOMI(odvp)->mi_zone)
return (EPERM);
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
- return (nfsrename(odvp, onm, ndvp, nnm, cr));
+ return (nfsrename(odvp, onm, ndvp, nnm, cr, ct));
}
/*
* nfsrename does the real work of renaming in NFS Version 2.
*/
static int
-nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
+nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+ caller_context_t *ct)
{
int error;
enum nfsstat status;
@@ -2465,10 +2503,10 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
* the server removing the file completely.
*/
tmpname = newname();
- error = nfs_link(ndvp, nvp, tmpname, cr);
+ error = nfs_link(ndvp, nvp, tmpname, cr, NULL, 0);
if (error == EOPNOTSUPP) {
error = nfs_rename(ndvp, nnm, ndvp, tmpname,
- cr);
+ cr, NULL, 0);
}
if (error) {
kmem_free(tmpname, MAXNAMELEN);
@@ -2570,7 +2608,7 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
if (rp->r_unldvp != NULL) {
if (strcmp(rp->r_unlname, onm) == 0) {
(void) strncpy(rp->r_unlname,
- nnm, MAXNAMELEN);
+ nnm, MAXNAMELEN);
rp->r_unlname[MAXNAMELEN - 1] = '\0';
if (ndvp != rp->r_unldvp) {
@@ -2595,13 +2633,13 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
if (error == 0) {
if (nvp)
- vnevent_rename_dest(nvp, ndvp, nnm);
+ vnevent_rename_dest(nvp, ndvp, nnm, ct);
if (odvp != ndvp)
- vnevent_rename_dest_dir(ndvp);
+ vnevent_rename_dest_dir(ndvp, ct);
ASSERT(ovp != NULL);
- vnevent_rename_src(ovp, odvp, onm);
+ vnevent_rename_src(ovp, odvp, onm, ct);
}
if (nvp) {
@@ -2615,8 +2653,10 @@ nfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
+nfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int error;
struct nfscreatargs args;
@@ -2701,8 +2741,10 @@ nfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
+nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
enum nfsstat status;
@@ -2789,7 +2831,7 @@ nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
}
if (error == 0) {
- vnevent_rmdir(vp, dvp, nm);
+ vnevent_rmdir(vp, dvp, nm, ct);
}
VN_RELE(vp);
@@ -2798,8 +2840,10 @@ nfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr)
+nfs_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int error;
struct nfsslargs args;
@@ -2868,8 +2912,10 @@ static int nfs_shrinkreaddir = 0;
* may return only one block's worth of entries. Entries may be compressed
* on the server.
*/
+/* ARGSUSED */
static int
-nfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp)
+nfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int error;
size_t count;
@@ -2980,7 +3026,7 @@ top:
*/
mutex_exit(&rp->r_statelock);
(void) nfs_rw_enter_sig(&rp->r_rwlock,
- RW_READER, FALSE);
+ RW_READER, FALSE);
rddir_cache_rele(rdc);
if (nrdc != NULL)
rddir_cache_rele(nrdc);
@@ -2988,7 +3034,7 @@ top:
}
mutex_exit(&rp->r_statelock);
(void) nfs_rw_enter_sig(&rp->r_rwlock,
- RW_READER, FALSE);
+ RW_READER, FALSE);
rddir_cache_rele(rdc);
goto top;
}
@@ -3434,8 +3480,9 @@ nfs_bio(struct buf *bp, cred_t *cr)
return (error);
}
+/* ARGSUSED */
static int
-nfs_fid(vnode_t *vp, fid_t *fidp)
+nfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
struct nfs_fid *fp;
rnode_t *rp;
@@ -3486,7 +3533,7 @@ nfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-nfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+nfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
/*
@@ -3514,10 +3561,11 @@ static int nfs_lostpage = 0; /* number of times we lost original page */
/*
* Return all the pages from [off..off+len) in file
*/
+/* ARGSUSED */
static int
nfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
rnode_t *rp;
int error;
@@ -3661,8 +3709,8 @@ reread:
else if (blkoff == rp->r_nextr)
readahead = nfs_nra;
else if (rp->r_nextr > blkoff &&
- ((ra_window = (rp->r_nextr - blkoff) / bsize)
- <= (nfs_nra - 1)))
+ ((ra_window = (rp->r_nextr - blkoff) / bsize)
+ <= (nfs_nra - 1)))
readahead = nfs_nra - ra_window;
else
readahead = 0;
@@ -3736,7 +3784,7 @@ again:
} else
blksize = rp->r_size - blkoff;
} else if ((off == 0) ||
- (off != rp->r_nextr && !readahead_issued)) {
+ (off != rp->r_nextr && !readahead_issued)) {
blksize = PAGESIZE;
blkoff = off; /* block = page here */
} else
@@ -3818,9 +3866,9 @@ again:
}
if (!readahead_issued && !error) {
- mutex_enter(&rp->r_statelock);
- rp->r_nextr = io_off + io_len;
- mutex_exit(&rp->r_statelock);
+ mutex_enter(&rp->r_statelock);
+ rp->r_nextr = io_off + io_len;
+ mutex_exit(&rp->r_statelock);
}
}
}
@@ -3970,8 +4018,10 @@ nfs_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/* ARGSUSED */
static int
-nfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+nfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -4172,7 +4222,7 @@ nfs_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
*/
if (!(flags & B_ASYNC)) {
error = nfs_putpage(vp, io_off, io_len,
- B_INVAL | B_FORCE, cr);
+ B_INVAL | B_FORCE, cr, NULL);
}
} else {
if (error)
@@ -4188,9 +4238,11 @@ nfs_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -4292,7 +4344,8 @@ done:
/* ARGSUSED */
static int
nfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
rnode_t *rp;
@@ -4315,9 +4368,10 @@ nfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
return (0);
}
+/* ARGSUSED */
static int
-nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, cred_t *cr)
+nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
+ struct flk_callback *flk_cbp, cred_t *cr, caller_context_t *ct)
{
netobj lm_fh;
int rc;
@@ -4374,7 +4428,7 @@ nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (!lm_safelock(vp, bfp, cr))
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
rp = VTOR(vp);
@@ -4404,26 +4458,27 @@ nfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
if (cmd != F_GETLK) {
mutex_enter(&rp->r_statelock);
while (rp->r_count > 0) {
- if (intr) {
- klwp_t *lwp = ttolwp(curthread);
+ if (intr) {
+ klwp_t *lwp = ttolwp(curthread);
- if (lwp != NULL)
- lwp->lwp_nostop++;
- if (cv_wait_sig(&rp->r_cv, &rp->r_statelock) == 0) {
+ if (lwp != NULL)
+ lwp->lwp_nostop++;
+ if (cv_wait_sig(&rp->r_cv, &rp->r_statelock)
+ == 0) {
+ if (lwp != NULL)
+ lwp->lwp_nostop--;
+ rc = EINTR;
+ break;
+ }
if (lwp != NULL)
lwp->lwp_nostop--;
- rc = EINTR;
- break;
- }
- if (lwp != NULL)
- lwp->lwp_nostop--;
- } else
+ } else
cv_wait(&rp->r_cv, &rp->r_statelock);
}
mutex_exit(&rp->r_statelock);
if (rc != 0)
goto done;
- error = nfs_putpage(vp, (offset_t)0, 0, B_INVAL, cr);
+ error = nfs_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
if (error) {
if (error == ENOSPC || error == EDQUOT) {
mutex_enter(&rp->r_statelock);
@@ -4512,7 +4567,7 @@ nfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
/* ARGSUSED */
static int
-nfs_realvp(vnode_t *vp, vnode_t **vpp)
+nfs_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
return (EINVAL);
@@ -4531,7 +4586,8 @@ nfs_realvp(vnode_t *vp, vnode_t **vpp)
/* ARGSUSED */
static int
nfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
int caller_found;
int error;
@@ -4661,10 +4717,10 @@ nfs_delmap_callback(struct as *as, void *arg, uint_t event)
if ((mi->mi_flags & MI_NOCTO) ||
nfs_zone() != mi->mi_zone)
error = nfs_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_ASYNC, dmapp->cr);
+ B_ASYNC, dmapp->cr, NULL);
else
error = nfs_putpage(dmapp->vp, dmapp->off, dmapp->len,
- 0, dmapp->cr);
+ 0, dmapp->cr, NULL);
if (!error) {
mutex_enter(&rp->r_statelock);
error = rp->r_error;
@@ -4676,7 +4732,7 @@ nfs_delmap_callback(struct as *as, void *arg, uint_t event)
if ((rp->r_flags & RDIRECTIO) || (mi->mi_flags & MI_DIRECTIO))
(void) nfs_putpage(dmapp->vp, dmapp->off, dmapp->len,
- B_INVAL, dmapp->cr);
+ B_INVAL, dmapp->cr, NULL);
dmapp->caller->error = error;
(void) as_delete_callback(as, arg);
@@ -4685,7 +4741,8 @@ nfs_delmap_callback(struct as *as, void *arg, uint_t event)
/* ARGSUSED */
static int
-nfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+nfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
int error = 0;
@@ -4748,7 +4805,7 @@ nfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
break;
}
return (error ? EINVAL : 0);
- }
+ }
case _PC_XATTR_EXISTS:
*valp = 0;
@@ -4806,9 +4863,10 @@ nfs_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
nfs_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, cred_t *cr)
+ int flags, cred_t *cr, caller_context_t *ct)
{
int error;
rnode_t *rp;
@@ -4837,8 +4895,10 @@ nfs_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
return (error);
}
+/* ARGSUSED */
static int
-nfs_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -4856,8 +4916,10 @@ nfs_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (ENOSYS);
}
+/* ARGSUSED */
static int
-nfs_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
+nfs_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
mntinfo_t *mi;
@@ -4872,11 +4934,13 @@ nfs_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr)
return (error);
}
- return (fs_fab_acl(vp, vsecattr, flag, cr));
+ return (fs_fab_acl(vp, vsecattr, flag, cr, ct));
}
+/* ARGSUSED */
static int
-nfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
+nfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+ caller_context_t *ct)
{
int error;
struct shrlock nshr;
@@ -4905,7 +4969,7 @@ nfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr)
* request off to the local share code.
*/
if (VTOMI(vp)->mi_flags & MI_LLOCK)
- return (fs_shrlock(vp, cmd, shr, flag, cr));
+ return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
switch (cmd) {
case F_SHARE:
diff --git a/usr/src/uts/common/fs/objfs/objfs_common.c b/usr/src/uts/common/fs/objfs/objfs_common.c
index 35252c0d91..bdce50353e 100644
--- a/usr/src/uts/common/fs/objfs/objfs_common.c
+++ b/usr/src/uts/common/fs/objfs/objfs_common.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,7 +36,8 @@
*/
/* ARGSUSED */
int
-objfs_dir_open(vnode_t **cpp, int flag, cred_t *cr)
+objfs_dir_open(vnode_t **cpp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
return (EINVAL);
@@ -50,17 +50,19 @@ objfs_dir_open(vnode_t **cpp, int flag, cred_t *cr)
*/
/* ARGSUSED */
int
-objfs_common_close(vnode_t *vp, int flag, int count, offset_t off, cred_t *cr)
+objfs_common_close(vnode_t *vp, int flag, int count, offset_t off, cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
/*
- * For directories, ensure we're not open for writting.
+ * For directories, ensure we're not open for writing.
*/
/* ARGSUSED */
int
-objfs_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+objfs_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VWRITE)
return (EACCES);
diff --git a/usr/src/uts/common/fs/objfs/objfs_data.c b/usr/src/uts/common/fs/objfs/objfs_data.c
index 4e050112fb..6777cd469e 100644
--- a/usr/src/uts/common/fs/objfs/objfs_data.c
+++ b/usr/src/uts/common/fs/objfs/objfs_data.c
@@ -455,7 +455,8 @@ objfs_create_data(vnode_t *pvp)
/* ARGSUSED */
static int
-objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
struct module *mp;
timestruc_t now;
@@ -480,7 +481,8 @@ objfs_data_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static int
-objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & (VWRITE|VEXEC))
return (EACCES);
@@ -490,7 +492,8 @@ objfs_data_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
int
-objfs_data_open(vnode_t **cpp, int flag, cred_t *cr)
+objfs_data_open(vnode_t **cpp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
if (flag & FWRITE)
return (EINVAL);
@@ -556,7 +559,7 @@ read_symtab(void *addr, size_t size, off_t offset, uio_t *uio)
/* ARGSUSED */
static int
objfs_data_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr,
- caller_context_t *ct)
+ caller_context_t *ct)
{
int error = 0;
objfs_datanode_t *dnode = vp->v_data;
@@ -745,7 +748,8 @@ error:
/* ARGSUSED */
static int
-objfs_data_seek(vnode_t *vp, offset_t off, offset_t *offp)
+objfs_data_seek(vnode_t *vp, offset_t off, offset_t *offp,
+ caller_context_t *ct)
{
return (0);
}
diff --git a/usr/src/uts/common/fs/objfs/objfs_odir.c b/usr/src/uts/common/fs/objfs/objfs_odir.c
index a7ef0ed502..9558061e83 100644
--- a/usr/src/uts/common/fs/objfs/objfs_odir.c
+++ b/usr/src/uts/common/fs/objfs/objfs_odir.c
@@ -63,7 +63,8 @@ objfs_create_odirnode(vnode_t *pvp, struct modctl *mp)
/* ARGSUSED */
static int
-objfs_odir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+objfs_odir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
timestruc_t now;
diff --git a/usr/src/uts/common/fs/objfs/objfs_root.c b/usr/src/uts/common/fs/objfs/objfs_root.c
index 1e9bb8c1f0..06f06d35f9 100644
--- a/usr/src/uts/common/fs/objfs/objfs_root.c
+++ b/usr/src/uts/common/fs/objfs/objfs_root.c
@@ -38,7 +38,8 @@
extern int last_module_id;
-static int objfs_root_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *);
+static int objfs_root_do_lookup(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
static int objfs_root_do_readdir(vnode_t *, struct dirent64 *, int *,
offset_t *, offset_t *, void *);
@@ -54,7 +55,8 @@ objfs_create_root(vfs_t *vfsp)
/* ARGSUSED */
static int
-objfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+objfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
vap->va_type = VDIR;
vap->va_mode = 0555;
@@ -67,8 +69,10 @@ objfs_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
return (objfs_common_getattr(vp, vap));
}
+/* ARGSUSED */
static int
-objfs_root_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop)
+objfs_root_do_lookup(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
{
int result = ENOENT;
struct modctl *mp;
@@ -148,11 +152,12 @@ objfs_root_do_readdir(vnode_t *vp, struct dirent64 *dp, int *eofp,
/* ARGSUSED */
static int
-objfs_root_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+objfs_root_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
struct modctl *mp = &modules;
- return (gfs_dir_readdir(vp, uiop, eofp, &mp));
+ return (gfs_dir_readdir(vp, uiop, eofp, &mp, cr, ct));
}
const fs_operation_def_t objfs_tops_root[] = {
diff --git a/usr/src/uts/common/fs/pathname.c b/usr/src/uts/common/fs/pathname.c
index 904477f3a4..82d2e36973 100644
--- a/usr/src/uts/common/fs/pathname.c
+++ b/usr/src/uts/common/fs/pathname.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -210,7 +209,7 @@ pn_getsymlink(vnode_t *vp, struct pathname *pnp, cred_t *crp)
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_extflg = UIO_COPY_CACHED;
auio.uio_resid = pnp->pn_bufsize;
- if ((error = VOP_READLINK(vp, &auio, crp)) == 0) {
+ if ((error = VOP_READLINK(vp, &auio, crp, NULL)) == 0) {
pnp->pn_pathlen = pnp->pn_bufsize - auio.uio_resid;
if (pnp->pn_pathlen == pnp->pn_bufsize)
error = ENAMETOOLONG;
diff --git a/usr/src/uts/common/fs/pcfs/pc_dir.c b/usr/src/uts/common/fs/pcfs/pc_dir.c
index 616efe23cb..cc6d1a8fe4 100644
--- a/usr/src/uts/common/fs/pcfs/pc_dir.c
+++ b/usr/src/uts/common/fs/pcfs/pc_dir.c
@@ -387,7 +387,8 @@ pc_dirremove(
struct pcnode *dp,
char *namep,
struct vnode *cdir,
- enum vtype type)
+ enum vtype type,
+ caller_context_t *ctp)
{
struct pcslot slot;
struct pcnode *pcp;
@@ -467,9 +468,9 @@ pc_dirremove(
if (error == 0) {
if (type == VDIR) {
- vnevent_rmdir(PCTOV(pcp), vp, namep);
+ vnevent_rmdir(PCTOV(pcp), vp, namep, ctp);
} else {
- vnevent_remove(PCTOV(pcp), vp, namep);
+ vnevent_remove(PCTOV(pcp), vp, namep, ctp);
}
}
@@ -556,7 +557,8 @@ pc_rename(
struct pcnode *dp, /* parent directory */
struct pcnode *tdp, /* target directory */
char *snm, /* source file name */
- char *tnm) /* target file name */
+ char *tnm, /* target file name */
+ caller_context_t *ctp)
{
struct pcnode *pcp; /* pcnode we are trying to rename */
struct pcnode *tpcp; /* pcnode that's in our way */
@@ -633,7 +635,7 @@ top:
newisdir = tpcp->pc_entry.pcd_attr & PCA_DIR;
brelse(slot.sl_bp);
- vnevent_rename_dest(PCTOV(tpcp), PCTOV(tdp), tnm);
+ vnevent_rename_dest(PCTOV(tpcp), PCTOV(tdp), tnm, ctp);
VN_RELE(PCTOV(tpcp));
/*
@@ -648,7 +650,7 @@ top:
} else {
/* nondir/nondir, remove target */
error = pc_dirremove(tdp, tnm,
- (struct vnode *)NULL, VREG);
+ (struct vnode *)NULL, VREG, ctp);
if (error == 0) {
VN_RELE(PCTOV(pcp));
goto top;
@@ -657,7 +659,7 @@ top:
} else if (oldisdir) {
/* dir/dir, remove target */
error = pc_dirremove(tdp, tnm,
- (struct vnode *)NULL, VDIR);
+ (struct vnode *)NULL, VDIR, ctp);
if (error == 0) {
VN_RELE(PCTOV(pcp));
goto top;
@@ -815,9 +817,9 @@ top:
}
}
out:
- vnevent_rename_src(PCTOV(pcp), PCTOV(dp), snm);
+ vnevent_rename_src(PCTOV(pcp), PCTOV(dp), snm, ctp);
if (dp != tdp) {
- vnevent_rename_dest_dir(PCTOV(tdp));
+ vnevent_rename_dest_dir(PCTOV(tdp), ctp);
}
VN_RELE(PCTOV(pcp));
diff --git a/usr/src/uts/common/fs/pcfs/pc_node.c b/usr/src/uts/common/fs/pcfs/pc_node.c
index 6dbc28dbba..33d6fd2659 100644
--- a/usr/src/uts/common/fs/pcfs/pc_node.c
+++ b/usr/src/uts/common/fs/pcfs/pc_node.c
@@ -207,7 +207,8 @@ syncpcp(struct pcnode *pcp, int flags)
if (!vn_has_cached_data(PCTOV(pcp)))
err = 0;
else
- err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags, kcred);
+ err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags,
+ kcred, NULL);
return (err);
}
diff --git a/usr/src/uts/common/fs/pcfs/pc_vfsops.c b/usr/src/uts/common/fs/pcfs/pc_vfsops.c
index 378fb15954..3697041c88 100644
--- a/usr/src/uts/common/fs/pcfs/pc_vfsops.c
+++ b/usr/src/uts/common/fs/pcfs/pc_vfsops.c
@@ -415,7 +415,7 @@ devlookup_done:
error = ENXIO;
if ((error != 0) ||
- (error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 ||
+ (error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
VN_RELE(bvp);
return (error);
@@ -695,7 +695,7 @@ pcfs_mount(
return (EBUSY);
}
error = VOP_OPEN(&devvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, cr);
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, cr, NULL);
if (error) {
VN_RELE(devvp);
return (error);
@@ -770,7 +770,7 @@ pcfs_mount(
errout:
(void) VOP_CLOSE(devvp,
vfsp->vfs_flag & VFS_RDONLY ? FREAD : FREAD | FWRITE,
- 1, (offset_t)0, cr);
+ 1, (offset_t)0, cr, NULL);
VN_RELE(devvp);
mutex_destroy(&fsp->pcfs_lock);
kmem_free(fsp, sizeof (*fsp));
@@ -1100,7 +1100,7 @@ pc_invalfat(struct pcfs *fsp)
*/
(void) VOP_CLOSE(fsp->pcfs_devvp,
(PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
- 1, (offset_t)0, CRED());
+ 1, (offset_t)0, CRED(), NULL);
}
void
diff --git a/usr/src/uts/common/fs/pcfs/pc_vnops.c b/usr/src/uts/common/fs/pcfs/pc_vnops.c
index 0becbc9b3c..9f77542636 100644
--- a/usr/src/uts/common/fs/pcfs/pc_vnops.c
+++ b/usr/src/uts/common/fs/pcfs/pc_vnops.c
@@ -69,45 +69,57 @@
#include <fs/fs_subr.h>
-static int pcfs_open(struct vnode **, int, struct cred *);
-static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *);
+static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct);
+static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *ct);
static int pcfs_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int pcfs_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
-static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *);
+ caller_context_t *);
+static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *,
+ caller_context_t *ct);
static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *,
caller_context_t *);
-static int pcfs_access(struct vnode *, int, int, struct cred *);
+static int pcfs_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *ct);
static int pcfs_lookup(struct vnode *, char *, struct vnode **,
- struct pathname *, int, struct vnode *, struct cred *);
+ struct pathname *, int, struct vnode *, struct cred *,
+ caller_context_t *, int *, pathname_t *);
static int pcfs_create(struct vnode *, char *, struct vattr *,
- enum vcexcl, int mode, struct vnode **, struct cred *, int);
-static int pcfs_remove(struct vnode *, char *, struct cred *);
+ enum vcexcl, int mode, struct vnode **, struct cred *, int,
+ caller_context_t *, vsecattr_t *);
+static int pcfs_remove(struct vnode *, char *, struct cred *,
+ caller_context_t *, int);
static int pcfs_rename(struct vnode *, char *, struct vnode *, char *,
- struct cred *);
+ struct cred *, caller_context_t *, int);
static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
- struct cred *);
-static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *);
-static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *);
-static int pcfs_fsync(struct vnode *, int, struct cred *);
-static void pcfs_inactive(struct vnode *, struct cred *);
-static int pcfs_fid(struct vnode *vp, struct fid *fidp);
+ struct cred *, caller_context_t *, int, vsecattr_t *);
+static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
+ caller_context_t *, int);
+static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *,
+ caller_context_t *, int);
+static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
+static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *);
+static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *);
static int pcfs_space(struct vnode *, int, struct flock64 *, int,
offset_t, cred_t *, caller_context_t *);
static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[],
- size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
+ size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
+ caller_context_t *);
static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
-static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *);
+static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
+ caller_context_t *);
static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t,
- size_t, uchar_t, uchar_t, uint_t, struct cred *);
+ size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t,
- size_t, uint_t, uint_t, uint_t, struct cred *);
-static int pcfs_seek(struct vnode *, offset_t, offset_t *);
-static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+ size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
+static int pcfs_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
+static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
struct cred *);
@@ -175,7 +187,8 @@ static int
pcfs_open(
struct vnode **vpp,
int flag,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -191,7 +204,8 @@ pcfs_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
return (0);
}
@@ -537,7 +551,8 @@ pcfs_getattr(
struct vnode *vp,
struct vattr *vap,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -556,7 +571,7 @@ pcfs_getattr(
/*
* Note that we don't check for "invalid node" (PC_INVAL) here
* only in order to make stat() succeed. We allow no I/O on such
- * a node, but do allow to check for its existance.
+ * a node, but do allow to check for its existence.
*/
if ((pcp = VTOPC(vp)) == NULL) {
pc_unlockfs(fsp);
@@ -816,7 +831,8 @@ pcfs_access(
struct vnode *vp,
int mode,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -847,7 +863,8 @@ static int
pcfs_fsync(
struct vnode *vp,
int syncflag,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -875,7 +892,8 @@ pcfs_fsync(
static void
pcfs_inactive(
struct vnode *vp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -946,7 +964,10 @@ pcfs_lookup(
struct pathname *pnp,
int flags,
struct vnode *rdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1001,7 +1022,9 @@ pcfs_create(
int mode,
struct vnode **vpp,
struct cred *cr,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
struct pcnode *pcp;
@@ -1055,7 +1078,7 @@ pcfs_create(
error = EISDIR;
} else if (mode) {
error = pcfs_access(PCTOV(pcp), mode, 0,
- cr);
+ cr, ct);
} else {
error = 0;
}
@@ -1068,7 +1091,7 @@ pcfs_create(
if (error) {
VN_RELE(PCTOV(pcp));
} else {
- vnevent_create(PCTOV(pcp));
+ vnevent_create(PCTOV(pcp), ct);
}
}
}
@@ -1087,7 +1110,9 @@ static int
pcfs_remove(
struct vnode *vp,
char *nm,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1109,7 +1134,7 @@ pcfs_remove(
return (EACCES);
}
}
- error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG);
+ error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct);
pc_unlockfs(fsp);
return (error);
}
@@ -1126,7 +1151,9 @@ pcfs_rename(
char *snm, /* old (source) entry name */
struct vnode *tdvp, /* new (target) parent vnode */
char *tnm, /* new (target) entry name */
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct pcfs *fsp;
struct pcnode *dp; /* parent pcnode */
@@ -1140,7 +1167,7 @@ pcfs_rename(
/*
* make sure we can muck with this directory.
*/
- error = pcfs_access(sdvp, VWRITE, 0, cr);
+ error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
if (error) {
return (error);
}
@@ -1152,7 +1179,7 @@ pcfs_rename(
pc_unlockfs(fsp);
return (EIO);
}
- error = pc_rename(dp, tdp, snm, tnm);
+ error = pc_rename(dp, tdp, snm, tnm, ct);
pc_unlockfs(fsp);
return (error);
}
@@ -1164,7 +1191,10 @@ pcfs_mkdir(
char *nm,
struct vattr *vap,
struct vnode **vpp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1206,7 +1236,9 @@ pcfs_rmdir(
struct vnode *dvp,
char *nm,
struct vnode *cdir,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct pcfs *fsp;
struct pcnode *pcp;
@@ -1230,7 +1262,7 @@ pcfs_rmdir(
}
}
- error = pc_dirremove(pcp, nm, cdir, VDIR);
+ error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
pc_unlockfs(fsp);
return (error);
}
@@ -1246,7 +1278,9 @@ pcfs_readdir(
struct vnode *dvp,
struct uio *uiop,
struct cred *cr,
- int *eofp)
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct pcnode *pcp;
struct pcfs *fsp;
@@ -1517,6 +1551,7 @@ out:
/*
* Return all the pages from [off..off+len] in given file
*/
+/* ARGSUSED */
static int
pcfs_getpage(
struct vnode *vp,
@@ -1528,7 +1563,8 @@ pcfs_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
int err;
@@ -1574,7 +1610,8 @@ pcfs_putpage(
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct pcnode *pcp;
page_t *pp;
@@ -1814,7 +1851,8 @@ pcfs_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int error;
@@ -1861,7 +1899,8 @@ static int
pcfs_seek(
struct vnode *vp,
offset_t ooff,
- offset_t *noffp)
+ offset_t *noffp,
+ caller_context_t *ct)
{
if (*noffp < 0)
return (EINVAL);
@@ -1882,7 +1921,8 @@ pcfs_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
if (vp->v_flag & VNOMAP)
return (ENOSYS);
@@ -1900,7 +1940,8 @@ pcfs_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
if (vp->v_flag & VNOMAP)
return (ENOSYS);
@@ -1916,7 +1957,8 @@ pcfs_pathconf(
struct vnode *vp,
int cmd,
ulong_t *valp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
ulong_t val;
int error = 0;
@@ -2018,7 +2060,7 @@ pcfs_space(
return (EINVAL);
vattr.va_mask = AT_SIZE;
vattr.va_size = bfp->l_start;
- error = VOP_SETATTR(vp, &vattr, 0, cr, ct);
+ error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct);
}
return (error);
}
@@ -2373,8 +2415,9 @@ pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
return (0);
}
+/* ARGSUSED */
static int
-pcfs_fid(struct vnode *vp, struct fid *fidp)
+pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct pc_fid *pcfid;
struct pcnode *pcp;
diff --git a/usr/src/uts/common/fs/portfs/port_fd.c b/usr/src/uts/common/fs/portfs/port_fd.c
index dd26b0af9c..c1f868ad11 100644
--- a/usr/src/uts/common/fs/portfs/port_fd.c
+++ b/usr/src/uts/common/fs/portfs/port_fd.c
@@ -171,7 +171,7 @@ port_cache_lookup_fp(port_fdcache_t *pcp, int fd, file_t *fp)
* will be submitted to the event port with port_send_event().
* Otherwise VOP_POLL does not return events but it delivers a pointer to a
* pollhead_t structure. In such a case the corresponding file system behind
- * VOP_POLL will use the pollwakeup() function to notify about exisiting
+ * VOP_POLL will use the pollwakeup() function to notify about existing
* events.
*/
int
@@ -314,7 +314,7 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events,
* poll routine to change.
*/
curthread->t_pollcache = (pollcache_t *)pcp;
- error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php);
+ error = VOP_POLL(fp->f_vnode, events, 0, &revents, &php, NULL);
curthread->t_pollcache = NULL;
/*
@@ -512,7 +512,7 @@ port_bind_pollhead(pollhead_t **php, polldat_t *pdp, short *revents)
pdp->pd_php = *php;
fp = pdp->pd_fp;
curthread->t_pollcache = (pollcache_t *)pdp->pd_pcache;
- error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, revents, php);
+ error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0, revents, php, NULL);
curthread->t_pollcache = NULL;
return (error);
}
diff --git a/usr/src/uts/common/fs/portfs/port_fop.c b/usr/src/uts/common/fs/portfs/port_fop.c
index 8e07046236..d3530280d2 100644
--- a/usr/src/uts/common/fs/portfs/port_fop.c
+++ b/usr/src/uts/common/fs/portfs/port_fop.c
@@ -57,7 +57,7 @@
* The time stamps collected by a stat(2) call are passed in fo_atime,
* fo_mtime, fo_ctime. At the time a file events watch is registered, the
* time stamps passed in are compared with the current time stamps of the
- * file. If it has changed, relavant events are sent immediately. If the time
+ * file. If it has changed, relevant events are sent immediately. If the time
* stamps are all '0', they will not be compared.
*
*
@@ -206,33 +206,40 @@ static void port_close_fop(void *arg, int port, pid_t pid, int lastclose);
/*
* port fop functions that will be the fem hooks.
*/
-static int port_fop_open(femarg_t *vf, int mode, cred_t *cr);
+static int port_fop_open(femarg_t *vf, int mode, cred_t *cr,
+ caller_context_t *);
static int port_fop_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct);
+ struct caller_context *ct);
static int port_fop_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- caller_context_t *ct);
+ caller_context_t *ct);
static int port_fop_map(femarg_t *vf, offset_t off, struct as *as,
- caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxport,
- uint_t flags, cred_t *cr);
+ caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxport,
+ uint_t flags, cred_t *cr, caller_context_t *ct);
static int port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
- caller_context_t *ct);
+ caller_context_t *ct);
static int port_fop_create(femarg_t *vf, char *name, vattr_t *vap,
- vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr,
- int flag);
-static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr);
-static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr);
+ vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp);
+static int port_fop_remove(femarg_t *vf, char *nm, cred_t *cr,
+ caller_context_t *ct, int flags);
+static int port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags);
static int port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct, int flags);
static int port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap,
- vnode_t **vpp, cred_t *cr);
-static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr);
-static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp);
+ vnode_t **vpp, cred_t *cr, caller_context_t *ct, int flags,
+ vsecattr_t *vsecp);
+static int port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags);
+static int port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags);
static int port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap,
- char *target, cred_t *cr);
+ char *target, cred_t *cr, caller_context_t *ct, int flags);
static int port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
+
static int port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp,
- char *cname);
+ char *cname, caller_context_t *ct);
static int port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr);
@@ -812,7 +819,7 @@ port_check_timestamp(vnode_t *vp, portfop_t *pfp, void *objptr)
if (fobj->fo_atime.tv_sec || fobj->fo_atime.tv_nsec ||
fobj->fo_mtime.tv_sec || fobj->fo_mtime.tv_nsec ||
fobj->fo_ctime.tv_sec || fobj->fo_ctime.tv_nsec) {
- if (VOP_GETATTR(vp, &vatt, 0, CRED())) {
+ if (VOP_GETATTR(vp, &vatt, 0, CRED(), NULL)) {
return;
}
} else {
@@ -828,7 +835,7 @@ port_check_timestamp(vnode_t *vp, portfop_t *pfp, void *objptr)
if (fobj32->fo_atime.tv_sec || fobj32->fo_atime.tv_nsec ||
fobj32->fo_mtime.tv_sec || fobj32->fo_mtime.tv_nsec ||
fobj32->fo_ctime.tv_sec || fobj32->fo_ctime.tv_nsec) {
- if (VOP_GETATTR(vp, &vatt, 0, CRED())) {
+ if (VOP_GETATTR(vp, &vatt, 0, CRED(), NULL)) {
return;
}
} else {
@@ -1182,7 +1189,7 @@ port_resolve_vp(vnode_t *vp)
* This should take care of lofs mounted fs systems and nfs4
* hardlinks.
*/
- if ((VOP_REALVP(vp, &rvp) == 0) && vp != rvp) {
+ if ((VOP_REALVP(vp, &rvp, NULL) == 0) && vp != rvp) {
VN_HOLD(rvp);
VN_RELE(vp);
vp = rvp;
@@ -1263,7 +1270,7 @@ port_associate_fop(port_t *pp, int source, uintptr_t object, int events,
vp = port_resolve_vp(vp);
- if (vp != NULL && vnevent_support(vp)) {
+ if (vp != NULL && vnevent_support(vp, NULL)) {
error = ENOTSUP;
goto errout;
}
@@ -1547,7 +1554,7 @@ port_close_fop(void *arg, int port, pid_t pid, int lastclose)
/*
* Given the list of associations(watches), it will send exception events,
* if still active, and discard them. The exception events are handled
- * seperately because, the pfp needs to be removed from the port cache and
+ * separately because, the pfp needs to be removed from the port cache and
* freed as the vnode's identity is changing or being removed. To remove
* the pfp from the port's cache, we need to hold the cache lock (pfc_lock).
* The lock order is pfc_lock -> pvp_mutex(vnode's) mutex and that is why
@@ -1809,7 +1816,7 @@ port_fop(vnode_t *vp, int op, int retval)
return;
/*
- * These events occuring on the watched file.
+ * These events occurring on the watched file.
*/
if (op & FOP_MODIFIED_MASK) {
event = FILE_MODIFIED;
@@ -1907,12 +1914,12 @@ port_fop_unmount(fsemarg_t *vf, int flag, cred_t *cr)
* The O_TRUNC operation is caught with the VOP_SETATTR(AT_SIZE) call.
*/
static int
-port_fop_open(femarg_t *vf, int mode, cred_t *cr)
+port_fop_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_open(vf, mode, cr);
+ retval = vnext_open(vf, mode, cr, ct);
port_fop(vp, FOP_FILE_OPEN, retval);
return (retval);
}
@@ -1931,12 +1938,14 @@ port_fop_write(femarg_t *vf, struct uio *uiop, int ioflag, struct cred *cr,
static int
port_fop_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxport, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxport, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_map(vf, off, as, addrp, len, prot, maxport, flags, cr);
+ retval = vnext_map(vf, off, as, addrp, len, prot, maxport,
+ flags, cr, ct);
port_fop(vp, FOP_FILE_MAP, retval);
return (retval);
}
@@ -1980,7 +1989,8 @@ port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
int
port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
int retval, got = 1;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
@@ -1993,13 +2003,14 @@ port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
* file was actually created.
*/
vatt.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
- if (VOP_GETATTR(vp, &vatt, 0, CRED())) {
+ if (VOP_GETATTR(vp, &vatt, 0, CRED(), ct)) {
got = 0;
}
- retval = vnext_create(vf, name, vap, excl, mode, vpp, cr, flag);
+ retval = vnext_create(vf, name, vap, excl, mode, vpp, cr,
+ flag, ct, vsecp);
vatt1.va_mask = AT_ATIME|AT_MTIME|AT_CTIME;
- if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED())) {
+ if (got && !VOP_GETATTR(vp, &vatt1, 0, CRED(), ct)) {
if ((vatt1.va_mtime.tv_sec > vatt.va_mtime.tv_sec ||
(vatt1.va_mtime.tv_sec = vatt.va_mtime.tv_sec &&
vatt1.va_mtime.tv_nsec > vatt.va_mtime.tv_nsec))) {
@@ -2013,23 +2024,25 @@ port_fop_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
}
int
-port_fop_remove(femarg_t *vf, char *nm, cred_t *cr)
+port_fop_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
+ int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_remove(vf, nm, cr);
+ retval = vnext_remove(vf, nm, cr, ct, flags);
port_fop(vp, FOP_FILE_REMOVE, retval);
return (retval);
}
int
-port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
+port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_link(vf, svp, tnm, cr);
+ retval = vnext_link(vf, svp, tnm, cr, ct, flags);
port_fop(vp, FOP_FILE_LINK, retval);
return (retval);
}
@@ -2041,58 +2054,61 @@ port_fop_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr)
* if the source dir != target dir.
*/
int
-port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
+port_fop_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_rename(vf, snm, tdvp, tnm, cr);
+ retval = vnext_rename(vf, snm, tdvp, tnm, cr, ct, flags);
port_fop(vp, FOP_FILE_RENAMESRC, retval);
return (retval);
}
int
port_fop_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_mkdir(vf, dirname, vap, vpp, cr);
+ retval = vnext_mkdir(vf, dirname, vap, vpp, cr, ct, flags, vsecp);
port_fop(vp, FOP_FILE_MKDIR, retval);
return (retval);
}
int
-port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr)
+port_fop_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_rmdir(vf, nm, cdir, cr);
+ retval = vnext_rmdir(vf, nm, cdir, cr, ct, flags);
port_fop(vp, FOP_FILE_RMDIR, retval);
return (retval);
}
int
-port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp)
+port_fop_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_readdir(vf, uiop, cr, eofp);
+ retval = vnext_readdir(vf, uiop, cr, eofp, ct, flags);
port_fop(vp, FOP_FILE_READDIR, retval);
return (retval);
}
int
port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_symlink(vf, linkname, vap, target, cr);
+ retval = vnext_symlink(vf, linkname, vap, target, cr, ct, flags);
port_fop(vp, FOP_FILE_SYMLINK, retval);
return (retval);
}
@@ -2101,11 +2117,12 @@ port_fop_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
* acl, facl call this.
*/
int
-port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr)
+port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
int retval;
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
- retval = vnext_setsecattr(vf, vsap, flags, cr);
+ retval = vnext_setsecattr(vf, vsap, flags, cr, ct);
port_fop(vp, FOP_FILE_SETSECATTR, retval);
return (retval);
}
@@ -2114,11 +2131,11 @@ port_fop_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flags, cred_t *cr)
* these are events on the watched file/directory
*/
int
-port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name)
+port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name,
+ caller_context_t *ct)
{
vnode_t *vp = (vnode_t *)vf->fa_fnode->fn_available;
-
switch (vnevent) {
case VE_RENAME_SRC:
port_fop_sendevent(vp, FILE_RENAME_FROM, dvp, name);
@@ -2151,5 +2168,5 @@ port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name)
default:
break;
}
- return (vnext_vnevent(vf, vnevent, dvp, name));
+ return (vnext_vnevent(vf, vnevent, dvp, name, ct));
}
diff --git a/usr/src/uts/common/fs/portfs/port_vnops.c b/usr/src/uts/common/fs/portfs/port_vnops.c
index aa8bc952d2..00c1044dfa 100644
--- a/usr/src/uts/common/fs/portfs/port_vnops.c
+++ b/usr/src/uts/common/fs/portfs/port_vnops.c
@@ -36,13 +36,16 @@
#include <sys/port_impl.h>
/* local functions */
-static int port_open(struct vnode **, int, cred_t *);
-static int port_close(struct vnode *, int, int, offset_t, cred_t *);
-static int port_getattr(struct vnode *, struct vattr *, int, cred_t *);
-static int port_access(struct vnode *, int, int, cred_t *);
-static int port_realvp(vnode_t *, vnode_t **);
-static int port_poll(vnode_t *, short, int, short *, struct pollhead **);
-static void port_inactive(struct vnode *, cred_t *);
+static int port_open(struct vnode **, int, cred_t *, caller_context_t *);
+static int port_close(struct vnode *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+static int port_getattr(struct vnode *, struct vattr *, int, cred_t *,
+ caller_context_t *);
+static int port_access(struct vnode *, int, int, cred_t *, caller_context_t *);
+static int port_realvp(vnode_t *, vnode_t **, caller_context_t *);
+static int port_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+static void port_inactive(struct vnode *, cred_t *, caller_context_t *);
const fs_operation_def_t port_vnodeops_template[] = {
VOPNAME_OPEN, { .vop_open = port_open },
@@ -62,7 +65,7 @@ const fs_operation_def_t port_vnodeops_template[] = {
/* ARGSUSED */
static int
-port_open(struct vnode **vpp, int flag, cred_t *cr)
+port_open(struct vnode **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -146,7 +149,8 @@ port_close_events(port_queue_t *portq)
*/
/* ARGSUSED */
static int
-port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr)
+port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
port_t *pp;
port_queue_t *portq;
@@ -276,7 +280,7 @@ port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr)
/*ARGSUSED*/
static int
port_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
port_t *pp;
port_queue_t *portq;
@@ -308,7 +312,8 @@ port_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
/* ARGSUSED */
static int
-port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr)
+port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
port_t *pp;
extern dev_t portdev;
@@ -340,7 +345,7 @@ port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr)
*/
/* ARGSUSED */
static void
-port_inactive(struct vnode *vp, cred_t *cr)
+port_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
{
port_t *pp = VTOEP(vp);
extern port_kstat_t port_kstat;
@@ -359,14 +364,15 @@ port_inactive(struct vnode *vp, cred_t *cr)
/* ARGSUSED */
static int
-port_access(struct vnode *vp, int mode, int flags, cred_t *cr)
+port_access(struct vnode *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static int
-port_realvp(vnode_t *vp, vnode_t **vpp)
+port_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
*vpp = vp;
return (0);
diff --git a/usr/src/uts/common/fs/proc/prcontrol.c b/usr/src/uts/common/fs/proc/prcontrol.c
index 9bbf929b5f..f4b20a4045 100644
--- a/usr/src/uts/common/fs/proc/prcontrol.c
+++ b/usr/src/uts/common/fs/proc/prcontrol.c
@@ -1460,7 +1460,7 @@ pr_setsig(prnode_t *pnp, siginfo_t *sip)
}
thread_lock(t);
if (ISWAKEABLE(t) || ISWAITING(t)) {
- /* Set signalled sleeping/waiting lwp running */
+ /* Set signaled sleeping/waiting lwp running */
setrun_locked(t);
} else if (t->t_state == TS_STOPPED && sig == SIGKILL) {
/* If SIGKILL, set stopped lwp running */
diff --git a/usr/src/uts/common/fs/proc/prioctl.c b/usr/src/uts/common/fs/proc/prioctl.c
index 1eb2861b0f..45fddda6f6 100644
--- a/usr/src/uts/common/fs/proc/prioctl.c
+++ b/usr/src/uts/common/fs/proc/prioctl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -127,14 +127,27 @@ prctioctl(prnode_t *pnp, int cmd, intptr_t arg, int flag, cred_t *cr)
/*
* Control operations (lots).
*/
+/*ARGSUSED*/
#ifdef _SYSCALL32_IMPL
static int
-prioctl64(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl64(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
#else
int
-prioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
#endif /* _SYSCALL32_IMPL */
{
caddr_t cmaddr = (caddr_t)arg;
@@ -1657,9 +1670,16 @@ oprgetpsinfo32(proc_t *p, prpsinfo32_t *psp, kthread_t *tp)
}
}
+/*ARGSUSED*/
static int
-prioctl32(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl32(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
caddr_t cmaddr = (caddr_t)arg;
proc_t *p;
@@ -3126,7 +3146,7 @@ propenm(prnode_t *pnp, caddr_t cmaddr, caddr_t va, int *rvalp, cred_t *cr)
prunlock(pnp);
if (error == 0) {
- if ((error = VOP_ACCESS(xvp, VREAD, 0, cr)) == 0)
+ if ((error = VOP_ACCESS(xvp, VREAD, 0, cr, NULL)) == 0)
error = fassign(&xvp, FREAD, &n);
if (error) {
VN_RELE(xvp);
@@ -3876,16 +3896,23 @@ again:
}
#endif /* _SYSCALL32_IMPL */
+/*ARGSUSED*/
#ifdef _SYSCALL32_IMPL
int
-prioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp)
+prioctl(
+ struct vnode *vp,
+ int cmd,
+ intptr_t arg,
+ int flag,
+ cred_t *cr,
+ int *rvalp,
+ caller_context_t *ct)
{
switch (curproc->p_model) {
case DATAMODEL_ILP32:
- return (prioctl32(vp, cmd, arg, flag, cr, rvalp));
+ return (prioctl32(vp, cmd, arg, flag, cr, rvalp, ct));
case DATAMODEL_LP64:
- return (prioctl64(vp, cmd, arg, flag, cr, rvalp));
+ return (prioctl64(vp, cmd, arg, flag, cr, rvalp, ct));
default:
return (ENOSYS);
}
diff --git a/usr/src/uts/common/fs/proc/prsubr.c b/usr/src/uts/common/fs/proc/prsubr.c
index 60e541bb03..e716d3b0e3 100644
--- a/usr/src/uts/common/fs/proc/prsubr.c
+++ b/usr/src/uts/common/fs/proc/prsubr.c
@@ -1681,7 +1681,7 @@ prgetmap(proc_t *p, int reserved, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(mp->pr_mapname, "a.out");
else
@@ -1793,7 +1793,7 @@ prgetmap32(proc_t *p, int reserved, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(mp->pr_mapname, "a.out");
else
@@ -1996,7 +1996,7 @@ again:
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(pmp->pr_mapname, "a.out");
else
@@ -2143,7 +2143,7 @@ again:
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
if (vp == p->p_exec)
(void) strcpy(pmp->pr_mapname, "a.out");
else
@@ -3678,7 +3678,7 @@ pr_getsegsize(struct seg *seg, int reserved)
if (SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
u_offset_t fsize = vattr.va_size;
u_offset_t offset = SEGOP_GETOFFSET(seg, seg->s_base);
@@ -3981,7 +3981,8 @@ prgetxmap(proc_t *p, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(),
+ NULL) == 0) {
mp->pr_dev = vattr.va_fsid;
mp->pr_ino = vattr.va_nodeid;
if (vp == p->p_exec)
@@ -4164,7 +4165,8 @@ prgetxmap32(proc_t *p, list_t *iolhead)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, saddr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(),
+ NULL) == 0) {
(void) cmpldev(&mp->pr_dev,
vattr.va_fsid);
mp->pr_ino = vattr.va_nodeid;
diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c
index a8be6c151d..4b61f1cdcc 100644
--- a/usr/src/uts/common/fs/proc/prvnops.c
+++ b/usr/src/uts/common/fs/proc/prvnops.c
@@ -216,10 +216,10 @@ static prdirent_t lwpiddir[] = {
static void rebuild_objdir(struct as *);
static void prfreecommon(prcommon_t *);
-static int praccess(vnode_t *, int, int, cred_t *);
+static int praccess(vnode_t *, int, int, cred_t *, caller_context_t *);
static int
-propen(vnode_t **vpp, int flag, cred_t *cr)
+propen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp = *vpp;
prnode_t *pnp = VTOP(vp);
@@ -259,7 +259,7 @@ propen(vnode_t **vpp, int flag, cred_t *cr)
* Need to hold rvp since VOP_OPEN() may release it.
*/
VN_HOLD(rvp);
- error = VOP_OPEN(&rvp, flag, cr);
+ error = VOP_OPEN(&rvp, flag, cr, ct);
if (error) {
VN_RELE(rvp);
} else {
@@ -403,7 +403,8 @@ out:
/* ARGSUSED */
static int
-prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prcommon_t *pcp = pnp->pr_pcommon;
@@ -2692,7 +2693,8 @@ prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
}
static int
-prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prnodetype_t type = pnp->pr_type;
@@ -2742,13 +2744,13 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
if (!(flags & ATTR_REAL))
break;
/* restrict full knowledge of the attributes to owner or root */
- if ((error = praccess(vp, 0, 0, cr)) != 0)
+ if ((error = praccess(vp, 0, 0, cr, ct)) != 0)
return (error);
/* FALLTHROUGH */
case PR_OBJECT:
case PR_FD:
rvp = pnp->pr_realvp;
- error = VOP_GETATTR(rvp, vap, flags, cr);
+ error = VOP_GETATTR(rvp, vap, flags, cr, ct);
if (error)
return (error);
if (type == PR_FD) {
@@ -3093,7 +3095,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
}
static int
-praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
+praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prnodetype_t type = pnp->pr_type;
@@ -3126,7 +3128,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
(type == PR_FD && (vmode & mode) != mode &&
secpolicy_proc_access(cr) != 0))
return (EACCES);
- return (VOP_ACCESS(rvp, mode, flags, cr));
+ return (VOP_ACCESS(rvp, mode, flags, cr, ct));
case PR_PSINFO: /* these files can be read by anyone */
case PR_LPSINFO:
@@ -3166,7 +3168,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
*/
VN_HOLD(xvp);
prunlock(pnp);
- error = VOP_ACCESS(xvp, VREAD, 0, cr);
+ error = VOP_ACCESS(xvp, VREAD, 0, cr, ct);
VN_RELE(xvp);
}
if (error)
@@ -3178,7 +3180,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr)
/*
* Final access check on the underlying directory vnode.
*/
- return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr));
+ return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr, ct));
}
/*
@@ -3255,7 +3257,8 @@ static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
static int
prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
prnode_t *pnp = VTOP(dp);
prnodetype_t type = pnp->pr_type;
@@ -3281,20 +3284,22 @@ prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
case PR_CURDIR:
case PR_ROOTDIR:
/* restrict lookup permission to owner or root */
- if ((error = praccess(dp, VEXEC, 0, cr)) != 0)
+ if ((error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
/* FALLTHROUGH */
case PR_FD:
dp = pnp->pr_realvp;
- return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr));
+ return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr, ct,
+ direntflags, realpnp));
default:
break;
}
if ((type == PR_OBJECTDIR || type == PR_FDDIR || type == PR_PATHDIR) &&
- (error = praccess(dp, VEXEC, 0, cr)) != 0)
+ (error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
+ /* XXX - Do we need to pass ct, direntflags, or realpnp? */
*vpp = (pr_lookup_function[type](dp, comp));
return ((*vpp == NULL) ? ENOENT : 0);
@@ -3303,11 +3308,13 @@ prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
/* ARGSUSED */
static int
prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
- if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr)) != 0) {
+ if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr,
+ ct, NULL, NULL)) != 0) {
if (error == ENOENT) /* can't O_CREAT nonexistent files */
error = EACCES; /* unwriteable directories */
} else {
@@ -3326,7 +3333,7 @@ prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
vp = VTOP(vp)->pr_realvp;
mask = vap->va_mask;
vap->va_mask = AT_SIZE;
- error = VOP_SETATTR(vp, vap, 0, cr, NULL);
+ error = VOP_SETATTR(vp, vap, 0, cr, ct);
vap->va_mask = mask;
}
}
@@ -3615,7 +3622,7 @@ pr_lookup_objectdir(vnode_t *dp, char *comp)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
char name[64];
if (vp == p->p_exec) /* "a.out" */
@@ -4067,8 +4074,8 @@ pr_lookup_pathdir(vnode_t *dp, char *comp)
SEGOP_GETVP(seg, seg->s_base, &vp)
== 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED())
- == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(),
+ NULL) == 0) {
char name[64];
if (vp == p->p_exec)
@@ -4513,7 +4520,7 @@ prfreenode(prnode_t *pnp)
}
/*
- * Free a prcommon structure, if the refrence count reaches zero.
+ * Free a prcommon structure, if the reference count reaches zero.
*/
static void
prfreecommon(prcommon_t *pcp)
@@ -4596,12 +4603,14 @@ static int (*pr_readdir_function[PR_NFILES])() = {
/* ARGSUSED */
static int
-prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
+prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
prnode_t *pnp = VTOP(vp);
ASSERT(pnp->pr_type < PR_NFILES);
+ /* XXX - Do we need to pass ct and flags? */
return (pr_readdir_function[pnp->pr_type](pnp, uiop, eofp));
}
@@ -4764,7 +4773,7 @@ rebuild_objdir(struct as *as)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
for (i = 0; i < nentries; i++)
if (vp == dir[i])
break;
@@ -4920,7 +4929,8 @@ pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
*/
vattr.va_mask = AT_FSID | AT_NODEID;
while (n < objdirsize && (((vp = obj_entry(as, n)) == NULL) ||
- (VOP_GETATTR(vp, &vattr, 0, CRED()) != 0))) {
+ (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)
+ != 0))) {
vattr.va_mask = AT_FSID | AT_NODEID;
n++;
}
@@ -5275,7 +5285,7 @@ pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
if ((vp = obj_entry(as, obj)) == NULL)
continue;
vattr.va_mask = AT_FSID|AT_NODEID;
- if (VOP_GETATTR(vp, &vattr, 0, CRED()) != 0)
+ if (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) != 0)
continue;
if (vp == p->p_exec)
(void) strcpy(dirent->d_name, "a.out");
@@ -5429,7 +5439,7 @@ pr_readdir_ctdir(prnode_t *pnp, uio_t *uiop, int *eofp)
/* ARGSUSED */
static int
-prfsync(vnode_t *vp, int syncflag, cred_t *cr)
+prfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -5456,7 +5466,7 @@ pr_list_unlink(vnode_t *pvp, vnode_t **listp)
/* ARGSUSED */
static void
-prinactive(vnode_t *vp, cred_t *cr)
+prinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prnodetype_t type = pnp->pr_type;
@@ -5574,7 +5584,7 @@ prinactive(vnode_t *vp, cred_t *cr)
/* ARGSUSED */
static int
-prseek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+prseek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return (0);
}
@@ -5706,7 +5716,7 @@ prreadlink_lookup(prnode_t *pnp, char *buf, size_t size, cred_t *cr)
/* ARGSUSED */
static int
-prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
+prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ctp)
{
prnode_t *pnp = VTOP(vp);
char *buf;
@@ -5754,8 +5764,9 @@ prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr)
return (ret);
}
+/*ARGSUSED2*/
static int
-prcmp(vnode_t *vp1, vnode_t *vp2)
+prcmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
{
prnode_t *pp1, *pp2;
@@ -5783,13 +5794,13 @@ prcmp(vnode_t *vp1, vnode_t *vp2)
}
static int
-prrealvp(vnode_t *vp, vnode_t **vpp)
+prrealvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
{
vnode_t *rvp;
if ((rvp = VTOP(vp)->pr_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
@@ -5805,9 +5816,10 @@ prrealvp(vnode_t *vp, vnode_t **vpp)
* POLLERR /proc file descriptor is invalid
* POLLHUP process or lwp has terminated
*/
+/*ARGSUSED5*/
static int
prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
- pollhead_t **phpp)
+ pollhead_t **phpp, caller_context_t *ct)
{
prnode_t *pnp = VTOP(vp);
prcommon_t *pcp = pnp->pr_common;
@@ -5922,7 +5934,8 @@ prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
}
/* in prioctl.c */
-extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
+extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
/*
* /proc vnode operations vector
diff --git a/usr/src/uts/common/fs/sharefs/sharefs_vnops.c b/usr/src/uts/common/fs/sharefs/sharefs_vnops.c
index 1818c4ee03..cbafc38150 100644
--- a/usr/src/uts/common/fs/sharefs/sharefs_vnops.c
+++ b/usr/src/uts/common/fs/sharefs/sharefs_vnops.c
@@ -158,7 +158,8 @@ error_fault:
/* ARGSUSED */
static int
-sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
timestruc_t now;
shnode_t *sft = VTOSH(vp);
@@ -204,7 +205,8 @@ sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static int
-sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & (VWRITE|VEXEC))
return (EROFS);
@@ -214,7 +216,7 @@ sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
int
-sharefs_open(vnode_t **vpp, int flag, cred_t *cr)
+sharefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
vnode_t *vp;
vnode_t *ovp = *vpp;
@@ -267,7 +269,7 @@ sharefs_open(vnode_t **vpp, int flag, cred_t *cr)
/* ARGSUSED */
int
sharefs_close(vnode_t *vp, int flag, int count,
- offset_t off, cred_t *cr)
+ offset_t off, cred_t *cr, caller_context_t *ct)
{
shnode_t *sft = VTOSH(vp);
@@ -338,7 +340,7 @@ sharefs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr,
/* ARGSUSED */
static void
-sharefs_inactive(vnode_t *vp, cred_t *cr)
+sharefs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *tx)
{
gfs_file_t *fp = vp->v_data;
shnode_t *sft;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_acl.c b/usr/src/uts/common/fs/smbsrv/smb_acl.c
new file mode 100644
index 0000000000..2617268d9e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_acl.c
@@ -0,0 +1,1310 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Platform SDK: Security
+ *
+ * ACE Inheritance Rules
+ *
+ * The system propagates inheritable ACEs to child objects according to a
+ * set of inheritance rules. The system places inherited ACEs in the child's
+ * DACL according to the preferred order of ACEs in a DACL. For Windows
+ * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
+ *
+ * The following table shows the ACEs inherited by container and noncontainer
+ * child objects for different combinations of inheritance flags. These
+ * inheritance rules work the same for both DACLs and SACLs.
+ *
+ * Parent ACE type Effect on Child ACL
+ * ----------------------- -------------------
+ * OBJECT_INHERIT_ACE only Noncontainer child objects:
+ * Inherited as an effective ACE.
+ * Container child objects:
+ * Containers inherit an inherit-only ACE
+ * unless the NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ *
+ * CONTAINER_INHERIT_ACE only Noncontainer child objects:
+ * No effect on the child object.
+ * Container child objects:
+ * The child object inherits an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ *
+ * CONTAINER_INHERIT_ACE and
+ * OBJECT_INHERIT_ACE Noncontainer child objects:
+ * Inherited as an effective ACE.
+ * Container child objects:
+ * The child object inherits an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ *
+ * No inheritance flags set No effect on child container or noncontainer
+ * objects.
+ *
+ * If an inherited ACE is an effective ACE for the child object, the system
+ * maps any generic rights to the specific rights for the child object.
+ * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
+ * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
+ * rights or generic SIDs are left unchanged so that they can be mapped
+ * appropriately when the ACE is inherited by the next generation of child
+ * objects.
+ *
+ * For a case in which a container object inherits an ACE that is both
+ * effective on the container and inheritable by its descendants, the
+ * container may inherit two ACEs. This occurs if the inheritable ACE
+ * contains generic information. The container inherits an inherit-only
+ * ACE containing the generic information and an effective-only ACE in
+ * which the generic information has been mapped.
+ */
+
+#include <sys/acl.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_idmap.h>
+
+#define ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
+
+#define ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
+#define ZACE_IS_OWNGRP(zace) \
+ ((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
+
+#define ZACE_IS_USER(zace) \
+ (((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
+#define ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
+#define ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
+
+#define ZACE_IS_PROPAGATE(zace) \
+ ((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
+
+#define ZACE_IS_CREATOR_OWNER(zace) \
+ (ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
+
+#define ZACE_IS_CREATOR_GROUP(zace) \
+ (ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
+
+#define ZACE_IS_CREATOR(zace) \
+ (ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
+
+static int smb_ace_isvalid(smb_ace_hdr_t *ace, int which_acl);
+static int smb_ace_append_generic(smb_acl_t *acl, void *generic_ace);
+
+static int smb_ace_common_add(
+ smb_acl_t *acl,
+ uint8_t type,
+ uint8_t flags,
+ uint32_t access_mask,
+ nt_sid_t *sid);
+
+static void smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir);
+static uint16_t smb_ace_flags_tozfs(uint8_t c_flags, int isdir);
+static uint8_t smb_ace_flags_fromzfs(uint16_t z_flags);
+static void smb_acl_init(smb_acl_t *acl, uint16_t size, uint8_t rev);
+
+static int
+smb_ace_isvalid(smb_ace_hdr_t *ace, int which_acl)
+{
+ uint16_t min_len;
+ smb_ace_t *p;
+
+ min_len = sizeof (smb_ace_hdr_t);
+
+ if (ace->se_size < min_len)
+ return (0);
+
+ if (smb_ace_is_access(ace->se_type) &&
+ (which_acl != SMB_DACL_SECINFO)) {
+ return (0);
+ }
+
+ if (smb_ace_is_audit(ace->se_type) &&
+ (which_acl != SMB_SACL_SECINFO)) {
+ return (0);
+ }
+
+ if (smb_ace_is_generic(ace->se_type)) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ p = (smb_ace_t *)ace;
+
+ if (ace->se_size < sizeof (*p))
+ return (0); /* won't handle empty SubAuthority[] */
+
+ if (nt_sid_is_valid(&p->se_sid) == 0)
+ return (0);
+
+ min_len += sizeof (p->se_mask);
+ min_len += nt_sid_length(&p->se_sid);
+
+ if (ace->se_size < min_len)
+ return (0);
+ }
+
+ /*
+ * XXX object-specific ACE validation will be added later.
+ */
+ return (1);
+}
+
+int
+smb_acl_isvalid(smb_acl_t *acl, int which_acl)
+{
+ uint16_t min_len;
+ unsigned char *scan;
+ unsigned char *scan_end;
+ smb_ace_hdr_t *ace;
+ uint16_t count = 0;
+
+ min_len = sizeof (smb_acl_t);
+
+ if (acl->sl_size < min_len)
+ return (0);
+
+ if (acl->sl_revision != ACL_REVISION) {
+ /*
+ * XXX we are rejecting ACLs with object-specific ACEs for now
+ */
+ return (0);
+ }
+
+ scan = (unsigned char *) &acl[0];
+ scan_end = scan + acl->sl_size;
+ scan = (unsigned char *) &acl[1]; /* skip Acl header */
+
+ while (count < acl->sl_acecnt && scan < scan_end) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_hdr_t *)scan;
+
+ if (scan + sizeof (smb_ace_hdr_t) >= scan_end)
+ return (0);
+
+ if (scan + ace->se_size > scan_end)
+ return (0); /* overflow */
+
+ if (!smb_ace_isvalid(ace, which_acl))
+ return (0);
+
+ scan += ace->se_size;
+ count++;
+ }
+
+ return (1);
+}
+
+
+static void
+smb_acl_init(smb_acl_t *acl, uint16_t size, uint8_t rev)
+{
+ bzero(acl, size);
+ acl->sl_revision = rev;
+ acl->sl_size = size;
+}
+
+uint16_t
+smb_acl_len(smb_acl_t *acl)
+{
+ smb_ace_hdr_t *ace;
+ unsigned char *scan_beg;
+ unsigned char *scan_end;
+ unsigned char *scan;
+ uint16_t length;
+ uint16_t count;
+
+ scan_beg = (unsigned char *) &acl[0];
+ scan_end = scan_beg + acl->sl_size;
+ scan = (unsigned char *) &acl[1];
+ length = sizeof (smb_acl_t);
+ count = 0;
+
+ while ((count < acl->sl_acecnt) && (scan < scan_end)) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_hdr_t *)scan;
+ length += ace->se_size;
+ scan += ace->se_size;
+ count++;
+ }
+
+ return (length);
+}
+
+/*
+ * Append the generic ACE to the ACL. This is used to put any
+ * kind of ACE on the ACL so the argument is declared as a void*. We cast it
+ * to an ACCESS_ALLOWED_ACE just because there is no sense of a generic ACE.
+ */
+static int
+smb_ace_append_generic(smb_acl_t *acl, void *generic_ace)
+{
+ smb_ace_t *ace = (smb_ace_t *)generic_ace;
+ uint16_t acl_len = smb_acl_len(acl);
+ unsigned char *scan = (uchar_t *)acl;
+
+ if ((acl_len + ace->se_header.se_size) > acl->sl_size) {
+ /* no room in the acl for this ace */
+ return (0);
+ }
+
+ /* append the ace to the acl and inc ace count */
+ bcopy(ace, &scan[acl_len], ace->se_header.se_size);
+ acl->sl_acecnt++;
+
+ return (1);
+}
+
+/*
+ * Helper for the ACL sort routine
+ */
+typedef struct smb_ace_entry {
+ smb_ace_t *e_ace;
+ list_node_t e_node;
+} smb_ace_entry_t;
+
+/*
+ * ACE groups within a DACL
+ *
+ * This is from lower to higher ACE order priority
+ */
+#define SMB_AG_START 0
+#define SMB_AG_ALW_INHRT 0
+#define SMB_AG_DNY_INHRT 1
+#define SMB_AG_ALW_DRCT 2
+#define SMB_AG_DNY_DRCT 3
+#define SMB_AG_NUM 4
+
+/*
+ * smb_acl_do_sort
+ *
+ * Sorts the given ACL, acl, and returns the result
+ * in a newly allocated memory.
+ *
+ * The following is an excerpt from MSDN website.
+ *
+ * Order of ACEs in a DACL
+ *
+ * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
+ * is simple: In a DACL, all access-denied ACEs should precede any
+ * access-allowed ACEs.
+ *
+ * For Windows 2000 or later, the proper order of ACEs is more complicated
+ * because of the introduction of object-specific ACEs and automatic
+ * inheritance.
+ *
+ * The following describes the preferred order:
+ *
+ * To ensure that noninherited ACEs have precedence over inherited ACEs,
+ * place all noninherited ACEs in a group before any inherited ACEs. This
+ * ordering ensures, for example, that a noninherited access-denied ACE
+ * is enforced regardless of any inherited ACE that allows access.
+ * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
+ * according to ACE type, as the following shows:
+ * . Access-denied ACEs that apply to the object itself
+ * . Access-denied ACEs that apply to a subobject of the
+ * object, such as a property set or property
+ * . Access-allowed ACEs that apply to the object itself
+ * . Access-allowed ACEs that apply to a subobject of the object
+ *
+ * Of course, not all ACE types are required in an ACL.
+ */
+static smb_acl_t *
+smb_acl_do_sort(smb_acl_t *acl, list_t *ace_grps)
+{
+ smb_acl_t *sorted_acl;
+ smb_ace_entry_t *nae;
+ int i;
+
+ sorted_acl = kmem_alloc(acl->sl_size, KM_SLEEP);
+ *sorted_acl = *acl;
+
+ /* start with no ACE in the sorted ACL */
+ sorted_acl->sl_acecnt = 0;
+
+ /*
+ * start with highest priority ACE group and append
+ * the ACEs to the ACL.
+ */
+ for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
+ nae = list_head(&ace_grps[i]);
+ while (nae) {
+ if (!smb_ace_append_generic(sorted_acl, nae->e_ace)) {
+ kmem_free(sorted_acl, acl->sl_size);
+ return (NULL);
+ }
+ nae = list_next(&ace_grps[i], nae);
+ }
+ }
+
+ return (sorted_acl);
+}
+
+/*
+ * smb_acl_need_sort
+ *
+ * Here is the desired ACE order
+ *
+ * deny-direct, allow-direct, deny-inherited, allow-inherited
+ *
+ * If any ace has been encountered which belongs to a group
+ * with lower priority of the specified ace_grp then the acl
+ * should be sorted.
+ */
+static int
+smb_acl_need_sort(list_t *ace_grps, int ace_grp)
+{
+ int i;
+
+ for (i = SMB_AG_START; i < ace_grp; i++)
+ if (!list_is_empty(&ace_grps[i]))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * smb_acl_sort
+ *
+ * Returns NULL upon failure.
+ * Returns pointer to the passed (original) acl if no sort is required.
+ * Returns pointer to a new acl upon successful sort in which case the
+ * caller is responsible for freeing the allocated memory.
+ */
+smb_acl_t *
+smb_acl_sort(smb_acl_t *acl)
+{
+ smb_acl_t *sorted_acl;
+ smb_ace_t *ace;
+ smb_ace_entry_t *ace_list;
+ int ace_list_size;
+ list_t ace_grps[SMB_AG_NUM];
+ int ag;
+ int do_sort = 0;
+ uint16_t i;
+ uint8_t ace_flags;
+
+ ASSERT(acl);
+
+ if (acl->sl_acecnt == 0) {
+ /*
+ * ACL with no entry is a valid ACL and it means
+ * no access for anybody.
+ */
+ return (acl);
+ }
+
+ for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
+ list_create(&ace_grps[i], sizeof (smb_ace_entry_t),
+ offsetof(smb_ace_entry_t, e_node));
+ }
+
+ /*
+ * Allocate the helper entries to group the ACEs based on
+ * the desired priorities.
+ */
+ ace_list_size = sizeof (smb_ace_entry_t) * acl->sl_acecnt;
+ ace_list = kmem_alloc(ace_list_size, KM_SLEEP);
+
+ for (i = 0; i < acl->sl_acecnt; ++i) {
+ ace_list[i].e_ace = smb_ace_get(acl, i);
+ ace = ace_list[i].e_ace;
+ ASSERT(ace);
+
+ ace_flags = ace->se_header.se_flags;
+
+ switch (ace->se_header.se_type) {
+ case ACCESS_DENIED_ACE_TYPE:
+ if (ace_flags & INHERITED_ACE) {
+ ag = SMB_AG_DNY_INHRT;
+ do_sort |= smb_acl_need_sort(ace_grps, ag);
+ } else {
+ ag = SMB_AG_DNY_DRCT;
+ do_sort |= smb_acl_need_sort(ace_grps, ag);
+ }
+ break;
+
+ case ACCESS_ALLOWED_ACE_TYPE:
+ if (ace_flags & INHERITED_ACE) {
+ ag = SMB_AG_ALW_INHRT;
+ } else {
+ ag = SMB_AG_ALW_DRCT;
+ do_sort |= smb_acl_need_sort(ace_grps, ag);
+ }
+ break;
+
+ default:
+ /*
+ * This is the lowest priority group so we put
+ * evertything unknown here.
+ */
+ ag = SMB_AG_ALW_INHRT;
+ break;
+ }
+
+ /* Put the element on the appropriate list */
+ list_insert_tail(&ace_grps[ag], &ace_list[i]);
+ }
+
+ if (do_sort)
+ sorted_acl = smb_acl_do_sort(acl, ace_grps);
+ else
+ sorted_acl = acl;
+
+ for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
+ void *ent;
+ list_t *alist = &ace_grps[i];
+
+ while ((ent = list_head(alist)) != NULL)
+ list_remove(alist, ent);
+ list_destroy(alist);
+ }
+
+ kmem_free(ace_list, ace_list_size);
+
+ return (sorted_acl);
+}
+
+static int
+smb_ace_common_add(
+ smb_acl_t *acl,
+ uint8_t type,
+ uint8_t flags,
+ uint32_t access_mask,
+ nt_sid_t *sid)
+{
+ smb_ace_t *ace;
+ unsigned char *scan = (unsigned char *) acl;
+ uint16_t used = smb_acl_len(acl);
+ uint16_t sid_len = nt_sid_length(sid);
+ uint16_t size;
+
+ size = sizeof (ace->se_header) + sizeof (ace->se_mask) + sid_len;
+
+ if (size + used > acl->sl_size) {
+ /* won't fit */
+ return (0);
+ }
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_t *)&scan[used];
+
+ ace->se_header.se_type = type;
+ ace->se_header.se_flags = flags;
+ ace->se_header.se_size = size;
+ ace->se_mask = access_mask;
+ bcopy(sid, &ace->se_sid, sid_len);
+
+ acl->sl_acecnt++;
+
+ return (1);
+}
+
+smb_ace_t *
+smb_ace_get(smb_acl_t *acl, uint16_t idx)
+{
+ smb_ace_t *ace;
+ unsigned char *scan_beg = (unsigned char *) &acl[0];
+ unsigned char *scan_end = scan_beg + acl->sl_size;
+ unsigned char *scan = (unsigned char *) &acl[1];
+ uint16_t count = 0;
+
+ if (idx >= acl->sl_acecnt)
+ return (NULL);
+
+ while (count <= idx && scan < scan_end) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ace = (smb_ace_t *)scan;
+
+ if (count == idx) {
+ return (ace);
+ }
+
+ scan += ace->se_header.se_size;
+ count++;
+ }
+
+ return (NULL);
+}
+
+int
+smb_acl_copy(uint16_t buflen, smb_acl_t *dst_acl, smb_acl_t *src_acl)
+{
+ smb_ace_hdr_t *dst_ace;
+ smb_ace_hdr_t *src_ace;
+ unsigned char *scan = (unsigned char *) &src_acl[1];
+ unsigned char *dest_beg = (unsigned char *) &dst_acl[0];
+ unsigned char *dest_end;
+ unsigned char *dest = (unsigned char *) &dst_acl[1];
+ uint16_t count = 0;
+ uint16_t n_bytes;
+
+ n_bytes = smb_acl_len(src_acl);
+ if (n_bytes > buflen)
+ return (0);
+
+ dest_end = dest_beg + n_bytes;
+
+ dst_acl->sl_revision = src_acl->sl_revision;
+ dst_acl->sl_sbz1 = 0;
+ dst_acl->sl_size = n_bytes;
+ dst_acl->sl_acecnt = 0;
+ dst_acl->sl_sbz2 = 0;
+
+ while (count < src_acl->sl_acecnt && dest < dest_end) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ src_ace = (smb_ace_hdr_t *)scan;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dst_ace = (smb_ace_hdr_t *)dest;
+ bcopy(src_ace, dst_ace, src_ace->se_size);
+ dest += dst_ace->se_size;
+ dst_acl->sl_acecnt++;
+ scan += src_ace->se_size;
+ count++;
+ }
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (dest - dest_beg);
+}
+
+/*
+ * smb_ace_len
+ *
+ * Returns the length of an ACE with the given SID
+ *
+ * struct smb_ace {
+ * smb_ace_hdr_t se_header;
+ * uint32_t se_mask;
+ * nt_sid_t se_sid;
+ * };
+ */
+uint16_t
+smb_ace_len(nt_sid_t *sid)
+{
+ ASSERT(sid);
+
+ return (sizeof (smb_ace_hdr_t)
+ + sizeof (uint32_t) + nt_sid_length(sid));
+}
+
+/*
+ * smb_ace_mask_g2s
+ *
+ * Converts generic access bits in the given mask (if any)
+ * to file specific bits. Generic access masks shouldn't be
+ * stored in filesystem ACEs.
+ */
+uint32_t
+smb_ace_mask_g2s(DWORD mask)
+{
+ if (mask & GENERIC_ALL) {
+ mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
+ | GENERIC_EXECUTE);
+
+ mask |= FILE_ALL_ACCESS;
+ return (mask);
+ }
+
+ if (mask & GENERIC_READ) {
+ mask &= ~GENERIC_READ;
+ mask |= FILE_GENERIC_READ;
+ }
+
+ if (mask & GENERIC_WRITE) {
+ mask &= ~GENERIC_WRITE;
+ mask |= FILE_GENERIC_WRITE;
+ }
+
+ if (mask & GENERIC_EXECUTE) {
+ mask &= ~GENERIC_EXECUTE;
+ mask |= FILE_GENERIC_EXECUTE;
+ }
+
+ return (mask);
+}
+
+/*
+ * smb_acl_getsids
+ *
+ * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
+ */
+static idmap_stat
+smb_acl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid)
+{
+ ace_t *zace;
+ idmap_stat idm_stat;
+ smb_idmap_t *sim;
+ uid_t id;
+ int i, idtype;
+
+ sim = sib->sib_maps;
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
+ zace++, i++, sim++) {
+ switch (zace->a_flags & ACE_TYPE_FLAGS) {
+ case ACE_OWNER:
+ id = uid;
+ idtype = SMB_IDMAP_USER;
+ break;
+
+ case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
+ /* owning group */
+ id = gid;
+ idtype = SMB_IDMAP_GROUP;
+ break;
+
+ case ACE_IDENTIFIER_GROUP:
+ /* regular group */
+ id = zace->a_who;
+ idtype = SMB_IDMAP_GROUP;
+ break;
+
+ case ACE_EVERYONE:
+ idtype = SMB_IDMAP_EVERYONE;
+ break;
+
+ default:
+ /* user entry */
+ id = zace->a_who;
+ idtype = SMB_IDMAP_USER;
+ }
+
+ idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
+ id, idtype);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (idm_stat);
+ }
+ }
+
+ idm_stat = smb_idmap_batch_getmappings(sib);
+ return (idm_stat);
+}
+
+/*
+ * smb_acl_grow
+ *
+ * Grow the acl size by given number of bytes in 'grow'
+ * Returns pointer to the newly allocated memory.
+ */
+static smb_acl_t *
+smb_acl_grow(smb_acl_t *acl, uint16_t grow)
+{
+ smb_acl_t *new_acl;
+ uint16_t smb_aclsz;
+
+ ASSERT(acl);
+
+ smb_aclsz = acl->sl_size;
+ new_acl = kmem_alloc(smb_aclsz + grow, KM_SLEEP);
+ (void) memcpy(new_acl, acl, smb_aclsz);
+ kmem_free(acl, smb_aclsz);
+ new_acl->sl_size = smb_aclsz + grow;
+
+ return (new_acl);
+}
+
+/*
+ * smb_acl_from_zfs
+ *
+ * Converts given ZFS ACL to a Windows ACL.
+ *
+ * A pointer to allocated memory for the Win ACL will be
+ * returned upon successful conversion.
+ */
+smb_acl_t *
+smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
+{
+ ace_t *zace;
+ int numaces;
+ smb_acl_t *acl;
+ uint16_t smb_aclsz;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *sim;
+ idmap_stat idm_stat;
+ int status;
+
+ idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
+ SMB_IDMAP_ID2SID);
+ if (idm_stat != IDMAP_SUCCESS)
+ return (NULL);
+
+ if (smb_acl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
+ smb_idmap_batch_destroy(&sib);
+ return (NULL);
+ }
+
+ smb_aclsz = sizeof (smb_acl_t);
+
+ acl = kmem_alloc(smb_aclsz, KM_SLEEP);
+ smb_acl_init(acl, smb_aclsz, ACL_REVISION);
+
+ sim = sib.sib_maps;
+ for (numaces = 0, zace = zacl->acl_aclp;
+ numaces < zacl->acl_cnt;
+ zace++, numaces++, sim++) {
+ ASSERT(sim->sim_sid);
+ if (sim->sim_sid == NULL) {
+ kmem_free(acl, acl->sl_size);
+ acl = NULL;
+ break;
+ }
+
+ /* Make room for this ACE */
+ acl = smb_acl_grow(acl, smb_ace_len(sim->sim_sid));
+
+ status = smb_ace_common_add(acl,
+ zace->a_type,
+ smb_ace_flags_fromzfs(zace->a_flags),
+ zace->a_access_mask,
+ sim->sim_sid);
+
+ if (status == 0) {
+ kmem_free(acl, acl->sl_size);
+ acl = NULL;
+ break;
+ }
+ }
+
+ smb_idmap_batch_destroy(&sib);
+ return (acl);
+}
+
+/*
+ * SID for Everyone group: S-1-1-0.
+ */
+nt_sid_t everyone_sid = {
+ NT_SID_REVISION,
+ 1,
+ NT_SECURITY_WORLD_AUTH,
+ { 0 }
+};
+
+/*
+ * smb_acl_null_empty
+ *
+ * NULL DACL means everyone full-access
+ * Empty DACL means everyone full-deny
+ *
+ * ZFS ACL must have at least one entry so smb server has
+ * to simulate the aforementioned expected behavior by adding
+ * an entry in case the requested DACL is null or empty. Adding
+ * a everyone full-deny entry has proved to be problematic in
+ * tests since a deny entry takes precedence over allow entries.
+ * So, instead of adding a everyone full-deny, an owner ACE with
+ * owner implicit permissions will be set.
+ */
+acl_t *
+smb_acl_null_empty(int null)
+{
+ acl_t *zacl;
+ ace_t *zace;
+
+ zacl = smb_fsop_aclalloc(1, ACL_AUTO_INHERIT);
+ zace = zacl->acl_aclp;
+
+ zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ if (null) {
+ zace->a_access_mask = ACE_ALL_PERMS;
+ zace->a_flags = ACE_EVERYONE;
+ } else {
+ zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
+ ACE_READ_ATTRIBUTES;
+ zace->a_flags = ACE_OWNER;
+ }
+
+ return (zacl);
+}
+
+/*
+ * smb_acl_to_zfs
+ *
+ * Converts given Windows ACL to a ZFS ACL.
+ *
+ * fs_acl will contain a pointer to the created ZFS ACL.
+ * The allocated memory should be freed by calling
+ * smb_fsop_aclfree().
+ *
+ * Since the output parameter, fs_acl, is allocated in this
+ * function, the caller has to make sure *fs_acl is NULL which
+ * means it's not pointing to any memory.
+ */
+uint32_t
+smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
+{
+ smb_ace_t *ace;
+ acl_t *zacl;
+ ace_t *zace;
+ smb_idmap_batch_t sib;
+ smb_idmap_t *sim;
+ idmap_stat idm_stat;
+ int i, isdir;
+
+ ASSERT(fs_acl);
+ ASSERT(*fs_acl == NULL);
+
+ if (acl && !smb_acl_isvalid(acl, which_acl))
+ return (NT_STATUS_INVALID_ACL);
+
+ if ((acl == NULL) || (acl->sl_acecnt == 0)) {
+ if (which_acl == SMB_DACL_SECINFO) {
+ *fs_acl = smb_acl_null_empty(acl == NULL);
+ }
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
+ SMB_IDMAP_SID2ID);
+ if (idm_stat != IDMAP_SUCCESS)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ isdir = ((flags & ACL_IS_DIR) == ACL_IS_DIR);
+
+ zacl = smb_fsop_aclalloc(acl->sl_acecnt, flags);
+
+ zace = zacl->acl_aclp;
+ sim = sib.sib_maps;
+
+ for (i = 0; ace = smb_ace_get(acl, i); i++, zace++, sim++) {
+ zace->a_type = ace->se_header.se_type & ACE_ALL_TYPES;
+ zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
+ zace->a_flags = smb_ace_flags_tozfs(ace->se_header.se_flags,
+ isdir);
+
+ if (nt_sid_is_equal(&ace->se_sid, &everyone_sid))
+ zace->a_flags |= ACE_EVERYONE;
+ else {
+ sim->sim_id = &zace->a_who;
+ idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
+ &ace->se_sid, -1);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_fsop_aclfree(zacl);
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+ }
+
+ idm_stat = smb_idmap_batch_getmappings(&sib);
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_fsop_aclfree(zacl);
+ smb_idmap_batch_destroy(&sib);
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ /*
+ * Set the ACEs group flag based on the type of ID returned.
+ */
+ zace = zacl->acl_aclp;
+ sim = sib.sib_maps;
+ for (i = 0; i < acl->sl_acecnt; i++, zace++, sim++) {
+ if (zace->a_flags & ACE_EVERYONE)
+ continue;
+
+ if (sim->sim_idtype == SMB_IDMAP_GROUP)
+ zace->a_flags |= ACE_IDENTIFIER_GROUP;
+ }
+
+ smb_idmap_batch_destroy(&sib);
+
+ *fs_acl = zacl;
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_acl_inheritable
+ *
+ * Checks to see if there are any inheritable ACEs in the
+ * given ZFS ACL. Returns the number of inheritable ACEs.
+ *
+ * The inherited ACL could be different based on the type of
+ * new object (file/dir) specified by 'is_dir'.
+ *
+ * Note that the input ACL is a ZFS ACL not Windows ACL.
+ *
+ * Any ACE except creator owner/group:
+ *
+ * FI DI NP #F #D
+ * ---- ---- ---- ---- ----
+ * - - ? 0 0
+ * X - - 1 1
+ * X - X 1 0
+ * - X - 0 1
+ * - X X 0 1
+ * X X - 1 1
+ * X X X 1 1
+ *
+ * Creator owner/group ACE:
+ *
+ * FI DI NP #F #D
+ * ---- ---- ---- ---- ----
+ * - - ? 0 0
+ * X - - 1r 1c
+ * X - X 1r 0
+ * - X - 0 2
+ * - X X 0 1r
+ * X X - 1r 2
+ * X X X 1r 1r
+ *
+ * Legend:
+ *
+ * FI: File Inherit
+ * DI: Dir Inherit
+ * NP: No Propagate
+ * #F: #ACE for a new file
+ * #D: #ACE for a new dir
+ *
+ * X: bit is set
+ * -: bit is not set
+ * ?: don't care
+ *
+ * 1r: one owner/group ACE
+ * 1c: one creator owner/group ACE
+ */
+static int
+smb_acl_inheritable(acl_t *zacl, int is_dir)
+{
+ int numaces;
+ int num_inheritable = 0;
+ ace_t *zace;
+
+ if (zacl == NULL)
+ return (0);
+
+ for (numaces = 0, zace = zacl->acl_aclp;
+ numaces < zacl->acl_cnt;
+ zace++, numaces++) {
+ switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
+ case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
+ /*
+ * Files inherit an effective ACE.
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ */
+ num_inheritable++;
+
+ if (is_dir && ZACE_IS_CREATOR(zace) &&
+ (ZACE_IS_PROPAGATE(zace))) {
+ num_inheritable++;
+ }
+ break;
+
+ case ACE_FILE_INHERIT_ACE:
+ /*
+ * Files inherit as an effective ACE.
+ *
+ * Dirs inherit an inherit-only ACE
+ * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ */
+ if (is_dir == 0)
+ num_inheritable++;
+ else if (ZACE_IS_PROPAGATE(zace))
+ num_inheritable++;
+ break;
+
+ case ACE_DIRECTORY_INHERIT_ACE:
+ /*
+ * No effect on files
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+ if (is_dir == 0)
+ break;
+
+ num_inheritable++;
+
+ if (ZACE_IS_CREATOR(zace) &&
+ (ZACE_IS_PROPAGATE(zace)))
+ num_inheritable++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (num_inheritable);
+}
+
+#define DEFAULT_DACL_ACENUM 2
+/*
+ * Default ACL:
+ * owner: full access
+ * SYSTEM: full access
+ */
+static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
+ { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
+ { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
+ ACE_ACCESS_ALLOWED_ACE_TYPE }
+};
+
+/*
+ * smb_acl_inherit
+ *
+ * Manufacture the inherited ACL from the given ACL considering
+ * the new object type (file/dir) specified by 'is_dir'. The
+ * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
+ * This function implements Windows inheritance rules.
+ *
+ * Note that the in/our ACLs are ZFS ACLs not Windows ACLs
+ */
+acl_t *
+smb_acl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid)
+{
+ boolean_t use_default = B_FALSE;
+ int num_inheritable = 0;
+ int numaces;
+ ace_t *dir_zace;
+ acl_t *new_zacl;
+ ace_t *new_zace;
+
+ num_inheritable = smb_acl_inheritable(dir_zacl, is_dir);
+
+ if (num_inheritable == 0) {
+ if (which_acl == SMB_DACL_SECINFO) {
+ /* No inheritable access ACEs -> default DACL */
+ num_inheritable = DEFAULT_DACL_ACENUM;
+ use_default = B_TRUE;
+ } else {
+ return (NULL);
+ }
+ }
+
+ new_zacl = smb_fsop_aclalloc(num_inheritable, ACL_AUTO_INHERIT);
+ new_zace = new_zacl->acl_aclp;
+
+ if (use_default) {
+ bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
+ new_zace->a_who = owner_uid;
+ return (new_zacl);
+ }
+
+ for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
+ numaces < dir_zacl->acl_cnt;
+ dir_zace++, numaces++) {
+ switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
+ case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
+ /*
+ * Files inherit an effective ACE.
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
+ */
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+
+ if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
+ (ZACE_IS_PROPAGATE(dir_zace))) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+ break;
+
+ case ACE_FILE_INHERIT_ACE:
+ /*
+ * Files inherit as an effective ACE.
+ *
+ * Dirs inherit an inherit-only ACE
+ * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
+ * flag is also set.
+ */
+ if (is_dir == 0) {
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+ } else if (ZACE_IS_PROPAGATE(dir_zace)) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+ break;
+
+ case ACE_DIRECTORY_INHERIT_ACE:
+ /*
+ * No effect on files
+ *
+ * Dirs inherit an effective ACE.
+ * The inherited ACE is inheritable unless the
+ * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+ if (is_dir == 0)
+ break;
+
+ smb_ace_inherit(dir_zace, new_zace, is_dir);
+ new_zace++;
+
+ if (ZACE_IS_CREATOR(dir_zace) &&
+ (ZACE_IS_PROPAGATE(dir_zace))) {
+ *new_zace = *dir_zace;
+ new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
+ ACE_INHERITED_ACE);
+ new_zace++;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (new_zacl);
+}
+
+static void
+smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir)
+{
+ *zace = *dir_zace;
+ if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
+ zace->a_flags &= ~ACE_INHERIT_FLAGS;
+ zace->a_flags |= ACE_INHERITED_ACE;
+
+ /*
+ * Replace creator owner/group ACEs with
+ * actual owner/group ACEs.
+ */
+ if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
+ zace->a_who = (uid_t)-1;
+ zace->a_flags |= ACE_OWNER;
+ } else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
+ zace->a_who = (uid_t)-1;
+ zace->a_flags |= ACE_GROUP;
+ }
+}
+
+static uint16_t
+smb_ace_flags_tozfs(uint8_t c_flags, int isdir)
+{
+ uint16_t z_flags = 0;
+
+ if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
+ z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
+
+ if (c_flags & FAILED_ACCESS_ACE_FLAG)
+ z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
+
+ if (c_flags & INHERITED_ACE)
+ z_flags |= ACE_INHERITED_ACE;
+
+ /*
+ * ZFS doesn't like any inheritance flags to be set on a
+ * file's ACE, only directories. Windows doesn't care.
+ */
+ if (isdir)
+ z_flags |= (c_flags & ACE_INHERIT_FLAGS);
+
+ return (z_flags);
+}
+
+static uint8_t
+smb_ace_flags_fromzfs(uint16_t z_flags)
+{
+ uint8_t c_flags;
+
+ c_flags = z_flags & ACE_INHERIT_FLAGS;
+
+ if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
+ c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
+
+ if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
+ c_flags |= FAILED_ACCESS_ACE_FLAG;
+
+ if (z_flags & ACE_INHERITED_ACE)
+ c_flags |= INHERITED_ACE;
+
+ return (c_flags);
+}
+
+/*
+ * This is generic (ACL version 2) vs. object-specific
+ * (ACL version 4) ACE types.
+ */
+int
+smb_ace_is_generic(int type)
+{
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+smb_ace_is_access(int type)
+{
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
+ case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+smb_ace_is_audit(int type)
+{
+ switch (type) {
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
+ return (1);
+
+ default:
+ break;
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_alloc.c b/usr/src/uts/common/fs/smbsrv/smb_alloc.c
new file mode 100644
index 0000000000..24de6ea712
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_alloc.c
@@ -0,0 +1,117 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/kmem.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+
+#include <smbsrv/alloc.h>
+
+#define MEM_HDR_SIZE 8
+static uint32_t mem_get_size(void *ptr);
+
+void *
+mem_malloc(uint32_t size)
+{
+ uint8_t *p;
+
+ size += MEM_HDR_SIZE;
+ p = kmem_alloc(size, KM_SLEEP);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ *(uint32_t *)p = size;
+ p += MEM_HDR_SIZE;
+
+ return (p);
+}
+
+void *
+mem_zalloc(uint32_t size)
+{
+ uint8_t *p;
+
+ p = mem_malloc(size);
+ (void) memset(p, 0, size);
+ return (p);
+}
+
+char *
+mem_strdup(const char *ptr)
+{
+ char *p;
+ size_t size;
+
+ size = strlen(ptr) + 1;
+ p = mem_malloc(size);
+ (void) memcpy(p, ptr, size);
+ return (p);
+}
+
+static uint32_t
+mem_get_size(void *ptr)
+{
+ uint32_t *p;
+
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ p = (uint32_t *)((uint8_t *)ptr - MEM_HDR_SIZE);
+
+ return (*p);
+}
+
+void *
+mem_realloc(void *ptr, uint32_t size)
+{
+ void *new_ptr;
+
+ if (ptr == NULL)
+ return (mem_malloc(size));
+
+ if (size == 0) {
+ smb_mem_free(ptr);
+ return (NULL);
+ }
+
+ new_ptr = mem_malloc(size);
+ (void) memcpy(new_ptr, ptr, mem_get_size(ptr));
+ smb_mem_free(ptr);
+
+ return (new_ptr);
+}
+
+void
+smb_mem_free(void *ptr)
+{
+ uint8_t *p;
+
+ if (ptr == 0)
+ return;
+
+ p = (uint8_t *)ptr - MEM_HDR_SIZE;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ kmem_free(p, *(uint32_t *)p);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_books.c b/usr/src/uts/common/fs/smbsrv/smb_books.c
new file mode 100644
index 0000000000..5e94d8a6f1
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_books.c
@@ -0,0 +1,170 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains functions which destruct SMB session, tree, file,
+ * user and xa structures.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_kproto.h>
+
+/*
+ * If this user is found in the user list,
+ * return 1 on the first occurrence
+ * else return 0 if end of list is reached
+ */
+
+/*
+ * Return # of users
+ */
+uint32_t
+smb_user_get_num(void)
+{
+ smb_session_t *sn = NULL;
+ smb_llist_t *ulist;
+ uint32_t cnt = 0;
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+ while ((sn = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx, sn))
+ != NULL) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ ulist = &sn->s_user_list;
+ cnt += smb_llist_get_count(ulist);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+ return (cnt);
+}
+
+static int
+smb_dr_user_create(smb_dr_user_ctx_t *uinfo, uint64_t sess_id, uint16_t uid,
+ char *domain, char *acct, char *workstation, uint32_t ipaddr,
+ int32_t native_os, time_t logon_time, uint32_t flags)
+{
+ if (!domain || !acct || !workstation)
+ return (-1);
+
+ uinfo->du_session_id = sess_id;
+ uinfo->du_uid = uid;
+
+ uinfo->du_domain_len = strlen(domain) + 1;
+ uinfo->du_domain = smb_kstrdup(domain, uinfo->du_domain_len);
+
+ uinfo->du_account_len = strlen(acct) + 1;
+ uinfo->du_account = smb_kstrdup(acct, uinfo->du_account_len);
+
+ uinfo->du_workstation_len = strlen(workstation) + 1;
+ uinfo->du_workstation = smb_kstrdup(workstation,
+ uinfo->du_workstation_len);
+
+ uinfo->du_native_os = native_os;
+ uinfo->du_ipaddr = ipaddr;
+ uinfo->du_logon_time = (int64_t)logon_time;
+ uinfo->du_flags = flags;
+
+ return (0);
+}
+
+void
+smb_dr_user_free(smb_dr_user_ctx_t *uinfo)
+{
+ if (!uinfo)
+ return;
+
+ if (uinfo->du_domain)
+ kmem_free(uinfo->du_domain, uinfo->du_domain_len);
+
+ if (uinfo->du_account)
+ kmem_free(uinfo->du_account, uinfo->du_account_len);
+
+ if (uinfo->du_workstation)
+ kmem_free(uinfo->du_workstation, uinfo->du_workstation_len);
+}
+
+void
+smb_dr_ulist_free(smb_dr_ulist_t *ulist)
+{
+ int i;
+
+ if (!ulist)
+ return;
+
+ for (i = 0; i < ulist->dul_cnt; i++) {
+ smb_dr_user_free(&ulist->dul_users[i]);
+ }
+}
+
+int
+smb_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist)
+{
+ smb_session_t *sn = NULL;
+ smb_user_t *user;
+ smb_llist_t *ulist;
+ smb_dr_user_ctx_t *uinfo;
+ int cnt = 0, skip = 0;
+
+ if (!dr_ulist)
+ return (-1);
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+ while ((sn = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx, sn))
+ != NULL && cnt < SMB_DR_MAX_USERS) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ ulist = &sn->s_user_list;
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+ while (user && cnt < SMB_DR_MAX_USERS) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ mutex_enter(&user->u_mutex);
+ if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
+ if (skip++ < offset) {
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(ulist, user);
+ continue;
+ }
+
+ uinfo = &dr_ulist->dul_users[cnt++];
+ if (smb_dr_user_create(uinfo, sn->s_kid,
+ user->u_uid, user->u_domain, user->u_name,
+ sn->workstation, sn->ipaddr, sn->native_os,
+ user->u_logon_time, user->u_flags) != 0) {
+ cnt--;
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(ulist, user);
+ continue;
+ }
+ }
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(ulist, user);
+ }
+ smb_llist_exit(ulist);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+ dr_ulist->dul_cnt = cnt;
+ return (cnt);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_check_directory.c b/usr/src/uts/common/fs/smbsrv/smb_check_directory.c
new file mode 100644
index 0000000000..d29e55eda6
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_check_directory.c
@@ -0,0 +1,126 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: check_directory
+ *
+ * This SMB is used to verify that a path exists and is a directory. No
+ * error is returned if the given path exists and the client has read
+ * access to it. Client machines which maintain a concept of a "working
+ * directory" will find this useful to verify the validity of a "change
+ * working directory" command. Note that the servers do NOT have a concept
+ * of working directory for a particular client. The client must always
+ * supply full pathnames relative to the Tid in the SMB header.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryPath[]; Directory path
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * DOS clients, in particular, depend on the SMB_ERR_BAD_PATH return code
+ * if the directory is not found.
+ *
+ * 4.3.3.1 Errors
+ *
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRnoaccess
+ * ERRHRD/ERRdata
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRaccess
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_check_directory(struct smb_request *sr)
+{
+ int rc;
+ struct smb_node *dnode;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Release hold on dir_snode taken in smbd_fs_query()
+ */
+
+ smb_node_release(sr->arg.dirop.fqi.dir_snode);
+
+ dnode = sr->arg.dirop.fqi.last_snode;
+
+ if (sr->arg.dirop.fqi.last_attr.sa_vattr.va_type != VDIR) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ smbsr_raise_errno(sr, ENOTDIR);
+ /* NOTREACHED */
+ }
+
+ rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_TRAVERSE);
+
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ if (rc != 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_close.c b/usr/src/uts/common/fs/smbsrv/smb_close.c
new file mode 100644
index 0000000000..c4d129c2e4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_close.c
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * Close a file by fid. All locks or other resources held by the
+ * requesting process on the file should be released by the server.
+ * The requesting process can no longer use the fid for further
+ * file access requests.
+ *
+ * If LastWriteTime is non-zero, it should be used to set the file
+ * timestamp. Otherwise, file system should set the timestamp.
+ * Failure to set the timestamp, even if requested by the client,
+ * should not result in an error response from the server.
+ */
+int
+smb_com_close(struct smb_request *sr)
+{
+ uint32_t last_wtime;
+ int rc = 0;
+
+ rc = smbsr_decode_vwv(sr, "wl", &sr->smb_fid, &last_wtime);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_common_close(sr, last_wtime);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Close the file represented by fid and then disconnect the
+ * associated tree.
+ */
+int
+smb_com_close_and_tree_disconnect(struct smb_request *sr)
+{
+ uint32_t last_wtime;
+ int rc = 0;
+
+ rc = smbsr_decode_vwv(sr, "wl", &sr->smb_fid, &last_wtime);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_common_close(sr, last_wtime);
+ smbsr_rq_notify(sr, sr->session, sr->tid_tree);
+ smb_tree_disconnect(sr->tid_tree);
+
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_common_close
+ *
+ * Common close function called by SmbClose, SmbWriteAndClose,
+ * and SMBCloseAndTreeDisconnect.
+ */
+int
+smb_common_close(struct smb_request *sr, uint32_t last_wtime)
+{
+ return (smb_ofile_close(sr->fid_ofile, last_wtime));
+}
+
+/*
+ * smb_commit_delete_on_close()
+ *
+ * Check for the DeleteOnClose flag on the smb file and set it on the
+ * smb node if it is not already set. This will inhibit subsequent
+ * open requests. The delete-on-close credentials should be set to the
+ * user credentials of the current open file instance.
+ *
+ * When DeleteOnClose is set on an smb_node, the common open code will
+ * reject subsequent open requests for the file. Observation of Windows
+ * 2000 indicates that subsequent opens should be allowed (assuming
+ * there would be no sharing violation) until the file is closed using
+ * the fid on which the DeleteOnClose was requested.
+ *
+ * If there are multiple opens with delete-on-close create options,
+ * whichever the first file handle is closed will trigger the node to be
+ * marked as delete-on-close. The credentials of that ofile will be used
+ * as the delete-on-close credentials of the node.
+ */
+void
+smb_commit_delete_on_close(struct smb_ofile *ofile)
+{
+ struct smb_node *node = ofile->f_node;
+
+ if (!(node->flags & NODE_FLAGS_DELETE_ON_CLOSE) &&
+ (ofile->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE)) {
+ node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
+ crhold(node->delete_on_close_cred = ofile->f_cr);
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_lock.c b/usr/src/uts/common/fs/smbsrv/smb_common_lock.c
new file mode 100644
index 0000000000..a11a321a7f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_lock.c
@@ -0,0 +1,424 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB Locking library functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * Oplock timeout configuration.
+ */
+#define OPLOCK_RETRIES 2
+time_t smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
+
+
+/*
+ * Oplock functionality enable/disable (see smb_oplock_init).
+ */
+
+/*
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command
+ * Error a 4-byte union, ignored in a request
+ * smb_flg a one byte set of eight flags
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * 0xFFFF is this command does not have
+ * or require a tree context
+ * smb_pid a 16-bit process ID
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid")
+ *
+ * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 8
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Fid; File handle
+ * UCHAR LockType; See LockType table below
+ * UCHAR OplockLevel; The new oplock level
+ * ULONG Timeout; Milliseconds to wait for unlock
+ * USHORT NumberOfUnlocks; Num. unlock range structs following
+ * USHORT NumberOfLocks; Num. lock range structs following
+ * USHORT ByteCount; Count of data bytes
+ * LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges
+ * LOCKING_ANDX_RANGE Locks[]; Lock ranges
+ *
+ * LockType Flag Name Value Description
+ * ============================ ===== ================================
+ *
+ * LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock
+ * LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification
+ * LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type
+ * LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request
+ * LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format
+ *
+ * LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * ULONG Offset; Offset to bytes to [un]lock
+ * ULONG Length; Number of bytes to [un]lock
+ *
+ * Large File LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * USHORT Pad; Pad to DWORD align (mbz)
+ * ULONG OffsetHigh; Offset to bytes to [un]lock
+ * (high)
+ * ULONG OffsetLow; Offset to bytes to [un]lock (low)
+ * ULONG LengthHigh; Number of bytes to [un]lock
+ * (high)
+ * ULONG LengthLow; Number of bytes to [un]lock (low)
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ */
+
+/*
+ * smb_acquire_oplock
+ *
+ * Attempt to acquire an oplock. Note that the oplock granted may be
+ * none, i.e. the oplock was not granted.
+ *
+ * We may have to break an oplock in order to acquire one, and depending
+ * on what action is taken by the other client (unlock or close), we may
+ * or may not end up with an oplock. The type of oplock being requested
+ * is passed in level_requested, the result is returned in level_granted
+ * and is only valid if the status is NT_STATUS_SUCCESS.
+ *
+ * The Returns NT status codes:
+ * NT_STATUS_SUCCESS
+ * NT_STATUS_CONNECTION_DISCONNECTED
+ */
+DWORD
+smb_acquire_oplock(
+ struct smb_request *sr,
+ struct smb_ofile *file,
+ unsigned int level_requested,
+ unsigned int *level_granted)
+{
+ struct smb_node *node = file->f_node;
+ unsigned int level;
+ int oplock_owner;
+ DWORD status;
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ level = level_requested & MYF_OPLOCK_MASK;
+ *level_granted = MYF_OPLOCK_NONE;
+
+ if (smb_info.si.skc_oplock_enable == 0)
+ return (NT_STATUS_SUCCESS);
+
+ if (fsd_chkcap(&sr->tid_tree->t_fsd, FSOLF_DISABLE_OPLOCKS) > 0)
+ return (NT_STATUS_SUCCESS);
+
+restart:
+ oplock_owner = 0;
+
+ /*
+ * I'm not convinced the client redirector will send multiple
+ * opens requesting a batch oplock for the same file. I think
+ * the client redirector will handle the multiple instances
+ * and only send a single open to the server. The the original
+ * implementation supported it, however, so I'll leave it here
+ * for now.
+ *
+ * Grant an oplock to the requester if this session is the
+ * only one that has the file open, regardless of the number
+ * of instances of the file opened by this session. We grant
+ * any oplock requested to the owner.
+ */
+ if (node->n_refcnt == 1 || oplock_owner == 1) {
+ if (MYF_IS_EXCLUSIVE_OPLOCK(level)) {
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->flags |= NODE_EXCLUSIVE_OPLOCK;
+ node->n_oplock.op_ofile = file;
+ } else if (MYF_IS_BATCH_OPLOCK(level)) {
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->flags |= NODE_BATCH_OPLOCK;
+ node->n_oplock.op_ofile = file;
+ } else {
+ level &= ~MYF_OPLOCK_MASK;
+ }
+
+ *level_granted = level;
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /*
+ * Other clients have this file open but they do not have any
+ * oplocks in force, so we must reject this oplock request.
+ */
+ if (node->n_refcnt > 1 && OPLOCKS_IN_FORCE(node) == 0) {
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /*
+ * Someone has an oplock, we need to break it.
+ */
+ if ((status = smb_break_oplock(sr, node)) == NT_STATUS_SUCCESS)
+ goto restart;
+
+ return (status);
+}
+
+
+/*
+ * smb_break_oplock
+ *
+ * The oplock break may succeed for multiple reasons: file close, oplock
+ * release, holder connection dropped, requesting client disconnect etc.
+ * Whatever the reason, the oplock should be broken when this function
+ * returns. The exceptions are when the client making this request gets
+ * disconnected or when another client is handling the break and it gets
+ * disconnected.
+ *
+ * Returns NT status codes:
+ * NT_STATUS_SUCCESS No oplock in force, i.e. the
+ * oplock has been broken.
+ * NT_STATUS_CONNECTION_DISCONNECTED Requesting client disconnected.
+ * NT_STATUS_INTERNAL_ERROR
+ */
+DWORD
+smb_break_oplock(struct smb_request *sr, struct smb_node *node)
+{
+ struct smb_session *sent_session;
+ struct smb_ofile *sent_ofile;
+ struct mbuf_chain mbc;
+ int retries = 0;
+ int tid;
+ unsigned short fid;
+ clock_t elapsed_time;
+ clock_t max_time;
+ boolean_t flag;
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+
+ if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
+
+ elapsed_time = 0;
+ max_time = MSEC_TO_TICK(smb_oplock_timeout * OPLOCK_RETRIES);
+ /*
+ * Another client is already attempting to break the oplock.
+ * We wait for it to finish. If the caller was trying to
+ * acquire an oplock, he should retry in case the client's
+ * connection was dropped while trying to break the oplock.
+ *
+ * If the holder's connection has been dropped, we yield to
+ * allow the thread handling the break to detect it and set
+ * the flags.
+ */
+ while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
+ (elapsed_time < max_time)) {
+ clock_t timeleft;
+
+ timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
+ if (timeleft == -1) {
+ elapsed_time = max_time;
+ } else {
+ elapsed_time += max_time - timeleft;
+ }
+ }
+ /*
+ * If there are no oplocks in force we're done.
+ * Otherwise fall through and break the oplock.
+ */
+ if (OPLOCKS_IN_FORCE(node) == 0) {
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+ } else {
+ /*
+ * Should we clear the
+ * LOCK_BREAKING_OPLOCK flag?
+ */
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+ }
+
+ /*
+ * No oplock break is in progress so we start one.
+ */
+ sent_ofile = node->n_oplock.op_ofile;
+ sent_session = sent_ofile->f_session;
+ ASSERT(sent_session);
+ /*
+ * If a client has an OPLOCK on a file it would not break it because
+ * another of its processes wants to open the same file. However, if
+ * a client were to behave like that it would create a deadlock in the
+ * code that follows. For now we leave the ASSERT(). Eventually the
+ * code will have to be more defensive.
+ */
+ ASSERT(sent_session != sr->session);
+ node->n_oplock.op_flags |= OPLOCK_FLAG_BREAKING;
+ smb_rwx_rwexit(&node->n_lock);
+
+ /*
+ * IR #104382
+ * What we could find from this panic was that the tree field
+ * of sent_ofile structure points to an invalid memory page,
+ * but we couldn't find why exactly this happened. So, this is
+ * a work around till we can find the real problem.
+ */
+ tid = sent_ofile->f_tree->t_tid;
+ fid = sent_ofile->f_fid;
+
+ max_time = MSEC_TO_TICK(smb_oplock_timeout);
+ do {
+ MBC_INIT(&mbc, MLEN);
+ (void) smb_encode_mbc(&mbc, "Mb19.wwwwbb3.ww10.",
+ SMB_COM_LOCKING_ANDX, /* Command */
+ tid, /* TID */
+ 0xffff, /* PID */
+ 0, /* UID */
+ 0xffff, /* MID oplock break */
+ 8, /* parameter words=8 */
+ 0xff, /* 0xFF=none */
+ fid, /* File handle */
+ LOCKING_ANDX_OPLOCK_RELEASE);
+
+ flag = B_TRUE;
+ smb_rwx_rwenter(&sent_session->s_lock, RW_WRITER);
+ while (flag) {
+ switch (sent_session->s_state) {
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ smb_rwx_rwexit(&sent_session->s_lock);
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->n_oplock.op_flags &=
+ ~OPLOCK_FLAG_BREAKING;
+ node->n_oplock.op_ofile = NULL;
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ flag = B_FALSE;
+ break;
+
+ case SMB_SESSION_STATE_NEGOTIATED:
+ sent_session->s_state =
+ SMB_SESSION_STATE_OPLOCK_BREAKING;
+ flag = B_FALSE;
+ break;
+
+ default:
+ (void) smb_rwx_rwwait(&sent_session->s_lock,
+ -1);
+ break;
+ }
+ }
+ smb_rwx_rwexit(&sent_session->s_lock);
+
+ (void) smb_session_send(sent_session, 0, &mbc);
+
+ elapsed_time = 0;
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
+ (elapsed_time < max_time)) {
+ clock_t timeleft;
+
+ timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
+ if (timeleft == -1) {
+ elapsed_time = max_time;
+ } else {
+ elapsed_time += max_time - timeleft;
+ }
+ }
+ if (OPLOCKS_IN_FORCE(node) == 0) {
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+ }
+ } while (++retries < OPLOCK_RETRIES);
+
+ /*
+ * Retries exhausted and timed out.
+ * Cancel the oplock and continue.
+ */
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
+ node->n_oplock.op_ofile = 0;
+ smb_rwx_rwexit(&node->n_lock);
+ return (NT_STATUS_SUCCESS);
+}
+
+
+/*
+ * smb_release_oplock
+ *
+ * The original code supported batch oplock inheritance but I'm not
+ * convinced the client redirector will open multiple instances of a
+ * file with batch oplocks on the server (see smb_acquire_oplock).
+ */
+void /*ARGSUSED*/
+smb_release_oplock(struct smb_ofile *file, int reason)
+{
+ struct smb_node *node = file->f_node;
+
+ smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ if ((node->n_oplock.op_ofile != file) || OPLOCKS_IN_FORCE(node) == 0) {
+ smb_rwx_rwexit(&node->n_lock);
+ return;
+ }
+
+ node->flags &= ~NODE_OPLOCKS_IN_FORCE;
+ node->n_oplock.op_ofile = 0;
+
+ if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
+ node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
+ }
+ smb_rwx_rwexit(&node->n_lock);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
new file mode 100644
index 0000000000..30058e8f82
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -0,0 +1,982 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the common open functionality to the various
+ * open and create SMB interface functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <sys/fcntl.h>
+
+extern uint32_t smb_is_executable(char *path);
+
+#define DENY_READ(share_access) ((share_access & FILE_SHARE_READ) == 0)
+
+#define DENY_WRITE(share_access) ((share_access & FILE_SHARE_WRITE) == 0)
+
+#define DENY_DELETE(share_access) ((share_access & FILE_SHARE_DELETE) == 0)
+
+#define DENY_RW(share_access) \
+ ((share_access & (FILE_SHARE_READ | FILE_SHARE_WRITE)) == 0)
+
+#define DENY_ALL(share_access) (share_access == 0)
+
+#define DENY_NONE(share_access) (share_access == FILE_SHARE_ALL)
+
+/*
+ * The default stability mode is to perform the write-through
+ * behaviour requested by the client.
+ */
+int smb_stable_mode = 0;
+
+
+/*
+ * This macro is used to delete a newly created object
+ * if any error happens after creation of object.
+ */
+#define SMB_DEL_NEWOBJ(obj) \
+ if (created) { \
+ if (is_dir) \
+ (void) smb_fsop_rmdir(sr, sr->user_cr, \
+ obj.dir_snode, obj.last_comp, 0); \
+ else \
+ (void) smb_fsop_remove(sr, sr->user_cr, \
+ obj.dir_snode, obj.last_comp, 0); \
+ }
+
+/*
+ * smb_set_stability
+ *
+ * Set the default stability mode. Normal (mode is zero) means perform
+ * the write-through behaviour requested by the client. Synchronous
+ * (mode is non-zero) means journal everything regardless of the write
+ * through behaviour requested by the client.
+ */
+void
+smb_set_stability(int mode)
+{
+ smb_stable_mode = mode;
+}
+
+/*
+ * smb_access_generic_to_file
+ *
+ * Search MSDN for IoCreateFile to see following mapping.
+ *
+ * GENERIC_READ STANDARD_RIGHTS_READ, FILE_READ_DATA,
+ * FILE_READ_ATTRIBUTES and FILE_READ_EA
+ *
+ * GENERIC_WRITE STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
+ * FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
+ *
+ * GENERIC_EXECUTE STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
+ */
+uint32_t
+smb_access_generic_to_file(uint32_t desired_access)
+{
+ uint32_t access = 0;
+
+ if (desired_access & GENERIC_ALL)
+ return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
+
+ if (desired_access & GENERIC_EXECUTE) {
+ desired_access &= ~GENERIC_EXECUTE;
+ access |= (STANDARD_RIGHTS_EXECUTE |
+ SYNCHRONIZE | FILE_EXECUTE);
+ }
+
+ if (desired_access & GENERIC_WRITE) {
+ desired_access &= ~GENERIC_WRITE;
+ access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
+ }
+
+ if (desired_access & GENERIC_READ) {
+ desired_access &= ~GENERIC_READ;
+ access |= FILE_GENERIC_READ;
+ }
+
+ return (access | desired_access);
+}
+
+/*
+ * smb_omode_to_amask
+ *
+ * This function converts open modes used by Open and Open AndX
+ * commands to desired access bits used by NT Create AndX command.
+ */
+uint32_t
+smb_omode_to_amask(uint32_t desired_access)
+{
+ switch (desired_access & SMB_DA_ACCESS_MASK) {
+ case SMB_DA_ACCESS_READ:
+ return (FILE_GENERIC_READ);
+
+ case SMB_DA_ACCESS_WRITE:
+ return (FILE_GENERIC_WRITE);
+
+ case SMB_DA_ACCESS_READ_WRITE:
+ return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
+
+ case SMB_DA_ACCESS_EXECUTE:
+ return (FILE_GENERIC_EXECUTE);
+ }
+
+ /* invalid open mode */
+ return ((uint32_t)SMB_INVALID_AMASK);
+}
+
+/*
+ * smb_denymode_to_sharemode
+ *
+ * This function converts deny modes used by Open and Open AndX
+ * commands to share access bits used by NT Create AndX command.
+ */
+uint32_t
+smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
+{
+ switch (desired_access & SMB_DA_SHARE_MASK) {
+ case SMB_DA_SHARE_COMPATIBILITY:
+ if (smb_is_executable(fname))
+ return (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ else {
+ if ((desired_access &
+ SMB_DA_ACCESS_MASK) == SMB_DA_ACCESS_READ)
+ return (FILE_SHARE_READ);
+ else
+ return (FILE_SHARE_NONE);
+ }
+
+ case SMB_DA_SHARE_EXCLUSIVE:
+ return (FILE_SHARE_NONE);
+
+ case SMB_DA_SHARE_DENY_WRITE:
+ return (FILE_SHARE_READ);
+
+ case SMB_DA_SHARE_DENY_READ:
+ return (FILE_SHARE_WRITE);
+
+ case SMB_DA_SHARE_DENY_NONE:
+ return (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ }
+
+ /* invalid deny mode */
+ return ((uint32_t)SMB_INVALID_SHAREMODE);
+}
+
+/*
+ * smb_ofun_to_crdisposition
+ *
+ * This function converts open function values used by Open and Open AndX
+ * commands to create disposition values used by NT Create AndX command.
+ */
+uint32_t
+smb_ofun_to_crdisposition(uint16_t ofun)
+{
+ static int ofun_cr_map[3][2] =
+ {
+ { -1, FILE_CREATE },
+ { FILE_OPEN, FILE_OPEN_IF },
+ { FILE_OVERWRITE, FILE_OVERWRITE_IF }
+ };
+
+ int row = ofun & SMB_OFUN_OPEN_MASK;
+ int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
+
+ if (row == 3)
+ return ((uint32_t)SMB_INVALID_CRDISPOSITION);
+
+ return (ofun_cr_map[row][col]);
+}
+
+/*
+ * smb_open_share_check
+ *
+ * check file sharing rules for current open request
+ * against the given existing open.
+ *
+ * Returns NT_STATUS_SHARING_VIOLATION if there is any
+ * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
+ */
+uint32_t
+smb_open_share_check(struct smb_request *sr,
+ struct smb_node *node,
+ struct smb_ofile *open)
+{
+ uint32_t desired_access;
+ uint32_t share_access;
+
+ desired_access = sr->arg.open.desired_access;
+ share_access = sr->arg.open.share_access;
+
+ /*
+ * As far as I can tell share modes are not relevant to
+ * directories. The check for exclusive access (Deny RW)
+ * remains because I don't know whether or not it was here
+ * for a reason.
+ */
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ if (DENY_RW(open->f_share_access) &&
+ (node->n_orig_uid != crgetuid(sr->user_cr))) {
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ /* if it's just meta data */
+ if ((open->f_granted_access & FILE_DATA_ALL) == 0)
+ return (NT_STATUS_SUCCESS);
+
+ /*
+ * Check requested share access against the
+ * open granted (desired) access
+ */
+ if (DENY_DELETE(share_access) && (open->f_granted_access & DELETE))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_READ(share_access) &&
+ (open->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_WRITE(share_access) &&
+ (open->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ /* check requested desired access against the open share access */
+ if (DENY_DELETE(open->f_share_access) && (desired_access & DELETE))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_READ(open->f_share_access) &&
+ (desired_access & (FILE_READ_DATA | FILE_EXECUTE)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ if (DENY_WRITE(open->f_share_access) &&
+ (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+ return (NT_STATUS_SHARING_VIOLATION);
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_file_share_check
+ *
+ * check file sharing rules for current open request
+ * against all existing opens for a file.
+ *
+ * Returns NT_STATUS_SHARING_VIOLATION if there is any
+ * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
+ */
+uint32_t
+smb_file_share_check(struct smb_request *sr, struct smb_node *node)
+{
+ struct smb_ofile *open;
+ uint32_t status;
+
+ if (node == 0 || node->n_refcnt <= 1)
+ return (NT_STATUS_SUCCESS);
+
+ /* if it's just meta data */
+ if ((sr->arg.open.desired_access & FILE_DATA_ALL) == 0)
+ return (NT_STATUS_SUCCESS);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ open = smb_llist_head(&node->n_ofile_list);
+ while (open) {
+ status = smb_open_share_check(sr, node, open);
+ if (status == NT_STATUS_SHARING_VIOLATION) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (status);
+ }
+ open = smb_llist_next(&node->n_ofile_list, open);
+ }
+ smb_llist_exit(&node->n_ofile_list);
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_amask_to_amode
+ * Converts specific read/write access rights of access mask to access
+ * mode flags.
+ */
+int
+smb_amask_to_amode(unsigned long amask)
+{
+ if ((amask & FILE_READ_DATA) &&
+ (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
+ return (O_RDWR);
+
+ if (amask & (FILE_WRITE_DATA | FILE_APPEND_DATA))
+ return (O_WRONLY);
+
+ return (O_RDONLY);
+}
+
+/*
+ * smb_open_subr
+ *
+ * Notes on write-through behaviour. It looks like pre-LM0.12 versions
+ * of the protocol specify the write-through mode when a file is opened,
+ * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
+ * SmbWriteAndUnlock) don't need to contain a write-through flag.
+ *
+ * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
+ * don't indicate which write-through mode to use. Instead the write
+ * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
+ * basis.
+ *
+ * We don't care which open call was used to get us here, we just need
+ * to ensure that the write-through mode flag is copied from the open
+ * parameters to the node. We test the omode write-through flag in all
+ * write functions.
+ *
+ * This function will return NT status codes but it also raises errors,
+ * in which case it won't return to the caller. Be careful how you
+ * handle things in here.
+ */
+uint32_t
+smb_open_subr(struct smb_request *sr)
+{
+ int created = 0;
+ struct smb_node *node = 0;
+ struct smb_node *dnode = 0;
+ struct smb_node *cur_node;
+ struct open_param *op = &sr->arg.open;
+ int rc;
+ struct smb_ofile *of;
+ smb_attr_t new_attr;
+ int pathlen;
+ int max_requested = 0;
+ uint32_t max_allowed;
+ unsigned int granted_oplock;
+ uint32_t status = NT_STATUS_SUCCESS;
+ int is_dir;
+ smb_error_t err;
+ int is_stream;
+ int lookup_flags = SMB_FOLLOW_LINKS;
+ uint32_t daccess;
+
+ is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
+
+ if (is_dir) {
+ /*
+ * The file being created or opened is a directory file.
+ * With this flag, the Disposition parameter must be set to
+ * one of FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
+ */
+ if ((op->create_disposition != FILE_CREATE) &&
+ (op->create_disposition != FILE_OPEN_IF) &&
+ (op->create_disposition != FILE_OPEN)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_ACCESS);
+ /* invalid open mode */
+ /* NOTREACHED */
+ }
+ }
+
+ if (op->desired_access & MAXIMUM_ALLOWED) {
+ max_requested = 1;
+ op->desired_access &= ~MAXIMUM_ALLOWED;
+ }
+ op->desired_access = smb_access_generic_to_file(op->desired_access);
+
+ if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
+
+ ASSERT(sr->uid_user);
+ cmn_err(CE_NOTE, "smbd[%s\\%s]: %s", sr->uid_user->u_domain,
+ sr->uid_user->u_name,
+ xlate_nt_status(NT_STATUS_TOO_MANY_OPENED_FILES));
+
+ smbsr_raise_cifs_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
+ ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
+ /* NOTREACHED */
+ }
+
+ /* This must be NULL at this point */
+ sr->fid_ofile = NULL;
+
+ op->devstate = 0;
+
+ switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ break;
+
+ case STYPE_IPC:
+ /*
+ * No further processing for IPC, we need to either
+ * raise an exception or return success here.
+ */
+ if ((rc = smb_rpc_open(sr)) != 0) {
+ smbsr_raise_nt_error(sr, rc);
+ /* NOTREACHED */
+ } else {
+ return (NT_STATUS_SUCCESS);
+ }
+ break;
+
+ default:
+ smbsr_raise_error(sr, ERRSRV, ERRinvdevice);
+ /* NOTREACHED */
+ break;
+ }
+
+ if ((pathlen = strlen(op->fqi.path)) >= MAXPATHLEN) {
+ smbsr_raise_error(sr, ERRSRV, ERRfilespecs);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Some clients pass null file names; NT interprets this as "\".
+ */
+ if (pathlen == 0) {
+ op->fqi.path = "\\";
+ pathlen = 1;
+ }
+
+ op->fqi.srch_attr = op->fqi.srch_attr;
+
+ if ((status = smb_validate_object_name(op->fqi.path, is_dir)) != 0) {
+ smbsr_raise_cifs_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
+ /* NOTREACHED */
+ }
+
+ cur_node = op->fqi.dir_snode ?
+ op->fqi.dir_snode : sr->tid_tree->t_snode;
+
+ if (rc = smb_pathname_reduce(sr, sr->user_cr, op->fqi.path,
+ sr->tid_tree->t_snode, cur_node, &op->fqi.dir_snode,
+ op->fqi.last_comp)) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * If the access mask has only DELETE set (ignore
+ * FILE_READ_ATTRIBUTES), then assume that this
+ * is a request to delete the link (if a link)
+ * and do not follow links. Otherwise, follow
+ * the link to the target.
+ */
+
+ daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
+
+ if (daccess == DELETE)
+ lookup_flags &= ~SMB_FOLLOW_LINKS;
+
+ rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
+ sr->tid_tree->t_snode, op->fqi.dir_snode, op->fqi.last_comp,
+ &op->fqi.last_snode, &op->fqi.last_attr);
+
+ if (rc == 0) {
+ op->fqi.last_comp_was_found = 1;
+ (void) strcpy(op->fqi.last_comp_od,
+ op->fqi.last_snode->od_name);
+ } else if (rc == ENOENT) {
+ op->fqi.last_comp_was_found = 0;
+ op->fqi.last_snode = NULL;
+ rc = 0;
+ } else {
+ smb_node_release(op->fqi.dir_snode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (op->fqi.last_comp_was_found) {
+ node = op->fqi.last_snode;
+ dnode = op->fqi.dir_snode;
+
+ /*
+ * Reject this request if the target is a directory
+ * and the client has specified that it must not be
+ * a directory (required by Lotus Notes).
+ */
+ if ((op->create_options & FILE_NON_DIRECTORY_FILE) &&
+ (op->fqi.last_attr.sa_vattr.va_type == VDIR)) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_FILE_IS_A_DIRECTORY,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
+ if ((sr->smb_com == SMB_COM_OPEN_ANDX) ||
+ (sr->smb_com == SMB_COM_OPEN)) {
+ /*
+ * Directories cannot be opened
+ * with the above commands
+ */
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_FILE_IS_A_DIRECTORY,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+ } else if (op->my_flags & MYF_MUST_BE_DIRECTORY) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ ERRDOS, ERROR_DIRECTORY);
+ /* NOTREACHED */
+ }
+
+ /*
+ * No more open should be accepted when "Delete on close"
+ * flag is set.
+ */
+ if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, NT_STATUS_DELETE_PENDING,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Specified file already exists so the operation should fail.
+ */
+ if (op->create_disposition == FILE_CREATE) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_OBJECT_NAME_COLLISION, ERRDOS,
+ ERROR_ALREADY_EXISTS);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Windows seems to check read-only access before file
+ * sharing check.
+ */
+ if (NODE_IS_READONLY(node)) {
+ /* Files data only */
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ if (op->desired_access & (FILE_WRITE_DATA |
+ FILE_APPEND_DATA)) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_error(sr, ERRDOS,
+ ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ status = smb_file_share_check(sr, node);
+ if (status == NT_STATUS_SHARING_VIOLATION) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ return (status);
+ }
+
+ status = smb_fsop_access(sr, sr->user_cr, node,
+ op->desired_access);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
+ smbsr_raise_cifs_error(sr,
+ status,
+ ERRDOS,
+ ERROR_PRIVILEGE_NOT_HELD);
+ } else {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_ACCESS_DENIED,
+ ERRDOS,
+ ERROR_ACCESS_DENIED);
+ }
+ }
+
+ /*
+ * Break the oplock before share checks. If another client
+ * has the file open, this will force a flush or close,
+ * which may affect the outcome of any share checking.
+ */
+ if (OPLOCKS_IN_FORCE(node)) {
+ status = smb_break_oplock(sr, node);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, status,
+ ERRDOS, ERROR_VC_DISCONNECTED);
+ /* NOTREACHED */
+ }
+ }
+
+ switch (op->create_disposition) {
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ case FILE_OVERWRITE:
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (node->attr.sa_vattr.va_size != op->dsize) {
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+ new_attr.sa_vattr.va_size = op->dsize;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ if ((rc = smb_fsop_setattr(sr, sr->user_cr,
+ (&op->fqi)->last_snode, &new_attr,
+ &op->fqi.last_attr)) != 0) {
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ }
+
+ /*
+ * If file is being replaced,
+ * we should remove existing streams
+ */
+ if (SMB_IS_STREAM(node) == 0)
+ (void) smb_fsop_remove_streams(sr, sr->user_cr,
+ node);
+
+ op->action_taken = SMB_OACT_TRUNCATED;
+ break;
+
+ default:
+ /*
+ * FILE_OPEN or FILE_OPEN_IF.
+ */
+ op->action_taken = SMB_OACT_OPENED;
+ break;
+ }
+ } else {
+
+ /* Last component was not found. */
+ dnode = op->fqi.dir_snode;
+
+ if ((op->create_disposition == FILE_OPEN) ||
+ (op->create_disposition == FILE_OVERWRITE)) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+
+ is_stream = smb_stream_parse_name(op->fqi.path,
+ NULL, NULL);
+ /*
+ * The requested file not found so the operation should
+ * fail with these two dispositions
+ */
+ if (is_stream)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOTREACHED */
+ }
+
+ /*
+ * lock the parent dir node in case another create
+ * request to the same parent directory comes in.
+ */
+ smb_rwx_rwenter(&dnode->n_lock, RW_WRITER);
+
+ bzero(&new_attr, sizeof (new_attr));
+ if (is_dir == 0) {
+ new_attr.sa_vattr.va_type = VREG;
+ new_attr.sa_vattr.va_mode = 0666;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
+ rc = smb_fsop_create(sr, sr->user_cr, dnode,
+ op->fqi.last_comp, &new_attr,
+ &op->fqi.last_snode, &op->fqi.last_attr);
+ if (rc != 0) {
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (op->dsize) {
+ new_attr.sa_vattr.va_size = op->dsize;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ rc = smb_fsop_setattr(sr, sr->user_cr,
+ op->fqi.last_snode, &new_attr,
+ &op->fqi.last_attr);
+ if (rc != 0) {
+ smb_node_release(op->fqi.last_snode);
+ (void) smb_fsop_remove(sr, sr->user_cr,
+ dnode, op->fqi.last_comp, 0);
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ }
+
+ } else {
+ op->dattr |= SMB_FA_DIRECTORY;
+ new_attr.sa_vattr.va_type = VDIR;
+ new_attr.sa_vattr.va_mode = 0777;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
+ rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
+ op->fqi.last_comp, &new_attr,
+ &op->fqi.last_snode, &op->fqi.last_attr);
+ if (rc != 0) {
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ }
+
+ created = 1;
+ op->action_taken = SMB_OACT_CREATED;
+ }
+
+ if (node == 0) {
+ node = op->fqi.last_snode;
+ }
+
+ if ((op->fqi.last_attr.sa_vattr.va_type != VREG) &&
+ (op->fqi.last_attr.sa_vattr.va_type != VDIR) &&
+ (op->fqi.last_attr.sa_vattr.va_type != VLNK)) {
+ /* not allowed to do this */
+ SMB_DEL_NEWOBJ(op->fqi);
+ smb_node_release(node);
+ if (created)
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ if (max_requested) {
+ smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
+ op->desired_access |= max_allowed;
+ }
+
+ /*
+ * smb_ofile_open() will copy node to of->node. Hence
+ * the hold on node (i.e. op->fqi.last_snode) will be "transferred"
+ * to the "of" structure.
+ */
+
+ of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op->desired_access,
+ op->create_options, op->share_access, SMB_FTYPE_DISK, NULL, 0,
+ &err);
+
+ if (of == NULL) {
+ SMB_DEL_NEWOBJ(op->fqi);
+ smb_node_release(node);
+ if (created)
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_raise_cifs_error(sr, err.status, err.errcls, err.errcode);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Propagate the write-through mode from the open params
+ * to the node: see the notes in the function header.
+ *
+ * IR #102318 Mirroring may force synchronous
+ * writes regardless of what we specify here.
+ */
+ if (smb_stable_mode || (op->create_options & FILE_WRITE_THROUGH))
+ node->flags |= NODE_FLAGS_WRITE_THROUGH;
+
+ op->fileid = op->fqi.last_attr.sa_vattr.va_nodeid;
+
+ if (op->fqi.last_attr.sa_vattr.va_type == VDIR) {
+ /* We don't oplock directories */
+ op->my_flags &= ~MYF_OPLOCK_MASK;
+ op->dsize = 0;
+ } else {
+ status = smb_acquire_oplock(sr, of, op->my_flags,
+ &granted_oplock);
+ op->my_flags &= ~MYF_OPLOCK_MASK;
+
+ if (status != NT_STATUS_SUCCESS) {
+ (void) smb_ofile_close(of, 0);
+ smb_ofile_release(of);
+ if (created)
+ smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+
+ smbsr_raise_cifs_error(sr, status,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ }
+
+ op->my_flags |= granted_oplock;
+ op->dsize = op->fqi.last_attr.sa_vattr.va_size;
+ }
+
+ if (created) {
+ node->flags |= NODE_FLAGS_CREATED;
+ /*
+ * Clients may set the DOS readonly bit on create but they
+ * expect subsequent write operations on the open fid to
+ * succeed. Thus the DOS readonly bit is not set until the
+ * file is closed. The NODE_CREATED_READONLY flag will
+ * inhibit other attempts to open the file with write access
+ * and act as the indicator to set the DOS readonly bit on
+ * close.
+ */
+ if (op->dattr & SMB_FA_READONLY) {
+ node->flags |= NODE_CREATED_READONLY;
+ op->dattr &= ~SMB_FA_READONLY;
+ }
+ smb_node_set_dosattr(node, op->dattr | SMB_FA_ARCHIVE);
+ if (op->utime.tv_sec == 0 || op->utime.tv_sec == 0xffffffff)
+ (void) microtime(&op->utime);
+ smb_node_set_time(node, NULL, &op->utime, 0, 0, SMB_AT_MTIME);
+ (void) smb_sync_fsattr(sr, sr->user_cr, node);
+ } else {
+ /*
+ * If we reach here, it means that file already exists
+ * and if create disposition is one of: FILE_SUPERSEDE,
+ * FILE_OVERWRITE_IF, or FILE_OVERWRITE it
+ * means that client wants to overwrite (or truncate)
+ * the existing file. So we should overwrite the dos
+ * attributes of destination file with the dos attributes
+ * of source file.
+ */
+
+ switch (op->create_disposition) {
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ case FILE_OVERWRITE:
+ smb_node_set_dosattr(node,
+ op->dattr | SMB_FA_ARCHIVE);
+ (void) smb_sync_fsattr(sr, sr->user_cr, node);
+ }
+ op->utime = *smb_node_get_crtime(node);
+ op->dattr = smb_node_get_dosattr(node);
+ }
+
+ /*
+ * Set up the file type in open_param for the response
+ */
+ op->ftype = SMB_FTYPE_DISK;
+ sr->smb_fid = of->f_fid;
+ sr->fid_ofile = of;
+
+ if (created) {
+ smb_rwx_rwexit(&dnode->n_lock);
+ }
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_validate_object_name
+ *
+ * Very basic file name validation. Directory validation is handed off
+ * to smb_validate_dirname. For filenames, we check for names of the
+ * form "AAAn:". Names that contain three characters, a single digit
+ * and a colon (:) are reserved as DOS device names, i.e. "COM1:".
+ *
+ * Returns NT status codes.
+ */
+uint32_t
+smb_validate_object_name(char *path, unsigned int ftype)
+{
+ char *filename;
+
+ if (path == 0)
+ return (0);
+
+ if (ftype)
+ return (smb_validate_dirname(path));
+
+ /*
+ * Basename with backslashes.
+ */
+ if ((filename = strrchr(path, '\\')) != 0)
+ ++filename;
+ else
+ filename = path;
+
+ if (strlen(filename) == 5 &&
+ mts_isdigit(filename[3]) &&
+ filename[4] == ':') {
+ return (NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_preset_delete_on_close
+ *
+ * Set the DeleteOnClose flag on the smb file. When the file is closed,
+ * the flag will be transferred to the smb node, which will commit the
+ * delete operation and inhibit subsequent open requests.
+ *
+ * When DeleteOnClose is set on an smb_node, the common open code will
+ * reject subsequent open requests for the file. Observation of Windows
+ * 2000 indicates that subsequent opens should be allowed (assuming
+ * there would be no sharing violation) until the file is closed using
+ * the fid on which the DeleteOnClose was requested.
+ */
+void
+smb_preset_delete_on_close(smb_ofile_t *file)
+{
+ mutex_enter(&file->f_mutex);
+ file->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
+ mutex_exit(&file->f_mutex);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_search.c b/usr/src/uts/common/fs/smbsrv/smb_common_search.c
new file mode 100644
index 0000000000..a17555669b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_search.c
@@ -0,0 +1,344 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Implementation of smb_rdir_open, smb_rdir_next and smb_rdir_close.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * smb_rdir_open
+ */
+int
+smb_rdir_open(smb_request_t *sr, char *path, unsigned short sattr)
+{
+ smb_odir_t *od;
+ smb_node_t *node;
+ char *last_component;
+ smb_session_t *session = sr->session;
+ unsigned int rc;
+ int erc;
+
+ last_component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode,
+ &node, last_component)) != 0) {
+ kmem_free(last_component, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((node->vp)->v_type != VDIR) {
+ smb_node_release(node);
+ kmem_free(last_component, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRbadpath);
+ /* NOTREACHED */
+ }
+
+ erc = smb_fsop_access(sr, sr->user_cr, node, FILE_LIST_DIRECTORY);
+ if (erc != 0) {
+ smb_node_release(node);
+ kmem_free(last_component, MAXNAMELEN);
+ if (sr->smb_com == SMB_COM_SEARCH) {
+ if (session->capabilities & CAP_STATUS32) {
+ smbsr_setup_nt_status(sr,
+ ERROR_SEVERITY_WARNING,
+ NT_STATUS_NO_MORE_FILES);
+ return (SDRC_NORMAL_REPLY);
+ } else {
+ smbsr_raise_error(sr,
+ ERRDOS, ERROR_NO_MORE_FILES);
+ /* NOTREACHED */
+ }
+ } else {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+ }
+
+ od = smb_odir_open(sr->tid_tree, node, last_component, sr->smb_pid,
+ sattr);
+ kmem_free(last_component, sizeof (od->d_pattern));
+ if (od == NULL) {
+ smb_node_release(node);
+ smbsr_raise_error(sr, ERRDOS, ERROR_NO_MORE_FILES);
+ /* NOTREACHED */
+ }
+
+ sr->smb_sid = od->d_sid;
+ sr->sid_odir = od;
+
+ return (-1);
+}
+
+
+/*
+ * smb_rdir_next
+ *
+ * Returns:
+ * 0 Found an entry
+ * ENOENT There is no (more) entry
+ * error code An error happened
+ */
+int
+smb_rdir_next(
+ smb_request_t *sr,
+ smb_node_t **rnode,
+ smb_odir_context_t *pc)
+{
+ struct smb_odir *dir;
+ ino64_t fileid;
+ int rc, n_name;
+ char last_component[MAXNAMELEN];
+ char namebuf[MAXNAMELEN];
+ smb_node_t *tmp_snode;
+ smb_node_t *dnode;
+ smb_node_t *fnode;
+ smb_attr_t ret_attr;
+
+ ASSERT(sr->sid_odir);
+ dir = sr->sid_odir;
+
+ if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
+ return (ENOENT);
+ }
+
+ if (dir->d_wildcards == 0) {
+ /* There are no wildcards in pattern */
+ if (pc->dc_cookie != 0) {
+ /* Already found entry... */
+ return (ENOENT);
+ }
+
+ pc->dc_name[0] = '\0';
+ pc->dc_shortname[0] = '\0';
+ pc->dc_name83[0] = '\0';
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, 0,
+ sr->tid_tree->t_snode, dir->d_dir_snode, dir->d_pattern,
+ &fnode, &pc->dc_attr, pc->dc_shortname, pc->dc_name83);
+
+ if (rc != 0)
+ return (rc);
+
+ /*
+ * We are here if there was a successful lookup of the
+ * name. The name may be a mangled name. If it was,
+ * then shortname has the copy of it. So, we may
+ * not need to do mangling later.
+ *
+ * dir->name will contain the case-preserved name.
+ * If that name is not available (this should not
+ * happen), then copy dir->pattern into dir->name.
+ */
+
+ if (fnode->od_name) {
+ (void) strcpy(pc->dc_name, fnode->od_name);
+ } else {
+ (void) strcpy(pc->dc_name, dir->d_pattern);
+ }
+
+ /* Root of file system? */
+ if ((strcmp(dir->d_pattern, "..") == 0) &&
+ (dir->d_dir_snode == sr->tid_tree->t_snode)) {
+ smb_node_release(fnode);
+ smb_node_ref(sr->tid_tree->t_snode);
+ fnode = sr->tid_tree->t_snode;
+ } else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
+ (void) strcpy(namebuf, dir->d_pattern);
+
+ tmp_snode = fnode;
+ rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
+ sr->tid_tree->t_snode, dir->d_dir_snode,
+ &dnode, last_component);
+
+ if (rc != 0) {
+ fnode = tmp_snode;
+ } else {
+ rc = smb_fsop_lookup(sr, sr->user_cr,
+ SMB_FOLLOW_LINKS, sr->tid_tree->t_snode,
+ dnode, last_component, &fnode, &ret_attr,
+ 0, 0);
+
+ smb_node_release(dnode);
+ if (rc != 0) {
+ fnode = tmp_snode;
+ } else {
+ pc->dc_attr = ret_attr;
+ smb_node_release(tmp_snode);
+ }
+ }
+ }
+
+ pc->dc_dattr = smb_node_get_dosattr(fnode);
+ /*
+ * If name not already mangled, do it.
+ *
+ * The name will only be mangled if smb_needs_mangle()
+ * determines that it is required. Mangling due to
+ * case-insensitive collisions is not necessary here.
+ */
+ if (pc->dc_name83[0] == '\0')
+ (void) smb_mangle_name(fnode->attr.sa_vattr.va_nodeid,
+ pc->dc_name, pc->dc_shortname, pc->dc_name83, 0);
+ if (rnode)
+ *rnode = fnode;
+ else
+ smb_node_release(fnode);
+
+ pc->dc_cookie = (uint32_t)-1;
+ return (0);
+ } /* No wild card search */
+
+ for (;;) {
+ if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
+ return (ENOENT);
+ }
+
+ /* sizeof dir->name == 256 */
+ n_name = (sizeof (pc->dc_name)) - 1;
+
+ rc = smb_fsop_readdir(sr, sr->user_cr, dir->d_dir_snode,
+ &pc->dc_cookie, pc->dc_name, &n_name, &fileid, NULL,
+ NULL, NULL);
+ if (rc != 0) {
+ return (rc);
+ }
+
+ if (n_name == 0) /* EOF */
+ break;
+ pc->dc_name[n_name] = '\0';
+
+ /*
+ * Don't return "." or ".." unless SMB_FA_HIDDEN bit is set
+ * We have to code these specially since we cannot set the
+ * SMB_FA_HIDDEN bits in these because they are simply links to
+ * the real directory and the real directory is NOT hidden.
+ */
+ if (((dir->d_sattr & SMB_FA_HIDDEN) == 0) &&
+ ((strcmp(pc->dc_name, ".") == 0) ||
+ ((strcmp(pc->dc_name, "..") == 0)))) {
+ continue;
+ }
+
+ /* may match a mangled name or "real" name */
+ if (smb_component_match(sr, fileid, dir, pc) <= 0)
+ continue;
+
+ /* Look up the "real" name */
+ rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
+ dir->d_dir_snode, pc->dc_name, &fnode, &pc->dc_attr, 0, 0);
+
+ if (rc != 0) {
+ if (rc != ENOENT) {
+ return (rc);
+ }
+ else
+ continue;
+ /* NOTREACHED */
+ }
+
+ /* Root of file system? */
+ if ((strcmp(pc->dc_name, "..") == 0) &&
+ (dir->d_dir_snode == sr->tid_tree->t_snode)) {
+ smb_node_release(fnode);
+ smb_node_ref(sr->tid_tree->t_snode);
+ fnode = sr->tid_tree->t_snode;
+ } else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
+ (void) strcpy(namebuf, pc->dc_name);
+
+ smb_node_release(fnode);
+ rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
+ sr->tid_tree->t_snode, dir->d_dir_snode, &dnode,
+ last_component);
+
+ if (rc != 0) {
+ continue;
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dnode, last_component,
+ &fnode, &ret_attr, 0, 0);
+
+ smb_node_release(dnode);
+ if (rc != 0) {
+ continue;
+ }
+ pc->dc_attr = ret_attr;
+ }
+
+ pc->dc_dattr = smb_node_get_dosattr(fnode);
+
+ /* Obey search attributes */
+ if ((pc->dc_dattr & SMB_FA_DIRECTORY) &&
+ !(dir->d_sattr & SMB_FA_DIRECTORY)) {
+ smb_node_release(fnode);
+ continue;
+ }
+
+ if ((pc->dc_dattr & SMB_FA_HIDDEN) &&
+ !(dir->d_sattr & SMB_FA_HIDDEN)) {
+ smb_node_release(fnode);
+ continue;
+ }
+
+ if ((pc->dc_dattr & SMB_FA_SYSTEM) &&
+ !(dir->d_sattr & SMB_FA_SYSTEM)) {
+ smb_node_release(fnode);
+ continue;
+ }
+
+ if (rnode)
+ *rnode = fnode;
+ else
+ smb_node_release(fnode);
+
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+/*
+ * smb_rdir_close
+ */
+void
+smb_rdir_close(struct smb_request *sr)
+{
+ smb_odir_t *od = sr->sid_odir;
+
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ smb_odir_close(od);
+ smb_odir_release(od);
+ sr->sid_odir = NULL;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
new file mode 100644
index 0000000000..2558716c5e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -0,0 +1,2485 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/oem.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/mailslot.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/nterror.h>
+
+extern int smb_maxbufsize;
+
+#define MAX_SHARE_NAME_LEN 13
+#define SHARE_INFO_1_SIZE (MAX_SHARE_NAME_LEN + sizeof (char) + \
+ sizeof (short) + sizeof (uint32_t))
+
+/*
+ * count of bytes in server response packet
+ * except parameters and data. Note that setup
+ * word count is zero.
+ */
+#define RESP_HEADER_LEN 24
+
+/*
+ * NB. I started by using common functions for transaction/transaction2
+ * and transaction_secondary/transaction2_secondary because they
+ * are respectively so similar. However, it turned out to be a bad
+ * idea because of quirky differences. Be sure if you modify one
+ * of these four functions to check and see if the modification should
+ * be applied to its peer.
+ */
+
+int smb_trans_ready(struct smb_xa *xa);
+int smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa);
+int smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa);
+int smb_trans2_find(struct smb_request *sr, struct smb_xa *xa, int opcode);
+int smb_trans2_query_fs_info(struct smb_request *sr, struct smb_xa *xa);
+
+
+int smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa);
+
+int
+smb_com_transaction(struct smb_request *sr)
+{
+ int rc;
+ unsigned char msrcnt, suwcnt;
+ uint16_t tpscnt, tdscnt, mprcnt, mdrcnt, flags;
+ uint16_t pscnt, psoff, dscnt, dsoff;
+ uint32_t timeo;
+ struct smb_xa *xa;
+ char *stn;
+ int ready;
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT,
+ &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &msrcnt, &flags,
+ &timeo, &pscnt, &psoff, &dscnt, &dsoff, &suwcnt);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
+ msrcnt, suwcnt);
+ if (xa == NULL) {
+ smbsr_raise_error(sr, ERRSRV, ERRnoroom);
+ /* NOTREACHED */
+ }
+
+ /* Should be some alignment stuff here in SMB? */
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
+ rc = smbsr_decode_data(sr, "%.U", sr, &stn);
+ } else {
+ rc = smbsr_decode_data(sr, "%s", sr, &stn);
+ }
+ if (rc != 0) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ xa->xa_smb_trans_name = MEM_STRDUP("smb", stn);
+
+ xa->smb_flags = flags;
+ xa->smb_timeout = timeo;
+ xa->req_disp_param = pscnt;
+ xa->req_disp_data = dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
+ sr->smb_vwv.chain_offset, suwcnt * 2)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ ready = smb_trans_ready(xa);
+
+ if (smb_xa_open(xa)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRsrverror);
+ /* NOTREACHED */
+ }
+ sr->r_xa = xa;
+
+ if (!ready) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (!smb_xa_complete(xa)) {
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ return (smb_trans_dispatch(sr, xa));
+}
+
+
+int
+smb_com_transaction_secondary(struct smb_request *sr)
+{
+ uint16_t tpscnt, tdscnt, pscnt, psdisp;
+ uint16_t dscnt, dsoff, dsdisp, psoff;
+ smb_xa_t *xa;
+ int rc;
+
+ if ((xa = smbsr_lookup_xa(sr)) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRsrverror);
+ /* NOTREACHED */
+ }
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (xa->smb_com != SMB_COM_TRANSACTION) {
+ return (SDRC_DROP_VC);
+ }
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANSSHDR_ED_FMT, &tpscnt, &tdscnt,
+ &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&xa->xa_mutex);
+ xa->smb_tpscnt = tpscnt; /* might have shrunk */
+ xa->smb_tdscnt = tdscnt; /* might have shrunk */
+ xa->req_disp_param = psdisp+pscnt;
+ xa->req_disp_data = dsdisp+dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ mutex_exit(&xa->xa_mutex);
+
+ if (!smb_trans_ready(xa))
+ return (SDRC_NO_REPLY);
+
+ if (!smb_xa_complete(xa))
+ return (SDRC_NO_REPLY);
+
+ return (smb_trans_dispatch(sr, xa));
+}
+
+
+int
+smb_com_ioctl(struct smb_request *sr)
+{
+ uint16_t fid, category, function, tpscnt, tdscnt, mprcnt;
+ uint16_t mdrcnt, pscnt, pdoff, dscnt, dsoff;
+ uint32_t timeout;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "wwwwwwwl2.wwww", &fid, &category, &function,
+ &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &timeout, &pscnt,
+ &pdoff, &dscnt, &dsoff);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+int /*ARGSUSED*/
+smb_com_ioctl_secondary(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+int
+smb_com_transaction2(struct smb_request *sr)
+{
+ unsigned char msrcnt, suwcnt;
+ uint16_t tpscnt, tdscnt, mprcnt, mdrcnt, flags;
+ uint16_t pscnt, psoff, dscnt, dsoff;
+ uint32_t timeo;
+ smb_xa_t *xa;
+ int ready;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT, &tpscnt, &tdscnt,
+ &mprcnt, &mdrcnt, &msrcnt, &flags, &timeo, &pscnt, &psoff, &dscnt,
+ &dsoff, &suwcnt);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
+ msrcnt, suwcnt);
+ if (xa == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRnoroom);
+ /* NOTREACHED */
+ }
+
+ xa->smb_flags = flags;
+ xa->smb_timeout = timeo;
+ xa->req_disp_param = pscnt;
+ xa->req_disp_data = dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
+ sr->smb_vwv.chain_offset, suwcnt*2)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ ready = smb_trans_ready(xa);
+
+ if (smb_xa_open(xa)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRsrverror);
+ /* NOTREACHED */
+ }
+ sr->r_xa = xa;
+
+ if (!ready) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (!smb_xa_complete(xa)) {
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ return (smb_trans2_dispatch(sr, xa));
+}
+
+
+int
+smb_com_transaction2_secondary(struct smb_request *sr)
+{
+ uint16_t tpscnt, tdscnt, fid;
+ uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
+ smb_xa_t *xa;
+ int rc;
+
+ if ((xa = smbsr_lookup_xa(sr)) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRsrverror);
+ /* NOTREACHED */
+ }
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (xa->smb_com != SMB_COM_TRANSACTION2) {
+ return (SDRC_DROP_VC);
+ }
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
+ &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&xa->xa_mutex);
+ xa->smb_tpscnt = tpscnt; /* might have shrunk */
+ xa->smb_tdscnt = tdscnt; /* might have shrunk */
+ xa->xa_smb_fid = fid; /* overwrite rules? */
+ xa->req_disp_param = psdisp + pscnt;
+ xa->req_disp_data = dsdisp + dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ mutex_exit(&xa->xa_mutex);
+
+ if (!smb_trans_ready(xa))
+ return (SDRC_NO_REPLY);
+
+ if (!smb_xa_complete(xa))
+ return (SDRC_NO_REPLY);
+
+ return (smb_trans2_dispatch(sr, xa));
+}
+
+static int
+smb_nt_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+
+ n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
+ n_setup++;
+ n_setup = n_setup & ~0x0001;
+ n_param = (xa->smb_mprcnt < smb_maxbufsize)
+ ? xa->smb_mprcnt : smb_maxbufsize;
+ n_param++;
+ n_param = n_param & ~0x0001;
+ rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
+ n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+ MBC_INIT(&xa->rep_param_mb, n_param);
+ MBC_INIT(&xa->rep_data_mb, n_data);
+
+ switch (xa->smb_func) {
+ case NT_TRANSACT_CREATE:
+ rc = smb_nt_transact_create(sr, xa);
+ break;
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ rc = smb_nt_transact_notify_change(sr, xa);
+ break;
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ rc = smb_nt_transact_query_security_info(sr, xa);
+ break;
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ rc = smb_nt_transact_set_security_info(sr, xa);
+ break;
+ case NT_TRANSACT_IOCTL:
+ rc = smb_nt_transact_ioctl(sr, xa);
+ break;
+
+ case NT_TRANSACT_QUERY_QUOTA:
+ (void) smb_nt_transact_query_quota(sr, xa);
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+
+ case NT_TRANSACT_SET_QUOTA:
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+
+ default:
+ smbsr_raise_error(sr, ERRSRV, ERRsmbcmd);
+ /* NOTREACHED */
+ }
+
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_DROP_VC:
+ case SDRC_NO_REPLY:
+ case SDRC_ERROR_REPLY:
+ return (rc);
+
+ case SDRC_UNIMPLEMENTED:
+ case SDRC_UNSUPPORTED:
+ smbsr_raise_error(sr, ERRSRV, ERRsmbcmd);
+ /* NOTREACHED */
+
+ default:
+ break;
+ }
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ if (xa->smb_msrcnt < n_setup ||
+ xa->smb_mprcnt < n_param ||
+ xa->smb_mdrcnt < n_data) {
+ smbsr_raise_error(sr, ERRSRV, ERRsmbcmd);
+ /* NOTREACHED */
+ }
+
+ /* neato, blast it over there */
+
+ n_setup = (n_setup + 1) / 2; /* Conver to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
+ data_pad = (4 - ((param_off + n_param) & 3)) % 4; /* Pad to 4 byte */
+ data_off = param_off + n_param + data_pad; /* Param off from hdr */
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 18+n_setup, total_bytes,
+ "b 3. llllllllb C w #. C #. C",
+ 18 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_nt_transact_query_quota
+ *
+ * Stub to help debunk this function. There are 16 parameter bytes. The
+ * first parameter is definitely the fid. The second looks like a flags
+ * field. Then there are 12 bytes (probably 3 dwords) - all zero.
+ */
+int
+smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t fid;
+ uint16_t flags;
+ int rc;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "%ww", sr, &fid, &flags);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+int
+smb_com_nt_transact(struct smb_request *sr)
+{
+ uint16_t Function;
+ unsigned char MaxSetupCount, SetupCount;
+ uint32_t TotalParameterCount, TotalDataCount;
+ uint32_t MaxParameterCount, MaxDataCount, pscnt;
+ uint32_t psoff, dscnt, dsoff;
+ smb_xa_t *xa;
+ int ready;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, SMB_NT_TRANSHDR_ED_FMT, &MaxSetupCount,
+ &TotalParameterCount, &TotalDataCount, &MaxParameterCount,
+ &MaxDataCount, &pscnt, &psoff, &dscnt,
+ &dsoff, &SetupCount, &Function);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ xa = smb_xa_create(sr->session, sr, TotalParameterCount, TotalDataCount,
+ MaxParameterCount, MaxDataCount, MaxSetupCount, SetupCount);
+ if (xa == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRnoroom);
+ /* NOTREACHED */
+ }
+
+ xa->smb_flags = 0;
+ xa->smb_timeout = 0;
+ xa->smb_func = Function;
+ xa->req_disp_param = pscnt;
+ xa->req_disp_data = dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
+ sr->smb_vwv.chain_offset, SetupCount * 2)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ ready = smb_trans_ready(xa);
+
+ if (smb_xa_open(xa)) {
+ smb_xa_rele(sr->session, xa);
+ smbsr_raise_error(sr, ERRDOS, ERRsrverror);
+ /* NOTREACHED */
+ }
+ sr->r_xa = xa;
+
+ if (!ready) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (!smb_xa_complete(xa)) {
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+
+ return (smb_nt_trans_dispatch(sr, xa));
+}
+
+
+int
+smb_com_nt_transact_secondary(struct smb_request *sr)
+{
+ uint16_t tpscnt, tdscnt, fid;
+ uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
+ smb_xa_t *xa;
+ int rc;
+
+ if ((xa = smbsr_lookup_xa(sr)) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRsrverror);
+ /* NOTREACHED */
+ }
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (xa->smb_com != SMB_COM_TRANSACTION2) {
+ return (SDRC_DROP_VC);
+ }
+
+ rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
+ &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&xa->xa_mutex);
+ xa->smb_tpscnt = tpscnt; /* might have shrunk */
+ xa->smb_tdscnt = tdscnt; /* might have shrunk */
+ xa->xa_smb_fid = fid; /* overwrite rules? */
+ xa->req_disp_param = psdisp+pscnt;
+ xa->req_disp_data = dsdisp+dscnt;
+
+ if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_xa_close(xa);
+ smbsr_raise_error(sr, ERRDOS, ERRbadformat);
+ /* NOTREACHED */
+ }
+ mutex_exit(&xa->xa_mutex);
+
+ if (!smb_trans_ready(xa))
+ return (SDRC_NO_REPLY);
+
+ if (!smb_xa_complete(xa))
+ return (SDRC_NO_REPLY);
+
+ return (smb_nt_trans_dispatch(sr, xa));
+}
+
+int
+smb_trans_ready(struct smb_xa *xa)
+{
+ int rc;
+
+ mutex_enter(&xa->xa_mutex);
+ rc = xa->req_disp_data >= xa->smb_tdscnt &&
+ xa->req_disp_param >= xa->smb_tpscnt;
+ mutex_exit(&xa->xa_mutex);
+
+ return (rc);
+}
+
+
+/*
+ * smb_emit_SHARE_INFO_0
+ *
+ * This function will convert unicode chars to oem chars before
+ * and store the result in a fixed length, MAX_SHARE_NAME_LEN, buffer. If the
+ * length after conversion is longer than 12, -1 will be reported
+ * to indicate an error. The fixed length is a limitation of the
+ * smb protocol.
+ */
+static int
+smb_emit_SHARE_INFO_0(struct mbuf_chain *output, unsigned char *name)
+{
+ mts_wchar_t *unibuf;
+ char *tmpbuf;
+ unsigned int cpid = oem_get_smb_cpid();
+ unsigned int length;
+ char name_buf[MAX_SHARE_NAME_LEN];
+
+ if (name == 0)
+ tmpbuf = "";
+ else
+ tmpbuf = (char *)name;
+
+ length = strlen(tmpbuf) + 1;
+ unibuf = MEM_MALLOC("smb", length * sizeof (mts_wchar_t));
+
+ (void) mts_mbstowcs(unibuf, tmpbuf, length);
+ tmpbuf = MEM_MALLOC("smb", length);
+ if (unicodestooems(tmpbuf, unibuf, length, cpid) == 0)
+ (void) strcpy(tmpbuf, (char *)name);
+
+ if (strlen(tmpbuf) + 1 > MAX_SHARE_NAME_LEN) {
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+ return (-1);
+ }
+
+ bzero(name_buf, sizeof (name_buf));
+ (void) strcpy(name_buf, tmpbuf);
+ (void) smb_encode_mbc(output, "13c", name_buf);
+
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+
+ return (0);
+}
+
+static int
+smb_emit_SHARE_INFO_1(struct mbuf_chain *output, struct mbuf_chain *text,
+ unsigned char *name, uint16_t type,
+ unsigned char *comment)
+{
+ if (smb_emit_SHARE_INFO_0(output, name) < 0)
+ return (-1);
+
+ (void) smb_encode_mbc(output, ".wl", type, MBC_LENGTH(text));
+ (void) smb_encode_mbc(text, "s",
+ (comment ? comment : (unsigned char *)"No comment"));
+ return (0);
+}
+
+static void /*ARGSUSED*/
+smb_emit_SHARE_INFO_2(struct mbuf_chain *output, struct mbuf_chain *text,
+ struct smb_request *sr, unsigned char *name, uint16_t type,
+ unsigned char *comment, uint16_t access, char *path, char *password)
+{
+ unsigned char pword[9];
+
+ /*
+ * XXX PGD. Is there a bug here? We zero pword, copy password
+ * into pword then ignore it and use password for smb_encode_mbc?
+ */
+ bzero(pword, sizeof (pword));
+ (void) strncpy((char *)pword, password, sizeof (pword));
+ (void) smb_emit_SHARE_INFO_1(output, text, name, type, comment);
+ (void) smb_encode_mbc(output, "wwwl9c.",
+ access,
+ smb_info.si.skc_maxconnections,
+ smb_svcstate_session_count(&smb_info.si_svc_sm_ctx),
+ MBC_LENGTH(text),
+ password);
+ (void) smb_encode_mbc(text, "s", path);
+}
+
+/*
+ * is_long_sharename
+ *
+ * This function is extracted from smb_emit_SHARE_INFO_0 only for
+ * finding shares that their names are longer than MAX_SHARE_NAME_LEN.
+ *
+ * The function returns 1 for long share names and 0 when the length
+ * is Ok.
+ */
+static int
+is_long_sharename(unsigned char *name)
+{
+ mts_wchar_t *unibuf;
+ char *tmpbuf;
+ unsigned int cpid = oem_get_smb_cpid();
+ unsigned int length;
+
+ if (name == 0)
+ tmpbuf = "";
+ else
+ tmpbuf = (char *)name;
+
+ length = strlen(tmpbuf) + 1;
+ unibuf = MEM_MALLOC("smb", length * sizeof (mts_wchar_t));
+ (void) mts_mbstowcs(unibuf, tmpbuf, length);
+ tmpbuf = MEM_MALLOC("smb", length);
+ if (unicodestooems(tmpbuf, unibuf, length, cpid) == 0)
+ (void) strcpy(tmpbuf, (char *)name);
+
+ if (strlen(tmpbuf) + 1 > MAX_SHARE_NAME_LEN) {
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+ return (1);
+ }
+
+ MEM_FREE("smb", unibuf);
+ MEM_FREE("smb", tmpbuf);
+
+ return (0);
+}
+
+/*
+ * This structure holds information about shares which will
+ * fit in the specified client buffer size.
+ *
+ * sei_bufsize: Client specified buffer size
+ * sei_count: Maximum number of shares that can be
+ * sent in the buffer.
+ *
+ * The return data section consists of a number of SHARE_INFO_1 structures.
+ * In case there are multiple SHARE_INFO_1 data structures to return this
+ * function put all fixed length part of these structures in the return buffer
+ * and then put all the variable length data (shares' comment) at the end of
+ * buffer.
+ *
+ * sei_info_len: Size of fixed length part of SHARE_INFO_1
+ * structures for sei_count shares
+ * sei_cmnt_len: Size of comments for sei_count shares
+ */
+typedef struct {
+ uint16_t sei_bufsize;
+ short sei_count;
+ int sei_infolen;
+ int sei_cmntlen;
+} smb_share_enum_t;
+
+/*
+ * smb_share_update_info
+ *
+ * Check to see if the given buffer has enough
+ * room to fit the information of the given share.
+ * If there is enough room update the passed max_???
+ * information.
+ *
+ * Return 1 if buffer is not full yet, 0 if it's full.
+ */
+static int
+smb_share_update_info(lmshare_info_t *si, smb_share_enum_t *shr_enum_info)
+{
+ int cmnt_len;
+ int new_info_len = shr_enum_info->sei_infolen;
+ int new_cmnt_len = shr_enum_info->sei_cmntlen;
+
+ if (lmshrd_is_special(si->share_name))
+ cmnt_len = 1;
+ else
+ cmnt_len = (strlen(si->comment) + 1);
+
+ new_info_len += SHARE_INFO_1_SIZE;
+ new_cmnt_len += cmnt_len;
+
+ if ((new_info_len + new_cmnt_len) < shr_enum_info->sei_bufsize) {
+ shr_enum_info->sei_count++;
+ shr_enum_info->sei_infolen = new_info_len;
+ shr_enum_info->sei_cmntlen = new_cmnt_len;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_share_skip_share
+ *
+ * Determines whether the given share should be enumerated
+ * or not. The share will not be enumerated if its name is
+ * long or it's autohome share.
+ *
+ * Return 1 if the share should be skipped; otherwise returns
+ * 0
+ */
+static int
+smb_share_skip_share(lmshare_info_t *si)
+{
+ if (is_long_sharename((unsigned char *)si->share_name)) {
+ return (1);
+ }
+
+ /* Skip autohome share if autohome filter is enabled */
+ if (si->mode == LMSHRM_TRANS) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_share_add_autohome
+ *
+ * Determines if an autohome share should be added to shares' list
+ * for the given user.
+ * Autohome will be add when all the following conditions are true:
+ *
+ * 1. Autohome feature is enabled
+ * 2. A share with the same name as the given user exists
+ * 3. The share is not a permanent share
+ * 4. Share name is not longer than maximum allowed
+ */
+static int
+smb_share_add_autohome(char *username, lmshare_info_t *si)
+{
+ int do_add = 0;
+
+ do_add = (lmshrd_getinfo(username, si) == NERR_Success) &&
+ (si->mode & LMSHRM_TRANS) &&
+ (is_long_sharename((unsigned char *)(si->share_name)) == 0);
+
+ return (do_add);
+}
+
+/*
+ * smb_share_total_info
+ *
+ * This function calculates following informations
+ * - Maximum number of shares that can be sent for clients
+ * according to its buffer size (cli_bufsize)
+ * - length of fixed information about above shares
+ * - length of comments of above shares
+ * - total number of shares that their names are no longer
+ * than MAX_SHARE_NAME_LEN.
+ *
+ * Added SMB user object to the parameter list to filter out other
+ * user autohome shares.
+ */
+static void
+smb_share_total_info(smb_share_enum_t *shr_enum_info, short *tot_shares_num,
+ smb_user_t *user)
+{
+ uint64_t iterator;
+ lmshare_info_t *si;
+ struct lmshare_info *auto_si;
+ int more_room = 1;
+
+ si = kmem_zalloc(sizeof (lmshare_info_t), KM_SLEEP);
+ auto_si = kmem_zalloc(sizeof (struct lmshare_info), KM_SLEEP);
+
+ *tot_shares_num = 0;
+ shr_enum_info->sei_count = 0;
+ shr_enum_info->sei_infolen = 0;
+ shr_enum_info->sei_cmntlen = 0;
+
+ if (smb_share_add_autohome(user->u_name, auto_si)) {
+ (*tot_shares_num)++;
+ more_room = smb_share_update_info(auto_si, shr_enum_info);
+ }
+
+ iterator = lmshrd_open_iterator(LMSHRM_ALL);
+ if (iterator == 0) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+ return;
+ }
+
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+ return;
+ }
+
+ while (*si->share_name != 0) {
+ if (smb_share_skip_share(si)) {
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si,
+ sizeof (struct lmshare_info));
+ return;
+ }
+ continue;
+ }
+
+ (*tot_shares_num)++;
+
+ if (more_room) {
+ more_room = smb_share_update_info(si, shr_enum_info);
+ }
+
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+ return;
+ }
+ }
+
+ (void) lmshrd_close_iterator(iterator);
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(auto_si, sizeof (struct lmshare_info));
+}
+
+/*
+ * smb_encode_SHARE_INFO_1
+ *
+ * This function is extracted from smb_emit_SHARE_INFO_1 and only
+ * encodes fixed part of SHARE_INFO_1 structure.
+ *
+ * The function returns -1 if encoding fails and 0 on success.
+ */
+static int
+smb_encode_SHARE_INFO_1(struct mbuf_chain *output, unsigned char *name,
+ uint16_t type, int cmnt_len)
+{
+ if (smb_emit_SHARE_INFO_0(output, name) < 0)
+ return (-1);
+ (void) smb_encode_mbc(output, ".wl", type, cmnt_len);
+ return (0);
+}
+
+/*
+ * collect_shares_info
+ *
+ * This function encodes information of shares_num of shares
+ * into data_mb and cmnt_str.
+ *
+ * Added SMB user object to the parameter list to filter out other
+ * user autohome shares.
+ *
+ */
+static void
+collect_shares_info(uint64_t iterator, int shares_num,
+ struct mbuf_chain *data_mb,
+ char *cmnt_str, int *cmnt_len,
+ smb_user_t *user, int first_resp)
+{
+ int i = 0;
+ lmshare_info_t *si;
+ struct lmshare_info *tsi;
+ int is_special;
+
+ si = kmem_zalloc(sizeof (lmshare_info_t), KM_SLEEP);
+ tsi = kmem_zalloc(sizeof (struct lmshare_info), KM_SLEEP);
+
+ if (first_resp && smb_share_add_autohome(user->u_name, tsi)) {
+ if (smb_encode_SHARE_INFO_1(data_mb,
+ (unsigned char *)tsi->share_name,
+ tsi->stype, *cmnt_len) == 0) {
+ (void) memcpy(cmnt_str+(*cmnt_len),
+ tsi->comment, strlen(tsi->comment)+1);
+ (*cmnt_len) += (strlen(tsi->comment) + 1);
+ i++;
+ }
+ }
+
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+ return;
+ }
+
+ while ((i < shares_num) && (*si->share_name != 0)) {
+ if (smb_share_skip_share(si)) {
+ goto next;
+ }
+
+
+ is_special = lmshrd_is_special(si->share_name);
+ /* check for door errors */
+ if (is_special == NERR_InternalError) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+ return;
+ }
+
+ if (is_special) {
+ si->stype |= STYPE_HIDDEN;
+ if (smb_encode_SHARE_INFO_1(data_mb,
+ (unsigned char *)si->share_name,
+ si->stype, *cmnt_len) < 0) {
+ goto next;
+ }
+ cmnt_str[*cmnt_len] = '\0';
+ (*cmnt_len)++;
+ } else {
+ if (smb_encode_SHARE_INFO_1(data_mb,
+ (unsigned char *)si->share_name, si->stype,
+ *cmnt_len) < 0) {
+ goto next;
+ }
+ (void) memcpy(cmnt_str+(*cmnt_len), si->comment,
+ strlen(si->comment)+1);
+ (*cmnt_len) += (strlen(si->comment) + 1);
+ }
+
+ next:
+ /* check for door errors */
+ if (lmshrd_iterate(iterator, si) != NERR_Success) {
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+ return;
+ }
+ }
+ kmem_free(si, sizeof (lmshare_info_t));
+ kmem_free(tsi, sizeof (struct lmshare_info));
+}
+
+int
+smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_share_enum_t shr_enum_info;
+ short left_shares_cnt; /* Number of shares not sent yet */
+
+ /*
+ * Number of shares that should be sent
+ * in the current response packet.
+ * It can be a number between 0 and
+ * max_share_scnt.
+ */
+ short shares_scnt;
+
+ /*
+ * Maximum number of shares that can be
+ * sent in one response packet regarding
+ * the maximum negotiated buffer size
+ * for SMB messages.
+ */
+ short max_shares_per_packet;
+
+ /*
+ * Total number of shares on the server
+ * that their name is not greater than
+ * MAX_SHARE_NAME_LEN
+ */
+ short shares_tot_num;
+
+ /*
+ * Size of total data (info + cmnt)
+ * that should be sent for client
+ */
+ int shares_tot_byte;
+
+ /*
+ * Maximum size of data that can be
+ * sent in one SMB transaction response
+ * according to the maximum negotiated
+ * buffer size for SMB packets
+ */
+ int data_buf_limit;
+
+ /*
+ * Number of comment bytes that will
+ * be sent in the current response
+ */
+ uint16_t cmnt_scnt;
+
+ /*
+ * Number of data bytes that will
+ * be sent in the current response
+ */
+ uint16_t data_scnt;
+
+ /*
+ * Total number of data bytes that
+ * are sent till now. This is only
+ * used for calculating current data
+ * displacement
+ */
+ uint16_t tot_data_scnt;
+
+ /*
+ * Number of parameter bytes should
+ * be sent for the current response.
+ * It is 8 for the 1st response and
+ * 0 for others
+ */
+ uint16_t param_scnt;
+
+ /* number of setup and parameter bytes */
+ uint16_t n_setup, n_param;
+
+ /* data and parameter displacement */
+ uint16_t data_disp, param_disp;
+
+ /* return status by the 1st reply */
+ uint16_t ret_stat;
+
+ /* parameter and data offset and pad */
+ int param_off, param_pad, data_off, data_pad;
+
+ /*
+ * total bytes of parameters and data
+ * in the packet, plus the pad bytes.
+ */
+ int tot_packet_bytes;
+
+ char first_resp;
+ uint16_t opcode, level, cli_bufsize;
+ unsigned char *r_fmt;
+ char fmt[10];
+ uint64_t iterator;
+ char *cmnt_str, *cmnt_start;
+ int cmnt_len;
+ struct mbuf_chain reply;
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ /*
+ * Initialize the mbuf chain of reply to zero. If it is not
+ * zero, code inside the while loop will try to free the chain.
+ */
+ bzero(&reply, sizeof (struct mbuf_chain));
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wss(lev)w(size)w", sr,
+ &opcode, &r_fmt, &r_fmt, &level, &cli_bufsize) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ if (level != 1) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ NERR_BadTransactConfig, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ n_setup = 0; /* Setup count for NetShareEnum SMB is 0 */
+ n_param = 8;
+ data_buf_limit = sr->session->smb_msg_size -
+ (SMB_HEADER_ED_LEN + RESP_HEADER_LEN + n_param);
+
+ shr_enum_info.sei_bufsize = cli_bufsize;
+ smb_share_total_info(&shr_enum_info, &shares_tot_num, user);
+
+ shares_tot_byte = shr_enum_info.sei_infolen + shr_enum_info.sei_cmntlen;
+
+ /* Check buffer to have enough space */
+ if (shares_tot_byte == 0) {
+ return (SDRC_ERROR_REPLY);
+ }
+
+ max_shares_per_packet = data_buf_limit / SHARE_INFO_1_SIZE;
+
+ shares_scnt = (shr_enum_info.sei_count > max_shares_per_packet)
+ ? max_shares_per_packet : shr_enum_info.sei_count;
+
+ cmnt_str = MEM_MALLOC("smb", shr_enum_info.sei_cmntlen * sizeof (char));
+ cmnt_len = 0;
+ /* save start of buffer to free it at the end of function */
+ cmnt_start = cmnt_str;
+
+ iterator = lmshrd_open_iterator(LMSHRM_ALL);
+
+ if (iterator == NULL) {
+ MEM_FREE("smb", cmnt_str);
+ return (SDRC_DROP_VC);
+ }
+
+ /*
+ * The rep_setup_mb is already initialized in smb_trans_dispatch().
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources before calling MBC_INIT() again.
+ */
+ m_freem(xa->rep_setup_mb.chain);
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+
+ left_shares_cnt = shr_enum_info.sei_count;
+ tot_data_scnt = 0;
+ cmnt_scnt = 0;
+
+ first_resp = 1;
+ while (tot_data_scnt < shares_tot_byte) {
+ /*
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources if any before calling MBC_INIT().
+ */
+ m_freem(xa->rep_data_mb.chain);
+ MBC_INIT(&xa->rep_data_mb, data_buf_limit);
+ collect_shares_info(iterator, shares_scnt, &xa->rep_data_mb,
+ cmnt_str, &cmnt_len, user, first_resp);
+ data_scnt = shares_scnt * SHARE_INFO_1_SIZE;
+ left_shares_cnt -= shares_scnt;
+ if (left_shares_cnt < max_shares_per_packet)
+ shares_scnt = left_shares_cnt;
+ if (left_shares_cnt == 0) {
+ /*
+ * Now send comments.
+ * Append comments to the end of share_info_1
+ * structures.
+ */
+ cmnt_scnt = data_buf_limit -
+ MBC_LENGTH(&xa->rep_data_mb);
+ if (cmnt_scnt > shr_enum_info.sei_cmntlen) {
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ cmnt_scnt = shr_enum_info.sei_cmntlen;
+ }
+ (void) sprintf(fmt, "%dc", cmnt_scnt);
+ (void) smb_encode_mbc(&xa->rep_data_mb, fmt, cmnt_str);
+ cmnt_str += cmnt_scnt;
+ shr_enum_info.sei_cmntlen -= cmnt_scnt;
+ }
+ data_scnt += cmnt_scnt;
+ tot_data_scnt += data_scnt;
+
+ /* Only the 1st response packet contains parameters */
+ param_scnt = (first_resp) ? n_param : 0;
+ param_pad = 1; /* always one */
+ param_off = SMB_HEADER_ED_LEN + RESP_HEADER_LEN;
+ param_disp = (first_resp) ? 0 : n_param;
+
+ /*
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources if any before calling MBC_INIT().
+ */
+ m_freem(xa->rep_param_mb.chain);
+ MBC_INIT(&xa->rep_param_mb, param_scnt);
+ if (first_resp) {
+ first_resp = 0;
+ /* Prepare parameters for the 1st response packet */
+ ret_stat = (shares_tot_num > shr_enum_info.sei_count)
+ ? ERROR_MORE_DATA : 0;
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ ret_stat, -shr_enum_info.sei_infolen,
+ shr_enum_info.sei_count,
+ shares_tot_num);
+ }
+
+ data_pad = (param_off + n_param) & 1; /* Pad to short */
+
+ /* data off from hdr start */
+ data_off = param_off + param_scnt + data_pad;
+ data_disp = tot_data_scnt - data_scnt;
+ tot_packet_bytes = param_pad + param_scnt + data_pad +
+ data_scnt;
+
+ /*
+ * Calling MBC_INIT() will initialized the structure and so the
+ * pointer to the mbuf chains will be lost. Therefore, we need
+ * to free the resources if any before calling MBC_INIT().
+ */
+ m_freem(reply.chain);
+ MBC_INIT(&reply, SMB_HEADER_ED_LEN
+ + sizeof (uchar_t) /* word parameters count */
+ + 10*sizeof (ushort_t) /* word parameters */
+ + n_setup*sizeof (ushort_t) /* setup parameters */
+ + sizeof (ushort_t) /* total data byte count */
+ + tot_packet_bytes);
+
+ (void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ (void) smb_encode_mbc(&reply,
+ "b ww 2. www www b . C w #. C #. C",
+ 10 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ shares_tot_byte, /* Total Data Bytes */
+ param_scnt, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ param_disp, /* Param displacement */
+ data_scnt, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ data_disp, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ tot_packet_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ (void) smb_session_send(sr->session, 0, &reply);
+ }
+
+ (void) lmshrd_close_iterator(iterator);
+ MEM_FREE("smb", cmnt_start);
+ return (SDRC_NO_REPLY);
+}
+
+int
+smb_trans_net_share_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes, access;
+ uint32_t type;
+ unsigned char *req_fmt;
+ unsigned char *rep_fmt;
+ struct mbuf_chain str_mb;
+ char *share;
+ char *path;
+ char *password;
+ char *comment;
+ lmshare_info_t si;
+ int shr_found;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wsss(lev)w(size)w", sr,
+ &opcode, &req_fmt, &rep_fmt, &share, &level, &max_bytes) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ (void) utf8_strlwr(share);
+ shr_found = lmshrd_getinfo(share, &si);
+ if (strcmp(share, "ipc$") == 0) {
+ type = STYPE_IPC;
+ path = "";
+ password = "";
+ access = SHARE_ACCESS_ALL;
+ } else if (shr_found) {
+ path = si.directory;
+ type = STYPE_DISKTREE;
+ if (path[strlen(path)] == '$')
+ type |= STYPE_HIDDEN;
+ password = "";
+ access = SHARE_ACCESS_ALL;
+ } else {
+ /* We have no idea what this share is... */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www",
+ NERR_NetNameNotFound, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (shr_found)
+ comment = si.comment;
+ else
+ comment = "";
+
+ password = "";
+
+ MBC_INIT(&str_mb, max_bytes);
+
+ switch (level) {
+ case 0 :
+ (void) smb_emit_SHARE_INFO_0(&xa->rep_data_mb,
+ (unsigned char *)share);
+ break;
+
+ case 1 :
+ (void) smb_emit_SHARE_INFO_1(&xa->rep_data_mb, &str_mb,
+ (unsigned char *)share, type,
+ (unsigned char *)comment);
+ break;
+
+ case 2 :
+ smb_emit_SHARE_INFO_2(&xa->rep_data_mb, &str_mb, sr,
+ (unsigned char *)share, type, (unsigned char *)comment,
+ access, path, password);
+ default:
+ m_freem(str_mb.chain);
+ return (SDRC_UNSUPPORTED);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
+ -MBC_LENGTH(&xa->rep_data_mb),
+ MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
+ m_freem(str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_trans_net_workstation_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes;
+ unsigned char *req_fmt;
+ unsigned char *rep_fmt;
+ struct mbuf_chain str_mb;
+ char *domain;
+ char *hostname;
+
+ if ((smb_decode_mbc(&xa->req_param_mb, "%wss(lev)w(size)w", sr,
+ &opcode, &req_fmt, &rep_fmt, &level, &max_bytes) != 0) ||
+ (level != 10)) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ NERR_BadTransactConfig, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ domain = smb_info.si.skc_resource_domain;
+ hostname = smb_info.si.skc_hostname;
+
+ MBC_INIT(&str_mb, max_bytes);
+
+ (void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", hostname);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "nobody");
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", domain);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bbl",
+ SMB_VERSION_MAJOR, SMB_VERSION_MINOR, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", domain);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", domain);
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
+ -MBC_LENGTH(&xa->rep_data_mb),
+ MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
+ m_freem(str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_trans_net_user_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes;
+ unsigned char *req_fmt;
+ unsigned char *rep_fmt;
+ unsigned char *user;
+ int rc;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "%wssww", sr,
+ &opcode,
+ &req_fmt,
+ &rep_fmt,
+ &user,
+ &level,
+ &max_bytes);
+
+ if (rc != 0)
+ return (SDRC_UNSUPPORTED);
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www",
+ NERR_UserNotFound, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+int
+smb_trans_server_get_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, buf_size;
+ char *req_fmt;
+ char *rep_fmt;
+ char server_name[16];
+ struct mbuf_chain str_mb;
+ char *hostname;
+ char *comment;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wssww", sr,
+ &opcode, &req_fmt, &rep_fmt, &level, &buf_size) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ comment = smb_info.si.skc_system_comment;
+ hostname = smb_info.si.skc_hostname;
+
+ MBC_INIT(&str_mb, buf_size);
+
+ bzero(server_name, sizeof (server_name));
+ (void) strncpy(server_name, hostname, sizeof (server_name));
+
+ switch (level) {
+ case 0:
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16c", server_name);
+ break;
+ case 1:
+ (void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
+ SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
+ MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", comment);
+ break;
+ case 2:
+ /* B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWz */
+ (void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
+ /* B16BBDz */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
+ SMB_VERSION_MAJOR,
+ SMB_VERSION_MINOR, MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", comment);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "lllwwl",
+ (uint32_t)1,
+ (uint32_t)2,
+ (uint32_t)3,
+ (uint16_t)4,
+ (uint16_t)5,
+ MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "str1");
+ (void) smb_encode_mbc(&xa->rep_data_mb, "wwwwwww21cbl",
+ (uint16_t)6,
+ (uint16_t)7,
+ (uint16_t)8,
+ (uint16_t)9,
+ (uint16_t)10,
+ (uint16_t)11,
+ (uint16_t)12,
+ "21 byte comment ",
+ (unsigned char)13,
+ MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "str2");
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "wwwwwwwwwwwwwwwwwwwwwwl",
+ (uint16_t)14,
+ (uint16_t)15,
+ (uint16_t)16,
+ (uint16_t)17,
+ (uint16_t)18,
+ (uint16_t)19,
+ (uint16_t)20,
+ (uint16_t)21,
+ (uint16_t)22,
+ (uint16_t)23,
+ (uint16_t)24,
+ (uint16_t)25,
+ (uint16_t)26,
+ (uint16_t)27,
+ (uint16_t)28,
+ (uint16_t)29,
+ (uint16_t)20,
+ (uint16_t)31,
+ (uint16_t)32,
+ (uint16_t)33,
+ (uint16_t)34,
+ (uint16_t)35,
+ MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", "str3");
+ break;
+ default:
+ m_freem(str_mb.chain);
+ return (SDRC_UNSUPPORTED);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
+ -MBC_LENGTH(&xa->rep_data_mb),
+ (MBC_LENGTH(&xa->rep_data_mb)) +
+ (MBC_LENGTH(&str_mb)));
+ (void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
+ m_freem(str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * 6.4 The NetServerEnum2 RAP Service
+ *
+ * The NetServerEnum2 RAP service lists all computers of the specified type
+ * or types that are visible in the specified domains. It may also
+ * enumerate domains.
+ *
+ * The following definition uses the notation and terminology defined in
+ * the CIFS Remote Administration Protocol specification, which is required
+ * in order to make it well-defined. The definition is:
+ *
+ * uint16_t NetServerEnum2 (
+ * uint16_t sLevel,
+ * RCVBUF pbBuffer,
+ * RCVBUFLEN cbBuffer,
+ * ENTCOUNT pcEntriesRead,
+ * uint16_t *pcTotalAvail,
+ * uint32_t fServerType,
+ * char *pszDomain,
+ * );
+ *
+ * where:
+ *
+ * sLevel specifies the level of detail (0 or 1) requested.
+ *
+ * pbBuffer points to the buffer to receive the returned data. If the
+ * function is successful, the buffer contains a sequence of
+ * server_info_x structures, where x is 0 or 1, depending on the
+ * level of detail requested.
+ *
+ * cbBuffer specifies the size, in bytes, of the buffer pointed to by
+ * the pbBuffer parameter.
+ *
+ * pcEntriesRead points to a 16 bit variable that receives a count of
+ * the number of servers enumerated in the buffer. This count is
+ * valid only if NetServerEnum2 returns the NERR_Success or
+ * ERROR_MORE_DATA values.
+ *
+ * pcTotal Avail points to a 16 bit variable that receives a count of
+ * the total number of available entries. This count is valid only if
+ * NetServerEnum2 returns the NERR_Success or ERROR_MORE_DATA values.
+ *
+ * fServerType specifies the type or types of computers to enumerate.
+ * Computers that match at least one of the specified types are
+ * returned in the buffer. Possible values are defined in the request
+ * parameters section.
+ *
+ * pszDomain points to a null-terminated string that contains the
+ * name of the workgroup in which to enumerate computers of the
+ * specified type or types. If the pszDomain parameter is a null
+ * string or a null pointer, servers are enumerated for the current
+ * domain of the computer.
+ *
+ * 6.4.1 Transaction Request Parameters section
+ *
+ * The Transaction request parameters section in this instance contains:
+ * . The 16 bit function number for NetServerEnum2 which is 104.
+ * . The parameter descriptor string which is "WrLehDz".
+ * . The data descriptor string for the (returned) data which is "B16" for
+ * level detail 0 or "B16BBDz" for level detail 1.
+ * . The actual parameters as described by the parameter descriptor
+ * string.
+ *
+ * The parameters are:
+ * . A 16 bit integer with a value of 0 or 1 (corresponding to the "W" in
+ * the parameter descriptor string. This represents the level of detail
+ * the server is expected to return
+ * . A 16 bit integer that contains the size of the receive buffer.
+ * . A 32 bit integer that represents the type of servers the function
+ * should enumerate. The possible values may be any of the following or
+ * a combination of the following:
+ *
+ * SV_TYPE_WORKSTATION 0x00000001 All workstations
+ * SV_TYPE_SERVER 0x00000002 All servers
+ * SV_TYPE_SQLSERVER 0x00000004 Any server running with SQL
+ * server
+ * SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
+ * SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
+ * SV_TYPE_TIME_SOURCE 0x00000020 Server running the timesource
+ * service
+ * SV_TYPE_AFP 0x00000040 Apple File Protocol servers
+ * SV_TYPE_NOVELL 0x00000080 Novell servers
+ * SV_TYPE_DOMAIN_MEMBER 0x00000100 Domain Member
+ * SV_TYPE_PRINTQ_SERVER 0x00000200 Server sharing print queue
+ * SV_TYPE_DIALIN_SERVER 0x00000400 Server running dialin service.
+ * SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
+ * SV_TYPE_NT 0x00001000 NT server
+ * SV_TYPE_WFW 0x00002000 Server running Windows for
+ * Workgroups
+ * SV_TYPE_SERVER_NT 0x00008000 Windows NT non DC server
+ * SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the browser
+ * service
+ * SV_TYPE_BACKUP_BROWSER 0x00020000 Backup browser server
+ * SV_TYPE_MASTER_BROWSER 0x00040000 Master browser server
+ * SV_TYPE_DOMAIN_MASTER 0x00080000 Domain Master Browser server
+ * SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Enumerate only entries marked
+ * "local"
+ * SV_TYPE_DOMAIN_ENUM 0x80000000 Enumerate Domains. The pszDomain
+ * parameter must be NULL.
+ *
+ * . A null terminated ASCII string representing the pszDomain parameter
+ * described above
+ *
+ * 6.4.2 Transaction Request Data section
+ *
+ * There is no data or auxiliary data to send as part of the request.
+ *
+ * 6.4.3 Transaction Response Parameters section
+ *
+ * The transaction response parameters section consists of:
+ * . A 16 bit word indicating the return status. The possible values are:
+ *
+ * Code Value Description
+ * NERR_Success 0 No errors encountered
+ * ERROR_MORE_DATA 234 Additional data is available
+ * NERR_ServerNotStarted 2114 The RAP service on the remote computer
+ * is not running
+ * NERR_BadTransactConfig 2141 The server is not configured for
+ * transactions, IPC$ is not shared
+ *
+ * . A 16 bit "converter" word.
+ * . A 16 bit number representing the number of entries returned.
+ * . A 16 bit number representing the total number of available entries.
+ * If the supplied buffer is large enough, this will equal the number of
+ * entries returned.
+ *
+ * 6.4.4 Transaction Response Data section
+ *
+ * The return data section consists of a number of SERVER_INFO_1 structures.
+ * The number of such structures present is determined by the third entry
+ * (described above) in the return parameters section.
+ *
+ * At level detail 0, the Transaction response data section contains a
+ * number of SERVER_INFO_0 data structure. The number of such structures is
+ * equal to the 16 bit number returned by the server in the third parameter
+ * in the Transaction response parameter section. The SERVER_INFO_0 data
+ * structure is defined as:
+ *
+ * struct SERVER_INFO_0 {
+ * char sv0_name[16];
+ * };
+ *
+ * where:
+ *
+ * sv0_name is a null-terminated string that specifies the name of a
+ * computer or domain .
+ *
+ * At level detail 1, the Transaction response data section contains a
+ * number of SERVER_INFO_1 data structure. The number of such structures is
+ * equal to the 16 bit number returned by the server in the third parameter
+ * in the Transaction response parameter section. The SERVER_INFO_1 data
+ * structure is defined as:
+ *
+ * struct SERVER_INFO_1 {
+ * char sv1_name[16];
+ * char sv1_version_major;
+ * char sv1_version_minor;
+ * uint32_t sv1_type;
+ * char *sv1_comment_or_master_browser;
+ * };
+ *
+ * sv1_name contains a null-terminated string that specifies the name
+ * of a computer, or a domain name if SV_TYPE_DOMAIN_ENUM is set in
+ * sv1_type.
+ *
+ * sv1_version_major whatever was specified in the HostAnnouncement
+ * or DomainAnnouncement frame with which the entry was registered.
+ *
+ * sv1_version_minor whatever was specified in the HostAnnouncement
+ * or DomainAnnouncement frame with which the entry was registered.
+ *
+ * sv1_type specifies the type of software the computer is running.
+ * The member can be one or a combination of the values defined above
+ * in the Transaction request parameters section for fServerType.
+ *
+ *
+ * sv1_comment_or_master_browser points to a null-terminated string. If
+ * the sv1_type indicates that the entry is for a domain, this
+ * specifies the name of server running the domain master browser;
+ * otherwise, it specifies a comment describing the server. The comment
+ * can be a null string or the pointer may be a null pointer.
+ *
+ * In case there are multiple SERVER_INFO_1 data structures to
+ * return, the server may put all these fixed length structures in
+ * the return buffer, leave some space and then put all the variable
+ * length data (the actual value of the sv1_comment strings) at the
+ * end of the buffer.
+ *
+ * There is no auxiliary data to receive.
+ */
+
+int
+smb_trans_net_server_enum2(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t opcode, level, max_bytes;
+ uint32_t server_type;
+ unsigned char *domain;
+ struct mbuf_chain str_mb;
+ char *hostname, *s;
+ smb_kmod_cfg_t *si;
+
+ if (smb_decode_mbc(&xa->req_param_mb,
+ "%w s(request format) s(reply format) wwls", sr, &opcode, &s, &s,
+ &level, &max_bytes, &server_type, &domain) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ si = &smb_info.si;
+
+ if (utf8_strcasecmp(si->skc_resource_domain, (char *)domain) != 0) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if ((server_type & MY_SERVER_TYPE) == 0) {
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ MBC_INIT(&str_mb, max_bytes);
+
+ hostname = si->skc_hostname;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "16c", hostname);
+ if (level == 1) {
+ (void) smb_encode_mbc(&xa->rep_data_mb, "bbll",
+ SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
+ MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
+ (void) smb_encode_mbc(&str_mb, "s", si->skc_system_comment);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0,
+ -MBC_LENGTH(&xa->rep_data_mb), 1, 1);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "m", str_mb.chain);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * is_supported_pipe
+ *
+ * Currently, just return 0 if the pipe is \\PIPE\repl otherwise
+ * return 1.
+ */
+int
+is_supported_pipe(char *pname)
+{
+ if (utf8_strcasecmp(pname, PIPE_REPL) == 0)
+ return (0);
+
+ return (1);
+}
+
+int
+smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc, pos;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ uint16_t opcode;
+ uint16_t devstate;
+ char *req_fmt;
+ char *rep_fmt;
+ struct vardata_block vdb;
+
+ n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
+ n_setup++;
+ n_setup = n_setup & ~0x0001;
+ n_param = (xa->smb_mprcnt < smb_maxbufsize)
+ ? xa->smb_mprcnt : smb_maxbufsize;
+ n_param++;
+ n_param = n_param & ~0x0001;
+ rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
+ n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+ MBC_INIT(&xa->rep_param_mb, n_param);
+ MBC_INIT(&xa->rep_data_mb, n_data);
+
+ if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) {
+ rc = smb_decode_mbc(&xa->req_setup_mb, "ww", &opcode,
+ &sr->smb_fid);
+ if (rc != 0)
+ goto trans_err_not_supported;
+ switch (opcode) {
+ case TRANS_SET_NMPIPE_STATE:
+ if ((rc = smb_decode_mbc(&xa->req_param_mb, "w",
+ &devstate)) != 0)
+ goto trans_err_not_supported;
+
+ rc = SDRC_NORMAL_REPLY;
+ break;
+
+ case TRANS_TRANSACT_NMPIPE:
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_decode_mbc(&xa->req_data_mb, "#B",
+ xa->smb_tdscnt, &vdb);
+ if (rc != 0)
+ goto trans_err_not_supported;
+
+ rc = smb_rpc_transact(sr, &vdb.uio);
+ break;
+
+ case TRANS_WAIT_NMPIPE:
+ if (is_supported_pipe(xa->xa_smb_trans_name) == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOT REACHED */
+ }
+ rc = SDRC_NORMAL_REPLY;
+ break;
+
+ default:
+ goto trans_err_not_supported;
+ }
+ } else {
+ if ((utf8_strcasecmp(xa->xa_smb_trans_name,
+ PIPE_LANMAN) != 0) &&
+ (utf8_strcasecmp(
+ xa->xa_smb_trans_name, MAILSLOT_LANMAN) != 0) &&
+ (utf8_strcasecmp(
+ xa->xa_smb_trans_name, MAILSLOT_BROWSE) != 0) &&
+ (utf8_strcasecmp(
+ xa->xa_smb_trans_name, MAILSLOT_MSBROWSE) != 0))
+ goto trans_err_not_supported;
+
+ if ((rc = smb_decode_mbc(&xa->req_param_mb, "%wss\b", sr,
+ &opcode, &req_fmt, &rep_fmt)) != 0)
+ goto trans_err_not_supported;
+
+ /* for now, only respond to the */
+ switch (opcode) {
+ case API_WshareEnum:
+ rc = smb_trans_net_share_enum(sr, xa);
+ break;
+
+ case API_WshareGetInfo:
+ rc = smb_trans_net_share_get_info(sr, xa);
+ break;
+
+ case API_WserverGetInfo:
+ rc = smb_trans_server_get_info(sr, xa);
+ break;
+
+ case API_WUserGetInfo:
+ rc = smb_trans_net_user_get_info(sr, xa);
+ break;
+
+ case API_WWkstaGetInfo:
+ rc = smb_trans_net_workstation_get_info(sr, xa);
+ break;
+
+ case API_NetServerEnum2:
+ rc = smb_trans_net_server_enum2(sr, xa);
+ break;
+
+ default:
+ goto trans_err_not_supported;
+ }
+ }
+
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_DROP_VC:
+ case SDRC_NO_REPLY:
+ case SDRC_ERROR_REPLY:
+ return (rc);
+
+ case SDRC_UNIMPLEMENTED:
+ case SDRC_UNSUPPORTED:
+ goto trans_err_not_supported;
+
+ default:
+ break;
+ }
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ if (xa->smb_msrcnt < n_setup ||
+ xa->smb_mprcnt < n_param ||
+ xa->smb_mdrcnt < n_data) {
+ goto trans_err_too_small;
+ }
+
+ /* neato, blast it over there */
+
+ n_setup = (n_setup + 1) / 2; /* Convert to setup words */
+ param_pad = 1; /* always one */
+ param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
+ data_pad = (param_off + n_param) & 1; /* Pad to short */
+ /* Param off from hdr start */
+ data_off = param_off + n_param + data_pad;
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 10+n_setup, total_bytes,
+ "b ww 2. www www b . C w #. C #. C",
+ 10 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+ return (SDRC_NORMAL_REPLY);
+
+trans_err_too_small:
+ rc = NERR_BufTooSmall;
+ goto trans_err;
+
+trans_err_not_supported:
+ rc = ERROR_NOT_SUPPORTED;
+ goto trans_err;
+
+trans_err:
+ pos = MBC_LENGTH(&sr->reply) + 23;
+ smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
+ 10, /* wct */
+ 4, 0, /* tpscnt tdscnt */
+ 4, pos, 0, /* pscnt psoff psdisp */
+ 0, 0, 0, /* dscnt dsoff dsdisp */
+ 0, /* suwcnt */
+ 4, /* bcc */
+ rc,
+ 0); /* converter word? */
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc, pos;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ uint16_t opcode;
+ uint16_t nt_unknown_secret = 0x0100;
+ char *fmt;
+
+ n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
+ n_setup++;
+ n_setup = n_setup & ~0x0001;
+ n_param = (xa->smb_mprcnt < smb_maxbufsize)
+ ? xa->smb_mprcnt : smb_maxbufsize;
+ n_param++;
+ n_param = n_param & ~0x0001;
+ rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
+ n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
+ MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
+ MBC_INIT(&xa->rep_param_mb, n_param);
+ MBC_INIT(&xa->rep_data_mb, n_data);
+
+ if (smb_decode_mbc(&xa->req_setup_mb, "w", &opcode) != 0)
+ goto trans_err_not_supported;
+
+ /*
+ * Save this for /proc to read later.
+ */
+ xa->smb_func = opcode;
+
+ /* for now, only respond to the */
+ switch (opcode) {
+ case TRANS2_CREATE_DIRECTORY:
+ rc = smb_com_trans2_create_directory(sr, xa);
+ break;
+
+ case TRANS2_FIND_FIRST2:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_find_first2(sr, xa);
+ break;
+
+ case TRANS2_FIND_NEXT2:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_find_next2(sr, xa);
+ break;
+
+ case TRANS2_QUERY_FS_INFORMATION:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_query_fs_information(sr, xa);
+ break;
+
+ case TRANS2_QUERY_PATH_INFORMATION:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_query_path_information(sr, xa);
+ break;
+
+ case TRANS2_QUERY_FILE_INFORMATION:
+ /*
+ * Should have enough room to send the response
+ * data back to client.
+ */
+ if (n_data == 0) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INFO_LENGTH_MISMATCH,
+ ERRDOS, ERROR_BAD_LENGTH);
+ /* NOT REACHED */
+ }
+ rc = smb_com_trans2_query_file_information(sr, xa);
+ break;
+
+ case TRANS2_SET_PATH_INFORMATION:
+ rc = smb_com_trans2_set_path_information(sr, xa);
+ break;
+
+ case TRANS2_SET_FILE_INFORMATION:
+ rc = smb_com_trans2_set_file_information(sr, xa);
+ break;
+ default:
+ goto trans_err_not_supported;
+ }
+
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_DROP_VC:
+ case SDRC_NO_REPLY:
+ case SDRC_ERROR_REPLY:
+ return (rc);
+
+ case SDRC_UNIMPLEMENTED:
+ case SDRC_UNSUPPORTED:
+ goto trans_err_not_supported;
+
+ default:
+ break;
+ }
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ if (xa->smb_msrcnt < n_setup ||
+ xa->smb_mprcnt < n_param ||
+ xa->smb_mdrcnt < n_data) {
+ goto trans_err_too_small;
+ }
+
+ /* neato, blast it over there */
+
+ n_setup = (n_setup + 1) / 2; /* Conver to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
+
+ /*
+ * Including the nt_unknown_secret value persuades netmon to
+ * display the correct data format for QueryPathInfo and
+ * QueryFileInfo.
+ */
+ if (opcode == TRANS2_QUERY_FILE_INFORMATION ||
+ opcode == TRANS2_QUERY_PATH_INFORMATION) {
+ data_pad = sizeof (uint16_t);
+ data_off = param_off + n_param + data_pad;
+ fmt = "b ww 2. www www b . C w #. C w C";
+ nt_unknown_secret = 0x0100;
+ }
+ else
+ {
+ data_pad = (param_off + n_param) & 1; /* Pad to short */
+ /* Param off from hdr start */
+ data_off = param_off + n_param + data_pad;
+ fmt = "b ww 2. www www b . C w #. C #. C";
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ nt_unknown_secret = data_pad;
+ }
+
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 10+n_setup, total_bytes,
+ fmt,
+ 10 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data /* + data_pad */, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data /* + data_pad */, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ nt_unknown_secret,
+ &xa->rep_data_mb);
+ return (SDRC_NORMAL_REPLY);
+
+trans_err_too_small:
+ rc = NERR_BufTooSmall;
+ goto trans_err;
+
+trans_err_not_supported:
+ rc = ERROR_NOT_SUPPORTED;
+ goto trans_err;
+
+trans_err:
+ pos = MBC_LENGTH(&sr->reply) + 23;
+ smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
+ 10, /* wct */
+ 4, 0, /* tpscnt tdscnt */
+ 4, pos, 0, /* pscnt psoff psdisp */
+ 0, 0, 0, /* dscnt dsoff dsdisp */
+ 0, /* suwcnt */
+ 4, /* bcc */
+ rc,
+ 0); /* converter word? */
+ return (SDRC_NORMAL_REPLY);
+}
+
+smb_xa_t *
+smb_xa_create(
+ smb_session_t *session,
+ smb_request_t *sr,
+ uint32_t total_parameter_count,
+ uint32_t total_data_count,
+ uint32_t max_parameter_count,
+ uint32_t max_data_count,
+ uint32_t max_setup_count,
+ uint32_t setup_word_count)
+{
+ smb_xa_t *xa, *nxa;
+ smb_llist_t *xlist;
+
+ xa = MEM_ZALLOC("xa", sizeof (smb_xa_t));
+ xa->xa_refcnt = 1;
+ xa->smb_com = sr->smb_com;
+ xa->smb_flg = sr->smb_flg;
+ xa->smb_flg2 = sr->smb_flg2;
+ xa->smb_tid = sr->smb_tid;
+ xa->smb_pid = sr->smb_pid;
+ xa->smb_uid = sr->smb_uid;
+ xa->xa_smb_mid = sr->smb_mid;
+ xa->reply_seqnum = sr->reply_seqnum;
+ xa->smb_tpscnt = total_parameter_count;
+ xa->smb_tdscnt = total_data_count;
+ xa->smb_mprcnt = max_parameter_count;
+ xa->smb_mdrcnt = max_data_count;
+ xa->smb_msrcnt = max_setup_count;
+ xa->smb_suwcnt = setup_word_count;
+ xa->xa_session = session;
+ xa->xa_magic = SMB_XA_MAGIC;
+
+ /*
+ * The new xa structure is checked against the current list to see
+ * if it exists already.
+ */
+ xlist = &session->s_xa_list;
+ smb_llist_enter(xlist, RW_WRITER);
+ nxa = smb_llist_head(xlist);
+ while (nxa) {
+ ASSERT(nxa->xa_magic == SMB_XA_MAGIC);
+ if (nxa->xa_smb_mid == xa->xa_smb_mid &&
+ nxa->smb_pid == xa->smb_pid &&
+ !SMB_XA_CLOSED(nxa) &&
+ !(nxa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
+ smb_llist_exit(xlist);
+ MEM_FREE("xa", xa);
+ return (NULL);
+ }
+ nxa = smb_llist_next(xlist, nxa);
+ }
+ smb_llist_insert_tail(xlist, xa);
+ smb_llist_exit(xlist);
+ return (xa);
+}
+
+void
+smb_xa_delete(smb_xa_t *xa)
+{
+ ASSERT(xa->xa_refcnt == 0);
+ ASSERT(SMB_XA_CLOSED(xa));
+
+ if (xa->xa_smb_trans_name)
+ MEM_FREE("smb", xa->xa_smb_trans_name);
+
+ if (xa->rep_setup_mb.chain != NULL)
+ m_freem(xa->rep_setup_mb.chain);
+ if (xa->rep_param_mb.chain != NULL)
+ m_freem(xa->rep_param_mb.chain);
+ if (xa->rep_data_mb.chain != NULL)
+ m_freem(xa->rep_data_mb.chain);
+
+ xa->xa_magic = (uint32_t)~SMB_XA_MAGIC;
+ MEM_FREE("xa", xa);
+}
+
+smb_xa_t *
+smb_xa_hold(smb_xa_t *xa)
+{
+ mutex_enter(&xa->xa_mutex);
+ xa->xa_refcnt++;
+ ASSERT(xa->xa_refcnt);
+ mutex_exit(&xa->xa_mutex);
+ return (xa);
+}
+
+void
+smb_xa_rele(smb_session_t *session, smb_xa_t *xa)
+{
+ mutex_enter(&xa->xa_mutex);
+ ASSERT(xa->xa_refcnt);
+ xa->xa_refcnt--;
+ if (SMB_XA_CLOSED(xa) && (xa->xa_refcnt == 0)) {
+ mutex_exit(&xa->xa_mutex);
+ smb_llist_enter(&session->s_xa_list, RW_WRITER);
+ smb_llist_remove(&session->s_xa_list, xa);
+ smb_llist_exit(&session->s_xa_list);
+ smb_xa_delete(xa);
+ return;
+ }
+ mutex_exit(&xa->xa_mutex);
+}
+
+int
+smb_xa_open(smb_xa_t *xa)
+{
+ int rc;
+
+ mutex_enter(&xa->xa_mutex);
+
+ ASSERT((xa->xa_flags & SMB_XA_FLAG_OPEN) == 0);
+
+ if ((xa->xa_flags & SMB_XA_FLAG_CLOSE) == 0) {
+ xa->xa_flags |= SMB_XA_FLAG_OPEN;
+ rc = 0;
+ } else {
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ mutex_exit(&xa->xa_mutex);
+
+ return (rc);
+}
+
+void
+smb_xa_close(smb_xa_t *xa)
+{
+ mutex_enter(&xa->xa_mutex);
+ xa->xa_flags |= SMB_XA_FLAG_CLOSE;
+ xa->xa_flags &= ~SMB_XA_FLAG_OPEN;
+
+ if (xa->xa_refcnt == 0) {
+ mutex_exit(&xa->xa_mutex);
+ smb_llist_enter(&xa->xa_session->s_xa_list, RW_WRITER);
+ smb_llist_remove(&xa->xa_session->s_xa_list, xa);
+ smb_llist_exit(&xa->xa_session->s_xa_list);
+ smb_xa_delete(xa);
+ return;
+ }
+
+ mutex_exit(&xa->xa_mutex);
+}
+
+int
+smb_xa_complete(smb_xa_t *xa)
+{
+ int rc;
+
+ mutex_enter(&xa->xa_mutex);
+ if (xa->xa_flags & (SMB_XA_FLAG_COMPLETE | SMB_XA_FLAG_CLOSE)) {
+ rc = 0;
+ } else {
+ rc = 1;
+ xa->xa_flags |= SMB_XA_FLAG_COMPLETE;
+ }
+ mutex_exit(&xa->xa_mutex);
+ return (rc);
+}
+
+smb_xa_t *
+smb_xa_find(
+ smb_session_t *session,
+ uint16_t pid,
+ uint16_t mid)
+{
+ smb_xa_t *xa;
+ smb_llist_t *xlist;
+
+ xlist = &session->s_xa_list;
+ smb_llist_enter(xlist, RW_READER);
+ xa = smb_llist_head(xlist);
+ while (xa) {
+ mutex_enter(&xa->xa_mutex);
+ if (xa->xa_smb_mid == mid &&
+ xa->smb_pid == pid &&
+ !SMB_XA_CLOSED(xa) &&
+ !(xa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
+ xa->xa_refcnt++;
+ ASSERT(xa->xa_refcnt);
+ mutex_exit(&xa->xa_mutex);
+ break;
+ }
+ mutex_exit(&xa->xa_mutex);
+ xa = smb_llist_next(xlist, xa);
+ }
+ smb_llist_exit(xlist);
+ return (xa);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_tree.c b/usr/src/uts/common/fs/smbsrv/smb_common_tree.c
new file mode 100644
index 0000000000..7906233a35
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_tree.c
@@ -0,0 +1,397 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Common code for tree connections.
+ */
+
+#include <sys/errno.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_door_svc.h>
+
+
+#define SMB_TREE_EMSZ 64
+
+#define ADMINISTRATORS_SID "S-1-5-32-544"
+
+int smb_tcon_mute = 0;
+
+
+int smbsr_setup_share(struct smb_request *, char *, int32_t, char *);
+void smbsr_share_report(struct smb_request *, char *, char *, char *);
+int smb_get_stype(const char *, const char *, int32_t *);
+
+
+/*
+ * smbsr_connect_tree
+ *
+ * Set up a share. A Uniform Naming Convention (UNC) string is suppose to
+ * be in the form: \\HOST\SHARENAME. A sharename alone is also acceptable.
+ * We don't actually audit the host, we just ensure that the \ are present
+ * and extract the share name. Share names are case insensitive so we map
+ * the share name to lower-case. So it is important that all internal
+ * mechanisms (user interface, etc. use lower-case names.
+ */
+int
+smbsr_connect_tree(struct smb_request *sr)
+{
+ char errmsg[SMB_TREE_EMSZ];
+ char *sharename;
+ char *access_msg;
+ int32_t stype;
+ int rc;
+
+ errmsg[0] = '\0';
+ (void) utf8_strlwr(sr->arg.tcon.path);
+ sharename = sr->arg.tcon.path;
+
+ if (sharename[0] == '\\') {
+ /*
+ * Looks like a UNC path, make sure the format is correct.
+ */
+ if (sharename[1] != '\\') {
+ smbsr_raise_error(sr, ERRSRV, ERRinvnetname);
+ /* NOTREACHED */
+ }
+
+ if ((sharename = strchr(sharename+2, '\\')) == 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRinvnetname);
+ /* NOTREACHED */
+ }
+
+ ++sharename;
+ } else if (strchr(sharename, '\\')) {
+ /*
+ * This should be a sharename: no embedded '\' allowed.
+ */
+ smbsr_raise_error(sr, ERRSRV, ERRinvnetname);
+ /* NOTREACHED */
+ }
+
+ if (smb_get_stype(sharename, sr->arg.tcon.service, &stype) != 0) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
+ ERRDOS, ERROR_BAD_DEV_TYPE);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smbsr_setup_share(sr, sharename, stype, errmsg)) != 0) {
+ access_msg = "access denied";
+ smbsr_share_report(sr, sharename, access_msg, errmsg);
+
+ /*
+ * W2K sometimes tries to connect to user shares using an
+ * anonymous IPC connection. NT returns access denied.
+ */
+ if (rc == ERRaccess)
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRSRV, ERRaccess);
+ else
+ smbsr_raise_error(sr, ERRSRV, rc);
+ /* NOTREACHED */
+ }
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ access_msg = "ro access granted";
+ else
+ access_msg = "rw access granted";
+
+ smbsr_share_report(sr, sharename, access_msg, errmsg);
+ }
+
+ return (rc);
+}
+
+
+/*
+ * smbsr_share_report
+ *
+ * Report share access result to syslog.
+ */
+/*ARGSUSED*/
+void
+smbsr_share_report(struct smb_request *sr, char *sharename,
+ char *access_msg, char *errmsg)
+{
+ smb_user_t *user;
+
+ user = sr->uid_user;
+ ASSERT(user);
+
+ if (smb_tcon_mute)
+ return;
+
+ if (user->u_name) {
+ /*
+ * Only report normal users, i.e. ignore W2K misuse
+ * of the IPC connection by filtering out internal
+ * names such as nobody and root.
+ */
+ if ((strcmp(user->u_name, "root") == 0) ||
+ (strcmp(user->u_name, "nobody") == 0)) {
+ return;
+ }
+ }
+
+ cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
+ user->u_domain, user->u_name, sharename, access_msg);
+}
+
+/*
+ * smbsr_setup_share
+ *
+ * This is where the real of setting up share is done. The main thing
+ * to note is that we resolve ambiguities by assuming that a directory is
+ * being requested. This function returns error codes, rather than calling
+ * smbsr_raise_error. We return 0 on success or a non-zero error code if
+ * there is a problem.
+ */
+int
+smbsr_setup_share(struct smb_request *sr, char *sharename, int32_t stype,
+ char *errmsg)
+{
+ smb_node_t *dir_snode = NULL;
+ smb_node_t *snode = NULL;
+ char last_component[MAXNAMELEN];
+ smb_tree_t *tree;
+ char *resource;
+ uint16_t access = SMB_TREE_READ_WRITE;
+ int rc;
+ lmshare_info_t si;
+ nt_sid_t *sid;
+ fsvol_attr_t vol_attr;
+ smb_attr_t attr;
+ int is_admin;
+ smb_user_t *user = sr->uid_user;
+ cred_t *u_cred;
+
+ ASSERT(user);
+ u_cred = user->u_cred;
+ ASSERT(u_cred);
+
+ bzero(&si, sizeof (lmshare_info_t));
+
+ /*
+ * XXX Host based access control check to go here.
+ */
+
+ if (STYPE_ISIPC(stype)) {
+ if ((user->u_flags & SMB_USER_FLAG_IPC) &&
+ smb_info.si.skc_restrict_anon) {
+ (void) strlcpy(errmsg, "anonymous access restricted",
+ SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+
+ bzero(&vol_attr, sizeof (fsvol_attr_t));
+ resource = sharename;
+ sr->arg.tcon.service = "IPC";
+
+ tree = smb_tree_connect(sr->uid_user, access,
+ sharename, resource, stype, 0, &vol_attr);
+
+ if (tree == NULL)
+ return (ERRaccess);
+
+ sr->smb_tid = tree->t_tid;
+ sr->tid_tree = tree;
+ return (0);
+ }
+
+ /*
+ * From here on we can assume that this is a disk share.
+ */
+ ASSERT(STYPE_ISDSK(stype));
+
+ if (user->u_flags & SMB_USER_FLAG_IPC) {
+ (void) strlcpy(errmsg, "IPC only", SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+
+ /*
+ * Handle the default administration shares: C$, D$ etc.
+ * Only a user with admin rights is allowed to map these
+ * shares.
+ */
+ if ((is_admin = lmshrd_is_admin(sharename)) == NERR_InternalError) {
+ (void) strlcpy(errmsg, "internal error", SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+
+ if (is_admin) {
+ sid = nt_sid_strtosid(ADMINISTRATORS_SID);
+ if (sid) {
+ rc = smb_cred_is_member(u_cred, sid);
+ MEM_FREE("smbsrv", sid);
+ if (rc == 0) {
+ (void) strlcpy(errmsg,
+ "not administrator", SMB_TREE_EMSZ);
+ return (ERRaccess);
+ }
+ }
+ }
+
+ if (lmshrd_getinfo(sharename, &si) != NERR_Success) {
+ (void) strlcpy(errmsg, "share not found", SMB_TREE_EMSZ);
+ return (ERRinvnetname);
+ }
+
+ resource = si.directory;
+ sr->arg.tcon.service = "A:";
+
+#ifdef HOST_ACCESS
+ /*
+ * XXX This needs some sharemgr work
+ */
+ if (hostaccess == APRV_ACC_RO)
+ access = SMB_TREE_READ_ONLY;
+#endif /* HOST_ACCESS */
+
+ /*
+ * No password or password OK. Now check that the directory
+ * actually exists.
+ *
+ * The snode reference from smb_pathname_reduce() will not be
+ * released in this routine (except in an error path) because
+ * trees need a reference to their root node. The reference
+ * will be released upon tree deallocation.
+ */
+
+ rc = smb_pathname_reduce(sr, u_cred, resource, 0, 0, &dir_snode,
+ last_component);
+
+ if (rc) {
+ (void) strlcpy(errmsg, "smb_pathname_reduce", SMB_TREE_EMSZ);
+ return (ERRinvnetname);
+ }
+
+ rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS, 0, dir_snode,
+ last_component, &snode, &attr, 0, 0);
+
+ smb_node_release(dir_snode);
+
+ if (rc) {
+ (void) strlcpy(errmsg, "smb_fsop_lookup", SMB_TREE_EMSZ);
+ rc = ERRinvnetname;
+ goto error_out;
+ }
+
+ if ((rc = fsd_getattr(&snode->tree_fsd, &vol_attr)) != 0) {
+ (void) strlcpy(errmsg, "fsd_getattr", SMB_TREE_EMSZ);
+ rc = ERRinvnetname;
+ goto error_out;
+ }
+
+ tree = smb_tree_connect(sr->uid_user, access,
+ sharename, resource, stype, snode, &vol_attr);
+
+ if (tree == NULL) {
+ rc = ERRaccess;
+ goto error_out;
+ }
+
+ sr->smb_tid = tree->t_tid;
+ sr->tid_tree = tree;
+ return (0);
+
+error_out:
+ if (snode)
+ smb_node_release(snode);
+
+ return (rc);
+}
+
+/*
+ * smb_get_stype
+ *
+ * Map the service to a resource type. Valid values for service
+ * (CIFS/1.0 section 4.1.4) are:
+ *
+ * A: Disk share
+ * LPT1: Printer
+ * IPC Named pipe
+ * COMM Communications device
+ * ????? Any type of device (wildcard)
+ *
+ * We support IPC and disk shares; anything else is currently treated
+ * as an error. IPC$ is reserved as the named pipe share.
+ */
+int
+smb_get_stype(const char *sharename, const char *service, int32_t *stype_ret)
+{
+ const char *any = "?????";
+
+ if ((strcmp(service, any) == 0) || (strcasecmp(service, "IPC") == 0)) {
+ if (strcasecmp(sharename, "IPC$") == 0) {
+ *stype_ret = STYPE_IPC;
+ return (0);
+ }
+ }
+
+ if ((strcmp(service, any) == 0) || (strcasecmp(service, "A:") == 0)) {
+ if (strcasecmp(sharename, "IPC$") == 0)
+ return (-1);
+
+ *stype_ret = STYPE_DISKTREE;
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * smbsr_rq_notify
+ *
+ * Notify all requests, except sr, associated with the specified tree
+ * that it's time to complete.
+ * It's assumed that the tree has already been clipped from the session
+ * list so that no new requests can be added to the list while we're in
+ * here.
+ *
+ * Note that sr may be null.
+ *
+ * Returns:
+ */
+void
+smbsr_rq_notify(smb_request_t *sr, smb_session_t *session, smb_tree_t *tree)
+{
+ struct smb_request *asr;
+
+ smb_slist_enter(&session->s_req_list);
+ asr = smb_slist_head(&session->s_req_list);
+ while (asr) {
+ ASSERT(asr->sr_magic == SMB_REQ_MAGIC);
+ if ((asr != sr) && (asr->tid_tree == tree)) {
+ smb_request_cancel(asr);
+ }
+ asr = smb_slist_next(&session->s_req_list, asr);
+ }
+ smb_slist_exit(&session->s_req_list);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_copy.c b/usr/src/uts/common/fs/smbsrv/smb_copy.c
new file mode 100644
index 0000000000..4b33818eab
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_copy.c
@@ -0,0 +1,121 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: copy_file
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * USHORT Tid2; Second (target) path TID
+ * USHORT OpenFunction; What to do if target file exists
+ * USHORT Flags; Flags to control copy operation:
+ * bit 0 - target must be a file
+ * bit 1 - target must be a dir.
+ * bit 2 - copy target mode:
+ * 0 = binary, 1 = ASCII
+ * bit 3 - copy source mode:
+ * 0 = binary, 1 = ASCII
+ * bit 4 - verify all writes
+ * bit 5 - tree copy
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR SourceFileNameFormat; 0x04
+ * STRING SourceFileName; Pathname of source file
+ * UCHAR TargetFileNameFormat; 0x04
+ * STRING TargetFileName; Pathname of target file
+ *
+ * The file at SourceName is copied to TargetFileName, both of which must refer
+ * to paths on the same server.
+ *
+ * The Tid in the header is associated with the source while Tid2 is
+ * associated with the destination. These fields may contain the same or
+ * differing valid values. Tid2 can be set to -1 indicating that this is to
+ * be the same Tid as in the SMB header. This allows use of the move
+ * protocol with SMB_TREE_CONNECT_ANDX.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Number of files copied
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR ErrorFileFormat; 0x04 (only if error)
+ * STRING ErrorFileName;
+ *
+ * The source path must refer to an existing file or files. Wildcards are
+ * permitted. Source files specified by wildcards are processed until an
+ * error is encountered. If an error is encountered, the expanded name of
+ * the file is returned in ErrorFileName. Wildcards are not permitted in
+ * TargetFileName. TargetFileName can refer to either a file or a direc-
+ * tory.
+ *
+ * The destination can be required to be a file or a directory by the bits
+ * in Flags. If neither bit0 nor bit1 are set, the destination may be
+ * either a file or a directory. Flags also controls the copy mode. In a
+ * ascii copy for the source, the copy stops the first time an EOF
+ * (control-Z) is encountered. In a ascii copy for the target, the server
+ *
+ * must make sure that there is exactly one EOF in the target file and that
+ * it is the last character of the file.
+ *
+ * If the destination is a file and the source contains wildcards, the
+ * destination file will either be truncated or appended to at the start of
+ * the operation depending on bits in OpenFunction (see section 3.7).
+ * Subsequent files will then be appended to the file.
+ *
+ * If the negotiated dialect is LM1.2X002 or later, bit5 of Flags is used
+ * to specify a tree copy on the remote server. When this option is
+ * selected the destination must not be an existing file and the source
+ * mode must be binary. A request with bit5 set and either bit0 or bit3
+ * set is therefore an error. When the tree copy mode is selected, the
+ * Count field in the server response is undefined.
+ *
+ * 4.2.13.1 Errors
+ *
+ * ERRDOS/ERRfilexists
+ * ERRDOS/ERRshare
+ * ERRDOS/ERRnofids
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadshare
+ * ERRSRV/ERRnoaccess
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRaccess
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*ARGSUSED*/
+int
+smb_com_copy(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c
new file mode 100644
index 0000000000..fccdf5ba9e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c
@@ -0,0 +1,224 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+#define SMB_CREATE_NAMEBUF_SZ 16
+
+static uint32_t smb_common_create(struct smb_request *sr);
+
+/*
+ * Create a new file, or truncate an existing file to zero length,
+ * open the file and return a fid. The file is specified using a
+ * fully qualified name relative to the tree.
+ */
+int
+smb_com_create(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t status;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ if (smbsr_decode_vwv(sr, "wl", &op->dattr, &op->utime.tv_sec) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ op->create_disposition = FILE_OVERWRITE_IF;
+ status = smb_common_create(sr);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_SHARING_VIOLATION:
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ break;
+
+ default:
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ break;
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Create a new file and return a fid. The file is specified using
+ * a fully qualified name relative to the tree.
+ */
+int
+smb_com_create_new(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t status;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ if (smbsr_decode_vwv(sr, "wl", &op->dattr, &op->utime.tv_sec) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ op->create_disposition = FILE_CREATE;
+ status = smb_common_create(sr);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_SHARING_VIOLATION:
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ break;
+
+ default:
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ break;
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * Create a unique file in the specified directory relative to the
+ * current tree. No attributes are specified.
+ */
+int
+smb_com_create_temporary(struct smb_request *sr)
+{
+ static uint16_t tmp_id = 10000;
+ struct open_param *op = &sr->arg.open;
+ char name[SMB_CREATE_NAMEBUF_SZ];
+ char *buf;
+ uint32_t status;
+ uint16_t reserved;
+ uint16_t bcc;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ if (smbsr_decode_vwv(sr, "wl", &reserved, &op->utime.tv_sec) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ++tmp_id;
+ bcc = 1; /* null terminator */
+ bcc += snprintf(name, SMB_CREATE_NAMEBUF_SZ, "tt%05d.tmp", tmp_id);
+
+ buf = smbsr_malloc(&sr->request_storage, MAXPATHLEN);
+ (void) snprintf(buf, MAXPATHLEN, "%s\\%s", op->fqi.path, name);
+ op->fqi.path = buf;
+ op->create_disposition = FILE_CREATE;
+ status = smb_common_create(sr);
+
+ switch (status) {
+ case NT_STATUS_SUCCESS:
+ break;
+
+ case NT_STATUS_SHARING_VIOLATION:
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ break;
+
+ default:
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ break;
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bwwwbs", 1, sr->smb_fid, bcc, 4, name);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Common create file function. The file is opened in compatibility
+ * mode with read/write access.
+ */
+uint32_t
+smb_common_create(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t status;
+
+ op->utime.tv_sec = smb_local_time_to_gmt(op->utime.tv_sec);
+ op->utime.tv_nsec = 0;
+ op->omode = SMB_DA_ACCESS_READ_WRITE | SMB_DA_SHARE_COMPATIBILITY;
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
+ (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->dsize = 0;
+
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+
+ status = smb_open_subr(sr);
+
+ if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
+ sr->smb_flg &=
+ ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
+ }
+
+ return (status);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create_directory.c b/usr/src/uts/common/fs/smbsrv/smb_create_directory.c
new file mode 100644
index 0000000000..e369f59b47
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_create_directory.c
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: create_directory
+ *
+ * The create directory message is sent to create a new directory. The
+ * appropriate Tid and additional pathname are passed. The directory must
+ * not exist for it to be created.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryName[]; Directory name
+ *
+ * Servers require clients to have at least create permission for the
+ * subtree containing the directory in order to create a new directory.
+ * The creator's access rights to the new directory are be determined by
+ * local policy on the server.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ *
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+typedef struct smb_request SmbRequest;
+
+typedef struct {
+ char *sp_path; /* Original path */
+ char *sp_curp; /* Current pointer into the original path */
+ SmbRequest *sp_sr; /* Current request pointer */
+} SmbPath;
+
+
+extern int smb_common_create_directory(struct smb_request *sr);
+
+
+static int smbpath_next(SmbPath* spp);
+static SmbPath* smbpath_new(SmbRequest* sr);
+
+
+/*
+ * smb_com_create_directory
+ *
+ * It is possible to get a full pathname here and the client expects any
+ * or all of the components to be created if they don't already exist.
+ */
+int
+smb_com_create_directory(struct smb_request *sr)
+{
+ SmbPath* spp;
+ DWORD status;
+ int rc = 0;
+
+ if (smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) {
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_raise_nt_error(sr, status);
+ else
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_NAME);
+
+ /* NOTREACHED */
+ }
+
+ /*
+ * Try each component of the path. It is all right to get an EEXIST
+ * on each component except the last.
+ */
+ spp = smbpath_new(sr);
+
+ while (smbpath_next(spp)) {
+ rc = smb_common_create_directory(sr);
+ if (rc != 0 && rc != EEXIST)
+ smbsr_raise_errno(sr, rc);
+ }
+
+ /* We should have created one directory successfully! */
+ if (rc != 0)
+ smbsr_raise_errno(sr, rc);
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_validate_dirname
+ *
+ * Very basic directory name validation: checks for colons in a path.
+ * Need to skip the drive prefix since it contains a colon.
+ *
+ * Returns 0 if the name is valid, otherwise NT_STATUS_NOT_A_DIRECTORY.
+ */
+DWORD
+smb_validate_dirname(char *path)
+{
+ char *name;
+
+ if ((name = path) != 0) {
+ name += strspn(name, "\\");
+
+ if (strchr(name, ':') != 0)
+ return (NT_STATUS_NOT_A_DIRECTORY);
+ }
+
+ return (0);
+}
+
+
+/*
+ * smb_common_create_directory
+ *
+ * Currently called from:
+ * smb_com_create_directory
+ * smb_com_trans2_create_directory
+ *
+ * Returns errno values.
+ */
+int
+smb_common_create_directory(struct smb_request *sr)
+{
+ int rc;
+ smb_attr_t new_attr;
+ struct smb_node *dnode;
+ struct smb_node *node;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_NOT_EXIST);
+ if (rc)
+ return (rc);
+
+ /*
+ * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
+ * value, only fqi.dir_snode has a valid parameter (fqi.last_snode
+ * is NULL).
+ */
+ dnode = sr->arg.dirop.fqi.dir_snode;
+
+ bzero(&new_attr, sizeof (new_attr));
+ new_attr.sa_vattr.va_type = VDIR;
+ new_attr.sa_vattr.va_mode = 0777;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE;
+
+ if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
+ sr->arg.dirop.fqi.last_comp, &new_attr,
+ &sr->arg.dirop.fqi.last_snode,
+ &sr->arg.dirop.fqi.last_attr)) != 0) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ return (rc);
+ }
+
+ node = sr->arg.dirop.fqi.last_snode;
+ node->flags |= NODE_FLAGS_CREATED;
+
+ sr->arg.open.create_options = FILE_DIRECTORY_FILE;
+
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ return (0);
+}
+
+SmbPath*
+smbpath_new(SmbRequest* sr)
+{
+ int pathLen;
+ char *xpath;
+ SmbPath *spp;
+
+ /* Malloc from the request storage area. This is freed automatically */
+ /* so we don't need to worry about freeing it later */
+ spp = smbsr_malloc(&sr->request_storage, sizeof (SmbPath));
+ spp->sp_path = sr->arg.dirop.fqi.path;
+ pathLen = strlen(spp->sp_path);
+ spp->sp_curp = spp->sp_path;
+ xpath = smbsr_malloc(&sr->request_storage, pathLen + 1);
+ sr->arg.dirop.fqi.path = xpath;
+ spp->sp_sr = sr;
+
+ return (spp);
+}
+
+/*
+ * Perhaps somewhat dangerous since everything happens as a side effect. The
+ * returns 1 if there is a valid component updated to the fqi, 0 otherwise.
+ */
+int
+smbpath_next(SmbPath* spp)
+{
+ char *xp;
+ int xlen;
+
+ if (spp == 0)
+ return (0);
+
+ /* Move the index to the "next" "\" and copy the path to the fqi */
+ /* path for the next component. */
+
+ /* First look for the next component */
+ while (*spp->sp_curp == '\\')
+ spp->sp_curp++;
+
+ /* Now get to the end of the component */
+ xp = spp->sp_curp; /* Remember from where we started */
+ while (*spp->sp_curp != '\0' && *spp->sp_curp != '\\') {
+ spp->sp_curp++;
+ }
+
+ /* If we made no progress, we are done */
+ if (xp == spp->sp_curp)
+ return (0);
+
+ /*
+ * Now copy the original path up to but not including our current
+ * pointer
+ */
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ xlen = spp->sp_curp - spp->sp_path;
+ (void) strncpy(spp->sp_sr->arg.dirop.fqi.path, spp->sp_path, xlen);
+
+ /* Now NULL terminate it */
+ spp->sp_sr->arg.dirop.fqi.path[xlen] = '\0';
+ return (1);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c
new file mode 100644
index 0000000000..f35e3c4273
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c
@@ -0,0 +1,354 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbinfo.h>
+
+static DWORD smb_delete_check(struct smb_request *sr, struct smb_node *node,
+ uint16_t dattr, smb_error_t *smberr);
+static DWORD smb_delete_share_check(struct smb_node *node);
+
+/*
+ * smb_com_delete
+ *
+ * The delete file message is sent to delete a data file. The appropriate
+ * Tid and additional pathname are passed. Read only files may not be
+ * deleted, the read-only attribute must be reset prior to file deletion.
+ *
+ * NT supports a hidden permission known as File Delete Child (FDC). If
+ * the user has FullControl access to a directory, the user is permitted
+ * to delete any object in the directory regardless of the permissions
+ * on the object.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT SearchAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * Multiple files may be deleted in response to a single request as
+ * SMB_COM_DELETE supports wildcards
+ *
+ * SearchAttributes indicates the attributes that the target file(s) must
+ * have. If the attribute is zero then only normal files are deleted. If
+ * the system file or hidden attributes are specified then the delete is
+ * inclusive -both the specified type(s) of files and normal files are
+ * deleted. Attributes are described in the "Attribute Encoding" section
+ * of this document.
+ *
+ * If bit0 of the Flags2 field of the SMB header is set, a pattern is
+ * passed in, and the file has a long name, then the passed pattern much
+ * match the long file name for the delete to succeed. If bit0 is clear, a
+ * pattern is passed in, and the file has a long name, then the passed
+ * pattern must match the file's short name for the deletion to succeed.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * 4.2.10.1 Errors
+ *
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRbadshare # returned by NT for files that are already open
+ * ERRHRD/ERRnowrite
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ */
+int
+smb_com_delete(struct smb_request *sr)
+{
+ int rc;
+ int od = 0;
+ int deleted = 0;
+ unsigned short sattr;
+ char *path;
+ struct smb_node *dir_snode;
+ struct smb_node *node = 0;
+ char *name;
+ char *fname;
+ char *sname;
+ char *fullname;
+ smb_error_t smberr;
+ int is_stream;
+ smb_odir_context_t *pc;
+
+ pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ fullname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ if (smbsr_decode_vwv(sr, "w", &sattr) != 0) {
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ is_stream = smb_stream_parse_name(path, fname, sname);
+
+ (void) smb_rdir_open(sr, path, sattr);
+ dir_snode = sr->sid_odir->d_dir_snode;
+
+ /*
+ * This while loop is meant to deal with wildcards.
+ * It is not expected that wildcards will exist for
+ * streams. For the streams case, it is expected
+ * that the below loop will be executed only once.
+ */
+
+ while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
+ (void) strlcpy(name, pc->dc_name, MAXNAMELEN);
+
+ if (smb_delete_check(sr, node, pc->dc_dattr, &smberr)
+ != NT_STATUS_SUCCESS) {
+ smb_node_release(node);
+ goto delete_error;
+ }
+
+ smb_node_release(node);
+ node = NULL;
+
+ if (is_stream) {
+ /*
+ * It is assumed that fname does not contain
+ * any wildcards .
+ * smb_fsop_remove() requires filename+streamname
+ */
+ (void) snprintf(fullname, MAXPATHLEN, "%s%s",
+ fname, sname);
+ rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
+ fullname, 0);
+ } else {
+ /*
+ * name (i.e. pc->dc_name) is the on-disk name
+ * unless there is a case collision, in which
+ * case readdir will have returned a mangled name.
+ */
+ if (smb_maybe_mangled_name(name) == 0)
+ od = 1;
+
+ rc = smb_fsop_remove(sr, sr->user_cr, dir_snode,
+ name, od);
+ }
+
+ if (rc != 0) {
+ if (rc != ENOENT) {
+ smb_rdir_close(sr);
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ } else {
+ deleted++;
+ }
+ }
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* rc returned by smb_rdir_next() */
+ smb_rdir_close(sr);
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (deleted == 0) {
+ smberr.errcls = ERRDOS;
+ smberr.errcode = ERROR_FILE_NOT_FOUND;
+ smberr.status = (sr->sid_odir->d_wildcards == 0)
+ ? NT_STATUS_OBJECT_NAME_NOT_FOUND : NT_STATUS_NO_SUCH_FILE;
+ goto delete_error;
+ }
+
+ smb_rdir_close(sr);
+
+ smbsr_encode_empty_result(sr);
+
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ return (SDRC_NORMAL_REPLY);
+
+delete_error:
+ smb_rdir_close(sr);
+ kmem_free(pc, sizeof (*pc));
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(fullname, MAXPATHLEN);
+ smbsr_raise_cifs_error(sr,
+ smberr.status, smberr.errcls, smberr.errcode);
+ /* NOTREACHED */
+ return (SDRC_NORMAL_REPLY); /* compiler complains otherwise */
+}
+
+static DWORD
+smb_delete_check(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint16_t dattr,
+ smb_error_t *smberr)
+{
+ if (dattr & SMB_FA_DIRECTORY) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ smberr->status = NT_STATUS_FILE_IS_A_DIRECTORY;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if ((dattr & SMB_FA_READONLY) ||
+ (node->flags & NODE_CREATED_READONLY)) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ smberr->status = NT_STATUS_CANNOT_DELETE;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * NT does not always close a file immediately, which
+ * can cause the share and access checking to fail
+ * (the node refcnt is greater than one), and the file
+ * doesn't get deleted. Breaking the oplock before
+ * share and access checking gives the client a chance
+ * to close the file.
+ */
+ if (OPLOCKS_IN_FORCE(node)) {
+ smberr->status = smb_break_oplock(sr, node);
+
+ if (smberr->status != NT_STATUS_SUCCESS) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_VC_DISCONNECTED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ }
+
+ smberr->status = smb_delete_share_check(node);
+ if (smberr->status == NT_STATUS_SHARING_VIOLATION) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_SHARING_VIOLATION;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * This should be done after Share checking due to tests with
+ * W2K. I got sharing violation error trying to delete a
+ * locked file which is basically the same error if you
+ * try to delete a non-locked open file.
+ *
+ * One thing that I discovered during these tests is that
+ * W2K rejects lock requests on open files which are opened
+ * with Metadata open modes. The error is STATUS_ACCESS_DENIED.
+ */
+ if (smb_lock_range_access(sr, node, 0, 0, FILE_WRITE_DATA) !=
+ NT_STATUS_SUCCESS) {
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ smberr->status = NT_STATUS_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_delete_share_check
+ *
+ * An open file can be deleted only if opened for
+ * accessing meta data. Share modes aren't important
+ * in this case.
+ *
+ * NOTE: there is another mechanism for deleting an
+ * open file that NT clients usually use this method.
+ * That's setting "Delete on close" flag for an open
+ * file, in this way the file will be deleted after
+ * last close. This flag can be set by SmbTrans2SetFileInfo
+ * with FILE_DISPOSITION_INFO information level.
+ * For setting this flag file should be opened by
+ * DELETE access in the FID that is passed in the Trans2
+ * request.
+ */
+static DWORD
+smb_delete_share_check(struct smb_node *node)
+{
+ smb_ofile_t *file;
+
+ if (node == 0 || node->n_refcnt <= 1)
+ return (NT_STATUS_SUCCESS);
+
+ if (node->attr.sa_vattr.va_type == VDIR)
+ return (NT_STATUS_SUCCESS);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ file = smb_llist_head(&node->n_ofile_list);
+ while (file) {
+ ASSERT(file->f_magic == SMB_OFILE_MAGIC);
+ if (file->f_granted_access &
+ (FILE_READ_DATA |
+ FILE_WRITE_DATA |
+ FILE_APPEND_DATA |
+ FILE_EXECUTE |
+ DELETE)) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+ file = smb_llist_next(&node->n_ofile_list, file);
+ }
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c b/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c
new file mode 100644
index 0000000000..e959b240b8
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c
@@ -0,0 +1,114 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbinfo.h>
+
+/*
+ * smb_com_delete_directory
+ *
+ * The delete directory message is sent to delete an empty directory. The
+ * appropriate Tid and additional pathname are passed. The directory must
+ * be empty for it to be deleted.
+ *
+ * NT supports a hidden permission known as File Delete Child (FDC). If
+ * the user has FullControl access to a directory, the user is permitted
+ * to delete any object in the directory regardless of the permissions
+ * on the object.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryName[]; Directory name
+ *
+ * The directory to be deleted cannot be the root of the share specified
+ * by Tid.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+int
+smb_com_delete_directory(struct smb_request *sr)
+{
+ smb_node_t *dnode;
+ int rc;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ dnode = sr->arg.dirop.fqi.last_snode;
+
+ if (dnode->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) {
+ smb_node_release(dnode);
+ smb_node_release(sr->arg.dirop.fqi.dir_snode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ smbsr_raise_cifs_error(sr, NT_STATUS_CANNOT_DELETE,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dnode);
+
+ dnode = sr->arg.dirop.fqi.dir_snode;
+
+ rc = smb_fsop_rmdir(sr, sr->user_cr, dnode,
+ sr->arg.dirop.fqi.last_comp_od, 1);
+ if (rc != 0) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
new file mode 100644
index 0000000000..96a23bb995
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -0,0 +1,1574 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ *
+ * Dispatching SMB requests.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ALMOST EVERYTHING YOU NEED TO KNOW ABOUT A SERVER MESSAGE BLOCK
+ *
+ * Request
+ * Header
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command
+ * Error a 4-byte union, ignored in a request
+ * smb_flg a one byte set of eight flags
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * 0xFFFF is this command does not have
+ * or require a tree context
+ * smb_pid a 16-bit process ID
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid")
+ *
+ * Chained (AndX) commands (0 or more)
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 2 for chained command
+ * andx_com a byte, the "next" command, 0xFF for none
+ * . an unused byte
+ * andx_off a 16-bit offset, byte displacement from &Magic
+ * to the smb_wct field of the "next" command,
+ * ignore if andx_com is 0xFF, s/b 0 if no next
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands
+ * padding[] Optional padding
+ *
+ * Last command
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 0 for chained command
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands
+ *
+ * Reply
+ * Header
+ * Magic 0xFF 'S' 'M' 'B'
+ * smb_com a byte, the "first" command, corresponds
+ * to request
+ * Error a 4-byte union, coding depends on dialect in use
+ * for "DOS" errors
+ * a byte for error class
+ * an unused byte
+ * a 16-bit word for error code
+ * for "NT" errors
+ * a 32-bit error code which
+ * is a packed class and specifier
+ * for "OS/2" errors
+ * I don't know
+ * The error information is specific to the
+ * last command in the reply chain.
+ * smb_flg a one byte set of eight flags, 0x80 bit set
+ * indicating this message is a reply
+ * smb_flg2 a two byte set of 16 flags
+ * . twelve reserved bytes, have a role
+ * in connectionless transports (IPX, UDP?)
+ * smb_tid a 16-bit tree ID, a mount point sorta,
+ * should be the same as the request
+ * smb_pid a 16-bit process ID, MUST BE the same as request
+ * smb_uid a 16-bit user ID, specific to this "session"
+ * and mapped to a system (bona-fide) UID,
+ * should be the same as request
+ * smb_mid a 16-bit multiplex ID, used to differentiate
+ * multiple simultaneous requests from the same
+ * process (pid) (ref RPC "xid"), MUST BE the
+ * same as request
+ * padding[] Optional padding
+ *
+ * Chained (AndX) commands (0 or more)
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 2 for chained command,
+ * andx_com a byte, the "next" command, 0xFF for none,
+ * corresponds to request, if this is the chained
+ * command that had an error set to 0xFF
+ * . an unused byte
+ * andx_off a 16-bit offset, byte displacement from &Magic
+ * to the smb_wct field of the "next" command,
+ * ignore if andx_com is 0xFF, s/b 0 if no next
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block. Empty if an error.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands
+ * empty if an error.
+ *
+ * Last command
+ * smb_wct a byte, number of 16-bit words containing
+ * command parameters, min 0 for chained command
+ * smb_vwv[] 0 or more 16-bit (sorta) parameters for
+ * "this" command (i.e. smb_com if this is the
+ * first parameters, or the andx_com of the just
+ * previous block, empty if an error.
+ * smb_bcc a 16-bit count of smb_data[] bytes
+ * smb_data[] 0 or more bytes, format specific to commands,
+ * empty if an error.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <sys/sdt.h>
+
+#define SMB_ALL_DISPATCH_STAT_INCR(stat) atomic_inc_64(&stat);
+
+int smb_dispatch_diags = 0;
+static kstat_t *smb_dispatch_ksp = NULL;
+static kstat_named_t *smb_dispatch_kstat_data = NULL;
+static int smb_dispatch_kstat_size = 0;
+
+static int is_andx_com(unsigned char);
+
+extern void smbsr_decode_error(struct smb_request *sr);
+extern void smbsr_encode_error(struct smb_request *sr);
+extern void smbsr_check_result(struct smb_request *sr, int wct, int bcc);
+
+extern int smb_com_cancel_forward(struct smb_request *);
+extern int smb_com_check_directory(struct smb_request *);
+extern int smb_com_close(struct smb_request *);
+extern int smb_com_close_and_tree_disconnect(struct smb_request *);
+extern int smb_com_close_print_file(struct smb_request *);
+extern int smb_com_copy(struct smb_request *);
+extern int smb_com_create(struct smb_request *);
+extern int smb_com_create_directory(struct smb_request *);
+extern int smb_com_create_new(struct smb_request *);
+extern int smb_com_create_temporary(struct smb_request *);
+extern int smb_com_delete(struct smb_request *);
+extern int smb_com_delete_directory(struct smb_request *);
+extern int smb_com_echo(struct smb_request *);
+extern int smb_com_find(struct smb_request *);
+extern int smb_com_find_close(struct smb_request *);
+extern int smb_com_find_close2(struct smb_request *);
+extern int smb_com_find_notify_close(struct smb_request *);
+extern int smb_com_find_unique(struct smb_request *);
+extern int smb_com_flush(struct smb_request *);
+extern int smb_com_forward_user_name(struct smb_request *);
+extern int smb_com_get_machine_name(struct smb_request *);
+extern int smb_com_get_print_queue(struct smb_request *);
+extern int smb_com_invalid_command(struct smb_request *);
+extern int smb_com_ioctl(struct smb_request *);
+extern int smb_com_ioctl_secondary(struct smb_request *);
+extern int smb_com_lock_and_read(struct smb_request *);
+extern int smb_com_lock_byte_range(struct smb_request *);
+extern int smb_com_locking_andx(struct smb_request *);
+extern int smb_com_logoff_andx(struct smb_request *);
+extern int smb_com_move(struct smb_request *);
+extern int smb_com_negotiate(struct smb_request *);
+extern int smb_com_nt_cancel(struct smb_request *);
+extern int smb_com_nt_create_andx(struct smb_request *);
+extern int smb_com_nt_transact(struct smb_request *);
+extern int smb_com_nt_transact_secondary(struct smb_request *);
+extern int smb_com_open(struct smb_request *);
+extern int smb_com_open_andx(struct smb_request *);
+extern int smb_com_open_print_file(struct smb_request *);
+extern int smb_com_process_exit(struct smb_request *);
+extern int smb_com_query_information(struct smb_request *);
+extern int smb_com_query_information2(struct smb_request *);
+extern int smb_com_query_information_disk(struct smb_request *);
+extern int smb_com_read(struct smb_request *);
+extern int smb_com_read_andx(struct smb_request *);
+extern int smb_com_read_mpx(struct smb_request *);
+extern int smb_com_read_mpx_secondary(struct smb_request *);
+extern int smb_com_read_raw(struct smb_request *);
+extern int smb_com_rename(struct smb_request *);
+extern int smb_com_search(struct smb_request *);
+extern int smb_com_seek(struct smb_request *);
+extern int smb_com_send_broadcast_message(struct smb_request *);
+extern int smb_com_send_end_mb_message(struct smb_request *);
+extern int smb_com_send_single_message(struct smb_request *);
+extern int smb_com_send_start_mb_message(struct smb_request *);
+extern int smb_com_send_text_mb_message(struct smb_request *);
+extern int smb_com_session_setup_andx(struct smb_request *);
+extern int smb_com_set_information(struct smb_request *);
+extern int smb_com_set_information2(struct smb_request *);
+extern int smb_com_transaction(struct smb_request *);
+extern int smb_com_transaction2(struct smb_request *);
+extern int smb_com_transaction2_secondary(struct smb_request *);
+extern int smb_com_transaction_secondary(struct smb_request *);
+extern int smb_com_tree_connect(struct smb_request *);
+extern int smb_com_tree_connect_andx(struct smb_request *);
+extern int smb_com_tree_disconnect(struct smb_request *);
+extern int smb_com_unlock_byte_range(struct smb_request *);
+extern int smb_com_write(struct smb_request *);
+extern int smb_com_write_and_close(struct smb_request *);
+extern int smb_com_write_and_unlock(struct smb_request *);
+extern int smb_com_write_andx(struct smb_request *);
+extern int smb_com_write_complete(struct smb_request *);
+extern int smb_com_write_mpx(struct smb_request *);
+extern int smb_com_write_mpx_secondary(struct smb_request *);
+extern int smb_com_write_print_file(struct smb_request *);
+extern int smb_com_write_raw(struct smb_request *);
+
+static smb_dispatch_table_t dispatch[256] = {
+ { smb_com_create_directory, /* 0x00 000 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreateDirectory", KSTAT_DATA_UINT64 } },
+ { smb_com_delete_directory, /* 0x01 001 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbDeleteDirectory", KSTAT_DATA_UINT64 } },
+ { smb_com_open, /* 0x02 002 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbOpen", KSTAT_DATA_UINT64 } },
+ { smb_com_create, /* 0x03 003 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreate", KSTAT_DATA_UINT64 } },
+ { smb_com_close, /* 0x04 004 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbClose", KSTAT_DATA_UINT64 } },
+ { smb_com_flush, /* 0x05 005 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFlush", KSTAT_DATA_UINT64 } },
+ { smb_com_delete, /* 0x06 006 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbDelete", KSTAT_DATA_UINT64 } },
+ { smb_com_rename, /* 0x07 007 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbRename", KSTAT_DATA_UINT64 } },
+ { smb_com_query_information, /* 0x08 008 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbQueryInformation", KSTAT_DATA_UINT64 } },
+ { smb_com_set_information, /* 0x09 009 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSetInformation", KSTAT_DATA_UINT64 } },
+ { smb_com_read, /* 0x0A 010 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbRead", KSTAT_DATA_UINT64 } },
+ { smb_com_write, /* 0x0B 011 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWrite", KSTAT_DATA_UINT64 } },
+ { smb_com_lock_byte_range, /* 0x0C 012 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbLockByteRange", KSTAT_DATA_UINT64 } },
+ { smb_com_unlock_byte_range, /* 0x0D 013 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbUnlockByteRange", KSTAT_DATA_UINT64 } },
+ { smb_com_create_temporary, /* 0x0E 014 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreateTemporary", KSTAT_DATA_UINT64 } },
+ { smb_com_create_new, /* 0x0F 015 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCreateNew", KSTAT_DATA_UINT64 } },
+ { smb_com_check_directory, /* 0x10 016 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCheckDirectory", KSTAT_DATA_UINT64 } },
+ { smb_com_process_exit, /* 0x11 017 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbProcessExit", KSTAT_DATA_UINT64 } },
+ { smb_com_seek, /* 0x12 018 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSeek", KSTAT_DATA_UINT64 } },
+ { smb_com_lock_and_read, /* 0x13 019 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbLockAndRead", KSTAT_DATA_UINT64 } },
+ { smb_com_write_and_unlock, /* 0x14 020 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteAndUnlock", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x15 021 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x16 022 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x17 023 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x18 024 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x19 025 */
+ { smb_com_read_raw, /* 0x1A 026 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_WRITER,
+ { "SmbReadRaw", KSTAT_DATA_UINT64 } },
+ { smb_com_read_mpx, /* 0x1B 027 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbReadMpx", KSTAT_DATA_UINT64 } },
+ { smb_com_read_mpx_secondary, /* 0x1C 028 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbReadMpxSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_write_raw, /* 0x1D 029 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW | SDDF_SUPPRESS_UNLEASH,
+ RW_WRITER,
+ { "SmbWriteRaw", KSTAT_DATA_UINT64 } },
+ { smb_com_write_mpx, /* 0x1E 030 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteMpx", KSTAT_DATA_UINT64 } },
+ { smb_com_write_mpx_secondary, /* 0x1F 031 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteMpxSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_write_complete, /* 0x20 032 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteComplete", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, 0, 0 }, /* 0x21 033 */
+ { smb_com_set_information2, /* 0x22 034 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSetInformation2", KSTAT_DATA_UINT64 } },
+ { smb_com_query_information2, /* 0x23 035 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbQueryInformation2", KSTAT_DATA_UINT64 } },
+ { smb_com_locking_andx, /* 0x24 036 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbLockingX", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction, /* 0x25 037 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransaction", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction_secondary, /* 0x26 038 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransactionSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_ioctl, /* 0x27 039 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbIoctl", KSTAT_DATA_UINT64 } },
+ { smb_com_ioctl_secondary, /* 0x28 040 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbIoctlSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_copy, /* 0x29 041 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCopy", KSTAT_DATA_UINT64 } },
+ { smb_com_move, /* 0x2A 042 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbMove", KSTAT_DATA_UINT64 } },
+ { smb_com_echo, /* 0x2B 043 */
+ LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbEcho", KSTAT_DATA_UINT64 } },
+ { smb_com_write_and_close, /* 0x2C 044 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteAndClose", KSTAT_DATA_UINT64 } },
+ { smb_com_open_andx, /* 0x2D 045 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbOpenX", KSTAT_DATA_UINT64 } },
+ { smb_com_read_andx, /* 0x2E 046 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbReadX", KSTAT_DATA_UINT64 } },
+ { smb_com_write_andx, /* 0x2F 047 */
+ LANMAN1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWriteX", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, 0, 0 }, /* 0x30 048 */
+ { smb_com_close_and_tree_disconnect, /* 0x31 049 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCloseAndTreeDisconnect", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction2, /* 0x32 050 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransaction2", KSTAT_DATA_UINT64 } },
+ { smb_com_transaction2_secondary, /* 0x33 051 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbTransaction2Secondary", KSTAT_DATA_UINT64 } },
+ { smb_com_find_close2, /* 0x34 052 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindClose2", KSTAT_DATA_UINT64 } },
+ { smb_com_find_notify_close, /* 0x35 053 */
+ LM1_2X002, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindNotifyClose", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x36 054 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x37 055 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x38 056 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x39 057 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3A 058 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3B 059 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3C 060 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3D 061 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3E 062 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x3F 063 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x40 064 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x41 065 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x42 066 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x43 067 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x44 068 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x45 069 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x46 070 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x47 071 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x48 072 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x49 073 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4A 074 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4B 075 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4C 076 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4D 077 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4E 078 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x4F 079 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x50 080 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x51 081 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x52 082 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x53 083 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x54 084 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x55 085 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x56 086 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x57 087 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x58 088 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x59 089 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5A 090 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5B 091 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5C 092 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5D 093 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5E 094 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x5F 095 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x60 096 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x61 097 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x62 098 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x63 099 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x64 100 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x65 101 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x66 102 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x67 103 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x68 104 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x69 105 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6A 106 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6B 107 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6C 108 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6D 109 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6E 110 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x6F 111 */
+ { smb_com_tree_connect, /* 0x70 112 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID,
+ RW_READER,
+ { "SmbTreeConnect", KSTAT_DATA_UINT64 } },
+ { smb_com_tree_disconnect, /* 0x71 113 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbTreeDisconnect", KSTAT_DATA_UINT64 } },
+ { smb_com_negotiate, /* 0x72 114 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_WRITER,
+ { "SmbNegotiate", KSTAT_DATA_UINT64 } },
+ { smb_com_session_setup_andx, /* 0x73 115 */
+ LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
+ RW_READER,
+ { "SmbSessionSetupX", KSTAT_DATA_UINT64 } },
+ { smb_com_logoff_andx, /* 0x74 116 */
+ LM1_2X002, SDDF_SUPPRESS_TID,
+ RW_READER,
+ { "SmbLogoffX", KSTAT_DATA_UINT64 } },
+ { smb_com_tree_connect_andx, /* 0x75 117 */
+ LANMAN1_0, SDDF_SUPPRESS_TID,
+ RW_READER,
+ { "SmbTreeConnectX", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x76 118 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x77 119 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x78 120 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x79 121 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7A 122 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7B 123 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7C 124 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7D 125 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7E 126 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x7F 127 */
+ { smb_com_query_information_disk, /* 0x80 128 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbQueryInformationDisk", KSTAT_DATA_UINT64 } },
+ { smb_com_search, /* 0x81 129 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSearch", KSTAT_DATA_UINT64 } },
+ { smb_com_find, /* 0x82 130 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFind", KSTAT_DATA_UINT64 } },
+ { smb_com_find_unique, /* 0x83 131 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindUnique", KSTAT_DATA_UINT64 } },
+ { smb_com_find_close, /* 0x84 132 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbFindClose", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0x85 133 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x86 134 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x87 135 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x88 136 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x89 137 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8A 138 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8B 139 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8C 140 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8D 141 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8E 142 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x8F 143 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x90 144 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x91 145 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x92 146 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x93 147 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x94 148 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x95 149 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x96 150 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x97 151 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x98 152 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x99 153 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9A 154 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9B 155 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9C 156 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9D 157 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9E 158 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0x9F 159 */
+ { smb_com_nt_transact, /* 0xA0 160 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtTransact", KSTAT_DATA_UINT64 } },
+ { smb_com_nt_transact_secondary, /* 0xA1 161 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtTransactSecondary", KSTAT_DATA_UINT64 } },
+ { smb_com_nt_create_andx, /* 0xA2 162 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtCreateX", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, 0, 0 }, /* 0xA3 163 */
+ { smb_com_nt_cancel, /* 0xA4 164 */
+ NT_LM_0_12, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbNtCancel", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA5 165 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA6 166 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA7 167 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA8 168 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xA9 169 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAA 170 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAB 171 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAC 172 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAD 173 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAE 174 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xAF 175 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB0 176 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB1 177 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB2 178 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB3 179 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB4 180 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB5 181 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB6 182 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB7 183 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB8 184 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xB9 185 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBA 186 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBB 187 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBC 188 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBD 189 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBE 190 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xBF 191 */
+ { smb_com_open_print_file, /* 0xC0 192 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbOpenPrintFile", KSTAT_DATA_UINT64 } },
+ { smb_com_write_print_file, /* 0xC1 193 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
+ RW_READER,
+ { "SmbWritePrintFile", KSTAT_DATA_UINT64 } },
+ { smb_com_close_print_file, /* 0xC2 194 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbClosePrintFile", KSTAT_DATA_UINT64 } },
+ { smb_com_get_print_queue, /* 0xC3 195 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbGetPrintQueue", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC4 196 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC5 197 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC6 198 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC7 199 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC8 200 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xC9 201 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCA 202 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCB 203 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCC 204 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCD 205 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCE 206 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xCF 207 */
+ { smb_com_send_single_message, /* 0xD0 208 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendSingleMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_send_broadcast_message, /* 0xD1 209 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendBroadcastMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_forward_user_name, /* 0xD2 210 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbForwardUserName", KSTAT_DATA_UINT64 } },
+ { smb_com_cancel_forward, /* 0xD3 211 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbCancelForward", KSTAT_DATA_UINT64 } },
+ { smb_com_get_machine_name, /* 0xD4 212 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbGetMachineName", KSTAT_DATA_UINT64 } },
+ { smb_com_send_start_mb_message, /* 0xD5 213 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendStartMbMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_send_end_mb_message, /* 0xD6 214 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendEndMbMessage", KSTAT_DATA_UINT64 } },
+ { smb_com_send_text_mb_message, /* 0xD7 215 */
+ PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbSendTextMbMessage", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 }, /* 0xD8 216 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xD9 217 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDA 218 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDB 219 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDC 220 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDD 221 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDE 222 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xDF 223 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE0 224 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE1 225 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE2 226 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE3 227 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE4 228 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE5 229 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE6 230 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE7 231 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE8 232 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xE9 233 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEA 234 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEB 235 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEC 236 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xED 237 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEE 238 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xEF 239 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF0 240 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF1 241 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF2 242 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF3 243 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF4 244 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF5 245 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF6 246 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF7 247 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF8 248 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xF9 249 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFA 250 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFB 251 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFC 252 */
+ { 0, 0, 0, RW_READER, 0 }, /* 0xFD 253 */
+ { smb_com_invalid_command, /* 0xFE 254 */
+ LANMAN1_0, SDDF_NO_FLAGS,
+ RW_READER,
+ { "SmbInvalidCommand", KSTAT_DATA_UINT64 } },
+ { 0, 0, 0, RW_READER, 0 } /* 0xFF 255 */
+};
+
+int smb_watch = -1;
+int smb_emit_sending = 0;
+
+/*
+ * smbsr_cleanup
+ *
+ * If any user/tree/file is used by given request then
+ * the reference count for that resource has been incremented.
+ * This function decrements the reference count and close
+ * the resource if it's needed.
+ */
+
+void
+smbsr_cleanup(struct smb_request *sr)
+{
+ ASSERT((sr->sr_state != SMB_REQ_STATE_CLEANED_UP) &&
+ (sr->sr_state != SMB_REQ_STATE_COMPLETED));
+
+ if (sr->fid_ofile)
+ smbsr_disconnect_file(sr);
+
+ if (sr->sid_odir)
+ smbsr_disconnect_dir(sr);
+
+ if (sr->tid_tree) {
+ smb_tree_release(sr->tid_tree);
+ sr->tid_tree = NULL;
+ }
+
+ if (sr->uid_user) {
+ smb_user_release(sr->uid_user);
+ sr->uid_user = NULL;
+ }
+
+ if (sr->r_xa) {
+ if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE)
+ smb_xa_close(sr->r_xa);
+ smb_xa_rele(sr->session, sr->r_xa);
+ sr->r_xa = NULL;
+ }
+
+ /*
+ * Mark this request so we know that we've already cleaned it up.
+ * A request should only get cleaned up once so multiple calls to
+ * smbsr_cleanup for the same request indicate a bug.
+ */
+ mutex_enter(&sr->sr_mutex);
+ if (sr->sr_state != SMB_REQ_STATE_CANCELED)
+ sr->sr_state = SMB_REQ_STATE_CLEANED_UP;
+ mutex_exit(&sr->sr_mutex);
+}
+
+int
+smb_dispatch_request(struct smb_request *sr)
+{
+ int rc;
+ smb_dispatch_table_t *sdd;
+
+ ASSERT(sr->tid_tree == 0);
+ ASSERT(sr->uid_user == 0);
+ ASSERT(sr->fid_ofile == 0);
+ ASSERT(sr->sid_odir == 0);
+ sr->smb_fid = (uint16_t)-1;
+ sr->smb_sid = (uint16_t)-1;
+
+ /* temporary until we identify a user */
+ sr->user_cr = kcred;
+ sr->orig_request_hdr = sr->command.chain_offset;
+
+ /* If this connection is shutting down just kill request */
+ if (smb_decode_mbc(&sr->command, SMB_HEADER_ED_FMT,
+ &sr->smb_com,
+ &sr->smb_rcls,
+ &sr->smb_reh,
+ &sr->smb_err,
+ &sr->smb_flg,
+ &sr->smb_flg2,
+ &sr->smb_pid_high,
+ sr->smb_sig,
+ &sr->smb_tid,
+ &sr->smb_pid,
+ &sr->smb_uid,
+ &sr->smb_mid) != 0) {
+ return (-1);
+ }
+
+ /*
+ * The reply "header" is filled in now even though
+ * it most likely will be rewritten under reply_ready:
+ * below. Could just reserve the space. But this
+ * (for now) is convenient incase the dialect dispatcher
+ * has to send a special reply (like TRANSACT).
+ *
+ * Ensure that the 32-bit error code flag is turned off.
+ * Clients seem to set it in transact requests and they may
+ * get confused if we return success or a 16-bit SMB code.
+ */
+ sr->smb_rcls = 0;
+ sr->smb_reh = 0;
+ sr->smb_err = 0;
+ sr->smb_flg2 &= ~SMB_FLAGS2_NT_STATUS;
+
+ (void) smb_encode_mbc(&sr->reply, SMB_HEADER_ED_FMT,
+ sr->smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+ sr->first_smb_com = sr->smb_com;
+
+ /*
+ * Verify SMB signature if signing is enabled,
+ * dialiect is NT LM 0.12,
+ * signing was negotiated and authentication has occurred.
+ */
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
+ if (smb_sign_check_request(sr) != 0) {
+ /* Reply with ACCESS_DENIED */
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_ERROR,
+ NT_STATUS_ACCESS_DENIED);
+ else {
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRnoaccess;
+ }
+ rc = -1;
+ smb_rwx_rwenter(&sr->session->s_lock, RW_READER);
+ goto reply_error;
+ }
+ }
+
+andx_more:
+ sdd = &dispatch[sr->smb_com];
+
+ smb_rwx_rwenter(&sr->session->s_lock, sdd->sdt_slock_mode);
+
+ if (smb_decode_mbc(&sr->command, "b", &sr->smb_wct) != 0) {
+ rc = -3;
+ goto cant_decode;
+ }
+
+ (void) MBC_SHADOW_CHAIN(&sr->smb_vwv, &sr->command,
+ sr->command.chain_offset, sr->smb_wct * 2);
+
+ if (smb_decode_mbc(&sr->command, "#.w",
+ sr->smb_wct*2, &sr->smb_bcc) != 0) {
+ rc = -5;
+ goto cant_decode;
+ }
+
+ (void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
+ sr->command.chain_offset, sr->smb_bcc);
+
+ sr->command.chain_offset += sr->smb_bcc;
+ if (sr->command.chain_offset > sr->command.max_bytes) {
+ rc = -6;
+ goto cant_decode;
+ }
+
+ /* Store pointers for later */
+ sr->cur_reply_offset = sr->reply.chain_offset;
+
+ if (is_andx_com(sr->smb_com)) {
+ /* Peek ahead and don't disturb vwv */
+ if (smb_peek_mbc(&sr->smb_vwv, sr->smb_vwv.chain_offset, "b.w",
+ &sr->andx_com, &sr->andx_off) < 0) {
+ rc = -7;
+ goto cant_decode;
+ }
+ } else {
+ sr->andx_com = (unsigned char)-1;
+ }
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_SUBMITTED:
+ case SMB_REQ_STATE_CLEANED_UP:
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+ break;
+ case SMB_REQ_STATE_CANCELED:
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+
+ if (sdd->sdt_function) {
+
+ if ((rc = setjmp(&sr->exjb))) {
+ /*
+ * Handle any errors from raw write.
+ */
+ if (sr->session->s_state ==
+ SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
+ /*
+ * Set state so that the netbios session
+ * daemon will start accepting data again.
+ */
+ sr->session->s_write_raw_status = 0;
+ sr->session->s_state =
+ SMB_SESSION_STATE_NEGOTIATED;
+ }
+
+ /*
+ * We should never have sr->sr_keep set here
+ * since this is the error path.
+ */
+ ASSERT(sr->sr_keep == 0);
+
+ smbsr_cleanup(sr);
+
+ if (sr->smb_com == smb_watch) {
+ smb_emit_sending = 1;
+ }
+ if (rc < 0) {
+ rc -= 1000;
+ goto cant_decode;
+ }
+ goto reply_error;
+ }
+
+ /*
+ * Setup UID and TID information (if required). Both functions
+ * will set the sr credentials. In domain mode, the user and
+ * tree credentials should be the same. In share mode, the
+ * tree credentials (defined in the share definition) should
+ * override the user credentials.
+ */
+ if (!(sdd->sdt_flags & SDDF_SUPPRESS_UID)) {
+ sr->uid_user = smb_user_lookup_by_uid(sr->session,
+ &sr->user_cr, sr->smb_uid);
+ if (sr->uid_user == NULL) {
+ smbsr_raise_error(sr, ERRSRV, ERRbaduid);
+ /* NOTREACHED */
+ }
+ if (!(sdd->sdt_flags & SDDF_SUPPRESS_TID)) {
+ sr->tid_tree = smb_tree_lookup_by_tid(
+ sr->uid_user, sr->smb_tid);
+ if (sr->tid_tree == NULL) {
+ smbsr_raise_error(sr, ERRSRV,
+ ERRinvnid);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ /*
+ * If the command is not a read raw request we can set the
+ * state of the session back to SMB_SESSION_STATE_NEGOTIATED
+ * (if the current state is SMB_SESSION_STATE_OPLOCK_BREAKING).
+ * Otherwise we let the read raw handler to deal with it.
+ */
+ if ((sr->session->s_state ==
+ SMB_SESSION_STATE_OPLOCK_BREAKING) &&
+ (sr->smb_com != SMB_COM_READ_RAW)) {
+ krw_t mode;
+ /*
+ * The lock may have to be upgraded because, at this
+ * point, we don't know how it was entered. We just
+ * know that it has to be entered in writer mode here.
+ * Whatever mode was used to enter the lock, it will
+ * be restored.
+ */
+ mode = smb_rwx_rwupgrade(&sr->session->s_lock);
+ if (sr->session->s_state ==
+ SMB_SESSION_STATE_OPLOCK_BREAKING) {
+ sr->session->s_state =
+ SMB_SESSION_STATE_NEGOTIATED;
+ }
+ smb_rwx_rwdowngrade(&sr->session->s_lock, mode);
+ }
+
+ DTRACE_PROBE1(smb__dispatch__com, struct smb_request_t *, sr);
+
+ /*
+ * Increment method invocation count. This value is exposed
+ * via kstats, and it represents a count of all the dispatched
+ * requests, including the ones that have a return value, other
+ * than SDRC_NORMAL_REPLY.
+ */
+ SMB_ALL_DISPATCH_STAT_INCR(sdd->sdt_dispatch_stats.value.ui64);
+
+ rc = (*sdd->sdt_function)(sr);
+
+ /*
+ * Only call smbsr_cleanup if smb->sr_keep is not set. The
+ * smb_nt_transact_notify_change function will set
+ * smb->sr_keep if it retains control of the request when
+ * it returns. In that case the notify change code
+ * will call smbsr_cleanup later when the request is finally
+ * completed.
+ */
+ if (sr->sr_keep == 0)
+ smbsr_cleanup(sr);
+ } else {
+ rc = SDRC_UNIMPLEMENTED; /* Unknown? */
+ }
+
+ if (rc != SDRC_NORMAL_REPLY) { /* normal case special & fast */
+ switch (rc) {
+ case SDRC_NORMAL_REPLY:
+ break;
+
+ case SDRC_ERROR_REPLY:
+ goto reply_error;
+
+ case SDRC_DROP_VC:
+ switch (sr->session->s_state) {
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ break;
+ default:
+ smb_soshutdown(sr->session->sock);
+ break;
+ }
+ goto reply_error;
+
+ case SDRC_NO_REPLY:
+ /* tricky. */
+ smb_rwx_rwexit(&sr->session->s_lock);
+ return (0);
+
+ case SDRC_UNIMPLEMENTED:
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRbadfunc;
+ goto reply_error;
+
+ default:
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRerror; /* need better */
+ goto reply_error;
+ }
+ }
+
+ if (sr->andx_com == 0xff)
+ goto reply_ready;
+
+ /* have to back-patch the AndXCommand and AndXOffset */
+ sr->andx_prev_wct = sr->cur_reply_offset;
+ (void) smb_poke_mbc(&sr->reply, sr->andx_prev_wct + 1, "b.w",
+ sr->andx_com, MBC_LENGTH(&sr->reply));
+
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ /* now it gets interesting */
+ sr->command.chain_offset = sr->orig_request_hdr + sr->andx_off;
+
+ sr->smb_com = sr->andx_com;
+
+ goto andx_more;
+
+reply_ready:
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr)) {
+ sr->smb_flg |= SMB_FLAGS_CASE_INSENSITIVE;
+ } else {
+ sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
+ }
+
+ (void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ if ((rc = smb_session_send(sr->session, 0, &sr->reply)) == 0)
+ sr->reply.chain = 0;
+
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ return (rc);
+
+cant_decode:
+reply_error:
+ sr->reply.chain_offset = sr->cur_reply_offset;
+ (void) smb_encode_mbc(&sr->reply, "bw", 0, 0);
+
+ sr->smb_wct = 0;
+ sr->smb_bcc = 0;
+
+ if (sr->smb_rcls == 0) {
+ sr->smb_rcls = ERRSRV;
+ sr->smb_err = ERRerror;
+ }
+ goto reply_ready;
+}
+
+
+void
+smbsr_encode_result(struct smb_request *sr, int wct,
+ int bcc, char *fmt, ...)
+{
+ va_list ap;
+
+ if (MBC_LENGTH(&sr->reply) != sr->cur_reply_offset) {
+ smbsr_encode_error(sr);
+ }
+
+ va_start(ap, fmt);
+ (void) smb_mbc_encode(&sr->reply, fmt, ap);
+ va_end(ap);
+
+ sr->smb_wct = (unsigned char)wct;
+ sr->smb_bcc = (uint16_t)bcc;
+
+ smbsr_check_result(sr, wct, bcc);
+}
+
+void
+smbsr_check_result(struct smb_request *sr, int wct, int bcc)
+{
+ int offset = sr->cur_reply_offset;
+ int total_bytes;
+ unsigned char temp, temp1;
+ struct mbuf *m;
+
+ total_bytes = 0;
+ m = sr->reply.chain;
+ while (m != 0) {
+ total_bytes += m->m_len;
+ m = m->m_next;
+ }
+
+ if ((offset + 3) > total_bytes) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_peek_mbc(&sr->reply, offset, "b", &temp);
+ if (temp != wct) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((offset + (wct * 2 + 1)) > total_bytes) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /* reply wct & vwv seem ok, consider data now */
+ offset += wct * 2 + 1;
+
+ if ((offset + 2) > total_bytes) {
+ smbsr_encode_error(sr);
+ }
+
+ (void) smb_peek_mbc(&sr->reply, offset, "bb", &temp, &temp1);
+ if (bcc == VAR_BCC) {
+ if ((temp != 0xFF) || (temp1 != 0xFF)) {
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ } else {
+ bcc = (total_bytes - offset) - 2;
+ (void) smb_poke_mbc(&sr->reply, offset, "bb",
+ bcc, bcc >> 8);
+ }
+ } else {
+ if ((temp != (bcc&0xFF)) || (temp1 != ((bcc>>8)&0xFF))) {
+ smbsr_encode_error(sr);
+ }
+ }
+
+ offset += bcc + 2;
+
+ if (offset != total_bytes) {
+ smbsr_encode_error(sr);
+ }
+
+ sr->smb_wct = (unsigned char)wct;
+ sr->smb_bcc = (uint16_t)bcc;
+}
+
+int
+smbsr_decode_vwv(struct smb_request *sr, char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = smb_mbc_decode(&sr->smb_vwv, fmt, ap);
+ va_end(ap);
+
+ return (rc);
+}
+
+int
+smbsr_decode_data(struct smb_request *sr, char *fmt, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, fmt);
+ r = smb_mbc_decode(&sr->smb_data, fmt, ap);
+ va_end(ap);
+ return (r);
+}
+
+void
+smbsr_send_reply(struct smb_request *sr)
+{
+ (void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ (void) smb_session_send(sr->session, 0, &sr->reply);
+}
+
+
+void
+smbsr_decode_error(struct smb_request *sr)
+{
+ longjmp(&sr->exjb);
+}
+
+void
+smbsr_encode_error(struct smb_request *sr)
+{
+ longjmp(&sr->exjb);
+}
+
+void
+smbsr_encode_empty_result(struct smb_request *sr)
+{
+ smbsr_encode_result(sr, 0, 0, "bw", 0, 0);
+}
+
+/*
+ * cifs_raise_error
+ *
+ * Temporary workaround to the NT status versus Win32/SMB error codes
+ * decision: just report them both here.
+ */
+void
+smbsr_raise_cifs_error(struct smb_request *sr,
+ DWORD status,
+ int error_class,
+ int error_code)
+{
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_raise_nt_error(sr, status);
+ else
+ smbsr_raise_error(sr, error_class, error_code);
+
+ /* NOTREACHED */
+}
+
+void
+smbsr_raise_error(struct smb_request *sr, int errcls, int errcod)
+{
+ sr->smb_rcls = (unsigned char)errcls;
+ sr->smb_err = (uint16_t)errcod;
+ longjmp(&sr->exjb);
+}
+
+/*
+ * smbsr_setup_nt_status
+ *
+ * Set up an NT status in the smb_request but don't long jump or try
+ * to do any error handling. There are times when we need a status set
+ * up in the response to indicate that the request has either failed
+ * or, at least, is only partially complete (possibly indicated by the
+ * severity) but we also need to return some information to the client.
+ */
+void
+smbsr_setup_nt_status(struct smb_request *sr,
+ uint32_t severity,
+ uint32_t nt_status)
+{
+ nt_status |= severity;
+ sr->smb_rcls = nt_status & 0xff;
+ sr->smb_reh = (nt_status >> 8) & 0xff;
+ sr->smb_err = nt_status >> 16;
+ sr->smb_flg2 |= SMB_FLAGS2_NT_STATUS;
+}
+
+void
+smbsr_raise_nt_error(struct smb_request *sr, uint32_t errcod)
+{
+ errcod |= 0xc0000000;
+ sr->smb_rcls = errcod & 0xff;
+ sr->smb_reh = (errcod >> 8) & 0xff;
+ sr->smb_err = errcod >> 16;
+ sr->smb_flg2 |= SMB_FLAGS2_NT_STATUS;
+ longjmp(&sr->exjb);
+}
+
+
+/*
+ * Attempt to map errno values to SMB and NT status values.
+ * Note: ESRCH is used as special case to handle a lookup
+ * failure on streams.
+ */
+static struct {
+ int unix_errno;
+ int smb_error_class;
+ int smb_error_value;
+ DWORD nt_status;
+}
+smb_errno_map[] = {
+ { ENOSPC, ERRDOS, ERROR_DISK_FULL, NT_STATUS_DISK_FULL },
+ { EDQUOT, ERRDOS, ERROR_DISK_FULL, NT_STATUS_DISK_FULL },
+ { EPERM, ERRSRV, ERRaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOTDIR, ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { EISDIR, ERRDOS, ERRbadpath, NT_STATUS_FILE_IS_A_DIRECTORY },
+ { ENOENT, ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE },
+ { ENOTEMPTY, ERRDOS, ERROR_DIR_NOT_EMPTY,
+ NT_STATUS_DIRECTORY_NOT_EMPTY },
+ { EACCES, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOMEM, ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY },
+ { EIO, ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EXDEV, ERRSRV, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+ { EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+ { ESTALE, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ { EBADF, ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ { EEXIST, ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENXIO, ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE},
+ { ESRCH, ERRDOS, ERROR_FILE_NOT_FOUND,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ /*
+ * It's not clear why smb_read_common effectively returns
+ * ERRnoaccess if a range lock prevents access and smb_write_common
+ * effectively returns ERRaccess. This table entry is used by
+ * smb_read_common and preserves the behavior that was there before.
+ */
+ { ERANGE, ERRDOS, ERRnoaccess, NT_STATUS_FILE_LOCK_CONFLICT }
+};
+
+void
+smb_errmap_unix2smb(int en, smb_error_t *smberr)
+{
+ int i;
+
+ smberr->status = NT_STATUS_UNSUCCESSFUL;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_GEN_FAILURE;
+
+ for (i = 0; i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]); ++i) {
+ if (smb_errno_map[i].unix_errno == en) {
+ smberr->status = smb_errno_map[i].nt_status;
+ smberr->errcls = smb_errno_map[i].smb_error_class;
+ smberr->errcode = smb_errno_map[i].smb_error_value;
+ return;
+ }
+ }
+}
+
+int
+smbsr_set_errno(struct smb_request *sr, int en)
+{
+ int i;
+
+ ASSERT(en != -1);
+
+ /*
+ * If the client supports 32-bit NT status values, check for
+ * an appropriate mapping and raise an NT error, control won't
+ * return here due to the longjmp in smbsr_raise_nt_error.
+ */
+ if (sr->session->capabilities & CAP_STATUS32) {
+ for (i = 0;
+ i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]);
+ ++i) {
+ if (smb_errno_map[i].unix_errno == en) {
+ smbsr_raise_nt_error(sr,
+ smb_errno_map[i].nt_status);
+ /* NOTREACHED */
+ }
+ }
+ } else {
+ for (i = 0;
+ i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]);
+ ++i) {
+ if (smb_errno_map[i].unix_errno == en) {
+ sr->smb_rcls = smb_errno_map[i].smb_error_class;
+ sr->smb_err = smb_errno_map[i].smb_error_value;
+ return (0);
+ }
+ }
+ }
+
+ sr->smb_rcls = ERRSRV;
+ sr->smb_err = ERRerror;
+ return (-1);
+}
+
+void
+smbsr_raise_errno(struct smb_request *sr, int en)
+{
+ if (smbsr_set_errno(sr, en) != 0) {
+ if (smb_dispatch_diags) {
+ cmn_err(CE_NOTE, "SmbErrno: errno=%d", en);
+ }
+ }
+
+ longjmp(&sr->exjb);
+ /* no return */
+}
+
+smb_xa_t *
+smbsr_lookup_xa(smb_request_t *sr)
+{
+ ASSERT(sr->r_xa == 0);
+
+ sr->r_xa = smb_xa_find(sr->session, sr->smb_pid, sr->smb_mid);
+ return (sr->r_xa);
+}
+
+void
+smbsr_disconnect_file(smb_request_t *sr)
+{
+ smb_ofile_t *of = sr->fid_ofile;
+
+ sr->fid_ofile = NULL;
+ (void) smb_ofile_release(of);
+}
+
+void
+smbsr_disconnect_dir(smb_request_t *sr)
+{
+ smb_odir_t *od = sr->sid_odir;
+
+ sr->sid_odir = NULL;
+ smb_odir_release(od);
+}
+
+static int
+is_andx_com(unsigned char com)
+{
+ switch (com) {
+ case SMB_COM_LOCKING_ANDX:
+ case SMB_COM_OPEN_ANDX:
+ case SMB_COM_READ_ANDX:
+ case SMB_COM_WRITE_ANDX:
+ case SMB_COM_SESSION_SETUP_ANDX:
+ case SMB_COM_LOGOFF_ANDX:
+ case SMB_COM_TREE_CONNECT_ANDX:
+ case SMB_COM_NT_CREATE_ANDX:
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Invalid command stub.
+ */
+/*ARGSUSED*/
+int
+smb_com_invalid_command(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * smb_kstat_update_dispatch
+ *
+ * This callback function updates the smb_dispatch_kstat_data when kstat
+ * command is invoked.
+ */
+/*ARGSUSED*/
+static int
+smb_kstat_update_dispatch(kstat_t *ksp, int rw)
+{
+ int i = 0, j = 0;
+
+ if (rw == KSTAT_WRITE) {
+ return (EACCES);
+ } else {
+ for (i = 0; i < 256; i++) {
+ if (dispatch[i].sdt_function) {
+ (void) memcpy(&smb_dispatch_kstat_data[j],
+ &(dispatch[i].sdt_dispatch_stats),
+ sizeof (kstat_named_t));
+ j++;
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * smb_initialize_dispatch_kstat
+ *
+ * Initialize dispatch kstats.
+ */
+void
+smb_initialize_dispatch_kstat()
+{
+ int i = 0, alloc_size = 0;
+
+ for (i = 0; i < 256; i++) {
+ if (dispatch[i].sdt_function)
+ smb_dispatch_kstat_size++;
+ }
+
+ alloc_size = smb_dispatch_kstat_size * sizeof (kstat_named_t);
+ smb_dispatch_kstat_data = (kstat_named_t *)
+ kmem_zalloc(alloc_size, KM_SLEEP);
+
+ smb_dispatch_ksp = kstat_create("smb", 0, "smb_dispatch_all", "misc",
+ KSTAT_TYPE_NAMED, alloc_size/sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
+ if (smb_dispatch_ksp) {
+ smb_dispatch_ksp->ks_data = smb_dispatch_kstat_data;
+ smb_dispatch_ksp->ks_update = smb_kstat_update_dispatch;
+ kstat_install(smb_dispatch_ksp);
+ }
+}
+
+/*
+ * smb_remove_dispatch_kstat
+ *
+ * Remove dispatch kstats.
+ */
+void
+smb_remove_dispatch_kstat()
+{
+ if (smb_dispatch_kstat_data != NULL)
+ kmem_free(smb_dispatch_kstat_data,
+ smb_dispatch_kstat_size * sizeof (kstat_named_t));
+
+ if (smb_dispatch_ksp != NULL) {
+ kstat_delete(smb_dispatch_ksp);
+ smb_dispatch_ksp = NULL;
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_echo.c b/usr/src/uts/common/fs/smbsrv/smb_echo.c
new file mode 100644
index 0000000000..8a386c9959
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_echo.c
@@ -0,0 +1,132 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * The echo request is used to test the connection to the server,
+ * and to see if the server is still responding. The tid is ignored,
+ * so this request may be sent to the server even if there are no
+ * tree connections to the server.
+ *
+ * Each response echoes the data sent, though ByteCount may indicate
+ * no data. If echo-count is zero, no response is sent.
+ */
+int
+smb_com_echo(struct smb_request *sr)
+{
+ unsigned short necho;
+ unsigned short nbytes;
+ unsigned short i;
+ struct mbuf_chain reply;
+ char *data;
+
+ if (smbsr_decode_vwv(sr, "w", &necho) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ nbytes = sr->smb_bcc;
+
+ data = smbsr_malloc(&sr->request_storage, nbytes);
+
+ (void) smb_decode_mbc(&sr->smb_data, "#c", nbytes, data);
+
+ for (i = 1; i <= necho; ++i) {
+
+ MBC_INIT(&reply, SMB_HEADER_ED_LEN + 10 + nbytes);
+
+ (void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ (void) smb_encode_mbc(&reply, "bww#c", 1, i,
+ nbytes, nbytes, data);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, &reply);
+
+ (void) smb_session_send(sr->session, 0, &reply);
+ }
+
+ return (SDRC_NO_REPLY);
+}
+
+/*
+ * Broadcast messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_broadcast_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Multi-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_end_mb_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Single-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_single_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Multi-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_start_mb_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*
+ * Multi-block messages are not supported.
+ */
+int /*ARGSUSED*/
+smb_com_send_text_mb_message(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fem.c b/usr/src/uts/common/fs/smbsrv/smb_fem.c
new file mode 100644
index 0000000000..1248a0a66b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c
@@ -0,0 +1,285 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <sys/sdt.h>
+#include <sys/vfs.h>
+#include <sys/vfs_opreg.h>
+#include <sys/vnode.h>
+#include <sys/fem.h>
+
+fem_t *smb_fcn_ops = NULL;
+
+int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int,
+ vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
+int smb_fem_fcn_remove(femarg_t *, char *, cred_t *,
+ caller_context_t *, int);
+int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *,
+ cred_t *, caller_context_t *, int);
+int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **,
+ cred_t *, caller_context_t *, int, vsecattr_t *);
+int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *,
+ char *, cred_t *, caller_context_t *, int);
+
+static const fs_operation_def_t smb_fcn_tmpl[] = {
+ VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create },
+ VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove},
+ VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename},
+ VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir},
+ VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir},
+ VOPNAME_LINK, {.femop_link = smb_fem_fcn_link},
+ VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink},
+ NULL, NULL
+};
+
+int
+smb_fem_init()
+{
+ return (fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops));
+}
+
+void
+smb_fem_shutdown()
+{
+ if (smb_fcn_ops)
+ fem_free(smb_fcn_ops);
+}
+
+void
+smb_fem_fcn_install(smb_node_t *node)
+{
+ (void) fem_install(node->vp, smb_fcn_ops, (void *)node, OPARGUNIQ,
+ (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release);
+}
+
+void
+smb_fem_fcn_uninstall(smb_node_t *node)
+{
+ (void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node);
+}
+
+/*
+ * smb_fem_fcn_create()
+ *
+ * This monitor will catch only changes to VREG files and not to extended
+ * attribute files. This is fine because, for CIFS files, stream creates
+ * should not trigger any file change notification on the VDIR directory
+ * being monitored. Creates of any other kind of extended attribute in
+ * the directory will also not trigger any file change notification on the
+ * VDIR directory being monitored.
+ */
+
+int
+smb_fem_fcn_create(
+ femarg_t *arg,
+ char *name,
+ vattr_t *vap,
+ vcexcl_t excl,
+ int mode,
+ vnode_t **vpp,
+ cred_t *cr,
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+/*
+ * smb_fem_fcn_remove()
+ *
+ * This monitor will catch only changes to VREG files and to not extended
+ * attribute files. This is fine because, for CIFS files, stream deletes
+ * should not trigger any file change notification on the VDIR directory
+ * being monitored. Deletes of any other kind of extended attribute in
+ * the directory will also not trigger any file change notification on the
+ * VDIR directory being monitored.
+ */
+
+int
+smb_fem_fcn_remove(
+ femarg_t *arg,
+ char *name,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_remove(arg, name, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_rename(
+ femarg_t *arg,
+ char *snm,
+ vnode_t *tdvp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_mkdir(
+ femarg_t *arg,
+ char *name,
+ vattr_t *vap,
+ vnode_t **vpp,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_rmdir(
+ femarg_t *arg,
+ char *name,
+ vnode_t *cdir,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_rmdir(arg, name, cdir, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_link(
+ femarg_t *arg,
+ vnode_t *svp,
+ char *tnm,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_link(arg, svp, tnm, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
+
+int
+smb_fem_fcn_symlink(
+ femarg_t *arg,
+ char *linkname,
+ vattr_t *vap,
+ char *target,
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
+{
+ smb_node_t *dnode;
+ int error;
+
+ dnode = (smb_node_t *)arg->fa_fnode->fn_available;
+
+ ASSERT(dnode);
+
+ error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags);
+
+ if (error == 0)
+ smb_process_node_notify_change_queue(dnode);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c
new file mode 100644
index 0000000000..1492219714
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c
@@ -0,0 +1,440 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_find
+ *
+ * Request Format: (same as core Search Protocol - "Find First" form)
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 2
+ * WORD smb_count; max number of entries to find
+ * WORD smb_attr; search attribute
+ * WORD smb_bcc; minimum value = 5
+ * BYTE smb_ident1; ASCII (04)
+ * BYTE smb_pathname[]; filename (may contain global characters)
+ * BYTE smb_ident2; Variable Block (05)
+ * WORD smb_keylen; resume key length (zero if "Find First")
+ * BYTE smb_resumekey[*]; "Find Next" key, * = value of smb_keylen
+ *
+ * Response Format: (same as core Search Protocol)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_wct; value = 1
+ * WORD smb_count; number of entries found
+ * WORD smb_bcc; minimum value = 3
+ * BYTE smb_ident; Variable Block (05)
+ * WORD smb_datalen; data length
+ * BYTE smb_data[*]; directory entries
+ *
+ * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
+ *
+ * BYTE find_buf_reserved[21]; reserved (resume_key)
+ * BYTE find_buf_attr; attribute
+ * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx)
+ * where 'xxxxx' is in 2 second increments
+ * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd)
+ * DWORD find_buf_size; file size
+ * STRING find_buf_pname[13]; file name -- ASCII (null terminated)
+ *
+ * The resume_key has the following format:
+ *
+ * BYTE sr_res; reserved:
+ * bit 7 - reserved for consumer use
+ * bit 5,6 - reserved for system use
+ * (must be preserved)
+ * bits 0-4 - reserved for server
+ * (must be preserved)
+ * BYTE sr_name[11]; pathname sought.
+ * Format: 1-8 character file name,
+ * left justified 0-3 character extension,
+ * BYTE sr_findid[1]; uniquely identifies find through
+ * find_close
+ * BYTE sr_server[4]; available for server use
+ * (must be non-zero)
+ * BYTE sr_res[4]; reserved for consumer use
+ *
+ * Service:
+ *
+ * The Find protocol finds the directory entry or group of entries matching the
+ * specified file pathname. The filename portion of the pathname may contain
+ * global (wild card) characters.
+ *
+ * The Find protocol is used to match the find OS/2 system call. The protocols
+ * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
+ * a directory. These protocols may be used in place of the core "Search"
+ * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
+ * where the Search protocol will still be used.
+ *
+ * The format of the Find protocol is the same as the core "Search" protocol.
+ * The difference is that the directory is logically Opened with a Find protocol
+ * and logically closed with the Find Close protocol. This allows the Server to
+ * make better use of its resources. Search buffers are thus held (allowing
+ * search resumption via presenting a "resume_key") until a Find Close protocol
+ * is received. The sr_findid field of each resume key is a unique identifier
+ * (within the session) of the search from "Find" through "Find close". Thus if
+ * the consumer does "Find ahead", any find buffers containing resume keys with
+ * the matching find id may be released when the Find Close is requested.
+ *
+ * As is true of a failing open, if a Find request (Find "first" request where
+ * resume_key is null) fails (no entries are found), no find close protocol is
+ * expected.
+ *
+ * If no global characters are present, a "Find Unique" protocol should be used
+ * (only one entry is expected and find close need not be sent).
+ *
+ * The file path name in the request specifies the file to be sought. The
+ * attribute field indicates the attributes that the file must have. If the
+ * attribute is zero then only normal files are returned. If the system file,
+ * hidden or directory attributes are specified then the search is inclusive --
+ * both the specified type(s) of files and normal files are returned. If the
+ * volume label attribute is specified then the search is exclusive, and only
+ * the volume label entry is returned
+ *
+ * The max-count field specifies the number of directory entries to be returned.
+ * The response will contain zero or more directory entries as determined by the
+ * count-returned field. No more than max-count entries will be returned. Only
+ * entries that match the sought filename/attribute will be returned.
+ *
+ * The resume_key field must be null (length = 0) on the initial ("Find First")
+ * find request. Subsequent find requests intended to continue a search must
+ * contain the resume_key field extracted from the last directory entry of the
+ * previous response. The resume_key field is self-contained, for on calls
+ * containing a resume_key neither the attribute or pathname fields will be
+ * valid in the request. A find request will terminate when either the
+ * requested maximum number of entries that match the named file are found, or
+ * the end of directory is reached without the maximum number of matches being
+ * found. A response containing no entries indicates that no matching entries
+ * were found between the starting point of the search and the end of directory.
+ *
+ * There may be multiple matching entries in response to a single request as
+ * Find supports "wild cards" in the file name (last component of the pathname).
+ * "?" is the wild single characters, "*" or "null" will match any number of
+ * filename characters within a single part of the filename component. The
+ * filename is divided into two parts -- an eight character name and a three
+ * character extension. The name and extension are divided by a ".".
+ *
+ * If a filename part commences with one or more "?"s then exactly that number
+ * of characters will be matched by the Wild Cards, e.g., "??x" will equal "abx"
+ * but not "abcx" or "ax". When a filename part has trailing "?"s then it will
+ * match the specified number of characters or less, e.g., "x??" will match
+ * "xab", "xa" and "x", but not "xabc". If only "?"s are present in the filename
+ * part, then it is handled as for trailing "?"s "*" or "null" match entire
+ * pathname parts, thus "*.abc" or ".abc" will match any file with an extension
+ * of "abc". "*.*", "*" or "null" will match all files in a directory.
+ *
+ * Unprotected servers require the requester to have read permission on the
+ * subtree containing the directory searched (the share specifies read
+ * permission).
+ *
+ * Protected servers require the requester to have permission to search the
+ * specified directory.
+ *
+ * If a Find requests more data than can be placed in a message of the
+ * max-xmit-size for the TID specified, the server will return only the number
+ * of entries which will fit.
+ *
+ * The number of entries returned will be the minimum of:
+ * 1. The number of entries requested.
+ * 2. The number of (complete) entries that will fit in the negotiated SMB
+ * buffer.
+ * 3. The number of entries that match the requested name pattern and
+ * attributes.
+ *
+ * The error ERRnofiles set in smb_err field of the response header or a zero
+ * value in smb_count of the response indicates no matching entry was found.
+ *
+ * The resume search key returned along with each directory entry is a server
+ * defined key which when returned in the Find Next protocol, allows the
+ * directory search to be resumed at the directory entry fol lowing the one
+ * denoted by the resume search key.
+ *
+ * The date is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * y y y y y y y m m m m d d d d d
+ * where:
+ * y - bit of year 0-119 (1980-2099)
+ * m - bit of month 1-12
+ * d - bit of day 1-31
+ *
+ * The time is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * h h h h h m m m m m m x x x x x
+ * where:
+ * h - bit of hour (0-23)
+ * m - bit of minute (0-59)
+ * x - bit of 2 second increment
+ *
+ * Find may generate the following errors.
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRbadaccess
+ * ERRDOS/ERRbadshare
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRinvnid
+ */
+int
+smb_com_find(struct smb_request *sr)
+{
+ int rc;
+ unsigned short sattr, count, maxcount;
+ char *path;
+ char filename[14];
+ uint32_t cookie;
+ struct smb_node *node;
+ unsigned char type;
+ unsigned short key_len;
+ smb_odir_context_t *pc;
+
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len) != 0) ||
+ (type != 0x05)) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (key_len == 0) { /* begin search */
+ (void) smb_rdir_open(sr, path, sattr);
+ cookie = 0;
+ } else if (key_len == 21) {
+ sr->smb_sid = 0;
+ if (smb_decode_mbc(&sr->smb_data, SMB_RESUME_KEY_FMT,
+ filename, &sr->smb_sid, &cookie) != 0) {
+ /* We don't know which rdir to close */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
+ sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ cookie--; /* +1 when returned */
+ } else {
+ /* We don't know which rdir to close */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+ pc = MEM_ZALLOC("smb", sizeof (*pc));
+ pc->dc_cookie = cookie;
+ count = 0;
+ node = (struct smb_node *)0;
+ rc = 0;
+ while (count < maxcount) {
+ if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+ break;
+
+ (void) smb_encode_mbc(&sr->reply, ".8c3cbl4.bYl13c",
+ pc->dc_name83, pc->dc_name83+9, sr->smb_sid,
+ pc->dc_cookie+1, pc->dc_dattr,
+ smb_gmt_to_local_time(pc->dc_attr.sa_vattr.va_mtime.tv_sec),
+ (int32_t)smb_node_get_size(node, &pc->dc_attr),
+ (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name);
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ count++;
+ }
+ MEM_FREE("smb", pc);
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* returned error by smb_rdir_next() */
+ smb_rdir_close(sr);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (count == 0) {
+ smb_rdir_close(sr);
+ smbsr_raise_error(sr, ERRDOS, ERRnofiles);
+ /* NOTREACHED */
+ }
+
+ rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
+ if (smb_poke_mbc(&sr->reply, sr->cur_reply_offset,
+ "bwwbw", 1, count, rc+3, 5, rc) < 0) {
+ smb_rdir_close(sr);
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_com_find_close
+ *
+ * Request Format: (same as core Search Protocol - "Find Next" form)
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 2
+ * WORD smb_count; max number of entries to find
+ * WORD smb_attr; search attribute
+ * WORD smb_bcc; minimum value = 5
+ * BYTE smb_ident1; ASCII (04)
+ * BYTE smb_pathname[]; null (may contain only null)
+ * BYTE smb_ident2; Variable Block (05)
+ * WORD smb_keylen; resume (close) key length
+ * (may not be zero)
+ * BYTE smb_resumekey[*]; "Find Close" key
+ * (* = value of smb_keylen)
+ *
+ * Response Format: (same format as core Search Protocol)
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 1
+ * WORD smb_reserved; reserved
+ * WORD smb_bcc; value = 3
+ * BYTE smb_ident; Variable Block (05)
+ * WORD smb_datalen; data length (value = 0)
+ *
+ * The resume_key (or close key) has the following format:
+ *
+ * BYTE sr_res; reserved:
+ * bit 7 - reserved for consumer use
+ * bit 5,6 - reserved for system use
+ * (must be preserved)
+ * bits 0-4 - rsvd for server
+ * (must be preserved by consumer)
+ * BYTE sr_name[11]; pathname sought.
+ * Format: 1-8 character file name,
+ * left justified 0-3 character extension,
+ * left justified (in last 3 chars)
+ * BYTE sr_findid[1]; uniquely identifies find
+ * through find_close
+ * BYTE sr_server[4]; available for server use
+ * (must be non-zero)
+ * BYTE sr_res[4]; reserved for consumer use
+ *
+ * Service:
+ *
+ * The Find_Close protocol closes the association between a Find id
+ * returned (in the resume_key) by the Find protocol and the directory
+ * search.
+ *
+ * Whereas the First Find protocol logically opens the directory,
+ * subsequent find protocols presenting a resume_key further "read" the
+ * directory, the Find Close protocol "closes" the directory allowing the
+ * server to free any resources held in support of the directory search.
+ *
+ * The Find Close protocol is used to match the find Close OS/2
+ * system call. The protocols "Find", "Find Unique" and "Find Close" are
+ * methods of reading (or searching) a directory. These protocols may
+ * be used in place of the core "Search" protocol when LANMAN 1.0 dialect has
+ * been negotiated. There may be cases where the Search protocol will still be
+ * used.
+ *
+ * Although only the find id portion the resume key should be
+ * required to identify the search being ter minated, the entire
+ * resume_key as returned in the previous Find, either a "Find First" or "Find
+ * Next" is sent to the server in this protocol.
+ *
+ * Find Close may generate the following errors:
+ *
+ * ERRDOS/ERRbadfid
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ */
+int
+smb_com_find_close(struct smb_request *sr)
+{
+ unsigned short sattr, maxcount;
+ char *path;
+ char filename[14];
+ uint32_t cookie;
+ unsigned char type;
+ unsigned short key_len;
+ int rc;
+
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
+ if ((rc != 0) || (type != 0x05)) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (key_len == 0) { /* begin search */
+ smbsr_raise_error(sr, ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (key_len == 21) {
+ sr->smb_sid = 0;
+ if (smb_decode_mbc(&sr->smb_data, SMB_RESUME_KEY_FMT,
+ filename, &sr->smb_sid, &cookie) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
+ sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ cookie--; /* +1 when returned */
+ } else {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ smb_rdir_close(sr);
+ smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c b/usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c
new file mode 100644
index 0000000000..46a9953b55
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_find_notify_close.c
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_cmd; FIND_NOTIFY_CLOSE
+ * BYTE smb_wct; value = 1
+ * WORD smb_handle; Find notify handle
+ * WORD smb_bcc; value = 0
+ *
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * BYTE smb_cmd; FIND_NOTIFY_CLOSE
+ * BYTE smb_wct; value = 0
+ * WORD smb_bcc; value = 0
+ *
+ * The FIND_NOTIFY_CLOSE request closes the association between a
+ * directory handle returned following a resource monitor, established
+ * using a TRANS2_FIND_NOTIFY_FIRST request to the server, and the
+ * resulting system directory monitor. This request allows the server
+ * to free any resources held in support of the open handle.
+ *
+ * The Find Close protocol is used to match the DosFindNotifyClose
+ * OS/2 system call.
+ *
+ * Find Notify Close may generate the following errors.
+ *
+ * ERRDOS/ERRbadfid
+ * ERRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/<implementation specific>
+ * ERRHRD/<implementation specific>
+ */
+
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_find_notify_close
+ *
+ * As far as I can tell, this part of the protocol is not implemented
+ * by NT server.
+ */
+int /*ARGSUSED*/
+smb_com_find_notify_close(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find_unique.c b/usr/src/uts/common/fs/smbsrv/smb_find_unique.c
new file mode 100644
index 0000000000..59f9ba12b2
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_find_unique.c
@@ -0,0 +1,286 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * Request Format: (same as core Search Protocol - "Find First" form)
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * BYTE smb_wct; value = 2
+ * WORD smb_count; max number of entries to find
+ * WORD smb_attr; search attribute
+ * WORD smb_bcc; minimum value = 5
+ * BYTE smb_ident1; ASCII (04)
+ * BYTE smb_pathname[]; filename (may contain global characters)
+ * BYTE smb_ident2; Variable Block (05)
+ * WORD smb_keylen; must be zero ("Find First" only)
+ *
+ * Response Format: (same as core Search Protocol)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_wct; value = 1
+ * WORD smb_count; number of entries found
+ * WORD smb_bcc; minimum value = 3
+ * BYTE smb_ident; Variable Block (05)
+ * WORD smb_datalen; data length
+ * BYTE smb_data[*]; directory entries
+ *
+ * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
+ *
+ * BYTE find_buf_reserved[21]; reserved (resume_key)
+ * BYTE find_buf_attr; attribute
+ * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx)
+ * where 'xxxxx' is in 2 second increments
+ * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd)
+ * DWORD find_buf_size; file size
+ * STRING find_buf_pname[13]; file name -- ASCII (null terminated)
+ *
+ * The resume_key has the following format:
+ *
+ * BYTE sr_res; reserved:
+ * bit 7 - reserved for consumer use
+ * bit 5,6 - reserved for system use
+ * (must be preserved)
+ * bits 0-4 - reserved for server
+ * (must be preserved)
+ * BYTE sr_name[11]; pathname sought.
+ * Format: 1-8 character file name,
+ * left justified 0-3 character extension,
+ * BYTE sr_findid[1]; uniquely identifies find through
+ * find_close
+ * BYTE sr_server[4]; available for server use
+ * (must be non-zero)
+ * BYTE sr_res[4]; reserved for consumer use
+ *
+ * Service:
+ *
+ * The Find protocol finds the directory entry or group of entries matching the
+ * specified file pathname. The filename portion of the pathname may contain
+ * global (wild card) characters. The search may not be resumed and no Find
+ * Close protocol is expected.
+ *
+ * The Find protocol is used to match the find OS/2 system call. The protocols
+ * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
+ * a directory. These protocols may be used in place of the core "Search"
+ * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
+ * where the Search protocol will still be used.
+ *
+ * The format of the Find Unique protocol is the same as the core "Search"
+ * protocol. The difference is that the directory is logically opened ,
+ * any matching entries returned, and then the directory is logically
+ * closed.
+ *
+ * This allows the Server to make better use of its resources. No Search buffers
+ * are held (search resumption via presenting a "resume_key" will not be
+ * allowed).
+ *
+ * Only one buffer of entries is expected and find close need not be sent).
+ *
+ * The file path name in the request specifies the file to be
+ * sought. The attribute field indicates the attributes that the file
+ * must have. If the attribute is zero then only normal files are
+ * returned. If the system file, hidden or directory attributes are
+ * specified then the search is inclusive -- both the specified type(s)
+ * of files and normal files are returned. If the volume label attribute
+ * is specified then the search is exclusive, and only the volume label entry
+ * is returned
+ *
+ * The max-count field specifies the number of directory entries to be
+ * returned. The response will contain zero or more directory entries
+ * as determined by the count-returned field. No more than max-count
+ * entries will be returned. Only entries that match the sought
+ * filename/attribute will be returned.
+ *
+ * The resume_key field must be null (length = 0).
+ *
+ * A Find_Unique request will terminate when either the requested maximum
+ * number of entries that match the named file are found, or the end
+ * of directory is reached without the maximum number of matches being
+ * found. A response containing no entries indicates that no matching
+ * entries were found between the starting point of the search and the end of
+ * directory.
+ *
+ * There may be multiple matching entries in response to a single
+ * request as Find Unique supports "wild cards" in the file name (last
+ * component of the pathname). "?" is the wild card for single
+ * characters, "*" or "null" will match any number of filename characters
+ * within a single part of the filename component. The filename is
+ * divided into two parts -- an eight character name and a three
+ * character extension. The name and extension are divided by a ".".
+ *
+ * If a filename part commences with one or more "?"s then exactly
+ * that number of characters will be matched by the Wild Cards, e.g.,
+ * "??x" will equal "abx" but not "abcx" or "ax". When a filename part has
+ * trailing "?"s then it will match the specified number of characters
+ * or less, e.g., "x??" will match "xab", "xa" and "x", but not "xabc". If
+ * only "?"s are present in the filename part, then it is handled as
+ * for trailing "?"s
+ *
+ * "*" or "null" match entire pathname parts, thus "*.abc" or ".abc" will
+ * match any file with an extension of "abc". "*.*", "*" or "null" will
+ * match all files in a directory.
+ *
+ * Unprotected servers require the requester to have read permission on the
+ * subtree containing the directory searched, the share specifies read
+ * permission.
+ *
+ * Protected servers require the requester to have permission to search the
+ * specified directory.
+ *
+ * If a Find Unique requests more data than can be placed in a
+ * message of the max-xmit-size for the TID specified, the server will
+ * abort the virtual circuit to the consumer.
+ *
+ * The number of entries returned will be the minimum of:
+ *
+ * 1. The number of entries requested.
+ * 2. The number of complete entries that will fit in the
+ * negotiated SMB buffer.
+ * 3. The number of entries that match the requested name pattern and
+ * attributes.
+ *
+ * The error ERRnofiles set in smb_err field of the response header or a zero
+ * value in smb_count of the response indicates no matching entry was found.
+ *
+ * The resume search key returned along with each directory entry is a server
+ * defined key. This key will be returned as in the Find protocol and Search
+ * protocol however it may NOT be returned to continue the search.
+ *
+ * The date is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * y y y y y y y m m m m d d d d d
+ * where:
+ * y - bit of year 0-119 (1980-2099)
+ * m - bit of month 1-12
+ * d - bit of day 1-31
+ *
+ * The time is in the following format:
+ * bits:
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * h h h h h m m m m m m x x x x x
+ * where:
+ * h - bit of hour (0-23)
+ * m - bit of minute (0-59)
+ * x - bit of 2 second increment
+ *
+ * Find Unique may generate the following errors.
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadpath
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRbadaccess
+ * ERRDOS/ERRbadshare
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRinvnid
+ */
+int
+smb_com_find_unique(struct smb_request *sr)
+{
+ int rc;
+ unsigned short sattr, count, maxcount;
+ char *path;
+ struct vardata_block *vdb;
+ struct smb_node *node;
+ smb_odir_context_t *pc;
+
+ vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (vdb->len != 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+ /* begin search */
+ (void) smb_rdir_open(sr, path, sattr);
+
+ pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
+ pc->dc_cookie = 0;
+ count = 0;
+ node = (struct smb_node *)0;
+ rc = 0;
+ while (count < maxcount) {
+ if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+ break;
+
+ (void) smb_encode_mbc(&sr->reply, ".8c3cbl4.bYl13c",
+ pc->dc_name83, pc->dc_name83+9, sr->smb_sid,
+ pc->dc_cookie+1, pc->dc_dattr,
+ smb_gmt_to_local_time(pc->dc_attr.sa_vattr.va_mtime.tv_sec),
+ (int32_t)smb_node_get_size(node, &pc->dc_attr),
+ (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name);
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ count++;
+ }
+ kmem_free(pc, sizeof (*pc));
+
+ smb_rdir_close(sr);
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* returned error by smb_rdir_next() */
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (count == 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_raise_error(sr, ERRDOS, ERRnofiles);
+ /* NOTREACHED */
+ }
+
+ rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
+ if (smb_poke_mbc(&sr->reply, sr->cur_reply_offset,
+ "bwwbw", 1, count, rc+3, 5, rc) < 0) {
+ kmem_free(vdb, sizeof (struct vardata_block));
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+ kmem_free(vdb, sizeof (struct vardata_block));
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_flush.c b/usr/src/uts/common/fs/smbsrv/smb_flush.c
new file mode 100644
index 0000000000..b9cfb8c349
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_flush.c
@@ -0,0 +1,129 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The flush SMB is sent to ensure all data and allocation information
+ * for the corresponding file has been written to stable storage. This
+ * is a synchronous request. The response should not be sent until the
+ * writes are complete.
+ *
+ * The SmbFlush request is described in CIFS/1.0 1996 Section 3.9.14.
+ *
+ * CIFS/1.0 June 13, 1996
+ * Heizer, et al
+ * draft-heizer-cifs-v1-spec-00.txt
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+
+static void smb_flush_file(struct smb_request *sr, struct smb_ofile *ofile);
+
+
+int smb_flush_required = 1;
+
+
+/*
+ * smb_commit_required
+ *
+ * Specify whether or not SmbFlush should send commit requests to the
+ * file system. If state is non-zero, commit requests will be sent to
+ * the file system. If state is zero, SmbFlush is a no-op.
+ */
+void
+smb_commit_required(int state)
+{
+ smb_flush_required = state;
+}
+
+
+/*
+ * smb_com_flush
+ *
+ * Flush any cached data for a specified file, or for all files that
+ * this client has open, to stable storage. If the fid is valid (i.e.
+ * not 0xFFFF), we flush only that file. Otherwise we flush all files
+ * associated with this client.
+ *
+ * We need to protect the list because there's a good chance we'll
+ * block during the flush operation.
+ */
+int
+smb_com_flush(smb_request_t *sr)
+{
+ smb_ofile_t *file;
+ smb_llist_t *flist;
+
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smb_flush_required == 0) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ if (sr->smb_fid != 0xffff) {
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ smb_flush_file(sr, sr->fid_ofile);
+ } else {
+ flist = &sr->tid_tree->t_ofile_list;
+ smb_llist_enter(flist, RW_READER);
+ file = smb_llist_head(flist);
+ while (file) {
+ mutex_enter(&file->f_mutex);
+ smb_flush_file(sr, file);
+ mutex_exit(&file->f_mutex);
+ file = smb_llist_next(flist, file);
+ }
+ smb_llist_exit(flist);
+ }
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_flush_file
+ *
+ * If writes on this file are not synchronous, flush it using the NFSv3
+ * commit interface.
+ */
+static void smb_flush_file(struct smb_request *sr, struct smb_ofile *ofile)
+{
+ if ((ofile->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0)
+ (void) smb_fsop_commit(sr, sr->user_cr, ofile->f_node);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_forward.c b/usr/src/uts/common/fs/smbsrv/smb_forward.c
new file mode 100644
index 0000000000..498e3bcaa7
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_forward.c
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides the SMB ForwardUserName interface:
+ * smb_com_forward_user_name
+ * smb_com_cancel_forward
+ * smb_com_get_machine_name
+ *
+ * The description of this interface is taken verbatim from the netmon
+ * SMB protocol help. These functions are currently empty stubs that
+ * return SDRC_UNIMPLEMENTED.
+ */
+
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_forward_user_name
+ *
+ * This command informs the server that it should accept messages sent
+ * to the forwarded name. The name specified in this message does not
+ * include the one byte suffix ("03" or "05").
+ *
+ * Client Request Description
+ * ================================== =================================
+ * BYTE smb_com SMBfwdname
+ * BYTE smb_wct 0
+ * BYTE smb_bcc min = 2
+ * BYTE smb_buf[] ASCII -- 04
+ * forwarded name (max 15 bytes)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_com SMBfwdname
+ * BYTE smb_wct 0
+ * BYTE smb_bcc 0
+ *
+ * ForwardUserName may generate the following errors.
+ * ERRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/ERRrmuns
+ * ERRSRV/<implementation specific>
+ * ERRHRD/<implementation specific>
+ */
+int /*ARGSUSED*/
+smb_com_forward_user_name(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_cancel_forward
+ *
+ * The CancelForward command cancels the effect of a prior ForwardUserName
+ * command. The addressed server will no longer accept messages for the
+ * designated user name. The name specified in this message does not
+ * include the one byte suffix ("05").
+ *
+ * Client Request Description
+ * ================================== =================================
+ * BYTE smb_com SMBcancelf
+ * BYTE smb_wct 0
+ * BYTE smb_bcc min = 2
+ * BYTE smb_buf[] ASCII -- 04
+ * forwarded name (max 15 bytes)
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_com SMBcancelf
+ * BYTE smb_wct 0
+ * BYTE smb_bcc 0
+ *
+ * CancelForward may generate the following errors.
+ * ERRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/<implementation specific>
+ * ERRHRD/<implementation specific>
+ */
+int /*ARGSUSED*/
+smb_com_cancel_forward(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_get_machine_name
+ *
+ * The GetMachineName command obtains the machine name of the target machine.
+ * It is used prior to the CancelForward command to determine to which
+ * machine the CancelForward command should be sent. GetMachineName is sent
+ * to the forwarded name to be canceled, and the server then returns the
+ * machine name to which the CancelForward command must be sent.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * BYTE smb_com SMBgetmac
+ * BYTE smb_wct 0
+ * BYTE smb_bcc 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ * BYTE smb_com SMBgetmac
+ * BYTE smb_wct 0
+ * BYTE smb_bcc min = 2
+ * BYTE smb_buf[] ASCII -- 04
+ * machine name (max 15 bytes)
+ *
+ * GetMachineName may return the following errors.
+ * ERRRDOS/<implementation specific>
+ * ERRSRV/ERRerror
+ * ERRSRV/ERRinvnid
+ * ERRSRV/<implementation specific>
+ */
+int /*ARGSUSED*/
+smb_com_get_machine_name(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsd.c b/usr/src/uts/common/fs/smbsrv/smb_fsd.c
new file mode 100644
index 0000000000..354b7d3487
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsd.c
@@ -0,0 +1,276 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/feature_tests.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+#include <smbsrv/string.h>
+#include <smbsrv/smb_vops.h>
+
+fs_desc_t null_fsd = {0, 0};
+extern vfs_t *rootvfs;
+
+static void fsd_getname(vfs_t *vfsp, fsvol_attr_t *vol_attr);
+static void fsd_getflags(vfs_t *vfsp, unsigned *flags);
+static void fsd_getseq(vfs_t *vfsp, uint32_t *fs_sequence);
+static void fsd_name_from_mntpoint(char *, const char *, size_t);
+
+/*
+ * The "pathname" parameter may be either a path name or a volume name.
+ * Kernel caller must call fsd_rele(vfsp).
+ * User space caller will not have a hold on the fs.
+ */
+
+void *
+fsd_lookup(char *name, unsigned flags, fs_desc_t *fsd)
+{
+ int (*func)(const char *, const char *);
+ struct vfs *vfsp, *vfs_found = NULL;
+ refstr_t *vfs_mntpoint;
+ char vfs_volname[VOL_NAME_MAX];
+ char volname[VOL_NAME_MAX];
+
+ if (fsd)
+ *fsd = null_fsd;
+
+ vfs_list_read_lock();
+ vfsp = rootvfs;
+
+ func = (flags & FSOLF_CASE_INSENSITIVE) ? utf8_strcasecmp : strcmp;
+
+ fsd_name_from_mntpoint(volname, name, VOL_NAME_MAX);
+
+ do {
+ vfs_mntpoint = vfsp->vfs_mntpt;
+ refstr_hold(vfs_mntpoint);
+
+ fsd_name_from_mntpoint(vfs_volname, vfs_mntpoint->rs_string,
+ VOL_NAME_MAX);
+
+ if (func(volname, vfs_volname) == 0) {
+ VFS_HOLD(vfsp);
+ vfs_found = vfsp;
+
+ if (fsd) {
+ *fsd = vfsp->vfs_fsid;
+ }
+ refstr_rele(vfs_mntpoint);
+ break;
+ } else {
+ refstr_rele(vfs_mntpoint);
+ }
+ vfsp = vfsp->vfs_next;
+
+ } while (vfsp != rootvfs);
+
+ vfs_list_unlock();
+ return (vfs_found);
+}
+
+/*
+ * Compare two volume descriptors to determine whether or not they
+ * refer to the same volume. Returns 0 if the descriptors refer to
+ * the same volume. Otherwise returns 1.
+ */
+
+int
+fsd_cmp(fs_desc_t *fsd1, fs_desc_t *fsd2)
+{
+ if ((fsd1->val[0] == fsd2->val[0]) && (fsd1->val[1] == fsd2->val[1])) {
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * fsd_getattr
+ *
+ * Obtain volume attributes. If the volume is mounted, the attributes
+ * are copied to vol_attr. Otherwise, vol_attr is zero'd.
+ *
+ * Returns 0 on success. Otherwise an errno is returned to indicate
+ * the error.
+ */
+
+int
+fsd_getattr(fs_desc_t *fsd, fsvol_attr_t *vol_attr)
+{
+ vfs_t *vfsp;
+
+ ASSERT(fsd);
+ ASSERT(vol_attr);
+
+ if ((vfsp = getvfs(fsd)) == NULL)
+ return (ESTALE);
+
+ bzero(vol_attr, sizeof (fsvol_attr_t));
+ fsd_getname(vfsp, vol_attr);
+ fsd_getflags(vfsp, &vol_attr->flags);
+ fsd_getseq(vfsp, &vol_attr->fs_sequence);
+
+ VFS_RELE(vfsp);
+ return (0);
+}
+
+/*
+ * Check whether or not a file system supports the features identified
+ * by flags. Flags can be any combination of the FSOLF flags.
+ * Returns 1 if all of the features are supported. Otherwise returns 0.
+ * Exception: Returns -1 if stale fsd.
+ */
+
+int
+fsd_chkcap(fs_desc_t *fsd, unsigned flags)
+{
+ vfs_t *vfsp = getvfs(fsd);
+ unsigned getflags = 0;
+
+ if (!vfsp) {
+ return (-1);
+ }
+
+ fsd_getflags(vfsp, &getflags);
+
+ VFS_RELE(vfsp);
+
+ if ((flags != 0) && (getflags & flags) == flags) {
+ return (1);
+ }
+
+ return (0);
+}
+
+void *
+fsd_hold(fs_desc_t *fsd)
+{
+ void *vfsp = getvfs(fsd);
+
+ return (vfsp);
+}
+
+void
+fsd_rele(void *vfsp)
+{
+ ASSERT(vfsp);
+
+ VFS_RELE((vfs_t *)vfsp);
+}
+
+/*
+ * Returns volume name.
+ * Also fills in vol_attr->fs_typename (needed for fsd_getattr()).
+ *
+ * File system types are hardcoded in uts/common/os/vfs_conf.c .
+ */
+
+static void
+fsd_getname(vfs_t *vfsp, fsvol_attr_t *vol_attr)
+{
+ refstr_t *vfs_mntpoint;
+
+ (void) strlcpy(vol_attr->fs_typename,
+ vfssw[vfsp->vfs_fstype].vsw_name, VOL_NAME_MAX);
+
+ vfs_mntpoint = vfs_getmntpoint(vfsp);
+ fsd_name_from_mntpoint(vol_attr->name, vfs_mntpoint->rs_string,
+ VOL_NAME_MAX);
+
+ refstr_rele(vfs_mntpoint);
+}
+
+/*
+ * Always set supports ACLs because the VFS will fake ACLs
+ * for file systems that don't support them.
+ */
+static void
+fsd_getflags(vfs_t *vfsp, uint_t *flags_ret)
+{
+ char *fsname = vfssw[vfsp->vfs_fstype].vsw_name;
+ uint_t flags = FSOLF_SUPPORTS_ACLS;
+
+ if (vfsp->vfs_flag & VFS_RDONLY)
+ flags |= FSOLF_READONLY;
+
+ if (vfsp->vfs_flag & VFS_XATTR)
+ flags |= FSOLF_STREAMS;
+
+ if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
+ flags |= FSOLF_NO_ATIME;
+
+ if (strcmp(fsname, "tmpfs") == 0)
+ flags |= FSOLF_NOEXPORT;
+
+ if (vfs_has_feature(vfsp, VFSFT_XVATTR))
+ flags |= FSOLF_XVATTR;
+
+ if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
+ flags |= FSOLF_CASE_INSENSITIVE;
+
+ if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
+ flags |= FSOLF_NO_CASE_SENSITIVE;
+
+ if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
+ flags |= FSOLF_DIRENTFLAGS;
+
+ DTRACE_PROBE1(smb__vfs__getflags, uint_t, flags);
+ *flags_ret = flags;
+}
+
+
+/* ARGSUSED */
+static void
+fsd_getseq(vfs_t *vfsp, uint32_t *fs_sequence)
+{
+ /*
+ * This function is more complicated if there is
+ * DAVE support, but we have excised that code for
+ * the moment.
+ */
+ *fs_sequence = 0;
+}
+
+/*
+ * This function parses out the first conponent of a mount path,
+ * used elsewhere as the volume name.
+ *
+ * For "/", the volume name is "" (i.e. ROOTVOL).
+ */
+
+static void
+fsd_name_from_mntpoint(char *name, const char *mntpnt, size_t name_sz)
+{
+ const char *s = mntpnt;
+ char *tmp = name;
+
+ s += strspn(s, "/");
+ (void) strlcpy(name, s, name_sz);
+ (void) strsep((char **)&tmp, "/");
+
+ DTRACE_PROBE2(smb__vfs__volume, char *, mntpnt, char *, name);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
new file mode 100644
index 0000000000..655e5ad3ff
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -0,0 +1,2595 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sid.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <acl/acl_common.h>
+
+u_longlong_t smb_caller_id;
+
+static int smb_fsop_amask_to_omode(uint32_t granted_access);
+
+extern uint32_t smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd);
+
+extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
+ uint32_t secinfo);
+
+extern int smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr,
+ int *aclbsize);
+
+static int smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode,
+ smb_fssd_t *fs_sd);
+
+static void smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl,
+ int which_acl);
+static acl_t *smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl);
+
+/*
+ * The smb_fsop_* functions have knowledge of CIFS semantics.
+ *
+ * The smb_vop_* functions have minimal knowledge of CIFS semantics and
+ * serve as an interface to the VFS layer.
+ *
+ * Hence, smb_request_t and smb_node_t structures should not be passed
+ * from the smb_fsop_* layer to the smb_vop_* layer.
+ *
+ * In general, CIFS service code should only ever call smb_fsop_*
+ * functions directly, and never smb_vop_* functions directly.
+ *
+ * smb_fsop_* functions should call smb_vop_* functions where possible, instead
+ * of their smb_fsop_* counterparts. However, there are times when
+ * this cannot be avoided.
+ */
+
+/*
+ * Note: Stream names cannot be mangled.
+ */
+
+int
+smb_fsop_start()
+{
+ int error;
+
+ smb_caller_id = fs_new_caller_id();
+ error = smb_node_root_init();
+
+ if (error == 0)
+ error = smb_fem_init();
+
+ return (error);
+}
+
+void
+smb_fsop_stop()
+{
+ smb_fem_shutdown();
+ smb_vfs_rele_all();
+ smb_node_root_fini();
+}
+
+int
+smb_fsop_open(smb_ofile_t *of)
+{
+ caller_context_t ct;
+ int mode;
+
+ mode = smb_fsop_amask_to_omode(of->f_granted_access);
+
+ smb_get_caller_context(NULL, &ct);
+
+ /*
+ * Assuming that same vnode is returned as we had before
+ * (i.e. no special vnodes)
+ */
+
+ return (smb_vop_open(&of->f_node->vp, mode, of->f_cr, &ct));
+}
+
+int
+smb_fsop_close(smb_ofile_t *of)
+{
+ caller_context_t ct;
+ int mode;
+
+ mode = smb_fsop_amask_to_omode(of->f_granted_access);
+
+ smb_get_caller_context(NULL, &ct);
+
+ return (smb_vop_close(of->f_node->vp, mode, of->f_cr, &ct));
+}
+
+static int
+smb_fsop_amask_to_omode(uint32_t granted_access)
+{
+ int mode = 0;
+
+ if (granted_access & (ACE_READ_DATA | ACE_EXECUTE))
+ mode |= FREAD;
+
+ if (granted_access & (ACE_WRITE_DATA | ACE_APPEND_DATA))
+ mode |= FWRITE;
+
+ if (granted_access & ACE_APPEND_DATA)
+ mode |= FAPPEND;
+
+ return (mode);
+}
+
+static int
+smb_fsop_create_with_sd(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ char *name,
+ smb_attr_t *attr,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr,
+ smb_fssd_t *fs_sd)
+{
+ caller_context_t ct;
+ vsecattr_t *vsap;
+ vsecattr_t vsecattr;
+ acl_t *acl, *dacl, *sacl;
+ smb_attr_t set_attr;
+ vnode_t *vp;
+ int aclbsize = 0; /* size of acl list in bytes */
+ int flags = 0;
+ int is_dir;
+ int rc;
+
+ ASSERT(fs_sd);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ ASSERT(cr);
+ smb_get_caller_context(sr, &ct);
+
+ is_dir = ((fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR) != 0);
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACLONCREATE) {
+ if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
+ dacl = fs_sd->sd_zdacl;
+ sacl = fs_sd->sd_zsacl;
+ ASSERT(dacl || sacl);
+ if (dacl && sacl) {
+ acl = smb_fsop_aclmerge(dacl, sacl);
+ } else if (dacl) {
+ acl = dacl;
+ } else {
+ acl = sacl;
+ }
+
+ rc = smb_vop_acl_to_vsa(acl, &vsecattr, &aclbsize);
+
+ if (dacl && sacl)
+ acl_free(acl);
+
+ if (rc)
+ return (rc);
+
+ vsap = &vsecattr;
+ }
+ else
+ vsap = NULL;
+
+ if (is_dir) {
+ rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags,
+ cr, &ct, vsap);
+ } else {
+ rc = smb_vop_create(snode->vp, name, attr, &vp, flags,
+ cr, &ct, vsap);
+ }
+
+ if (vsap != NULL)
+ kmem_free(vsap->vsa_aclentp, aclbsize);
+
+ if (rc != 0)
+ return (rc);
+
+ set_attr.sa_mask = 0;
+
+ /*
+ * Ideally we should be able to specify the owner and owning
+ * group at create time along with the ACL. Since we cannot
+ * do that right now, kcred is passed to smb_vop_setattr so it
+ * doesn't fail due to lack of permission.
+ */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
+ set_attr.sa_mask |= SMB_AT_UID;
+ }
+
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
+ set_attr.sa_mask |= SMB_AT_GID;
+ }
+
+ if (set_attr.sa_mask) {
+ rc = smb_vop_setattr(snode->vp, NULL, &set_attr,
+ 0, kcred, &ct);
+ }
+
+ } else {
+ /*
+ * For filesystems that don't support ACL-on-create, try
+ * to set the specified SD after create, which could actually
+ * fail because of conflicts between inherited security
+ * attributes upon creation and the specified SD.
+ *
+ * Passing kcred to smb_fsop_sdwrite() to overcome this issue.
+ */
+
+ if (is_dir) {
+ rc = smb_vop_mkdir(snode->vp, name, attr, &vp, flags,
+ cr, &ct, NULL);
+ } else {
+ rc = smb_vop_create(snode->vp, name, attr, &vp, flags,
+ cr, &ct, NULL);
+ }
+
+ if (rc == 0)
+ rc = smb_fsop_sdwrite(sr, kcred, snode, fs_sd, 1);
+ }
+
+ if (rc == 0) {
+ *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name,
+ snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+
+ return (rc);
+}
+
+
+/*
+ * smb_fsop_create
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * all the smb_vop_creates are performed with the appropriate credentials.
+ * Please document any direct calls to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * *ret_snode is returned with a reference upon success. No reference is
+ * taken if an error is returned.
+ */
+
+int
+smb_fsop_create(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_attr_t *attr,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ struct open_param *op = &sr->arg.open;
+ smb_node_t *fnode;
+ smb_attr_t file_attr;
+ caller_context_t ct;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+ char *longname = NULL;
+ char *namep;
+ char *fname;
+ char *sname;
+ int is_stream;
+ int flags = 0;
+ int rc = 0;
+ smb_fssd_t fs_sd;
+ uint32_t secinfo;
+ uint32_t status;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(ret_snode);
+ *ret_snode = 0;
+
+ ASSERT(name);
+ if (*name == 0)
+ return (EINVAL);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ is_stream = smb_stream_parse_name(name, fname, sname);
+
+ if (is_stream)
+ namep = fname;
+ else
+ namep = name;
+
+ if (smb_maybe_mangled_name(namep)) {
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode, namep, longname,
+ MAXNAMELEN, NULL, NULL, 1);
+
+ if ((is_stream == 0) && (rc == 0))
+ rc = EEXIST;
+
+ if ((is_stream && rc) ||
+ ((is_stream == 0) && (rc != ENOENT))) {
+ kmem_free(longname, MAXNAMELEN);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (is_stream)
+ namep = longname;
+ else
+ kmem_free(longname, MAXNAMELEN);
+ }
+
+ if (is_stream) {
+ /*
+ * Look up the unnamed stream.
+ *
+ * Mangle processing in smb_fsop_lookup() for the unnamed
+ * stream won't be needed (as it was done above), but
+ * it may be needed on any link target (which
+ * smb_fsop_lookup() will provide).
+ */
+ rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_snode, namep, &fnode, &file_attr,
+ 0, 0);
+
+ if (longname) {
+ kmem_free(longname, MAXNAMELEN);
+ namep = NULL;
+ }
+
+ if (rc != 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp,
+ &xattrdirvp, flags, cr, &ct);
+
+ if (rc != 0) {
+ smb_node_release(fnode);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
+ vp, sname, ret_attr);
+
+ smb_node_release(fnode);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (ENOMEM);
+ }
+ } else {
+ if (op->sd_buf) {
+ /*
+ * SD sent by client in Windows format. Needs to be
+ * converted to FS format. No inheritance.
+ */
+ secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf);
+ smb_fsop_sdinit(&fs_sd, secinfo, 0);
+
+ status = smb_sd_tofs(op->sd_buf, &fs_sd);
+ if (status == NT_STATUS_SUCCESS) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+ else
+ rc = EINVAL;
+ smb_fsop_sdterm(&fs_sd);
+ } else if (sr->tid_tree->t_acltype == ACE_T) {
+ /*
+ * No incoming SD and filesystem is ZFS
+ * Server applies Windows inheritance rules,
+ * see smb_fsop_sdinherit() comments as to why.
+ */
+ smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, 0);
+ rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd);
+ if (rc == 0) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+
+ smb_fsop_sdterm(&fs_sd);
+ } else {
+ /*
+ * No incoming SD and filesystem is not ZFS
+ * let the filesystem handles the inheritance.
+ */
+ smb_get_caller_context(sr, &ct);
+ rc = smb_vop_create(dir_snode->vp, name, attr, &vp,
+ flags, cr, &ct, NULL);
+
+ if (rc == 0) {
+ *ret_snode = smb_node_lookup(sr, op, cr, vp,
+ name, dir_snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+
+ }
+ }
+
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+}
+
+/*
+ * smb_fsop_mkdir
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * *ret_snode is returned with a reference upon success. No reference is
+ * taken if an error is returned.
+ */
+int
+smb_fsop_mkdir(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_attr_t *attr,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ struct open_param *op = &sr->arg.open;
+ caller_context_t ct;
+ char *longname;
+ vnode_t *vp;
+ int flags = 0;
+ smb_fssd_t fs_sd;
+ uint32_t secinfo;
+ uint32_t status;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(ret_snode);
+ *ret_snode = 0;
+
+ ASSERT(name);
+ if (*name == 0)
+ return (EINVAL);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (smb_maybe_mangled_name(name)) {
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ rc = smb_unmangle_name(sr, cr, dir_snode, name, longname,
+ MAXNAMELEN, NULL, NULL, 1);
+
+ kmem_free(longname, MAXNAMELEN);
+
+ /*
+ * If the name passed in by the client has an unmangled
+ * equivalent that is found in the specified directory,
+ * then the mkdir cannot succeed. Return EEXIST.
+ *
+ * Only if ENOENT is returned will a mkdir be attempted.
+ */
+
+ if (rc == 0)
+ rc = EEXIST;
+
+ if (rc != ENOENT)
+ return (rc);
+ }
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ if (op->sd_buf) {
+ /*
+ * SD sent by client in Windows format. Needs to be
+ * converted to FS format. No inheritance.
+ */
+ secinfo = smb_sd_get_secinfo((smb_sdbuf_t *)op->sd_buf);
+ smb_fsop_sdinit(&fs_sd, secinfo, SMB_FSSD_FLAGS_DIR);
+
+ status = smb_sd_tofs(op->sd_buf, &fs_sd);
+ if (status == NT_STATUS_SUCCESS) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+ else
+ rc = EINVAL;
+ smb_fsop_sdterm(&fs_sd);
+ } else if (sr->tid_tree->t_acltype == ACE_T) {
+ /*
+ * No incoming SD and filesystem is ZFS
+ * Server applies Windows inheritance rules,
+ * see smb_fsop_sdinherit() comments as to why.
+ */
+ smb_fsop_sdinit(&fs_sd, SMB_ACL_SECINFO, SMB_FSSD_FLAGS_DIR);
+ rc = smb_fsop_sdinherit(sr, dir_snode, &fs_sd);
+ if (rc == 0) {
+ rc = smb_fsop_create_with_sd(sr, cr, dir_snode,
+ name, attr, ret_snode, ret_attr, &fs_sd);
+ }
+
+ smb_fsop_sdterm(&fs_sd);
+
+ } else {
+ rc = smb_vop_mkdir(dir_snode->vp, name, attr, &vp, flags, cr,
+ &ct, NULL);
+
+ if (rc == 0) {
+ *ret_snode = smb_node_lookup(sr, op, cr, vp, name,
+ dir_snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_remove
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * od: This means that the name passed in is an on-disk name.
+ * A null smb_request might be passed to this function.
+ */
+
+int
+smb_fsop_remove(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ int od)
+{
+ smb_node_t *fnode;
+ smb_attr_t file_attr;
+ caller_context_t ct;
+ char *longname;
+ char *fname;
+ char *sname;
+ int flags = 0;
+ int rc;
+
+ ASSERT(cr);
+ /*
+ * The state of the node could be SMB_NODE_STATE_DESTROYING if this
+ * function is called during the deletion of the node (because of
+ * DELETE_ON_CLOSE).
+ */
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ smb_get_caller_context(sr, &ct);
+
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (smb_stream_parse_name(name, fname, sname)) {
+
+ ASSERT(od == 0);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ /*
+ * Look up the unnamed stream (i.e. fname).
+ * Unmangle processing will be done on fname
+ * as well as any link target.
+ */
+
+ rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_snode, fname, &fnode, &file_attr,
+ 0, 0);
+
+ if (rc != 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * XXX
+ * Need to find out what permission is required by NTFS
+ * to remove a stream.
+ */
+ rc = smb_vop_stream_remove(fnode->vp, sname, flags, cr, &ct);
+
+ smb_node_release(fnode);
+ } else {
+ /*
+ * If the passed-in name is an on-disk name,
+ * then we need to do a case-sensitive remove.
+ * This is important if the on-disk name
+ * corresponds to a mangled name passed in by
+ * the client. We want to make sure to remove
+ * the exact file specified by the client,
+ * instead of letting the underlying file system
+ * do a remove on the "first match."
+ */
+
+ if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ rc = smb_vop_remove(dir_snode->vp, name, flags, cr, &ct);
+
+ if (rc == ENOENT) {
+ if (smb_maybe_mangled_name(name) == 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode, name,
+ longname, MAXNAMELEN, NULL, NULL, 1);
+
+ if (rc == 0) {
+ /*
+ * We passed "1" as the "od" parameter
+ * to smb_unmangle_name(), such that longname
+ * is the real (case-sensitive) on-disk name.
+ * We make sure we do a remove on this exact
+ * name, as the name was mangled and denotes
+ * a unique file.
+ */
+ flags &= ~SMB_IGNORE_CASE;
+ rc = smb_vop_remove(dir_snode->vp, longname,
+ flags, cr, &ct);
+ }
+
+ kmem_free(longname, MAXNAMELEN);
+ }
+ }
+
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+}
+
+/*
+ * smb_fsop_remove_streams
+ *
+ * This function removes a file's streams without removing the
+ * file itself.
+ *
+ * It is assumed that snode is not a link.
+ */
+int
+smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode)
+{
+ struct fs_stream_info stream_info;
+ caller_context_t ct;
+ uint32_t cookie = 0;
+ int flags = 0;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(fnode);
+ ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, fnode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ for (;;) {
+ rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info,
+ NULL, NULL, flags, cr, &ct);
+
+ if ((rc != 0) || (cookie == SMB_EOF))
+ break;
+
+ (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags,
+ cr, &ct);
+ }
+ return (rc);
+}
+
+/*
+ * smb_fsop_rmdir
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ *
+ * od: This means that the name passed in is an on-disk name.
+ */
+
+int
+smb_fsop_rmdir(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ char *name,
+ int od)
+{
+ caller_context_t ct;
+ int rc;
+ int flags = 0;
+ char *longname;
+
+ ASSERT(cr);
+ /*
+ * The state of the node could be SMB_NODE_STATE_DESTROYING if this
+ * function is called during the deletion of the node (because of
+ * DELETE_ON_CLOSE).
+ */
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ /*
+ * If the passed-in name is an on-disk name,
+ * then we need to do a case-sensitive rmdir.
+ * This is important if the on-disk name
+ * corresponds to a mangled name passed in by
+ * the client. We want to make sure to remove
+ * the exact directory specified by the client,
+ * instead of letting the underlying file system
+ * do a rmdir on the "first match."
+ */
+
+ if ((od == 0) && SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_rmdir(dir_snode->vp, name, flags, cr, &ct);
+
+ if (rc == ENOENT) {
+ if (smb_maybe_mangled_name(name) == 0)
+ return (rc);
+
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode,
+ name, longname, MAXNAMELEN, NULL,
+ NULL, 1);
+
+ if (rc == 0) {
+ /*
+ * We passed "1" as the "od" parameter
+ * to smb_unmangle_name(), such that longname
+ * is the real (case-sensitive) on-disk name.
+ * We make sure we do a rmdir on this exact
+ * name, as the name was mangled and denotes
+ * a unique directory.
+ */
+ flags &= ~SMB_IGNORE_CASE;
+ rc = smb_vop_rmdir(dir_snode->vp, longname, flags, cr,
+ &ct);
+ }
+
+ kmem_free(longname, MAXNAMELEN);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_getattr
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ smb_attr_t *attr)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ uint32_t status;
+ uint32_t access = 0;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, snode) == 0)
+ return (EACCES);
+
+ if (sr->fid_ofile) {
+ /* if uid and/or gid is requested */
+ if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
+ access |= READ_CONTROL;
+
+ /* if anything else is also requested */
+ if (attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
+ access |= FILE_READ_ATTRIBUTES;
+
+ status = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (status != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+ }
+
+ smb_get_caller_context(sr, &ct);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ }
+
+ return (smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr, &ct));
+}
+
+/*
+ * smb_fsop_readdir
+ *
+ * All SMB functions should use this smb_fsop_readdir wrapper to ensure that
+ * the smb_vop_readdir is performed with the appropriate credentials.
+ * Please document any direct call to smb_vop_readdir to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_readdir(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ uint32_t *cookie,
+ char *name,
+ int *namelen,
+ ino64_t *fileid,
+ struct fs_stream_info *stream_info,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ caller_context_t ct;
+ smb_node_t *ret_snodep;
+ smb_node_t *fnode;
+ smb_attr_t tmp_attr;
+ vnode_t *xattrdirvp;
+ vnode_t *fvp;
+ vnode_t *vp = NULL;
+ char *od_name;
+ int rc;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (*cookie == SMB_EOF) {
+ *namelen = 0;
+ return (0);
+ }
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (stream_info) {
+ rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name,
+ SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr, &ct);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode,
+ NULL, ret_attr);
+
+ kmem_free(od_name, MAXNAMELEN);
+
+ if (fnode == NULL) {
+ VN_RELE(fvp);
+ return (ENOMEM);
+ }
+
+ /*
+ * XXX
+ * Need to find out what permission(s) NTFS requires for getting
+ * a file's streams list.
+ *
+ * Might have to use kcred.
+ */
+ rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp,
+ &xattrdirvp, flags, cr, &ct);
+
+ if ((rc != 0) || (*cookie == SMB_EOF)) {
+ smb_node_release(fnode);
+ return (rc);
+ }
+
+ ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
+ vp, stream_info->name, &tmp_attr);
+
+ smb_node_release(fnode);
+
+ if (ret_snodep == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ return (ENOMEM);
+ }
+
+ stream_info->size = tmp_attr.sa_vattr.va_size;
+
+ if (ret_attr)
+ *ret_attr = tmp_attr;
+
+ if (ret_snode)
+ *ret_snode = ret_snodep;
+ else
+ smb_node_release(ret_snodep);
+
+ } else {
+ rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen,
+ fileid, &vp, od_name, flags, cr, &ct);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (*namelen) {
+ ASSERT(vp);
+ if (ret_attr || ret_snode) {
+ ret_snodep = smb_node_lookup(sr, NULL, cr, vp,
+ od_name, dir_snode, NULL, &tmp_attr);
+
+ if (ret_snodep == NULL) {
+ kmem_free(od_name, MAXNAMELEN);
+ VN_RELE(vp);
+ return (ENOMEM);
+ }
+
+ if (ret_attr)
+ *ret_attr = tmp_attr;
+
+ if (ret_snode)
+ *ret_snode = ret_snodep;
+ else
+ smb_node_release(ret_snodep);
+ }
+ }
+
+ kmem_free(od_name, MAXNAMELEN);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_getdents
+ *
+ * All SMB functions should use this smb_vop_getdents wrapper to ensure that
+ * the smb_vop_getdents is performed with the appropriate credentials.
+ * Please document any direct call to smb_vop_getdents to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+/*ARGSUSED*/
+int
+smb_fsop_getdents(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *dir_snode,
+ uint32_t *cookie,
+ uint64_t *verifierp,
+ int32_t *maxcnt,
+ char *args,
+ char *pattern)
+{
+ caller_context_t ct;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern,
+ flags, sr, cr, &ct));
+}
+
+/*
+ * smb_fsop_rename
+ *
+ * All SMB functions should use this smb_vop_rename wrapper to ensure that
+ * the smb_vop_rename is performed with the appropriate credentials.
+ * Please document any direct call to smb_vop_rename to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that references exist on from_dir_snode and to_dir_snode coming
+ * into this routine.
+ */
+int
+smb_fsop_rename(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *from_dir_snode,
+ char *from_name,
+ smb_node_t *to_dir_snode,
+ char *to_name)
+{
+ smb_node_t *from_snode;
+ caller_context_t ct;
+ smb_attr_t tmp_attr;
+ vnode_t *from_vp;
+ int flags = 0;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(from_dir_snode);
+ ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(from_dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(to_dir_snode);
+ ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(to_dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, from_dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_ROOT_FS(sr, to_dir_snode) == 0)
+ return (EACCES);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ /*
+ * Note: There is no need to check SMB_TREE_CASE_INSENSITIVE(sr)
+ * here.
+ *
+ * A case-sensitive rename is always done in this routine
+ * because we are using the on-disk name from an earlier lookup.
+ * If a mangled name was passed in by the caller (denoting a
+ * deterministic lookup), then the exact file must be renamed
+ * (i.e. SMB_IGNORE_CASE must not be passed to VOP_RENAME, or
+ * else the underlying file system might return a "first-match"
+ * on this on-disk name, possibly resulting in the wrong file).
+ */
+
+ /*
+ * XXX: Lock required through smb_node_release() below?
+ */
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_lookup(from_dir_snode->vp, from_name, &from_vp, NULL, 0,
+ NULL, cr, &ct);
+
+ if (rc != 0)
+ return (rc);
+
+ rc = smb_vop_rename(from_dir_snode->vp, from_name, to_dir_snode->vp,
+ to_name, flags, cr, &ct);
+
+ if (rc == 0) {
+ from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
+ from_dir_snode, NULL, &tmp_attr);
+
+ if (from_snode == NULL) {
+ VN_RELE(from_vp);
+ return (ENOMEM);
+ }
+
+ (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode,
+ to_name);
+
+ smb_node_release(from_snode);
+ } else {
+ VN_RELE(from_vp);
+ }
+
+ /* XXX: unlock */
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_setattr
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ * A null smb_request might be passed to this function.
+ */
+int
+smb_fsop_setattr(
+ smb_request_t *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ smb_attr_t *set_attr,
+ smb_attr_t *ret_attr)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ uint32_t status;
+ uint32_t access = 0;
+ int rc = 0;
+ int flags = 0;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_ROOT_FS(sr, snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ /* sr could be NULL in some cases */
+ if (sr && sr->fid_ofile) {
+ /* if uid and/or gid is requested */
+ if (set_attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
+ access |= WRITE_OWNER;
+
+ /* if anything else is also requested */
+ if (set_attr->sa_mask & ~(SMB_AT_UID|SMB_AT_GID))
+ access |= FILE_WRITE_ATTRIBUTES;
+
+ status = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (status != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+ }
+
+ smb_get_caller_context(sr, &ct);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ }
+
+ rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr, &ct);
+
+ if ((rc == 0) && ret_attr) {
+ /*
+ * This is an operation on behalf of CIFS service (to update
+ * smb node's attr) not on behalf of the user so it's done
+ * using kcred and the return value is intentionally ignored.
+ */
+ ret_attr->sa_mask = SMB_AT_ALL;
+ (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
+ kcred, &ct);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_read
+ *
+ * All SMB functions should use this wrapper to ensure that
+ * the the calls are performed with the appropriate credentials.
+ * Please document any direct call to explain the reason
+ * for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_read(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ uio_t *uio,
+ smb_attr_t *ret_attr)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(sr);
+ ASSERT(sr->fid_ofile);
+
+ rc = smb_ofile_access(sr->fid_ofile, cr, FILE_READ_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ rc = smb_ofile_access(sr->fid_ofile, cr, FILE_EXECUTE);
+ if (rc != NT_STATUS_SUCCESS)
+ return (EACCES);
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ /*
+ * Streams permission are checked against the unnamed stream,
+ * but in FS level they have their own permissions. To avoid
+ * rejection by FS due to lack of permission on the actual
+ * extended attr kcred is passed for streams.
+ */
+ cr = kcred;
+ }
+
+ smb_get_caller_context(sr, &ct);
+ rc = smb_vop_read(snode->vp, uio, cr, &ct);
+
+ if (rc == 0) {
+ /*
+ * This is an operation on behalf of CIFS service (to update
+ * smb node's attr) not on behalf of the user so it's done
+ * using kcred and the return value is intentionally ignored.
+ */
+ ret_attr->sa_mask = SMB_AT_ALL;
+ (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
+ kcred, &ct);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_write
+ *
+ * This is a wrapper function used for smb_write and smb_write_raw operations.
+ *
+ * It is assumed that a reference exists on snode coming into this routine.
+ */
+int
+smb_fsop_write(
+ struct smb_request *sr,
+ cred_t *cr,
+ smb_node_t *snode,
+ uio_t *uio,
+ uint32_t *lcount,
+ smb_attr_t *ret_attr,
+ uint32_t *flag)
+{
+ smb_node_t *unnamed_node;
+ vnode_t *unnamed_vp = NULL;
+ caller_context_t ct;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ ASSERT(sr->fid_ofile);
+
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+ /*
+ * XXX what if the file has been opened only with
+ * FILE_APPEND_DATA?
+ */
+ rc = smb_ofile_access(sr->fid_ofile, cr, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ smb_get_caller_context(sr, &ct);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ unnamed_vp = unnamed_node->vp;
+ /*
+ * Streams permission are checked against the unnamed stream,
+ * but in FS level they have their own permissions. To avoid
+ * rejection by FS due to lack of permission on the actual
+ * extended attr kcred is passed for streams.
+ */
+ cr = kcred;
+ }
+
+ rc = smb_vop_write(snode->vp, uio, flag, lcount, cr, &ct);
+
+ if (rc == 0) {
+ /*
+ * This is an operation on behalf of CIFS service (to update
+ * smb node's attr) not on behalf of the user so it's done
+ * using kcred and the return value is intentionally ignored.
+ */
+ ret_attr->sa_mask = SMB_AT_ALL;
+ (void) smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
+ kcred, &ct);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_statfs
+ *
+ * This is a wrapper function used for stat operations.
+ */
+int
+smb_fsop_statfs(
+ cred_t *cr,
+ smb_node_t *snode,
+ struct statvfs64 *statp)
+{
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ return (smb_vop_statfs(snode->vp, statp, cr));
+}
+
+/*
+ * smb_fsop_access
+ */
+int
+smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t faccess)
+{
+ int access = 0;
+ int error;
+ vnode_t *dir_vp;
+ boolean_t acl_check = B_TRUE;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (faccess == 0)
+ return (NT_STATUS_SUCCESS);
+
+ if (SMB_TREE_IS_READ_ONLY(sr)) {
+ if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA|
+ FILE_WRITE_EA|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES|
+ DELETE|WRITE_DAC|WRITE_OWNER)) {
+ return (NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams authorization should be performed against the
+ * unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ if (faccess & ACCESS_SYSTEM_SECURITY) {
+ /*
+ * This permission is required for reading/writing SACL and
+ * it's not part of DACL. It's only granted via proper
+ * privileges.
+ */
+ if ((sr->uid_user->u_privileges &
+ (SMB_USER_PRIV_BACKUP |
+ SMB_USER_PRIV_RESTORE |
+ SMB_USER_PRIV_SECURITY)) == 0)
+ return (NT_STATUS_PRIVILEGE_NOT_HELD);
+
+ faccess &= ~ACCESS_SYSTEM_SECURITY;
+ }
+
+ /* Links don't have ACL */
+ if (((sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) == 0) ||
+ (snode->attr.sa_vattr.va_type == VLNK))
+ acl_check = B_FALSE;
+
+ if (acl_check) {
+ dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+ error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
+ cr);
+ } else {
+ /*
+ * FS doesn't understand 32-bit mask, need to map
+ */
+ if (faccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))
+ access |= VWRITE;
+
+ if (faccess & FILE_READ_DATA)
+ access |= VREAD;
+
+ if (faccess & FILE_EXECUTE)
+ access |= VEXEC;
+
+ error = smb_vop_access(snode->vp, access, 0, NULL, cr);
+ }
+
+ return ((error) ? NT_STATUS_ACCESS_DENIED : NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_fsop_lookup_name()
+ *
+ * Sanity checks on dir_snode done in smb_fsop_lookup().
+ *
+ * Note: This function is called only from the open path.
+ * It will check if the file is a stream.
+ * It will also return an error if the looked-up file is in
+ * a child mount.
+ */
+
+int
+smb_fsop_lookup_name(
+ struct smb_request *sr,
+ cred_t *cr,
+ int flags,
+ smb_node_t *root_node,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr)
+{
+ smb_node_t *fnode;
+ smb_attr_t file_attr;
+ caller_context_t ct;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+ char *od_name;
+ char *fname;
+ char *sname;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ /*
+ * The following check is required for streams processing, below
+ */
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags |= SMB_IGNORE_CASE;
+
+ fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (smb_stream_parse_name(name, fname, sname)) {
+ /*
+ * Look up the unnamed stream (i.e. fname).
+ * Unmangle processing will be done on fname
+ * as well as any link target.
+ */
+ rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, fname,
+ &fnode, &file_attr, NULL, NULL);
+
+ if (rc != 0) {
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (rc);
+ }
+
+ od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ /*
+ * od_name is the on-disk name of the stream, except
+ * without the prepended stream prefix (SMB_STREAM_PREFIX)
+ */
+
+ /*
+ * XXX
+ * What permissions NTFS requires for stream lookup if any?
+ */
+ rc = smb_vop_stream_lookup(fnode->vp, sname, &vp, od_name,
+ &xattrdirvp, flags, root_node->vp, cr, &ct);
+
+ if (rc != 0) {
+ smb_node_release(fnode);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ *ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
+ vp, od_name, ret_attr);
+
+ kmem_free(od_name, MAXNAMELEN);
+ smb_node_release(fnode);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+ return (ENOMEM);
+ }
+ } else {
+ rc = smb_fsop_lookup(sr, cr, flags, root_node, dir_snode, name,
+ ret_snode, ret_attr, NULL, NULL);
+ }
+
+ if (rc == 0) {
+ ASSERT(ret_snode);
+ if (SMB_TREE_ROOT_FS(sr, *ret_snode) == 0) {
+ smb_node_release(*ret_snode);
+ *ret_snode = NULL;
+ rc = EACCES;
+ }
+ }
+
+ kmem_free(fname, MAXNAMELEN);
+ kmem_free(sname, MAXNAMELEN);
+
+ return (rc);
+}
+
+/*
+ * smb_fsop_lookup
+ *
+ * All SMB functions should use this smb_vop_lookup wrapper to ensure that
+ * the smb_vop_lookup is performed with the appropriate credentials and using
+ * case insensitive compares. Please document any direct call to smb_vop_lookup
+ * to explain the reason for avoiding this wrapper.
+ *
+ * It is assumed that a reference exists on dir_snode coming into this routine
+ * (and that it is safe from deallocation).
+ *
+ * Same with the root_node.
+ *
+ * *ret_snode is returned with a reference upon success. No reference is
+ * taken if an error is returned.
+ *
+ * Note: The returned ret_snode may be in a child mount. This is ok for
+ * readdir and getdents.
+ *
+ * Other smb_fsop_* routines will call SMB_TREE_ROOT_FS() to prevent
+ * operations on files not in the parent mount.
+ */
+int
+smb_fsop_lookup(
+ struct smb_request *sr,
+ cred_t *cr,
+ int flags,
+ smb_node_t *root_node,
+ smb_node_t *dir_snode,
+ char *name,
+ smb_node_t **ret_snode,
+ smb_attr_t *ret_attr,
+ char *ret_shortname, /* Must be at least MANGLE_NAMELEN chars */
+ char *ret_name83) /* Must be at least MANGLE_NAMELEN chars */
+{
+ smb_node_t *lnk_target_node;
+ smb_node_t *lnk_dnode;
+ caller_context_t ct;
+ char *longname;
+ char *od_name;
+ vnode_t *vp;
+ int rc;
+
+ ASSERT(cr);
+ ASSERT(dir_snode);
+ ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (name == NULL)
+ return (EINVAL);
+
+ if (SMB_TREE_ROOT_FS(sr, dir_snode) == 0)
+ return (EACCES);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags |= SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_vop_lookup(dir_snode->vp, name, &vp, od_name, flags,
+ root_node ? root_node->vp : NULL, cr, &ct);
+
+ if (rc != 0) {
+ if (smb_maybe_mangled_name(name) == 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ rc = smb_unmangle_name(sr, cr, dir_snode, name, longname,
+ MAXNAMELEN, ret_shortname, ret_name83, 1);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ kmem_free(longname, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * We passed "1" as the "od" parameter
+ * to smb_unmangle_name(), such that longname
+ * is the real (case-sensitive) on-disk name.
+ * We make sure we do a lookup on this exact
+ * name, as the name was mangled and denotes
+ * a unique file.
+ */
+
+ if (flags & SMB_IGNORE_CASE)
+ flags &= ~SMB_IGNORE_CASE;
+
+ rc = smb_vop_lookup(dir_snode->vp, longname, &vp, od_name,
+ flags, root_node ? root_node->vp : NULL, cr, &ct);
+
+ kmem_free(longname, MAXNAMELEN);
+
+ if (rc != 0) {
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+ }
+
+ if ((flags & SMB_FOLLOW_LINKS) && (vp->v_type == VLNK)) {
+
+ rc = smb_pathname(sr, od_name, FOLLOW, root_node, dir_snode,
+ &lnk_dnode, &lnk_target_node, cr);
+
+ if (rc != 0) {
+ /*
+ * The link is assumed to be for the last component
+ * of a path. Hence any ENOTDIR error will be returned
+ * as ENOENT.
+ */
+ if (rc == ENOTDIR)
+ rc = ENOENT;
+
+ VN_RELE(vp);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * Release the original VLNK vnode
+ */
+
+ VN_RELE(vp);
+ vp = lnk_target_node->vp;
+
+ rc = smb_vop_traverse_check(&vp);
+
+ if (rc != 0) {
+ smb_node_release(lnk_dnode);
+ smb_node_release(lnk_target_node);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ /*
+ * smb_vop_traverse_check() may have returned a different vnode
+ */
+
+ if (lnk_target_node->vp == vp) {
+ *ret_snode = lnk_target_node;
+ *ret_attr = (*ret_snode)->attr;
+ } else {
+ *ret_snode = smb_node_lookup(sr, NULL, cr, vp,
+ lnk_target_node->od_name, lnk_dnode, NULL,
+ ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ smb_node_release(lnk_target_node);
+ }
+
+ smb_node_release(lnk_dnode);
+
+ } else {
+
+ rc = smb_vop_traverse_check(&vp);
+ if (rc) {
+ VN_RELE(vp);
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+ }
+
+ *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
+ dir_snode, NULL, ret_attr);
+
+ if (*ret_snode == NULL) {
+ VN_RELE(vp);
+ rc = ENOMEM;
+ }
+ }
+
+ kmem_free(od_name, MAXNAMELEN);
+ return (rc);
+}
+
+/*
+ * smb_fsop_stream_readdir()
+ *
+ * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in)
+ *
+ * This routine will return only NTFS streams. If an NTFS stream is not
+ * found at the offset specified, the directory will be read until an NTFS
+ * stream is found or until EOF.
+ *
+ * Note: Sanity checks done in caller
+ * (smb_fsop_readdir(), smb_fsop_remove_streams())
+ */
+
+int
+smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
+ uint32_t *cookiep, struct fs_stream_info *stream_info,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr)
+{
+ smb_node_t *ret_snodep = NULL;
+ caller_context_t ct;
+ smb_attr_t tmp_attr;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+ int rc = 0;
+ int flags = 0;
+
+ /*
+ * XXX NTFS permission requirements if any?
+ */
+ ASSERT(cr);
+ ASSERT(fnode);
+ ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ flags = SMB_IGNORE_CASE;
+
+ smb_get_caller_context(sr, &ct);
+
+ rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp,
+ &xattrdirvp, flags, cr, &ct);
+
+ if ((rc != 0) || *cookiep == SMB_EOF)
+ return (rc);
+
+ ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp,
+ stream_info->name, &tmp_attr);
+
+ if (ret_snodep == NULL) {
+ VN_RELE(xattrdirvp);
+ VN_RELE(vp);
+ return (ENOMEM);
+ }
+
+ stream_info->size = tmp_attr.sa_vattr.va_size;
+
+ if (ret_attr)
+ *ret_attr = tmp_attr;
+
+ if (ret_snode)
+ *ret_snode = ret_snodep;
+ else
+ smb_node_release(ret_snodep);
+
+ return (rc);
+}
+
+int /*ARGSUSED*/
+smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
+{
+ caller_context_t ct;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ smb_get_caller_context(sr, &ct);
+
+ return (smb_vop_commit(snode->vp, cr, &ct));
+}
+
+/*
+ * smb_fsop_sdinit
+ *
+ * Initializes the given FS SD structure.
+ */
+void
+smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
+{
+ bzero(fs_sd, sizeof (smb_fssd_t));
+ fs_sd->sd_secinfo = secinfo;
+ fs_sd->sd_flags = flags;
+}
+
+/*
+ * smb_fsop_sdterm
+ *
+ * Frees allocated memory for acl fields.
+ */
+void
+smb_fsop_sdterm(smb_fssd_t *fs_sd)
+{
+ ASSERT(fs_sd);
+
+ smb_fsop_aclfree(fs_sd->sd_zdacl);
+ smb_fsop_aclfree(fs_sd->sd_zsacl);
+ bzero(fs_sd, sizeof (smb_fssd_t));
+}
+
+/*
+ * smb_fsop_aclread
+ *
+ * Retrieve filesystem ACL. Depends on requested ACLs in
+ * fs_sd->sd_secinfo, it'll set DACL and SACL pointers in
+ * fs_sd. Note that requesting a DACL/SACL doesn't mean that
+ * the corresponding field in fs_sd should be non-NULL upon
+ * return, since the target ACL might not contain that type of
+ * entries.
+ *
+ * Returned ACL is always in ACE_T (aka ZFS) format.
+ * If successful the allocated memory for the ACL should be freed
+ * using smb_fsop_aclfree() or smb_fsop_sdterm()
+ */
+int
+smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd)
+{
+ int error = 0;
+ int flags = 0;
+ int access = 0;
+ acl_t *acl;
+ caller_context_t ct;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+
+ if (sr->fid_ofile) {
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
+ access = READ_CONTROL;
+
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
+ access |= ACCESS_SYSTEM_SECURITY;
+
+ error = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (error != NT_STATUS_SUCCESS) {
+ return (EACCES);
+ }
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams don't have ACL, any read ACL attempt on a stream
+ * should be performed on the unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+
+ smb_get_caller_context(sr, &ct);
+ error = smb_vop_acl_read(snode->vp, &acl, flags,
+ sr->tid_tree->t_acltype, cr, &ct);
+ if (error != 0) {
+ return (error);
+ }
+
+ error = acl_translate(acl, _ACL_ACE_ENABLED,
+ (snode->vp->v_type == VDIR), fs_sd->sd_uid, fs_sd->sd_gid);
+
+ if (error == 0) {
+ smb_fsop_aclsplit(acl, &fs_sd->sd_zdacl, &fs_sd->sd_zsacl,
+ fs_sd->sd_secinfo);
+ }
+
+ acl_free(acl);
+ return (error);
+}
+
+/*
+ * smb_fsop_aclwrite
+ *
+ * Stores the filesystem ACL provided in fs_sd->sd_acl.
+ */
+int
+smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd)
+{
+ int target_flavor;
+ int error = 0;
+ int flags = 0;
+ int access = 0;
+ caller_context_t ct;
+ acl_t *acl, *dacl, *sacl;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ if (sr->fid_ofile) {
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
+ access = WRITE_DAC;
+
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
+ access |= ACCESS_SYSTEM_SECURITY;
+
+ error = smb_ofile_access(sr->fid_ofile, cr, access);
+ if (error != NT_STATUS_SUCCESS)
+ return (EACCES);
+ }
+
+ switch (sr->tid_tree->t_acltype) {
+ case ACLENT_T:
+ target_flavor = _ACL_ACLENT_ENABLED;
+ break;
+
+ case ACE_T:
+ target_flavor = _ACL_ACE_ENABLED;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams don't have ACL, any write ACL attempt on a stream
+ * should be performed on the unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ dacl = fs_sd->sd_zdacl;
+ sacl = fs_sd->sd_zsacl;
+
+ ASSERT(dacl || sacl);
+ if ((dacl == NULL) && (sacl == NULL))
+ return (EINVAL);
+
+ if (dacl && sacl)
+ acl = smb_fsop_aclmerge(dacl, sacl);
+ else if (dacl)
+ acl = dacl;
+ else
+ acl = sacl;
+
+ error = acl_translate(acl, target_flavor, (snode->vp->v_type == VDIR),
+ fs_sd->sd_uid, fs_sd->sd_gid);
+ if (error == 0) {
+ smb_get_caller_context(sr, &ct);
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS)
+ flags = ATTR_NOACLCHECK;
+
+ error = smb_vop_acl_write(snode->vp, acl, flags, cr, &ct);
+ }
+
+ if (dacl && sacl)
+ acl_free(acl);
+
+ return (error);
+}
+
+acl_t *
+smb_fsop_aclalloc(int acenum, int flags)
+{
+ acl_t *acl;
+
+ acl = acl_alloc(ACE_T);
+ acl->acl_cnt = acenum;
+ acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
+ acl->acl_flags = flags;
+ return (acl);
+}
+
+void
+smb_fsop_aclfree(acl_t *acl)
+{
+ if (acl)
+ acl_free(acl);
+}
+
+/*
+ * smb_fsop_aclmerge
+ *
+ * smb_fsop_aclread/write routines which interact with filesystem
+ * work with single ACL. This routine merges given DACL and SACL
+ * which might have been created during CIFS to FS conversion into
+ * one single ACL.
+ */
+static acl_t *
+smb_fsop_aclmerge(acl_t *dacl, acl_t *sacl)
+{
+ acl_t *acl;
+ int dacl_size;
+
+ ASSERT(dacl);
+ ASSERT(sacl);
+
+ acl = smb_fsop_aclalloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
+ dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
+ bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
+ bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
+ sacl->acl_cnt * sacl->acl_entry_size);
+
+ return (acl);
+}
+
+/*
+ * smb_fsop_aclsplit
+ *
+ * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
+ * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
+ * NULL even if they're specified in 'which_acl', which means the target
+ * doesn't have any access and/or audit ACEs.
+ */
+static void
+smb_fsop_aclsplit(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
+{
+ ace_t *zace;
+ ace_t *access_ace;
+ ace_t *audit_ace;
+ int naccess, naudit;
+ int get_dacl, get_sacl;
+ int i;
+
+ *dacl = *sacl = NULL;
+ naccess = naudit = 0;
+ get_dacl = (which_acl & SMB_DACL_SECINFO);
+ get_sacl = (which_acl & SMB_SACL_SECINFO);
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
+ if (get_dacl && smb_ace_is_access(zace->a_type))
+ naccess++;
+ else if (get_sacl && smb_ace_is_audit(zace->a_type))
+ naudit++;
+ }
+
+ if (naccess) {
+ *dacl = smb_fsop_aclalloc(naccess, zacl->acl_flags);
+ access_ace = (*dacl)->acl_aclp;
+ }
+
+ if (naudit) {
+ *sacl = smb_fsop_aclalloc(naudit, zacl->acl_flags);
+ audit_ace = (*sacl)->acl_aclp;
+ }
+
+ for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
+ if (get_dacl && smb_ace_is_access(zace->a_type)) {
+ *access_ace = *zace;
+ access_ace++;
+ } else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
+ *audit_ace = *zace;
+ audit_ace++;
+ }
+ }
+}
+
+acl_type_t
+smb_fsop_acltype(smb_node_t *snode)
+{
+ return (smb_vop_acl_type(snode->vp));
+}
+
+/*
+ * smb_fsop_sdread
+ *
+ * Read the requested security descriptor items from filesystem.
+ * The items are specified in fs_sd->sd_secinfo.
+ */
+int
+smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd)
+{
+ int error = 0;
+ int getowner = 0;
+ cred_t *ga_cred;
+ smb_attr_t attr;
+
+ ASSERT(cr);
+ ASSERT(fs_sd);
+
+ /*
+ * File's uid/gid is fetched in two cases:
+ *
+ * 1. it's explicitly requested
+ *
+ * 2. target ACL is ACE_T (ZFS ACL). They're needed for
+ * owner@/group@ entries. In this case kcred should be used
+ * because uid/gid are fetched on behalf of smb server.
+ */
+ if (fs_sd->sd_secinfo & (SMB_OWNER_SECINFO | SMB_GROUP_SECINFO)) {
+ getowner = 1;
+ ga_cred = cr;
+ } else if (sr->tid_tree->t_acltype == ACE_T) {
+ getowner = 1;
+ ga_cred = kcred;
+ }
+
+ if (getowner) {
+ /*
+ * Windows require READ_CONTROL to read owner/group SID since
+ * they're part of Security Descriptor.
+ * ZFS only requires read_attribute. Need to have a explicit
+ * access check here.
+ */
+ if (sr->fid_ofile == NULL) {
+ error = smb_fsop_access(sr, ga_cred, snode,
+ READ_CONTROL);
+ if (error)
+ return (error);
+ }
+
+ attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
+ error = smb_fsop_getattr(sr, ga_cred, snode, &attr);
+ if (error == 0) {
+ fs_sd->sd_uid = attr.sa_vattr.va_uid;
+ fs_sd->sd_gid = attr.sa_vattr.va_gid;
+ } else {
+ return (error);
+ }
+ }
+
+ if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
+ error = smb_fsop_aclread(sr, cr, snode, fs_sd);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_fsop_sdmerge
+ *
+ * From SMB point of view DACL and SACL are two separate list
+ * which can be manipulated independently without one affecting
+ * the other, but entries for both DACL and SACL will end up
+ * in the same ACL if target filesystem supports ACE_T ACLs.
+ *
+ * So, if either DACL or SACL is present in the client set request
+ * the entries corresponding to the non-present ACL shouldn't
+ * be touched in the FS ACL.
+ *
+ * fs_sd parameter contains DACL and SACL specified by SMB
+ * client to be set on a file/directory. The client could
+ * specify both or one of these ACLs (if none is specified
+ * we don't get this far). When both DACL and SACL are given
+ * by client the existing ACL should be overwritten. If only
+ * one of them is specified the entries corresponding to the other
+ * ACL should not be touched. For example, if only DACL
+ * is specified in input fs_sd, the function reads audit entries
+ * of the existing ACL of the file and point fs_sd->sd_zsdacl
+ * pointer to the fetched SACL, this way when smb_fsop_sdwrite()
+ * function is called the passed fs_sd would point to the specified
+ * DACL by client and fetched SACL from filesystem, so the file
+ * will end up with correct ACL.
+ */
+static int
+smb_fsop_sdmerge(smb_request_t *sr, smb_node_t *snode, smb_fssd_t *fs_sd)
+{
+ smb_fssd_t cur_sd;
+ int error = 0;
+
+ if (sr->tid_tree->t_acltype != ACE_T)
+ /* Don't bother if target FS doesn't support ACE_T */
+ return (0);
+
+ if ((fs_sd->sd_secinfo & SMB_ACL_SECINFO) != SMB_ACL_SECINFO) {
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ /*
+ * Don't overwrite existing audit entries
+ */
+ smb_fsop_sdinit(&cur_sd, SMB_SACL_SECINFO,
+ fs_sd->sd_flags);
+
+ error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
+ if (error == 0) {
+ ASSERT(fs_sd->sd_zsacl == NULL);
+ fs_sd->sd_zsacl = cur_sd.sd_zsacl;
+ if (fs_sd->sd_zsacl && fs_sd->sd_zdacl)
+ fs_sd->sd_zsacl->acl_flags =
+ fs_sd->sd_zdacl->acl_flags;
+ }
+ } else {
+ /*
+ * Don't overwrite existing access entries
+ */
+ smb_fsop_sdinit(&cur_sd, SMB_DACL_SECINFO,
+ fs_sd->sd_flags);
+
+ error = smb_fsop_sdread(sr, kcred, snode, &cur_sd);
+ if (error == 0) {
+ ASSERT(fs_sd->sd_zdacl == NULL);
+ fs_sd->sd_zdacl = cur_sd.sd_zdacl;
+ if (fs_sd->sd_zdacl && fs_sd->sd_zsacl)
+ fs_sd->sd_zdacl->acl_flags =
+ fs_sd->sd_zsacl->acl_flags;
+ }
+ }
+
+ if (error)
+ smb_fsop_sdterm(&cur_sd);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_fsop_sdwrite
+ *
+ * Stores the given uid, gid and acl in filesystem.
+ * Provided items in fs_sd are specified by fs_sd->sd_secinfo.
+ *
+ * A SMB security descriptor could contain owner, primary group,
+ * DACL and SACL. Setting an SD should be atomic but here it has to
+ * be done via two separate FS operations: VOP_SETATTR and
+ * VOP_SETSECATTR. Therefore, this function has to simulate the
+ * atomicity as well as it can.
+ */
+int
+smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd, int overwrite)
+{
+ int error = 0;
+ int access = 0;
+ smb_attr_t set_attr;
+ smb_attr_t orig_attr;
+
+ ASSERT(cr);
+ ASSERT(fs_sd);
+
+ ASSERT(sr);
+ ASSERT(sr->tid_tree);
+ if (SMB_TREE_IS_READ_ONLY(sr))
+ return (EROFS);
+
+ bzero(&set_attr, sizeof (smb_attr_t));
+
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ set_attr.sa_vattr.va_uid = fs_sd->sd_uid;
+ set_attr.sa_mask |= SMB_AT_UID;
+ }
+
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ set_attr.sa_vattr.va_gid = fs_sd->sd_gid;
+ set_attr.sa_mask |= SMB_AT_GID;
+ }
+
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO)
+ access |= WRITE_DAC;
+
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO)
+ access |= ACCESS_SYSTEM_SECURITY;
+
+ if (sr->fid_ofile)
+ error = smb_ofile_access(sr->fid_ofile, cr, access);
+ else
+ error = smb_fsop_access(sr, cr, snode, access);
+
+ if (error)
+ return (EACCES);
+
+ if (set_attr.sa_mask) {
+ /*
+ * Get the current uid, gid so if smb_fsop_aclwrite fails
+ * we can revert uid, gid changes.
+ *
+ * We use root cred here so the operation doesn't fail
+ * due to lack of permission for the user to read the attrs
+ */
+
+ orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
+ error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
+ if (error == 0)
+ error = smb_fsop_setattr(sr, cr, snode, &set_attr,
+ NULL);
+
+ if (error)
+ return (error);
+ }
+
+ if (fs_sd->sd_secinfo & SMB_ACL_SECINFO) {
+ if (overwrite == 0) {
+ error = smb_fsop_sdmerge(sr, snode, fs_sd);
+ if (error)
+ return (error);
+ }
+
+ error = smb_fsop_aclwrite(sr, cr, snode, fs_sd);
+ if (error) {
+ /*
+ * Revert uid/gid changes if required.
+ */
+ if (set_attr.sa_mask) {
+ orig_attr.sa_mask = set_attr.sa_mask;
+ (void) smb_fsop_setattr(sr, kcred, snode,
+ &orig_attr, NULL);
+ }
+ }
+ }
+
+ return (error);
+}
+
+/*ARGSUSED*/
+void
+smb_get_caller_context(smb_request_t *sr, caller_context_t *ct)
+{
+ ct->cc_caller_id = smb_caller_id;
+ ct->cc_pid = 0; /* TBD */
+ ct->cc_sysid = 0; /* TBD */
+}
+
+/*
+ * smb_fsop_sdinherit
+ *
+ * Inherit the security descriptor from the parent container.
+ * This function is called after FS has created the file/folder
+ * so if this doesn't do anything it means FS inheritance is
+ * in place.
+ *
+ * Do inheritance for ZFS internally.
+ *
+ * If we want to let ZFS does the inheritance the
+ * following setting should be true:
+ *
+ * - aclinherit = passthrough
+ * - aclmode = passthrough
+ * - smbd umask = 0777
+ *
+ * This will result in right effective permissions but
+ * ZFS will always add 6 ACEs for owner, owning group
+ * and others to be POSIX compliant. This is not what
+ * Windows clients/users expect, so we decided that CIFS
+ * implements Windows rules and overwrite whatever ZFS
+ * comes up with. This way we also don't have to care
+ * about ZFS aclinherit and aclmode settings.
+ */
+static int
+smb_fsop_sdinherit(smb_request_t *sr, smb_node_t *dnode, smb_fssd_t *fs_sd)
+{
+ int is_dir;
+ acl_t *dacl;
+ acl_t *sacl;
+ ksid_t *owner_sid;
+ int error;
+
+ ASSERT(fs_sd);
+
+ if (sr->tid_tree->t_acltype != ACE_T) {
+ /*
+ * No forced inheritance for non-ZFS filesystems.
+ */
+ fs_sd->sd_secinfo = 0;
+ return (0);
+ }
+
+
+ /* Fetch parent directory's ACL */
+ error = smb_fsop_sdread(sr, kcred, dnode, fs_sd);
+ if (error) {
+ return (error);
+ }
+
+ is_dir = (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR);
+ owner_sid = crgetsid(sr->user_cr, KSID_OWNER);
+ ASSERT(owner_sid);
+ dacl = smb_acl_inherit(fs_sd->sd_zdacl, is_dir, SMB_DACL_SECINFO,
+ owner_sid->ks_id);
+ sacl = smb_acl_inherit(fs_sd->sd_zsacl, is_dir, SMB_SACL_SECINFO,
+ (uid_t)-1);
+
+ smb_fsop_aclfree(fs_sd->sd_zdacl);
+ smb_fsop_aclfree(fs_sd->sd_zsacl);
+
+ fs_sd->sd_zdacl = dacl;
+ fs_sd->sd_zsacl = sacl;
+
+ return (0);
+}
+
+/*
+ * smb_fsop_eaccess
+ *
+ * Returns the effective permission of the given credential for the
+ * specified object.
+ *
+ * This is just a workaround. We need VFS/FS support for this.
+ */
+void
+smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t *eaccess)
+{
+ int access = 0;
+ vnode_t *dir_vp;
+ smb_node_t *unnamed_node;
+
+ ASSERT(cr);
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ unnamed_node = SMB_IS_STREAM(snode);
+ if (unnamed_node) {
+ ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
+ /*
+ * Streams authorization should be performed against the
+ * unnamed stream.
+ */
+ snode = unnamed_node;
+ }
+
+ if (sr->tid_tree->t_flags & SMB_TREE_FLAG_ACEMASKONACCESS) {
+ dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+ smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
+ cr);
+ return;
+ }
+
+ /*
+ * FS doesn't understand 32-bit mask
+ */
+ smb_vop_eaccess(snode->vp, &access, 0, NULL, cr);
+
+ *eaccess = READ_CONTROL | FILE_READ_EA | FILE_READ_ATTRIBUTES;
+
+ if (access & VREAD)
+ *eaccess |= FILE_READ_DATA;
+
+ if (access & VEXEC)
+ *eaccess |= FILE_EXECUTE;
+
+ if (access & VWRITE)
+ *eaccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
+ FILE_WRITE_EA | FILE_APPEND_DATA | FILE_DELETE_CHILD;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c
new file mode 100644
index 0000000000..1d3d8f39cb
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c
@@ -0,0 +1,796 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/modctl.h>
+#include <sys/cred.h>
+#include <sys/ioccom.h>
+#include <sys/priv.h>
+#include <sys/policy.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_ioctl.h>
+#include <smbsrv/smb_kproto.h>
+/*
+ * DDI entry points.
+ */
+static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
+static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
+static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int smb_drv_open(dev_t *, int, int, cred_t *);
+static int smb_drv_close(dev_t, int, int, cred_t *);
+static int smb_drv_busy(void);
+static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+/*
+ * module linkage info for the kernel
+ */
+static struct cb_ops cbops = {
+ smb_drv_open, /* cb_open */
+ smb_drv_close, /* cb_close */
+ nodev, /* cb_strategy */
+ nodev, /* cb_print */
+ nodev, /* cb_dump */
+ nodev, /* cb_read */
+ nodev, /* cb_write */
+ smb_drv_ioctl, /* cb_ioctl */
+ nodev, /* cb_devmap */
+ nodev, /* cb_mmap */
+ nodev, /* cb_segmap */
+ nochpoll, /* cb_chpoll */
+ ddi_prop_op, /* cb_prop_op */
+ NULL, /* cb_streamtab */
+ D_MP, /* cb_flag */
+ CB_REV, /* cb_rev */
+ nodev, /* cb_aread */
+ nodev, /* cb_awrite */
+};
+
+static struct dev_ops devops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ smb_drv_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ smb_drv_attach, /* devo_attach */
+ smb_drv_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &cbops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ NULL, /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* drv_modops */
+ "CIFS Server Protocol %I%", /* drv_linkinfo */
+ &devops,
+};
+
+static struct modlinkage modlinkage = {
+
+ MODREV_1, /* revision of the module, must be: MODREV_1 */
+ &modldrv, /* ptr to linkage structures */
+ NULL,
+};
+
+static int smb_info_init(struct smb_info *si);
+static void smb_info_fini(struct smb_info *si);
+
+extern int smb_fsop_start(void);
+extern void smb_fsop_stop(void);
+
+extern int nt_mapk_start(void);
+extern void nt_mapk_stop(void);
+
+
+extern int smb_get_kconfig(smb_kmod_cfg_t *cfg);
+
+extern void smb_notify_change_daemon(smb_thread_t *thread, void *arg);
+extern void smb_nbt_daemon(smb_thread_t *thread, void *arg);
+extern void smb_tcp_daemon(smb_thread_t *thread, void *arg);
+extern void smb_timers(smb_thread_t *thread, void *arg);
+extern void smb_session_worker(void *arg);
+
+extern int smb_maxbufsize;
+
+extern time_t smb_oplock_timeout;
+
+/* Debug logging level: 0=Disabled, 1=Quiet, 2=Verbose */
+int smbsrv_debug_level;
+
+struct smb_info smb_info;
+
+static dev_info_t *smb_drv_dip = NULL;
+static kmutex_t smb_drv_opencount_lock;
+static int smb_drv_opencount = 0;
+
+/*
+ * Kstat smb_info statistics.
+ */
+static struct smbinfo_stats {
+ kstat_named_t state;
+ kstat_named_t open_files;
+ kstat_named_t open_trees;
+ kstat_named_t open_users;
+} smbinfo_stats = {
+ { "state", KSTAT_DATA_UINT32 },
+ { "open_files", KSTAT_DATA_UINT32 },
+ { "connections", KSTAT_DATA_UINT32 },
+ { "sessions", KSTAT_DATA_UINT32 }
+};
+
+static int smb_kstat_init(void);
+static void smb_kstat_fini(void);
+static int smb_kstat_update_info(kstat_t *ksp, int rw);
+extern void smb_initialize_dispatch_kstat(void);
+extern void smb_remove_dispatch_kstat(void);
+
+static kstat_t *smbinfo_ksp = NULL;
+
+/*
+ * SMB pseudo-driver entry points
+ */
+
+
+
+int
+_init(void)
+{
+ int rc;
+
+ mutex_init(&smb_drv_opencount_lock, NULL, MUTEX_DRIVER, NULL);
+
+ if ((rc = mod_install(&modlinkage)) != 0) {
+ mutex_destroy(&smb_drv_opencount_lock);
+ cmn_err(CE_NOTE, "init: %d\n", rc);
+ return (rc);
+ }
+
+ return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int rc;
+
+ mutex_enter(&smb_drv_opencount_lock);
+ if (smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EBUSY);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ if ((rc = mod_remove(&modlinkage)) == 0)
+ mutex_destroy(&smb_drv_opencount_lock);
+
+ return (rc);
+}
+
+/*
+ * DDI entry points.
+ */
+
+/* ARGSUSED */
+static int
+smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+ ulong_t instance = getminor((dev_t)arg);
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = smb_drv_dip;
+ return (DDI_SUCCESS);
+
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)instance;
+ return (DDI_SUCCESS);
+
+ default:
+ break;
+ }
+
+ return (DDI_FAILURE);
+}
+
+
+static int
+smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ if (cmd != DDI_ATTACH) {
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_get_instance(dip) != 0) {
+ /* we only allow instance 0 to attach */
+ return (DDI_FAILURE);
+ }
+
+ smb_drv_dip = dip;
+
+ /* create the minor node */
+ if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
+ DDI_PSEUDO, 0) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "smb_drv_attach: failed creating minor node");
+ ddi_remove_minor_node(dip, NULL);
+ return (DDI_FAILURE);
+ }
+
+ if (smb_service_init() != 0) {
+ ddi_remove_minor_node(dip, NULL);
+ cmn_err(CE_WARN, "smb_drv_attach: failed to initialize "
+ "SMB service");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ if (cmd != DDI_DETACH)
+ return (DDI_FAILURE);
+
+ mutex_enter(&smb_drv_opencount_lock);
+ /*
+ * Service state value is not protected by a lock in this case but
+ * it shouldn't be possible for the service state machine to transition
+ * TO a busy state at a time when smb_drv_busy() would return false.
+ */
+ if (smb_drv_busy() || smb_svcstate_sm_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (DDI_FAILURE);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ smb_service_fini();
+
+ smb_drv_dip = NULL;
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
+ int *retval)
+{
+ int gmtoff;
+
+ switch (cmd) {
+
+ case SMB_IOC_GMTOFF:
+ if (ddi_copyin((int *)argp, &gmtoff, sizeof (int), flag))
+ return (EFAULT);
+ (void) smb_set_gmtoff((uint32_t)gmtoff);
+ break;
+
+ case SMB_IOC_CONFIG_REFRESH:
+#if 0
+ smb_svcstate_event(SMB_SVCEVT_CONFIG, NULL);
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ int rc = 0;
+
+ /*
+ * Only allow one open at a time
+ */
+ mutex_enter(&smb_drv_opencount_lock);
+ if (smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EBUSY);
+ }
+ smb_drv_opencount++;
+ mutex_exit(&smb_drv_opencount_lock);
+
+ /*
+ * Check caller's privileges.
+ */
+ if (secpolicy_smb(credp) != 0) {
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EPERM);
+ }
+
+ /*
+ * Start SMB service state machine
+ */
+ rc = smb_svcstate_sm_start(&smb_info.si_svc_sm_ctx);
+
+ if (rc != 0) {
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+ return (rc);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ mutex_enter(&smb_drv_opencount_lock);
+ if (!smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (0);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL);
+
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+
+ return (0);
+}
+
+/*
+ * Convenience function - must be called with smb_drv_opencount_lock held.
+ */
+static int
+smb_drv_busy(void)
+{
+ ASSERT(mutex_owned(&smb_drv_opencount_lock));
+ return (smb_drv_opencount);
+}
+
+/*
+ * SMB Service initialization and startup functions
+ */
+
+int
+smb_service_init(void)
+{
+ int rc;
+
+ rc = smb_info_init(&smb_info);
+ if (rc != 0) {
+ return (rc);
+ }
+
+ rc = smb_svcstate_sm_init(&smb_info.si_svc_sm_ctx);
+ if (rc != 0) {
+ smb_info_fini(&smb_info);
+ return (rc);
+ }
+
+ rc = smb_kstat_init();
+ if (rc != 0) {
+ smb_kstat_fini();
+ return (rc);
+ }
+
+ smb_winpipe_init();
+
+ return (0);
+}
+
+void
+smb_service_fini(void)
+{
+ smb_winpipe_fini();
+
+ smb_kstat_fini();
+
+ smb_svcstate_sm_fini(&smb_info.si_svc_sm_ctx);
+
+ smb_info_fini(&smb_info);
+}
+
+/*
+ * Progress bits for smb_info.si_open_progress. For use only by
+ * smb_service_open/smb_service_close.
+ */
+#define SMB_FS_STARTED 0x01
+#define LMSHRD_KCLIENT_STARTED 0x02
+#define SMB_KDOOR_CLNT_STARTED 0x04
+#define SMB_KDOOR_SRV_STARTED 0x08
+#define SMB_THREADS_STARTED 0x10
+
+int
+smb_service_open(struct smb_info *si)
+{
+ int rc;
+ int size; /* XXX TEMPORARY (remove when kconfig is removed) */
+
+ /* Track progress so we can cleanup from a partial failure */
+ si->si_open_progress = 0;
+ si->si_connect_progress = 0;
+
+ /* XXX TEMPORARY */
+ if (smb_get_kconfig(&si->si) == 0) {
+ if (si->si.skc_sync_enable)
+ smb_set_stability(1);
+
+ if (si->si.skc_flush_required)
+ smb_commit_required(0);
+
+ if (si->si.skc_maxconnections == 0)
+ si->si.skc_maxconnections = 0xFFFFFFFF;
+
+ size = si->si.skc_maxbufsize;
+ if (size != 0) {
+ if (size < 37 || size > 64)
+ size = 37;
+ smb_maxbufsize = SMB_NT_MAXBUF(size);
+ }
+
+ /*
+ * XXX should not override configuration.
+ * For now, this disables server side
+ * signing regardless of configuration.
+ */
+ si->si.skc_signing_enable = 0;
+ si->si.skc_signing_required = 0;
+ si->si.skc_signing_check = 0;
+
+ smb_correct_keep_alive_values(si->si.skc_keepalive);
+
+ /*
+ * XXX The following code was pulled from smb_oplock_init.
+ * It should be combined with with the config process if
+ * this info will be stored with the configuration or with
+ * the smb_fsop_start function if the data will be stored
+ * in the root of the fs.
+ */
+
+ /*
+ * XXX oplock enable flag.
+ * Should be stored in extended attribute in root of fs
+ * or a ZFS user-defined property.
+ */
+ if (si->si.skc_oplock_enable == 0) {
+ cmn_err(CE_NOTE, "SmbOplocks: disabled");
+ }
+
+ smb_oplock_timeout = si->si.skc_oplock_timeout;
+
+ /*
+ * XXX oplock timeout. Can a customer configure this?
+ */
+ if (si->si.skc_oplock_timeout < OPLOCK_MIN_TIMEOUT)
+ smb_oplock_timeout = OPLOCK_MIN_TIMEOUT;
+
+ } else {
+ return (EIO); /* XXX Errno? */
+ }
+
+ if ((rc = smb_fsop_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_FS_STARTED;
+
+ if ((rc = lmshrd_kclient_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= LMSHRD_KCLIENT_STARTED;
+
+ if ((rc = smb_kdoor_clnt_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_KDOOR_CLNT_STARTED;
+
+ if ((rc = smb_kdoor_srv_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_KDOOR_SRV_STARTED;
+
+ if ((rc = smb_service_start_threads(si)) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_THREADS_STARTED;
+
+ return (0);
+}
+
+void
+smb_service_close(struct smb_info *si)
+{
+ if (si->si_open_progress & SMB_THREADS_STARTED)
+ smb_service_stop_threads(si);
+
+ if (si->si_open_progress & SMB_KDOOR_SRV_STARTED)
+ smb_kdoor_srv_stop();
+
+ if (si->si_open_progress & SMB_KDOOR_CLNT_STARTED)
+ smb_kdoor_clnt_stop();
+
+ if (si->si_open_progress & LMSHRD_KCLIENT_STARTED)
+ lmshrd_kclient_stop();
+
+ if (si->si_open_progress & SMB_FS_STARTED)
+ smb_fsop_stop();
+}
+
+/*
+ * Start the Netbios and TCP services.
+ *
+ * Awaken arguments are not known until thread starts.
+ *
+ * XXX We give up the NET_MAC_AWARE privilege because it keeps us from
+ * re-opening the connection when there are leftover TCP connections in
+ * TCPS_TIME_WAIT state. There seem to be some security ramifications
+ * around reestablishing a connection while possessing the NET_MAC_AWARE
+ * privilege.
+ *
+ * This approach may cause problems when we try to support zones. An
+ * alternative would be to retry the connection setup for a fixed period
+ * of time until the stale connections clear up but that implies we
+ * would be offline for a couple minutes every time the service is
+ * restarted with active connections.
+ */
+int
+smb_service_connect(struct smb_info *si)
+{
+ int rc1, rc2;
+
+ if ((rc1 = setpflags(NET_MAC_AWARE, 0, CRED())) != 0) {
+ cmn_err(CE_WARN, "Cannot remove NET_MAC_AWARE privilege");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)rc1);
+ return (rc1);
+ }
+
+ rc1 = smb_thread_start(&si->si_nbt_daemon);
+ rc2 = smb_thread_start(&si->si_tcp_daemon);
+ if (rc2 != 0)
+ rc1 = rc2;
+ return (rc1);
+}
+
+void
+smb_service_disconnect(struct smb_info *si)
+{
+ smb_thread_stop(&si->si_nbt_daemon);
+ smb_thread_stop(&si->si_tcp_daemon);
+}
+
+/*
+ * Start any service-related kernel threads except for the NBT and TCP
+ * daemon threads. Those service daemon threads are handled separately.
+ *
+ * Returns 0 for success, non-zero for failure. If failure is returned the
+ * caller should call smb_service_stop_threads to cleanup any threads that
+ * were successfully started.
+ */
+int
+smb_service_start_threads(struct smb_info *si)
+{
+ int rval;
+
+ si->thread_pool = taskq_create(
+ "smb_workers",
+ si->si.skc_maxworkers,
+ SMB_WORKER_PRIORITY,
+ si->si.skc_maxworkers,
+ INT_MAX,
+ TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
+ ASSERT(si->thread_pool != NULL);
+
+ rval = smb_thread_start(&si->si_thread_notify_change);
+ if (rval != 0)
+ return (rval);
+
+ rval = smb_thread_start(&si->si_thread_timers);
+ if (rval != 0) {
+ smb_thread_stop(&si->si_thread_notify_change);
+ return (rval);
+ }
+
+ return (0);
+}
+
+void
+smb_service_stop_threads(struct smb_info *si)
+{
+ smb_thread_stop(&si->si_thread_timers);
+ smb_thread_stop(&si->si_thread_notify_change);
+ taskq_destroy(si->thread_pool);
+}
+
+static int
+smb_info_init(struct smb_info *si)
+{
+ int i;
+
+ bzero(si, sizeof (smb_info));
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_llist_constructor(&si->node_hash_table[i],
+ sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
+ }
+
+ smb_llist_constructor(&si->si_vfs_list,
+ sizeof (smb_vfs_t), offsetof(smb_vfs_t, sv_lnd));
+
+ smb_slist_constructor(&si->si_ncr_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ smb_slist_constructor(&si->si_nce_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ si->si_cache_vfs = kmem_cache_create("smb_vfs_cache",
+ sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_request = kmem_cache_create("smb_request_cache",
+ sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_session = kmem_cache_create("smb_session_cache",
+ sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_user = kmem_cache_create("smb_user_cache",
+ sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_tree = kmem_cache_create("smb_tree_cache",
+ sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_ofile = kmem_cache_create("smb_ofile_cache",
+ sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_odir = kmem_cache_create("smb_odir_cache",
+ sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_node = kmem_cache_create("smb_smb_node_cache",
+ sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+
+ smb_thread_init(&si->si_nbt_daemon, "smb_nbt_daemon", smb_nbt_daemon,
+ si, NULL, NULL);
+ smb_thread_init(&si->si_tcp_daemon, "smb_tcp_daemon", smb_tcp_daemon,
+ si, NULL, NULL);
+ smb_thread_init(&si->si_thread_notify_change,
+ "smb_notify_change_daemon", smb_notify_change_daemon, &smb_info,
+ NULL, NULL);
+ smb_thread_init(&si->si_thread_timers, "smb_timers", smb_timers,
+ si, NULL, NULL);
+
+ return (0);
+}
+
+static void
+smb_info_fini(struct smb_info *si)
+{
+ int i;
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_node_t *node;
+
+ /*
+ * The following sequence is just intended for sanity check.
+ * This will have to be modified when the code goes into
+ * production.
+ *
+ * The SMB node hash table should be emtpy at this point. If the
+ * hash table is not empty all the nodes remaining are displayed
+ * (it should help figure out what actions led to this state)
+ * and "oops" will be set to B_TRUE which will trigger the
+ * ASSERT that follows.
+ *
+ * The reason why SMB nodes are still remaining in the hash
+ * table is problably due to a mismatch between calls to
+ * smb_node_lookup() and smb_node_release(). You must track that
+ * down.
+ *
+ * Now if you are reading this comment because you actually hit
+ * the ASSERT, the temptation to ignore it is going to be very
+ * strong. To help you make the right decision you should know
+ * that when the ASSERT happened a message containing you SunID
+ * has been sent to cifsgate. By now it has been logged into a
+ * special database.
+ *
+ * You are being watched...
+ */
+ node = smb_llist_head(&si->node_hash_table[i]);
+ ASSERT(node == NULL);
+ }
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_llist_destructor(&si->node_hash_table[i]);
+ }
+
+ smb_llist_destructor(&si->si_vfs_list);
+
+ kmem_cache_destroy(si->si_cache_vfs);
+ kmem_cache_destroy(si->si_cache_request);
+ kmem_cache_destroy(si->si_cache_session);
+ kmem_cache_destroy(si->si_cache_user);
+ kmem_cache_destroy(si->si_cache_tree);
+ kmem_cache_destroy(si->si_cache_ofile);
+ kmem_cache_destroy(si->si_cache_odir);
+ kmem_cache_destroy(si->si_cache_node);
+
+ smb_thread_destroy(&si->si_nbt_daemon);
+ smb_thread_destroy(&si->si_tcp_daemon);
+ smb_thread_destroy(&si->si_thread_notify_change);
+ smb_thread_destroy(&si->si_thread_timers);
+}
+
+static int
+smb_kstat_init()
+{
+
+ /* create and initialize smb kstats - smb_info stats */
+ smbinfo_ksp = kstat_create("smb", 0, "smb_info", "misc",
+ KSTAT_TYPE_NAMED, sizeof (smbinfo_stats) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL);
+ if (smbinfo_ksp) {
+ smbinfo_ksp->ks_data = (void *) &smbinfo_stats;
+ smbinfo_ksp->ks_update = smb_kstat_update_info;
+ kstat_install(smbinfo_ksp);
+ }
+
+ /* create and initialize smb kstats - smb_dispatch stats */
+ smb_initialize_dispatch_kstat();
+
+ return (0);
+}
+
+static void
+smb_kstat_fini()
+{
+ if (smbinfo_ksp != NULL) {
+ kstat_delete(smbinfo_ksp);
+ smbinfo_ksp = NULL;
+ }
+
+ smb_remove_dispatch_kstat();
+}
+
+/* ARGSUSED */
+static int
+smb_kstat_update_info(kstat_t *ksp, int rw)
+{
+ if (rw == KSTAT_WRITE) {
+ return (EACCES);
+ } else {
+ smbinfo_stats.state.value.ui32 =
+ smb_info.si_svc_sm_ctx.ssc_state;
+ smbinfo_stats.open_files.value.ui32 = smb_info.open_files;
+ smbinfo_stats.open_trees.value.ui32 = smb_info.open_trees;
+ smbinfo_stats.open_users.value.ui32 = smb_info.open_users;
+ }
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c
new file mode 100644
index 0000000000..df2cd5368b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_clnt.c
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/door.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+door_handle_t smb_kdoor_clnt_dh;
+
+/*
+ * smb_kdoor_clnt_free
+ *
+ * This function should be invoked to free both the argument/result door buffer
+ * regardless of the status of the up-call.
+ *
+ * The doorfs allocates a new buffer if the result buffer passed by the client
+ * is too small. This function will deallocate that buffer as well.
+ */
+void
+smb_kdoor_clnt_free(char *argp, size_t arg_size, char *rbufp, size_t rbuf_size)
+{
+ if (argp) {
+ if (argp == rbufp) {
+ kmem_free(argp, arg_size);
+ } else if (rbufp) {
+ kmem_free(argp, arg_size);
+ kmem_free(rbufp, rbuf_size);
+ }
+ } else {
+ if (rbufp)
+ kmem_free(rbufp, rbuf_size);
+ }
+}
+
+/*
+ * smb_kdoor_clnt_start
+ *
+ * The SMB kernel module should invoke this function upon startup.
+ */
+int
+smb_kdoor_clnt_start()
+{
+ int rc = 0;
+
+ rc = door_ki_open(SMB_DR_SVC_NAME, &smb_kdoor_clnt_dh);
+
+ return (rc);
+}
+
+/*
+ * smb_kdoor_clnt_stop
+ *
+ * The SMB kernel module should invoke this function upon unload.
+ */
+void
+smb_kdoor_clnt_stop()
+{
+ door_ki_rele(smb_kdoor_clnt_dh);
+}
+
+/*
+ * smb_kdoor_clnt_upcall
+ *
+ * This function will make a door up-call to the server function
+ * associated with the door descriptor fp. The specified door
+ * request buffer (i.e. argp) will be passed as the argument to the
+ * door_ki_upcall(). Upon success, the result buffer is returned. Otherwise,
+ * NULL pointer is returned. The size of the result buffer is returned
+ * via rbufsize.
+ */
+char *
+smb_kdoor_clnt_upcall(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t desc_num, size_t *rbufsize)
+{
+ door_arg_t door_arg;
+ int err;
+
+ if (!argp) {
+ cmn_err(CE_WARN, "smb_kdoor_clnt_upcall: invalid parameter");
+ return (NULL);
+ }
+
+ door_arg.data_ptr = argp;
+ door_arg.data_size = arg_size;
+ door_arg.desc_ptr = dp;
+ door_arg.desc_num = desc_num;
+ door_arg.rbuf = argp;
+ door_arg.rsize = arg_size;
+
+ if ((err = door_ki_upcall(smb_kdoor_clnt_dh, &door_arg)) != 0) {
+ cmn_err(CE_WARN, "smb_kdoor_clnt_upcall: failed(%d)", err);
+ kmem_free(argp, arg_size);
+ argp = NULL;
+ return (NULL);
+ }
+
+ if (smb_dr_get_res_stat(door_arg.data_ptr, door_arg.rsize) !=
+ SMB_DR_OP_SUCCESS) {
+ smb_kdoor_clnt_free(argp, arg_size, door_arg.rbuf,
+ door_arg.rsize);
+ *rbufsize = 0;
+ return (NULL);
+ }
+ *rbufsize = door_arg.rsize;
+ return (door_arg.data_ptr);
+
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c
new file mode 100644
index 0000000000..701e587fbc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_encdec.c
@@ -0,0 +1,266 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_xdr.h>
+
+
+/*
+ * smb_kdr_decode_common
+ *
+ * This function can be used for decoding both door request and result buffer.
+ * pre-condition: data is non-null pointer, and is bzero'd.
+ */
+int
+smb_kdr_decode_common(char *buf, size_t len, xdrproc_t proc, void *data)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ if (!data) {
+ cmn_err(CE_WARN, "smb_kdr_decode_common: invalid param");
+ return (-1);
+ }
+
+ xdrmem_create(&xdrs, buf, len, XDR_DECODE);
+ if (!proc(&xdrs, data))
+ rc = -1;
+
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * smb_kdr_encode_common
+ *
+ * This function is used for encoding both request/result door buffer.
+ * This function will first encode integer value 'reserved' (opcode/status),
+ * followed by the data (which will be encoded via the specified XDR routine.
+ *
+ * Returns encoded buffer upon success. Otherwise, returns NULL.
+ */
+char *
+smb_kdr_encode_common(uint_t reserved, void *data, xdrproc_t proc, size_t *len)
+{
+ XDR xdrs;
+ char *buf;
+
+ if (proc && !data) {
+ cmn_err(CE_WARN, "smb_kdr_encode_common: invalid param");
+ *len = 0;
+ return (NULL);
+ }
+
+ *len = xdr_sizeof(xdr_uint32_t, &reserved);
+ if (proc)
+ *len += xdr_sizeof(proc, data);
+ buf = kmem_alloc(*len, KM_SLEEP);
+ xdrmem_create(&xdrs, buf, *len, XDR_ENCODE);
+ if (!xdr_uint32_t(&xdrs, &reserved)) {
+ cmn_err(CE_WARN, "smb_kdr_encode_common: encode error 1");
+ kmem_free(buf, *len);
+ *len = 0;
+ xdr_destroy(&xdrs);
+ return (NULL);
+ }
+
+ if (proc && !proc(&xdrs, data)) {
+ cmn_err(CE_WARN, "smb_kdr_encode_common: encode error 2");
+ kmem_free(buf, *len);
+ buf = NULL;
+ *len = 0;
+ }
+
+ xdr_destroy(&xdrs);
+ return (buf);
+}
+
+/*
+ * Get the opcode of the door argument buffer.
+ */
+int
+smb_dr_get_opcode(char *argp, size_t arg_size)
+{
+ int opcode;
+
+ if (smb_kdr_decode_common(argp, arg_size, xdr_uint32_t, &opcode) != 0)
+ opcode = -1;
+ return (opcode);
+}
+
+/*
+ * Set the opcode of the door argument buffer.
+ */
+char *
+smb_dr_set_opcode(uint32_t opcode, size_t *len)
+{
+ char *buf;
+
+ buf = smb_kdr_encode_common(opcode, NULL, NULL, len);
+ return (buf);
+}
+
+/*
+ * Get the status of the door result buffer.
+ */
+int
+smb_dr_get_res_stat(char *rbufp, size_t rbuf_size)
+{
+ int stat;
+ if (smb_kdr_decode_common(rbufp, rbuf_size, xdr_uint32_t, &stat) != 0)
+ stat = -1;
+ return (stat);
+}
+
+/*
+ * Set the status of the door result buffer.
+ */
+char *
+smb_dr_set_res_stat(uint32_t stat, size_t *len)
+{
+ char *buf;
+
+ buf = smb_kdr_encode_common(stat, NULL, NULL, len);
+ return (buf);
+}
+
+char *
+smb_dr_encode_arg_get_token(netr_client_t *clnt_info, size_t *len)
+{
+
+ char *buf;
+ smb_dr_bytes_t arg;
+ uint_t opcode = SMB_DR_USER_AUTH_LOGON;
+
+ arg.bytes_val = netr_client_mkselfrel(clnt_info,
+ &arg.bytes_len);
+
+ buf = smb_kdr_encode_common(opcode, &arg, xdr_smb_dr_bytes_t, len);
+ kmem_free(arg.bytes_val, arg.bytes_len);
+ return (buf);
+}
+
+smb_token_t *
+smb_dr_decode_res_token(char *buf, size_t len)
+{
+ smb_dr_bytes_t res;
+ smb_token_t *token;
+
+ bzero(&res, sizeof (smb_dr_bytes_t));
+ if (smb_kdr_decode_common(buf, len, xdr_smb_dr_bytes_t, &res) !=
+ 0) {
+ cmn_err(CE_WARN, "smb_dr_decode_res_token: failed");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+ return (NULL);
+ }
+ token = smb_token_mkabsolute(res.bytes_val, res.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+
+ return (token);
+}
+
+char *
+smb_dr_encode_string(uint32_t reserved, char *str, size_t *len)
+{
+ char *buf = NULL;
+ smb_dr_string_t res;
+
+ if (!str) {
+ *len = 0;
+ return (buf);
+ }
+
+ res.buf = str;
+ if ((buf = smb_kdr_encode_common(reserved, &res,
+ xdr_smb_dr_string_t, len)) == 0)
+ cmn_err(CE_WARN, "smb_dr_encode_string: failed");
+ return (buf);
+}
+
+/*
+ * smb_dr_decode_kshare()
+ *
+ * The kshare information arrives encoded in a flat buffer, so retrieve
+ * the flat buffer and convert it to an smb_dr_kshare structure.
+ */
+
+smb_dr_kshare_t *
+smb_dr_decode_kshare(char *buf, size_t len)
+{
+ smb_dr_bytes_t res;
+ smb_dr_kshare_t *kshare;
+
+ bzero(&res, sizeof (smb_dr_bytes_t));
+ if (smb_kdr_decode_common(buf, len, xdr_smb_dr_bytes_t, &res) !=
+ 0) {
+ cmn_err(CE_WARN, "smb_dr_decode_kshare: failed");
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+ return (NULL);
+ }
+ kshare = smb_share_mkabsolute(res.bytes_val, res.bytes_len);
+ xdr_free(xdr_smb_dr_bytes_t, (char *)&res);
+
+ return (kshare);
+}
+
+/*
+ * smb_share_mkabsolute
+ *
+ * decode: flat buffer -> structure
+ */
+
+smb_dr_kshare_t *
+smb_share_mkabsolute(uint8_t *buf, uint32_t len)
+{
+ smb_dr_kshare_t *obj;
+ XDR xdrs;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
+ obj = kmem_zalloc(sizeof (smb_dr_kshare_t), KM_SLEEP);
+
+ if (!xdr_smb_dr_kshare_t(&xdrs, obj)) {
+ kmem_free(obj, sizeof (smb_dr_kshare_t));
+ obj = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ return (obj);
+}
+
+void
+smb_dr_kshare_free(smb_dr_kshare_t *kshare)
+{
+ if (!kshare)
+ return;
+
+ xdr_free(xdr_smb_dr_kshare_t, (char *)kshare);
+ kmem_free(kshare, sizeof (smb_dr_kshare_t));
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c
new file mode 100644
index 0000000000..d6be914182
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c
@@ -0,0 +1,159 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Kernel door operations
+ */
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smb_incl.h>
+
+/* SMB kernel module's door operation table */
+smb_kdr_op_t smb_kdoorsrv_optab[] =
+{
+ smb_kdr_op_user_num,
+ smb_kdr_op_users,
+ smb_kdr_op_share
+};
+
+int
+smb_kdr_is_valid_opcode(int opcode)
+{
+ if (opcode < 0 ||
+ opcode > (sizeof (smb_kdoorsrv_optab) / sizeof (smb_kdr_op_t)))
+ return (-1);
+ else
+ return (0);
+}
+
+/*ARGSUSED*/
+char *
+smb_kdr_op_user_num(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
+{
+ uint32_t num;
+ char *rbuf;
+
+ *errno = SMB_DR_OP_SUCCESS;
+ num = smb_user_get_num();
+ rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, &num, xdr_uint32_t,
+ rbufsize);
+ if (!rbuf) {
+ *errno = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ return (NULL);
+ }
+
+ return (rbuf);
+}
+
+char *
+smb_kdr_op_users(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
+{
+ smb_dr_ulist_t *ulist;
+ uint32_t offset;
+ char *rbuf = NULL;
+
+ *errno = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+ if (smb_kdr_decode_common(argp, arg_size, xdr_uint32_t, &offset) != 0) {
+ *errno = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ ulist = kmem_zalloc(sizeof (smb_dr_ulist_t), KM_SLEEP);
+ (void) smb_dr_ulist_get(offset, ulist);
+
+ if ((rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, ulist,
+ xdr_smb_dr_ulist_t, rbufsize)) == NULL) {
+ *errno = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ }
+
+ smb_dr_ulist_free(ulist);
+ kmem_free(ulist, sizeof (smb_dr_ulist_t));
+ return (rbuf);
+}
+
+/*
+ * smb_kdr_op_share()
+ *
+ * This function decodes an smb_dr_kshare_t structure from userland and
+ * calls smb_share() to take action depending on whether a share is being
+ * enabled or disabled.
+ */
+
+char *
+smb_kdr_op_share(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
+{
+ smb_dr_kshare_t *kshare;
+ char *rbuf = NULL;
+ int error = 0;
+
+ *errno = SMB_DR_OP_SUCCESS;
+ *rbufsize = 0;
+
+ kshare = smb_dr_decode_kshare(argp, arg_size);
+
+ if (kshare == NULL) {
+ *errno = SMB_DR_OP_ERR_DECODE;
+ return (NULL);
+ }
+
+ switch (kshare->k_op) {
+ case LMSHR_ADD:
+ error = smb_share_export(kshare->k_path);
+ break;
+ case LMSHR_DELETE:
+ error = smb_share_unexport(kshare->k_path, kshare->k_sharename);
+ break;
+ default:
+ ASSERT(0);
+ error = EINVAL;
+ break;
+ }
+
+ smb_dr_kshare_free(kshare);
+
+ if (error)
+ return (NULL);
+
+ rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, &error, xdr_int32_t,
+ rbufsize);
+
+ if (!rbuf) {
+ *errno = SMB_DR_OP_ERR_ENCODE;
+ *rbufsize = 0;
+ return (NULL);
+ }
+
+ return (rbuf);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c b/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c
new file mode 100644
index 0000000000..7199aa62f4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c
@@ -0,0 +1,217 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Kernel door service
+ * It has dependency on the kernel door client interface because the downcall
+ * descriptor is required to be passed up to SMB daemon via door up-call.
+ */
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/door.h>
+#include <sys/kmem.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+
+door_handle_t smb_kdoor_hdl = NULL;
+
+/*
+ * Since the action performed by smb_kdoor_srv_callback might vary
+ * according to request type/opcode, the smb_kdoor_cookie will
+ * be set to the request type in the server procedure
+ * (i.e. smb_kdoor_svc). It will then be passed to the callback
+ * function when the kernel is done with the copyout operation.
+ */
+int smb_kdoor_cookie = -1;
+
+extern smb_kdr_op_t smb_kdoorsrv_optab[];
+
+/* forward declaration */
+void smb_kdoor_svc(void *data, door_arg_t *dap, void (**destfnp)(void *,
+ void *), void **destarg, int *error);
+
+/*
+ * smb_kdoor_srv_start
+ *
+ * When driver is opened, this function should be called to create the
+ * kernel door. The door descriptor will then be passed up to the
+ * user-space SMB daemon.
+ *
+ * Returns 0 upon success otherwise non-zero
+ */
+int
+smb_kdoor_srv_start()
+{
+ door_desc_t smb_kdoor_desc;
+ int err;
+ int res;
+ int opcode = SMB_DR_SET_DWNCALL_DESC;
+
+ if ((err = door_ki_create(smb_kdoor_svc,
+ &smb_kdoor_cookie, 0, &smb_kdoor_hdl)) != 0) {
+ cmn_err(CE_WARN, "SmbKdoorInit: door_create"
+ " failed(%d)", err);
+ return (err);
+ }
+
+ smb_kdoor_desc.d_attributes = DOOR_HANDLE;
+ smb_kdoor_desc.d_data.d_handle = smb_kdoor_hdl;
+
+ res = smb_upcall_set_dwncall_desc(opcode, &smb_kdoor_desc, 1);
+ if (res != SMB_DR_OP_SUCCESS) {
+ cmn_err(CE_WARN, "SmbKdoorInit: smbd failed to set the"
+ " downcall descriptor res=%d", res);
+ smb_kdoor_srv_stop();
+ return (EIO);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_kdoor_srv_stop
+ *
+ * This function will stop the kernel door service when the driver is closed.
+ */
+void
+smb_kdoor_srv_stop()
+{
+ if (smb_kdoor_hdl) {
+ door_ki_rele(smb_kdoor_hdl);
+ smb_kdoor_hdl = NULL;
+ }
+}
+
+/*
+ * smb_kdoor_srv_callback
+ *
+ * This callback function will be executed by the kernel after copyout()
+ * completes. Currently, this function only free the server buffer that
+ * was previously allocated in the smb_kdoor_srv(). It can be enhanced
+ * to perform any action based on the opcode if there is a need in the
+ * future.
+ */
+static void
+smb_kdoor_srv_callback(void *cookie, void *arg)
+{
+ /*LINTED E_FUNC_VAR_UNUSED*/
+ int *opcode;
+ smb_kdoor_cb_arg_t *cbarg;
+
+ if (cookie)
+ opcode = (int *)cookie;
+
+ if (!arg)
+ return;
+
+ cbarg = (smb_kdoor_cb_arg_t *)arg;
+ if (cbarg->rbuf)
+ kmem_free(cbarg->rbuf, cbarg->rbuf_size);
+
+ kmem_free(cbarg, sizeof (smb_kdoor_cb_arg_t));
+}
+
+
+void
+smb_kdoor_svc(void *cookie, door_arg_t *dap, void (**destfnp)(void *,
+ void *), void **destarg, int *error)
+{
+ int opcode;
+ smb_kdoor_cb_arg_t *cbarg;
+ size_t arg_size;
+ char *argp = NULL;
+ smb_kdr_op_t smbop;
+
+ /*
+ * Be aware that *destfnp cannot be NULL even if there isn't
+ * any additional work after the kernel completes copyout() operation.
+ */
+ *destfnp = smb_kdoor_srv_callback;
+ *destarg = NULL;
+ *error = 0;
+
+ if (!dap) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: invalid arguments");
+ *error = EINVAL;
+ return;
+ }
+
+ arg_size = dap->data_size;
+ argp = kmem_alloc(arg_size, KM_SLEEP);
+ /* The data_ptr points to user data */
+ (void) copyin(dap->data_ptr, argp, dap->data_size);
+ /* initialize the returned data size to be 0 */
+ dap->data_size = 0;
+
+ opcode = smb_dr_get_opcode(argp, arg_size);
+ *((int *)cookie) = opcode;
+
+ if (smb_kdr_is_valid_opcode(opcode) != 0) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: invalid opcode(%d)", opcode);
+ *error = EINVAL;
+ kmem_free(argp, arg_size);
+ return;
+
+ }
+
+ smbop = smb_kdoorsrv_optab[opcode];
+ cbarg = kmem_alloc(sizeof (smb_kdoor_cb_arg_t), KM_SLEEP);
+ if ((cbarg->rbuf = smbop(argp + sizeof (opcode),
+ arg_size - sizeof (opcode), &cbarg->rbuf_size, error)) == NULL) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: door op failed");
+
+ switch (*error) {
+ case SMB_DR_OP_ERR_ENCODE:
+ *error = EINVAL;
+ cmn_err(CE_WARN, "SmbKdoorSvc: encode error");
+ break;
+ case SMB_DR_OP_ERR_DECODE:
+ *error = EINVAL;
+ cmn_err(CE_WARN, "SmbKdoorSvc: decode error");
+ break;
+ case SMB_DR_OP_ERR_EMPTYBUF:
+ if ((cbarg->rbuf = smb_dr_set_res_stat(
+ SMB_DR_OP_ERR_EMPTYBUF, &cbarg->rbuf_size))
+ == NULL) {
+ cmn_err(CE_WARN, "SmbKdoorSvc: return nothing");
+ *error = EINVAL;
+ }
+ *error = 0;
+ break;
+ default:
+ cmn_err(CE_WARN, "SmbKdoorSvc: unknown error");
+ }
+ }
+
+ kmem_free(argp, arg_size);
+ dap->data_size = cbarg->rbuf_size;
+ dap->rbuf = cbarg->rbuf;
+ *destarg = cbarg;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
new file mode 100644
index 0000000000..53e8d0326e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: lock_byte_range
+ *
+ * The lock record message is sent to lock the given byte range. More than
+ * one non-overlapping byte range may be locked in a given file. Locks
+ * prevent attempts to lock, read or write the locked portion of the file
+ * by other clients or Pids. Overlapping locks are not allowed. Offsets
+ * beyond the current end of file may be locked. Such locks will not cause
+ * allocation of file space.
+ *
+ * Since Offset is a 32 bit quantity, this request is inappropriate for
+ * general locking within a very large file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 5
+ * USHORT Fid; File handle
+ * ULONG Count; Count of bytes to lock
+ * ULONG Offset; Offset from start of file
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Locks may only be unlocked by the Pid that performed the lock.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * This client request does not wait for the lock to be granted. If the
+ * lock can not be immediately granted (within 200-300 ms), the server
+ * should return failure to the client
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_lock_byte_range(struct smb_request *sr)
+{
+ uint32_t count;
+ uint32_t off;
+ DWORD result;
+
+ if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &count, &off) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ /*
+ * The last parameter is lock type. This is dependent on
+ * lock flag (3rd parameter). Since the lock flag is
+ * set to be exclusive, lock type is passed as
+ * normal lock (write lock).
+ */
+ result = smb_lock_range(sr, sr->fid_ofile,
+ (off_t)off, (uint64_t)count, 0, SMB_LOCK_TYPE_READWRITE);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c b/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
new file mode 100644
index 0000000000..e043472af5
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_svc.c
@@ -0,0 +1,709 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides range lock functionality for CIFS/SMB clients.
+ * Lock range service functions process SMB lock and and unlock
+ * requests for a file by applying lock rules and marks file range
+ * as locked if the lock is successful otherwise return proper
+ * error code.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+static int
+smb_lock_range_overlap(struct smb_lock *lock, uint64_t start, uint64_t length);
+
+static uint32_t smb_lock_range_lckrules(struct smb_request *sr,
+ smb_ofile_t *file, struct smb_node *node, smb_lock_t *dlock,
+ smb_lock_t **clockp);
+
+static uint32_t
+smb_lock_wait(struct smb_request *sr, smb_lock_t *b_lock, smb_lock_t *c_lock);
+
+static uint32_t
+smb_lock_range_ulckrules(struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length,
+ struct smb_lock **nodelock);
+
+static smb_lock_t *smb_lock_create(smb_request_t *sr,
+ uint64_t start, uint64_t length, uint32_t locktype, uint32_t timeout);
+static void smb_lock_destroy(smb_lock_t *lock);
+static void smb_lock_free(smb_lock_t *lock);
+
+/*
+ * smb_lock_range_overlap
+ *
+ * Checks if lock range(start, length) overlaps
+ * range in lock structure.
+ *
+ * return values:
+ * 0 - Lock range doesn't overlap
+ * 1 - Lock range overlaps.
+ */
+
+#define RANGE_NO_OVERLAP 0
+#define RANGE_OVERLAP 1
+
+static int
+smb_lock_range_overlap(struct smb_lock *lock, uint64_t start, uint64_t length)
+{
+ /* A zero-length range doesn't overlap anything */
+ if (length == 0 || lock->l_length == 0)
+ return (RANGE_NO_OVERLAP);
+
+ if (start < lock->l_start) {
+ if (start + length > lock->l_start)
+ return (RANGE_OVERLAP);
+ } else if (start < lock->l_start + lock->l_length)
+ return (RANGE_OVERLAP);
+
+ if (start + length > lock->l_start + lock->l_length) {
+ if (start < lock->l_start + lock->l_length)
+ return (RANGE_OVERLAP);
+ } else if (start + length > lock->l_start)
+ return (RANGE_OVERLAP);
+
+ /* Lock range doen't overlap */
+ return (RANGE_NO_OVERLAP);
+}
+
+/*
+ * smb_lock_range_lckrules
+ *
+ * Lock range rules:
+ * 1. Overlapping read locks are allowed if the
+ * current locks in the region are only read locks
+ * irrespective of pid of smb client issuing lock request.
+ *
+ * 2. Read lock in the overlapped region of write lock
+ * are allowed if the pervious lock is performed by the
+ * same pid and connection.
+ *
+ * return status:
+ * NT_STATUS_SUCCESS - Input lock range adapts to lock rules.
+ * NT_STATUS_LOCK_NOT_GRANTED - Input lock conflicts lock rules.
+ * NT_STATUS_CANCELLED - Error in processing lock rules
+ */
+static uint32_t
+smb_lock_range_lckrules(
+ struct smb_request *sr,
+ smb_ofile_t *file,
+ struct smb_node *node,
+ smb_lock_t *dlock,
+ smb_lock_t **clockp)
+{
+ smb_lock_t *lock;
+ uint32_t status = NT_STATUS_SUCCESS;
+
+ /* Check if file is closed */
+ if (!smb_ofile_is_open(file)) {
+ return (NT_STATUS_RANGE_NOT_LOCKED);
+ }
+
+ /* Caller must hold lock for node->n_lock_list */
+ for (lock = smb_llist_head(&node->n_lock_list);
+ lock != NULL;
+ lock = smb_llist_next(&node->n_lock_list, lock)) {
+
+ if (!smb_lock_range_overlap(lock, dlock->l_start,
+ dlock->l_length))
+ continue;
+
+ /*
+ * Check to see if lock in the overlapping record
+ * is only read lock. Current finding is read
+ * locks can overlapped irrespective of pids.
+ */
+ if ((lock->l_type == SMB_LOCK_TYPE_READONLY) &&
+ (dlock->l_type == SMB_LOCK_TYPE_READONLY)) {
+ continue;
+ }
+
+ /*
+ * When the read lock overlaps write lock, check if
+ * allowed.
+ */
+ if ((dlock->l_type == SMB_LOCK_TYPE_READONLY) &&
+ !(lock->l_type == SMB_LOCK_TYPE_READONLY)) {
+ if (lock->l_file == sr->fid_ofile &&
+ lock->l_session_kid == sr->session->s_kid &&
+ lock->l_pid == sr->smb_pid &&
+ lock->l_uid == sr->smb_uid) {
+ continue;
+ }
+ }
+
+ /* Conflict in overlapping lock element */
+ *clockp = lock;
+ status = NT_STATUS_LOCK_NOT_GRANTED;
+ break;
+ }
+
+ return (status);
+}
+
+/*
+ * smb_lock_wait
+ *
+ * Wait operation for smb overlapping lock to be released. Caller must hold
+ * write lock for node->n_lock_list so that the set of active locks can't
+ * change unexpectedly. The lock for node->n_lock_list will be released
+ * within this function during the sleep after the lock dependency has
+ * been recorded.
+ *
+ * return value
+ *
+ * NT_STATUS_CANCELLED Error occurred during wait operation
+ * NT_STATUS_SUCCESS Wait completed.
+ */
+static uint32_t
+smb_lock_wait(smb_request_t *sr, smb_lock_t *b_lock, smb_lock_t *c_lock)
+{
+ clock_t result;
+ uint32_t status = NT_STATUS_SUCCESS;
+
+ ASSERT(sr->sr_awaiting == NULL);
+
+ mutex_enter(&sr->sr_mutex);
+
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_ACTIVE:
+ /*
+ * Wait up till the timeout time keeping track of actual
+ * time waited for possible retry failure.
+ */
+ sr->sr_state = SMB_REQ_STATE_WAITING_LOCK;
+ sr->sr_awaiting = c_lock;
+ mutex_exit(&sr->sr_mutex);
+
+ mutex_enter(&c_lock->l_mutex);
+ /*
+ * The conflict list (l_conflict_list) for a lock contains
+ * all the locks that are blocked by and in conflict with
+ * that lock. Add the new lock to the conflict list for the
+ * active lock.
+ *
+ * l_conflict_list is currently a fancy way of representing
+ * the references/dependencies on a lock. It could be
+ * replaced with a reference count but this approach
+ * has the advantage that MDB can display the lock
+ * dependencies at any point in time. In the future
+ * we should be able to leverage the list to implement
+ * an asynchronous locking model.
+ *
+ * l_blocked_by is the reverse of the conflict list. It
+ * points to the lock that the new lock conflicts with.
+ * As currently implemented this value is purely for
+ * debug purposes -- there are windows of time when
+ * l_blocked_by may be non-NULL even though there is no
+ * conflict list
+ */
+ b_lock->l_blocked_by = c_lock;
+ smb_slist_insert_tail(&c_lock->l_conflict_list, b_lock);
+ smb_llist_exit(&c_lock->l_file->f_node->n_lock_list);
+
+ /*
+ * XXX Hack.. drop s_lock to avoid blocking subsequent SMBs
+ * that might affect the state of this lock (i.e.
+ * smb_com_close). We shouldn't sleep while holding
+ * locks anyway.
+ */
+ smb_rwx_rwexit(&sr->session->s_lock);
+
+ if (SMB_LOCK_INDEFINITE_WAIT(b_lock)) {
+ cv_wait(&c_lock->l_cv, &c_lock->l_mutex);
+ } else {
+ result = cv_timedwait(&c_lock->l_cv,
+ &c_lock->l_mutex, b_lock->l_end_time);
+ if (result == -1) {
+ status = NT_STATUS_CANCELLED;
+ }
+ }
+
+ /*
+ * XXX Hack continued from above... re-acquire s_lock
+ * OK to hardcode RW_READER since this is just a hack and
+ * we really should yank it out and do something else.
+ */
+ smb_rwx_rwenter(&sr->session->s_lock, RW_READER);
+
+ mutex_exit(&c_lock->l_mutex);
+
+ smb_llist_enter(&c_lock->l_file->f_node->n_lock_list,
+ RW_WRITER);
+ smb_slist_remove(&c_lock->l_conflict_list, b_lock);
+
+ mutex_enter(&sr->sr_mutex);
+ sr->sr_awaiting = NULL;
+ if (sr->sr_state == SMB_REQ_STATE_CANCELED) {
+ status = NT_STATUS_CANCELLED;
+ } else {
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+ }
+ break;
+
+ case SMB_REQ_STATE_CANCELED:
+ status = NT_STATUS_CANCELLED;
+ mutex_exit(&sr->sr_mutex);
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ mutex_exit(&sr->sr_mutex);
+
+ return (status);
+}
+
+/*
+ * smb_lock_range_ulckrules
+ *
+ * 1. Unlock should be performed at exactly matching ends.
+ * This has been changed because overlapping ends is
+ * allowed and there is no other precise way of locating
+ * lock entity in node lock list.
+ *
+ * 2. Unlock is failed if there is no corresponding lock exists.
+ *
+ * Return values
+ *
+ * NT_STATUS_SUCCESS Unlock request matches lock record
+ * pointed by 'nodelock' lock structure.
+ *
+ * NT_STATUS_RANGE_NOT_LOCKED Unlock request doen't match any
+ * of lock record in node lock request or
+ * error in unlock range processing.
+ */
+static uint32_t
+smb_lock_range_ulckrules(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length,
+ struct smb_lock **nodelock)
+{
+ smb_lock_t *lock;
+ uint32_t status = NT_STATUS_RANGE_NOT_LOCKED;
+
+ /* Caller must hold lock for node->n_lock_list */
+ for (lock = smb_llist_head(&node->n_lock_list);
+ lock != NULL;
+ lock = smb_llist_next(&node->n_lock_list, lock)) {
+
+ if ((start == lock->l_start) &&
+ (length == lock->l_length) &&
+ lock->l_file == sr->fid_ofile &&
+ lock->l_session_kid == sr->session->s_kid &&
+ lock->l_pid == sr->smb_pid &&
+ lock->l_uid == sr->smb_uid) {
+ *nodelock = lock;
+ status = NT_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return (status);
+}
+
+
+/*
+ * smb_unlock_range
+ *
+ * locates lock range performed for corresponding to unlock request.
+ *
+ * NT_STATUS_SUCCESS - Lock range performed successfully.
+ * !NT_STATUS_SUCCESS - Error in unlock range operation.
+ */
+uint32_t
+smb_unlock_range(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length)
+{
+ struct smb_lock *lock = 0;
+ uint32_t status;
+
+ /* Apply unlocking rules */
+ smb_llist_enter(&node->n_lock_list, RW_WRITER);
+ status = smb_lock_range_ulckrules(sr, node, start, length, &lock);
+ if (status != NT_STATUS_SUCCESS) {
+ /*
+ * If lock range is not matching in the list
+ * return error.
+ */
+ ASSERT(lock == 0);
+ smb_llist_exit(&node->n_lock_list);
+ return (status);
+ }
+
+ smb_llist_remove(&node->n_lock_list, lock);
+ smb_llist_exit(&node->n_lock_list);
+
+ smb_lock_destroy(lock);
+
+ return (status);
+}
+
+/*
+ * smb_lock_range
+ *
+ * checks for integrity of
+ * file lock operation for the given range of file data.
+ * This is performed by applying lock rules with all
+ * the elements of the node lock list.
+ *
+ * The function returns with new lock added if lock
+ * request is non-conflicting with existing range
+ * lock for the file. Otherwise smb request is filed
+ * without returning.
+ *
+ * NT_STATUS_SUCCESS - Lock range performed successfully.
+ * !NT_STATUS_SUCCESS - Error in lock range operation.
+ */
+uint32_t
+smb_lock_range(
+ struct smb_request *sr,
+ smb_ofile_t *file,
+ uint64_t start,
+ uint64_t length,
+ uint32_t timeout,
+ uint32_t locktype)
+{
+ smb_node_t *node = file->f_node;
+ smb_lock_t *lock;
+ smb_lock_t *clock = 0;
+ uint32_t result = NT_STATUS_SUCCESS;
+
+ lock = smb_lock_create(sr, start, length, locktype, timeout);
+
+ smb_llist_enter(&node->n_lock_list, RW_WRITER);
+ for (;;) {
+ /* Apply locking rules */
+ result = smb_lock_range_lckrules(sr, file, node, lock, &clock);
+
+ if ((result == NT_STATUS_CANCELLED) ||
+ (result == NT_STATUS_SUCCESS) ||
+ (result == NT_STATUS_RANGE_NOT_LOCKED)) {
+ ASSERT(clock == 0);
+ break;
+ } else {
+ ASSERT(result == NT_STATUS_LOCK_NOT_GRANTED);
+ ASSERT(clock);
+ /*
+ * Call smb_lock_wait holding write lock for
+ * node lock list. smb_lock_wait will release
+ * this lock if it blocks.
+ */
+ ASSERT(node == clock->l_file->f_node);
+ if ((timeout == 0) ||
+ ((result = smb_lock_wait(sr, lock, clock)) !=
+ NT_STATUS_SUCCESS)) {
+ break;
+ }
+ clock = 0;
+ }
+ }
+
+ lock->l_blocked_by = NULL;
+
+ if (result != NT_STATUS_SUCCESS) {
+ /*
+ * Under certain conditions NT_STATUS_FILE_LOCK_CONFLICT
+ * should be returned instead of NT_STATUS_LOCK_NOT_GRANTED.
+ */
+ if (result == NT_STATUS_LOCK_NOT_GRANTED) {
+ /*
+ * Locks with timeouts always return
+ * NT_STATUS_FILE_LOCK_CONFLICT
+ */
+ if (timeout != 0) {
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /*
+ * Locks starting higher than 0xef000000 that do not
+ * have the MSB set always return
+ * NT_STATUS_FILE_LOCK_CONFLICT
+ */
+ if ((lock->l_start >= 0xef000000) &&
+ !(lock->l_start & (1ULL << 63))) {
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+
+ /*
+ * If the last lock attempt to fail on this file handle
+ * started at the same offset as this one then return
+ * NT_STATUS_FILE_LOCK_CONFLICT
+ */
+ mutex_enter(&file->f_mutex);
+ if ((file->f_flags & SMB_OFLAGS_LLF_POS_VALID) &&
+ (lock->l_start == file->f_llf_pos)) {
+ result = NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+ mutex_exit(&file->f_mutex);
+ }
+
+ /* Update last lock failed offset */
+ mutex_enter(&file->f_mutex);
+ file->f_llf_pos = lock->l_start;
+ file->f_flags |= SMB_OFLAGS_LLF_POS_VALID;
+ mutex_exit(&file->f_mutex);
+
+ smb_lock_free(lock);
+ } else {
+ smb_llist_insert_tail(&node->n_lock_list, lock);
+ }
+ smb_llist_exit(&node->n_lock_list);
+
+ return (result);
+}
+
+
+/*
+ * smb_lock_range_access
+ *
+ * scans node lock list
+ * to check if there is any overlapping lock. Overlapping
+ * lock is allowed only under same session and client pid.
+ *
+ * Return values
+ * NT_STATUS_SUCCESS lock access granted.
+ * NT_STATUS_FILE_LOCK_CONFLICT access denied due to lock conflict.
+ */
+int
+smb_lock_range_access(
+ struct smb_request *sr,
+ struct smb_node *node,
+ uint64_t start,
+ uint64_t length,
+ uint32_t desired_access)
+{
+ smb_lock_t *lock;
+ smb_llist_t *llist;
+ int status = NT_STATUS_SUCCESS;
+
+ ASSERT((desired_access & ~(FILE_READ_DATA | FILE_WRITE_DATA)) == 0);
+ ASSERT((desired_access & (FILE_READ_DATA | FILE_WRITE_DATA)) != 0);
+
+ llist = &node->n_lock_list;
+ smb_llist_enter(llist, RW_READER);
+ /* Search for any applicable lock */
+ for (lock = smb_llist_head(llist);
+ lock != 0;
+ lock = smb_llist_next(llist, lock)) {
+
+ if (!smb_lock_range_overlap(lock, start, length))
+ /* Lock does not overlap */
+ continue;
+
+ if (lock->l_type == SMB_LOCK_TYPE_READONLY &&
+ desired_access == FILE_READ_DATA)
+ continue;
+
+ if (lock->l_type == SMB_LOCK_TYPE_READWRITE &&
+ lock->l_session_kid == sr->session->s_kid &&
+ lock->l_pid == sr->smb_pid)
+ continue;
+
+ status = NT_STATUS_FILE_LOCK_CONFLICT;
+ break;
+ }
+ smb_llist_exit(llist);
+ return (status);
+}
+
+static smb_lock_t *
+smb_lock_create(
+ smb_request_t *sr,
+ uint64_t start,
+ uint64_t length,
+ uint32_t locktype,
+ uint32_t timeout)
+{
+ smb_lock_t *lock;
+
+ ASSERT(locktype == SMB_LOCK_TYPE_READWRITE ||
+ locktype == SMB_LOCK_TYPE_READONLY);
+
+ lock = kmem_zalloc(sizeof (smb_lock_t), KM_SLEEP);
+ lock->l_magic = SMB_LOCK_MAGIC;
+ lock->l_sr = sr; /* Invalid after lock is active */
+ lock->l_session_kid = sr->session->s_kid;
+ lock->l_session = sr->session;
+ lock->l_file = sr->fid_ofile;
+ lock->l_uid = sr->smb_uid;
+ lock->l_pid = sr->smb_pid;
+ lock->l_type = locktype;
+ lock->l_start = start;
+ lock->l_length = length;
+ /*
+ * Calculate the absolute end time so that we can use it
+ * in cv_timedwait.
+ */
+ lock->l_end_time = lbolt + MSEC_TO_TICK(timeout);
+ if (timeout == 0xffffffff) {
+ lock->l_flags |= SMB_LOCK_FLAG_INDEFINITE;
+ }
+ mutex_init(&lock->l_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&lock->l_cv, NULL, CV_DEFAULT, NULL);
+ smb_slist_constructor(&lock->l_conflict_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_conflict_lnd));
+
+ return (lock);
+}
+
+static void
+smb_lock_free(smb_lock_t *lock)
+{
+ smb_slist_destructor(&lock->l_conflict_list);
+ cv_destroy(&lock->l_cv);
+ mutex_destroy(&lock->l_mutex);
+
+ kmem_free(lock, sizeof (smb_lock_t));
+}
+
+/*
+ * smb_lock_destroy
+ *
+ * Caller must hold node->n_lock_list
+ */
+static void
+smb_lock_destroy(smb_lock_t *lock)
+{
+ /*
+ * Caller must hold node->n_lock_list lock.
+ */
+ mutex_enter(&lock->l_mutex);
+ cv_broadcast(&lock->l_cv);
+ mutex_exit(&lock->l_mutex);
+
+ /*
+ * The cv_broadcast above should wake up any locks that previous
+ * had conflicts with this lock. Wait for the locking threads
+ * to remove their references to this lock.
+ */
+ smb_slist_wait_for_empty(&lock->l_conflict_list);
+
+ smb_lock_free(lock);
+}
+
+void
+smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file)
+{
+ smb_lock_t *lock;
+ smb_lock_t *nxtl;
+ list_t destroy_list;
+
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ ASSERT(node->n_refcnt);
+
+ /*
+ * Move locks matching the specified file from the node->n_lock_list
+ * to a temporary list (holding the lock the entire time) then
+ * destroy all the matching locks. We can't call smb_lock_destroy
+ * while we are holding the lock for node->n_lock_list because we will
+ * deadlock and we can't drop the lock because the list contents might
+ * change (for example nxtl might get removed on another thread).
+ */
+ list_create(&destroy_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_lnd));
+
+ smb_llist_enter(&node->n_lock_list, RW_WRITER);
+ lock = smb_llist_head(&node->n_lock_list);
+ while (lock) {
+ nxtl = smb_llist_next(&node->n_lock_list, lock);
+ if (lock->l_file == file) {
+ smb_llist_remove(&node->n_lock_list, lock);
+ list_insert_tail(&destroy_list, lock);
+ }
+ lock = nxtl;
+ }
+ smb_llist_exit(&node->n_lock_list);
+
+ lock = list_head(&destroy_list);
+ while (lock) {
+ nxtl = list_next(&destroy_list, lock);
+ list_remove(&destroy_list, lock);
+ smb_lock_destroy(lock);
+ lock = nxtl;
+ }
+
+ list_destroy(&destroy_list);
+}
+
+void
+smb_lock_range_raise_error(smb_request_t *sr, uint32_t ntstatus)
+{
+ switch (ntstatus) {
+ case NT_STATUS_CANCELLED:
+ /*
+ * XXX What is the proper error here?
+ */
+ smbsr_raise_error(sr, ERRDOS, ERRlock);
+ /* NOTREACHED */
+ case NT_STATUS_FILE_LOCK_CONFLICT:
+ smbsr_raise_cifs_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
+ ERRDOS, ERRlock);
+ /* NOTREACHED */
+ case NT_STATUS_LOCK_NOT_GRANTED:
+ smbsr_raise_cifs_error(sr, NT_STATUS_LOCK_NOT_GRANTED,
+ ERRDOS, ERRlock);
+ /* NOTREACHED */
+ case NT_STATUS_RANGE_NOT_LOCKED:
+ smbsr_raise_cifs_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
+ ERRDOS, ERRlock);
+ /* NOTREACHED */
+ default:
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRDOS, ntstatus);
+ /* NOTREACHED */
+ }
+}
+
+
+void
+smb_unlock_range_raise_error(smb_request_t *sr, uint32_t ntstatus)
+{
+ switch (ntstatus) {
+ case NT_STATUS_RANGE_NOT_LOCKED:
+ smbsr_raise_cifs_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
+ ERRDOS, ERRnotlocked);
+ /* NOTREACHED */
+ default:
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRDOS, ntstatus);
+ /* NOTREACHED */
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
new file mode 100644
index 0000000000..0acf7922c4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
@@ -0,0 +1,378 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: locking_andx
+ *
+ * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 8
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Fid; File handle
+ * UCHAR LockType; See LockType table below
+ * UCHAR OplockLevel; The new oplock level
+ * ULONG Timeout; Milliseconds to wait for unlock
+ * USHORT NumberOfUnlocks; Num. unlock range structs following
+ * USHORT NumberOfLocks; Num. lock range structs following
+ * USHORT ByteCount; Count of data bytes
+ * LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges
+ * LOCKING_ANDX_RANGE Locks[]; Lock ranges
+ *
+ * LockType Flag Name Value Description
+ * ============================ ===== ================================
+ *
+ * LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock
+ * LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification
+ * LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type
+ * LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request
+ * LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format
+ *
+ * LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * ULONG Offset; Offset to bytes to [un]lock
+ * ULONG Length; Number of bytes to [un]lock
+ *
+ * Large File LOCKING_ANDX_RANGE Format
+ * =====================================================================
+ *
+ * USHORT Pid; PID of process "owning" lock
+ * USHORT Pad; Pad to DWORD align (mbz)
+ * ULONG OffsetHigh; Offset to bytes to [un]lock
+ * (high)
+ * ULONG OffsetLow; Offset to bytes to [un]lock (low)
+ * ULONG LengthHigh; Number of bytes to [un]lock
+ * (high)
+ * ULONG LengthLow; Number of bytes to [un]lock (low)
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Locking is a simple mechanism for excluding other processes read/write
+ * access to regions of a file. The locked regions can be anywhere in the
+ * logical file. Locking beyond end-of-file is permitted. Any process
+ * using the Fid specified in this request's Fid has access to the locked
+ * bytes, other processes will be denied the locking of the same bytes.
+ *
+ * The proper method for using locks is not to rely on being denied read or
+ * write access on any of the read/write protocols but rather to attempt
+ * the locking protocol and proceed with the read/write only if the locks
+ * succeeded.
+ *
+ * Locking a range of bytes will fail if any subranges or overlapping
+ * ranges are locked. In other words, if any of the specified bytes are
+ * already locked, the lock will fail.
+ *
+ * If NumberOfUnlocks is non-zero, the Unlocks vector contains
+ * NumberOfUnlocks elements. Each element requests that a lock at Offset
+ * of Length be released. If NumberOfLocks is nonzero, the Locks vector
+ * contains NumberOfLocks elements. Each element requests the acquisition
+ * of a lock at Offset of Length.
+ *
+ * Timeout is the maximum amount of time to wait for the byte range(s)
+ * specified to become unlocked. A timeout value of 0 indicates that the
+ * server should fail immediately if any lock range specified is locked. A
+ *
+ * timeout value of -1 indicates that the server should wait as long as it
+ * takes for each byte range specified to become unlocked so that it may be
+ * again locked by this protocol. Any other value of smb_timeout specifies
+ * the maximum number of milliseconds to wait for all lock range(s)
+ * specified to become available.
+ *
+ * If any of the lock ranges timeout because of the area to be locked is
+ * already locked (or the lock fails), the other ranges in the protocol
+ * request which were successfully locked as a result of this protocol will
+ * be unlocked (either all requested ranges will be locked when this
+ * protocol returns to the client or none).
+ *
+ * If LockType has the LOCKING_ANDX_SHARED_LOCK flag set, the lock is
+ * specified as a shared lock. Locks for both read and write (where
+ * LOCKING_ANDX_SHARED_LOCK is clear) should be prohibited, but other
+ * shared locks should be permitted. If shared locks can not be supported
+ * by a server, the server should map the lock to a lock for both read and
+ * write. Closing a file with locks still in force causes the locks to be
+ * released in no defined order.
+ *
+ * If LockType has the LOCKING_ANDX_LARGE_FILES flag set and if the
+ * negotiated protocol is NT LM 0.12 or later, then the Locks and Unlocks
+ * vectors are in the Large File LOCKING_ANDX_RANGE format. This allows
+ * specification of 64 bit offsets for very large files.
+ *
+ * If the one and only member of the Locks vector has the
+ * LOCKING_ANDX_CANCEL_LOCK flag set in the LockType field, the client is
+ * requesting the server to cancel a previously requested, but not yet
+ * responded to, lock.
+ *
+ * If LockType has the LOCKING_ANDX_CHANGE_LOCKTYPE flag set, the client is
+ * requesting that the server atomically change the lock type from a shared
+ * lock to an exclusive lock or vice versa. If the server can not do this
+ * in an atomic fashion, the server must reject this request. NT and W95
+ * servers do not support this capability.
+ *
+ * Oplocks are described in the "Opportunistic Locks" section elsewhere in
+ * this document. A client requests an oplock by setting the appropriate
+ * bit in the SMB_COM_OPEN_ANDX request when the file is being opened in a
+ * mode which is not exclusive. The server responds by setting the
+ * appropriate bit in the response SMB indicating whether or not the oplock
+ * was granted. By granting the oplock, the server tells the client the
+ * file is currently only being used by this one client process at the
+ * current time. The client can therefore safely do read ahead and write
+ * behind as well as local caching of file locks knowing that the file will
+ * not be accessed/changed in any way by another process while the oplock
+ * is in effect. The client will be notified when any other process
+ * attempts to open or modify the oplocked file.
+ *
+ * When another user attempts to open or otherwise modify the file which a
+ * client has oplocked, the server delays the second attempt and notifies
+ * the client via an SMB_LOCKING_ANDX SMB asynchronously sent from the
+ * server to the client. This message has the LOCKING_ANDX_OPLOCK_RELEASE
+ * flag set indicating to the client that the oplock is being broken.
+ *
+ * OplockLevel indicates the type of oplock the client now owns. If
+ * OplockLevel is 0, the client possesses no oplocks on the file at all, if
+ * OplockLevel is 1 the client possesses a Level II oplock. The client is
+ * expected to flush any dirty buffers to the server, submit any file locks
+ * and respond to the server with either an SMB_LOCKING_ANDX SMB having the
+ * LOCKING_ANDX_OPLOCK_RELEASE flag set, or with a file close if the file
+ * is no longer in use by the client. If the client sends an
+ * SMB_LOCKING_ANDX SMB with the LOCKING_ANDX_OPLOCK_RELEASE flag set and
+ * NumberOfLocks is zero, the server does not send a response. Since a
+ * close being sent to the server and break oplock notification from the
+ * server could cross on the wire, if the client gets an oplock
+ * notification on a file which it does not have open, that notification
+ * should be ignored.
+ *
+ * Due to timing, the client could get an "oplock broken" notification in a
+ * user's data buffer as a result of this notification crossing on the wire
+ * with a SMB_COM_READ_RAW request. The client must detect this (use
+ * length of msg, "FFSMB", MID of -1 and Command of SMB_COM_LOCKING_ANDX)
+ * and honor the "oplock broken" notification as usual. The server must
+ * also note on receipt of an SMB_COM_READ_RAW request that there is an
+ * outstanding (unanswered) "oplock broken" notification to the client and
+ * return a zero length response denoting failure of the read raw request.
+ * The client should (after responding to the "oplock broken"
+ * notification), use a standard read protocol to redo the read request.
+ * This allows a file to actually contain data matching an "oplock broken"
+ * notification and still be read correctly.
+ *
+ * The entire message sent and received including the optional second
+ * protocol must fit in the negotiated maximum transfer size. The
+ * following are the only valid SMB commands for AndXCommand for
+ * SMB_COM_LOCKING_ANDX:
+ *
+ * SMB_COM_READ SMB_COM_READ_ANDX
+ * SMB_COM_WRITE SMB_COM_WRITE_ANDX
+ * SMB_COM_FLUSH
+ *
+ * 4.2.6.1 Errors
+ *
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRbadfid
+ * ERRDOS/ERRlock
+ * ERRDOS/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_locking_andx(struct smb_request *sr)
+{
+ unsigned short i;
+ unsigned char lock_type; /* See lock_type table above */
+ unsigned char oplock_level; /* The new oplock level */
+ uint32_t timeout; /* Milliseconds to wait for lock */
+ unsigned short unlock_num; /* # unlock range structs */
+ unsigned short lock_num; /* # lock range structs */
+ unsigned short pid; /* Process Id of owner */
+ uint32_t offset32, length32;
+ uint64_t offset64;
+ uint64_t length64;
+ DWORD result;
+ int rc;
+ uint32_t ltype;
+
+ rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
+ &oplock_level, &timeout, &unlock_num, &lock_num);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (lock_type & LOCKING_ANDX_SHARED_LOCK)
+ ltype = SMB_LOCK_TYPE_READONLY;
+ else
+ ltype = SMB_LOCK_TYPE_READWRITE;
+
+ pid = sr->smb_pid; /* Save the original pid */
+
+ if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
+ smb_release_oplock(sr->fid_ofile, OPLOCK_RELEASE_LOCK_RELEASED);
+
+ /*
+ * According to the protocol:
+ *
+ * If the client sends an SMB_LOCKING_ANDX request with the
+ * LOCKING_ANDX_OPLOCK_RELEASE flag set
+ * and NumberOfLocks is zero,
+ * the server does not send a response.
+ *
+ * I'm not sure if it's going to break anything if I change
+ * it according to the protocol. So, I leave it unchanged
+ * for now.
+ */
+ if (unlock_num == 0 && lock_num == 0)
+ return (SDRC_NO_REPLY);
+ }
+
+ /*
+ * No support for changing locktype (although we could probably
+ * implement this)
+ */
+ if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) {
+ smbsr_raise_error(sr, ERRDOS, ERRnoatomiclocks);
+ /* NOT REACHED */
+ }
+
+ /*
+ * No support for cancel lock (smbtorture expects this)
+ */
+ if (lock_type & LOCKING_ANDX_CANCEL_LOCK) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOT REACHED */
+ }
+
+ if (lock_type & LOCKING_ANDX_LARGE_FILES) {
+ /*
+ * negotiated protocol should be NT LM 0.12 or later
+ */
+ if (sr->session->dialect < NT_LM_0_12) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOT REACHED */
+ }
+
+ for (i = 0; i < unlock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "w2.QQ",
+ &sr->smb_pid, &offset64, &length64);
+ if (rc) {
+ /*
+ * This is the error returned by a W2K system
+ * even when NT Status is negotiated.
+ */
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node,
+ offset64, length64);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_unlock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+
+ for (i = 0; i < lock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "w2.QQ",
+ &sr->smb_pid, &offset64, &length64);
+ if (rc) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_lock_range(sr, sr->fid_ofile,
+ offset64, length64, timeout, ltype);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+ } else {
+ for (i = 0; i < unlock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "wll", &sr->smb_pid,
+ &offset32, &length32);
+ if (rc) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node,
+ (uint64_t)offset32, (uint64_t)length32);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_unlock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+
+ for (i = 0; i < lock_num; i++) {
+ rc = smb_decode_mbc(&sr->smb_data, "wll", &sr->smb_pid,
+ &offset32, &length32);
+ if (rc) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOT REACHED */
+ }
+
+ result = smb_lock_range(sr, sr->fid_ofile,
+ (uint64_t)offset32,
+ (uint64_t)length32,
+ timeout, ltype);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+ }
+ }
+
+ sr->smb_pid = pid;
+ smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c b/usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c
new file mode 100644
index 0000000000..278916b8fd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_logoff_andx.c
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_logoff_andx
+ *
+ * This SMB is the inverse of SMB_COM_SESSION_SETUP_ANDX.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The user represented by Uid in the SMB header is logged off. The server
+ * closes all files currently open by this user, and invalidates any
+ * outstanding requests with this Uid.
+ *
+ * SMB_COM_SESSION_SETUP_ANDX is the only valid AndX command for this SMB.
+ *
+ * 4.1.3.1 Errors
+ *
+ * ERRSRV/invnid - TID was invalid
+ * ERRSRV/baduid - UID was invalid
+ */
+int
+smb_com_logoff_andx(struct smb_request *sr)
+{
+ if (sr->uid_user == NULL) {
+ cmn_err(CE_WARN, "SmbLogoffAndX: bad uid");
+ smbsr_raise_error(sr, ERRSRV, ERRbaduid);
+ /* NOTREACHED */
+ }
+
+ smb_user_logoff(sr->uid_user);
+
+ smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, -1, 0);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
new file mode 100644
index 0000000000..21a4b42939
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
@@ -0,0 +1,777 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#include <sys/errno.h>
+#include <smbsrv/string.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static int smb_match_unknown(char *name, char *pattern);
+static int smb_is_reserved_dos_name(char *name);
+static int smb_match_reserved(char *name, char *rsrv);
+
+/*
+ * smb_match_name
+ *
+ * This function will mangle the "name" field and save the resulted
+ * shortname to the "shortname" field and 8.3 name to "name83" field.
+ * The three fields, "name", "shortname" and "name83" will then be
+ * sent for pattern match with "pattern" field.
+ *
+ * The 0 is returned when the name is a reserved dos name, no match
+ * for the pattern or any type of failure. The 1 is returned when
+ * there is a match.
+ */
+int
+smb_match_name(ino64_t fileid, char *name, char *shortname,
+ char *name83, char *pattern, int ignore_case)
+{
+ int rc = 0;
+ int force;
+
+ /* Leading or trailing dots are disallowed */
+ if (smb_is_reserved_dos_name(name))
+ return (0);
+
+ for (force = 0; (force < 2 && rc == 0); force++) {
+ (void) smb_mangle_name(fileid, name, shortname, name83, force);
+
+ rc = smb_match_ci(pattern, name);
+
+ /* If no match, check for shortname (if any) */
+
+ if (rc == 0 && strchr(pattern, '~'))
+ if (*shortname != 0)
+ rc = smb_match_ci(pattern, shortname);
+
+ /*
+ * Sigh... DOS Shells use short name
+ * interchangeably with long case sensitive
+ * names. So check that too...
+ */
+ if ((rc == 0) && !ignore_case)
+ rc = smb_match83(pattern, name83);
+
+ /*
+ * Still not found and potentially a premangled name...
+ * Check to see if the butt-head programmer is
+ * assuming that we mangle names in the same manner
+ * as NT...
+ */
+ if (rc == 0)
+ rc = smb_match_unknown(name, pattern);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_match_unknown
+ *
+ * I couldn't figure out what the assumptions of this peice of
+ * code about the format of pattern and name are and so how
+ * it's trying to match them. I just cleaned it up a little bit!
+ *
+ * If anybody could figure out what this is doing, please put
+ * comment here and change the function's name!
+ */
+static int
+smb_match_unknown(char *name, char *pattern)
+{
+ int rc;
+ char nc, pc;
+ char *np, *pp;
+
+ rc = 0;
+ if (utf8_isstrupr(pattern) <= 0)
+ return (rc);
+
+ np = name;
+ pp = pattern;
+
+ pc = *pattern;
+ while ((nc = *np++) != 0) {
+ if (nc == ' ')
+ continue;
+
+ nc = mts_toupper(nc);
+ if ((pc = *pp++) != nc)
+ break;
+ }
+
+ if ((pc == '~') &&
+ (pp != (pattern + 1)) &&
+ ((pc = *pp++) != 0)) {
+ while (mts_isdigit(pc))
+ pc = *pp++;
+
+ if (pc == '.') {
+ while ((nc = *np++) != 0) {
+ if (nc == '.')
+ break;
+ }
+
+ while ((nc = *np++) != 0) {
+ nc = mts_toupper(nc);
+ if ((pc = *pp++) != nc)
+ break;
+ }
+ }
+
+ if (pc == 0)
+ rc = 1;
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_match_reserved
+ *
+ * Checks if the given name matches given
+ * DOS reserved name prefix.
+ *
+ * Returns 1 if match, 0 otherwise
+ */
+static int
+smb_match_reserved(char *name, char *rsrv)
+{
+ char ch;
+
+ int len = strlen(rsrv);
+ return (!utf8_strncasecmp(rsrv, name, len) &&
+ ((ch = *(name + len)) == 0 || ch == '.'));
+}
+
+/*
+ * smb_is_reserved_dos_name
+ *
+ * This function checks if the name is a reserved dos name.
+ *
+ * The function returns 1 when the name is a reserved dos name;
+ * otherwise, it returns 0.
+ */
+static int
+smb_is_reserved_dos_name(char *name)
+{
+ char ch;
+
+ /*
+ * Eliminate all names reserved by DOS and Windows.
+ */
+ ch = mts_toupper(*name);
+
+ switch (ch) {
+ case 'A':
+ if (smb_match_reserved(name, "AUX"))
+ return (1);
+ break;
+
+ case 'C':
+ if (smb_match_reserved(name, "CLOCK$") ||
+ smb_match_reserved(name, "COM1") ||
+ smb_match_reserved(name, "COM2") ||
+ smb_match_reserved(name, "COM3") ||
+ smb_match_reserved(name, "COM4") ||
+ smb_match_reserved(name, "CON")) {
+ return (1);
+ }
+
+ break;
+
+ case 'L':
+ if ((utf8_strncasecmp("LPT1", name, 4) == 0) ||
+ (utf8_strncasecmp("LPT2", name, 4) == 0) ||
+ (utf8_strncasecmp("LPT3", name, 4) == 0))
+ return (1);
+ break;
+
+ case 'N':
+ if (smb_match_reserved(name, "NUL"))
+ return (1);
+ break;
+
+ case 'P':
+ if (smb_match_reserved(name, "PRN"))
+ return (1);
+ }
+
+ /*
+ * If the server is configured to support Catia Version 5
+ * deployments, any filename that contains backslash will
+ * have already been translated to the UTF-8 encoding of
+ * Latin Small Letter Y with Diaeresis. Thus, the check
+ * for backslash in the filename is not necessary.
+ */
+#ifdef CATIA_SUPPORT
+ /* XXX Catia support */
+ if ((get_caps() & NFCAPS_CATIA) == 0) {
+ while (*name != 0) {
+ if (*name == '\\')
+ return (1);
+ name++;
+ }
+ }
+#endif /* CATIA_SUPPORT */
+
+ return (0);
+}
+
+/*
+ * Characters we don't allow in DOS file names.
+ * If a filename contains any of these chars, it should
+ * get mangled.
+ *
+ * '.' is also an invalid DOS char but since it's a special
+ * case it doesn't appear in the list.
+ */
+static char *invalid_dos_chars =
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ " \"/\\:|<>*?";
+
+/*
+ * According to MSKB article #142982, Windows deletes invalid chars and
+ * spaces from file name in mangling process; and invalid chars include:
+ * ."/\[]:;=,
+ *
+ * But some of these chars and some other chars (e.g. +) are replaced
+ * with underscore (_). They are introduced here as special chars.
+ */
+static char *special_chars = "[];=,+";
+
+#define isinvalid(c) (strchr(invalid_dos_chars, c) || (c & 0x80))
+
+/*
+ * smb_needs_mangle
+ *
+ * Determines whether the given name needs to get mangled.
+ *
+ * Here are the (known) rules:
+ *
+ * 1st char is dot (.)
+ * name length > 12 chars
+ * # dots > 1
+ * # dots == 0 and length > 8
+ * # dots == 1 and name isn't 8.3
+ * contains illegal chars
+ */
+int
+smb_needs_mangle(char *name, char **dot_pos)
+{
+ int len, ndots;
+ char *namep;
+ char *last_dot;
+
+ /*
+ * Returning (1) for these cases forces consistency with how
+ * these names are treated (smb_mangle_name() will produce an 8.3 name
+ * for these)
+ */
+ if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
+ return (1);
+
+ /* skip the leading dots (if any) */
+ for (namep = name; *namep == '.'; namep++)
+ ;
+
+ len = ndots = 0;
+ last_dot = 0;
+ for (; *namep; namep++) {
+ len++;
+ if (*namep == '.') {
+ /* keep the position of last dot */
+ last_dot = namep;
+ ndots++;
+ }
+ }
+ *dot_pos = last_dot;
+
+ /* Windows mangles names like .a, .abc, or .abcd */
+ if (*name == '.')
+ return (1);
+
+ if (len > 12)
+ return (1);
+
+ switch (ndots) {
+ case 0:
+ /* no dot */
+ if (len > 8)
+ return (1);
+ break;
+
+ case 1:
+ /* just one dot */
+ /*LINTED E_PTR_DIFF_OVERFLOW*/
+ if (((last_dot - name) > 8) || /* name length > 8 */
+ (strlen(last_dot + 1) > 3)) /* extention > 3 */
+ return (1);
+ break;
+
+ default:
+ /* more than one dot */
+ return (1);
+ }
+
+ for (namep = name; *namep; namep++) {
+ if (!mts_isascii(*namep) ||
+ strchr(special_chars, *namep) ||
+ strchr(invalid_dos_chars, *namep))
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_needs_shortname
+ *
+ * Determine whether a shortname should be generated for a file name that is
+ * already in 8.3 format.
+ *
+ * Paramters:
+ * name - original file name
+ *
+ * Return:
+ * 1 - Shortname is required to be generated.
+ * 0 - No shortname needs to be generated.
+ *
+ * Note
+ * =======
+ * Windows NT server: shortname is created only if either
+ * the filename or extension portion of
+ * a file is made up of mixed case.
+ * Windows 2000 server: shortname is not created regardless
+ * of the case.
+ * Windows 2003 server: [Same as Windows NT server.]
+ *
+ * StorEdge will conform to the rule used by Windows NT/2003 server.
+ *
+ * For instance:
+ * File | Create shortname?
+ * ================================
+ * nf.txt | N
+ * NF.TXT | N
+ * NF.txt | N
+ * nf | N
+ * NF | N
+ * nF.txt | Y
+ * nf.TxT | Y
+ * Nf | Y
+ * nF | Y
+ *
+ */
+static int
+smb_needs_shortname(char *name)
+{
+ char buf[9];
+ int len;
+ int create = 0;
+ const char *dot_pos = 0;
+
+ dot_pos = strrchr(name, '.');
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ len = (!dot_pos) ? strlen(name) : (dot_pos - name);
+ /* First, examine the name portion of the file */
+ if (len) {
+ (void) snprintf(buf, len + 1, "%s", name);
+ /* if the name contains both lower and upper cases */
+ if (utf8_isstrupr(buf) == 0 && utf8_isstrlwr(buf) == 0) {
+ /* create shortname */
+ create = 1;
+ } else if (dot_pos) {
+ /* Next, examine the extension portion of the file */
+ (void) snprintf(buf, sizeof (buf), "%s", dot_pos + 1);
+ /*
+ * if the extension contains both lower and upper
+ * cases
+ */
+ if (utf8_isstrupr(buf) == 0 && utf8_isstrlwr(buf) == 0)
+ /* create shortname */
+ create = 1;
+ }
+ }
+
+ return (create);
+}
+
+/*
+ * smb_mangle_char
+ *
+ * If given char is an invalid DOS character or it's not an
+ * ascii char, it should be deleted from mangled and 8.3 name.
+ *
+ * If given char is one of special chars, it should be replaced
+ * with '_'.
+ *
+ * Otherwise just make it upper case.
+ */
+static unsigned char
+smb_mangle_char(unsigned char ch)
+{
+ if (isinvalid(ch))
+ return (0);
+
+ if (strchr(special_chars, ch))
+ return ('_');
+
+ return (mts_toupper(ch));
+}
+
+/*
+ * smb_generate_mangle
+ *
+ * Generates a mangle string which contains
+ * at least 2 (considering fileid cannot be 0)
+ * and at most 7 chars.
+ *
+ * Returns the number of chars in the generated mangle.
+ */
+static int
+smb_generate_mangle(ino64_t fileid, unsigned char *mangle_buf)
+{
+ /*
+ * 36**6 = 2176782336: more than enough to express inodes in 6
+ * chars
+ */
+ static char *base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ unsigned char *manglep = mangle_buf;
+
+ for (*manglep++ = '~'; fileid > 0; fileid /= 36)
+ *manglep++ = base36[fileid % 36];
+ *manglep = 0;
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ return (manglep - mangle_buf);
+}
+
+/*
+ * smb_maybe_mangled_name
+ *
+ * returns true if the passed name can possibly be a mangled name.
+ * mangled names should be valid dos file names hence less than 12 characters
+ * long and should contain at least one tilde character.
+ *
+ * note that this function can be further enhanced to check for invalid
+ * dos characters/character patterns (such as "file..1.c") but this version
+ * should be sufficient in most cases.
+ */
+int
+smb_maybe_mangled_name(char *name)
+{
+ int i, has_tilde = 0;
+
+ for (i = 0; *name && (i < 12); i++, name++) {
+ if ((*name == '~') && (i < 8))
+ has_tilde = 1;
+
+ if (*name == '.' && has_tilde == 0)
+ return (0);
+ }
+
+ return ((*name == 0) && has_tilde);
+}
+
+/*
+ * smb_mangle_name
+ *
+ * Microsoft knowledge base article #142982 describes how Windows
+ * generates 8.3 filenames from long file names. Some other details
+ * can be found in article #114816.
+ *
+ * The function first checks to see whether the given name needs mangling.
+ * If not, and the force parameter is not set, then no mangling is done,
+ * but both the shortname (if needed) and the 8.3 name are produced and
+ * returned.
+ *
+ * If the "force" parameter is set (as will be the case for case-insensitive
+ * collisions), then the name will be mangled.
+ *
+ * Whenever mangling is needed, both the shortname and the 8.3 names are
+ * produced and returned.
+ *
+ * For example, the xxx.xy in 8.3 format will be "xxx .xy ".
+ */
+
+int smb_mangle_name(
+ ino64_t fileid, /* inode number to generate unique mangle */
+ char *name, /* original file name */
+ char *shortname, /* mangled name (if applicable) */
+ char *name83, /* (mangled) name in 8.3 format */
+ int force) /* force mangling even if mangling is not */
+ /* needed according to standard algorithm */
+{
+ int avail;
+ unsigned char ch;
+ unsigned char mangle_buf[8];
+ unsigned char *namep;
+ unsigned char *manglep;
+ unsigned char *out_short;
+ unsigned char *out_83;
+ char *dot_pos = NULL;
+
+ /*
+ * NOTE:
+ * This function used to consider filename case
+ * in order to mangle. I removed those checks.
+ */
+
+ *shortname = *name83 = 0;
+
+ /* Allow dot and dot dot up front */
+ if (strcmp(name, ".") == 0) {
+ /* no shortname */
+ (void) strcpy(name83, ". . ");
+ return (1);
+ }
+
+ if (strcmp(name, "..") == 0) {
+ /* no shortname */
+ (void) strcpy(name83, ".. . ");
+ return (1);
+ }
+
+ out_short = (unsigned char *)shortname;
+ out_83 = (unsigned char *)name83;
+
+ if ((smb_needs_mangle(name, &dot_pos) == 0) && (force == 0)) {
+ /* no mangle */
+
+ /* check if shortname is required or not */
+ if (smb_needs_shortname(name)) {
+ namep = (unsigned char *)name;
+ while (*namep)
+ *out_short++ = mts_toupper(*namep++);
+ *out_short = '\0';
+ }
+
+ out_83 = (unsigned char *)name83;
+ (void) strcpy((char *)out_83, " . ");
+ while (*name && *name != '.')
+ *out_83++ = mts_toupper(*name++);
+
+ if (*name == '.') {
+ /* copy extension */
+ name++;
+ out_83 = (unsigned char *)name83 + 9;
+ while (*name)
+ *out_83++ = mts_toupper(*name++);
+ }
+ return (1);
+ }
+
+ avail = 8 - smb_generate_mangle(fileid, mangle_buf);
+
+ /*
+ * generated mangle part has always less than 8 chars, so
+ * use the chars before the first dot in filename
+ * and try to generate a full 8 char name.
+ */
+
+ /* skip the leading dots (if any) */
+ for (namep = (unsigned char *)name; *namep == '.'; namep++)
+ ;
+
+ for (; avail && *namep && (*namep != '.'); namep++) {
+ ch = smb_mangle_char(*namep);
+ if (ch == 0)
+ continue;
+ *out_short++ = *out_83++ = ch;
+ avail--;
+ }
+
+ /* Copy in mangled part */
+ manglep = mangle_buf;
+
+ while (*manglep)
+ *out_short++ = *out_83++ = *(manglep++);
+
+ /* Pad any leftover in 8.3 name with spaces */
+ while (avail--)
+ *out_83++ = ' ';
+
+ /* Work on extension now */
+ avail = 3;
+ *out_83++ = '.';
+ if (dot_pos) {
+ namep = (unsigned char *)dot_pos + 1;
+ if (*namep != 0) {
+ *out_short++ = '.';
+ for (; avail && *namep; namep++) {
+ ch = smb_mangle_char(*namep);
+ if (ch == 0)
+ continue;
+
+ *out_short++ = *out_83++ = ch;
+ avail--;
+ }
+ }
+ }
+
+ while (avail--)
+ *out_83++ = ' ';
+
+ *out_short = *out_83 = '\0';
+
+ return (1);
+}
+
+/*
+ * smb_unmangle_name
+ *
+ * Given a mangled name, try to find the real file name as it appears
+ * in the directory entry. If the name does not contain a ~, it is most
+ * likely not a mangled name but the caller can still try to get the
+ * actual on-disk name by setting the "od" parameter.
+ *
+ * Returns 0 if a name has been returned in real_name. There are three
+ * possible scenarios:
+ * 1. Name did not contain a ~ and "od" was not set, in which
+ * case, real_name contains name.
+ * 2. Name did not contain a ~ and "od" was set, in which
+ * case, real_name contains the actual directory entry name.
+ * 3. Name did contain a ~, in which case, name was mangled and
+ * real_name contains the actual directory entry name.
+ *
+ * EINVAL: a parameter was invalid.
+ * ENOENT: an unmangled name could not be found.
+ */
+
+int
+smb_unmangle_name(struct smb_request *sr, cred_t *cred, smb_node_t *dir_node,
+ char *name, char *real_name, int realname_size, char *shortname,
+ char *name83, int od)
+{
+ int err;
+ int len;
+ int force = 0;
+ ino64_t inode;
+ uint32_t cookie;
+ struct smb_node *snode = NULL;
+ smb_attr_t ret_attr;
+ char *dot_pos = NULL;
+ char *readdir_name;
+ char *shortp;
+ char xxx[MANGLE_NAMELEN];
+
+ if (dir_node == NULL || name == NULL || real_name == NULL ||
+ realname_size == 0)
+ return (EINVAL);
+
+ *real_name = '\0';
+ snode = NULL;
+
+ if (smb_maybe_mangled_name(name) == 0) {
+ if (od == 0) {
+ (void) strlcpy(real_name, name, realname_size);
+ return (0);
+ }
+
+ err = smb_fsop_lookup(sr, cred, 0, sr->tid_tree->t_snode,
+ dir_node, name, &snode, &ret_attr, NULL, NULL);
+
+ if (err != 0)
+ return (err);
+
+ (void) strlcpy(real_name, snode->od_name, realname_size);
+ smb_node_release(snode);
+ return (0);
+ }
+
+ if (shortname == 0)
+ shortname = xxx;
+ if (name83 == 0)
+ name83 = xxx;
+
+ cookie = 0;
+
+ readdir_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ snode = NULL;
+ while (cookie != 0x7FFFFFFF) {
+
+ len = realname_size - 1;
+
+ err = smb_fsop_readdir(sr, cred, dir_node, &cookie,
+ readdir_name, &len, &inode, NULL, &snode, &ret_attr);
+
+ if (err || (cookie == 0x7FFFFFFF))
+ break;
+
+ readdir_name[len] = 0;
+
+ /*
+ * smb_fsop_readdir() may return a mangled name if the
+ * name has a case collision.
+ *
+ * If readdir_name is not a mangled name, we mangle
+ * readdir_name to see if it will match the name the
+ * client passed in.
+ *
+ * If smb_needs_mangle() does not succeed, we try again
+ * using the force flag. It is possible that the client
+ * is using a mangled name that resulted from a prior
+ * case collision which no longer exists in the directory.
+ * smb_needs_mangle(), with the force flag, will produce
+ * a mangled name regardless of whether the name passed in
+ * meets standard DOS criteria for name mangling.
+ */
+
+ if (smb_maybe_mangled_name(readdir_name)) {
+ shortp = readdir_name;
+ } else {
+ if (smb_needs_mangle(readdir_name, &dot_pos) == 0)
+ force = 1;
+ (void) smb_mangle_name(inode, readdir_name, shortname,
+ name83, force);
+ shortp = shortname;
+ }
+
+ if (utf8_strcasecmp(name, shortp) == 0) {
+ kmem_free(readdir_name, MAXNAMELEN);
+ (void) strlcpy(real_name, snode->od_name,
+ realname_size);
+
+ smb_node_release(snode);
+
+ return (0);
+ } else {
+ smb_node_release(snode);
+ snode = NULL;
+ }
+ }
+
+ kmem_free(readdir_name, MAXNAMELEN);
+
+ return (ENOENT);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
new file mode 100644
index 0000000000..d97f410e8b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
@@ -0,0 +1,1659 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB mbuf marshaling encode/decode.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+#define MALLOC_QUANTUM 80
+
+#define DECODE_NO_ERROR 0
+#define DECODE_NO_MORE_DATA 1
+#define DECODE_ALLOCATION_ERROR 2
+#define DECODE_CONVERSION_ERROR 3
+
+
+/*
+ * Put data into mbuf chain allocating as needed.
+ * Adds room to end of mbuf chain if needed.
+ */
+
+int
+mbc_marshal_make_room(struct mbuf_chain *mbc, int32_t bytes_needed)
+{
+ struct mbuf *m;
+ struct mbuf *l;
+ int32_t bytes_available;
+
+ bytes_needed += mbc->chain_offset;
+ if (bytes_needed > mbc->max_bytes)
+ return (EMSGSIZE);
+
+ if ((m = mbc->chain) == 0) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_len = 0;
+ if (mbc->max_bytes > MLEN)
+ MCLGET(m, M_WAIT);
+ mbc->chain = m;
+ /* xxxx */
+ /* ^ */
+ }
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+
+ l = 0;
+ while ((m != 0) && (bytes_needed >= m->m_len)) {
+ l = m;
+ bytes_needed -= m->m_len;
+ m = m->m_next;
+ }
+
+ if ((bytes_needed == 0) || (m != 0)) {
+ /* We have enough room already */
+ return (0);
+ }
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+ /* Back up to start of last mbuf */
+ m = l;
+ bytes_needed += m->m_len;
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+
+ bytes_available = (m->m_flags & M_EXT) ?
+ m->m_ext.ext_size : MLEN;
+
+ /* ---- ----- --xx ---xxx */
+ /* ^ */
+ while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
+ m->m_len = bytes_available;
+ bytes_needed -= m->m_len;
+ /* ---- ----- --xx ------ */
+ /* ^ */
+
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ m = m->m_next;
+ m->m_len = 0;
+ if (bytes_needed > MLEN)
+ MCLGET(m, M_WAIT);
+
+ bytes_available = (m->m_flags & M_EXT) ?
+ m->m_ext.ext_size : MLEN;
+
+ /* ---- ----- --xx ------ xxxx */
+ /* ^ */
+ }
+
+ /* ---- ----- --xx ------ xxxx */
+ /* ^ */
+ /* Expand last tail as needed */
+ if (m->m_len <= bytes_needed) {
+ m->m_len = bytes_needed;
+ /* ---- ----- --xx ------ --xx */
+ /* ^ */
+ }
+
+ return (0);
+}
+
+
+void
+mbc_marshal_store_byte(struct mbuf_chain *mbc, unsigned char data)
+{
+ struct mbuf *m = mbc->chain;
+ int32_t cur_offset = mbc->chain_offset;
+
+ /*
+ * Scan forward looking for the last data currently in chain.
+ */
+ while (cur_offset >= m->m_len) {
+ cur_offset -= m->m_len;
+ m = m->m_next;
+ }
+ ((char *)m->m_data)[cur_offset] = data;
+ mbc->chain_offset++;
+}
+
+
+int
+mbc_marshal_put_char(struct mbuf_chain *mbc, unsigned char data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
+ return (DECODE_NO_MORE_DATA);
+ mbc_marshal_store_byte(mbc, data);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_short(struct mbuf_chain *mbc, unsigned short data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (short)))
+ return (DECODE_NO_MORE_DATA);
+ mbc_marshal_store_byte(mbc, data);
+ mbc_marshal_store_byte(mbc, data >> 8);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_long(struct mbuf_chain *mbc, uint32_t data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
+ return (DECODE_NO_MORE_DATA);
+ mbc_marshal_store_byte(mbc, data);
+ mbc_marshal_store_byte(mbc, data >> 8);
+ mbc_marshal_store_byte(mbc, data >> 16);
+ mbc_marshal_store_byte(mbc, data >> 24);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_long_long(struct mbuf_chain *mbc, uint64_t data)
+{
+ if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
+ return (DECODE_NO_MORE_DATA);
+
+ mbc_marshal_store_byte(mbc, data);
+ mbc_marshal_store_byte(mbc, data >> 8);
+ mbc_marshal_store_byte(mbc, data >> 16);
+ mbc_marshal_store_byte(mbc, data >> 24);
+ mbc_marshal_store_byte(mbc, data >> 32);
+ mbc_marshal_store_byte(mbc, data >> 40);
+ mbc_marshal_store_byte(mbc, data >> 48);
+ mbc_marshal_store_byte(mbc, data >> 56);
+ return (0);
+}
+
+
+/*
+ * When need to convert from UTF-8 (internal format) to a single
+ * byte string (external format ) when marshalling a string.
+ */
+int
+mbc_marshal_put_ascii_string(struct mbuf_chain *mbc, char *mbs, int repc)
+{
+ mts_wchar_t wide_char;
+ int nbytes;
+ int length;
+
+ if ((length = mts_sbequiv_strlen(mbs)) == -1)
+ return (DECODE_NO_MORE_DATA);
+
+ length += sizeof (char);
+
+ if ((repc > 1) && (repc < length))
+ length = repc;
+ if (mbc_marshal_make_room(mbc, length))
+ return (DECODE_NO_MORE_DATA);
+
+ while (*mbs) {
+ /*
+ * We should restore oem chars here.
+ */
+ nbytes = mts_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
+ if (nbytes == -1)
+ return (DECODE_NO_MORE_DATA);
+
+ mbc_marshal_store_byte(mbc, (unsigned char)wide_char);
+
+ if (wide_char & 0xFF00)
+ mbc_marshal_store_byte(mbc, wide_char >> 8);
+
+ mbs += nbytes;
+ }
+
+ mbc_marshal_store_byte(mbc, 0);
+ return (0);
+}
+
+
+int
+mbc_marshal_put_alignment(struct mbuf_chain *mbc, unsigned int align)
+{
+ int32_t delta = mbc->chain_offset % align;
+
+ if (delta != 0) {
+ align -= delta;
+ if (mbc_marshal_make_room(mbc, align))
+ return (DECODE_NO_MORE_DATA);
+ while (align-- > 0)
+ mbc_marshal_store_byte(mbc, 0);
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_put_unicode_string(struct mbuf_chain *mbc, char *ascii, int repc)
+{
+ mts_wchar_t wchar;
+ int consumed;
+ int length;
+
+ if ((length = mts_wcequiv_strlen(ascii)) == -1)
+ return (DECODE_NO_MORE_DATA);
+
+ length += sizeof (mts_wchar_t);
+
+#if 0
+ if (mbc_marshal_put_alignment(mbc, sizeof (mts_wchar_t)) != 0)
+ return (DECODE_NO_MORE_DATA);
+#endif
+ if ((repc > 1) && (repc < length))
+ length = repc;
+
+ if (mbc_marshal_make_room(mbc, length))
+ return (DECODE_NO_MORE_DATA);
+ while (length > 0) {
+ consumed = mts_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
+ if (consumed == -1)
+ break; /* Invalid sequence */
+ /*
+ * Note that consumed will be 0 when the null terminator
+ * is encountered and ascii will not be advanced beyond
+ * that point. Length will continue to be decremented so
+ * we won't get stuck here.
+ */
+ ascii += consumed;
+ mbc_marshal_store_byte(mbc, wchar);
+ mbc_marshal_store_byte(mbc, wchar >> 8);
+ length -= sizeof (mts_wchar_t);
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_put_uio(struct mbuf_chain *mbc, struct uio *uio)
+{
+ struct mbuf **t;
+ struct mbuf *m = 0;
+ struct iovec *iov = uio->uio_iov;
+ int32_t i, iov_cnt = uio->uio_iovcnt;
+
+ iov = uio->uio_iov;
+ t = &mbc->chain;
+ for (i = 0; i < iov_cnt; i++) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_ext.ext_buf = iov->iov_base;
+ m->m_ext.ext_ref = smb_noop;
+ m->m_data = m->m_ext.ext_buf;
+ m->m_flags |= M_EXT;
+ m->m_len = m->m_ext.ext_size = iov->iov_len;
+ mbc->max_bytes += m->m_len;
+ m->m_next = 0;
+ *t = m;
+ t = &m->m_next;
+ iov++;
+ }
+ return (0);
+}
+
+int
+mbc_marshal_put_mbufs(struct mbuf_chain *mbc, struct mbuf *m)
+{
+ struct mbuf *mt;
+ struct mbuf **t;
+ int bytes;
+
+ if (m != 0) {
+ mt = m;
+ bytes = mt->m_len;
+ while (mt->m_next != 0) {
+ mt = mt->m_next;
+ bytes += mt->m_len;
+ }
+ if (bytes != 0) {
+ t = &mbc->chain;
+ while (*t != 0) {
+ bytes += (*t)->m_len;
+ t = &(*t)->m_next;
+ }
+ *t = m;
+ mbc->chain_offset = bytes;
+ } else {
+ m_freem(m);
+ }
+ }
+ return (0);
+}
+
+int
+mbc_marshal_put_mbuf_chain(struct mbuf_chain *mbc, struct mbuf_chain *nmbc)
+{
+ if (nmbc->chain != 0) {
+ if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
+ return (DECODE_NO_MORE_DATA);
+ MBC_SETUP(nmbc, nmbc->max_bytes);
+ }
+ return (0);
+}
+
+int
+mbc_marshal_put_SID(struct mbuf_chain *mbc, nt_sid_t *pSid)
+{
+ int i;
+
+ if (mbc_marshal_put_char(mbc, pSid->Revision) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ if (mbc_marshal_put_char(mbc, pSid->SubAuthCount) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ for (i = 0; i < 6; i++) {
+ if (mbc_marshal_put_char(mbc,
+ pSid->Authority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ }
+
+ for (i = 0; i < pSid->SubAuthCount; i++) {
+ if (mbc_marshal_put_long(mbc, pSid->SubAuthority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_put_skip(struct mbuf_chain *mbc, unsigned int skip)
+{
+ if (mbc_marshal_make_room(mbc, skip))
+ return (DECODE_NO_MORE_DATA);
+ while (skip-- > 0)
+ mbc_marshal_store_byte(mbc, 0);
+ return (0);
+}
+
+unsigned char
+mbc_marshal_fetch_byte(struct mbuf_chain *mbc)
+{
+ unsigned char data;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ data = ((unsigned char *)m->m_data)[offset];
+ mbc->chain_offset++;
+ return (data);
+}
+
+
+int
+mbc_marshal_get_char(struct mbuf_chain *mbc, unsigned char *data)
+{
+ if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ *data = mbc_marshal_fetch_byte(mbc);
+ return (0);
+}
+
+
+int
+mbc_marshal_get_short(struct mbuf_chain *mbc, unsigned short *data)
+{
+ unsigned short tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if ((m->m_len - offset) >= sizeof (short)) {
+ *data = LE_IN16(m->m_data + offset);
+ mbc->chain_offset += sizeof (short);
+ } else {
+ tmp = (unsigned short)mbc_marshal_fetch_byte(mbc);
+ tmp |= ((unsigned short)mbc_marshal_fetch_byte(mbc)) << 8;
+ *data = tmp;
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_get_long(struct mbuf_chain *mbc, uint32_t *data)
+{
+ uint32_t tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if ((m->m_len - offset) >= sizeof (int32_t)) {
+ *data = LE_IN32(m->m_data + offset);
+ mbc->chain_offset += sizeof (int32_t);
+ } else {
+ tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
+ tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
+ tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
+ tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
+ *data = tmp;
+ }
+ return (0);
+}
+
+uint64_t
+qswap(uint64_t ll)
+{
+ uint64_t v;
+
+ v = ll >> 32;
+ v |= ll << 32;
+
+ return (v);
+}
+
+int
+mbc_marshal_get_odd_long_long(struct mbuf_chain *mbc, uint64_t *data)
+{
+ uint64_t tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+
+ if ((m->m_len - offset) >= sizeof (int64_t)) {
+ *data = qswap(LE_IN64(m->m_data + offset));
+ mbc->chain_offset += sizeof (int64_t);
+ } else {
+ tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
+ tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
+
+ *(uint64_t *)data = tmp;
+ }
+ return (0);
+}
+
+int
+mbc_marshal_get_long_long(struct mbuf_chain *mbc, uint64_t *data)
+{
+ uint64_t tmp;
+ struct mbuf *m = mbc->chain;
+ int32_t offset = mbc->chain_offset;
+
+ if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ }
+ if ((m->m_len - offset) >= sizeof (int64_t)) {
+ *data = LE_IN64(m->m_data + offset);
+ mbc->chain_offset += sizeof (int64_t);
+ } else {
+ tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
+ tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
+ *(uint64_t *)data = tmp;
+ }
+ return (0);
+}
+
+/*
+ * mbc_marshal_get_ascii_string
+ *
+ * The ascii string in smb includes oem chars. Since the
+ * system needs utf8 encodes unicode char, conversion is
+ * required to convert the oem char to unicode and then
+ * to encode the converted wchars to utf8 format.
+ * Therefore, the **ascii returned will be in such format
+ * instead of the real ASCII format.
+ */
+static int
+mbc_marshal_get_ascii_string(
+ struct smb_malloc_list *ml,
+ struct mbuf_chain *mbc,
+ unsigned char **ascii,
+ int max_ascii)
+{
+ char *rcvbuf;
+ char *ch;
+ mts_wchar_t *wtmpbuf;
+ int max;
+ int length = 0;
+ unsigned int cpid = oem_get_smb_cpid();
+
+ max = MALLOC_QUANTUM;
+ rcvbuf = smbsr_malloc(ml, max);
+
+ if (max_ascii == 0)
+ max_ascii = 0xffff;
+
+ ch = rcvbuf;
+ for (;;) {
+ while (length < max) {
+ if (max_ascii-- <= 0) {
+ *ch++ = 0;
+ goto multibyte_encode;
+ }
+ if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
+ goto multibyte_encode;
+ length++;
+ }
+ max += MALLOC_QUANTUM;
+ rcvbuf = smbsr_realloc(rcvbuf, max);
+ ch = rcvbuf + length;
+ }
+
+multibyte_encode:
+ /*
+ * UTF-8 encode the string for internal system use.
+ */
+ length = strlen(rcvbuf) + 1;
+ wtmpbuf = smbsr_malloc(ml, length*sizeof (mts_wchar_t));
+ *ascii = smbsr_malloc(ml, length * MTS_MB_CHAR_MAX);
+
+ if (oemstounicodes(wtmpbuf, rcvbuf, length, cpid) > 0)
+ (void) mts_wcstombs((char *)*ascii, wtmpbuf,
+ length * MTS_MB_CHAR_MAX);
+ else
+ (void) mts_stombs((char *)*ascii, rcvbuf, length * 2);
+ return (0);
+}
+
+
+int
+mbc_marshal_get_unicode_string(struct smb_malloc_list *ml,
+ struct mbuf_chain *mbc, unsigned char **ascii, int max_unicode)
+{
+ int max;
+ unsigned short wchar;
+ char *ch;
+ int emitted;
+ int length = 0;
+
+ if (max_unicode == 0)
+ max_unicode = 0xffff;
+
+ max = MALLOC_QUANTUM;
+ *ascii = smbsr_malloc(ml, max);
+
+ ch = (char *)*ascii;
+ for (;;) {
+ while ((length + MTS_MB_CHAR_MAX) < max) {
+ if (max_unicode <= 0)
+ goto done;
+ max_unicode -= 2;
+
+ if (mbc_marshal_get_short(mbc, &wchar) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ if (wchar == 0) goto done;
+
+ emitted = mts_wctomb(ch, wchar);
+ length += emitted;
+ ch += emitted;
+ }
+ max += MALLOC_QUANTUM;
+ *ascii = smbsr_realloc(*ascii, max);
+ ch = (char *)*ascii + length;
+ }
+done: *ch = 0;
+ return (0);
+}
+
+
+int /*ARGSUSED*/
+mbc_marshal_get_mbufs(struct mbuf_chain *mbc, int32_t bytes, struct mbuf **m)
+{
+ if (MBC_ROOM_FOR(mbc, bytes) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+ return (0);
+}
+
+int
+mbc_marshal_get_mbuf_chain(struct mbuf_chain *mbc,
+ int32_t bytes, struct mbuf_chain *nmbc)
+{
+ int rc;
+ struct mbuf *m;
+
+ if (bytes == 0) {
+ /* Get all the rest */
+ bytes = mbc->max_bytes - mbc->chain_offset;
+ }
+
+ MBC_SETUP(nmbc, mbc->max_bytes);
+ if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
+ if (m)
+ m_freem(m);
+ return (rc);
+ }
+ nmbc->chain = m;
+ while (m != 0) {
+ bytes += m->m_len;
+ m = m->m_next;
+ }
+ nmbc->max_bytes = bytes;
+ return (0);
+}
+
+
+int
+mbc_marshal_get_uio(struct mbuf_chain *mbc, struct uio *uio)
+{
+ int i, offset;
+ int32_t bytes = uio->uio_resid;
+ int32_t remainder;
+ struct iovec *iov;
+ struct mbuf *m;
+
+ /*
+ * The residual count is tested because in the case of write requests
+ * with no data (smbtorture RAW-WRITE test will generate that type of
+ * request) this function is called with a residual count of zero
+ * bytes.
+ */
+ if (bytes) {
+ iov = uio->uio_iov;
+ uio->uio_segflg = UIO_SYSSPACE;
+
+ if (MBC_ROOM_FOR(mbc, bytes) == 0) {
+ /* Data will never be available */
+ return (DECODE_NO_MORE_DATA);
+ }
+
+ m = mbc->chain;
+ offset = mbc->chain_offset;
+ while (offset >= m->m_len) {
+ offset -= m->m_len;
+ m = m->m_next;
+ ASSERT((offset == 0) || (offset && m));
+ }
+
+ for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
+ iov[i].iov_base = &m->m_data[offset];
+ remainder = m->m_len - offset;
+ if (remainder >= bytes) {
+ iov[i].iov_len = bytes;
+ mbc->chain_offset += bytes;
+ break;
+ }
+ iov[i].iov_len = remainder;
+ mbc->chain_offset += remainder;
+ bytes -= remainder;
+ m = m->m_next;
+ offset = 0;
+ }
+ if (i == uio->uio_iovcnt) {
+ return (DECODE_NO_MORE_DATA);
+ }
+ uio->uio_iovcnt = i;
+ }
+ return (0);
+}
+
+
+int
+mbc_marshal_get_SID(struct mbuf_chain *mbc, nt_sid_t *pSid)
+{
+ int i;
+
+ if (mbc_marshal_get_char(mbc, &pSid->Revision) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ if (mbc_marshal_get_char(mbc, &pSid->SubAuthCount) != 0)
+ return (DECODE_NO_MORE_DATA);
+
+ for (i = 0; i < 6; i++) {
+ if (mbc_marshal_get_char(mbc,
+ &pSid->Authority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+
+ for (i = 0; i < pSid->SubAuthCount; i++) {
+ if (mbc_marshal_get_long(mbc, &pSid->SubAuthority[i]) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ return (0);
+}
+
+int
+mbc_marshal_get_skip(struct mbuf_chain *mbc, unsigned int skip)
+{
+ if (MBC_ROOM_FOR(mbc, skip) == 0)
+ return (DECODE_NO_MORE_DATA);
+ mbc->chain_offset += skip;
+ return (0);
+}
+
+int
+mbc_marshal_get_alignment(struct mbuf_chain *mbc, unsigned int align)
+{
+ int32_t delta = mbc->chain_offset % align;
+
+ if (delta != 0) {
+ align -= delta;
+ return (mbc_marshal_get_skip(mbc, delta));
+ }
+ return (0);
+}
+
+/*
+ * The mbuf chain passed in contains the data to be decoded.
+ *
+ * The format string provides a description of the parameters passed in as well
+ * as an action to be taken by smb_mbc_decode().
+ *
+ * \b Restore the mbuf chain offset to its initial value.
+ *
+ * % Pointer to an SMB request structure (smb_request_t *). There
+ * should be only one of these in the string.
+ *
+ * C Pointer to an mbuf chain. Copy to that mbuf chain the number of
+ * bytes specified (number preceding C).
+ *
+ * m Pointer to an mbuf. Copy to that mbuf the number of bytes
+ * specified (number preceding m).
+ *
+ * M Read the 32 bit value at the current location of the mbuf chain
+ * and check if it matches the signature of an SMB request (SMBX).
+ *
+ * b Pointer to a buffer. Copy to that buffer the number of bytes
+ * specified (number preceding b).
+ *
+ * c Same as 'b'.
+ *
+ * w Pointer to a word (16bit value). Copy the next 16bit value into
+ * that location.
+ *
+ * l Pointer to a long (32bit value). Copy the next 32bit value into
+ * that location.
+ *
+ * q Pointer to a quad (64bit value). Copy the next 64bit value into
+ * that location.
+ *
+ * Q Same as above with a call to qswap().
+ *
+ * B Pointer to a vardata_block structure. That structure is used to
+ * retrieve data from the mbuf chain (an iovec type structure is
+ * embedded in a vardata_block).
+ *
+ * D Pointer to a vardata_block structure. That structure is used to
+ * retrieve data from the mbuf chain, however, two fields of the
+ * vardata_block structure (tag and len) are first initialized
+ * using the mbuf chain itself.
+ *
+ * V Same as 'D'.
+ *
+ * L
+ *
+ * A
+ *
+ * P Same as 'A'
+ *
+ * S Same as 'A'
+ *
+ * u Pointer to a string pointer. Allocate memory and retrieve the
+ * string at the current location in the mbuf chain. Store the
+ * address to the buffer allocated at the address specified by
+ * the pointer. In addition if an sr was passed and it indicates
+ * that the string is an unicode string, convert it.
+ *
+ * s Same as 'u' without convertion.
+ *
+ * U Same as 'u'. The string to retrieve is unicode.
+ *
+ * R Not used anymore.
+ *
+ * y Pointer to a 32bit value. Read the dos time at the current mbuf
+ * chain location, convert it to unix time and store it at the
+ * location indicated by the pointer.
+ *
+ * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted.
+ *
+ * . Skip the number of bytes indicated by the number preceding '.'.
+ *
+ * , Same as '.' but take in account it is an unicode string.
+ *
+ * The parameters can be named in the format string. They have to appear between
+ * parenthesis (indicating they should be ignored bu the decoder).
+ */
+int
+smb_mbc_decode(struct mbuf_chain *mbc, char *fmt, va_list ap)
+{
+ unsigned char c, cval;
+ unsigned char *cvalp;
+ unsigned char **cvalpp;
+ unsigned short *wvalp;
+ unsigned int *ivalp;
+ uint32_t *lvalp;
+ uint64_t *llvalp;
+ struct vardata_block *vdp;
+ unsigned char name[32];
+ struct smb_request *sr = NULL;
+ uint32_t lval;
+ int unicode = 0;
+ int repc;
+ /*LINTED E_FUNC_SET_NOT_USED*/
+ enum {EVEN, UNALIGNED, ODD} alignment;
+ int32_t saved_chain_offset = mbc->chain_offset;
+
+ name[0] = 0;
+ while ((c = *fmt++) != 0) {
+ repc = 1;
+ alignment = EVEN;
+
+ if (c == ' ' || c == '\t') continue;
+ if (c == '(') {
+ char *nm = (char *)name;
+
+ while (((c = *fmt++) != 0) && c != ')') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ continue;
+ }
+
+ if (c == '{') {
+ unsigned char op[8];
+ char *nm = (char *)op;
+
+ while (((c = *fmt++) != 0) && c != '}') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ if (strcmp((char *)op, "SID") == 0) {
+ nt_sid_t *sidp;
+
+ sidp = va_arg(ap, nt_sid_t *);
+ (void) mbc_marshal_get_SID(mbc, sidp);
+ }
+ continue;
+ }
+
+ if ('0' <= c && c <= '9') {
+ repc = 0;
+ do {
+ repc = repc * 10 + c - '0';
+ c = *fmt++;
+ } while ('0' <= c && c <= '9');
+ } else if (c == '*') {
+ ivalp = va_arg(ap, unsigned int *);
+ repc = *(ivalp++);
+ c = *fmt++;
+ } else if (c == '!') {
+ alignment = ODD;
+ c = *fmt++;
+ } else if (c == '^') {
+ alignment = UNALIGNED;
+ c = *fmt++;
+ } else if (c == '#') {
+ repc = va_arg(ap, int);
+ c = *fmt++;
+ }
+
+ switch (c) {
+ default:
+ goto format_mismatch;
+
+ case '\b':
+ mbc->chain_offset = saved_chain_offset;
+ break;
+
+ case '%':
+ sr = va_arg(ap, struct smb_request *);
+ unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
+ break;
+
+ case 'C': /* Mbuf_chain */
+ if (mbc_marshal_get_mbuf_chain(mbc, repc,
+ va_arg(ap, struct mbuf_chain *)) != 0)
+ goto underflow;
+ break;
+
+ case 'm': /* struct_mbuf */
+ if (mbc_marshal_get_mbufs(mbc, repc,
+ va_arg(ap, struct mbuf **)) != 0)
+ goto underflow;
+ break;
+
+ case 'M':
+ if (mbc_marshal_get_long(mbc, &lval) != 0) {
+ /* Data will never be available */
+ goto underflow;
+ }
+ if (lval != 0x424D53FF) /* 0xFF S M B */
+ goto underflow;
+ break;
+
+ case 'b':
+ case 'c':
+ cvalp = va_arg(ap, unsigned char *);
+ if (MBC_ROOM_FOR(mbc, repc) == 0) {
+ /* Data will never be available */
+ goto underflow;
+ }
+ while (repc-- > 0)
+ *cvalp++ = mbc_marshal_fetch_byte(mbc);
+ break;
+
+ case 'w':
+ wvalp = va_arg(ap, unsigned short *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_short(mbc, wvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'l':
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_long(mbc, lvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'q':
+ llvalp = va_arg(ap, uint64_t *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_long_long(
+ mbc, llvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'Q':
+ llvalp = va_arg(ap, uint64_t *);
+ while (repc-- > 0)
+ if (mbc_marshal_get_odd_long_long(
+ mbc, llvalp++) != 0)
+ goto underflow;
+ break;
+
+ case 'B':
+ vdp = va_arg(ap, struct vardata_block *);
+ vdp->tag = 0;
+
+ /*LINTED E_ASSIGN_NARROW_CONV (BYTE)*/
+ vdp->len = repc;
+ vdp->uio.uio_iov = &vdp->iovec[0];
+ vdp->uio.uio_iovcnt = MAX_IOVEC;
+ vdp->uio.uio_resid = repc;
+ if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0)
+ goto underflow;
+ break;
+
+ case 'D': case 'V':
+ vdp = va_arg(ap, struct vardata_block *);
+ if (mbc_marshal_get_char(mbc, &vdp->tag) != 0)
+ goto underflow;
+ if (mbc_marshal_get_short(mbc, &vdp->len) != 0)
+ goto underflow;
+ vdp->uio.uio_iov = &vdp->iovec[0];
+ vdp->uio.uio_iovcnt = MAX_IOVEC;
+ vdp->uio.uio_resid = vdp->len;
+ if (vdp->len != 0) {
+ if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0)
+ goto underflow;
+ }
+ break;
+
+ case 'L':
+ if (mbc_marshal_get_char(mbc, &cval) != 0)
+ goto underflow;
+ if (cval != 2)
+ goto format_mismatch;
+ goto ascii_conversion;
+
+ case 'A': case 'P': case 'S':
+ if (mbc_marshal_get_char(mbc, &cval) != 0)
+ goto underflow;
+ if (((c == 'A' || c == 'S') && cval != 4) ||
+ (c == 'L' && cval != 2) || (c == 'P' && cval != 3))
+ goto format_mismatch;
+ /* FALLTHROUGH */
+
+ case 'u': /* Convert from unicode if flags are set */
+ if (unicode)
+ goto unicode_translation;
+ /* FALLTHROUGH */
+
+ case 's':
+ascii_conversion:
+ ASSERT(sr != NULL);
+ cvalpp = va_arg(ap, unsigned char **);
+ if (repc <= 1)
+ repc = 0;
+ if (mbc_marshal_get_ascii_string(&sr->request_storage,
+ mbc, cvalpp, repc) != 0)
+ goto underflow;
+ break;
+
+ case 'U': /* Convert from unicode */
+unicode_translation:
+ ASSERT(sr != 0);
+ cvalpp = va_arg(ap, unsigned char **);
+ if (repc <= 1)
+ repc = 0;
+ if (mbc->chain_offset & 1)
+ mbc->chain_offset++;
+ if (mbc_marshal_get_unicode_string(&sr->request_storage,
+ mbc, cvalpp, repc) != 0)
+ goto underflow;
+ break;
+
+ case 'R':
+ /*
+ * This was used to decode RPC format unicode strings
+ * prior to having a DCE RPC support. It is no longer
+ * required.
+ */
+ ASSERT(0);
+ break;
+
+ case 'Y': /* dos time to unix time tt/dd */
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0) {
+ short d, t;
+
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&t) != 0)
+ goto underflow;
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&d) != 0)
+ goto underflow;
+ *lvalp++ = dosfs_dos_to_ux_time(d, t);
+ }
+ break;
+
+ case 'y': /* dos time to unix time dd/tt */
+ lvalp = va_arg(ap, uint32_t *);
+ while (repc-- > 0) {
+ short d, t;
+
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&d) != 0)
+ goto underflow;
+ if (mbc_marshal_get_short(mbc,
+ (unsigned short *)&t) != 0)
+ goto underflow;
+ *lvalp++ = dosfs_dos_to_ux_time(d, t);
+ }
+ break;
+
+ case ',':
+ if (unicode)
+ repc *= 2;
+ /* FALLTHROUGH */
+
+ case '.':
+ if (mbc_marshal_get_skip(mbc, repc) != 0)
+ goto underflow;
+ break;
+ }
+ }
+ return (0);
+
+
+format_mismatch:
+ return (-1);
+
+underflow:
+ return (-1);
+}
+
+
+int
+smb_decode_mbc(struct mbuf_chain *mbc, char *fmt, ...)
+{
+ int xx;
+ va_list ap;
+
+ va_start(ap, fmt);
+ xx = smb_mbc_decode(mbc, fmt, ap);
+ va_end(ap);
+ return (xx);
+}
+
+
+int
+smb_decode_buf(unsigned char *buf, int n_buf, char *fmt, ...)
+{
+ int rc;
+ struct mbuf_chain mbc;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ MBC_ATTACH_BUF(&mbc, buf, n_buf);
+ rc = smb_mbc_decode(&mbc, fmt, ap);
+ m_freem(mbc.chain);
+ va_end(ap);
+ return (rc);
+}
+
+/*
+ * The mbuf chain passed in will receive the encoded data.
+ *
+ * The format string provides a description of the parameters passed in as well
+ * as an action to be taken by smb_mbc_encode().
+ *
+ * \b Restore the mbuf chain offset to its initial value.
+ *
+ * % Pointer to an SMB request structure (smb_request_t *). There
+ * should be only one of these in the string. If an sr in present
+ * it will be used to determine if unicode conversion should be
+ * applied to the strings.
+ *
+ * C Pointer to an mbuf chain. Copy that mbuf chain into the
+ * destination mbuf chain.
+ *
+ * D Pointer to a vardata_block structure. Copy the data described
+ * by that structure into the mbuf chain. The tag field is hard
+ * coded to '1'.
+ *
+ * M Write the SMB request signature ('SMBX') into the mbuf chain.
+ *
+ * T Pointer to a timestruc_t. Convert the content of the structure
+ * into NT time and store the result of the conversion in the
+ * mbuf chain.
+ *
+ * V Same as 'D' but the tag field is hard coded to '5'.
+ *
+ * b Byte. Store the byte or the nymber of bytes specified into the
+ * the mbuf chain. A format string like this "2b" would require 2
+ * bytes to be passed in.
+ *
+ * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
+ * chain.
+ *
+ * c Pointer to a buffer. Copy the buffer into the mbuf chain. The
+ * size of the buffer is indicated by the number preceding 'c'.
+ *
+ * w Word (16bit value). Store the word or the number of words
+ * specified into the the mbuf chain. A format string like this
+ * "2w" would require 2 words to be passed in.
+ *
+ * l Long (32bit value). Store the long or the number of longs
+ * specified into the the mbuf chain. A format string like this
+ * "2l" would require 2 longs to be passed in.
+ *
+ * q Quad (64bit value). Store the quad or the number of quads
+ * specified into the the mbuf chain. A format string like this
+ * "2q" would require 2 quads to be passed in.
+ *
+ * L Pointer to a string. Store the string passed in into the mbuf
+ * chain preceded with a tag value of '2'.
+ *
+ * S Pointer to a string. Store the string passed in into the mbuf
+ * chain preceded with a tag value of '4'. Applied a unicode
+ * conversion is appropriate.
+ *
+ * A Same as 'S'
+ *
+ * P Pointer to a string. Store the string passed in into the mbuf
+ * chain preceded with a tag value of '5'. Applied a unicode
+ * conversion is appropriate.
+ *
+ * u Pointer to a string. Store the string passed in into the mbuf
+ * chain. Applied a unicode conversion is appropriate.
+ *
+ * s Pointer to a string. Store the string passed in into the mbuf
+ * chain.
+ *
+ * Y Date/Time. Store the Date/Time or the number of Date/Time(s)
+ * specified into the the mbuf chain. A format string like this
+ * "2Y" would require 2 Date/Time values. The Date/Time is
+ * converted to DOS before storing.
+ *
+ * y Same as 'Y'. The order of Date and Time is reversed.
+ *
+ * , Character. Store the character or number of character specified
+ * into the mbuf chain. A format string like this "2c" would
+ * require 2 characters to be passed in. A unicode conversion is
+ * applied if appropriate.
+ *
+ * . Same as '`' without unicode conversion.
+ *
+ * U Align the offset of the mbuf chain on a 16bit boundary.
+ *
+ * Z Unicode string. Store the unicode string into the mbuf chain
+ * without alignment considerations.
+ *
+ * The parameters can be named in the format string. They have to appear between
+ * parenthesis (indicating they should be ignored bu the encoder).
+ */
+int
+smb_mbc_encode(struct mbuf_chain *mbc, char *fmt, va_list ap)
+{
+ unsigned char name[32];
+ unsigned char cval, c;
+ unsigned short wval;
+ uint64_t llval;
+ uint32_t lval;
+ unsigned int tag;
+ unsigned char *cvalp;
+ unsigned int *ivalp;
+ timestruc_t *tvp;
+ int64_t nt_time;
+ struct vardata_block *vdp;
+ struct smb_request *sr = 0;
+ int unicode = 0;
+ int repc = 1;
+ /*LINTED E_FUNC_SET_NOT_USED*/
+ enum {EVEN, UNALIGNED, ODD} alignment;
+
+ while ((c = *fmt++) != 0) {
+ name[0] = 0;
+ repc = 1;
+ alignment = EVEN;
+ if (c == ' ' || c == '\t') continue;
+ if (c == '(') {
+ char *nm = (char *)name;
+
+ while (((c = *fmt++) != 0) && c != ')') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ continue;
+ }
+
+ if (c == '{') {
+ unsigned char op[8];
+ char *nm = (char *)op;
+
+ while (((c = *fmt++) != 0) && c != '}') {
+ *nm++ = c;
+ }
+ *nm = 0;
+ if (!c) fmt--;
+ if (strcmp((char *)op, "SID") == 0) {
+ nt_sid_t *sidp;
+
+ sidp = va_arg(ap, nt_sid_t *);
+ (void) mbc_marshal_put_SID(mbc, sidp);
+ }
+ continue;
+ }
+
+ if ('0' <= c && c <= '9') {
+ repc = 0;
+ do {
+ repc = repc * 10 + c - '0';
+ c = *fmt++;
+ } while ('0' <= c && c <= '9');
+ } else if (c == '*') {
+ ivalp = va_arg(ap, unsigned int *);
+
+ repc = *ivalp;
+ c = *fmt++;
+ } else if (c == '!') {
+ alignment = ODD;
+ c = *fmt++;
+ } else if (c == '^') {
+ alignment = UNALIGNED;
+ c = *fmt++;
+ } else if (c == '#') {
+ repc = va_arg(ap, int);
+ c = *fmt++;
+ }
+
+ switch (c) {
+ default:
+ goto format_mismatch;
+
+ case '%':
+ sr = va_arg(ap, struct smb_request *);
+ unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
+ break;
+
+ case 'C': /* Mbuf_chain */
+ if (mbc_marshal_put_mbuf_chain(mbc,
+ va_arg(ap, struct mbuf_chain *)) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'D':
+ vdp = va_arg(ap, struct vardata_block *);
+
+ if (mbc_marshal_put_char(mbc, 1) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, vdp->len) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'M':
+ /* 0xFF S M B */
+ if (mbc_marshal_put_long(mbc, 0x424D53FF))
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'T':
+ tvp = va_arg(ap, timestruc_t *);
+ nt_time = unix_to_nt_time(tvp);
+ if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'V':
+ vdp = va_arg(ap, struct vardata_block *);
+
+ if (mbc_marshal_put_char(mbc, 5) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, vdp->len) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'b':
+ while (repc-- > 0) {
+ cval = va_arg(ap, int);
+ if (mbc_marshal_put_char(mbc, cval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'm': /* struct_mbuf */
+ if (mbc_marshal_put_mbufs(mbc,
+ va_arg(ap, struct mbuf *)) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'c':
+ cvalp = va_arg(ap, unsigned char *);
+ while (repc-- > 0) {
+ if (mbc_marshal_put_char(mbc,
+ *cvalp++) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'w':
+ while (repc-- > 0) {
+ wval = va_arg(ap, int);
+ if (mbc_marshal_put_short(mbc, wval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'l':
+ while (repc-- > 0) {
+ lval = va_arg(ap, uint32_t);
+ if (mbc_marshal_put_long(mbc, lval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'q':
+ while (repc-- > 0) {
+ llval = va_arg(ap, uint64_t);
+ if (mbc_marshal_put_long_long(mbc, llval) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+
+ case 'L':
+ tag = 2;
+ goto ascii_conversion;
+
+ case 'S':
+ case 'A': tag = 4; goto tagged_str;
+ case 'P': tag = 3; goto tagged_str;
+ tagged_str:
+ if (mbc_marshal_put_char(mbc, tag) != 0)
+ return (DECODE_NO_MORE_DATA);
+ /* FALLTHROUGH */
+
+ case 'u': /* Convert from unicode if flags are set */
+ if (unicode)
+ goto unicode_translation;
+ /* FALLTHROUGH */
+
+ case 's': /* ASCII/multibyte string */
+ascii_conversion: cvalp = va_arg(ap, unsigned char *);
+ if (mbc_marshal_put_ascii_string(mbc,
+ (char *)cvalp, repc) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'Y': /* int32_t, encode dos date/time */
+ while (repc-- > 0) {
+ unsigned short d, t;
+
+ lval = va_arg(ap, uint32_t);
+ (void) dosfs_ux_to_dos_time(lval,
+ (short *)&d, (short *)&t);
+ if (mbc_marshal_put_short(mbc, t) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, d) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case 'y': /* int32_t, encode dos date/time */
+ while (repc-- > 0) {
+ unsigned short d, t;
+
+ lval = va_arg(ap, uint32_t);
+ (void) dosfs_ux_to_dos_time(lval,
+ (short *)&d, (short *)&t);
+ if (mbc_marshal_put_short(mbc, d) != 0)
+ return (DECODE_NO_MORE_DATA);
+ if (mbc_marshal_put_short(mbc, t) != 0)
+ return (DECODE_NO_MORE_DATA);
+ }
+ break;
+
+ case ',':
+ if (unicode)
+ repc *= 2;
+ /* FALLTHROUGH */
+
+ case '.':
+ while (repc-- > 0)
+ if (mbc_marshal_put_char(mbc, 0) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+
+ case 'R':
+ /*
+ * This was used to encode RPC format unicode strings
+ * prior to having a DCE RPC support. It is no longer
+ * required.
+ */
+ ASSERT(0);
+ break;
+
+ case 'U': /* Convert to unicode, align to word boundary */
+unicode_translation:
+ if (mbc->chain_offset & 1)
+ mbc->chain_offset++;
+ /* FALLTHROUGH */
+
+ case 'Z': /* Convert to unicode, no alignment adjustment */
+ cvalp = va_arg(ap, unsigned char *);
+ if (mbc_marshal_put_unicode_string(mbc,
+ (char *)cvalp, repc) != 0)
+ return (DECODE_NO_MORE_DATA);
+ break;
+ }
+ }
+ return (0);
+
+format_mismatch:
+ return (-1);
+}
+
+
+int
+smb_encode_mbc(struct mbuf_chain *mbc, char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = smb_mbc_encode(mbc, fmt, ap);
+ va_end(ap);
+ return (rc);
+}
+
+
+int
+smb_encode_buf(unsigned char *buf, int n_buf, char *fmt, ...)
+{
+ int rc;
+ struct mbuf_chain mbc;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ MBC_ATTACH_BUF(&mbc, buf, n_buf);
+ rc = smb_mbc_encode(&mbc, fmt, ap);
+ m_freem(mbc.chain);
+ va_end(ap);
+ return (rc);
+}
+
+
+int
+smb_decode_vwv(struct smb_request *sr, char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = smb_mbc_decode(&sr->smb_vwv, fmt, ap);
+ va_end(ap);
+ return (rc);
+}
+
+
+int
+smb_decode_data(struct smb_request *sr, char *fmt, ...)
+{
+ if (smb_decode_mbc(&sr->smb_data, fmt, (int *)(&fmt + 1)) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ return (0);
+}
+
+
+void
+smb_encode_header(struct smb_request *sr, int wct,
+ int bcc, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (smb_mbc_encode(&sr->reply, fmt, ap) != 0) {
+ va_end(ap);
+ smbsr_encode_error(sr);
+ /* NOTREACHED */
+ }
+ va_end(ap);
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ sr->smb_wct = wct;
+ /*LINTED E_ASSIGN_NARROW_CONV*/
+ sr->smb_bcc = bcc;
+}
+
+int
+smb_peek_mbc(struct mbuf_chain *mbc, int offset, char *fmt, ...)
+{
+ int xx;
+ struct mbuf_chain tmp;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
+ xx = smb_mbc_decode(&tmp, fmt, ap);
+ va_end(ap);
+ return (xx);
+}
+
+
+int
+smb_poke_mbc(struct mbuf_chain *mbc, int offset, char *fmt, ...)
+{
+ int xx;
+ struct mbuf_chain tmp;
+ va_list ap;
+
+ (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
+ va_start(ap, fmt);
+ xx = smb_mbc_encode(&tmp, fmt, ap);
+ va_end(ap);
+ return (xx);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
new file mode 100644
index 0000000000..b8e45289cd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
@@ -0,0 +1,334 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLRPC server-side library processing. This is where we decode the
+ * request header to figure out what type of request is being made,
+ * call the server stub, if appropriate, and build the response header.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mbuf.h>
+
+/*
+ * Fragment size (5680: NT style). Tuning parameter
+ * used during development of multiple fragment support.
+ */
+
+#define MLRPC_FRAG_SIZE 5680
+#define MLRPC_RSP_HDR_SIZE 24
+
+/*
+ * smb_mbuf_get
+ *
+ * Allocate mbufs to hold the amount of data specified.
+ * A pointer to the head of the mbuf list is returned.
+ */
+struct mbuf *
+smb_mbuf_get(uchar_t *buf, int nbytes)
+{
+ struct mbuf *mhead = 0;
+ struct mbuf *m = 0;
+ int count;
+ int offset = 0;
+
+ while (nbytes) {
+ count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
+ nbytes -= count;
+
+ if (mhead == 0) {
+ MGET(mhead, M_WAIT, MT_DATA);
+ m = mhead;
+ } else {
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ m = m->m_next;
+ }
+
+ if (count > MLEN) {
+ MCLGET(m, M_WAIT);
+ }
+
+ m->m_len = count;
+ bcopy(buf + offset, m->m_data, count);
+ offset += count;
+ }
+ return (mhead);
+}
+
+/*
+ * Allocate enough mbufs to accommodate the residual count in a uio.
+ */
+struct mbuf *
+smb_mbuf_allocate(struct uio *uio)
+{
+ struct iovec *iovp;
+ struct mbuf *mhead = 0;
+ struct mbuf *m = 0;
+ int count, iovs, resid;
+
+ iovp = uio->uio_iov;
+ iovs = uio->uio_iovcnt;
+ resid = uio->uio_resid;
+
+ while ((resid > 0) && (iovs > 0)) {
+ count = (resid > MCLBYTES) ? MCLBYTES : resid;
+ resid -= count;
+
+ if (mhead == 0) {
+ MGET(mhead, M_WAIT, MT_DATA);
+ m = mhead;
+ } else {
+ MGET(m->m_next, M_WAIT, MT_DATA);
+ m = m->m_next;
+ }
+
+ if (count > MLEN) {
+ MCLGET(m, M_WAIT);
+ }
+
+ iovp->iov_base = m->m_data;
+ iovp->iov_len = m->m_len = count;
+ iovs--;
+ iovp++;
+ }
+
+ uio->uio_iovcnt -= iovs;
+ return (mhead);
+}
+
+/*
+ * Trim an mbuf chain to nbytes.
+ */
+void
+smb_mbuf_trim(struct mbuf *mhead, int nbytes)
+{
+ struct mbuf *m = mhead;
+
+ while (m != 0) {
+ if (nbytes <= m->m_len) {
+ m->m_len = nbytes;
+ if (m->m_next != 0) {
+ m_freem(m->m_next);
+ m->m_next = 0;
+ }
+ break;
+ }
+ nbytes -= m->m_len;
+ m = m->m_next;
+ }
+}
+
+int
+MBC_LENGTH(struct mbuf_chain *MBC)
+{
+ struct mbuf *m = (MBC)->chain;
+ int used = 0;
+
+ while (m != 0) {
+ used += m->m_len;
+ m = m->m_next;
+ }
+ return (used);
+}
+
+void
+MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
+{
+ bzero((MBC), sizeof (struct mbuf_chain));
+ (MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize;
+}
+
+void
+MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
+{
+ struct mbuf *m;
+
+ bzero((MBC), sizeof (struct mbuf_chain));
+
+ if (max_bytes != 0) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_len = 0;
+ (MBC)->chain = m;
+ if (max_bytes > MINCLSIZE)
+ MCLGET(m, M_WAIT);
+ }
+ (MBC)->max_bytes = max_bytes;
+}
+
+void
+MBC_FLUSH(struct mbuf_chain *MBC)
+{
+ extern void m_freem(struct mbuf *);
+ struct mbuf *m;
+
+ while ((m = (MBC)->chain) != 0) {
+ (MBC)->chain = m->m_nextpkt;
+ m->m_nextpkt = 0;
+ m_freem(m);
+ }
+ MBC_SETUP(MBC, (MBC)->max_bytes);
+}
+
+void
+MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
+{
+ if (MBC->chain != 0)
+ MBC_FLUSH(MBC);
+
+ (MBC)->chain_offset = 0;
+ (MBC)->chain = (MBUF);
+}
+
+void
+MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
+{
+ struct mbuf *m;
+
+ if ((MBC)->chain == 0) {
+ (MBC)->chain = (MBUF);
+ } else {
+ m = (MBC)->chain;
+ while (m->m_next != 0)
+ m = m->m_next;
+ m->m_next = (MBUF);
+ }
+}
+
+
+void
+MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
+{
+ MGET((MBC)->chain, M_WAIT, MT_DATA);
+ (MBC)->chain_offset = 0;
+ (MBC)->chain->m_flags |= M_EXT;
+ (MBC)->chain->m_data = (caddr_t)(BUF);
+ (MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
+ (MBC)->chain->m_len = (LEN);
+ (MBC)->chain->m_ext.ext_size = (LEN);
+ (MBC)->chain->m_ext.ext_ref = smb_noop;
+ (MBC)->max_bytes = (LEN);
+}
+
+
+int
+MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
+ int OFF, int LEN)
+{
+ if (((OFF) + (LEN)) > (MBC)->max_bytes)
+ return (EMSGSIZE);
+
+ *(SUBMBC) = *(MBC);
+ (SUBMBC)->chain_offset = (OFF);
+ (SUBMBC)->max_bytes = (OFF) + (LEN);
+ (SUBMBC)->shadow_of = (MBC);
+ return (0);
+}
+
+/*
+ * Free a single mbuf structure. Calls m->m_ext.ext_ref() to free any
+ * associated external buffers if present (indicated by m->m_flags & M_EXT)
+ */
+struct mbuf *
+m_free(struct mbuf *m)
+{
+ struct mbuf *n;
+
+ MFREE(m, n);
+ return (n);
+}
+
+/*
+ * Free a list of mbufs. Each mbuf in the list is freed similarly to m_free.
+ */
+void
+m_freem(struct mbuf *m)
+{
+ struct mbuf *n;
+
+ if (m == NULL)
+ return;
+ /*
+ * Lint doesn't like the m = n assignment at the close of the loop
+ * but it is correct. MFREE assigns n = (m)->m_next so the loop
+ * is effectively assigning m = (m)->m_next then exiting when
+ * m == NULL
+ */
+ do {
+ MFREE(m, n);
+ } while ((m = n) != 0);
+}
+
+/*
+ * Mbuffer utility routines.
+ */
+
+int /*ARGSUSED*/
+mclref(caddr_t p, int size, int adj) /* size, adj are unused */
+{
+ MEM_FREE("mbuf", p);
+ return (0);
+}
+
+int /*ARGSUSED*/
+mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
+{
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_memory_manager.c b/usr/src/uts/common/fs/smbsrv/smb_memory_manager.c
new file mode 100644
index 0000000000..61e1066388
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_memory_manager.c
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Memory management functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * smbsr_malloc
+ *
+ * allocate a block of memory with the given size and
+ * add it to the given linked list. This function is
+ * used to allocate temporary memories which are needed
+ * during processing of a SMB request. These memories
+ * get freed when request processing is finished.
+ */
+void *
+smbsr_malloc(smb_malloc_list *list, size_t size)
+{
+ smb_malloc_list *element;
+
+ size += sizeof (smb_malloc_list);
+ element = MEM_MALLOC("smb", size);
+ element->forw = list->forw;
+ element->back = list;
+ list->forw->back = element;
+ list->forw = element;
+ return (void *)(element + 1); /* return address of data */
+}
+
+/*
+ * smbsr_realloc
+ *
+ * This function is used in conjunction with smbsr_malloc to
+ * resize an already allocated entity.
+ */
+void *
+smbsr_realloc(void *mem, size_t size)
+{
+ smb_malloc_list *element = (smb_malloc_list *)mem;
+ smb_malloc_list *new_entry;
+ smb_malloc_list *list;
+
+ element--;
+ list = element->back;
+ QUEUE_CLIP(element);
+ size += sizeof (smb_malloc_list);
+
+ new_entry = MEM_REALLOC("smb", element, size);
+ new_entry->forw = list->forw;
+ new_entry->back = list;
+ list->forw->back = new_entry;
+ list->forw = new_entry;
+ return (void *)(new_entry + 1); /* return address of new data */
+}
+
+/*
+ * smbsr_free_malloc_list
+ *
+ * Frees all memory block in the given linked list.
+ */
+void
+smbsr_free_malloc_list(smb_malloc_list *root)
+{
+ smb_malloc_list *element;
+
+ /*
+ * we initialize smb_request structure in smb_nt_notify_change
+ * function, so we should check root->forw to make sure it's
+ * not NULL.
+ */
+ while (root->forw && root->forw != root) {
+ element = root->forw;
+
+ element->forw->back = element->back;
+ element->back->forw = element->forw;
+
+ /* and release it... */
+ MEM_FREE("smb", element);
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_move.c b/usr/src/uts/common/fs/smbsrv/smb_move.c
new file mode 100644
index 0000000000..eb44e5a84d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_move.c
@@ -0,0 +1,114 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: move
+ *
+ * The source file is copied to the destination and the source is
+ * subsequently deleted.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * USHORT Tid2; Second (target) file id
+ * USHORT OpenFunction; what to do if target file exists
+ * USHORT Flags; Flags to control move operations:
+ * 0 - target must be a file
+ * 1 - target must be a directory
+ * 2 - reserved (must be 0)
+ * 3 - reserved (must be 0)
+ * 4 - verify all writes
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR Format1; 0x04
+ * STRING OldFileName[]; Old file name
+ * UCHAR FormatNew; 0x04
+ * STRING NewFileName[]; New file name
+ *
+ * OldFileName is copied to NewFileName, then OldFileName is deleted. Both
+ * OldFileName and NewFileName must refer to paths on the same server.
+ * NewFileName can refer to either a file or a directory. All file
+ * components except the last must exist; directories will not be created.
+ *
+ * NewFileName can be required to be a file or a directory by the Flags
+ * field.
+ *
+ * The Tid in the header is associated with the source while Tid2 is
+ * associated with the destination. These fields may contain the same or
+ * differing valid values. Tid2 can be set to -1 indicating that this is to
+ *
+ * be the same Tid as in the SMB header. This allows use of the move
+ * protocol with SMB_TREE_CONNECT_ANDX.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Number of files moved
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR ErrorFileFormat; 0x04 (only if error)
+ * STRING ErrorFileName[]; Pathname of file where error
+ * occurred
+ *
+ * The source path must refer to an existing file or files. Wildcards are
+ * permitted. Source files specified by wildcards are processed until an
+ * error is encountered. If an error is encountered, the expanded name of
+ * the file is returned in ErrorFileName. Wildcards are not permitted in
+ * NewFileName.
+ *
+ * OpenFunction controls what should happen if the destination file exists.
+ * If (OpenFunction & 0x30) == 0, the operation should fail if the
+ * destination exists. If (OpenFunction & 0x30) == 0x20, the destination
+ * file should be overwritten.
+ *
+ * 4.2.12.1 Errors
+ *
+ * ERRDOS/ERRfilexists
+ * ERRDOS/ERRbadfile
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRnofiles
+ * ERRDOS/ERRbadshare
+ * ERRHRD/ERRnowrite
+ * ERRSRV/ERRnoaccess
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRinvid
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRnosupport
+ * ERRSRV/ERRaccess
+ */
+
+#include <smbsrv/smb_incl.h>
+/*ARGSUSED*/
+int
+smb_com_move(struct smb_request *sr)
+{
+ /* TODO move */
+ /* TODO move wildcards */
+ /* TODO move */
+
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
new file mode 100644
index 0000000000..844e84a889
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
@@ -0,0 +1,478 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Notes on the virtual circuit (VC) values in the SMB Negotiate
+ * response and SessionSetupAndx request.
+ *
+ * A virtual circuit (VC) represents a connection between a client and a
+ * server using a reliable, session oriented transport protocol, such as
+ * NetBIOS or TCP/IP. Originally, each SMB session was restricted to a
+ * single underlying transport connection, i.e. a single NetBIOS session,
+ * which limited performance for raw data transfers.
+ *
+ * The intention behind multiple VCs was to improve performance by
+ * allowing parallelism over each NetBIOS session. For example, raw data
+ * could be transmitted using a different VC from other types of SMB
+ * requests to remove the interleaving restriction while a raw transfer
+ * is in progress. So the MaxNumberVcs field was added to the negotiate
+ * response to make the number of VCs configurable and to allow servers
+ * to specify how many they were prepared to support per session
+ * connection. This turned out to be difficult to manage and, with
+ * technology improvements, it has become obsolete.
+ *
+ * Servers should set the MaxNumberVcs value in the Negotiate response
+ * to 1. Clients should probably ignore it. If a server receives a
+ * SessionSetupAndx with a VC value of 0, it should close all other
+ * VCs to that client. If it receives a non-zero VC, it should leave
+ * other VCs in tact.
+ *
+ */
+
+/*
+ * SMB: negotiate
+ *
+ * Client Request Description
+ * ============================ =======================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * struct {
+ * UCHAR BufferFormat; 0x02 -- Dialect
+ * UCHAR DialectName[]; ASCII null-terminated string
+ * } Dialects[];
+ *
+ * The Client sends a list of dialects that it can communicate with. The
+ * response is a selection of one of those dialects (numbered 0 through n)
+ * or -1 (hex FFFF) indicating that none of the dialects were acceptable.
+ * The negotiate message is binding on the virtual circuit and must be
+ * sent. One and only one negotiate message may be sent, subsequent
+ * negotiate requests will be rejected with an error response and no action
+ * will be taken.
+ *
+ * The protocol does not impose any particular structure to the dialect
+ * strings. Implementors of particular protocols may choose to include,
+ * for example, version numbers in the string.
+ *
+ * If the server does not understand any of the dialect strings, or if PC
+ * NETWORK PROGRAM 1.0 is the chosen dialect, the response format is
+ *
+ * Server Response Description
+ * ============================ =======================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT DialectIndex; Index of selected dialect
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * If the chosen dialect is greater than core up to and including
+ * LANMAN2.1, the protocol response format is
+ *
+ * Server Response Description
+ * ============================ =======================================
+ *
+ * UCHAR WordCount; Count of parameter words = 13
+ * USHORT DialectIndex; Index of selected dialect
+ * USHORT SecurityMode; Security mode:
+ * bit 0: 0 = share, 1 = user
+ * bit 1: 1 = use challenge/response
+ * authentication
+ * USHORT MaxBufferSize; Max transmit buffer size (>= 1024)
+ * USHORT MaxMpxCount; Max pending multiplexed requests
+ * USHORT MaxNumberVcs; Max VCs between client and server
+ * USHORT RawMode; Raw modes supported:
+ * bit 0: 1 = Read Raw supported
+ * bit 1: 1 = Write Raw supported
+ * ULONG SessionKey; Unique token identifying this session
+ * SMB_TIME ServerTime; Current time at server
+ * SMB_DATE ServerDate; Current date at server
+ * USHORT ServerTimeZone; Current time zone at server
+ * USHORT EncryptionKeyLength; MBZ if this is not LM2.1
+ * USHORT Reserved; MBZ
+ * USHORT ByteCount Count of data bytes
+ * UCHAR EncryptionKey[]; The challenge encryption key
+ * STRING PrimaryDomain[]; The server's primary domain
+ *
+ * MaxBufferSize is the size of the largest message which the client can
+ * legitimately send to the server
+ *
+ * If bit0 of the Flags field is set in the negotiate response, this
+ * indicates the server supports the SMB_COM_LOCK_AND_READ and
+ * SMB_COM_WRITE_AND_UNLOCK client requests.
+ *
+ * If the SecurityMode field indicates the server is running in user mode,
+ * the client must send appropriate SMB_COM_SESSION_SETUP_ANDX requests
+ * before the server will allow the client to access resources. If the
+ * SecurityMode fields indicates the client should use challenge/response
+ * authentication, the client should use the authentication mechanism
+ * specified in section 2.10.
+ *
+ * Clients should submit no more than MaxMpxCount distinct unanswered SMBs
+ * to the server when using multiplexed reads or writes (see sections 5.13
+ * and 5.25)
+ *
+ * Clients using the "MICROSOFT NETWORKS 1.03" dialect use a different
+ * form of raw reads than documented here, and servers are better off
+ * setting RawMode in this response to 0 for such sessions.
+ *
+ * If the negotiated dialect is "DOS LANMAN2.1" or "LANMAN2.1", then
+ * PrimaryDomain string should be included in this response.
+ *
+ * If the negotiated dialect is NT LM 0.12, the response format is
+ *
+ * Server Response Description
+ * ========================== =========================================
+ *
+ * UCHAR WordCount; Count of parameter words = 17
+ * USHORT DialectIndex; Index of selected dialect
+ * UCHAR SecurityMode; Security mode:
+ * bit 0: 0 = share, 1 = user
+ * bit 1: 1 = encrypt passwords
+ * USHORT MaxMpxCount; Max pending multiplexed requests
+ * USHORT MaxNumberVcs; Max VCs between client and server
+ * ULONG MaxBufferSize; Max transmit buffer size
+ * ULONG MaxRawSize; Maximum raw buffer size
+ * ULONG SessionKey; Unique token identifying this session
+ * ULONG Capabilities; Server capabilities
+ * ULONG SystemTimeLow; System (UTC) time of the server (low).
+ * ULONG SystemTimeHigh; System (UTC) time of the server (high).
+ * USHORT ServerTimeZone; Time zone of server (min from UTC)
+ * UCHAR EncryptionKeyLength; Length of encryption key.
+ * USHORT ByteCount; Count of data bytes
+ * UCHAR EncryptionKey[]; The challenge encryption key
+ * UCHAR OemDomainName[]; The name of the domain (in OEM chars)
+ *
+ * In addition to the definitions above, MaxBufferSize is the size of the
+ * largest message which the client can legitimately send to the server.
+ * If the client is using a connectionless protocol, MaxBufferSize must be
+ * set to the smaller of the server's internal buffer size and the amount
+ * of data which can be placed in a response packet.
+ *
+ * MaxRawSize specifies the maximum message size the server can send or
+ * receive for SMB_COM_WRITE_RAW or SMB_COM_READ_RAW.
+ *
+ * Connectionless clients must set Sid to 0 in the SMB request header.
+ *
+ * Capabilities allows the server to tell the client what it supports.
+ * The bit definitions defined in cifs.h. Bit 0x2000 used to be set in
+ * the negotiate response capabilities but it caused problems with
+ * Windows 2000. It is probably not valid, it doesn't appear in the
+ * CIFS spec.
+ *
+ * 4.1.1.1 Errors
+ *
+ * SUCCESS/SUCCESS
+ * ERRSRV/ERRerror
+ */
+#include <sys/types.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/socket.h>
+#include <sys/random.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_i18n.h>
+
+
+/*
+ * Maximum buffer size for DOS: chosen to be the same as NT.
+ * Do not change this value, DOS is very sensitive to it.
+ */
+#define SMB_DOS_MAXBUF 0x1104
+
+/*
+ * Maximum buffer size for NT: configurable based on the client environment.
+ * IR104720 Experiments with Windows 2000 indicate that we achieve better
+ * SmbWriteX performance with a buffer size of 64KB instead of the 37KB
+ * used with Windows NT4.0. Previous experiments with NT4.0 resulted in
+ * directory listing problems so this buffer size is configurable based
+ * on the end-user environment. When in doubt use 37KB.
+ */
+int smb_maxbufsize = SMB_NT_MAXBUF(37);
+
+/*
+ * The DOS TCP rcvbuf is set to 8700 because DOS 6.1 seems to have problems
+ * with other values. DOS 6.1 seems to depend on a window value of 8700 to
+ * send the next set of data. If we return a window value of 40KB, after
+ * sending 8700 bytes of data, it will start the next set of data from 40KB
+ * instead of 8.7k. Why 8.7k? We have no idea; it is the value that NT uses.
+ * September 2000.
+ *
+ * IR104720 Increased smb_nt_tcp_rcvbuf from 40KB to just under 1MB to allow
+ * for a larger TCP window sizei based on observations of Windows 2000 and
+ * performance testing. March 2003.
+ */
+uint32_t smb_dos_tcp_rcvbuf = 8700;
+uint32_t smb_nt_tcp_rcvbuf = 1048560; /* scale factor of 4 */
+
+static void smb_get_security_info(
+ struct smb_request *sr,
+ unsigned short *secmode,
+ unsigned char *key,
+ unsigned char *keylen,
+ uint32_t *sesskey);
+
+/*
+ * Function: int smb_com_negotiate(struct smb_request *)
+ */
+
+int
+smb_com_negotiate(struct smb_request *sr)
+{
+ int dialect = 0;
+ int this_dialect;
+ unsigned char keylen;
+ int sel_pos = -1;
+ int pos;
+ char key[32];
+ char *p;
+ timestruc_t time_val;
+ unsigned short secmode;
+ uint32_t sesskey;
+ uint32_t capabilities = 0;
+
+ unsigned short max_mpx_count;
+ WORD tz_correction;
+ char ipaddr_buf[INET_ADDRSTRLEN];
+
+ if (sr->session->s_state != SMB_SESSION_STATE_ESTABLISHED) {
+ /* The protocol has already been negotiated. */
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ for (pos = 0;
+ sr->smb_data.chain_offset < sr->smb_data.max_bytes;
+ pos++) {
+ if (smb_decode_mbc(&sr->smb_data, "%L", sr, &p) != 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ this_dialect = smb_xlate_dialect_str_to_cd(p);
+
+ if (this_dialect < 0)
+ continue;
+
+ if (dialect < this_dialect) {
+ dialect = this_dialect;
+ sel_pos = pos;
+ }
+ }
+ if (sel_pos < 0) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ smb_get_security_info(sr, &secmode, (unsigned char *)key,
+ &keylen, &sesskey);
+
+ (void) microtime(&time_val);
+
+ tz_correction = -(WORD)(smb_get_gmtoff() / 60); /* tz correct. (min) */
+
+ switch (dialect) {
+ case DIALECT_UNKNOWN:
+ case PC_NETWORK_PROGRAM_1_0: /* core */
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_dos_tcp_rcvbuf,
+ sizeof (smb_dos_tcp_rcvbuf));
+ smbsr_encode_result(sr, 1, 0, "bww", 1, sel_pos, 0);
+ break;
+
+ case Windows_for_Workgroups_3_1a:
+ case PCLAN1_0:
+ case MICROSOFT_NETWORKS_1_03:
+ case MICROSOFT_NETWORKS_3_0:
+ case LANMAN1_0:
+ case LM1_2X002:
+ case DOS_LM1_2X002:
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_dos_tcp_rcvbuf,
+ sizeof (smb_dos_tcp_rcvbuf));
+ sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
+ smbsr_encode_result(sr, 13, VAR_BCC,
+ "(wct) b" "(dix) w" "(sec) w" "(mbs) w"
+ "(mmc) w" "(mnv) w" "(raw) w" "(key) l"
+ "(tim/dat) Y" "(tz) w" "(ekl) w"
+ "(mbz) 2.""(bcc) w" "(key) #c",
+ 13, /* wct */
+ sel_pos, /* dialect index */
+ secmode, /* security mode */
+ SMB_DOS_MAXBUF, /* max buffer size */
+ 1, /* max MPX (temporary) */
+ 1, /* max VCs (temporary, ambiguous) */
+ 3, /* raw mode (s/b 3) */
+ sesskey, /* session key */
+ time_val.tv_sec, /* server time/date */
+ tz_correction, /* see smb_get_gmtoff */
+ (short)keylen, /* Encryption Key Length */
+ /* reserved field handled 2. */
+ VAR_BCC,
+ (int)keylen,
+ key); /* encryption key */
+ break;
+
+ case DOS_LANMAN2_1:
+ case LANMAN2_1:
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_dos_tcp_rcvbuf,
+ sizeof (smb_dos_tcp_rcvbuf));
+ sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK;
+ smbsr_encode_result(sr, 13, VAR_BCC,
+ "(wct) b" "(dix) w" "(sec) w" "(mbs) w"
+ "(mmc) w" "(mnv) w" "(raw) w" "(key) l"
+ "(tim/dat) Y" "(tz) w" "(ekl) w"
+ "(mbz) 2.""(bcc) w" "(key) #c" "(dom) s",
+ 13, /* wct */
+ sel_pos, /* dialect index */
+ secmode, /* security mode */
+ SMB_DOS_MAXBUF, /* max buffer size */
+ 1, /* max MPX (temporary) */
+ 1, /* max VCs (temporary, ambiguous) */
+ 3, /* raw mode (s/b 3) */
+ sesskey, /* session key */
+ time_val.tv_sec, /* server time/date */
+ tz_correction,
+ (short)keylen, /* Encryption Key Length */
+ /* reserved field handled 2. */
+ VAR_BCC,
+ (int)keylen,
+ key, /* encryption key */
+ smb_info.si.skc_resource_domain);
+ break;
+
+ case NT_LM_0_12:
+ (void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
+ (const void *)&smb_nt_tcp_rcvbuf,
+ sizeof (smb_nt_tcp_rcvbuf));
+ capabilities = CAP_LARGE_FILES
+ | CAP_NT_SMBS
+ | CAP_STATUS32
+ | CAP_NT_FIND
+ | CAP_RAW_MODE
+ | CAP_LEVEL_II_OPLOCKS
+ | CAP_LOCK_AND_READ
+ | CAP_RPC_REMOTE_APIS
+ | CAP_LARGE_READX;
+
+ /*
+ * UNICODE support is required to enable support for long
+ * share names and long file names and streams.
+ */
+
+ capabilities |= CAP_UNICODE;
+
+
+ /*
+ * Turn off Extended Security Negotiation
+ */
+ sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC;
+
+ /*
+ * Allow SMB signatures if security challenge response enabled
+ */
+ if ((secmode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
+ smb_info.si.skc_signing_enable) {
+ secmode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
+ if (smb_info.si.skc_signing_required)
+ secmode |=
+ NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
+
+ sr->session->secmode = secmode;
+ }
+
+ (void) inet_ntop(AF_INET, (char *)&sr->session->ipaddr,
+ ipaddr_buf, sizeof (ipaddr_buf));
+ /*LINTED E_ASSIGN_NARROW_CONV (uint16_t)*/
+ max_mpx_count = smb_info.si.skc_maxworkers;
+
+ smbsr_encode_result(sr, 17, VAR_BCC,
+ "(wct) b" "(dix) w" "(sec) b" "(mmc) w"
+ "(mnv) w" "(mbs) l" "(raw) l" "(key) l"
+ "(cap) l" "(tim) T" "(tz) w" "(ekl) b"
+ "(bcc) w" "(key) #c" "(dom) Z",
+ 17, /* wct */
+ sel_pos, /* dialect index */
+ secmode, /* security mode */
+ max_mpx_count, /* max MPX (temporary) */
+ 1, /* max VCs (temporary, ambiguous) */
+ (DWORD)smb_maxbufsize, /* max buffer size */
+ 0xFFFF, /* max raw size */
+ sesskey, /* session key */
+ capabilities,
+ &time_val, /* system time */
+ tz_correction,
+ keylen, /* Encryption Key Length */
+ VAR_BCC,
+ (int)keylen,
+ key, /* encryption key */
+ smb_info.si.skc_resource_domain);
+ break;
+
+ default:
+ /* Just to make sure. */
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Save the agreed dialect. Note that this value is also
+ * used to detect and reject attempts to re-negotiate.
+ */
+ sr->session->dialect = dialect;
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ return (SDRC_NORMAL_REPLY);
+}
+
+static void
+smb_get_security_info(
+ struct smb_request *sr,
+ unsigned short *secmode,
+ unsigned char *key,
+ unsigned char *keylen,
+ uint32_t *sesskey)
+{
+ uchar_t tmp_key[8];
+
+ (void) random_get_pseudo_bytes(tmp_key, 8);
+ bcopy(tmp_key, &sr->session->challenge_key, 8);
+ sr->session->challenge_len = 8;
+ *keylen = 8;
+ bcopy(tmp_key, key, 8);
+
+ sr->session->secmode = NEGOTIATE_SECURITY_CHALLENGE_RESPONSE|
+ NEGOTIATE_SECURITY_USER_LEVEL;
+
+ (void) random_get_pseudo_bytes(tmp_key, 4);
+ sr->session->sesskey = tmp_key[0] | tmp_key[1] << 8 |
+ tmp_key[2] << 16 | tmp_key[3] << 24;
+
+ *secmode = sr->session->secmode;
+ *sesskey = sr->session->sesskey;
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_net.c b/usr/src/uts/common/fs/smbsrv/smb_net.c
new file mode 100644
index 0000000000..0c8f0a9db3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_net.c
@@ -0,0 +1,281 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/cpuvar.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/time.h>
+#include <sys/varargs.h>
+#include <sys/modctl.h>
+#include <sys/pathname.h>
+#include <sys/fs/snode.h>
+#include <sys/fs/dv_node.h>
+#include <sys/vnode.h>
+#undef mem_free /* XXX Remove this after we convert everything to kmem_alloc */
+
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smb_kproto.h>
+
+/*
+ * SMB Network Socket API
+ *
+ * smb_socreate: Creates an socket based on domain/type.
+ * smb_soshutdown: Disconnect a socket created with smb_socreate
+ * smb_sodestroy: Release resources associated with a socket
+ * smb_sosend: Send the contents of a buffer on a socket
+ * smb_sorecv: Receive data into a buffer from a socket
+ * smb_iov_sosend: Send the contents of an iovec on a socket
+ * smb_iov_sorecv: Receive data into an iovec from a socket
+ */
+
+struct sonode *
+smb_socreate(int domain, int type, int protocol)
+{
+ vnode_t *dvp = NULL;
+ vnode_t *vp = NULL;
+ struct snode *csp = NULL;
+ int err = 0;
+ major_t maj;
+
+ if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) {
+
+ /*
+ * solookup calls sogetvp if the vp is not found in the cache.
+ * Since the call to sogetvp is hardwired to use USERSPACE
+ * and declared static we'll do the work here instead.
+ */
+ err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp",
+ UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
+ if (err)
+ return (NULL);
+
+ /* Check that it is the correct vnode */
+ if (vp->v_type != VCHR) {
+ VN_RELE(vp);
+ return (NULL);
+ }
+
+ csp = VTOS(VTOS(vp)->s_commonvp);
+ if (!(csp->s_flag & SDIPSET)) {
+ char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+ err = ddi_dev_pathname(vp->v_rdev, S_IFCHR,
+ pathname);
+ if (err == 0) {
+ err = devfs_lookupname(pathname, NULLVPP,
+ &dvp);
+ }
+ VN_RELE(vp);
+ kmem_free(pathname, MAXPATHLEN);
+ if (err != 0) {
+ return (NULL);
+ }
+ vp = dvp;
+ }
+
+ maj = getmajor(vp->v_rdev);
+ if (!STREAMSTAB(maj)) {
+ VN_RELE(vp);
+ return (NULL);
+ }
+ }
+
+ return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err));
+}
+
+/*
+ * smb_soshutdown will disconnect the socket and prevent subsequent PDU
+ * reception and transmission. The sonode still exists but its state
+ * gets modified to indicate it is no longer connected. Calls to
+ * smb_sorecv/smb_iov_sorecv will return so smb_soshutdown can be used
+ * regain control of a thread stuck in smb_sorecv.
+ */
+void
+smb_soshutdown(struct sonode *so)
+{
+ (void) soshutdown(so, SHUT_RDWR);
+}
+
+/*
+ * smb_sodestroy releases all resources associated with a socket previously
+ * created with smb_socreate. The socket must be shutdown using smb_soshutdown
+ * before the socket is destroyed with smb_sodestroy, otherwise undefined
+ * behavior will result.
+ */
+void
+smb_sodestroy(struct sonode *so)
+{
+ vnode_t *vp = SOTOV(so);
+
+ (void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL);
+ VN_RELE(vp);
+}
+
+int
+smb_sosend(struct sonode *so, void *msg, size_t len)
+{
+ iovec_t iov;
+ int err;
+
+ ASSERT(so != NULL);
+ ASSERT(len != 0);
+
+ /*
+ * Fill in iovec and receive data
+ */
+ iov.iov_base = msg;
+ iov.iov_len = len;
+
+ if ((err = smb_iov_sosend(so, &iov, 1, len)) != 0) {
+ return (err);
+ }
+
+ /* Successful receive */
+ return (0);
+}
+
+int
+smb_sorecv(struct sonode *so, void *msg, size_t len)
+{
+ iovec_t iov;
+ int err;
+
+ ASSERT(so != NULL);
+ ASSERT(len != 0);
+
+ /*
+ * Fill in iovec and receive data
+ */
+ iov.iov_base = msg;
+ iov.iov_len = len;
+
+ if ((err = smb_iov_sorecv(so, &iov, 1, len)) != 0) {
+ return (err);
+ }
+
+ /* Successful receive */
+ return (0);
+}
+
+/*
+ * smb_iov_sosend - Sends an iovec on a connection.
+ *
+ * This function puts the data provided on the wire by calling sosendmsg.
+ * It will return only when all the data has been sent or if an error
+ * occurs.
+ *
+ * Returns 0 for success, the socket errno value if sosendmsg fails, and
+ * -1 if sosendmsg returns success but uio_resid != 0
+ */
+int
+smb_iov_sosend(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len)
+{
+ struct msghdr msg;
+ struct uio uio;
+ int error;
+
+ ASSERT(iop != NULL);
+
+ /* Initialization of the message header. */
+ bzero(&msg, sizeof (msg));
+ msg.msg_iov = iop;
+ msg.msg_flags = MSG_WAITALL;
+ msg.msg_iovlen = iovlen;
+
+ /* Initialization of the uio structure. */
+ bzero(&uio, sizeof (uio));
+ uio.uio_iov = iop;
+ uio.uio_iovcnt = iovlen;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_resid = total_len;
+
+ if ((error = sosendmsg(so, &msg, &uio)) == 0) {
+ /* Data sent */
+ if (uio.uio_resid == 0) {
+ /* All data sent. Success. */
+ return (0);
+ } else {
+ /* Not all data was sent. Failure */
+ return (-1);
+ }
+ }
+
+ /* Send failed */
+ return (error);
+}
+
+/*
+ * smb_iov_sorecv - Receives an iovec from a connection
+ *
+ * This function gets the data asked for from the socket. It will return
+ * only when all the requested data has been retrieved or if an error
+ * occurs.
+ *
+ * Returns 0 for success, the socket errno value if sorecvmsg fails, and
+ * -1 if sorecvmsg returns success but uio_resid != 0
+ */
+int
+smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen, size_t total_len)
+{
+ struct msghdr msg;
+ struct uio uio;
+ int error;
+
+ ASSERT(iop != NULL);
+
+ /* Initialization of the message header. */
+ bzero(&msg, sizeof (msg));
+ msg.msg_iov = iop;
+ msg.msg_flags = MSG_WAITALL;
+ msg.msg_iovlen = iovlen;
+
+ /* Initialization of the uio structure. */
+ bzero(&uio, sizeof (uio));
+ uio.uio_iov = iop;
+ uio.uio_iovcnt = iovlen;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_resid = total_len;
+
+ if ((error = sorecvmsg(so, &msg, &uio)) == 0) {
+ /* Received data */
+ if (uio.uio_resid == 0) {
+ /* All requested data received. Success */
+ return (0);
+ } else {
+ /* Not all data was sent. Failure */
+ return (-1);
+ }
+ }
+
+ /* Receive failed */
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c
new file mode 100644
index 0000000000..5ea8c5f1c3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c
@@ -0,0 +1,770 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB Node State Machine
+ * ----------------------
+ *
+ * +----------------------------+ T0
+ * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation
+ * +----------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-----------------------------+ T2
+ * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free
+ * +-----------------------------+
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_node_lookup(). If the node looked for is
+ * not found in the has table a new node is created. The reference count is
+ * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_node_release(). If the reference count
+ * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more
+ * reference count will be given out for that node.
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_node_release(). The structure is deleted.
+ *
+ * Comments
+ * --------
+ *
+ * The reason the smb node has 2 states is the following synchronization
+ * rule:
+ *
+ * There's a mutex embedded in the node used to protect its fields and
+ * there's a lock embedded in the bucket of the hash table the node belongs
+ * to. To increment or to decrement the reference count the mutex must be
+ * entered. To insert the node into the bucket and to remove it from the
+ * bucket the lock must be entered in RW_WRITER mode. When both (mutex and
+ * lock) have to be entered, the lock has always to be entered first then
+ * the mutex. This prevents a deadlock between smb_node_lookup() and
+ * smb_node_release() from occurring. However, in smb_node_release() when the
+ * reference count drops to zero and triggers the deletion of the node, the
+ * mutex has to be released before entering the lock of the bucket (to
+ * remove the node). This creates a window during which the node that is
+ * about to be freed could be given out by smb_node_lookup(). To close that
+ * window the node is moved to the state SMB_NODE_STATE_DESTROYING before
+ * releasing the mutex. That way, even if smb_node_lookup() finds it, the
+ * state will indicate that the node should be treated as non existent (of
+ * course the state of the node should be tested/updated under the
+ * protection of the mutex).
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <sys/pathname.h>
+#include <sys/sdt.h>
+
+uint32_t smb_is_executable(char *path);
+static void smb_node_delete_on_close(smb_node_t *node);
+
+uint32_t smb_node_hit = 0;
+uint32_t smb_node_miss = 0;
+uint32_t smb_node_alloc = 0;
+uint32_t smb_node_free = 0;
+
+#define VALIDATE_DIR_NODE(_dir_, _node_) \
+ ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
+ ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
+ ASSERT((_dir_)->dir_snode != (_node_));
+
+/*
+ * smb_node_lookup()
+ *
+ * NOTE: This routine should only be called by the file system interface layer,
+ * and not by SMB.
+ *
+ * smb_node_lookup() is called upon successful lookup, mkdir, and create
+ * (for both non-streams and streams). In each of these cases, a held vnode is
+ * passed into this routine. If an smb_node already exists for this vnode,
+ * the vp is released. Otherwise, a new smb_node will be created and the
+ * reference will be held until the refcnt on the node goes to 0 (see
+ * smb_node_release()).
+ *
+ * A reference is taken on the smb_node whether found in the hash table
+ * or newly created.
+ *
+ * If an smb_node needs to be created, a reference is also taken on the
+ * dir_snode (if passed in).
+ *
+ * See smb_node_release() for details on the release of these references.
+ */
+
+/*ARGSUSED*/
+smb_node_t *
+smb_node_lookup(
+ struct smb_request *sr,
+ struct open_param *op,
+ cred_t *cred,
+ vnode_t *vp,
+ char *od_name,
+ smb_node_t *dir_snode,
+ smb_node_t *unnamed_node,
+ smb_attr_t *attr)
+{
+ smb_llist_t *node_hdr;
+ smb_node_t *node;
+ uint32_t hashkey = 0;
+ fs_desc_t fsd;
+ int error;
+ krw_t lock_mode;
+ caller_context_t ct;
+ vnode_t *unnamed_vp = NULL;
+
+ /*
+ * smb_vop_getattr() is called here instead of smb_fsop_getattr(),
+ * because the node may not yet exist. We also do not want to call
+ * it with the list lock held.
+ */
+
+ if (unnamed_node)
+ unnamed_vp = unnamed_node->vp;
+
+ /*
+ * This getattr is performed on behalf of the server
+ * that's why kcred is used not the user's cred
+ */
+ smb_get_caller_context(sr, &ct);
+ attr->sa_mask = SMB_AT_ALL;
+ error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred, &ct);
+ if (error)
+ return (NULL);
+
+ if (sr) {
+ if (sr->tid_tree) {
+ /*
+ * The fsd for a file is that of the tree, even
+ * if the file resides in a different mountpoint
+ * under the share.
+ */
+ fsd = sr->tid_tree->t_fsd;
+ } else {
+ /*
+ * This should be getting executed only for the
+ * tree's root smb_node.
+ */
+ fsd = vp->v_vfsp->vfs_fsid;
+ }
+ } else {
+ fsd = vp->v_vfsp->vfs_fsid;
+ }
+
+ hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid;
+ hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
+ node_hdr = &smb_info.node_hash_table[(hashkey & SMBND_HASH_MASK)];
+ lock_mode = RW_READER;
+
+ smb_llist_enter(node_hdr, lock_mode);
+ for (;;) {
+ node = list_head(&node_hdr->ll_list);
+ while (node) {
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_hash_bucket == node_hdr);
+ if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
+ smb_rwx_xenter(&node->n_lock);
+ DTRACE_PROBE1(smb_node_lookup_hit,
+ smb_node_t *, node);
+ switch (node->n_state) {
+ case SMB_NODE_STATE_AVAILABLE:
+ /* The node was found. */
+ node->n_refcnt++;
+ if ((node->dir_snode == NULL) &&
+ (dir_snode != NULL) &&
+ (strcmp(od_name, "..") != 0) &&
+ (strcmp(od_name, ".") != 0)) {
+ VALIDATE_DIR_NODE(dir_snode,
+ node);
+ node->dir_snode = dir_snode;
+ smb_node_ref(dir_snode);
+ }
+ node->attr = *attr;
+
+ smb_audit_node(node);
+ smb_rwx_xexit(&node->n_lock);
+ smb_llist_exit(node_hdr);
+ VN_RELE(vp);
+ return (node);
+
+ case SMB_NODE_STATE_DESTROYING:
+ /*
+ * Although the node exists it is about
+ * to be destroyed. We act as it hasn't
+ * been found.
+ */
+ smb_rwx_xexit(&node->n_lock);
+ break;
+ default:
+ /*
+ * Although the node exists it is in an
+ * unknown state. We act as it hasn't
+ * been found.
+ */
+ ASSERT(0);
+ smb_rwx_xexit(&node->n_lock);
+ break;
+ }
+ }
+ node = smb_llist_next(node_hdr, node);
+ }
+ if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) {
+ lock_mode = RW_WRITER;
+ continue;
+ }
+ break;
+ }
+ node = kmem_cache_alloc(smb_info.si_cache_node, KM_SLEEP);
+ smb_node_alloc++;
+
+ bzero(node, sizeof (smb_node_t));
+
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ node->n_hash_bucket = node_hdr;
+
+ if (fsd_chkcap(&fsd, FSOLF_READONLY) > 0) {
+ node->flags |= NODE_READ_ONLY;
+ }
+
+ smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
+ offsetof(smb_ofile_t, f_nnd));
+ smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_lnd));
+ node->n_hashkey = hashkey;
+ node->n_refcnt = 1;
+
+ if (sr) {
+ node->n_orig_session_id = sr->session->s_kid;
+ node->n_orig_uid = crgetuid(sr->user_cr);
+ }
+
+ node->vp = vp;
+
+ ASSERT(od_name);
+ (void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
+ node->tree_fsd = fsd;
+
+ if (op)
+ node->flags |= smb_is_executable(op->fqi.last_comp);
+
+ if (dir_snode) {
+ smb_node_ref(dir_snode);
+ node->dir_snode = dir_snode;
+ ASSERT(dir_snode->dir_snode != node);
+ ASSERT((dir_snode->vp->v_xattrdir) ||
+ (dir_snode->vp->v_type == VDIR));
+ }
+
+ if (unnamed_node) {
+ smb_node_ref(unnamed_node);
+ node->unnamed_stream_node = unnamed_node;
+ }
+
+ node->attr = *attr;
+ node->flags |= NODE_FLAGS_ATTR_VALID;
+ node->n_size = node->attr.sa_vattr.va_size;
+
+ smb_rwx_init(&node->n_lock);
+ node->n_magic = SMB_NODE_MAGIC;
+ smb_audit_buf_node_create(node);
+
+ DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
+ smb_audit_node(node);
+ smb_llist_insert_head(node_hdr, node);
+ smb_llist_exit(node_hdr);
+ return (node);
+}
+
+/*
+ * smb_stream_node_lookup()
+ *
+ * Note: stream_name (the name that will be stored in the "od_name" field
+ * of a stream's smb_node) is the same as the on-disk name for the stream
+ * except that it does not have SMB_STREAM_PREFIX prepended.
+ */
+
+smb_node_t *
+smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
+ vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
+{
+ smb_node_t *xattrdir_node;
+ smb_node_t *snode;
+ smb_attr_t tmp_attr;
+
+ xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
+ fnode, NULL, &tmp_attr);
+
+ if (xattrdir_node == NULL)
+ return (NULL);
+
+ snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
+ fnode, ret_attr);
+
+ /*
+ * The following VN_HOLD is necessary because the caller will VN_RELE
+ * xattrdirvp in the case of an error. (xattrdir_node has the original
+ * hold on the vnode, which the smb_node_release() call below will
+ * release.)
+ */
+ if (snode == NULL) {
+ VN_HOLD(xattrdirvp);
+ }
+ (void) smb_node_release(xattrdir_node);
+ return (snode);
+}
+
+
+/*
+ * This function should be called whenever a reference is needed on an
+ * smb_node pointer. The copy of an smb_node pointer from one non-local
+ * data structure to another requires a reference to be taken on the smb_node
+ * (unless the usage is localized). Each data structure deallocation routine
+ * will call smb_node_release() on its smb_node pointers.
+ *
+ * In general, an smb_node pointer residing in a structure should never be
+ * stale. A node pointer may be NULL, however, and care should be taken
+ * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid.
+ * Care also needs to be taken with respect to racing deallocations of a
+ * structure.
+ */
+
+void
+smb_node_ref(smb_node_t *node)
+{
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+
+ smb_rwx_xenter(&node->n_lock);
+ node->n_refcnt++;
+ ASSERT(node->n_refcnt);
+ DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
+ smb_audit_node(node);
+ smb_rwx_xexit(&node->n_lock);
+}
+
+/*
+ * smb_node_lookup() takes a hold on an smb_node, whether found in the
+ * hash table or newly created. This hold is expected to be released
+ * in the following manner.
+ *
+ * smb_node_lookup() takes an address of an smb_node pointer. This should
+ * be getting passed down via a lookup (whether path name or component), mkdir,
+ * create. If the original smb_node pointer resides in a data structure, then
+ * the deallocation routine for the data structure is responsible for calling
+ * smb_node_release() on the smb_node pointer. Alternatively,
+ * smb_node_release() can be called as soon as the smb_node pointer is no longer
+ * needed. In this case, callers are responsible for setting an embedded
+ * pointer to NULL if it is known that the last reference is being released.
+ *
+ * If the passed-in address of the smb_node pointer belongs to a local variable,
+ * then the caller with the local variable should call smb_node_release()
+ * directly.
+ *
+ * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
+ * as smb_node_lookup() takes a hold on dir_snode.
+ */
+
+void
+smb_node_release(smb_node_t *node)
+{
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+
+ smb_rwx_xenter(&node->n_lock);
+ ASSERT(node->n_refcnt);
+ DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
+ if (--node->n_refcnt == 0) {
+ switch (node->n_state) {
+
+ case SMB_NODE_STATE_AVAILABLE:
+ node->n_state = SMB_NODE_STATE_DESTROYING;
+ smb_rwx_xexit(&node->n_lock);
+
+ smb_llist_enter(node->n_hash_bucket, RW_WRITER);
+ smb_llist_remove(node->n_hash_bucket, node);
+ smb_llist_exit(node->n_hash_bucket);
+
+ /*
+ * Check if the file was deleted
+ */
+ smb_node_delete_on_close(node);
+ node->n_magic = (uint32_t)~SMB_NODE_MAGIC;
+
+ /* These lists should be empty. */
+ smb_llist_destructor(&node->n_ofile_list);
+ smb_llist_destructor(&node->n_lock_list);
+
+ if (node->dir_snode) {
+ ASSERT(node->dir_snode->n_magic ==
+ SMB_NODE_MAGIC);
+ smb_node_release(node->dir_snode);
+ }
+
+ if (node->unnamed_stream_node) {
+ ASSERT(node->unnamed_stream_node->n_magic ==
+ SMB_NODE_MAGIC);
+ smb_node_release(node->unnamed_stream_node);
+ }
+
+ ASSERT(node->vp);
+ VN_RELE(node->vp);
+
+ smb_audit_buf_node_destroy(node);
+ smb_rwx_destroy(&node->n_lock);
+ kmem_cache_free(smb_info.si_cache_node, node);
+ ++smb_node_free;
+ return;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ }
+ smb_audit_node(node);
+ smb_rwx_xexit(&node->n_lock);
+}
+
+static void
+smb_node_delete_on_close(smb_node_t *node)
+{
+ smb_node_t *d_snode;
+ int rc = 0;
+
+ d_snode = node->dir_snode;
+ if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
+
+ node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
+ ASSERT(node->od_name != NULL);
+ if (node->attr.sa_vattr.va_type == VDIR)
+ rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
+ d_snode, node->od_name, 1);
+ else
+ rc = smb_fsop_remove(0, node->delete_on_close_cred,
+ d_snode, node->od_name, 1);
+ smb_cred_rele(node->delete_on_close_cred);
+ }
+ if (rc != 0)
+ cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n",
+ node->od_name, rc);
+ DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node);
+}
+
+/*
+ * smb_node_rename()
+ *
+ */
+int
+smb_node_rename(
+ smb_node_t *from_dir_snode,
+ smb_node_t *ret_snode,
+ smb_node_t *to_dir_snode,
+ char *to_name)
+{
+ ASSERT(from_dir_snode);
+ ASSERT(to_dir_snode);
+ ASSERT(ret_snode);
+ ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
+ ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
+ ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE);
+
+ smb_node_ref(to_dir_snode);
+ smb_rwx_xenter(&ret_snode->n_lock);
+ ret_snode->dir_snode = to_dir_snode;
+ smb_rwx_xexit(&ret_snode->n_lock);
+ ASSERT(to_dir_snode->dir_snode != ret_snode);
+ ASSERT((to_dir_snode->vp->v_xattrdir) ||
+ (to_dir_snode->vp->v_type == VDIR));
+ smb_node_release(from_dir_snode);
+
+ (void) strcpy(ret_snode->od_name, to_name);
+
+ /*
+ * XXX Need to update attributes?
+ */
+
+ return (0);
+}
+
+int
+smb_node_root_init()
+{
+ smb_attr_t va;
+
+ /*
+ * Take an explicit hold on rootdir. This goes with the
+ * corresponding release in smb_node_root_fini()/smb_node_release().
+ */
+
+ VN_HOLD(rootdir);
+
+ if ((smb_info.si_root_smb_node = smb_node_lookup(NULL, NULL, kcred,
+ rootdir, ROOTVOL, NULL, NULL, &va)) == NULL)
+ return (-1);
+ else
+ return (0);
+}
+
+void
+smb_node_root_fini()
+{
+ if (smb_info.si_root_smb_node) {
+ smb_node_release(smb_info.si_root_smb_node);
+ smb_info.si_root_smb_node = NULL;
+ }
+}
+
+/*
+ * smb_node_get_size
+ */
+uint64_t
+smb_node_get_size(
+ smb_node_t *node,
+ smb_attr_t *attr)
+{
+ uint64_t size;
+
+ if (attr->sa_vattr.va_type == VDIR)
+ return (0);
+
+ smb_rwx_xenter(&node->n_lock);
+ if (node && (node->flags & NODE_FLAGS_SET_SIZE))
+ size = node->n_size;
+ else
+ size = attr->sa_vattr.va_size;
+ smb_rwx_xexit(&node->n_lock);
+ return (size);
+}
+
+static int
+timeval_cmp(timestruc_t *a, timestruc_t *b)
+{
+ if (a->tv_sec < b->tv_sec)
+ return (-1);
+ if (a->tv_sec > b->tv_sec)
+ return (1);
+ /* Seconds are equal compare tv_nsec */
+ if (a->tv_nsec < b->tv_nsec)
+ return (-1);
+ return (a->tv_nsec > b->tv_nsec);
+}
+
+/*
+ * smb_node_set_time
+ *
+ * This function will update the time stored in the node and
+ * set the appropriate flags. If there is nothing to update
+ * or the node is readonly, the function would return without
+ * any updates. The update is only in the node level and the
+ * attribute in the file system will be updated when client
+ * close the file.
+ */
+void
+smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
+ struct timestruc *mtime, struct timestruc *atime,
+ struct timestruc *ctime, unsigned int what)
+{
+ smb_rwx_xenter(&node->n_lock);
+ if (node->flags & NODE_READ_ONLY || what == 0) {
+ smb_rwx_xexit(&node->n_lock);
+ return;
+ }
+
+ if ((what & SMB_AT_CRTIME && crtime == 0) ||
+ (what & SMB_AT_MTIME && mtime == 0) ||
+ (what & SMB_AT_ATIME && atime == 0) ||
+ (what & SMB_AT_CTIME && ctime == 0)) {
+ smb_rwx_xexit(&node->n_lock);
+ return;
+ }
+
+ if ((what & SMB_AT_CRTIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
+ crtime) != 0) {
+ node->what |= SMB_AT_CRTIME;
+ node->attr.sa_crtime = *((timestruc_t *)crtime);
+ }
+
+ if ((what & SMB_AT_MTIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
+ mtime) != 0) {
+ node->what |= SMB_AT_MTIME;
+ node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
+ }
+
+ if ((what & SMB_AT_ATIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
+ atime) != 0) {
+ node->what |= SMB_AT_ATIME;
+ node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
+ }
+
+ /*
+ * The ctime handling is trickier. It has three scenarios.
+ * 1. Only ctime need to be set and it is the same as the ctime
+ * stored in the node. (update not necessary)
+ * 2. The ctime is the same as the ctime stored in the node but
+ * is not the only time need to be set. (update required)
+ * 3. The ctime need to be set and is not the same as the ctime
+ * stored in the node. (update required)
+ * Unlike other time setting, the ctime needs to be set even when
+ * it is the same as the ctime in the node if there are other time
+ * needs to be set (#2). This will ensure the ctime not being
+ * updated when other times are being updated in the file system.
+ *
+ * Retained file rules:
+ *
+ * 1. Don't add SMB_AT_CTIME to node->what by default because the
+ * request will be rejected by filesystem
+ * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
+ * any request for changing ctime on these files should have
+ * been already rejected
+ */
+ node->what |= SMB_AT_CTIME;
+ if (what & SMB_AT_CTIME) {
+ if ((what == SMB_AT_CTIME) &&
+ timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
+ ctime) == 0) {
+ node->what &= ~SMB_AT_CTIME;
+ } else {
+ gethrestime(&node->attr.sa_vattr.va_ctime);
+ }
+ } else {
+ gethrestime(&node->attr.sa_vattr.va_ctime);
+ }
+ smb_rwx_xexit(&node->n_lock);
+}
+
+
+timestruc_t *
+smb_node_get_crtime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_crtime);
+}
+
+timestruc_t *
+smb_node_get_atime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
+}
+
+timestruc_t *
+smb_node_get_ctime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
+}
+
+timestruc_t *
+smb_node_get_mtime(smb_node_t *node)
+{
+ return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
+}
+
+/*
+ * smb_node_set_dosattr
+ *
+ * Parse the specified DOS attributes and, if they have been modified,
+ * update the node cache. This call should be followed by a
+ * smb_sync_fsattr() call to write the attribute changes to filesystem.
+ */
+void
+smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr)
+{
+ unsigned int mode; /* New mode */
+
+ mode = 0;
+
+ /* Handle the archive bit */
+ if (dos_attr & SMB_FA_ARCHIVE)
+ mode |= FILE_ATTRIBUTE_ARCHIVE;
+
+ /* Handle the readonly bit */
+ if (dos_attr & SMB_FA_READONLY)
+ mode |= FILE_ATTRIBUTE_READONLY;
+
+ /* Handle the hidden bit */
+ if (dos_attr & SMB_FA_HIDDEN)
+ mode |= FILE_ATTRIBUTE_HIDDEN;
+
+ /* Handle the system bit */
+ if (dos_attr & SMB_FA_SYSTEM)
+ mode |= FILE_ATTRIBUTE_SYSTEM;
+
+ smb_rwx_xenter(&node->n_lock);
+ if (node->attr.sa_dosattr != mode) {
+ node->attr.sa_dosattr = mode;
+ node->what |= SMB_AT_DOSATTR;
+ }
+ smb_rwx_xexit(&node->n_lock);
+}
+
+/*
+ * smb_node_get_dosattr
+ *
+ * This function will get dos attribute using the node.
+ */
+uint32_t
+smb_node_get_dosattr(smb_node_t *node)
+{
+ return (smb_mode_to_dos_attributes(&node->attr));
+}
+
+int
+smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
+{
+ int rc = -1;
+
+ smb_rwx_xenter(&node->n_lock);
+ if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
+ !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
+ crhold(cr);
+ node->delete_on_close_cred = cr;
+ node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
+ rc = 0;
+ }
+ smb_rwx_xexit(&node->n_lock);
+ return (rc);
+}
+
+void
+smb_node_reset_delete_on_close(smb_node_t *node)
+{
+ smb_rwx_xenter(&node->n_lock);
+ if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
+ node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
+ crfree(node->delete_on_close_cred);
+ node->delete_on_close_cred = NULL;
+ }
+ smb_rwx_xexit(&node->n_lock);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c
new file mode 100644
index 0000000000..79334395f0
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c
@@ -0,0 +1,77 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: nt_cancel
+ *
+ * This SMB allows a client to cancel a request currently pending at the
+ * server.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; No words are sent (== 0)
+ * USHORT ByteCount; No bytes (==0)
+ *
+ * The Sid, Uid, Pid, Tid, and Mid fields of the SMB are used to locate an
+ * pending server request from this session. If a pending request is
+ * found, it is "hurried along" which may result in success or failure of
+ * the original request. No other response is generated for this SMB.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_nt_cancel(struct smb_request *sr)
+{
+ struct smb_request *req;
+ struct smb_session *session;
+
+ session = sr->session;
+
+ smb_slist_enter(&session->s_req_list);
+ req = smb_slist_head(&session->s_req_list);
+ while (req) {
+ ASSERT(req->sr_magic == SMB_REQ_MAGIC);
+ if ((req != sr) &&
+ (req->smb_sid == sr->smb_sid) &&
+ (req->smb_uid == sr->smb_uid) &&
+ (req->smb_pid == sr->smb_pid) &&
+ (req->smb_tid == sr->smb_tid) &&
+ (req->smb_mid == sr->smb_mid)) {
+ smb_request_cancel(req);
+ }
+ req = smb_slist_next(&session->s_req_list, req);
+ }
+ smb_slist_exit(&session->s_req_list);
+
+ /* Now, search the notify change queue to find the request */
+
+ smb_reply_specific_cancel_request(sr);
+
+ return (SDRC_NO_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
new file mode 100644
index 0000000000..36a3df5992
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -0,0 +1,373 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This command is used to create or open a file or directory.
+ */
+
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_vops.h>
+
+/*
+ * smb_com_nt_create_andx
+ *
+ * This command is used to create or open a file or directory.
+ *
+ * Client Request Description
+ * ================================= ==================================
+ *
+ * UCHAR WordCount; Count of parameter words = 24
+ * UCHAR AndXCommand; Secondary command; 0xFF = None
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * UCHAR Reserved; Reserved (must be 0)
+ * USHORT NameLength; Length of Name[] in bytes
+ * ULONG Flags; Create bit set:
+ * 0x02 - Request an oplock
+ * 0x04 - Request a batch oplock
+ * 0x08 - Target of open must be
+ * directory
+ * ULONG RootDirectoryFid; If non-zero, open is relative to
+ * this directory
+ * ACCESS_MASK DesiredAccess; access desired
+ * LARGE_INTEGER AllocationSize; Initial allocation size
+ * ULONG ExtFileAttributes; File attributes
+ * ULONG ShareAccess; Type of share access
+ * ULONG CreateDisposition; Action to take if file exists or
+ * not
+ * ULONG CreateOptions; Options to use if creating a file
+ * ULONG ImpersonationLevel; Security QOS information
+ * UCHAR SecurityFlags; Security tracking mode flags:
+ * 0x1 - SECURITY_CONTEXT_TRACKING
+ * 0x2 - SECURITY_EFFECTIVE_ONLY
+ * USHORT ByteCount; Length of byte parameters
+ * STRING Name[]; File to open or create
+ *
+ * The DesiredAccess parameter is specified in section 3.7 on Access Mask
+ * Encoding.
+ *
+ * If no value is specified, it still allows an application to query
+ * attributes without actually accessing the file.
+ *
+ * The ExtFIleAttributes parameter specifies the file attributes and flags
+ * for the file. The parameter's value is the sum of allowed attributes and
+ * flags defined in section 3.11 on Extended File Attribute Encoding
+ *
+ * The ShareAccess field Specifies how this file can be shared. This
+ * parameter must be some combination of the following values:
+ *
+ * Name Value Meaning
+ * 0 Prevents the file from being shared.
+ * FILE_SHARE_READ 0x00000001 Other open operations can be performed on
+ * the file for read access.
+ * FILE_SHARE_WRITE 0x00000002 Other open operations can be performed on
+ * the file for write access.
+ * FILE_SHARE_DELETE 0x00000004 Other open operations can be performed on
+ * the file for delete access.
+ *
+ * The CreateDisposition parameter can contain one of the following values:
+ *
+ * CREATE_NEW Creates a new file. The function fails if the
+ * specified file already exists.
+ * CREATE_ALWAYS Creates a new file. The function overwrites the file
+ * if it exists.
+ * OPEN_EXISTING Opens the file. The function fails if the file does
+ * not exist.
+ * OPEN_ALWAYS Opens the file, if it exists. If the file does not
+ * exist, act like CREATE_NEW.
+ * TRUNCATE_EXISTING Opens the file. Once opened, the file is truncated so
+ * that its size is zero bytes. The calling process must
+ * open the file with at least GENERIC_WRITE access. The
+ * function fails if the file does not exist.
+ *
+ * The ImpersonationLevel parameter can contain one or more of the
+ * following values:
+ *
+ * SECURITY_ANONYMOUS Specifies to impersonate the client at the
+ * Anonymous impersonation level.
+ * SECURITY_IDENTIFICATION Specifies to impersonate the client at the
+ * Identification impersonation level.
+ * SECURITY_IMPERSONATION Specifies to impersonate the client at the
+ * Impersonation impersonation level.
+ * SECURITY_DELEGATION Specifies to impersonate the client at the
+ * Delegation impersonation level.
+ *
+ * The SecurityFlags parameter can have either of the following two flags
+ * set:
+ *
+ * SECURITY_CONTEXT_TRACKING Specifies that the security tracking mode is
+ * dynamic. If this flag is not specified,
+ * Security Tracking Mode is static.
+ * SECURITY_EFFECTIVE_ONLY Specifies that only the enabled aspects of
+ * the client's security context are available
+ * to the server. If you do not specify this
+ * flag, all aspects of the client's security
+ * context are available. This flag allows the
+ * client to limit the groups and privileges
+ * that a server can use while impersonating the
+ * client.
+ *
+ * The response is as follows:
+ *
+ * Server Response Description
+ * ================================= ==================================
+ *
+ * UCHAR WordCount; Count of parameter words = 26
+ * UCHAR AndXCommand; Secondary 0xFF = None
+ * command;
+ * UCHAR AndXReserved; MBZ
+ * USHORT AndXOffset; Offset to next command WordCount
+ * UCHAR OplockLevel; The oplock level granted
+ * 0 - No oplock granted
+ * 1 - Exclusive oplock granted
+ * 2 - Batch oplock granted
+ * 3 - Level II oplock granted
+ * USHORT Fid; The file ID
+ * ULONG CreateAction; The action taken
+ * TIME CreationTime; The time the file was created
+ * TIME LastAccessTime; The time the file was accessed
+ * TIME LastWriteTime; The time the file was last written
+ * TIME ChangeTime; The time the file was last changed
+ * ULONG ExtFileAttributes; The file attributes
+ * LARGE_INTEGER AllocationSize; The number of bytes allocated
+ * LARGE_INTEGER EndOfFile; The end of file offset
+ * USHORT FileType;
+ * USHORT DeviceState; state of IPC device (e.g. pipe)
+ * BOOLEAN Directory; TRUE if this is a directory
+ * USHORT ByteCount; = 0
+ *
+ * The following SMBs may follow SMB_COM_NT_CREATE_ANDX:
+ *
+ * SMB_COM_READ SMB_COM_READ_ANDX
+ * SMB_COM_IOCTL
+ */
+int
+smb_com_nt_create_andx(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ unsigned char OplockLevel;
+ unsigned char DirFlag;
+ unsigned char SecurityFlags;
+ uint32_t ExtFileAttributes;
+ uint32_t Flags;
+ uint32_t ImpersonationLevel;
+ uint32_t RootDirFid;
+ unsigned short NameLength;
+ smb_attr_t new_attr;
+ smb_node_t *node;
+ DWORD status;
+ int count;
+ int rc;
+
+ op->dsize = 0;
+
+ rc = smbsr_decode_vwv(sr, "5.wlllqlllllb",
+ &NameLength,
+ &Flags,
+ &RootDirFid,
+ &op->desired_access,
+ &op->dsize,
+ &ExtFileAttributes,
+ &op->share_access,
+ &op->create_disposition,
+ &op->create_options,
+ &ImpersonationLevel,
+ &SecurityFlags);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (NameLength >= MAXPATHLEN) {
+ smbsr_raise_nt_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%#u", sr, NameLength, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
+ !(op->desired_access & DELETE)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->fqi.srch_attr = 0;
+ op->omode = 0;
+ op->utime.tv_sec = op->utime.tv_nsec = 0;
+ op->my_flags = 0;
+ op->dattr = ExtFileAttributes;
+
+ if (Flags) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+ if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)
+ op->my_flags |= MYF_MUST_BE_DIRECTORY;
+ }
+
+ if (ExtFileAttributes & FILE_FLAG_WRITE_THROUGH)
+ op->create_options |= FILE_WRITE_THROUGH;
+
+ if (ExtFileAttributes & FILE_FLAG_DELETE_ON_CLOSE)
+ op->create_options |= FILE_DELETE_ON_CLOSE;
+
+ if (RootDirFid == 0) {
+ op->fqi.dir_snode = sr->tid_tree->t_snode;
+ } else {
+ sr->smb_fid = (ushort_t)RootDirFid;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ op->fqi.dir_snode = sr->fid_ofile->f_node;
+ smbsr_disconnect_file(sr);
+ }
+
+ status = NT_STATUS_SUCCESS;
+ /*
+ * According to NT, when exclusive share access failed,
+ * instead of raising "access deny" error immediately,
+ * we should wait for the client holding the exclusive
+ * file to close the file. If the wait timed out, we
+ * report a sharing violation; otherwise, we grant access.
+ * smb_open_subr returns NT_STATUS_SHARING_VIOLATION when
+ * it encounters an exclusive share access deny: we wait
+ * and retry.
+ */
+ for (count = 0; count <= 4; count++) {
+ if (count) {
+ delay(MSEC_TO_TICK(400));
+ }
+
+ if ((status = smb_open_subr(sr)) == NT_STATUS_SUCCESS)
+ break;
+ }
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ switch (MYF_OPLOCK_TYPE(op->my_flags)) {
+ case MYF_EXCLUSIVE_OPLOCK :
+ OplockLevel = 1;
+ break;
+ case MYF_BATCH_OPLOCK :
+ OplockLevel = 2;
+ break;
+ case MYF_LEVEL_II_OPLOCK :
+ OplockLevel = 3;
+ break;
+ case MYF_OPLOCK_NONE :
+ default:
+ OplockLevel = 0;
+ break;
+ }
+
+ if (op->create_options & FILE_DELETE_ON_CLOSE)
+ smb_preset_delete_on_close(sr->fid_ofile);
+
+ /*
+ * Set up the directory flag and ensure that
+ * we don't return a stale file size.
+ */
+ node = sr->fid_ofile->f_node;
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ DirFlag = 1;
+ new_attr.sa_vattr.va_size = 0;
+ } else {
+ DirFlag = 0;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ (void) smb_fsop_getattr(sr, kcred, node, &new_attr);
+ node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size;
+ }
+
+ smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
+ 34,
+ sr->andx_com,
+ 0x67,
+ OplockLevel,
+ sr->smb_fid,
+ op->action_taken,
+ &node->attr.sa_crtime,
+ &node->attr.sa_vattr.va_atime,
+ &node->attr.sa_vattr.va_mtime,
+ &node->attr.sa_vattr.va_ctime,
+ op->dattr & FILE_ATTRIBUTE_MASK,
+ new_attr.sa_vattr.va_size,
+ new_attr.sa_vattr.va_size,
+ op->ftype,
+ op->devstate,
+ DirFlag,
+ 0);
+ } else {
+ /* Named PIPE */
+ OplockLevel = 0;
+ smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
+ 34,
+ sr->andx_com,
+ 0x67,
+ OplockLevel,
+ sr->smb_fid,
+ op->action_taken,
+ 0LL,
+ 0LL,
+ 0LL,
+ 0LL,
+ SMB_FA_NORMAL,
+ 0x1000LL,
+ 0LL,
+ op->ftype,
+ op->devstate,
+ 0,
+ 0);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
new file mode 100644
index 0000000000..63f1f81440
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -0,0 +1,255 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This command is used to create or open a file or directory, when EAs
+ * or an SD must be applied to the file. The functionality is similar
+ * to SmbNtCreateAndx with the option to supply extended attributes or
+ * a security descriptor.
+ *
+ * Note: we don't decode the extended attributes because we don't
+ * support them at this time.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_vops.h>
+
+/*
+ * smb_nt_transact_create
+ *
+ * This command is used to create or open a file or directory, when EAs
+ * or an SD must be applied to the file. The request parameter block
+ * encoding, data block encoding and output parameter block encoding are
+ * described in CIFS section 4.2.2.
+ *
+ * The format of the command is SmbNtTransact but it is basically the same
+ * as SmbNtCreateAndx with the option to supply extended attributes or a
+ * security descriptor. For information not defined in CIFS section 4.2.2
+ * see section 4.2.1 (NT_CREATE_ANDX).
+ */
+int
+smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa)
+{
+ struct open_param *op = &sr->arg.open;
+ uint8_t OplockLevel;
+ uint8_t DirFlag;
+ uint8_t SecurityFlags;
+ uint32_t ExtFileAttributes;
+ uint32_t sd_len;
+ uint32_t EaLength;
+ uint32_t Flags;
+ uint32_t ImpersonationLevel;
+ uint32_t RootDirFid;
+ uint32_t NameLength;
+ smb_attr_t new_attr;
+ smb_node_t *node;
+ DWORD status;
+ int rc;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "%lllqllllllllb",
+ sr,
+ &Flags,
+ &RootDirFid,
+ &op->desired_access,
+ &op->dsize,
+ &ExtFileAttributes,
+ &op->share_access,
+ &op->create_disposition,
+ &op->create_options,
+ &sd_len,
+ &EaLength,
+ &NameLength,
+ &ImpersonationLevel,
+ &SecurityFlags);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * If name length is zero, interpret as "\".
+ */
+ if (NameLength == 0) {
+ op->fqi.path = "\\";
+ } else {
+ rc = smb_decode_mbc(&xa->req_param_mb, "%#u",
+ sr, NameLength, &op->fqi.path);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ }
+
+ if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
+ !(op->desired_access & DELETE)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ if (sd_len >= sizeof (smb_sdbuf_t)) {
+ /* ignore security setting for files on Unix volumes */
+ op->sd_buf = kmem_alloc(sd_len, KM_SLEEP);
+
+ if ((smb_decode_mbc(&xa->req_data_mb, "#c", sd_len,
+ (char *)op->sd_buf)) != 0) {
+ kmem_free(op->sd_buf, sd_len);
+ smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL);
+ /* NOTREACHED */
+ }
+ } else {
+ op->sd_buf = 0;
+ }
+
+ op->fqi.srch_attr = 0;
+ op->omode = 0;
+
+ op->utime.tv_sec = op->utime.tv_nsec = 0;
+ op->my_flags = 0;
+
+ op->dattr = ExtFileAttributes;
+
+ if (Flags) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
+ if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+ if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)
+ op->my_flags |= MYF_MUST_BE_DIRECTORY;
+ }
+
+ if (ExtFileAttributes & FILE_FLAG_WRITE_THROUGH)
+ op->create_options |= FILE_WRITE_THROUGH;
+
+ if (ExtFileAttributes & FILE_FLAG_DELETE_ON_CLOSE)
+ op->create_options |= FILE_DELETE_ON_CLOSE;
+
+ if (RootDirFid == 0) {
+ op->fqi.dir_snode = sr->tid_tree->t_snode;
+ } else {
+ sr->smb_fid = (ushort_t)RootDirFid;
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ /*
+ * XXX: ASSERT() for now but we should understand if the test
+ * of the return value is missing because it cannot happen.
+ */
+ ASSERT(sr->fid_ofile != NULL);
+ op->fqi.dir_snode = sr->fid_ofile->f_node;
+ smbsr_disconnect_file(sr);
+ }
+
+ status = smb_open_subr(sr);
+ if (op->sd_buf)
+ kmem_free(op->sd_buf, sd_len);
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ switch (MYF_OPLOCK_TYPE(op->my_flags)) {
+ case MYF_EXCLUSIVE_OPLOCK :
+ OplockLevel = 1;
+ break;
+ case MYF_BATCH_OPLOCK :
+ OplockLevel = 2;
+ break;
+ case MYF_LEVEL_II_OPLOCK :
+ OplockLevel = 3;
+ break;
+ case MYF_OPLOCK_NONE :
+ default:
+ OplockLevel = 0;
+ break;
+ }
+
+ if (op->create_options & FILE_DELETE_ON_CLOSE)
+ smb_preset_delete_on_close(sr->fid_ofile);
+
+ /*
+ * Set up the directory flag and ensure that
+ * we don't return a stale file size.
+ */
+ node = sr->fid_ofile->f_node;
+ if (node->attr.sa_vattr.va_type == VDIR) {
+ DirFlag = 1;
+ new_attr.sa_vattr.va_size = 0;
+ } else {
+ DirFlag = 0;
+ new_attr.sa_mask = SMB_AT_SIZE;
+ (void) smb_fsop_getattr(sr, kcred, node, &new_attr);
+ node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size;
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
+ OplockLevel,
+ sr->smb_fid,
+ op->action_taken,
+ 0, /* EaErrorOffset */
+ &node->attr.sa_crtime,
+ &node->attr.sa_vattr.va_atime,
+ &node->attr.sa_vattr.va_mtime,
+ &node->attr.sa_vattr.va_ctime,
+ op->dattr & FILE_ATTRIBUTE_MASK,
+ new_attr.sa_vattr.va_size,
+ new_attr.sa_vattr.va_size,
+ op->ftype,
+ op->devstate,
+ DirFlag);
+ } else {
+ /* Named PIPE */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
+ 0,
+ sr->smb_fid,
+ op->action_taken,
+ 0, /* EaErrorOffset */
+ 0LL,
+ 0LL,
+ 0LL,
+ 0LL,
+ op->dattr,
+ 0x1000LL,
+ 0LL,
+ op->ftype,
+ op->devstate,
+ 0);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
new file mode 100644
index 0000000000..5725814a0f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -0,0 +1,110 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/winioctl.h>
+#include <smbsrv/ntstatus.h>
+
+
+/*
+ * This table defines the list of IOCTL/FSCTL values for which we'll
+ * return a specific NT status code, based on observation of NT.
+ */
+static struct {
+ uint32_t fcode;
+ DWORD status;
+} ioctl_ret_tbl[] = {
+ {FSCTL_GET_OBJECT_ID, NT_STATUS_INVALID_PARAMETER},
+ {FSCTL_QUERY_ALLOCATED_RANGES, NT_STATUS_INVALID_PARAMETER}
+};
+
+
+/*
+ * smb_nt_transact_ioctl
+ *
+ * This command allows device and file system control functions to be
+ * transferred transparently from client to server. This is currently
+ * a stub to work out whether or not we need to return an NT status
+ * code.
+ *
+ * Setup Words Encoding Description
+ * =========================== =========================================
+ * ULONG FunctionCode; NT device or file system control code
+ * USHORT Fid; Handle for io or fs control. Unless BIT0
+ * of ISFLAGS is set.
+ * BOOLEAN IsFsctl; Indicates whether the command is a device
+ * control (FALSE) or a file system control
+ * (TRUE).
+ * UCHAR IsFlags; BIT0 - command is to be applied to share
+ * root handle. Share must be a DFS share.
+ *
+ * Data Block Encoding Description
+ * =========================== =========================================
+ * Data[ TotalDataCount ] Passed to the Fsctl or Ioctl
+ *
+ * Server Response Description
+ * =========================== ==================================
+ * SetupCount 1
+ * Setup[0] Length of information returned by
+ * io or fs control.
+ * DataCount Length of information returned by
+ * io or fs control.
+ * Data[ DataCount ] The results of the io or fs control.
+ */
+int
+smb_nt_transact_ioctl(struct smb_request *sr, struct smb_xa *xa)
+{
+ DWORD status = NT_STATUS_SUCCESS;
+ uint32_t fcode;
+ unsigned short fid;
+ unsigned char is_fsctl;
+ unsigned char is_flags;
+ int i;
+
+ if (smb_decode_mbc(&xa->req_setup_mb, "lwbb",
+ &fcode,
+ &fid,
+ &is_fsctl,
+ &is_flags) != 0) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ }
+
+ for (i = 0;
+ i < sizeof (ioctl_ret_tbl) / sizeof (ioctl_ret_tbl[0]);
+ i++) {
+ if (ioctl_ret_tbl[i].fcode == fcode) {
+ status = ioctl_ret_tbl[i].status;
+ break;
+ }
+ }
+
+ if (status != NT_STATUS_SUCCESS)
+ smbsr_raise_nt_error(sr, status);
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", 0);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
new file mode 100644
index 0000000000..d70ddf4fc0
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
@@ -0,0 +1,613 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * File Change Notification (FCN)
+ */
+
+/*
+ * SMB: nt_transact_notify_change
+ *
+ * Client Setup Words Description
+ * ================================== =================================
+ *
+ * ULONG CompletionFilter; Specifies operation to monitor
+ * USHORT Fid; Fid of directory to monitor
+ * BOOLEAN WatchTree; TRUE = watch all subdirectories too
+ * UCHAR Reserved; MBZ
+ *
+ * This command notifies the client when the directory specified by Fid is
+ * modified. It also returns the name(s) of the file(s) that changed. The
+ * command completes once the directory has been modified based on the
+ * supplied CompletionFilter. The command is a "single shot" and therefore
+ * needs to be reissued to watch for more directory changes.
+ *
+ * A directory file must be opened before this command may be used. Once
+ * the directory is open, this command may be used to begin watching files
+ * and subdirectories in the specified directory for changes. The first
+ * time the command is issued, the MaxParameterCount field in the transact
+ * header determines the size of the buffer that will be used at the server
+ * to buffer directory change information between issuances of the notify
+ * change commands.
+ *
+ * When a change that is in the CompletionFilter is made to the directory,
+ * the command completes. The names of the files that have changed since
+ * the last time the command was issued are returned to the client. The
+ * ParameterCount field of the response indicates the number of bytes that
+ * are being returned. If too many files have changed since the last time
+ * the command was issued, then zero bytes are returned and an alternate
+ * status code is returned in the Status field of the response.
+ *
+ * The CompletionFilter is a mask created as the sum of any of the
+ * following flags:
+ *
+ * FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
+ * FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
+ * FILE_NOTIFY_CHANGE_NAME 0x00000003
+ * FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
+ * FILE_NOTIFY_CHANGE_SIZE 0x00000008
+ * FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
+ * FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
+ * FILE_NOTIFY_CHANGE_CREATION 0x00000040
+ * FILE_NOTIFY_CHANGE_EA 0x00000080
+ * FILE_NOTIFY_CHANGE_SECURITY 0x00000100
+ * FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+ * FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+ * FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+ *
+ * Server Response Description
+ * ================================== ================================
+ * ParameterCount # of bytes of change data
+ * Parameters[ ParameterCount ] FILE_NOTIFY_INFORMATION
+ * structures
+ *
+ * The response contains FILE_NOTIFY_INFORMATION structures, as defined
+ * below. The NextEntryOffset field of the structure specifies the offset,
+ * in bytes, from the start of the current entry to the next entry in the
+ * list. If this is the last entry in the list, this field is zero. Each
+ * entry in the list must be longword aligned, so NextEntryOffset must be a
+ * multiple of four.
+ *
+ * typedef struct {
+ * ULONG NextEntryOffset;
+ * ULONG Action;
+ * ULONG FileNameLength;
+ * WCHAR FileName[1];
+ * } FILE_NOTIFY_INFORMATION;
+ *
+ * Where Action describes what happened to the file named FileName:
+ *
+ * FILE_ACTION_ADDED 0x00000001
+ * FILE_ACTION_REMOVED 0x00000002
+ * FILE_ACTION_MODIFIED 0x00000003
+ * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
+ * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
+ * FILE_ACTION_ADDED_STREAM 0x00000006
+ * FILE_ACTION_REMOVED_STREAM 0x00000007
+ * FILE_ACTION_MODIFIED_STREAM 0x00000008
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <sys/sdt.h>
+
+/*
+ * smb_nt_transact_notify_change
+ *
+ * This function is responsible for processing NOTIFY CHANGE requests.
+ * Requests are stored in a global queue. This queue is processed when
+ * a monitored directory is changed or client cancels one of its already
+ * sent requests.
+ */
+int
+smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint32_t CompletionFilter;
+ unsigned char WatchTree;
+ smb_node_t *node;
+
+ if (smb_decode_mbc(&xa->req_setup_mb, "lwb",
+ &CompletionFilter, &sr->smb_fid, &WatchTree) != 0)
+ return (SDRC_UNSUPPORTED);
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ node = sr->fid_ofile->f_node;
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ /*
+ * notify change requests are only valid for
+ * directories
+ */
+ smbsr_raise_nt_error(sr, NT_STATUS_NOT_A_DIRECTORY);
+ /* NOTREACHED */
+ }
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_ACTIVE:
+ node->waiting_event++;
+ node->flags |= NODE_FLAGS_NOTIFY_CHANGE;
+ if ((node->flags & NODE_FLAGS_CHANGED) == 0) {
+ sr->sr_ncr.nc_node = node;
+ sr->sr_ncr.nc_flags = CompletionFilter;
+ if (WatchTree)
+ sr->sr_ncr.nc_flags |= NODE_FLAGS_WATCH_TREE;
+
+ sr->sr_keep = B_TRUE;
+ sr->sr_state = SMB_REQ_STATE_WAITING_EVENT;
+ smb_slist_insert_tail(&smb_info.si_ncr_list, sr);
+
+ /*
+ * Monitor events system-wide.
+ *
+ * XXX: smb_node_ref() and smb_node_release()
+ * take &node->n_lock. May need alternate forms
+ * of these routines if node->n_lock is taken
+ * around calls to smb_fem_fcn_install() and
+ * smb_fem_fcn_uninstall().
+ */
+
+ smb_fem_fcn_install(node);
+
+ mutex_exit(&sr->sr_mutex);
+ return (SDRC_NO_REPLY);
+ } else {
+ /* node already changed, reply immediately */
+ if (--node->waiting_event == 0)
+ node->flags &=
+ ~(NODE_FLAGS_NOTIFY_CHANGE |
+ NODE_FLAGS_CHANGED);
+ mutex_exit(&sr->sr_mutex);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ case SMB_REQ_STATE_CANCELED:
+ mutex_exit(&sr->sr_mutex);
+ smbsr_raise_nt_error(sr, NT_STATUS_CANCELLED);
+ /* NOTREACHED */
+ default:
+ ASSERT(0);
+ mutex_exit(&sr->sr_mutex);
+ return (SDRC_NORMAL_REPLY);
+ }
+}
+
+/*
+ * smb_reply_notify_change_request
+ *
+ * This function sends appropriate response to an already queued NOTIFY CHANGE
+ * request. If node is changed (reply == NODE_FLAGS_CHANGED), a normal reply is
+ * sent.
+ * If client cancels the request or session dropped, an NT_STATUS_CANCELED
+ * is sent in reply.
+ */
+int
+smb_reply_notify_change_request(
+ smb_request_t *sr)
+{
+ smb_node_t *node;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ struct smb_xa *xa;
+
+ xa = sr->r_xa;
+ node = sr->sr_ncr.nc_node;
+
+ if (--node->waiting_event == 0) {
+ node->flags &= ~(NODE_FLAGS_NOTIFY_CHANGE | NODE_FLAGS_CHANGED);
+ smb_fem_fcn_uninstall(node);
+ }
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+
+ case SMB_REQ_STATE_EVENT_OCCURRED:
+ sr->sr_state = SMB_REQ_STATE_ACTIVE;
+
+ /* many things changed */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0L);
+
+ /* setup the NT transact reply */
+
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&xa->rep_param_mb);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ n_setup = (n_setup + 1) / 2; /* Convert to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
+ /* Pad to 4 bytes */
+ data_pad = (4 - ((param_off + n_param) & 3)) % 4;
+ /* Param off from hdr */
+ data_off = param_off + n_param + data_pad;
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ smbsr_encode_result(sr, 18+n_setup, total_bytes,
+ "b 3. llllllllb C w #. C #. C",
+ 18 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &xa->rep_param_mb,
+ data_pad,
+ &xa->rep_data_mb);
+ break;
+
+ case SMB_REQ_STATE_CANCELED:
+ /*
+ * an STATUS should be sent,
+ * we need an implementation of nt_raise_error
+ * but without long jump.
+ */
+ smbsr_setup_nt_status(sr, 0xc0000000, NT_STATUS_CANCELLED);
+ (void) smb_encode_mbc(&sr->reply, "bwbw",
+ (short)0, 0L, (short)0, 0L);
+ sr->smb_wct = 0;
+ sr->smb_bcc = 0;
+ break;
+ default:
+ ASSERT(0);
+ }
+ mutex_exit(&sr->sr_mutex);
+
+ /* Setup the header */
+ (void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, NULL);
+
+ /* send the reply */
+ DTRACE_PROBE1(ncr__reply, struct smb_request *, sr)
+ (void) smb_session_send(sr->session, 0, &sr->reply);
+ smbsr_cleanup(sr);
+
+ mutex_enter(&sr->sr_mutex);
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+ smb_request_free(sr);
+ return (0);
+}
+
+/*
+ * smb_process_session_notify_change_queue
+ *
+ * This function traverses notify change request queue and sends
+ * cancel replies to all of requests that are related to a specific
+ * session.
+ */
+void
+smb_process_session_notify_change_queue(struct smb_session *session)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ if (sr->session == session) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_process_file_notify_change_queue
+ *
+ * This function traverses notify change request queue and sends
+ * cancel replies to all of requests that are related to the
+ * specified file.
+ */
+void
+smb_process_file_notify_change_queue(struct smb_ofile *of)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ if (sr->fid_ofile == of) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_reply_specific_cancel_request
+ *
+ * This function searches global request list for a specific request. If found,
+ * moves the request to event queue and kicks the notify change daemon.
+ */
+
+void
+smb_reply_specific_cancel_request(struct smb_request *zsr)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ if ((sr->session == zsr->session) &&
+ (sr->smb_sid == zsr->smb_sid) &&
+ (sr->smb_uid == zsr->smb_uid) &&
+ (sr->smb_pid == zsr->smb_pid) &&
+ (sr->smb_tid == zsr->smb_tid) &&
+ (sr->smb_mid == zsr->smb_mid)) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_process_node_notify_change_queue
+ *
+ * This function searches notify change request queue and sends
+ * 'NODE MODIFIED' reply to all requests which are related to a
+ * specific node.
+ * WatchTree flag: We handle this flag in a special manner just
+ * for DAVE clients. When something is changed, we notify all
+ * requests which came from DAVE clients on the same volume which
+ * has been modified. We don't care about the tree that they wanted
+ * us to monitor. any change in any part of the volume will lead
+ * to notifying all notify change requests from DAVE clients on the
+ * different parts of the volume hierarchy.
+ */
+void
+smb_process_node_notify_change_queue(struct smb_node *node)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ boolean_t sig = B_FALSE;
+
+ if (!(node->flags & NODE_FLAGS_NOTIFY_CHANGE))
+ return;
+
+ node->flags |= NODE_FLAGS_CHANGED;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&smb_info.si_ncr_list, sr);
+ /*
+ * send notify if:
+ * - it's a request for the same node or
+ * - it's a request from a DAVE client, its 'watch tree'
+ * flag is set and monitors a tree on the same volume.
+ */
+ if ((sr->sr_ncr.nc_node == node) ||
+ ((sr->sr_ncr.nc_flags & NODE_FLAGS_WATCH_TREE) &&
+ (sr->session->native_os == NATIVE_OS_MACOS) &&
+ !fsd_cmp(&sr->sr_ncr.nc_node->tree_fsd, &node->tree_fsd))) {
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_WAITING_EVENT:
+ smb_slist_obj_move(
+ &smb_info.si_nce_list,
+ &smb_info.si_ncr_list,
+ sr);
+ sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED;
+ sig = B_TRUE;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ }
+ sr = tmp;
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+ smb_slist_exit(&smb_info.si_ncr_list);
+ if (sig) {
+ smb_thread_signal(&smb_info.si_thread_notify_change);
+ }
+}
+
+/*
+ * smb_notify_change_daemon
+ *
+ * This function processes notify change event list and send appropriate
+ * responses to the requests. This function executes in the system as an
+ * indivdual thread.
+ */
+
+void
+smb_notify_change_daemon(smb_thread_t *thread, void *si_void)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+ list_t sr_list;
+ smb_info_t *si = si_void;
+
+ list_create(&sr_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ ASSERT(si != NULL);
+
+ while (smb_thread_continue(thread)) {
+
+ while (smb_slist_move_tail(&sr_list, &si->si_nce_list)) {
+ sr = list_head(&sr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = list_next(&sr_list, sr);
+ list_remove(&sr_list, sr);
+ (void) smb_reply_notify_change_request(sr);
+ sr = tmp;
+ }
+ }
+ }
+
+ list_destroy(&sr_list);
+}
+
+/*
+ * smb_notify_change_event_queue_dump
+ *
+ * Dumps all requests in NCE queue to the system log.
+ */
+void
+smb_notify_change_event_queue_dump()
+{
+ smb_request_t *sr;
+ int i = 0;
+
+ smb_slist_enter(&smb_info.si_nce_list);
+ sr = smb_slist_head(&smb_info.si_nce_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ ASSERT((sr->sr_state == SMB_REQ_STATE_CANCELED) ||
+ (sr->sr_state == SMB_REQ_STATE_EVENT_OCCURRED));
+ i++;
+ sr = smb_slist_next(&smb_info.si_nce_list, sr);
+ }
+ smb_slist_exit(&smb_info.si_nce_list);
+}
+
+/*
+ * smb_notify_change_req_queue_dump
+ *
+ * Dumps all requests in NCR queue to the system log.
+ */
+void
+smb_notify_change_req_queue_dump()
+{
+ smb_request_t *sr;
+ int i = 0;
+
+ smb_slist_enter(&smb_info.si_ncr_list);
+ sr = smb_slist_head(&smb_info.si_ncr_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ ASSERT(sr->sr_state == SMB_REQ_STATE_WAITING_EVENT);
+ i++;
+ sr = smb_slist_next(&smb_info.si_ncr_list, sr);
+ }
+ smb_slist_exit(&smb_info.si_ncr_list);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
new file mode 100644
index 0000000000..70d8437cdf
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
@@ -0,0 +1,213 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_secdesc.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+extern uint32_t smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
+ uint32_t secinfo, uint32_t *buflen);
+extern uint32_t smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd,
+ uint32_t secinfo);
+
+/*
+ * smb_nt_transact_query_security_info
+ *
+ * This command allows the client to retrieve the security descriptor
+ * on a file. The result of the call is returned to the client in the
+ * Data part of the transaction response.
+ *
+ * Some clients specify a non-zero maximum data return size (mdrcnt)
+ * for the SD and some specify zero. In either case, if the mdrcnt is
+ * too small we need to return NT_STATUS_BUFFER_TOO_SMALL and a buffer
+ * size hint. The client should then retry with the appropriate buffer
+ * size.
+ *
+ * Client Parameter Block Description
+ * ================================== =================================
+ *
+ * USHORT Fid; FID of target
+ * USHORT Reserved; MBZ
+ * ULONG secinfo; Fields of descriptor to set
+ *
+ * Data Block Encoding Description
+ * ================================== ==================================
+ *
+ * Data[TotalDataCount] Security Descriptor information
+ */
+
+int
+smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_sdbuf_t *sr_sd;
+ uint32_t secinfo;
+ uint32_t sr_sdlen;
+ uint32_t status;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
+ &sr->smb_fid, &secinfo) != 0) {
+ /*
+ * It's not clear why ERRnomem is returned here.
+ * This should rarely happen and we're not sure if
+ * it's going to break something if we change this
+ * error code, so we're going to keep it for now.
+ */
+ smbsr_raise_error(sr, ERRSRV, ERRnomem);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+
+ if ((sr->fid_ofile->f_node == NULL) ||
+ (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (sr->tid_tree->t_acltype != ACE_T) {
+ /*
+ * If target filesystem doesn't support ACE_T acls then
+ * don't process SACL
+ */
+ secinfo &= ~SMB_SACL_SECINFO;
+ }
+
+ sr_sdlen = xa->smb_mdrcnt;
+ status = smb_sd_read(sr, &sr_sd, secinfo, &sr_sdlen);
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_BUFFER_TOO_SMALL) {
+ /*
+ * The maximum data return count specified by the
+ * client is not big enough to hold the security
+ * descriptor. We have to return an error but we
+ * can provide a buffer size hint for the client.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", sr_sdlen);
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_ERROR,
+ NT_STATUS_BUFFER_TOO_SMALL);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "#c", (int)sr_sdlen, sr_sd);
+ (void) smb_encode_mbc(&xa->rep_param_mb, "l", sr_sdlen);
+
+ kmem_free(sr_sd, sr_sdlen);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_nt_transact_set_security_info
+ *
+ * This command allows the client to change the security descriptor on a
+ * file. All we do here is decode the parameters and the data. The data
+ * is passed directly to smb_nt_set_security_object, with the security
+ * information describing the information to set. There are no response
+ * parameters or data.
+ *
+ * Client Parameter Block Encoding Description
+ * ================================== ==================================
+ * USHORT Fid; FID of target
+ * USHORT Reserved; MBZ
+ * ULONG SecurityInformation; Fields of SD that to set
+ *
+ * Data Block Encoding Description
+ * ================================== ==================================
+ * Data[TotalDataCount] Security Descriptor information
+ */
+int
+smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_sdbuf_t *sd_buf;
+ uint32_t sec_info;
+ uint32_t status;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "w2.l",
+ &sr->smb_fid, &sec_info) != 0) {
+ smbsr_raise_nt_error(sr, NT_STATUS_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if ((sr->fid_ofile->f_node == NULL) ||
+ (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK)) {
+ smbsr_raise_nt_error(sr, NT_STATUS_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (sr->fid_ofile->f_node->flags & NODE_READ_ONLY) {
+ smbsr_raise_nt_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED);
+ /* NOTREACHED */
+ }
+
+ if (sr->tid_tree->t_acltype != ACE_T) {
+ /*
+ * If target filesystem doesn't support ACE_T acls then
+ * don't process SACL
+ */
+ sec_info &= ~SMB_SACL_SECINFO;
+ }
+
+ if ((sec_info & SMB_ALL_SECINFO) == 0) {
+ return (NT_STATUS_SUCCESS);
+ }
+
+ sd_buf = kmem_alloc(xa->smb_tdscnt, KM_SLEEP);
+
+ if ((smb_decode_mbc(&xa->req_data_mb, "#c",
+ xa->smb_tdscnt, (char *)sd_buf)) != 0) {
+ kmem_free(sd_buf, xa->smb_tdscnt);
+ smbsr_raise_nt_error(sr, NT_STATUS_BUFFER_TOO_SMALL);
+ /* NOTREACHED */
+ }
+
+ status = smb_sd_write(sr, sd_buf, sec_info);
+ kmem_free(sd_buf, xa->smb_tdscnt);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smbsr_raise_nt_error(sr, status);
+ /* NOTREACHED */
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c
new file mode 100644
index 0000000000..43ecf7b023
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c
@@ -0,0 +1,456 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * Odir State Machine
+ * ------------------
+ *
+ * +-------------------------+ T0
+ * | SMB_ODIR_STATE_OPEN |<----------- Creation/Allocation
+ * +-------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-------------------------+
+ * | SMB_ODIR_STATE_CLOSING |
+ * +-------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-------------------------+ T3
+ * | SMB_ODIR_STATE_CLOSED |----------> Deletion/Free
+ * +-------------------------+
+ *
+ * SMB_ODIR_STATE_OPEN
+ *
+ * While in this state:
+ * - The odir is queued in the list of odirs of its tree.
+ * - References will be given out if the odir is looked up.
+ *
+ * SMB_ODIR_STATE_CLOSING
+ *
+ * While in this state:
+ * - The odir is queued in the list of odirs of its tree.
+ * - References will not be given out if the odir is looked up.
+ * - The odir is closed.
+ * - The resources associated with the odir remain.
+ *
+ * SMB_ODIR_STATE_CLOSED
+ *
+ * While in this state:
+ * - The odir is queued in the list of odirs of its tree.
+ * - References will not be given out if the odir is looked up.
+ * - The resources associated with the odir remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_odir_open(). A new odir is created and
+ * added to the list of odirs of a tree.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_odir_close().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_odir_release(). The resources associated
+ * with the odir are freed as well as the odir structure. For the
+ * transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED
+ * state and the reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the odir structures is controlled by 3 elements:
+ * - The list of odirs of the tree it belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the odir structure used to protect its fields
+ * and there's a lock embedded in the list of odirs of a tree. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the odir into the list of odirs of the tree and to remove
+ * the odir from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a odir structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the odir
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to an odir require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the odir
+ * is opened. The other when the odir is looked up. This translates
+ * into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid().
+ *
+ * It should be noted that the reference count of an odir registers the
+ * number of references to the odir in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The odir is open. An odir is anchored by his state. If there's
+ * no activity involving an odir currently open, the reference count
+ * of that odir is zero.
+ *
+ * 2) The odir is queued in the list of odirs of its tree. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_fsops.h>
+
+/* Static functions defined further down this file. */
+static void smb_odir_delete(smb_odir_t *of);
+static smb_odir_t *smb_odir_close_and_next(smb_odir_t *od);
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * smb_odir_open
+ */
+smb_odir_t *
+smb_odir_open(
+ smb_tree_t *tree,
+ smb_node_t *node,
+ char *pattern,
+ uint16_t pid,
+ unsigned short sattr)
+{
+ smb_odir_t *dir;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(node);
+ ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ ASSERT(pattern);
+
+ if (strlen(pattern) >= sizeof (dir->d_pattern)) {
+ return (NULL);
+ }
+
+ dir = kmem_cache_alloc(smb_info.si_cache_odir, KM_SLEEP);
+ bzero(dir, sizeof (smb_odir_t));
+ dir->d_refcnt = 1;
+ dir->d_session = tree->t_session;
+ dir->d_user = tree->t_user;
+ dir->d_tree = tree;
+ (void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern));
+ dir->d_wildcards = smb_convert_unicode_wildcards(pattern);
+ dir->d_state = SMB_ODIR_STATE_OPEN;
+
+ if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) {
+ kmem_cache_free(smb_info.si_cache_odir, dir);
+ return (NULL);
+ }
+ mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL);
+ dir->d_sattr = sattr;
+ dir->d_opened_by_pid = pid;
+ dir->d_dir_snode = node;
+ dir->d_state = SMB_ODIR_STATE_OPEN;
+ dir->d_magic = SMB_ODIR_MAGIC;
+
+ smb_llist_enter(&tree->t_odir_list, RW_WRITER);
+ smb_llist_insert_tail(&tree->t_odir_list, dir);
+ smb_llist_exit(&tree->t_odir_list);
+
+ atomic_inc_32(&tree->t_session->s_dir_cnt);
+ return (dir);
+}
+
+/*
+ * smb_odir_close
+ */
+void
+smb_odir_close(
+ smb_odir_t *od)
+{
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ mutex_enter(&od->d_mutex);
+ ASSERT(od->d_refcnt);
+ switch (od->d_state) {
+ case SMB_ODIR_STATE_OPEN:
+ od->d_state = SMB_ODIR_STATE_CLOSED;
+ break;
+ case SMB_ODIR_STATE_CLOSING:
+ case SMB_ODIR_STATE_CLOSED:
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&od->d_mutex);
+}
+
+/*
+ * smb_odir_close_all
+ *
+ *
+ */
+void
+smb_odir_close_all(
+ smb_tree_t *tree)
+{
+ smb_odir_t *od;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_odir_list, RW_READER);
+ od = smb_llist_head(&tree->t_odir_list);
+ while (od) {
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_tree == tree);
+ od = smb_odir_close_and_next(od);
+ }
+ smb_llist_exit(&tree->t_odir_list);
+}
+
+/*
+ * smb_odir_close_all_by_pid
+ *
+ *
+ */
+void
+smb_odir_close_all_by_pid(
+ smb_tree_t *tree,
+ uint16_t pid)
+{
+ smb_odir_t *od;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_odir_list, RW_READER);
+ od = smb_llist_head(&tree->t_odir_list);
+ while (od) {
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_tree == tree);
+ if (od->d_opened_by_pid == pid) {
+ od = smb_odir_close_and_next(od);
+ } else {
+ od = smb_llist_next(&tree->t_odir_list, od);
+ }
+ }
+ smb_llist_exit(&tree->t_odir_list);
+}
+
+/*
+ * smb_odir_release
+ */
+void
+smb_odir_release(
+ smb_odir_t *od)
+{
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ mutex_enter(&od->d_mutex);
+ ASSERT(od->d_refcnt);
+ od->d_refcnt--;
+ switch (od->d_state) {
+ case SMB_ODIR_STATE_CLOSING:
+ case SMB_ODIR_STATE_OPEN:
+ break;
+
+ case SMB_ODIR_STATE_CLOSED:
+ if (od->d_refcnt == 0) {
+ mutex_exit(&od->d_mutex);
+ smb_odir_delete(od);
+ return;
+ }
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&od->d_mutex);
+}
+
+/*
+ * smb_odir_lookup_by_sid
+ */
+smb_odir_t *
+smb_odir_lookup_by_sid(
+ smb_tree_t *tree,
+ uint16_t sid)
+{
+ smb_llist_t *od_list;
+ smb_odir_t *od;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ od_list = &tree->t_odir_list;
+
+ smb_llist_enter(od_list, RW_READER);
+ od = smb_llist_head(od_list);
+ while (od) {
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_tree == tree);
+ if (od->d_sid == sid) {
+ mutex_enter(&od->d_mutex);
+ if (od->d_state != SMB_ODIR_STATE_OPEN) {
+ mutex_exit(&od->d_mutex);
+ smb_llist_exit(od_list);
+ return (NULL);
+ }
+ od->d_refcnt++;
+ mutex_exit(&od->d_mutex);
+ break;
+ }
+ od = smb_llist_next(od_list, od);
+ }
+ smb_llist_exit(od_list);
+ return (od);
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_odir_close_and_next
+ *
+ * This function closes the directory passed in (if appropriate) and returns the
+ * next directory in the list of directories of the tree of the directory passed
+ * in. It requires that the list of directories of the tree be entered in
+ * RW_READER mode before being called.
+ */
+static smb_odir_t *
+smb_odir_close_and_next(
+ smb_odir_t *od)
+{
+ smb_odir_t *next_od;
+ smb_tree_t *tree;
+
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+ mutex_enter(&od->d_mutex);
+ switch (od->d_state) {
+ case SMB_ODIR_STATE_OPEN:
+ /* The directory is still opened. */
+ od->d_refcnt++;
+ ASSERT(od->d_refcnt);
+ tree = od->d_tree;
+ mutex_exit(&od->d_mutex);
+ smb_llist_exit(&od->d_tree->t_odir_list);
+ smb_odir_close(od);
+ smb_odir_release(od);
+ smb_llist_enter(&tree->t_odir_list, RW_READER);
+ next_od = smb_llist_head(&tree->t_odir_list);
+ break;
+ case SMB_ODIR_STATE_CLOSING:
+ case SMB_ODIR_STATE_CLOSED:
+ /*
+ * The odir exists but is closed or is in the process
+ * of being closed.
+ */
+ mutex_exit(&od->d_mutex);
+ next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&od->d_mutex);
+ next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
+ break;
+ }
+ return (next_od);
+}
+
+/*
+ * smb_odir_delete
+ */
+static void
+smb_odir_delete(
+ smb_odir_t *od)
+{
+ ASSERT(od);
+ ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+ ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
+ ASSERT(od->d_refcnt == 0);
+
+ /*
+ * Let's remove the odir from the list of odirs of the tree. This has
+ * to be done before any resources associated with the odir are
+ * released.
+ */
+ smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER);
+ smb_llist_remove(&od->d_tree->t_odir_list, od);
+ smb_llist_exit(&od->d_tree->t_odir_list);
+
+ smb_node_release(od->d_dir_snode);
+ atomic_dec_32(&od->d_tree->t_session->s_dir_cnt);
+ smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid);
+ mutex_destroy(&od->d_mutex);
+ kmem_cache_free(smb_info.si_cache_odir, od);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
new file mode 100644
index 0000000000..150262e28b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -0,0 +1,726 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * Ofile State Machine
+ * ------------------
+ *
+ * +-------------------------+ T0
+ * | SMB_OFILE_STATE_OPEN |<----------- Creation/Allocation
+ * +-------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-------------------------+
+ * | SMB_OFILE_STATE_CLOSING |
+ * +-------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-------------------------+ T3
+ * | SMB_OFILE_STATE_CLOSED |----------> Deletion/Free
+ * +-------------------------+
+ *
+ * SMB_OFILE_STATE_OPEN
+ *
+ * While in this state:
+ * - The ofile is queued in the list of ofiles of its tree.
+ * - References will be given out if the ofile is looked up.
+ *
+ * SMB_OFILE_STATE_CLOSING
+ *
+ * While in this state:
+ * - The ofile is queued in the list of ofiles of its tree.
+ * - References will not be given out if the ofile is looked up.
+ * - The file is closed and the locks held are being released.
+ * - The resources associated with the ofile remain.
+ *
+ * SMB_OFILE_STATE_CLOSED
+ *
+ * While in this state:
+ * - The ofile is queued in the list of ofiles of its tree.
+ * - References will not be given out if the ofile is looked up.
+ * - The resources associated with the ofile remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_ofile_open(). A new ofile is created and
+ * added to the list of ofiles of a tree.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_ofile_close().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_ofile_release(). The resources associated
+ * with the ofile are freed as well as the ofile structure. For the
+ * transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED
+ * state and the reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the ofile structures is controlled by 3 elements:
+ * - The list of ofiles of the tree it belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the ofile structure used to protect its fields
+ * and there's a lock embedded in the list of ofiles of a tree. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the ofile into the list of ofiles of the tree and to remove
+ * the ofile from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a ofile structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the ofile
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to an ofile require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the ofile
+ * is opened. The other one when the ofile is looked up. This translates
+ * into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid().
+ *
+ * It should be noted that the reference count of an ofile registers the
+ * number of references to the ofile in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The ofile is open. An ofile is anchored by his state. If there's
+ * no activity involving an ofile currently open, the reference count
+ * of that ofile is zero.
+ *
+ * 2) The ofile is queued in the list of ofiles of its tree. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_kproto.h>
+#include <smbsrv/smb_fsops.h>
+
+/* Static functions defined further down this file. */
+static void smb_ofile_delete(smb_ofile_t *of);
+static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of);
+
+/*
+ * smb_ofile_open
+ *
+ *
+ */
+smb_ofile_t *
+smb_ofile_open(
+ smb_tree_t *tree,
+ smb_node_t *node,
+ uint16_t pid,
+ uint32_t access_granted,
+ uint32_t create_options,
+ uint32_t share_access,
+ uint16_t ftype,
+ char *pipe_name,
+ uint32_t rpc_fid,
+ smb_error_t *err)
+{
+ smb_ofile_t *of;
+ uint16_t fid;
+
+ if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) {
+ err->status = NT_STATUS_TOO_MANY_OPENED_FILES;
+ err->errcls = ERRDOS;
+ err->errcode = ERROR_TOO_MANY_OPEN_FILES;
+ return (NULL);
+ }
+
+ of = kmem_cache_alloc(smb_info.si_cache_ofile, KM_SLEEP);
+ bzero(of, sizeof (smb_ofile_t));
+ of->f_magic = SMB_OFILE_MAGIC;
+ of->f_refcnt = 1;
+ of->f_fid = fid;
+ of->f_opened_by_pid = pid;
+ of->f_granted_access = access_granted;
+ of->f_share_access = share_access;
+ of->f_create_options = create_options;
+ of->f_cr = tree->t_user->u_cred;
+ crhold(of->f_cr);
+ of->f_ftype = ftype;
+ of->f_session = tree->t_user->u_session;
+ of->f_user = tree->t_user;
+ of->f_tree = tree;
+ of->f_node = node;
+ mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
+ of->f_state = SMB_OFILE_STATE_OPEN;
+
+ if (ftype == SMB_FTYPE_MESG_PIPE) {
+ of->f_pipe_info = kmem_alloc(sizeof (mlsvc_pipe_t), KM_SLEEP);
+ bzero(of->f_pipe_info, sizeof (mlsvc_pipe_t));
+ of->f_pipe_info->pipe_name = pipe_name;
+ of->f_pipe_info->fid = rpc_fid;
+ mutex_init(&of->f_pipe_info->mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&of->f_pipe_info->cv, NULL, CV_DEFAULT, NULL);
+ } else {
+ ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */
+ ASSERT(node);
+ if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) {
+ /*
+ * Add this bit for the file's owner even if it's not
+ * specified in the request (Windows behavior).
+ */
+ of->f_granted_access |= FILE_READ_ATTRIBUTES;
+ }
+
+ if ((node->vp->v_type == VREG) && (smb_fsop_open(of) != 0)) {
+ of->f_magic = 0;
+ mutex_destroy(&of->f_mutex);
+ crfree(of->f_cr);
+ smb_idpool_free(&tree->t_fid_pool, of->f_fid);
+ kmem_cache_free(smb_info.si_cache_ofile, of);
+ err->status = NT_STATUS_ACCESS_DENIED;
+ err->errcls = ERRDOS;
+ err->errcode = ERROR_ACCESS_DENIED;
+ return (NULL);
+ }
+ smb_llist_enter(&node->n_ofile_list, RW_WRITER);
+ smb_llist_insert_tail(&node->n_ofile_list, of);
+ smb_llist_exit(&node->n_ofile_list);
+ }
+ smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
+ smb_llist_insert_tail(&tree->t_ofile_list, of);
+ smb_llist_exit(&tree->t_ofile_list);
+ atomic_inc_32(&smb_info.open_files);
+ atomic_inc_32(&of->f_session->s_file_cnt);
+
+ return (of);
+}
+
+/*
+ * smb_ofile_close
+ *
+ *
+ */
+int
+smb_ofile_close(
+ smb_ofile_t *of,
+ uint32_t last_wtime)
+{
+ int rc = 0;
+
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN: {
+
+ of->f_state = SMB_OFILE_STATE_CLOSING;
+ mutex_exit(&of->f_mutex);
+
+ if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
+ smb_rpc_close(of);
+ } else {
+ if (of->f_node->vp->v_type == VREG)
+ (void) smb_fsop_close(of);
+
+ if (of->f_node->flags & NODE_CREATED_READONLY) {
+ smb_node_set_dosattr(of->f_node,
+ of->f_node->attr.sa_dosattr |
+ SMB_FA_READONLY);
+ of->f_node->flags &= ~NODE_CREATED_READONLY;
+ }
+
+ smb_ofile_close_timestamp_update(of, last_wtime);
+ rc = smb_sync_fsattr(NULL, of->f_cr, of->f_node);
+ smb_commit_delete_on_close(of);
+ smb_release_oplock(of, OPLOCK_RELEASE_FILE_CLOSED);
+ smb_commit_delete_on_close(of);
+ /*
+ * if there is any notify change request for
+ * this file then see if any of them is related
+ * to this open instance. If there is any then
+ * cancel them.
+ */
+ if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE)
+ smb_process_file_notify_change_queue(of);
+ smb_node_destroy_lock_by_ofile(of->f_node, of);
+ }
+ atomic_dec_32(&smb_info.open_files);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
+ of->f_state = SMB_OFILE_STATE_CLOSED;
+ mutex_exit(&of->f_mutex);
+ return (rc);
+ }
+ case SMB_OFILE_STATE_CLOSED:
+ case SMB_OFILE_STATE_CLOSING:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&of->f_mutex);
+ return (rc);
+}
+
+/*
+ * smb_ofile_close_all
+ *
+ *
+ */
+void
+smb_ofile_close_all(
+ smb_tree_t *tree)
+{
+ smb_ofile_t *of;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_ofile_list, RW_READER);
+ of = smb_llist_head(&tree->t_ofile_list);
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+ of = smb_ofile_close_and_next(of);
+ }
+ smb_llist_exit(&tree->t_ofile_list);
+}
+
+/*
+ * smb_ofiles_close_by_pid
+ *
+ *
+ */
+void
+smb_ofile_close_all_by_pid(
+ smb_tree_t *tree,
+ uint16_t pid)
+{
+ smb_ofile_t *of;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ smb_llist_enter(&tree->t_ofile_list, RW_READER);
+ of = smb_llist_head(&tree->t_ofile_list);
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+ if (of->f_opened_by_pid == pid) {
+ of = smb_ofile_close_and_next(of);
+ } else {
+ of = smb_llist_next(&tree->t_ofile_list, of);
+ }
+ }
+ smb_llist_exit(&tree->t_ofile_list);
+}
+
+/*
+ * smb_ofile_release
+ *
+ */
+void
+smb_ofile_release(
+ smb_ofile_t *of)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ ASSERT(of->f_refcnt);
+ of->f_refcnt--;
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN:
+ case SMB_OFILE_STATE_CLOSING:
+ break;
+
+ case SMB_OFILE_STATE_CLOSED:
+ if (of->f_refcnt == 0) {
+ mutex_exit(&of->f_mutex);
+ smb_ofile_delete(of);
+ return;
+ }
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&of->f_mutex);
+}
+
+/*
+ * smb_ofile_lookup_by_fid
+ *
+ * Find the open file whose fid matches the one specified in the request.
+ * If we can't find the fid or the shares (trees) don't match, we have a
+ * bad fid.
+ */
+smb_ofile_t *
+smb_ofile_lookup_by_fid(
+ smb_tree_t *tree,
+ uint16_t fid)
+{
+ smb_llist_t *of_list;
+ smb_ofile_t *of;
+
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ of_list = &tree->t_ofile_list;
+
+ smb_llist_enter(of_list, RW_READER);
+ of = smb_llist_head(of_list);
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+ if (of->f_fid == fid) {
+ mutex_enter(&of->f_mutex);
+ if (of->f_state != SMB_OFILE_STATE_OPEN) {
+ mutex_exit(&of->f_mutex);
+ smb_llist_exit(of_list);
+ return (NULL);
+ }
+ of->f_refcnt++;
+ mutex_exit(&of->f_mutex);
+ break;
+ }
+ of = smb_llist_next(of_list, of);
+ }
+ smb_llist_exit(of_list);
+ return (of);
+}
+
+/*
+ * smb_ofile_set_flags
+ *
+ * Return value:
+ *
+ * Current flags value
+ *
+ */
+void
+smb_ofile_set_flags(
+ smb_ofile_t *of,
+ uint32_t flags)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt);
+
+ mutex_enter(&of->f_mutex);
+ of->f_flags |= flags;
+ mutex_exit(&of->f_mutex);
+}
+/*
+ * smb_ofile_seek
+ *
+ * Return value:
+ *
+ * 0 Success
+ * EINVAL Unknown mode
+ * EOVERFLOW offset too big
+ *
+ */
+int
+smb_ofile_seek(
+ smb_ofile_t *of,
+ ushort_t mode,
+ int32_t off,
+ uint32_t *retoff)
+{
+ off_t newoff = 0;
+ int rc = 0;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt);
+
+ mutex_enter(&of->f_mutex);
+ switch (mode) {
+ case SMB_SEEK_SET:
+ if (off < 0)
+ newoff = 0;
+ else
+ newoff = (off_t)off;
+ break;
+
+ case SMB_SEEK_CUR:
+ if (off < 0 && (-off) > of->f_seek_pos)
+ newoff = 0;
+ else
+ newoff = of->f_seek_pos + (off_t)off;
+ break;
+
+ case SMB_SEEK_END:
+ if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size)
+ newoff = 0;
+ else
+ newoff = of->f_node->attr.sa_vattr.va_size + (off_t)off;
+ break;
+
+ default:
+ mutex_exit(&of->f_mutex);
+ return (EINVAL);
+ }
+
+ if (newoff > ULONG_MAX) {
+ rc = EOVERFLOW;
+ } else {
+ of->f_seek_pos = newoff;
+ *retoff = (uint32_t)newoff;
+ }
+ mutex_exit(&of->f_mutex);
+ return (rc);
+}
+
+/*
+ * smb_ofile_close_timestamp_update
+ *
+ *
+ */
+void
+smb_ofile_close_timestamp_update(
+ smb_ofile_t *of,
+ uint32_t last_wtime)
+{
+ smb_node_t *node;
+ timestruc_t mtime, atime;
+ unsigned int what = 0;
+
+ mtime.tv_sec = last_wtime;
+ mtime.tv_nsec = 0;
+
+ if (mtime.tv_sec != 0 && mtime.tv_sec != 0xFFFFFFFF) {
+ mtime.tv_sec = smb_local_time_to_gmt(mtime.tv_sec);
+ what |= SMB_AT_MTIME;
+ }
+
+ /*
+ * NODE_FLAGS_SYNCATIME is set whenever something is
+ * written to a file. Compliant volumes don't update
+ * atime upon write, so don't update the atime if the
+ * volume is compliant.
+ */
+ node = of->f_node;
+ if (node->flags & NODE_FLAGS_SYNCATIME) {
+ node->flags &= ~NODE_FLAGS_SYNCATIME;
+ what |= SMB_AT_ATIME;
+ (void) microtime(&atime);
+ }
+
+ smb_node_set_time(node, 0, &mtime, &atime, 0, what);
+}
+
+/*
+ * smb_ofile_is_open
+ *
+ */
+boolean_t
+smb_ofile_is_open(
+ smb_ofile_t *of)
+{
+ boolean_t rc = B_FALSE;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ if (of->f_state == SMB_OFILE_STATE_OPEN) {
+ rc = B_TRUE;
+ }
+ mutex_exit(&of->f_mutex);
+ return (rc);
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_ofile_close_and_next
+ *
+ * This function closes the file passed in (if appropriate) and returns the
+ * next open file in the list of open files of the tree of the open file passed
+ * in. It requires that the list of open files of the tree be entered in
+ * RW_READER mode before being called.
+ */
+static smb_ofile_t *
+smb_ofile_close_and_next(
+ smb_ofile_t *of)
+{
+ smb_ofile_t *next_of;
+ smb_tree_t *tree;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN:
+ /* The file is still open. */
+ of->f_refcnt++;
+ ASSERT(of->f_refcnt);
+ tree = of->f_tree;
+ mutex_exit(&of->f_mutex);
+ smb_llist_exit(&of->f_tree->t_ofile_list);
+ (void) smb_ofile_close(of, 0);
+ smb_ofile_release(of);
+ smb_llist_enter(&tree->t_ofile_list, RW_READER);
+ next_of = smb_llist_head(&tree->t_ofile_list);
+ break;
+ case SMB_OFILE_STATE_CLOSING:
+ case SMB_OFILE_STATE_CLOSED:
+ /*
+ * The ofile exists but is closed or
+ * in the process being closed.
+ */
+ mutex_exit(&of->f_mutex);
+ next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&of->f_mutex);
+ next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
+ break;
+ }
+ return (next_of);
+}
+
+/*
+ * smb_ofile_delete
+ *
+ *
+ */
+static void
+smb_ofile_delete(
+ smb_ofile_t *of)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt == 0);
+ ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
+
+ /*
+ * Let's remove the ofile from the list of ofiles of the tree. This has
+ * to be done before any resources associated with the ofile are
+ * released.
+ */
+ smb_llist_enter(&of->f_tree->t_ofile_list, RW_WRITER);
+ smb_llist_remove(&of->f_tree->t_ofile_list, of);
+ smb_llist_exit(&of->f_tree->t_ofile_list);
+ atomic_dec_32(&of->f_session->s_file_cnt);
+
+ if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
+ kmem_free(of->f_pipe_info, sizeof (mlsvc_pipe_t));
+ of->f_pipe_info = NULL;
+ } else {
+ ASSERT(of->f_ftype == SMB_FTYPE_DISK);
+ ASSERT(of->f_node != NULL);
+ smb_llist_enter(&of->f_node->n_ofile_list, RW_WRITER);
+ smb_llist_remove(&of->f_node->n_ofile_list, of);
+ smb_llist_exit(&of->f_node->n_ofile_list);
+ smb_node_release(of->f_node);
+ }
+
+ of->f_magic = (uint32_t)~SMB_OFILE_MAGIC;
+ mutex_destroy(&of->f_mutex);
+ crfree(of->f_cr);
+ smb_idpool_free(&of->f_tree->t_fid_pool, of->f_fid);
+ kmem_cache_free(smb_info.si_cache_ofile, of);
+}
+
+/*
+ * smb_ofile_access
+ *
+ * This function will check to see if the access requested is granted.
+ * Returns NT status codes.
+ */
+uint32_t
+smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access)
+{
+
+ if ((of == NULL) || (cr == kcred))
+ return (NT_STATUS_SUCCESS);
+
+ /*
+ * If the request is for something
+ * I don't grant it is an error
+ */
+ if (~(of->f_granted_access) & access) {
+ if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) &&
+ (access & ACCESS_SYSTEM_SECURITY)) {
+ return (NT_STATUS_PRIVILEGE_NOT_HELD);
+ }
+ return (NT_STATUS_ACCESS_DENIED);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
new file mode 100644
index 0000000000..aa02274224
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -0,0 +1,431 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_vops.h>
+
+/*
+ * This module provides the common open functionality to the various
+ * open and create SMB interface functions.
+ */
+
+/*
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 15
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Flags; Additional information: bit set-
+ * 0 - return additional info
+ * 1 - exclusive oplock requested
+ * 2 - batch oplock requested
+ * USHORT DesiredAccess; File open mode
+ * USHORT SearchAttributes;
+ * USHORT FileAttributes;
+ * UTIME CreationTime; Creation timestamp for file if it
+ * gets created
+ * USHORT OpenFunction; Action to take if file exists
+ * ULONG AllocationSize; Bytes to reserve on create or
+ * truncate
+ * ULONG Reserved[2]; Must be 0
+ * USHORT ByteCount; Count of data bytes; min = 1
+ * UCHAR BufferFormat 0x04
+ * STRING FileName;
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 15
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Fid; File handle
+ * USHORT FileAttributes;
+ * UTIME LastWriteTime;
+ * ULONG DataSize; Current file size
+ * USHORT GrantedAccess; Access permissions actually
+ * allowed
+ * USHORT FileType; Type of file opened
+ * USHORT DeviceState; State of the named pipe
+ * USHORT Action; Action taken
+ * ULONG ServerFid; Server unique file id
+ * USHORT Reserved; Reserved (must be 0)
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * DesiredAccess describes the access the client desires for the file (see
+ * section 3.6 - Access Mode Encoding).
+ *
+ * OpenFunction specifies the action to be taken depending on whether or
+ * not the file exists (see section 3.8 - Open Function Encoding). Action
+ *
+ * in the response specifies the action as a result of the Open request
+ * (see section 3.9 - Open Action Encoding).
+ *
+ * SearchAttributes indicates the attributes that the file must have to be
+ * found while searching to see if it exists. The encoding of this field
+ * is described in the "File Attribute Encoding" section elsewhere in this
+ * document. If SearchAttributes is zero then only normal files are
+ * returned. If the system file, hidden or directory attributes are
+ * specified then the search is inclusive -- both the specified type(s) of
+ * files and normal files are returned.
+ *
+ * FileType returns the kind of resource actually opened:
+ *
+ * Name Value Description
+ * ========================== ====== ==================================
+ *
+ * FileTypeDisk 0 Disk file or directory as defined
+ * in the attribute field
+ * FileTypeByteModePipe 1 Named pipe in byte mode
+ * FileTypeMessageModePipe 2 Named pipe in message mode
+ * FileTypePrinter 3 Spooled printer
+ * FileTypeUnknown 0xFFFF Unrecognized resource type
+ *
+ * If bit0 of Flags is clear, the FileAttributes, LastWriteTime, DataSize,
+ * FileType, and DeviceState have indeterminate values in the response.
+ *
+ * This SMB can request an oplock on the opened file. Oplocks are fully
+ * described in the "Oplocks" section elsewhere in this document, and there
+ * is also discussion of oplocks in the SMB_COM_LOCKING_ANDX SMB
+ * description. Bit1 and bit2 of the Flags field are used to request
+ * oplocks during open.
+ *
+ * The following SMBs may follow SMB_COM_OPEN_ANDX:
+ *
+ * SMB_COM_READ SMB_COM_READ_ANDX
+ * SMB_COM_IOCTL
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * SMB: open
+ *
+ * This message is sent to obtain a file handle for a data file. This
+ * returned Fid is used in subsequent client requests such as read, write,
+ * close, etc.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT DesiredAccess; Mode - read/write/share
+ * USHORT SearchAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * FileName is the fully qualified file name, relative to the root of the
+ * share specified in the Tid field of the SMB header. If Tid in the SMB
+ * header refers to a print share, this SMB creates a new file which will
+ * be spooled to the printer when closed. In this case, FileName is
+ * ignored.
+ *
+ * SearchAttributes specifies the type of file desired. The encoding is
+ * described in the "File Attribute Encoding" section.
+ *
+ * DesiredAccess controls the mode under which the file is opened, and the
+ * file will be opened only if the client has the appropriate permissions.
+ * The encoding of DesiredAccess is discussed in the section entitled
+ * "Access Mode Encoding".
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 7
+ * USHORT Fid; File handle
+ * USHORT FileAttributes; Attributes of opened file
+ * UTIME LastWriteTime; Time file was last written
+ * ULONG DataSize; File size
+ * USHORT GrantedAccess; Access allowed
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid is the handle value which should be used for subsequent file
+ * operations.
+ *
+ * FileAttributes specifies the type of file obtained. The encoding is
+ * described in the "File Attribute Encoding" section.
+ *
+ * GrantedAccess indicates the access permissions actually allowed, and may
+ * have one of the following values:
+ *
+ * 0 read-only
+ * 1 write-only
+ * 2 read/write
+ *
+ * File Handles (Fids) are scoped per client. A Pid may reference any Fid
+ * established by itself or any other Pid on the client (so far as the
+ * server is concerned). The actual accesses allowed through the Fid
+ * depends on the open and deny modes specified when the file was opened
+ * (see below).
+ *
+ * The MS-DOS compatibility mode of file open provides exclusion at the
+ * client level. A file open in compatibility mode may be opened (also in
+ * compatibility mode) any number of times for any combination of reading
+ * and writing (subject to the user's permissions) by any Pid on the same
+ * client. If the first client has the file open for writing, then the
+ * file may not be opened in any way by any other client. If the first
+ * client has the file open only for reading, then other clients may open
+ * the file, in compatibility mode, for reading.. The above
+ * notwithstanding, if the filename has an extension of .EXE, .DLL, .SYM,
+ * or .COM other clients are permitted to open the file regardless of
+ * read/write open modes of other compatibility mode opens. However, once
+ * multiple clients have the file open for reading, no client is permitted
+ * to open the file for writing and no other client may open the file in
+ * any mode other than compatibility mode.
+ *
+ * The other file exclusion modes (Deny read/write, Deny write, Deny read,
+ * Deny none) provide exclusion at the file level. A file opened in any
+ * "Deny" mode may be opened again only for the accesses allowed by the
+ * Deny mode (subject to the user's permissions). This is true regardless
+ * of the identity of the second opener -a different client, a Pid from the
+ * same client, or the Pid that already has the file open. For example, if
+ * a file is open in "Deny write" mode a second open may only obtain read
+ * permission to the file.
+ *
+ * Although Fids are available to all Pids on a client, Pids other than the
+ * owner may not have the full access rights specified in the open mode by
+ * the Fid's creator. If the open creating the Fid specified a deny mode,
+ * then any Pid using the Fid, other than the creating Pid, will have only
+ * those access rights determined by "anding" the open mode rights and the
+ * deny mode rights, i.e., the deny mode is checked on all file accesses.
+ * For example, if a file is opened for Read/Write in Deny write mode, then
+ * other clients may only read the file and cannot write; if a file is
+ * opened for Read in Deny read mode, then the other clients can neither
+ * read nor write the file.
+ */
+
+int
+smb_com_open(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint16_t file_attr;
+ DWORD status;
+
+ bzero(op, sizeof (sr->arg.open));
+ if (smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.srch_attr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
+ (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->dsize = 0; /* Don't set spurious size */
+ op->utime.tv_sec = op->utime.tv_nsec = 0;
+ op->create_disposition = FILE_OPEN;
+ op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
+ ? FILE_WRITE_THROUGH : 0;
+
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
+ op->my_flags = MYF_BATCH_OPLOCK;
+ } else {
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ }
+ }
+
+ if ((status = smb_open_subr(sr)) != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
+ sr->smb_flg &=
+ ~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
+ }
+
+ if (op->dsize > 0xffffffff)
+ smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
+
+ file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
+
+ smbsr_encode_result(sr, 7, 0, "bwwllww",
+ 7,
+ sr->smb_fid,
+ file_attr,
+ smb_gmt_to_local_time(op->utime.tv_sec),
+ (uint32_t)op->dsize,
+ op->omode & SMB_DA_ACCESS_MASK,
+ (uint16_t)0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+int
+smb_com_open_andx(struct smb_request *sr)
+{
+ struct open_param *op = &sr->arg.open;
+ uint16_t flags;
+ uint32_t CreationTime;
+ uint16_t granted_access;
+ uint16_t ofun;
+ uint16_t file_attr;
+ int count;
+ DWORD status;
+ int rc;
+
+ bzero(op, sizeof (sr->arg.open));
+ op->dsize = 0;
+ rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
+ &sr->andx_off, &flags, &op->omode, &op->fqi.srch_attr,
+ &file_attr, &CreationTime, &ofun, &op->dsize, &op->timeo);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%u", sr, &op->fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
+ (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->dattr = file_attr;
+ op->create_disposition = smb_ofun_to_crdisposition(ofun);
+ if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) {
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_PARAMETER);
+ /* NOTREACHED */
+ }
+
+ op->create_options = (op->omode & SMB_DA_WRITE_THROUGH)
+ ? FILE_WRITE_THROUGH : 0;
+
+ if (flags & 2)
+ op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ else if (flags & 4)
+ op->my_flags = MYF_BATCH_OPLOCK;
+
+ if ((CreationTime != 0) && (CreationTime != 0xffffffff))
+ op->utime.tv_sec = smb_local_time_to_gmt(CreationTime);
+ op->utime.tv_nsec = 0;
+
+ status = NT_STATUS_SUCCESS;
+ /*
+ * According to NT, when exclusive share access failed,
+ * instead of raising "access deny" error immediately,
+ * we should wait for the client holding the exclusive
+ * file to close the file. If the wait timed out, we
+ * report a sharing violation; otherwise, we grant access.
+ * smb_open_subr returns NT_STATUS_SHARING_VIOLATION when
+ * it encounters an exclusive share access deny: we wait
+ * and retry.
+ */
+ for (count = 0; count <= 4; count++) {
+ if (count) {
+ delay(MSEC_TO_TICK(400));
+ }
+
+ if ((status = smb_open_subr(sr)) == NT_STATUS_SUCCESS)
+ break;
+ }
+
+ if (status != NT_STATUS_SUCCESS) {
+ if (status == NT_STATUS_SHARING_VIOLATION)
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ else
+ smbsr_raise_nt_error(sr, status);
+
+ /* NOTREACHED */
+ }
+
+ if (op->dsize > 0xffffffff)
+ smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
+
+ if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
+ op->action_taken |= SMB_OACT_LOCK;
+ } else {
+ op->action_taken &= ~SMB_OACT_LOCK;
+ }
+
+ granted_access = (sr->tid_tree->t_access == SMB_TREE_READ_ONLY)
+ ? SMB_DA_ACCESS_READ : op->omode & SMB_DA_ACCESS_MASK;
+
+ file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smb_node_t *node = sr->fid_ofile->f_node;
+ smbsr_encode_result(sr, 15, 0,
+ "b b.w w wll www wl 2. w",
+ 15,
+ sr->andx_com, VAR_BCC,
+ sr->smb_fid,
+ file_attr,
+ smb_gmt_to_local_time(node->attr.sa_vattr.va_mtime.tv_sec),
+ (uint32_t)op->dsize,
+ granted_access, op->ftype,
+ op->devstate,
+ op->action_taken, op->fileid,
+ 0);
+ } else {
+ smbsr_encode_result(sr, 15, 0,
+ "b b.w w wll www wl 2. w",
+ 15,
+ sr->andx_com, VAR_BCC,
+ sr->smb_fid,
+ file_attr,
+ 0L,
+ 0L,
+ granted_access, op->ftype,
+ op->devstate,
+ op->action_taken, op->fileid,
+ 0);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
new file mode 100644
index 0000000000..cacbbb3e9d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
@@ -0,0 +1,539 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <sys/pathname.h>
+#include <sys/sdt.h>
+
+uint32_t
+smb_is_executable(char *path)
+{
+ char extension[5];
+ int len = strlen(path);
+
+ if ((len >= 4) && (path[len - 4] == '.')) {
+ (void) strcpy(extension, &path[len - 3]);
+ (void) utf8_strupr(extension);
+
+ if (strcmp(extension, "EXE") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+
+ if (strcmp(extension, "COM") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+
+ if (strcmp(extension, "DLL") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+
+ if (strcmp(extension, "SYM") == 0)
+ return (NODE_FLAGS_EXECUTABLE);
+ }
+
+ return (0);
+}
+
+/*
+ * smbd_fs_query
+ *
+ * This function has been changed to return errors instead of using
+ * smbsr_raise_errno to longjmp round the calling code. This allows
+ * the caller to release resources when an error occurs.
+ *
+ * Upon success, the caller will need to call smb_node_release() on
+ * fqi.last_snode (if it isn't already set to NULL by this routine) and
+ * and fqi.dir_snode. These pointers will not be used after the caller
+ * is done with them and should be released immediately. (The position
+ * of smb_fqi in a union in the smb_request structure makes it difficult
+ * to free these pointers at smb_request deallocation time.)
+ *
+ * If smbd_fs_query() returns error, no smb_nodes will need to be released
+ * by callers as a result of references taken in this routine, and
+ * fqi.last_snode and fqi.dir_snode will be set to NULL.
+ */
+
+int
+smbd_fs_query(struct smb_request *sr, struct smb_fqi *fqi, int fqm)
+{
+ int rc;
+
+ fqi->last_comp_was_found = 0;
+
+ rc = smb_pathname_reduce(sr, sr->user_cr, fqi->path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &fqi->dir_snode,
+ fqi->last_comp);
+
+ if (rc)
+ return (rc);
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, fqi->dir_snode, fqi->last_comp,
+ &fqi->last_snode, &fqi->last_attr, 0, 0);
+
+ if (rc == 0) {
+ fqi->last_comp_was_found = 1;
+ (void) strcpy(fqi->last_comp_od,
+ fqi->last_snode->od_name);
+
+ if (fqm == FQM_PATH_MUST_NOT_EXIST) {
+ smb_node_release(fqi->dir_snode);
+ smb_node_release(fqi->last_snode);
+ SMB_NULL_FQI_NODES(*fqi);
+ return (EEXIST);
+ }
+
+ return (0);
+ }
+
+ if (fqm == FQM_PATH_MUST_EXIST) {
+ smb_node_release(fqi->dir_snode);
+ SMB_NULL_FQI_NODES(*fqi);
+ return (rc);
+ }
+
+ if (rc == ENOENT) {
+ fqi->last_snode = NULL;
+ return (0);
+ }
+
+ smb_node_release(fqi->dir_snode);
+ SMB_NULL_FQI_NODES(*fqi);
+
+ return (rc);
+}
+
+/*
+ * smb_pathname_reduce
+ *
+ * smb_pathname_reduce() takes a path and returns the smb_node for the
+ * second-to-last component of the path. It also returns the name of the last
+ * component. Pointers for both of these fields must be supplied by the caller.
+ *
+ * Upon success, 0 is returned.
+ *
+ * Upon error, *dir_node will be set to 0.
+ *
+ * *sr (in)
+ * ---
+ * smb_request structure pointer
+ *
+ * *cred (in)
+ * -----
+ * credential
+ *
+ * *path (in)
+ * -----
+ * pathname to be looked up
+ *
+ * *share_root_node (in)
+ * ----------------
+ * File operations which are share-relative should pass sr->tid_tree->t_snode.
+ * If the call is not for a share-relative operation, this parameter must be 0
+ * (e.g. the call from smbsr_setup_share()). (Such callers will have path
+ * operations done using root_smb_node.) This parameter is used to determine
+ * whether mount points can be crossed.
+ *
+ * share_root_node should have at least one reference on it. This reference
+ * will stay intact throughout this routine.
+ *
+ * *cur_node (in)
+ * ---------
+ * The smb_node for the current directory (for relative paths).
+ * cur_node should have at least one reference on it.
+ * This reference will stay intact throughout this routine.
+ *
+ * **dir_node (out)
+ * ----------
+ * Directory for the penultimate component of the original path.
+ * (Note that this is not the same as the parent directory of the ultimate
+ * target in the case of a link.)
+ *
+ * The directory smb_node is returned held. The caller will need to release
+ * the hold or otherwise make sure it will get released (e.g. in a destroy
+ * routine if made part of a global structure).
+ *
+ * last_component (out)
+ * --------------
+ * The last component of the path. (This may be different from the name of any
+ * link target to which the last component may resolve.)
+ *
+ *
+ * ____________________________
+ *
+ * The CIFS server lookup path needs to have logic equivalent to that of
+ * smb_fsop_lookup(), smb_vop_lookup() and other smb_vop_*() routines in the
+ * following areas:
+ *
+ * - non-traversal of child mounts (handled by smb_pathname_reduce)
+ * - unmangling (handled in smb_pathname)
+ * - "chroot" behavior of share root (handled by lookuppnvp)
+ *
+ * In addition, it needs to replace backslashes with forward slashes. It also
+ * ensures that link processing is done correctly, and that directory
+ * information requested by the caller is correctly returned (i.e. for paths
+ * with a link in the last component, the directory information of the
+ * link and not the target needs to be returned).
+ */
+
+int
+smb_pathname_reduce(
+ smb_request_t *sr,
+ cred_t *cred,
+ const char *path,
+ smb_node_t *share_root_node,
+ smb_node_t *cur_node,
+ smb_node_t **dir_node,
+ char *last_component)
+{
+ smb_node_t *root_node;
+ struct pathname ppn;
+ char *usepath;
+ int lookup_flags = FOLLOW;
+ int trailing_slash = 0;
+ int err = 0;
+ int len;
+
+ ASSERT(dir_node);
+ ASSERT(last_component);
+
+ *dir_node = NULL;
+ *last_component = '\0';
+
+ if (SMB_TREE_CASE_INSENSITIVE(sr))
+ lookup_flags |= FIGNORECASE;
+
+ if (path == NULL)
+ return (EINVAL);
+
+ if (*path == '\0')
+ return (ENOENT);
+
+ usepath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ if ((len = strlcpy(usepath, path, MAXPATHLEN)) >= MAXPATHLEN) {
+ kmem_free(usepath, MAXPATHLEN);
+ return (ENAMETOOLONG);
+ }
+
+ (void) strsubst(usepath, '\\', '/');
+
+ if (usepath[len - 1] == '/')
+ trailing_slash = 1;
+
+ (void) strcanon(usepath, "/");
+
+ if (share_root_node)
+ root_node = share_root_node;
+ else
+ root_node = smb_info.si_root_smb_node;
+
+ if (cur_node == NULL)
+ cur_node = root_node;
+
+ (void) pn_alloc(&ppn);
+
+ if ((err = pn_set(&ppn, usepath)) != 0) {
+ (void) pn_free(&ppn);
+ kmem_free(usepath, MAXPATHLEN);
+ return (err);
+ }
+
+ /*
+ * If a path does not have a trailing slash, strip off the
+ * last component. (We only need to return an smb_node for
+ * the second to last component; a name is returned for the
+ * last component.)
+ */
+
+ if (trailing_slash) {
+ (void) strlcpy(last_component, ".", MAXNAMELEN);
+ } else {
+ (void) pn_setlast(&ppn);
+ (void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
+ ppn.pn_path[0] = '\0';
+ }
+
+ if (strcmp(ppn.pn_buf, "/") == 0) {
+ smb_node_ref(root_node);
+ *dir_node = root_node;
+ } else if (ppn.pn_buf[0] == '\0') {
+ smb_node_ref(cur_node);
+ *dir_node = cur_node;
+ } else {
+ err = smb_pathname(sr, ppn.pn_buf, lookup_flags, root_node,
+ cur_node, NULL, dir_node, cred);
+ }
+
+ (void) pn_free(&ppn);
+ kmem_free(usepath, MAXPATHLEN);
+
+ /*
+ * Prevent access to anything outside of the share root, except
+ * when mapping a share because that may require traversal from
+ * / to a mounted file system. share_root_node is NULL when
+ * mapping a share.
+ *
+ * Note that we disregard whether the traversal of the path went
+ * outside of the file system and then came back (say via a link).
+ */
+
+ if ((err == 0) && share_root_node) {
+ if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp)
+ err = EACCES;
+ }
+
+ if (err) {
+ if (*dir_node) {
+ (void) smb_node_release(*dir_node);
+ *dir_node = NULL;
+ }
+ *last_component = 0;
+ }
+
+ return (err);
+}
+
+/*
+ * smb_pathname() - wrapper to lookuppnvp(). Handles name unmangling.
+ *
+ * *dir_node is the true directory of the target *node.
+ *
+ * If any component but the last in the path is not found, ENOTDIR instead of
+ * ENOENT will be returned.
+ *
+ * Path components are processed one at a time so that smb_nodes can be
+ * created for each component. This allows the dir_snode field in the
+ * smb_node to be properly populated.
+ *
+ * Mangle checking is also done on each component.
+ */
+
+int
+smb_pathname(
+ smb_request_t *sr,
+ char *path,
+ int flags,
+ smb_node_t *root_node,
+ smb_node_t *cur_node,
+ smb_node_t **dir_node,
+ smb_node_t **ret_node,
+ cred_t *cred)
+{
+ char *component = NULL;
+ char *real_name = NULL;
+ char *namep;
+ struct pathname pn;
+ struct pathname rpn;
+ struct pathname upn;
+ struct pathname link_pn;
+ smb_node_t *dnode = NULL;
+ smb_node_t *fnode = NULL;
+ vnode_t *rootvp;
+ vnode_t *dvp;
+ vnode_t *vp = NULL;
+ smb_attr_t attr;
+ size_t pathleft;
+ int err = 0;
+ int nlink = 0;
+ int local_flags;
+
+ if (path == NULL)
+ return (EINVAL);
+
+ ASSERT(root_node);
+ ASSERT(cur_node);
+ ASSERT(ret_node);
+
+ *ret_node = NULL;
+
+ if (dir_node)
+ *dir_node = NULL;
+
+ (void) pn_alloc(&upn);
+
+ if ((err = pn_set(&upn, path)) != 0) {
+ (void) pn_free(&upn);
+ return (err);
+ }
+
+ (void) pn_alloc(&pn);
+ (void) pn_alloc(&rpn);
+
+ component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ real_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ dnode = cur_node;
+ smb_node_ref(dnode);
+
+ rootvp = (vnode_t *)root_node->vp;
+
+ /*
+ * Instead of passing the FOLLOW flag to lookuppnvp(), process links in
+ * this routine. This allows smb_nodes to be created for each component
+ * of a link.
+ */
+ local_flags = flags & FIGNORECASE;
+
+ /*
+ * Path components are processed one at a time so that smb_nodes
+ * can be created for each component. This allows the dir_snode
+ * field in the smb_node to be properly populated.
+ *
+ * Mangle checking is also done on each component.
+ */
+ while ((pathleft = pn_pathleft(&upn)) != 0) {
+ if (fnode) {
+ smb_node_release(dnode);
+ dnode = fnode;
+ fnode = NULL;
+ }
+
+ if ((err = pn_getcomponent(&upn, component)) != 0)
+ break;
+
+ if (smb_maybe_mangled_name(component)) {
+ if ((err = smb_unmangle_name(sr, cred, dnode,
+ component, real_name, MAXNAMELEN, 0, 0,
+ 1)) != 0)
+ break;
+
+ namep = real_name;
+ } else {
+ namep = component;
+ }
+
+ if ((err = pn_set(&pn, namep)) != 0)
+ break;
+
+ /*
+ * Holds on dvp and rootvp (if not rootdir) are
+ * required by lookuppnvp() and will be released within
+ * that routine.
+ */
+ vp = NULL;
+ dvp = dnode->vp;
+
+ VN_HOLD(dvp);
+ if (rootvp != rootdir)
+ VN_HOLD(rootvp);
+
+ err = lookuppnvp(&pn, &rpn, local_flags, NULL, &vp, rootvp, dvp,
+ cred);
+
+ if (err)
+ break;
+
+ if ((vp->v_type == VLNK) &&
+ ((flags & FOLLOW) || pn_pathleft(&upn))) {
+
+ if (++nlink > MAXSYMLINKS) {
+ err = ELOOP;
+ break;
+ }
+
+ (void) pn_alloc(&link_pn);
+ err = pn_getsymlink(vp, &link_pn, cred);
+
+ if (err) {
+ (void) pn_free(&link_pn);
+ break;
+ }
+
+ if (pn_pathleft(&link_pn) == 0)
+ (void) pn_set(&link_pn, ".");
+ err = pn_insert(&upn, &link_pn, strlen(namep));
+ pn_free(&link_pn);
+
+ if (err)
+ break;
+
+ if (upn.pn_pathlen == 0) {
+ err = ENOENT;
+ break;
+ }
+
+ if (upn.pn_path[0] == '/') {
+ fnode = root_node;
+ smb_node_ref(fnode);
+ }
+
+ if (pn_fixslash(&upn))
+ flags |= FOLLOW;
+
+ } else {
+ if (flags & FIGNORECASE) {
+ if (strcmp(rpn.pn_path, "/") != 0)
+ pn_setlast(&rpn);
+
+ namep = rpn.pn_path;
+ } else
+ namep = pn.pn_path;
+
+ fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
+ dnode, NULL, &attr);
+
+ if (fnode == NULL) {
+ err = ENOMEM;
+ break;
+ }
+ }
+
+ while (upn.pn_path[0] == '/') {
+ upn.pn_path++;
+ upn.pn_pathlen--;
+ }
+ }
+
+ /*
+ * Since no parent vp was passed to lookuppnvp(), all
+ * ENOENT errors are returned as ENOENT
+ */
+
+ if ((pathleft) && (err == ENOENT))
+ err = ENOTDIR;
+
+ if (err) {
+ if (fnode)
+ smb_node_release(fnode);
+ if (dnode)
+ smb_node_release(dnode);
+ } else {
+ *ret_node = fnode;
+
+ if (dir_node)
+ *dir_node = dnode;
+ else
+ smb_node_release(dnode);
+ }
+
+ kmem_free(component, MAXNAMELEN);
+ kmem_free(real_name, MAXNAMELEN);
+ (void) pn_free(&pn);
+ (void) pn_free(&rpn);
+ (void) pn_free(&upn);
+
+ return (err);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_print.c b/usr/src/uts/common/fs/smbsrv/smb_print.c
new file mode 100644
index 0000000000..13f3746b06
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_print.c
@@ -0,0 +1,253 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB print interface.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_open_print_file
+ *
+ * This message is sent to create a new printer file which will be deleted
+ * once it has been closed and printed.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT SetupLength; Length of printer setup data
+ * USHORT Mode; 0 = Text mode (DOS expands TABs)
+ * 1 = Graphics mode
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING IdentifierString[]; Identifier string
+ *
+ * Tid in the SMB header must refer to a printer resource type.
+ *
+ * SetupLength is the number of bytes in the first part of the resulting
+ * print spool file which contains printer-specific control strings.
+ *
+ * Mode can have the following values:
+ *
+ * 0 Text mode. The server may optionally
+ * expand tabs to a series of spaces.
+ * 1 Graphics mode. No conversion of data
+ * should be done by the server.
+ *
+ * IdentifierString can be used by the server to provide some sort of per-
+ * client identifying component to the print file.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid is the returned handle which may be used by subsequent write and
+ * close operations. When the file is finally closed, it will be sent to
+ * the spooler and printed.
+ *
+ * 4.5.1.1 Errors
+ *
+ * ERRDOS/ERRnoaccess
+ * ERRDOS/ERRnofids
+ * ERRSRV/ERRinvdevice
+ * ERRSRV/ERRbaduid
+ * ERRSRV/ERRqfull
+ * ERRSRV/ERRqtoobig
+ */
+int /*ARGSUSED*/
+smb_com_open_print_file(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_close_print_file
+ *
+ *
+ * This message invalidates the specified file handle and queues the file
+ * for printing.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid refers to a file previously created with SMB_COM_OPEN_PRINT_FILE.
+ * On successful completion of this request, the file is queued for
+ * printing by the server.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Servers which negotiate dialects of LANMAN1.0 and newer allow all the
+ * other types of Fid closing requests to invalidate the Fid and begin
+ * spooling.
+ */
+int /*ARGSUSED*/
+smb_com_close_print_file(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * smb_com_get_print_queue
+ *
+ * This message obtains a list of the elements currently in the print queue
+ * on the server.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT MaxCount; Max number of entries to return
+ * USHORT StartIndex; First queue entry to return
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * StartIndex specifies the first entry in the queue to return.
+ *
+ * MaxCount specifies the maximum number of entries to return, this may be
+ * a positive or negative number. A positive number requests a forward
+ * search, a negative number indicates a backward search.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT Count; Number of entries returned
+ * USHORT RestartIndex; Index of entry after last
+ * returned
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR BufferFormat; 0x01 -- Data block
+ * USHORT DataLength; Length of data
+ * UCHAR Data[]; Queue elements
+ *
+ * Count indicates how many entries were actually returned. RestartIndex
+ * is the index of the entry following the last entry returned; it may be
+ * used as the StartIndex in a subsequent request to resume the queue
+ * listing.
+ *
+ * The format of each returned queue element is:
+ *
+ * Queue Element Member Description
+ * ================================ ===================================
+ *
+ * SMB_DATE FileDate; Date file was queued
+ * SMB_TIME FileTime; Time file was queued
+ * UCHAR Status; Entry status. One of:
+ * 01 = held or stopped
+ * 02 = printing
+ * 03 = awaiting print
+ * 04 = in intercept
+ * 05 = file had error
+ * 06 = printer error
+ * 07-FF = reserved
+ * USHORT SpoolFileNumber; Assigned by the spooler
+ * ULONG SpoolFileSize; Number of bytes in spool file
+ * UCHAR Reserved;
+ * UCHAR SpoolFileName[16]; Client which created the spool file
+ *
+ * SMB_COM_GET_PRINT_QUEUE will return less than the requested number of
+ * elements only when the top or end of the queue is encountered.
+ *
+ * Support for this SMB is server optional. In particular, no current
+ * Microsoft client software issues this request.
+ *
+ * 4.5.2.1 Errors
+ *
+ * ERRHRD/ERRnotready
+ * ERRHRD/ERRerror
+ * ERRSRV/ERRbaduid
+ */
+int
+smb_com_get_print_queue(struct smb_request *sr)
+{
+ unsigned short max_count, start_ix;
+
+ if (smbsr_decode_vwv(sr, "ww", &max_count, &start_ix) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 2, 3, "bwwwbw", 2, 0, 0, 3, 1, 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_com_write_print_file
+ *
+ * This message is sent to write bytes into a print spool file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes; min = 4
+ * UCHAR BufferFormat; 0x01 -- Data block
+ * USHORT DataLength; Length of data
+ * UCHAR Data[]; Data
+ *
+ * Fid indicates the print spool file to be written, it must refer to a
+ * print spool file.
+ *
+ * ByteCount specifies the number of bytes to be written, and must be less
+ * than MaxBufferSize for the Tid specified.
+ *
+ * Data contains the bytes to append to the print spool file. The first
+ * SetupLength bytes in the resulting print spool file contain printer
+ * setup data. SetupLength is specified in the SMB_COM_OPEN_PRINT_FILE SMB
+ * request.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Servers which negotiate a protocol dialect of LANMAN1.0 or later also
+ * support the application of normal write requests to print spool files.
+ *
+ */
+int /*ARGSUSED*/
+smb_com_write_print_file(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_process_exit.c b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
new file mode 100644
index 0000000000..40d49ea17f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c
@@ -0,0 +1,84 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: process_exit
+ *
+ * This command informs the server that a client process has terminated.
+ * The server must close all files opened by Pid in the SMB header. This
+ * must automatically release all locks the process holds.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * This SMB should not generate any errors from the server, unless the
+ * server is a user mode server and Uid in the SMB header is invalid.
+ *
+ * Clients are not required to send this SMB, they can do all cleanup
+ * necessary by sending close SMBs to the server to release resources. In
+ * fact, clients who have negotiated LANMAN 1.0 and later probably do not
+ * send this message at all.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_process_exit(struct smb_request *sr)
+{
+ sr->uid_user = smb_user_lookup_by_uid(sr->session, &sr->user_cr,
+ sr->smb_uid);
+ if (sr->uid_user == NULL) {
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+ }
+
+ /*
+ * If request has a valid tree ID, only look for the PID within
+ * that tree. Otherwise look in all the trees. smbtorture seems
+ * to be the only thing that sends this request these days and
+ * it doesn't provide a TID.
+ */
+ sr->tid_tree = smb_tree_lookup_by_tid(sr->uid_user, sr->smb_tid);
+ if (sr->tid_tree != NULL) {
+ smb_ofile_close_all_by_pid(sr->tid_tree, sr->smb_pid);
+ smb_odir_close_all_by_pid(sr->tid_tree, sr->smb_pid);
+ } else {
+ smb_tree_close_all_by_pid(sr->uid_user, sr->smb_pid);
+ }
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information.c b/usr/src/uts/common/fs/smbsrv/smb_query_information.c
new file mode 100644
index 0000000000..8cb636aaa9
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c
@@ -0,0 +1,128 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: query_information
+ *
+ * This request is sent to obtain information about a file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * FileName is the fully qualified name of the file relative to the Tid in
+ * the header.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 10
+ * USHORT FileAttributes;
+ * UTIME LastWriteTime; Time of last write
+ * ULONG FileSize; File size
+ * USHORT Reserved [5]; Reserved - client should ignore
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * FileAttributes are as described in the "Attributes Encoding" section of
+ * this document.
+ *
+ * Note that FileSize is limited to 32 bits, this request is inappropriate
+ * for files whose size is too large.
+ *
+ * NOTES:
+ * Some clients send a NULL file name. Right now we return ERRbadfile
+ * until we find out what a MS client would send...
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_query_information(struct smb_request *sr)
+{
+ int rc;
+ unsigned short dattr;
+ uint32_t write_time, file_size;
+ char *path;
+ struct smb_node *dir_node;
+ struct smb_node *node;
+ smb_attr_t attr;
+ char *name;
+ timestruc_t *mtime;
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Some MS clients pass NULL file names
+ * NT interprets this as "\"
+ */
+ if (strlen(path) == 0) path = "\\";
+
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
+ != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, name, &node, &attr, 0, 0)) != 0) {
+ smb_node_release(dir_node);
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dir_node);
+
+ dattr = smb_node_get_dosattr(node);
+ mtime = smb_node_get_mtime(node);
+ write_time = smb_gmt_to_local_time(mtime->tv_sec);
+ file_size = (uint32_t)smb_node_get_size(node, &node->attr);
+
+ smb_node_release(node);
+
+ smbsr_encode_result(sr, 10, 0, "bwll10.w",
+ 10, /* wct */
+ dattr,
+ write_time, /* Last write time */
+ file_size, /* FileSize */
+ 0); /* bcc */
+
+ kmem_free(name, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
new file mode 100644
index 0000000000..a1324aa74e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: query_information2
+ *
+ * This SMB is gets information about the file represented by Fid.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT Fid; File handle
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 11
+ * SMB_DATE CreationDate;
+ * SMB_TIME CreationTime;
+ * SMB_DATE LastAccessDate;
+ * SMB_TIME LastAccessTime;
+ * SMB_DATE LastWriteDate;
+ * SMB_TIME LastWriteTime;
+ * ULONG FileDataSize; File end of data
+ * ULONG FileAllocationSize; File allocation size
+ * USHORT FileAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 0
+ *
+ * The file being interrogated is specified by Fid, which must possess at
+ * least read permission.
+ *
+ * FileAttributes are described in the "File Attribute Encoding" section
+ * elsewhere in this document.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_query_information2(struct smb_request *sr)
+{
+ smb_node_t *node;
+ smb_attr_t *attr;
+ uint32_t dsize, dasize;
+ unsigned short dattr;
+
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+
+ if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
+ cmn_err(CE_NOTE, "SmbQueryInfo2: access denied");
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ node = sr->fid_ofile->f_node;
+ attr = &node->attr;
+
+ dattr = smb_node_get_dosattr(node);
+ dasize = attr->sa_vattr.va_blksize * attr->sa_vattr.va_nblocks;
+ dsize = (dattr & SMB_FA_DIRECTORY) ? 0 : attr->sa_vattr.va_size;
+
+ smbsr_encode_result(sr, 11, 0, "byyyllww",
+ 11, /* wct */
+ smb_gmt_to_local_time(attr->sa_crtime.tv_sec),
+ /* LastAccessTime */
+ smb_gmt_to_local_time(attr->sa_vattr.va_atime.tv_sec),
+ /* LastWriteTime */
+ smb_gmt_to_local_time(attr->sa_vattr.va_mtime.tv_sec),
+ dsize,
+ dasize,
+ dattr, /* FileAttributes */
+ 0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c b/usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c
new file mode 100644
index 0000000000..4c69d8516e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information_disk.c
@@ -0,0 +1,129 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: query_information_disk
+ *
+ * The SMB_COM_QUERY_INFORMATION_DISK command is used to determine the
+ * capacity and remaining free space on the drive hosting the directory
+ * structure indicated by Tid in the SMB header.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 5
+ * USHORT TotalUnits; Total allocation units per server
+ * USHORT BlocksPerUnit; Blocks per allocation unit
+ * USHORT BlockSize; Block size (in bytes)
+ * USHORT FreeUnits; Number of free units
+ * USHORT Reserved; Reserved (client should ignore)
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The blocking/allocation units used in this response may be independent
+ * of the actual physical or logical blocking/allocation algorithm(s) used
+ * internally by the server. However, they must accurately reflect the
+ * amount of space on the server.
+ *
+ * This SMB only returns 16 bits of information for each field, which may
+ * not be large enough for some disk systems. In particular TotalUnits is
+ * commonly > 64K. Fortunately, it turns out the all the client cares
+ * about is the total disk size, in bytes, and the free space, in bytes.
+ * So, it is reasonable for a server to adjust the relative values of
+ * BlocksPerUnit and BlockSize to accommodate. If after all adjustment,
+ * the numbers are still too high, the largest possible values for
+ * TotalUnit or FreeUnits (i.e. 0xFFFF) should be returned.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_query_information_disk(struct smb_request *sr)
+{
+ int rc;
+ struct statvfs64 df;
+ fsblkcnt64_t total_blocks, free_blocks;
+ unsigned long block_size, unit_size;
+ unsigned short blocks_per_unit, bytes_per_block;
+ unsigned short total_units, free_units;
+
+ if ((rc = smb_fsop_statfs(sr->user_cr, sr->tid_tree->t_snode, &df))
+ != 0)
+ smbsr_raise_errno(sr, rc);
+
+ unit_size = 1;
+ block_size = df.f_frsize;
+ total_blocks = df.f_blocks;
+ free_blocks = df.f_bavail;
+
+ /*
+ * It seems that DOS clients cannot handle block sizes
+ * bigger than 512 KB. So we have to set the block size at
+ * most to 512
+ */
+
+ while (block_size > 512) {
+ block_size >>= 1;
+ unit_size <<= 1;
+ }
+
+ /* adjust blocks and sizes until they fit into a word */
+
+ while (total_blocks >= 0xFFFF) {
+ total_blocks >>= 1;
+ free_blocks >>= 1;
+ if ((unit_size <<= 1) > 0xFFFF) {
+ unit_size >>= 1;
+ total_blocks = 0xFFFF;
+ free_blocks <<= 1;
+ break;
+ }
+ }
+
+ total_units = (total_blocks >= 0xFFFF) ?
+ 0xFFFF : (unsigned short)total_blocks;
+ free_units = (free_blocks >= 0xFFFF) ?
+ 0xFFFF : (unsigned short)free_blocks;
+ bytes_per_block = (unsigned short)block_size;
+ blocks_per_unit = (unsigned short)unit_size;
+
+ smbsr_encode_result(sr, 5, 0, "bwwww2.w",
+ 5,
+ total_units, /* total_units */
+ blocks_per_unit, /* blocks_per_unit */
+ bytes_per_block, /* blocksize */
+ free_units, /* free_units */
+ 0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_read.c b/usr/src/uts/common/fs/smbsrv/smb_read.c
new file mode 100644
index 0000000000..6554c07014
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c
@@ -0,0 +1,456 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/syslog.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+
+typedef struct smb_read_param {
+ uint64_t r_offset;
+ uint16_t r_count;
+ uint16_t r_mincnt;
+} smb_read_param_t;
+
+
+int smb_common_read(struct smb_request *sr, smb_read_param_t *param);
+
+
+/*
+ * Read bytes from a file or named pipe (SMB Core).
+ *
+ * The requested count specifies the number of bytes desired. Offset
+ * is limited to 32 bits, so this client request is inappropriate for
+ * files with 64 bit offsets.
+ *
+ * On return, count is the number of bytes actually being returned, which
+ * may be less than the count requested only if a read specifies bytes
+ * beyond the current file size. In this case only the bytes that exist
+ * are returned. A read completely beyond the end of file results in a
+ * response of length zero. This is the only circumstance when a zero
+ * length response is generated. A count returned which is less than the
+ * count requested is the end of file indicator.
+ */
+int
+smb_com_read(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ uint32_t off_low;
+ uint16_t remcnt;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
+ &param.r_count, &off_low, &remcnt);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param.r_offset = (uint64_t)off_low;
+ param.r_mincnt = 0;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_read(sr, &param)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
+ 5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data);
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/
+ * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
+ * attempt to use it on non-disk shares.
+ *
+ * The requested count specifies the number of bytes desired. Offset
+ * specifies the offset in the file of the first byte to be locked then
+ * read. Note that offset is limited to 32 bits, so this client request
+ * is inappropriate for files with 64 bit offsets.
+ *
+ * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
+ * immediately an error should be returned to the client. If an error
+ * occurs on the lock, the bytes should not be read.
+ *
+ * On return, count is the number of bytes actually being returned, which
+ * may be less than the count requested only if a read specifies bytes
+ * beyond the current file size. In this case only the bytes that exist
+ * are returned. A read completely beyond the end of file results in a
+ * response of length zero. This is the only circumstance when a zero
+ * length response is generated. A count returned which is less than the
+ * count requested is the end of file indicator.
+ */
+int
+smb_com_lock_and_read(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ uint16_t remcnt;
+ uint32_t off_low;
+ DWORD result;
+ int rc;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
+ &param.r_count, &off_low, &remcnt);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param.r_offset = (uint64_t)off_low;
+ param.r_mincnt = 0;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ result = smb_lock_range(sr, sr->fid_ofile, param.r_offset,
+ (uint64_t)param.r_count, 0xffffffff, SMB_LOCK_TYPE_READWRITE);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_lock_range_raise_error(sr, result);
+ }
+
+ if ((rc = smb_common_read(sr, &param)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
+ 5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data);
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
+ * SMB Core Plus to maximize performance when reading a large block
+ * of data from a server. This request was extended in LM 0.12 to
+ * support 64-bit offsets; the server can indicate support by setting
+ * CAP_LARGE_FILES in the negotiated capabilities.
+ *
+ * The client must guarantee that there is (and will be) no other request
+ * to the server for the duration of the SMB_COM_READ_RAW, since the
+ * server response has no header or trailer. To help ensure that there
+ * are no interruptions, we block all I/O for the session during read raw.
+ *
+ * If this is the first SMB request received since we sent an oplock break
+ * to this client, we don't know if it's safe to send the raw data because
+ * the requests may have crossed on the wire and the client may have
+ * interpreted the oplock break as part of the raw data. To avoid problems,
+ * we send a zero length session packet, which will force the client to
+ * retry the read.
+ *
+ * Read errors are handled by sending a zero length response.
+ */
+int
+smb_com_read_raw(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ smb_node_t *node;
+ uint32_t off_low;
+ uint32_t off_high;
+ uint32_t timeout;
+ int rc;
+
+ switch (sr->session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ if (sr->smb_wct == 8) {
+ rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
+ &off_low, &param.r_count, &param.r_mincnt,
+ &timeout);
+ param.r_offset = (uint64_t)off_low;
+ } else {
+ rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
+ &off_low, &param.r_count, &param.r_mincnt, &timeout,
+ &off_high);
+ param.r_offset = ((uint64_t)off_high << 32) | off_low;
+ }
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ rc = smb_common_read(sr, &param);
+ /*
+ * XXX Do we need to handle errors here? What if we have an
+ * access error (either permissions or range lock violations?
+ */
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ node = sr->fid_ofile->f_node;
+ if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
+ rc = EAGAIN;
+ }
+ }
+
+ if (rc != 0) {
+ (void) smb_session_send(sr->session, 0, NULL);
+ m_freem(sr->raw_data.chain);
+ sr->raw_data.chain = 0;
+ } else {
+ (void) smb_session_send(sr->session, 0, &sr->raw_data);
+ }
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ (void) smb_session_send(sr->session, 0, NULL);
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
+ ASSERT(0);
+ return (SDRC_DROP_VC);
+
+ case SMB_SESSION_STATE_TERMINATED:
+ ASSERT(0);
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_DISCONNECTED:
+ return (SDRC_NO_REPLY);
+
+ case SMB_SESSION_STATE_CONNECTED:
+ case SMB_SESSION_STATE_ESTABLISHED:
+ default:
+ ASSERT(0);
+ return (SDRC_DROP_VC);
+ }
+}
+
+/*
+ * Read bytes from a file (SMB Core). This request was extended in
+ * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
+ * 12 and including additional offset information.
+ */
+int
+smb_com_read_andx(struct smb_request *sr)
+{
+ smb_read_param_t param;
+ uint32_t off_low;
+ uint32_t off_high;
+ uint16_t remcnt;
+ uint16_t offset2;
+ uint8_t secondary;
+ int rc;
+
+ if (sr->smb_wct == 12) {
+ rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary,
+ &sr->smb_fid, &off_low, &param.r_count, &remcnt, &off_high);
+
+ param.r_offset = ((uint64_t)off_high << 32) | off_low;
+ } else {
+ rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary,
+ &sr->smb_fid, &off_low, &param.r_count, &remcnt);
+
+ param.r_offset = (uint64_t)off_low;
+ }
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param.r_mincnt = 0;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_read(sr, &param)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Ensure that the next response offset is zero
+ * if there is no secondary command.
+ */
+ offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59;
+
+ /*
+ * The STYPE_IPC response format is different.
+ * The unknown value (2) may be to indicate that it
+ * is a follow-up to an earlier RPC transaction.
+ */
+ if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
+ smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
+ 12, /* wct */
+ secondary, /* Secondary andx command */
+ offset2, /* offset to next */
+ 0, /* must be 0 */
+ param.r_count, /* data byte count */
+ 60, /* Offset from start to data */
+ VAR_BCC, /* BCC marker */
+ 0x02, /* unknown */
+ &sr->raw_data);
+ } else {
+ smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
+ 12, /* wct */
+ secondary, /* Secondary andx command */
+ offset2, /* offset to next */
+ -1, /* must be -1 */
+ param.r_count, /* data byte count */
+ 59, /* Offset from start to data */
+ VAR_BCC, /* BCC marker */
+ &sr->raw_data);
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Common function for reading files or IPC/MSRPC named pipes. All
+ * protocol read functions should lookup the fid before calling this
+ * function. We can't move the fid lookup here because lock-and-read
+ * requires the fid to do locking before attempting the read.
+ *
+ * Returns errno values.
+ */
+int
+smb_common_read(struct smb_request *sr, smb_read_param_t *param)
+{
+ smb_ofile_t *ofile = sr->fid_ofile;
+ smb_node_t *node;
+ struct vardata_block *vdb;
+ struct mbuf *top;
+ int rc;
+
+ vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
+ vdb->tag = 0;
+ vdb->uio.uio_iov = &vdb->iovec[0];
+ vdb->uio.uio_iovcnt = MAX_IOVEC;
+ vdb->uio.uio_resid = param->r_count;
+ vdb->uio.uio_offset = param->r_offset;
+ vdb->uio.uio_segflg = UIO_SYSSPACE;
+
+ switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ node = ofile->f_node;
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, node, param->r_offset,
+ param->r_count, FILE_READ_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ rc = ERANGE;
+ break;
+ }
+ }
+
+ (void) smb_sync_fsattr(sr, sr->user_cr, node);
+
+ sr->raw_data.max_bytes = vdb->uio.uio_resid;
+ top = smb_mbuf_allocate(&vdb->uio);
+
+ rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
+ &node->attr);
+
+ sr->raw_data.max_bytes -= vdb->uio.uio_resid;
+ smb_mbuf_trim(top, sr->raw_data.max_bytes);
+ MBC_ATTACH_MBUF(&sr->raw_data, top);
+ break;
+
+ case STYPE_IPC:
+ rc = smb_rpc_read(sr, &vdb->uio);
+ break;
+
+ default:
+ rc = EACCES;
+ break;
+ }
+
+ param->r_count -= vdb->uio.uio_resid;
+ kmem_free(vdb, sizeof (struct vardata_block));
+
+ if (rc != 0)
+ return (rc);
+
+ if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) {
+ /*
+ * mincnt is only used by read-raw and is typically
+ * zero. If mincnt is greater than zero and the
+ * number of bytes read is less than mincnt, tell
+ * the client that we read nothing.
+ */
+ param->r_count = 0;
+ }
+
+ param->r_offset += param->r_count;
+ mutex_enter(&sr->fid_ofile->f_mutex);
+ ofile->f_seek_pos = param->r_offset;
+ mutex_exit(&sr->fid_ofile->f_mutex);
+ return (rc);
+}
+
+/*
+ * The Read Block Multiplexed protocol is used to maximize performance
+ * when reading a large block of data from server to client while still
+ * allowing other operations to take place between the client and server
+ * in parallel.
+ *
+ * The mpx sub protocol is not supported because we support only
+ * connection oriented transports and NT supports SMB_COM_READ_MPX
+ * only over connectionless transports.
+ */
+/*ARGSUSED*/
+int
+smb_com_read_mpx(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+/*ARGSUSED*/
+int
+smb_com_read_mpx_secondary(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c
new file mode 100644
index 0000000000..f22e7187de
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c
@@ -0,0 +1,347 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/nterror.h>
+#include <sys/synch.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static int smb_do_rename(struct smb_request *sr,
+ struct smb_fqi *src_fqi,
+ struct smb_fqi *dst_fqi);
+
+
+/*
+ * smb_com_rename
+ *
+ * Rename a file. Files OldFileName must exist and NewFileName must not.
+ * Both pathnames must be relative to the Tid specified in the request.
+ * Open files may be renamed.
+ *
+ * Multiple files may be renamed in response to a single request as Rename
+ * File supports wildcards in the file name (last component of the path).
+ * NOTE: we don't support rename with wildcards.
+ *
+ * SearchAttributes indicates the attributes that the target file(s) must
+ * have. If SearchAttributes is zero then only normal files are renamed.
+ * If the system file or hidden attributes are specified then the rename
+ * is inclusive - both the specified type(s) of files and normal files are
+ * renamed. The encoding of SearchAttributes is described in section 3.10
+ * - File Attribute Encoding.
+ */
+int
+smb_com_rename(struct smb_request *sr)
+{
+ static kmutex_t mutex;
+ struct smb_fqi *src_fqi;
+ struct smb_fqi *dst_fqi;
+ struct smb_node *dst_node;
+ int rc;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ src_fqi = &sr->arg.dirop.fqi;
+ dst_fqi = &sr->arg.dirop.dst_fqi;
+
+ if (smbsr_decode_vwv(sr, "w", &src_fqi->srch_attr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->path, &dst_fqi->path);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ dst_fqi->srch_attr = 0;
+
+ mutex_enter(&mutex);
+ rc = smb_do_rename(sr, src_fqi, dst_fqi);
+ mutex_exit(&mutex);
+
+ if (rc != 0) {
+ /*
+ * ERROR_FILE_EXISTS doesn't work for Windows98 clients.
+ *
+ * Windows95 clients don't see this problem because the target
+ * is deleted before the rename request.
+ *
+ * The following values are based on observed WFWG, Win9x,
+ * NT and W2K client behaviour.
+ */
+ if (rc == EEXIST) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_OBJECT_NAME_COLLISION,
+ ERRDOS, ERROR_ALREADY_EXISTS);
+ /* NOTREACHED */
+ }
+
+ if (rc == EPIPE) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_SHARING_VIOLATION,
+ ERRDOS, ERROR_SHARING_VIOLATION);
+ /* NOTREACHED */
+ }
+
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (src_fqi->dir_snode)
+ smb_node_release(src_fqi->dir_snode);
+
+ dst_node = dst_fqi->dir_snode;
+ if (dst_node) {
+ if (dst_node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
+ dst_node->flags |= NODE_FLAGS_CHANGED;
+ smb_process_node_notify_change_queue(dst_node);
+ }
+ smb_node_release(dst_node);
+ }
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_rename_share_check
+ *
+ * An open file can be renamed if
+ *
+ * 1. isn't opened for data writing or deleting
+ *
+ * 2. Opened with "Deny Delete" share mode
+ * But not opened for data reading or executing
+ * (opened for accessing meta data)
+ */
+DWORD
+smb_rename_share_check(struct smb_node *node)
+{
+ struct smb_ofile *open;
+
+ if (node == 0 || node->n_refcnt <= 1)
+ return (NT_STATUS_SUCCESS);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ open = smb_llist_head(&node->n_ofile_list);
+ while (open) {
+ if (open->f_granted_access &
+ (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+
+ if ((open->f_share_access & FILE_SHARE_DELETE) == 0) {
+ if (open->f_granted_access &
+ (FILE_READ_DATA | FILE_EXECUTE)) {
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SHARING_VIOLATION);
+ }
+ }
+ open = smb_llist_next(&node->n_ofile_list, open);
+ }
+ smb_llist_exit(&node->n_ofile_list);
+ return (NT_STATUS_SUCCESS);
+}
+
+
+/*
+ * smb_do_rename
+ *
+ * Backend to smb_com_rename to ensure that the rename operation is atomic.
+ * This function should be called within a mutual exclusion region. If the
+ * source and destination are identical, we don't actually do a rename, we
+ * just check that the conditions are right. If the source and destination
+ * files differ only in case, we a case-sensitive rename. Otherwise, we do
+ * a full case-insensitive rename.
+ *
+ * This function should always return errno values.
+ *
+ * Upon success, the last_snode's and dir_snode's of both src_fqi and dst_fqi
+ * are not released in this routine but in smb_com_rename().
+ */
+static int
+smb_do_rename(
+ struct smb_request *sr,
+ struct smb_fqi *src_fqi,
+ struct smb_fqi *dst_fqi)
+{
+ struct smb_node *src_node;
+ char *dstname;
+ DWORD status;
+ int rc;
+ int count;
+
+ if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) {
+ return (rc);
+ }
+
+ src_node = src_fqi->last_snode;
+
+ /*
+ * Break the oplock before access checks. If a client
+ * has a file open, this will force a flush or close,
+ * which may affect the outcome of any share checking.
+ */
+ if (OPLOCKS_IN_FORCE(src_node)) {
+ status = smb_break_oplock(sr, src_node);
+
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(src_node);
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (EACCES);
+ }
+ }
+
+ status = smb_lock_range_access(sr, src_node, 0, 0, FILE_WRITE_DATA);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_node_release(src_node);
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (EACCES);
+ }
+
+
+ for (count = 0; count <= 3; count++) {
+ if (count)
+ delay(MSEC_TO_TICK(400));
+ status = smb_rename_share_check(src_node);
+ if (status != NT_STATUS_SHARING_VIOLATION)
+ break;
+ }
+
+ smb_node_release(src_node);
+
+ if (status == NT_STATUS_SHARING_VIOLATION) {
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (EPIPE); /* = ERRbadshare */
+ }
+
+ if (utf8_strcasecmp(src_fqi->path, dst_fqi->path) == 0) {
+ if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) {
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (rc);
+ }
+
+ /*
+ * Because the fqm parameter to smbd_fs_query() was 0,
+ * a successful return value means that dst_fqi->last_snode
+ * may be NULL.
+ */
+ if (dst_fqi->last_snode)
+ smb_node_release(dst_fqi->last_snode);
+
+ rc = strcmp(src_fqi->last_comp_od, dst_fqi->last_comp);
+ if (rc == 0) {
+ smb_node_release(src_fqi->dir_snode);
+ smb_node_release(dst_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (0);
+ }
+
+ rc = smb_fsop_rename(sr, sr->user_cr,
+ src_fqi->dir_snode,
+ src_fqi->last_comp_od,
+ dst_fqi->dir_snode,
+ dst_fqi->last_comp);
+
+ if (rc != 0) {
+ smb_node_release(src_fqi->dir_snode);
+ smb_node_release(dst_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ }
+ return (rc);
+ }
+
+ rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
+ if (rc != 0) {
+ smb_node_release(src_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ return (rc);
+ }
+
+ /*
+ * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
+ * value, only dst_fqi->dir_snode is valid (dst_fqi->last_snode
+ * is NULL).
+ */
+
+ /*
+ * Use the unmangled form of the destination name if the
+ * source and destination names are the same and the source
+ * name is mangled. (We are taking a chance here, assuming
+ * that this is what the user wants.)
+ */
+
+ if ((smb_maybe_mangled_name(src_fqi->last_comp)) &&
+ (strcmp(src_fqi->last_comp, dst_fqi->last_comp) == 0)) {
+ dstname = src_fqi->last_comp_od;
+ } else {
+ dstname = dst_fqi->last_comp;
+ }
+
+ rc = smb_fsop_rename(sr, sr->user_cr,
+ src_fqi->dir_snode,
+ src_fqi->last_comp_od,
+ dst_fqi->dir_snode,
+ dstname);
+
+ if (rc != 0) {
+ smb_node_release(src_fqi->dir_snode);
+ smb_node_release(dst_fqi->dir_snode);
+
+ SMB_NULL_FQI_NODES(*src_fqi);
+ SMB_NULL_FQI_NODES(*dst_fqi);
+ }
+
+ return (rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rpc.c b/usr/src/uts/common/fs/smbsrv/smb_rpc.c
new file mode 100644
index 0000000000..394c5addbe
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_rpc.c
@@ -0,0 +1,532 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides a set of wrapper functions to interface to the
+ * RPC layer. Although this interface was originally implemented as a
+ * single transaction using an input buffer and an output buffer, it
+ * turns out that it really should have been a stream/pipe interface.
+ * This was first discovered when we noticed that Windows2000 was using
+ * smb_rpc_write and smb_rpc_read instead of smb_rpc_transact and then
+ * later when we tried to return a larger number of shares than would
+ * fit in a single transaction buffer.
+ *
+ * The interface is still limited by the buffers passed between this
+ * module and the RPC module but now it will support a buffer overflow
+ * and allow the client to read the remaining data on subsequent
+ * requests. Also note that the smb_rpc_write and smb_rpc_read calls
+ * are basically emulating the smb_rpc_transact function.
+ */
+
+#include <sys/ksynch.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mlsvc.h>
+
+
+/*
+ * This is the list of well-known RPC named pipes that we support.
+ * The full pipe path will be in the form \\PIPE\\SERVICE. The first
+ * part can be assumed, so all we need here are the service names.
+ */
+static char *rpc_named_pipes[] = {
+ "\\LSARPC",
+ "\\NETLOGON",
+ "\\SAMR",
+ "\\SPOOLSS",
+ "\\SRVSVC",
+ "\\SVCCTL",
+ "\\WINREG",
+ "\\WKSSVC",
+ "\\EVENTLOG"
+};
+
+
+/*
+ * This is a list of the port addresses for the named pipes above.
+ * We need to check that these are correct but nothing appears to
+ * rely on them so this is low priority.
+ */
+#if 0
+static char *rpc_np_ports[] = {
+ "\\PIPE\\",
+ "\\PIPE\\lsass",
+ "\\PIPE\\lsass",
+ "\\PIPE\\spoolss",
+ "\\PIPE\\ntsvcs",
+ "\\PIPE\\ntsvcs",
+ "\\PIPE\\winreg",
+ "\\PIPE\\ntsvcs",
+ "\\PIPE\\ntsvcs"
+};
+#endif
+
+
+static int smb_rpc_initialize(struct smb_request *sr, char *pipe_name);
+static uint32_t smb_rpc_fid(void);
+
+
+/*
+ * Named pipe I/O is serialized to ensure that each request has exclusive
+ * access to the in and out pipe data for the duration of the request.
+ */
+static void
+smb_rpc_enter(mlsvc_pipe_t *pi)
+{
+ mutex_enter(&pi->mutex);
+
+ while (pi->busy)
+ cv_wait(&pi->cv, &pi->mutex);
+
+ pi->busy = 1;
+ mutex_exit(&pi->mutex);
+}
+
+static void
+smb_rpc_exit(mlsvc_pipe_t *pi)
+{
+ mutex_enter(&pi->mutex);
+ pi->busy = 0;
+ cv_signal(&pi->cv);
+ mutex_exit(&pi->mutex);
+}
+
+/*
+ * smb_rpc_lookup
+ *
+ * Lookup a path to see if it's a well-known RPC named pipe.
+ *
+ * Returns a pointer to the pipe name (without any leading \'s) if the path
+ * refers to a well-known RPC named pipe. Otherwise returns a null pointer.
+ */
+char *
+smb_rpc_lookup(char *path)
+{
+ int i;
+ char *pipe_name;
+
+ if (path == 0) {
+ cmn_err(CE_WARN, "smb_rpc_lookup: invalid parameter");
+ return (0);
+ }
+
+ /*
+ * Skip past the static part of the pipe
+ * name if it appears in the path.
+ */
+ if (utf8_strncasecmp(path, "\\PIPE\\", 6) == 0)
+ path += 5;
+
+ for (i = 0;
+ i < sizeof (rpc_named_pipes) / sizeof (rpc_named_pipes[0]);
+ ++i) {
+ if (utf8_strcasecmp(path, rpc_named_pipes[i]) == 0) {
+ pipe_name = rpc_named_pipes[i];
+ pipe_name += strspn(pipe_name, "\\");
+
+ return (pipe_name);
+ }
+ }
+ return (0);
+}
+
+/*
+ * smb_rpc_open
+ *
+ * Open a well-known RPC named pipe. This routine should be called if
+ * a file open is requested on a share of type STYPE_IPC. If we
+ * recognize the pipe, we initialize the session data. This will setup
+ * a new ofile and insert it into the session file list.
+ *
+ * Returns 0 on success, Otherwise an NT status is returned to indicate
+ * an error.
+ */
+int
+smb_rpc_open(struct smb_request *sr)
+{
+ struct open_param *op;
+ char *pipe_name;
+ int status;
+
+ if (smb_winpipe_open() != 0)
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ op = &sr->arg.open;
+
+ if ((pipe_name = smb_rpc_lookup(op->fqi.path)) != 0) {
+ if ((status = smb_rpc_initialize(sr, pipe_name)) != 0)
+ return (status);
+
+ return (NT_STATUS_SUCCESS);
+ }
+
+ return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
+}
+
+
+/*
+ * smb_rpc_initialize
+ *
+ * Initialize various parts of the session data for a named pipe: open
+ * parameters and the ofile. There are a number of magic numbers in
+ * here that we need to identify but largely these values are ignored
+ * by the rest of the code. Insert the ofile into the session file list.
+ *
+ * Returns 0 on success, Otherwise an NT status is returned to indicate
+ * an error.
+ */
+static int
+smb_rpc_initialize(struct smb_request *sr, char *pipe_name)
+{
+ struct open_param *op;
+ struct smb_ofile *of;
+ smb_error_t err;
+
+ op = &sr->arg.open;
+ of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid,
+ op->desired_access, 0, op->share_access,
+ SMB_FTYPE_MESG_PIPE, pipe_name, smb_rpc_fid(), &err);
+ if (of == NULL)
+ return (err.status);
+
+ op->dsize = 0x01000;
+ op->utime.tv_sec = 0;
+ op->utime.tv_nsec = 0;
+ op->dattr = SMB_FA_NORMAL;
+ op->ftype = SMB_FTYPE_MESG_PIPE;
+ op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
+ op->devstate = SMB_PIPE_READMODE_MESSAGE
+ | SMB_PIPE_TYPE_MESSAGE
+ | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
+ op->fileid = of->f_fid;
+ op->create_options = 0;
+
+ sr->smb_fid = of->f_fid;
+ sr->fid_ofile = of;
+ return (0);
+}
+
+/*
+ * smb_rpc_transact
+ *
+ * This is the entry point for RPC transactions to provide a wrapper for
+ * the RPC layer. The SMB decoding and encoding is handled here so that
+ * the RPC layer doesn't have to deal with it. Both bind operations and
+ * RPC requests are handled here. The connection_fid is an arbitrary id
+ * used to associate RPC requests with a particular binding handle.
+ *
+ * The RPC library expects the input stream to contain the request data.
+ * It will build the output stream.
+ *
+ * If the data to be returned is larger than the client expects, we
+ * return as much as the client can handle and report a buffer overflow
+ * warning to inform the client that we have more data to return. The
+ * residual data remains in the output stream until the client claims
+ * it or closes the pipe.
+ */
+int
+smb_rpc_transact(struct smb_request *sr, struct uio *uio)
+{
+ struct smb_xa *xa;
+ mlsvc_pipe_t *pipe_info;
+ mlsvc_stream_t *streamin;
+ struct mbuf *mhead;
+ int mdrcnt;
+ int nbytes;
+ int rc;
+
+ ASSERT(sr->fid_ofile);
+ ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(sr->fid_ofile->f_pipe_info != NULL);
+
+ xa = sr->r_xa;
+ mdrcnt = xa->smb_mdrcnt;
+ pipe_info = sr->fid_ofile->f_pipe_info;
+
+ smb_rpc_enter(pipe_info);
+
+ if (pipe_info->fid == 0) {
+ smb_rpc_exit(pipe_info);
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERROR_INVALID_HANDLE);
+ /* NOTREACHED */
+ }
+
+ streamin = &pipe_info->input;
+ streamin->uio.uio_iov = uio->uio_iov;
+ streamin->uio.uio_iovcnt = uio->uio_iovcnt;
+ streamin->uio.uio_offset = 0;
+ streamin->uio.uio_resid = uio->uio_resid;
+ streamin->uio.uio_segflg = UIO_SYSSPACE;
+
+ nbytes = mdrcnt;
+
+ rc = smb_winpipe_call(sr, pipe_info, streamin, SMB_RPC_TRANSACT,
+ (uint32_t *)&nbytes);
+
+ if (rc != 0) {
+ smb_rpc_exit(pipe_info);
+ smbsr_raise_nt_error(sr,
+ NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID);
+ /* NOTREACHED */
+ }
+
+ /*
+ * We need to zero the input stream so that we don't try to
+ * flush it on close: the mbuf chain belongs to the SMB XA.
+ * Then reassign the stream to refer to the output/response.
+ */
+ if (nbytes > mdrcnt) {
+ /*
+ * We have more data to return than the client expects in the
+ * response to this request. So we send as much as the client
+ * can handle, mdrcnt, and store the rest in the output chain.
+ * The buffer overflow warning informs the client that we
+ * have more data to send. Typically, the client will call
+ * SmbRead&X, which will call smb_rpc_read, to get the data.
+ */
+
+ mhead = smb_mbuf_get(pipe_info->output, mdrcnt);
+ xa->rep_data_mb.max_bytes = mdrcnt;
+ MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
+
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_setup_nt_status(sr, ERROR_SEVERITY_WARNING,
+ NT_STATUS_BUFFER_OVERFLOW);
+ else {
+ sr->smb_rcls = ERRDOS;
+ sr->smb_err = ERRmoredata;
+ }
+ } else {
+ /*
+ * The client has provided enough buffer space, all
+ * we have to do is attach the output stream to the
+ * transaction response and zero out the stream.
+ */
+ if (nbytes != 0) {
+ mhead = smb_mbuf_get(pipe_info->output, nbytes);
+ xa->rep_data_mb.max_bytes = nbytes;
+ MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
+ }
+ }
+
+ if (pipe_info->output) {
+ kmem_free(pipe_info->output, pipe_info->outlen);
+ pipe_info->output = NULL;
+ pipe_info->outlen = 0;
+ }
+
+ smb_rpc_exit(pipe_info);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_rpc_fid
+ *
+ * The connection_fid is an arbitrary id used to associate RPC requests
+ * with a particular binding handle. This routine provides a new fid on
+ * each call. It will not assign 0 or -1 so that those values can
+ * remain available as sentinels.
+ */
+static uint32_t
+smb_rpc_fid(void)
+{
+ static uint32_t connection_fid;
+ static kmutex_t smb_rpc_fid_mutex;
+
+ mutex_enter(&smb_rpc_fid_mutex);
+
+ if (connection_fid == 0)
+ connection_fid = lbolt << 11;
+
+ do {
+ ++connection_fid;
+ } while (connection_fid == 0 || connection_fid == (uint32_t)-1);
+
+ mutex_exit(&smb_rpc_fid_mutex);
+
+ return (connection_fid);
+}
+
+
+/*
+ * smb_rpc_close
+ *
+ * This function should be called whenever an IPC file/pipe is closed.
+ * All remaining I/O is flushed and the RPC layer is informed so that
+ * it can release the resources being used for this connection.
+ */
+void
+smb_rpc_close(struct smb_ofile *of)
+{
+ mlsvc_pipe_t *pipe_info;
+ uint32_t nbytes = 0;
+
+ ASSERT(of);
+ ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(of->f_pipe_info != NULL);
+
+ pipe_info = of->f_pipe_info;
+ smb_rpc_enter(pipe_info);
+
+ if (pipe_info->fid != 0) {
+ (void) smb_winpipe_call(0, pipe_info, 0, SMB_RPC_FLUSH,
+ &nbytes);
+ pipe_info->fid = 0;
+ }
+
+ if (pipe_info->output) {
+ kmem_free(pipe_info->output, pipe_info->outlen);
+ pipe_info->output = NULL;
+ pipe_info->outlen = 0;
+ }
+
+ smb_rpc_exit(pipe_info);
+
+ cv_destroy(&pipe_info->cv);
+ mutex_destroy(&pipe_info->mutex);
+}
+
+/*
+ * smb_rpc_write
+ *
+ * This interface is an alternative to smb_rpc_transact. We set up the
+ * connection fid, as required, and copy the input data to the input
+ * stream. The input stream is created by allocating enough mbufs to
+ * hold the incoming data and doing a uio transfer. It is then up
+ * to the client to call smb_rpc_read to actually make the transaction
+ * happen.
+ *
+ * Returns 0 on success or an errno on failure.
+ */
+int
+smb_rpc_write(struct smb_request *sr, struct uio *uio)
+{
+ mlsvc_pipe_t *pipe_info;
+ mlsvc_stream_t *streamin;
+ uint32_t mdrcnt;
+ int rc;
+
+ ASSERT(sr->fid_ofile);
+ ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(sr->fid_ofile->f_pipe_info != NULL);
+
+ pipe_info = sr->fid_ofile->f_pipe_info;
+ smb_rpc_enter(pipe_info);
+
+ if (pipe_info->fid == 0) {
+ smb_rpc_exit(pipe_info);
+ return (EBADF);
+ }
+
+ streamin = &pipe_info->input;
+ streamin->uio.uio_iov = uio->uio_iov;
+ streamin->uio.uio_iovcnt = uio->uio_iovcnt;
+ streamin->uio.uio_offset = 0;
+ streamin->uio.uio_resid = uio->uio_resid;
+ streamin->uio.uio_segflg = UIO_SYSSPACE;
+ mdrcnt = (uint32_t)uio->uio_resid;
+
+ rc = smb_winpipe_call(sr, pipe_info, streamin, SMB_RPC_WRITE,
+ &mdrcnt);
+
+ smb_rpc_exit(pipe_info);
+
+ return ((rc == 0) ? 0 : EIO);
+}
+
+/*
+ * smb_rpc_read
+ *
+ * This interface may be called because smb_rpc_transact could not return
+ * all of the data in the original transaction or to form the second half
+ * of a transaction set up using smb_rpc_write. If there is data in the
+ * output stream, we return it. Otherwise we assume that there is data
+ * in the input stream that will provide the context to perform an RPC
+ * transaction. The connection fid (pipe_info->fid) will provide the
+ * context for mlsvc_rpc_process.
+ *
+ * The response data is encoded into raw_data as required by the smb_read
+ * functions. The uio_resid value indicates the number of bytes read.
+ */
+/*ARGSUSED*/
+int
+smb_rpc_read(struct smb_request *sr, struct uio *uio)
+{
+ mlsvc_pipe_t *pinfo;
+ mlsvc_stream_t *streamin;
+ struct mbuf *mhead;
+ int mdrcnt;
+ int nbytes;
+ int rc = 0;
+
+ ASSERT(sr->fid_ofile);
+ ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
+ ASSERT(sr->fid_ofile->f_pipe_info != NULL);
+
+ pinfo = sr->fid_ofile->f_pipe_info;
+ smb_rpc_enter(pinfo);
+
+ if (pinfo->fid == 0) {
+ rc = EBADF;
+ goto smb_rpc_read_exit;
+ }
+
+ /*
+ * if there is data left in the outpipe return it now
+ */
+ streamin = 0;
+ mdrcnt = uio->uio_resid;
+ nbytes = mdrcnt;
+
+ rc = smb_winpipe_call(sr, pinfo, streamin, SMB_RPC_READ,
+ (uint32_t *)&nbytes);
+
+ if (rc != 0 || nbytes == 0) {
+ rc = EIO;
+ goto smb_rpc_read_exit;
+ }
+ if (nbytes > mdrcnt) {
+ nbytes = mdrcnt;
+ }
+
+ mhead = smb_mbuf_get(pinfo->output, nbytes);
+ MBC_SETUP(&sr->raw_data, nbytes);
+ MBC_ATTACH_MBUF(&sr->raw_data, mhead);
+
+ uio->uio_resid -= nbytes;
+
+smb_rpc_read_exit:
+ if (pinfo->output) {
+ kmem_free(pinfo->output, pinfo->outlen);
+ pinfo->output = NULL;
+ pinfo->outlen = 0;
+ }
+
+ smb_rpc_exit(pinfo);
+ return (rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_sd.c b/usr/src/uts/common/fs/smbsrv/smb_sd.c
new file mode 100644
index 0000000000..4afa258b9a
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_sd.c
@@ -0,0 +1,862 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides Security Descriptor handling functions.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_idmap.h>
+
+#define AS_DWORD(X) (*(uint32_t *)&(X))
+#define SELF_REL(P, M, T) (T *)(((char *)(P)) + AS_DWORD((P)->M))
+
+void smb_fmt_sid(char *buf, nt_sid_t *sid);
+
+void
+smb_sd_init(smb_sd_t *sd, uint8_t revision)
+{
+ bzero(sd, sizeof (smb_sd_t));
+ sd->sd_hdr.sd_revision = revision;
+}
+
+/*
+ * smb_sd_term
+ *
+ * Free non-NULL members of 'sd' which has to be in
+ * absolute (pointer) form.
+ */
+void
+smb_sd_term(smb_sd_t *sd)
+{
+ ASSERT(sd);
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ if (sd->sd_owner)
+ MEM_FREE("libnt", sd->sd_owner);
+
+ if (sd->sd_group)
+ MEM_FREE("libnt", sd->sd_group);
+
+ if (sd->sd_dacl)
+ kmem_free(sd->sd_dacl, sd->sd_dacl->sl_size);
+
+ if (sd->sd_sacl)
+ kmem_free(sd->sd_sacl, sd->sd_sacl->sl_size);
+
+ bzero(sd, sizeof (smb_sd_t));
+}
+
+/*
+ * Hmmm. For all of these smb_sd_set_xxx() functions,
+ * what do we do if the affected member is already set?
+ * Should we free() it? For now, punt and risk a memory leak.
+ */
+
+void
+smb_sd_set_owner(smb_sd_t *sd, nt_sid_t *owner, int defaulted)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_owner = owner;
+ if (defaulted)
+ sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
+ else
+ sd->sd_hdr.sd_control &= ~SE_OWNER_DEFAULTED;
+}
+
+void
+smb_sd_set_group(smb_sd_t *sd, nt_sid_t *group, int defaulted)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_group = group;
+ if (defaulted)
+ sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
+ else
+ sd->sd_hdr.sd_control &= ~SE_GROUP_DEFAULTED;
+}
+
+void
+smb_sd_set_dacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_dacl = acl;
+
+ if (flags & ACL_DEFAULTED)
+ sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
+ if (flags & ACL_AUTO_INHERIT)
+ sd->sd_hdr.sd_control |= SE_DACL_AUTO_INHERITED;
+ if (flags & ACL_PROTECTED)
+ sd->sd_hdr.sd_control |= SE_DACL_PROTECTED;
+
+ if (present)
+ sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
+}
+
+void
+smb_sd_set_sacl(smb_sd_t *sd, int present, smb_acl_t *acl, int flags)
+{
+ ASSERT((sd->sd_hdr.sd_control & SE_SELF_RELATIVE) == 0);
+
+ sd->sd_sacl = acl;
+
+ if (flags & ACL_DEFAULTED)
+ sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
+ if (flags & ACL_AUTO_INHERIT)
+ sd->sd_hdr.sd_control |= SE_SACL_AUTO_INHERITED;
+ if (flags & ACL_PROTECTED)
+ sd->sd_hdr.sd_control |= SE_SACL_PROTECTED;
+
+ if (present)
+ sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
+}
+
+nt_sid_t *
+smb_sd_get_owner(void *sd, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ nt_sid_t *sid;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_OWNER_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ sid = SELF_REL(sr_sd, sd_owner_offs, nt_sid_t);
+ }
+ else
+ sid = ((smb_sd_t *)sd)->sd_owner;
+
+ return (sid);
+}
+
+nt_sid_t *
+smb_sd_get_group(void *sd, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ nt_sid_t *sid;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_GROUP_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ sid = SELF_REL(sr_sd, sd_group_offs, nt_sid_t);
+ }
+ else
+ sid = ((smb_sd_t *)sd)->sd_group;
+
+ return (sid);
+}
+
+smb_acl_t *
+smb_sd_get_dacl(void *sd, int *present, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ smb_acl_t *acl = NULL;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (present != NULL)
+ *present = (sd_hdr->sd_control & SE_DACL_PRESENT) ? 1 : 0;
+
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_DACL_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ if (sr_sd->sd_dacl_offs) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ acl = SELF_REL(sr_sd, sd_dacl_offs, smb_acl_t);
+ }
+ }
+ else
+ acl = ((smb_sd_t *)sd)->sd_dacl;
+
+ return (acl);
+}
+
+smb_acl_t *
+smb_sd_get_sacl(void *sd, int *present, int *defaulted)
+{
+ smb_sdbuf_t *sr_sd;
+ smb_sd_hdr_t *sd_hdr;
+ smb_acl_t *acl = NULL;
+
+ sd_hdr = (smb_sd_hdr_t *)sd;
+ if (present != NULL)
+ *present = (sd_hdr->sd_control & SE_SACL_PRESENT) ? 1 : 0;
+
+ if (defaulted != NULL)
+ *defaulted = (sd_hdr->sd_control & SE_SACL_DEFAULTED) ? 1 : 0;
+
+ if (sd_hdr->sd_control & SE_SELF_RELATIVE) {
+ sr_sd = ((smb_sdbuf_t *)sd);
+ if (sr_sd->sd_sacl_offs) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ acl = SELF_REL(sr_sd, sd_sacl_offs, smb_acl_t);
+ }
+ }
+ else
+ acl = ((smb_sd_t *)sd)->sd_sacl;
+
+ return (acl);
+}
+
+uint32_t
+smb_sd_len(void *sd, uint32_t secinfo)
+{
+ uint32_t length = 0;
+ nt_sid_t *sid;
+ smb_acl_t *acl;
+ int present;
+
+ /* SD Header */
+ length += sizeof (smb_sdbuf_t);
+
+ /* Owner */
+ if (secinfo & SMB_OWNER_SECINFO) {
+ sid = smb_sd_get_owner(sd, NULL);
+ if (sid)
+ length += nt_sid_length(sid);
+ }
+
+
+ /* Group */
+ if (secinfo & SMB_GROUP_SECINFO) {
+ sid = smb_sd_get_group(sd, NULL);
+ if (sid)
+ length += nt_sid_length(sid);
+ }
+
+
+ /* DACL */
+ if (secinfo & SMB_DACL_SECINFO) {
+ acl = smb_sd_get_dacl(sd, &present, NULL);
+ if (present && acl)
+ length += smb_acl_len(acl);
+ }
+
+ /* SACL */
+ if (secinfo & SMB_SACL_SECINFO) {
+ acl = smb_sd_get_sacl(sd, &present, NULL);
+ if (present && acl)
+ length += smb_acl_len(acl);
+ }
+
+ return (length);
+}
+
+/*
+ * smb_sd_get_secinfo
+ *
+ * Return the security information mask for the specified security
+ * descriptor.
+ */
+uint32_t
+smb_sd_get_secinfo(void *sd)
+{
+ uint32_t sec_info = 0;
+ smb_acl_t *acl;
+ int present;
+
+ if (sd == 0)
+ return (0);
+
+ if (smb_sd_get_owner(sd, NULL) != 0)
+ sec_info |= SMB_OWNER_SECINFO;
+
+ if (smb_sd_get_group(sd, NULL) != 0)
+ sec_info |= SMB_GROUP_SECINFO;
+
+ acl = smb_sd_get_dacl(sd, &present, NULL);
+ if (acl && present)
+ sec_info |= SMB_DACL_SECINFO;
+
+ acl = smb_sd_get_sacl(sd, &present, NULL);
+ if (acl && present)
+ sec_info |= SMB_SACL_SECINFO;
+
+ return (sec_info);
+}
+
+/*
+ * smb_sd_abs2selfrel
+ *
+ * This function takes an absolute SD (sd) and make a self relative
+ * SD which will be returned in srel_sd.
+ *
+ * srel_sdsz contains the size of buffer which srel_sd points to.
+ *
+ * Do not add new error codes here without checking the impact on
+ * all callers of this function.
+ *
+ * Returns NT status codes:
+ * NT_STATUS_SUCCESS
+ * NT_STATUS_BUFFER_TOO_SMALL
+ * NT_STATUS_INVALID_SECURITY_DESCR
+ */
+static uint32_t
+smb_sd_abs2selfrel(
+ smb_sd_t *sd,
+ uint32_t secinfo,
+ smb_sdbuf_t *srel_sd,
+ uint32_t srel_sdsz)
+{
+ uint32_t avail_len = srel_sdsz;
+ uint32_t length = 0;
+ unsigned char *scan_beg = (unsigned char *) srel_sd;
+ unsigned char *scan = scan_beg;
+ unsigned char *scan_end;
+ nt_sid_t *sid;
+ smb_acl_t *acl;
+ int present, defaulted;
+
+ length = smb_sd_len(sd, secinfo);
+
+ if (length == 0)
+ return (NT_STATUS_INVALID_SECURITY_DESCR);
+
+ if (avail_len < length)
+ return (NT_STATUS_BUFFER_TOO_SMALL);
+
+ bzero(srel_sd, length);
+ scan_end = scan_beg + length;
+
+ /* SD Header */
+ length = sizeof (smb_sdbuf_t);
+ srel_sd->sd_hdr.sd_revision = sd->sd_hdr.sd_revision;
+ srel_sd->sd_hdr.sd_control = SE_SELF_RELATIVE;
+ scan += length;
+
+ if (secinfo & SMB_OWNER_SECINFO) {
+ /* Owner */
+ sid = smb_sd_get_owner(sd, &defaulted);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_OWNER_DEFAULTED;
+
+ if (sid) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = nt_sid_copy((void*)scan, sid, scan_end - scan);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_owner_offs = scan - scan_beg;
+ scan += length;
+ }
+ }
+
+ if (secinfo & SMB_GROUP_SECINFO) {
+ /* Group */
+ sid = smb_sd_get_group(sd, &defaulted);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_GROUP_DEFAULTED;
+
+ if (sid) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = nt_sid_copy((void*)scan, sid, scan_end - scan);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_group_offs = scan - scan_beg;
+ scan += length;
+ }
+ }
+
+
+ if (secinfo & SMB_DACL_SECINFO) {
+ /* Dacl */
+ acl = smb_sd_get_dacl(sd, &present, &defaulted);
+
+ srel_sd->sd_hdr.sd_control |=
+ (sd->sd_hdr.sd_control & SE_DACL_INHERITANCE_MASK);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_DACL_DEFAULTED;
+
+ if (present)
+ srel_sd->sd_hdr.sd_control |= SE_DACL_PRESENT;
+
+ if (present && acl) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = smb_acl_copy(scan_end - scan,
+ (void*) scan, acl);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_dacl_offs = scan - scan_beg;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ acl = (smb_acl_t *)scan;
+ acl->sl_size = (WORD)length; /* set the size */
+ scan += length;
+ }
+ }
+
+ if (secinfo & SMB_SACL_SECINFO) {
+ /* Sacl */
+ acl = smb_sd_get_sacl(sd, &present, &defaulted);
+
+ srel_sd->sd_hdr.sd_control |=
+ (sd->sd_hdr.sd_control & SE_SACL_INHERITANCE_MASK);
+
+ if (defaulted)
+ srel_sd->sd_hdr.sd_control |= SE_SACL_DEFAULTED;
+
+ if (present)
+ srel_sd->sd_hdr.sd_control |= SE_SACL_PRESENT;
+
+ if (present && acl) {
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ length = smb_acl_copy(scan_end - scan,
+ (void*) scan, acl);
+ if (length == 0)
+ goto fail;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ srel_sd->sd_sacl_offs = scan - scan_beg;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ acl = (smb_acl_t *)scan;
+ acl->sl_size = (WORD)length; /* set the size */
+ scan += length;
+ }
+ }
+
+ return (NT_STATUS_SUCCESS);
+
+fail:
+ return (NT_STATUS_INVALID_SECURITY_DESCR);
+}
+
+/*
+ * smb_sd_fromfs
+ *
+ * Makes an Windows style security descriptor in absolute form
+ * based on the given filesystem security information.
+ *
+ * Should call smb_sd_term() for the returned sd to free allocated
+ * members.
+ */
+static uint32_t
+smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
+{
+ uint32_t status = NT_STATUS_SUCCESS;
+ smb_acl_t *acl = NULL;
+ smb_acl_t *sorted_acl;
+ nt_sid_t *sid;
+ idmap_stat idm_stat;
+
+ ASSERT(fs_sd);
+ ASSERT(sd);
+
+ smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
+
+ /* Owner */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
+ SMB_IDMAP_USER, &sid);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ smb_sd_set_owner(sd, sid, 0);
+ }
+
+ /* Group */
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
+ SMB_IDMAP_GROUP, &sid);
+
+ if (idm_stat != IDMAP_SUCCESS) {
+ smb_sd_term(sd);
+ return (NT_STATUS_NONE_MAPPED);
+ }
+
+ smb_sd_set_group(sd, sid, 0);
+ }
+
+ /* DACL */
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ if (fs_sd->sd_zdacl != NULL) {
+ acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
+ fs_sd->sd_gid);
+ if (acl == NULL) {
+ smb_sd_term(sd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /*
+ * Need to sort the ACL before send it to Windows
+ * clients. Winodws GUI is sensitive about the order
+ * of ACEs.
+ */
+ sorted_acl = smb_acl_sort(acl);
+ if (sorted_acl && (sorted_acl != acl)) {
+ kmem_free(acl, acl->sl_size);
+ acl = sorted_acl;
+ }
+ smb_sd_set_dacl(sd, 1, acl, fs_sd->sd_zdacl->acl_flags);
+ } else {
+ smb_sd_set_dacl(sd, 0, NULL, 0);
+ }
+ }
+
+ /* SACL */
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+ if (fs_sd->sd_zsacl != NULL) {
+ acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
+ fs_sd->sd_gid);
+ if (acl == NULL) {
+ smb_sd_term(sd);
+ return (NT_STATUS_INTERNAL_ERROR);
+ }
+
+ smb_sd_set_sacl(sd, 1, acl, fs_sd->sd_zsacl->acl_flags);
+ } else {
+ smb_sd_set_sacl(sd, 0, NULL, 0);
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_sd_tofs
+ *
+ * Creates a filesystem security structure based on the given
+ * Windows security descriptor.
+ */
+uint32_t
+smb_sd_tofs(smb_sdbuf_t *sr_sd, smb_fssd_t *fs_sd)
+{
+ nt_sid_t *sid;
+ smb_acl_t *acl;
+ uint32_t status = NT_STATUS_SUCCESS;
+ uint16_t sd_control;
+ idmap_stat idm_stat;
+ int present;
+ int idtype;
+ int flags = 0;
+
+ sd_control = sr_sd->sd_hdr.sd_control;
+
+ /*
+ * ZFS only has one set of flags so for now only
+ * Windows DACL flags are taken into account.
+ */
+ if (sd_control & SE_DACL_DEFAULTED)
+ flags |= ACL_DEFAULTED;
+ if (sd_control & SE_DACL_AUTO_INHERITED)
+ flags |= ACL_AUTO_INHERIT;
+ if (sd_control & SE_DACL_PROTECTED)
+ flags |= ACL_PROTECTED;
+
+ if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
+ flags |= ACL_IS_DIR;
+
+ /* Owner */
+ if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+ sid = smb_sd_get_owner(sr_sd, NULL);
+ if (nt_sid_is_valid(sid) == 0) {
+ return (NT_STATUS_INVALID_SID);
+ }
+
+ idtype = SMB_IDMAP_UNKNOWN;
+ idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_NONE_MAPPED);
+ }
+ }
+
+ /* Group */
+ if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+ sid = smb_sd_get_group(sr_sd, NULL);
+ if (nt_sid_is_valid(sid) == 0) {
+ return (NT_STATUS_INVALID_SID);
+ }
+
+ idtype = SMB_IDMAP_UNKNOWN;
+ idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (NT_STATUS_NONE_MAPPED);
+ }
+ }
+
+ /* DACL */
+ if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+ acl = smb_sd_get_dacl(sr_sd, &present, NULL);
+ if (present) {
+ status = smb_acl_to_zfs(acl, flags,
+ SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
+ if (status != NT_STATUS_SUCCESS)
+ return (status);
+ }
+ else
+ return (NT_STATUS_INVALID_ACL);
+ }
+
+ /* SACL */
+ if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+ acl = smb_sd_get_sacl(sr_sd, &present, NULL);
+ if (present) {
+ status = smb_acl_to_zfs(acl, flags,
+ SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
+ if (status != NT_STATUS_SUCCESS) {
+ return (status);
+ }
+ } else {
+ return (NT_STATUS_INVALID_ACL);
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_sd_read
+ *
+ * Read uid, gid and ACL from filesystem. The returned ACL from read
+ * routine is always in ZFS format. Convert the ZFS acl to a Win acl
+ * and return the Win SD in relative form.
+ *
+ * NOTE: upon successful return caller MUST free the memory allocated
+ * for the returned SD by calling kmem_free(). The length of the allocated
+ * buffer is returned in 'buflen'.
+ */
+uint32_t
+smb_sd_read(smb_request_t *sr, smb_sdbuf_t **sr_sd,
+ uint32_t secinfo, uint32_t *buflen)
+{
+ smb_sd_t sd;
+ smb_fssd_t fs_sd;
+ smb_error_t smb_err;
+ smb_sdbuf_t *sdbuf;
+ smb_node_t *node;
+ uint32_t sdlen;
+ uint32_t status = NT_STATUS_SUCCESS;
+ uint32_t sd_flags;
+ int error;
+
+ *sr_sd = NULL;
+
+ node = sr->fid_ofile->f_node;
+ sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
+ smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
+
+ error = smb_fsop_sdread(sr, sr->user_cr, node, &fs_sd);
+ if (error) {
+ smb_errmap_unix2smb(error, &smb_err);
+ return (smb_err.status);
+ }
+
+ status = smb_sd_fromfs(&fs_sd, &sd);
+ smb_fsop_sdterm(&fs_sd);
+
+ if (status != NT_STATUS_SUCCESS)
+ return (status);
+
+ sdlen = smb_sd_len(&sd, secinfo);
+
+ if (*buflen < sdlen) {
+ /* return the required size */
+ *buflen = sdlen;
+ smb_sd_term(&sd);
+ return (NT_STATUS_BUFFER_TOO_SMALL);
+ }
+
+ sdbuf = kmem_alloc(sdlen, KM_SLEEP);
+ status = smb_sd_abs2selfrel(&sd, secinfo, sdbuf, sdlen);
+ smb_sd_term(&sd);
+
+ if (status == NT_STATUS_SUCCESS) {
+ *sr_sd = sdbuf;
+ *buflen = sdlen;
+ }
+ else
+ kmem_free(sdbuf, sdlen);
+
+ return (status);
+}
+
+/*
+ * smb_sd_write
+ *
+ * Takes a Win SD in self-relative form, convert it to
+ * ZFS format and write it to filesystem. The write routine
+ * converts ZFS acl to Posix acl if required.
+ */
+uint32_t
+smb_sd_write(smb_request_t *sr, smb_sdbuf_t *sr_sd, uint32_t secinfo)
+{
+ smb_node_t *node;
+ smb_fssd_t fs_sd;
+ smb_error_t smb_err;
+ uint32_t status;
+ uint32_t sd_flags;
+ int error;
+
+ node = sr->fid_ofile->f_node;
+ sd_flags = (node->vp->v_type == VDIR) ? SMB_FSSD_FLAGS_DIR : 0;
+ smb_fsop_sdinit(&fs_sd, secinfo, sd_flags);
+
+ status = smb_sd_tofs(sr_sd, &fs_sd);
+ if (status != NT_STATUS_SUCCESS) {
+ smb_fsop_sdterm(&fs_sd);
+ return (status);
+ }
+
+ error = smb_fsop_sdwrite(sr, sr->user_cr, node, &fs_sd, 0);
+ smb_fsop_sdterm(&fs_sd);
+
+ if (error) {
+ smb_errmap_unix2smb(error, &smb_err);
+ return (smb_err.status);
+ }
+
+ return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_fmt_sid
+ *
+ * Make an string SID and copy the result into the specified buffer.
+ */
+void
+smb_fmt_sid(char *buf, nt_sid_t *sid)
+{
+ char *sid_str;
+
+ sid_str = nt_sid_format(sid);
+ if (sid_str) {
+ (void) strcpy(buf, sid_str);
+ MEM_FREE("smb", sid_str);
+ } else {
+ (void) strcpy(buf, "<invalid SID>");
+ }
+}
+
+/*
+ * smb_sd_log
+ *
+ * log the given Windows style security descriptor information
+ * in system log. This is for debugging purposes.
+ */
+void
+smb_sd_log(void *sd)
+{
+ smb_acl_t *acl;
+ smb_ace_t *ace;
+ nt_sid_t *sid;
+ int present, defaulted;
+ char entry[128];
+ char *inherit;
+ char *type;
+ int ix_dacl;
+
+ sid = smb_sd_get_owner(sd, &defaulted);
+ if (sid)
+ smb_fmt_sid(entry, sid);
+ else
+ (void) strcpy(entry, "NULL");
+
+ cmn_err(CE_NOTE, " Owner: %s", entry);
+
+ sid = smb_sd_get_group(sd, &defaulted);
+ if (sid)
+ smb_fmt_sid(entry, sid);
+ else
+ (void) strcpy(entry, "NULL");
+
+ cmn_err(CE_NOTE, " Primary Group: %s", entry);
+
+ acl = smb_sd_get_dacl(sd, &present, &defaulted);
+
+ if (!present || !acl) {
+ cmn_err(CE_NOTE, " No DACL");
+ return;
+ }
+
+ for (ix_dacl = 0;
+ ace = smb_ace_get(acl, ix_dacl);
+ ix_dacl++) {
+ /*
+ * Make sure the ACE type is something we grok.
+ * All ACE, now and in the future, have a valid
+ * header. Can't access fields passed the Header
+ * until we're sure it's right.
+ */
+ switch (ace->se_header.se_type) {
+ case ACCESS_ALLOWED_ACE_TYPE:
+ type = "(Allow)";
+ break;
+ case ACCESS_DENIED_ACE_TYPE:
+ type = "(Deny)";
+ break;
+
+ case SYSTEM_AUDIT_ACE_TYPE:
+ default:
+ /* Ignore unrecognized/misplaced ACE */
+ continue;
+ }
+
+ smb_fmt_sid(entry, &ace->se_sid);
+
+ switch (ace->se_header.se_flags & INHERIT_MASK_ACE) {
+ case OBJECT_INHERIT_ACE:
+ inherit = "(OI)";
+ break;
+ case CONTAINER_INHERIT_ACE:
+ inherit = "(CI)";
+ break;
+ case INHERIT_ONLY_ACE:
+ inherit = "(IO)";
+ break;
+ case NO_PROPOGATE_INHERIT_ACE:
+ inherit = "(NP)";
+ break;
+ default:
+ inherit = "";
+ }
+
+ (void) snprintf(entry + strlen(entry), sizeof (entry),
+ ":%s 0x%X %s", inherit, ace->se_mask, type);
+
+ cmn_err(CE_NOTE, " %s", entry);
+ }
+
+ cmn_err(CE_NOTE, " %d ACE(s)", ix_dacl);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_search.c b/usr/src/uts/common/fs/smbsrv/smb_search.c
new file mode 100644
index 0000000000..0700b8fd2d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_search.c
@@ -0,0 +1,289 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: search
+ *
+ * This command is used to search directories.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT MaxCount; Number of dir. entries to return
+ * USHORT SearchAttributes;
+ * USHORT ByteCount; Count of data bytes; min = 5
+ * UCHAR BufferFormat1; 0x04 -- ASCII
+ * UCHAR FileName[]; File name, may be null
+ * UCHAR BufferFormat2; 0x05 -- Variable block
+ * USHORT ResumeKeyLength; Length of resume key, may be 0
+ * UCHAR ResumeKey[]; Resume key
+ *
+ * FileName specifies the file to be sought. SearchAttributes indicates
+ * the attributes that the file must have, and is described in the "File
+ * Attribute Encoding" section of this document. If SearchAttributes is
+ * zero then only normal files are returned. If the system file, hidden or
+ * directory attributes are specified then the search is inclusive@both the
+ * specified type(s) of files and normal files are returned. If the volume
+ * label attribute is specified then the search is exclusive, and only the
+ * volume label entry is returned.
+ *
+ * MaxCount specifies the number of directory entries to be returned.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Number of entries returned
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR BufferFormat; 0x05 -- Variable block
+ * USHORT DataLength; Length of data
+ * UCHAR DirectoryInformationData[]; Data
+ *
+ * The response will contain one or more directory entries as determined by
+ * the Count field. No more than MaxCount entries will be returned. Only
+ * entries that match the sought FileName and SearchAttributes combination
+ * will be returned.
+ *
+ * ResumeKey must be null (length = 0) on the initial search request.
+ * Subsequent search requests intended to continue a search must contain
+ * the ResumeKey field extracted from the last directory entry of the
+ * previous response. ResumeKey is self-contained, for on calls containing
+ * a non-zero ResumeKey neither the SearchAttributes or FileName fields
+ * will be valid in the request. ResumeKey has the following format:
+ *
+ * Resume Key Field Description
+ * ================================== =================================
+ *
+ * UCHAR Reserved; bit 7 - consumer use
+ * bits 5,6 - system use (must
+ * preserve)
+ * bits 0-4 - server use (must
+ * preserve)
+ * UCHAR FileName[11]; Name of the returned file
+ * UCHAR ReservedForServer[5]; Client must not modify
+ * UCHAR ReservedForConsumer[4]; Server must not modify
+ *
+ * FileName is 8.3 format, with the three character extension left
+ * justified into FileName[9-11]. If the client is prior to the LANMAN1.0
+ * dialect, the returned FileName should be uppercased.
+ *
+ * SMB_COM_SEARCH terminates when either the requested maximum number of
+ * entries that match the named file are found, or the end of directory is
+ * reached without the maximum number of matches being found. A response
+ * containing no entries indicates that no matching entries were found
+ * between the starting point of the search and the end of directory.
+ *
+ * There may be multiple matching entries in response to a single request
+ * as SMB_COM_SEARCH supports wildcards in the last component of FileName
+ * of the initial request.
+ *
+ * Returned directory entries in the DirectoryInformationData field of the
+ * response each have the following format:
+ *
+ * Directory Information Field Description
+ * ================================== =================================
+ *
+ * SMB_RESUME_KEY ResumeKey; Described above
+ * UCHAR FileAttributes; Attributes of the found file
+ * SMB_TIME LastWriteTime; Time file was last written
+ * SMB_DATE LastWriteDate; Date file was last written
+ * ULONG FileSize; Size of the file
+ * UCHAR FileName[13]; ASCII, space-filled null
+ * terminated
+ *
+ * FileName must conform to 8.3 rules, and is padded after the extension
+ * with 0x20 characters if necessary. If the client has negotiated a
+ * dialect prior to the LANMAN1.0 dialect, or if bit0 of the Flags2 SMB
+ * header field of the request is clear, the returned FileName should be
+ * uppercased.
+ *
+ * As can be seen from the above structure, SMB_COM_SEARCH can not return
+ * long filenames, and can not return UNICODE filenames. Files which have
+ * a size greater than 2^32 bytes should have the least significant 32 bits
+ * of their size returned in FileSize.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_search(struct smb_request *sr)
+{
+ int rc;
+ unsigned short sattr, count, maxcount;
+ char *path;
+ uint32_t cookie;
+ char name[14];
+ unsigned char resume_char;
+ uint32_t resume_key;
+ struct smb_node *node;
+ unsigned char type;
+ unsigned short key_len;
+ fsvol_attr_t vol_attr;
+ smb_odir_context_t *pc;
+
+ /* We only handle 8.3 name here */
+ sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
+ sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
+
+ if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len) != 0) ||
+ (type != 0x05)) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ count = 0;
+
+ if ((sattr == SMB_FA_VOLUME) && (key_len != 21)) {
+ (void) memset(name, ' ', sizeof (name));
+ (void) strncpy(name, vol_attr.name, sizeof (name));
+
+ if (key_len >= 21) {
+ (void) smb_decode_mbc(&sr->smb_data, "17.l",
+ &resume_key);
+ } else {
+ resume_key = 0;
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbwb11c5.lb8.13c",
+ 1, 0, VAR_BCC, 5, 0, 0, path+1,
+ resume_key, sattr, name);
+ count++;
+ } else {
+ cookie = 0;
+ if (key_len == 0) { /* begin search */
+ /*
+ * Some MS clients pass NULL file names
+ * NT interprets this as "\"
+ */
+ if (strlen(path) == 0) path = "\\";
+
+ rc = smb_rdir_open(sr, path, sattr);
+ if (rc == SDRC_NORMAL_REPLY) {
+ sr->reply.chain_offset = sr->cur_reply_offset;
+ (void) smb_encode_mbc(&sr->reply, "bw", 0, 0);
+ return (rc);
+ }
+ resume_char = 0;
+ resume_key = 0;
+ } else if (key_len == 21) {
+ if (smb_decode_mbc(&sr->smb_data, "b12.wwl",
+ &resume_char, &cookie, &sr->smb_sid,
+ &resume_key) != 0) {
+ /* We don't know which search to close! */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
+ sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr,
+ NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+ } else {
+ /* We don't know which search to close! */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+ pc = MEM_ZALLOC("smb", sizeof (*pc));
+ pc->dc_cookie = cookie;
+ node = (struct smb_node *)0;
+ rc = 0;
+ while (count < maxcount) {
+ if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+ break;
+ if ((strcmp(pc->dc_name, ".") == 0) ||
+ (strcmp(pc->dc_name, "..") == 0)) {
+ if (node) {
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ }
+ continue;
+ }
+
+ (void) memset(name, ' ', sizeof (name));
+ if (*pc->dc_shortname)
+ (void) strncpy(name, pc->dc_shortname, 13);
+ else {
+ (void) strncpy(name, pc->dc_name, 13);
+ if ((sr->session->dialect <= LANMAN1_0) ||
+ ((sr->smb_flg2 &
+ SMB_FLAGS2_KNOWS_LONG_NAMES) == 0))
+ (void) utf8_strupr(name);
+ }
+
+ (void) smb_encode_mbc(&sr->reply, "b8c3c.wwlbYl13c",
+ resume_char,
+ pc->dc_name83, pc->dc_name83+9,
+ pc->dc_cookie, sr->smb_sid,
+ resume_key,
+ pc->dc_dattr & 0xff,
+ pc->dc_attr.sa_vattr.va_mtime.tv_sec,
+ (int32_t)smb_node_get_size(node, &pc->dc_attr),
+ name);
+ smb_node_release(node);
+ node = (struct smb_node *)0;
+ count++;
+ }
+ MEM_FREE("smb", pc);
+
+ if ((rc != 0) && (rc != ENOENT)) {
+ /* returned error by smb_rdir_next() */
+ smb_rdir_close(sr);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (count == 0) {
+ smb_rdir_close(sr);
+ smbsr_raise_error(sr, ERRDOS, ERRnofiles);
+ /* NOTREACHED */
+ }
+ }
+
+ rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
+ (void) smb_poke_mbc(&sr->reply, sr->cur_reply_offset, "bwwbw",
+ 1, count, rc+3, 5, rc);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_seek.c b/usr/src/uts/common/fs/smbsrv/smb_seek.c
new file mode 100644
index 0000000000..a120a26a9d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_seek.c
@@ -0,0 +1,129 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The seek message is sent to set the current file pointer for FID.
+ * This request should generally only be used by clients wishing to
+ * find the size of a file, since all read and write requests include
+ * the read or write file position as part of the SMB. This request
+ * is inappropriate for large files, as the offsets specified are only
+ * 32 bits.
+ *
+ * The CIFS/1.0 (1996) spec contains the following incomplete statement:
+ *
+ * "A seek which results in an Offset which can not be expressed
+ * in 32 bits returns the least significant."
+ *
+ * It would probably be a mistake to make an assumption about what this
+ * statement means. So, for now, we return an error if the resultant
+ * file offset is beyond the 32-bit limit.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * smb_com_seek
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 4
+ * USHORT Fid; File handle
+ * USHORT Mode; Seek mode: 0, 1 or 2
+ * LONG Offset; Relative offset
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The starting point of the seek is set by Mode:
+ *
+ * 0 seek from start of file
+ * 1 seek from current current position
+ * 2 seek from end of file
+ *
+ * The "current position" reflects the offset plus data length specified in
+ * the previous read, write or seek request, and the pointer set by this
+ * command will be replaced by the offset specified in the next read, write
+ * or seek command.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 2
+ * ULONG Offset; Offset from start of file
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The response returns the new file pointer in Offset, which is expressed
+ * as the offset from the start of the file, and may be beyond the current
+ * end of file. An attempt to seek before the start of the file sets the
+ * current file pointer to the start of the file.
+ */
+int
+smb_com_seek(struct smb_request *sr)
+{
+ ushort_t mode;
+ int32_t off;
+ uint32_t off_ret;
+ int rc;
+
+ if (smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &mode, &off) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (mode == SMB_SEEK_END) {
+ (void) smb_set_file_size(sr);
+ }
+
+ rc = smb_ofile_seek(sr->fid_ofile, mode, off, &off_ret);
+ if (rc == 0) {
+ smbsr_encode_result(sr, 2, 0, "blw", 2, off_ret, 0);
+ return (SDRC_NORMAL_REPLY);
+ }
+ if (rc == EINVAL) {
+ smbsr_raise_error(sr, ERRDOS, ERRbadfunc);
+ /* NOTREACHED */
+ }
+ if (rc == EOVERFLOW) {
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+ }
+ ASSERT(0);
+ smbsr_raise_error(sr, ERRSRV, ERRerror);
+ /* NOTREACHED */
+
+ /*
+ * Although smbsr_raise_error() doesn't return and the compiler is
+ * told so in smb_kproto.h it still has a problem if it doesn't
+ * find here a return instruction with a value.
+ */
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
new file mode 100644
index 0000000000..3be7eaab1f
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -0,0 +1,1252 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/atomic.h>
+#include <sys/strsubr.h>
+#include <sys/synch.h>
+#include <sys/types.h>
+#include <sys/socketvar.h>
+#include <sys/sdt.h>
+#include <smbsrv/netbios.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_i18n.h>
+
+extern int smb_maxbufsize;
+
+extern unsigned int smb_nt_tcp_rcvbuf;
+
+uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
+uint32_t smb_send_retries = 0;
+uint32_t smb_receive_retries = 0;
+
+static int smb_session_message(smb_session_t *);
+static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
+ uint8_t *, size_t);
+
+void smb_request_init_command_mbuf(smb_request_t *sr);
+static void smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void);
+
+
+void
+smb_timers(smb_thread_t *thread, void *si_void)
+{
+ smb_info_t *si = si_void;
+ smb_session_t *sn;
+
+ ASSERT(si != NULL);
+
+ while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) {
+ /*
+ * Walk through the table and decrement each keep_alive
+ * timer that has not timed out yet. (keepalive > 0)
+ */
+ smb_svcstate_lock_read(&si->si_svc_sm_ctx);
+
+ sn = NULL;
+ while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx,
+ sn)) != NULL) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ if (sn->keep_alive && (sn->keep_alive != (uint32_t)-1))
+ sn->keep_alive--;
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+
+ }
+}
+
+/*
+ * smb_reconnection_check
+ *
+ * This function is called when a client indicates its current connection
+ * should be the only one it has with the server, as indicated by VC=0 in
+ * a SessionSetupX request. We go through the session list and destroy any
+ * stale connections for that client.
+ *
+ * Clients don't associate IP addresses and servers. So a client may make
+ * independent connections (i.e. with VC=0) to a server with multiple
+ * IP addresses. So, when checking for a reconnection, we need to include
+ * the local IP address, to which the client is connecting, when checking
+ * for stale sessions.
+ *
+ * Also check the server's NetBIOS name to support simultaneous access by
+ * multiple clients behind a NAT server. This will only work for SMB over
+ * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
+ * there is no NetBIOS name. See also Knowledge Base article Q301673.
+ */
+void
+smb_reconnection_check(struct smb_session *session)
+{
+ smb_info_t *si = &smb_info;
+ smb_session_t *sn;
+
+ smb_svcstate_lock_read(&si->si_svc_sm_ctx);
+
+ sn = NULL;
+ while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn))
+ != NULL) {
+
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ if ((sn != session) &&
+ (sn->ipaddr == session->ipaddr) &&
+ (sn->local_ipaddr == session->local_ipaddr) &&
+ (strcasecmp(sn->workstation, session->workstation) == 0) &&
+ (sn->opentime <= session->opentime) &&
+ (sn->s_kid < session->s_kid)) {
+ smb_thread_stop(&sn->s_thread);
+ }
+ }
+
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
+
+
+void
+smb_correct_keep_alive_values(uint32_t new_keep_alive)
+{
+ smb_info_t *si = &smb_info;
+ smb_session_t *sn;
+
+ if (new_keep_alive == smb_keep_alive)
+ return;
+ /*
+ * keep alive == 0 means do not drop connection if it's idle
+ */
+ smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
+
+ /*
+ * Walk through the table and set each session to the new keep_alive
+ * value if they have not already timed out. Block clock interrupts.
+ */
+ smb_svcstate_lock_read(&si->si_svc_sm_ctx);
+
+ sn = NULL;
+ while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn))
+ != NULL) {
+ if (sn->keep_alive)
+ sn->keep_alive = new_keep_alive;
+ }
+
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
+
+/*
+ * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
+ *
+ * The mbuf chain is copied into a contiguous buffer so that the whole
+ * message is submitted to smb_sosend as a single request. This should
+ * help Ethereal/Wireshark delineate the packets correctly even though
+ * TCP_NODELAY has been set on the socket.
+ *
+ * If an mbuf chain is provided, it will be freed and set to NULL here.
+ */
+int
+smb_session_send(smb_session_t *session, uint8_t type, struct mbuf_chain *mbc)
+{
+ struct mbuf *m = 0;
+ uint8_t *buf;
+ smb_xprt_t hdr;
+ int count = 0;
+ int rc;
+
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ if ((mbc != NULL) && (mbc->chain != NULL)) {
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->flags = 0;
+ }
+ return (ENOTCONN);
+ default:
+ break;
+ }
+
+ buf = kmem_alloc(NETBIOS_REQ_MAX_SIZE, KM_SLEEP);
+
+ if ((mbc != NULL) && (mbc->chain != NULL)) {
+ count = NETBIOS_HDR_SZ; /* Account for the NBT header. */
+ m = mbc->chain;
+
+ while (m) {
+ if ((count + m->m_len) > NETBIOS_REQ_MAX_SIZE) {
+ kmem_free(buf, NETBIOS_REQ_MAX_SIZE);
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->flags = 0;
+ return (EMSGSIZE);
+ }
+ bcopy(m->m_data, buf + count, m->m_len);
+ count += m->m_len;
+ m = m->m_next;
+ }
+
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->flags = 0;
+ count -= NETBIOS_HDR_SZ;
+ }
+
+ hdr.xh_type = type;
+ hdr.xh_length = count;
+
+ rc = smb_session_xprt_puthdr(session, &hdr, buf, NETBIOS_HDR_SZ);
+ if (rc == 0) {
+ count += NETBIOS_HDR_SZ;
+ rc = smb_sosend(session->sock, buf, count);
+ }
+
+ kmem_free(buf, NETBIOS_REQ_MAX_SIZE);
+ return (rc);
+}
+
+/*
+ * Read, process and respond to a NetBIOS session request.
+ *
+ * A NetBIOS session must be established for SMB-over-NetBIOS. Validate
+ * the calling and called name format and save the client NetBIOS name,
+ * which is used when a NetBIOS session is established to check for and
+ * cleanup leftover state from a previous session.
+ *
+ * Session requests are not valid for SMB-over-TCP, which is unfortunate
+ * because without the client name leftover state cannot be cleaned up
+ * if the client is behind a NAT server.
+ */
+static int
+smb_session_request(struct smb_session *session)
+{
+ int rc;
+ char *calling_name;
+ char *called_name;
+ char client_name[NETBIOS_NAME_SZ];
+ struct mbuf_chain mbc;
+ char *names = NULL;
+ mts_wchar_t *wbuf = NULL;
+ smb_xprt_t hdr;
+ char *p;
+ unsigned int cpid = oem_get_smb_cpid();
+ int rc1, rc2;
+
+ session->keep_alive = smb_keep_alive;
+
+ if (smb_session_xprt_gethdr(session, &hdr) != 0)
+ return (EINVAL);
+
+ DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
+ smb_xprt_t *, &hdr);
+
+ if ((hdr.xh_type != SESSION_REQUEST) ||
+ (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
+ DTRACE_PROBE1(receive__session__req__failed,
+ struct session *, session);
+ return (EINVAL);
+ }
+
+ names = kmem_alloc(hdr.xh_length, KM_SLEEP);
+
+ if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
+ kmem_free(names, hdr.xh_length);
+ DTRACE_PROBE1(receive__session__req__failed,
+ struct session *, session);
+ return (rc);
+ }
+
+ DTRACE_PROBE3(receive__session__req__data, struct session *, session,
+ char *, names, uint32_t, hdr.xh_length);
+
+ called_name = &names[0];
+ calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
+
+ rc1 = netbios_name_isvalid(called_name, 0);
+ rc2 = netbios_name_isvalid(calling_name, client_name);
+
+ if (rc1 == 0 || rc2 == 0) {
+
+ DTRACE_PROBE3(receive__invalid__session__req,
+ struct session *, session, char *, names,
+ uint32_t, hdr.xh_length);
+
+ kmem_free(names, hdr.xh_length);
+ MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
+ (void) smb_encode_mbc(&mbc, "b",
+ DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
+ (void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
+ &mbc);
+ return (EINVAL);
+ }
+
+ DTRACE_PROBE3(receive__session__req__calling__decoded,
+ struct session *, session,
+ char *, calling_name, char *, client_name);
+
+ /*
+ * The client NetBIOS name is in oem codepage format.
+ * We need to convert it to unicode and store it in
+ * multi-byte format. We also need to strip off any
+ * spaces added as part of the NetBIOS name encoding.
+ */
+ wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (mts_wchar_t)), KM_SLEEP);
+ (void) oemstounicodes(wbuf, client_name, SMB_PI_MAX_HOST, cpid);
+ (void) mts_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
+ kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (mts_wchar_t)));
+
+ if ((p = strchr(session->workstation, ' ')) != 0)
+ *p = '\0';
+
+ kmem_free(names, hdr.xh_length);
+ return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
+}
+
+/*
+ * Read 4-byte header from the session socket and build an in-memory
+ * session transport header. See smb_xprt_t definition for header
+ * format information.
+ *
+ * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445. The
+ * first byte of the four-byte header must be 0 and the next three
+ * bytes contain the length of the remaining data.
+ */
+int
+smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
+{
+ unsigned char buf[NETBIOS_HDR_SZ];
+
+ if (smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ) != 0)
+ return (-1);
+
+ switch (session->s_local_port) {
+ case SSN_SRVC_TCP_PORT:
+ ret_hdr->xh_type = buf[0];
+ ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
+ ((uint32_t)buf[2] << 8) |
+ ((uint32_t)buf[3]);
+ break;
+
+ case SMB_SRVC_TCP_PORT:
+ ret_hdr->xh_type = buf[0];
+
+ if (ret_hdr->xh_type != 0) {
+ cmn_err(CE_WARN, "0x%08x: invalid type (%u)",
+ session->ipaddr, ret_hdr->xh_type);
+ return (-1);
+ }
+
+ ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
+ ((uint32_t)buf[2] << 8) |
+ ((uint32_t)buf[3]);
+ break;
+
+ default:
+ cmn_err(CE_WARN, "0x%08x: invalid port %u",
+ session->ipaddr, session->s_local_port);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Encode a transport session packet header into a 4-byte buffer.
+ * See smb_xprt_t definition for header format information.
+ */
+static int
+smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
+ uint8_t *buf, size_t buflen)
+{
+ if (session == NULL || hdr == NULL ||
+ buf == NULL || buflen < NETBIOS_HDR_SZ) {
+ return (-1);
+ }
+
+ switch (session->s_local_port) {
+ case SSN_SRVC_TCP_PORT:
+ buf[0] = hdr->xh_type;
+ buf[1] = ((hdr->xh_length >> 16) & 1);
+ buf[2] = (hdr->xh_length >> 8) & 0xff;
+ buf[3] = hdr->xh_length & 0xff;
+ break;
+
+ case SMB_SRVC_TCP_PORT:
+ buf[0] = hdr->xh_type;
+ buf[1] = (hdr->xh_length >> 16) & 0xff;
+ buf[2] = (hdr->xh_length >> 8) & 0xff;
+ buf[3] = hdr->xh_length & 0xff;
+ break;
+
+ default:
+ cmn_err(CE_WARN, "0x%08x: invalid port (%u)",
+ session->ipaddr, session->s_local_port);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_request_alloc
+ *
+ * Allocate an smb_request_t structure from the kmem_cache. Partially
+ * initialize the found/new request.
+ *
+ * Returns pointer to a request
+ */
+smb_request_t *
+smb_request_alloc(struct smb_session *session, int req_length)
+{
+ struct smb_request *sr;
+
+ sr = kmem_cache_alloc(smb_info.si_cache_request, KM_SLEEP);
+
+ /*
+ * Future: Use constructor to pre-initialize some fields. For now
+ * there are so many fields that it is easiest just to zero the
+ * whole thing and start over.
+ */
+ bzero(sr, sizeof (smb_request_t));
+
+ mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
+ sr->session = session;
+ sr->request_storage.forw = &sr->request_storage;
+ sr->request_storage.back = &sr->request_storage;
+ sr->command.max_bytes = req_length;
+ sr->reply.max_bytes = smb_maxbufsize;
+ sr->sr_req_length = req_length;
+ sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
+ sr->sr_magic = SMB_REQ_MAGIC;
+ sr->sr_state = SMB_REQ_STATE_INITIALIZING;
+ smb_slist_insert_tail(&session->s_req_list, sr);
+ return (sr);
+}
+
+void
+smb_request_init_command_mbuf(smb_request_t *sr)
+{
+ MGET(sr->command.chain, 0, MT_DATA);
+
+ /*
+ * Setup mbuf, mimic MCLGET but use the complete packet buffer.
+ */
+ sr->command.chain->m_ext.ext_buf = sr->sr_request_buf;
+ sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf;
+ sr->command.chain->m_len = sr->sr_req_length;
+ sr->command.chain->m_flags |= M_EXT;
+ sr->command.chain->m_ext.ext_size = sr->sr_req_length;
+ sr->command.chain->m_ext.ext_ref = &mclrefnoop;
+
+ /*
+ * Initialize the rest of the mbuf_chain fields
+ */
+ sr->command.flags = 0;
+ sr->command.shadow_of = 0;
+ sr->command.max_bytes = sr->sr_req_length;
+ sr->command.chain_offset = 0;
+}
+
+/*
+ * smb_request_cancel
+ *
+ * Handle a cancel for a request properly depending on the current request
+ * state.
+ */
+void
+smb_request_cancel(smb_request_t *sr)
+{
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+
+ case SMB_REQ_STATE_SUBMITTED:
+ case SMB_REQ_STATE_ACTIVE:
+ case SMB_REQ_STATE_CLEANED_UP:
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+ break;
+
+ case SMB_REQ_STATE_WAITING_LOCK:
+ /*
+ * This request is waiting on a lock. Wakeup everything
+ * waiting on the lock so that the relevant thread regains
+ * control and notices that is has been canceled. The
+ * other lock request threads waiting on this lock will go
+ * back to sleep when they discover they are still blocked.
+ */
+ sr->sr_state = SMB_REQ_STATE_CANCELED;
+
+ ASSERT(sr->sr_awaiting != NULL);
+ mutex_enter(&sr->sr_awaiting->l_mutex);
+ cv_broadcast(&sr->sr_awaiting->l_cv);
+ mutex_exit(&sr->sr_awaiting->l_mutex);
+
+ break;
+
+ case SMB_REQ_STATE_WAITING_EVENT:
+ case SMB_REQ_STATE_EVENT_OCCURRED:
+ /*
+ * Cancellations for these states are handled by the
+ * notify-change code
+ */
+ break;
+
+ case SMB_REQ_STATE_COMPLETED:
+ case SMB_REQ_STATE_CANCELED:
+ /*
+ * No action required for these states since the request
+ * is completing.
+ */
+ break;
+ /*
+ * Cases included:
+ * SMB_REQ_STATE_FREE:
+ * SMB_REQ_STATE_INITIALIZING:
+ */
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+}
+
+/*
+ * smb_request_free
+ *
+ * release the memories which have been allocated for a smb request.
+ */
+void
+smb_request_free(smb_request_t *sr)
+{
+ ASSERT(sr->session);
+
+ ASSERT(sr->fid_ofile == NULL);
+ ASSERT(sr->sid_odir == NULL);
+ ASSERT(sr->tid_tree == NULL);
+ ASSERT(sr->uid_user == NULL);
+ ASSERT(sr->r_xa == NULL);
+
+ smb_slist_remove(&sr->session->s_req_list, sr);
+
+ sr->session = 0;
+
+ /* Release any temp storage */
+ smbsr_free_malloc_list(&sr->request_storage);
+
+ if (sr->sr_request_buf)
+ kmem_free(sr->sr_request_buf, sr->sr_req_length);
+ if (sr->command.chain)
+ m_freem(sr->command.chain);
+ if (sr->reply.chain)
+ m_freem(sr->reply.chain);
+ if (sr->raw_data.chain)
+ m_freem(sr->raw_data.chain);
+
+ sr->sr_magic = (uint32_t)~SMB_REQ_MAGIC;
+ mutex_destroy(&sr->sr_mutex);
+ kmem_cache_free(smb_info.si_cache_request, sr);
+}
+
+/*ARGSUSED*/
+void
+smb_wakeup_session_daemon(smb_thread_t *thread, void *session_void)
+{
+ struct smb_session *session = session_void;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_TERMINATED:
+ case SMB_SESSION_STATE_DISCONNECTED:
+ break;
+ default:
+ smb_soshutdown(session->sock);
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+}
+
+/*
+ * This is the entry point for processing SMB messages over NetBIOS or
+ * SMB-over-TCP.
+ *
+ * NetBIOS connections require a session request to establish a session
+ * on which to send session messages.
+ *
+ * Session requests are not valid on SMB-over-TCP. We don't need to do
+ * anything here as session requests will be treated as an error when
+ * handling session messages.
+ */
+/*ARGSUSED*/
+void
+smb_session_daemon(smb_thread_t *thread, void *session_void)
+{
+ struct smb_session *session = session_void;
+ int rc = 0;
+
+ ASSERT(session != NULL);
+
+ if (session->s_local_port == SSN_SRVC_TCP_PORT)
+ rc = smb_session_request(session);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+
+ if ((rc == 0) || (session->s_local_port == SMB_SRVC_TCP_PORT))
+ session->s_state = SMB_SESSION_STATE_ESTABLISHED;
+ else
+ session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+
+ while (session->s_state != SMB_SESSION_STATE_DISCONNECTED) {
+ smb_rwx_rwexit(&session->s_lock);
+
+ rc = smb_session_message(session);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+
+ if (rc != 0)
+ break;
+ }
+
+ smb_soshutdown(session->sock);
+ session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+ smb_rwx_rwexit(&session->s_lock);
+
+ DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
+
+ smb_session_cancel(session);
+
+ /*
+ * At this point everything related to the session should have been
+ * cleaned up and we expect that nothing will attempt to use the
+ * socket.
+ */
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ session->s_state = SMB_SESSION_STATE_TERMINATED;
+ smb_sodestroy(session->sock);
+ session->sock = NULL;
+ smb_rwx_rwexit(&session->s_lock);
+
+ /*
+ * Notify SMB service state machine so it can cleanup the session
+ */
+ smb_svcstate_event(SMB_SVCEVT_SESSION_DELETE, (uintptr_t)session);
+}
+
+/*
+ * Read and process SMB requests.
+ *
+ * Returns:
+ * 0 Success
+ * 1 Unable to read transport header
+ * 2 Invalid transport header type
+ * 3 Invalid SMB length (too small)
+ * 4 Unable to read SMB header
+ * 5 Invalid SMB header (bad magic number)
+ * 6 Unable to read SMB data
+ * 2x Write raw failed
+ */
+static int
+smb_session_message(smb_session_t *session)
+{
+ struct smb_request *sr = NULL;
+ smb_xprt_t hdr;
+ uint8_t *req_buf;
+ uint32_t resid;
+ int rc;
+
+ if (smb_session_xprt_gethdr(session, &hdr) != 0)
+ return (1);
+
+ DTRACE_PROBE2(session__receive__xprthdr, struct session *, session,
+ smb_xprt_t *, &hdr);
+
+ if (hdr.xh_type != SESSION_MESSAGE) {
+ /*
+ * Anything other than SESSION_MESSAGE or SESSION_KEEP_ALIVE
+ * is an error. A SESSION_REQUEST may indicate a new session
+ * request but we need to close this session and we can treat
+ * it as an error here.
+ */
+ if (hdr.xh_type == SESSION_KEEP_ALIVE) {
+ session->keep_alive = smb_keep_alive;
+ return (0);
+ }
+
+ return (2);
+ }
+
+ if (hdr.xh_length < SMB_HEADER_LEN)
+ return (3);
+
+ session->keep_alive = smb_keep_alive;
+
+ /*
+ * Allocate a request context, read the SMB header and validate it.
+ * The sr includes a buffer large enough to hold the SMB request
+ * payload. If the header looks valid, read any remaining data.
+ */
+ sr = smb_request_alloc(session, hdr.xh_length);
+
+ req_buf = (uint8_t *)sr->sr_request_buf;
+ resid = hdr.xh_length;
+
+ if (smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN) != 0) {
+ smb_request_free(sr);
+ return (4);
+ }
+
+ if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
+ smb_request_free(sr);
+ return (5);
+ }
+
+ if (resid > SMB_HEADER_LEN) {
+ req_buf += SMB_HEADER_LEN;
+ resid -= SMB_HEADER_LEN;
+
+ if (smb_sorecv(session->sock, req_buf, resid) != 0) {
+ smb_request_free(sr);
+ return (6);
+ }
+ }
+
+ /*
+ * Initialize command MBC to represent the received data.
+ */
+ smb_request_init_command_mbuf(sr);
+
+ DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
+
+ /*
+ * If this is a raw write, hand off the request. The handler
+ * will retrieve the remaining raw data and process the request.
+ */
+ if (SMB_IS_WRITERAW(sr)) {
+ rc = smb_handle_write_raw(session, sr);
+ /* XXX smb_request_free(sr); ??? */
+ return (rc);
+ }
+
+ sr->sr_state = SMB_REQ_STATE_SUBMITTED;
+ (void) taskq_dispatch(smb_info.thread_pool, smb_session_worker,
+ sr, TQ_SLEEP);
+ return (0);
+}
+
+/*
+ * smb_session_wakeup_daemon
+ *
+ * When the smbsrv kernel module/driver gets unloaded, chances are the
+ * smb_nbt_daemon and smb_tcp_daemon threads are blocked in soaccept.
+ * We can't get control of the threads until they return from soaccept.
+ * This function will attempt to connect to the SMB service via
+ * "localhost" to wake up the threads.
+ */
+/*ARGSUSED*/
+static void
+smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void)
+{
+ struct sonode *so = so_void;
+
+ ASSERT(so != NULL);
+
+ mutex_enter(&so->so_lock);
+ so->so_error = EINTR;
+ cv_signal(&so->so_connind_cv);
+ mutex_exit(&so->so_lock);
+}
+
+/*
+ * SMB-over-NetBIOS service.
+ *
+ * Traditional SMB service over NetBIOS (port 139), which requires
+ * that a NetBIOS session be established.
+ */
+void
+smb_nbt_daemon(smb_thread_t *thread, void *arg)
+{
+ /* XXX Defaults for these values should come from smbd and SMF */
+ uint32_t txbuf_size = 128*1024;
+ uint32_t on = 1;
+ struct smb_session *session;
+ struct sonode *l_so, *s_so;
+ struct sockaddr_in sin;
+ int error;
+ smb_info_t *si = arg;
+
+ ASSERT(si != NULL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(SSN_SRVC_TCP_PORT);
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ l_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
+ if (l_so == NULL) {
+ cmn_err(CE_WARN, "NBT: socket create failed");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM);
+ return;
+ }
+
+ (void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&on, sizeof (on));
+
+ if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin),
+ 0, 0)) != 0) {
+ cmn_err(CE_WARN, "NBT: bind failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+ if ((error = solisten(l_so, 20)) < 0) {
+ cmn_err(CE_WARN, "NBT: listen failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+
+ smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so);
+ si->si_connect_progress |= SMB_SI_NBT_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL);
+
+ while (smb_thread_continue_nowait(thread)) {
+ DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so);
+
+ error = soaccept(l_so, 0, &s_so);
+ if (error) {
+ DTRACE_PROBE1(so__accept__error, int, error);
+ if (error == EINTR) {
+ continue;
+ }
+
+ break;
+ }
+
+ DTRACE_PROBE1(so__accept, struct sonode *, s_so);
+
+ (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
+ (const void *)&txbuf_size, sizeof (txbuf_size));
+
+ /*
+ * Create a session for this connection and notify the SMB
+ * service state machine. The service state machine may
+ * start a session thread or reject the session depending
+ * on the current service state or number of connections.
+ */
+ session = smb_session_create(s_so, SSN_SRVC_TCP_PORT);
+ smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE,
+ (uintptr_t)session);
+
+ }
+
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ si->si_connect_progress &= ~SMB_SI_NBT_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+}
+
+/*
+ * SMB-over-TCP (or NetBIOS-less SMB) service.
+ *
+ * SMB service natively over TCP (port 445), i.e. no NetBIOS support.
+ */
+void
+smb_tcp_daemon(smb_thread_t *thread, void *arg)
+{
+ /* XXX Defaults for these values should come from smbd and SMF */
+ uint32_t txbuf_size = 128*1024;
+ uint32_t on = 1;
+ struct smb_session *session;
+ struct sonode *l_so, *s_so;
+ struct sockaddr_in sin;
+ int error;
+ smb_info_t *si = arg;
+
+ ASSERT(si != NULL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(SMB_SRVC_TCP_PORT);
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ l_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
+ if (l_so == NULL) {
+ cmn_err(CE_WARN, "TCP: socket create failed");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM);
+ return;
+ }
+
+ (void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&on, sizeof (on));
+
+ if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin),
+ 0, 0)) != 0) {
+ cmn_err(CE_WARN, "TCP: bind failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+ if ((error = solisten(l_so, 20)) < 0) {
+ cmn_err(CE_WARN, "TCP: listen failed");
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+ return;
+ }
+
+ smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so);
+ si->si_connect_progress |= SMB_SI_TCP_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL);
+
+ while (smb_thread_continue_nowait(thread)) {
+ DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so);
+
+ error = soaccept(l_so, 0, &s_so);
+ if (error) {
+ DTRACE_PROBE1(so__accept__error, int, error);
+ if (error == EINTR) {
+ continue;
+ }
+
+ break;
+ }
+
+ DTRACE_PROBE1(so__accept, struct sonode *, s_so);
+
+ (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *)&on, sizeof (on));
+ (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
+ (const void *)&txbuf_size, sizeof (txbuf_size));
+
+ /*
+ * Create a session for this connection and notify the SMB
+ * service state machine. The service state machine may
+ * start a session thread or reject the session depending
+ * on the current service state or number of connections.
+ */
+ session = smb_session_create(s_so, SMB_SRVC_TCP_PORT);
+ smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE,
+ (uintptr_t)session);
+
+ }
+
+ smb_soshutdown(l_so);
+ smb_sodestroy(l_so);
+ si->si_connect_progress &= ~SMB_SI_TCP_CONNECTED;
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
+}
+
+/*
+ * smb_session_reject
+ *
+ * Build and send a NEGATIVE_SESSION_RESPONSE on the specified socket.
+ * The reason is written to the log.
+ */
+/*ARGSUSED*/
+void
+smb_session_reject(smb_session_t *session, char *reason)
+{
+ unsigned char reply[8];
+
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ if (session->sock != NULL) {
+ reply[0] = NEGATIVE_SESSION_RESPONSE;
+ reply[1] = 0;
+ reply[2] = 0;
+ reply[3] = 1;
+ reply[4] = SESSION_INSUFFICIENT_RESOURCES;
+
+ (void) smb_sosend(session->sock, reply, 5);
+ }
+ smb_rwx_rwexit(&session->s_lock);
+}
+
+/*
+ * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT.
+ */
+smb_session_t *
+smb_session_create(struct sonode *new_so, uint16_t port)
+{
+ uint32_t ipaddr;
+ uint32_t local_ipaddr;
+ struct sockaddr_in sin;
+ smb_session_t *session;
+
+ session = kmem_cache_alloc(smb_info.si_cache_session, KM_SLEEP);
+ bzero(session, sizeof (smb_session_t));
+
+ if (smb_idpool_constructor(&session->s_uid_pool)) {
+ kmem_cache_free(smb_info.si_cache_session, session);
+ return (NULL);
+ }
+
+ session->s_kid = SMB_NEW_KID();
+ session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+ session->native_os = NATIVE_OS_UNKNOWN;
+ session->opentime = lbolt64;
+ session->keep_alive = smb_keep_alive;
+ session->activity_timestamp = lbolt64;
+
+ smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_session_lnd));
+
+ smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
+ offsetof(smb_user_t, u_lnd));
+
+ smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
+ offsetof(smb_xa_t, xa_lnd));
+
+ smb_thread_init(&session->s_thread, "smb_session", &smb_session_daemon,
+ session, smb_wakeup_session_daemon, session);
+
+ smb_rwx_init(&session->s_lock);
+
+ bcopy(new_so->so_faddr_sa, &sin, new_so->so_faddr_len);
+ ipaddr = sin.sin_addr.s_addr;
+
+ bcopy(new_so->so_laddr_sa, &sin, new_so->so_faddr_len);
+ local_ipaddr = sin.sin_addr.s_addr;
+
+ session->s_local_port = port;
+ session->ipaddr = ipaddr;
+ session->local_ipaddr = local_ipaddr;
+ session->sock = new_so;
+
+ session->s_magic = SMB_SESSION_MAGIC;
+ return (session);
+}
+
+void
+smb_session_delete(smb_session_t *session)
+{
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ session->s_magic = (uint32_t)~SMB_SESSION_MAGIC;
+
+ smb_rwx_destroy(&session->s_lock);
+ smb_thread_destroy(&session->s_thread);
+ smb_slist_destructor(&session->s_req_list);
+ smb_llist_destructor(&session->s_user_list);
+ smb_llist_destructor(&session->s_xa_list);
+
+ ASSERT(session->s_tree_cnt == 0);
+ ASSERT(session->s_file_cnt == 0);
+ ASSERT(session->s_dir_cnt == 0);
+
+ smb_idpool_destructor(&session->s_uid_pool);
+ kmem_cache_free(smb_info.si_cache_session, session);
+}
+
+void
+smb_session_cancel(smb_session_t *session)
+{
+ smb_xa_t *xa, *nextxa;
+
+ /* All the request currently being treated must be canceled. */
+ smb_session_cancel_requests(session);
+
+ /*
+ * We wait for the completion of all the requests associated with
+ * this session.
+ */
+ smb_slist_wait_for_empty(&session->s_req_list);
+
+ /*
+ * At this point the reference count of the users, trees, files,
+ * directories should be zero. It should be possible to destroy them
+ * without any problem.
+ */
+ xa = smb_llist_head(&session->s_xa_list);
+ while (xa) {
+ nextxa = smb_llist_next(&session->s_xa_list, xa);
+ smb_xa_close(xa);
+ xa = nextxa;
+ }
+ smb_user_logoff_all(session);
+}
+
+void
+smb_session_cancel_requests(
+ smb_session_t *session)
+{
+ smb_request_t *sr;
+ smb_request_t *tmp;
+
+ /* All the SMB requests on the notification queue are canceled. */
+ smb_process_session_notify_change_queue(session);
+
+ smb_slist_enter(&session->s_req_list);
+ sr = smb_slist_head(&session->s_req_list);
+ while (sr) {
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+ tmp = smb_slist_next(&session->s_req_list, sr);
+
+ smb_request_cancel(sr);
+
+ sr = tmp;
+ }
+ smb_slist_exit(&session->s_req_list);
+}
+
+void
+smb_session_worker(
+ void *arg)
+{
+ smb_request_t *sr;
+
+ sr = (smb_request_t *)arg;
+
+ ASSERT(sr != NULL);
+ ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+
+ mutex_enter(&sr->sr_mutex);
+ switch (sr->sr_state) {
+ case SMB_REQ_STATE_SUBMITTED:
+ mutex_exit(&sr->sr_mutex);
+ if (smb_dispatch_request(sr) < 0) {
+ smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
+ if (sr->session->s_state !=
+ SMB_SESSION_STATE_DISCONNECTED) {
+ smb_soshutdown(sr->session->sock);
+ sr->session->s_state =
+ SMB_SESSION_STATE_DISCONNECTED;
+ }
+ smb_rwx_rwexit(&sr->session->s_lock);
+ }
+ mutex_enter(&sr->sr_mutex);
+ if (!sr->sr_keep) {
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+ smb_request_free(sr);
+ break;
+ }
+ mutex_exit(&sr->sr_mutex);
+ break;
+
+ default:
+ ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+ smb_request_free(sr);
+ break;
+ }
+}
+
+/*
+ * smb_session_disconnect_share
+ *
+ * Disconnects the specified share. This function should be called after the
+ * share passed in has been made unavailable by the "share manager".
+ */
+void
+smb_session_disconnect_share(char *sharename)
+{
+ smb_session_t *session;
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+
+ session = NULL;
+ while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx,
+ session)) != NULL) {
+
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
+ smb_user_t *user;
+ smb_user_t *next;
+
+ user = smb_user_lookup_by_state(session, NULL);
+ while (user) {
+ smb_user_disconnect_share(user, sharename);
+ next = smb_user_lookup_by_state(session, user);
+ smb_user_release(user);
+ user = next;
+ }
+ break;
+
+ }
+ default:
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
+
+/*
+ * smb_session_disconnect_volume
+ *
+ * This function is called when a volume is deleted. We need to ensure
+ * all trees with a reference to the volume are destroyed before we
+ * discard the fs_online. Before destroying each tree, we notify any
+ * in-progress requests and give them a chance to complete.
+ *
+ * NOTE:
+ * We shouldn't be accepting any new connection on this volume while
+ * we are in this function.
+ */
+void
+smb_session_disconnect_volume(fs_desc_t *fsd)
+{
+ smb_session_t *session;
+
+ smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
+
+ session = NULL;
+ while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx,
+ session)) != NULL) {
+
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
+ smb_user_t *user;
+ smb_user_t *next;
+
+ user = smb_user_lookup_by_state(session, NULL);
+ while (user) {
+ smb_user_disconnect_volume(user, fsd);
+ next = smb_user_lookup_by_state(session, user);
+ smb_user_release(user);
+ user = next;
+ }
+ break;
+
+ }
+ default:
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+ }
+ smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
new file mode 100644
index 0000000000..b7217cf78b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
@@ -0,0 +1,516 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * SMB: session_setup_andx
+ *
+ * This SMB is used to further "Set up" the session normally just
+ * established via the negotiate protocol.
+ *
+ * One primary function is to perform a "user logon" in the case where the
+ * server is in user level security mode. The Uid in the SMB header is set
+ * by the client to be the userid desired for the AccountName and validated
+ * by the AccountPassword.
+ *
+ * If the negotiated protocol is prior to NT LM 0.12, the format of
+ * SMB_COM_SESSION_SETUP_ANDX is:
+ *
+ * Client Request Description
+ * ============================== =====================================
+ *
+ * UCHAR WordCount; Count of parameter words = 10
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT MaxBufferSize; Client maximum buffer size
+ * USHORT MaxMpxCount; Actual maximum multiplexed pending
+ * requests
+ * USHORT VcNumber; 0 = first (only), nonzero=additional
+ * VC number
+ * ULONG SessionKey; Session key (valid iff VcNumber != 0)
+ * USHORT PasswordLength; Account password size
+ * ULONG Reserved; Must be 0
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR AccountPassword[]; Account Password
+ * STRING AccountName[]; Account Name
+ * STRING PrimaryDomain[]; Client's primary domain
+ * STRING NativeOS[]; Client's native operating system
+ * STRING NativeLanMan[]; Client's native LAN Manager type
+ *
+ * and the response is:
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF =
+ * none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Action; Request mode:
+ * bit0 = logged in as GUEST
+ * USHORT ByteCount; Count of data bytes
+ * STRING NativeOS[]; Server's native operating system
+ * STRING NativeLanMan[]; Server's native LAN Manager type
+ * STRING PrimaryDomain[]; Server's primary domain
+ *
+ * If the server is in "share level security mode", the account name and
+ * passwd should be ignored by the server.
+ *
+ * If challenge/response authentication is not being used, AccountPassword
+ * should be a null terminated ASCII string with PasswordLength set to the
+ * string size including the null; the password will case insensitive. If
+ * challenge/response authentication is being used (see section 2.10), then
+ * AccountPassword will be the response to the server's challenge, and
+ * PasswordLength should be set to its length.
+ *
+ * The server validates the name and password supplied and if valid, it
+ * registers the user identifier on this session as representing the
+ * specified AccountName. The Uid field in the SMB header will then be
+ * used to validate access on subsequent SMB requests. The SMB requests
+ * where permission checks are required are those which refer to a
+ * symbolically named resource such as SMB_COM_OPEN, SMB_COM_RENAME,
+ * SMB_COM_DELETE, etc.. The value of the Uid is relative to a specific
+ * client/server session so it is possible to have the same Uid value
+ * represent two different users on two different sessions at the server.
+ *
+ * Multiple session setup commands may be sent to register additional users
+ * on this session. If the server receives an additional
+ * SMB_COM_SESSION_SETUP_ANDX, only the Uid, AccountName and
+ * AccountPassword fields need contain valid values (the server MUST ignore
+ * the other fields).
+ *
+ * The client writes the name of its domain in PrimaryDomain if it knows
+ * what the domain name is. If the domain name is unknown, the client
+ * either encodes it as a NULL string, or as a question mark.
+ *
+ * If bit0 of Action is set, this informs the client that although the
+ * server did not recognize the AccountName, it logged the user in as a
+ * guest. This is optional behavior by the server, and in any case one
+ * would ordinarily expect guest privileges to limited.
+ *
+ * Another function of the Session Set Up protocol is to inform the server
+ * of the maximum values which will be utilized by this client. Here
+ * MaxBufferSize is the maximum message size which the client can receive.
+ * Thus although the server may support 16k buffers (as returned in the
+ * SMB_COM_NEGOTIATE response), if the client only has 4k buffers, the
+ * value of MaxBufferSize here would be 4096. The minimum allowable value
+ * for MaxBufferSize is 1024. The SMB_COM_NEGOTIATE response includes the
+ * server buffer size supported. Thus this is the maximum SMB message size
+ * which the client can send to the server. This size may be larger than
+ * the size returned to the server from the client via the
+ * SMB_COM_SESSION_SETUP_AND X protocol which is the maximum SMB message
+ * size which the server may send to the client. Thus if the server's
+ * buffer size were 4k and the client's buffer size were only 2K, the
+ * client could send up to 4k (standard) write requests but must only
+ * request up to 2k for (standard) read requests.
+ *
+ * The field, MaxMpxCount informs the server of the maximum number of
+ * requests which the client will have outstanding to the server
+ * simultaneously (see sections 5.13 and 5.25).
+ *
+ * The VcNumber field specifies whether the client wants this to be the
+ * first VC or an additional VC. If the the SMB_COM_SESSION_SETUP_ANDX
+ * request contains a VcNumber of 0 and other VCs are still connected to
+ * that client, they should be aborted to free any resources held by the
+ * server. This condition could occur if the client was rebooted and
+ * reconnected to the server before the transport level had informed the
+ * server of the previous VC termination. There is more information on
+ * VCs in smb_negotiate.c.
+ *
+ * The values for MaxBufferSize, MaxMpxCount, and VcNumber must be less
+ * than or equal to the maximum values supported by the server as returned
+ * in the SMB_COM_NEGOTIATE response.
+ *
+ * If the negotiated SMB dialect is "NT LM 0.12" or later, the format of
+ * the response SMB is unchanged, but the request is:
+ *
+ * Client Request Description
+ * ============================== =====================================
+ *
+ * UCHAR WordCount; Count of parameter words = 13
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT MaxBufferSize; Client's maximum buffer size
+ * USHORT MaxMpxCount; Actual maximum multiplexed pending
+ * requests
+ * USHORT VcNumber; 0 = first (only), nonzero=additional
+ * VC number
+ * ULONG SessionKey; Session key (valid iff VcNumber != 0)
+ * USHORT Account password size, ANSI
+ * CaseInsensitivePasswordLength;
+ * USHORT Account password size, Unicode
+ * CaseSensitivePasswordLength;
+ * ULONG Reserved; must be 0
+ * ULONG Capabilities; Client capabilities
+ * USHORT ByteCount; Count of data bytes; min = 0
+ * UCHAR Account Password, ANSI
+ * CaseInsensitivePassword[];
+ * UCHAR CaseSensitivePassword[]; Account Password, Unicode
+ * STRING AccountName[]; Account Name, Unicode
+ * STRING PrimaryDomain[]; Client's primary domain, Unicode
+ * STRING NativeOS[]; Client's native operating system,
+ * Unicode
+ * STRING NativeLanMan[]; Client's native LAN Manager type,
+ * Unicode
+ *
+ * The client expresses its capabilities to the server encoded in the
+ * Capabilities field:
+ *
+ * Capability Name Encoding Description
+ * ======================== ========= ================================
+ *
+ * CAP_UNICODE 0x0004 The client can use UNICODE
+ * strings
+ * CAP_LARGE_FILES 0x0008 The client can deal with files
+ * having 64 bit offsets
+ * CAP_NT_SMBS 0x0010 The client understands the SMBs
+ * introduced with the NT LM 0.12
+ * dialect. Implies CAP_NT_FIND.
+ * CAP_NT_FIND 0x0200
+ * CAP_STATUS32 0x0040 The client can receive 32 bit
+ * errors encoded in Status.Status
+ * CAP_LEVEL_II_OPLOCKS 0x0080 The client understands Level II
+ * oplocks
+ *
+ * The entire message sent and received including the optional ANDX SMB
+ * must fit in the negotiated maximum transfer size. The following are the
+ * only valid SMB commands for AndXCommand for SMB_COM_SESSION_SETUP_ANDX
+ *
+ * SMB_COM_TREE_CONNECT_ANDX SMB_COM_OPEN
+ * SMB_COM_OPEN_ANDX SMB_COM_CREATE
+ * SMB_COM_CREATE_NEW SMB_COM_CREATE_DIRECTORY
+ * SMB_COM_DELETE SMB_COM_DELETE_DIRECTORY
+ * SMB_COM_FIND SMB_COM_FIND_UNIQUE
+ * SMB_COM_COPY SMB_COM_RENAME
+ * SMB_COM_NT_RENAME SMB_COM_CHECK_DIRECTORY
+ * SMB_COM_QUERY_INFORMATION SMB_COM_SET_INFORMATION
+ * SMB_COM_NO_ANDX_COMMAND SMB_COM_OPEN_PRINT_FILE
+ * SMB_COM_GET_PRINT_QUEUE SMB_COM_TRANSACTION
+ *
+ * 4.1.2.1 Errors
+ *
+ * ERRSRV/ERRerror - no NEG_PROT issued
+ * ERRSRV/ERRbadpw - password not correct for given user name
+ * ERRSRV/ERRtoomanyuids - maximum number of users per session exceeded
+ * ERRSRV/ERRnosupport - chaining of this request to the previous one is
+ * not supported
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/smb_door_svc.h>
+
+int
+smb_com_session_setup_andx(struct smb_request *sr)
+{
+ uint16_t maxbufsize, maxmpxcount, vcnumber = 0;
+ uint32_t sesskey;
+ uint32_t capabilities = 0;
+ char *account_name = "";
+ char *primary_domain = "";
+ char *native_os = "";
+ char *native_lanman = "";
+ char *hostname = smb_info.si.skc_hostname;
+ smb_token_t *usr_token = NULL;
+ smb_user_t *user = NULL;
+ int security = smb_info.si.skc_secmode;
+
+ uint16_t ci_pwlen = 0;
+ unsigned char *ci_password = NULL;
+ uint16_t cs_pwlen = 0;
+ unsigned char *cs_password = NULL;
+
+ netr_client_t clnt_info;
+ smb_session_key_t *session_key = NULL;
+ int rc;
+
+ if (sr->session->dialect >= NT_LM_0_12) {
+ rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
+ &sr->andx_off, &maxbufsize, &maxmpxcount, &vcnumber,
+ &sesskey, &ci_pwlen, &cs_pwlen, &capabilities);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP);
+ cs_password = kmem_alloc(cs_pwlen + 1, KM_SLEEP);
+
+ /*
+ * The padding between the Native OS and Native LM is a
+ * bit strange. On NT4.0, there is a 2 byte pad between
+ * the OS (Windows NT 1381) and LM (Windows NT 4.0).
+ * On Windows 2000, there is no padding between the OS
+ * (Windows 2000 2195) and LM (Windows 2000 5.0).
+ *
+ * If the padding is removed from this decode string
+ * the NT4.0 LM comes out as an empty string.
+ *
+ * So if the client's native OS is Win NT we consider
+ * the padding otherwise we don't.
+ */
+ rc = smbsr_decode_data(sr, "%#c#cuuu",
+ sr,
+ ci_pwlen, ci_password,
+ cs_pwlen, cs_password,
+ &account_name,
+ &primary_domain,
+ &native_os);
+
+ if (rc != 0) {
+ kmem_free(ci_password, ci_pwlen + 1);
+ kmem_free(cs_password, cs_pwlen + 1);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password[ci_pwlen] = 0;
+ cs_password[cs_pwlen] = 0;
+
+ sr->session->native_os = smbnative_os_value(native_os);
+
+ if (sr->session->native_os == NATIVE_OS_WINNT)
+ rc = smbsr_decode_data(sr, "%,u", sr, &native_lanman);
+ else
+ rc = smbsr_decode_data(sr, "%u", sr, &native_lanman);
+
+ /*
+ * Native Lanman could be null so we really don't care
+ * if above decode fails, but to have a valid value for
+ * the field we set it to Win NT.
+ */
+ if (rc != 0)
+ native_lanman = "NT LAN Manager 4.0";
+
+ } else {
+ rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
+ &sr->andx_off, &maxbufsize, &maxmpxcount,
+ &vcnumber, &sesskey, &ci_pwlen);
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP);
+ rc = smbsr_decode_data(sr, "%#c", sr, ci_pwlen, ci_password);
+ if (rc != 0) {
+ kmem_free(ci_password, ci_pwlen + 1);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ ci_password[ci_pwlen] = 0;
+
+ /*
+ * Despite the CIFS/1.0 spec, the rest of this message is
+ * not always present. We need to try to get the account
+ * name and the primary domain but we don't care about the
+ * the native OS or native LanMan fields.
+ */
+ if (smbsr_decode_data(sr, "%u", sr, &account_name) != 0)
+ account_name = "";
+
+ if (smbsr_decode_data(sr, "%u", sr, &primary_domain) != 0)
+ primary_domain = "";
+
+ sr->session->native_os = NATIVE_OS_UNKNOWN;
+ }
+
+ /*
+ * If the vcnumber is zero, we can discard any
+ * other connections associated with this client.
+ */
+ sr->session->vcnumber = vcnumber;
+ if (vcnumber == 0)
+ smb_reconnection_check(sr->session);
+
+ sr->session->smb_msg_size = maxbufsize;
+
+ bzero(&clnt_info, sizeof (netr_client_t));
+
+ if (*primary_domain == 0)
+ primary_domain = smb_info.si.skc_resource_domain;
+
+ if ((cs_pwlen == 0) &&
+ (ci_pwlen == 0 || (ci_pwlen == 1 && *ci_password == 0))) {
+ /* anonymous user */
+ clnt_info.flags |= NETR_CFLG_ANON;
+ account_name = "nobody";
+ } else if (*account_name == '\0') {
+ if (ci_password)
+ kmem_free(ci_password, ci_pwlen + 1);
+ if (cs_password)
+ kmem_free(cs_password, cs_pwlen + 1);
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ } else if (utf8_strcasecmp(primary_domain, hostname) == 0) {
+ /*
+ * When domain name is equal to hostname, it means
+ * the user is local even if system is running in
+ * domain mode, so perform a local logon.
+ */
+ clnt_info.flags |= NETR_CFLG_LOCAL;
+ } else if (security == SMB_SECMODE_DOMAIN) {
+ clnt_info.flags |= NETR_CFLG_DOMAIN;
+ } else if (security == SMB_SECMODE_WORKGRP) {
+ clnt_info.flags |= NETR_CFLG_LOCAL;
+ }
+
+ (void) utf8_strupr(primary_domain);
+
+ /*
+ * If this is an additional setup for an existing user
+ * on this session, duplicate the authenticated user.
+ * Otherwise authenticate as new user.
+ */
+ user = smb_user_lookup_by_name(sr->session, primary_domain,
+ account_name);
+
+ if (user) {
+ smb_user_t *orig_user = user;
+
+ user = smb_user_dup(orig_user);
+ smb_user_release(orig_user);
+ } else {
+ cred_t *cr;
+ uint32_t privileges;
+
+ clnt_info.logon_level = NETR_NETWORK_LOGON;
+ clnt_info.domain = primary_domain;
+ clnt_info.username = account_name;
+ clnt_info.workstation = sr->session->workstation;
+ clnt_info.ipaddr = sr->session->ipaddr;
+ clnt_info.local_ipaddr = sr->session->local_ipaddr;
+ clnt_info.challenge_key.challenge_key_val =
+ sr->session->challenge_key;
+ clnt_info.challenge_key.challenge_key_len =
+ sr->session->challenge_len;
+ clnt_info.nt_password.nt_password_val = cs_password;
+ clnt_info.nt_password.nt_password_len = cs_pwlen;
+ clnt_info.lm_password.lm_password_val = ci_password;
+ clnt_info.lm_password.lm_password_len = ci_pwlen;
+ clnt_info.native_os = sr->session->native_os;
+ clnt_info.native_lm = smbnative_lm_value(native_lanman);
+ clnt_info.local_port = sr->session->s_local_port;
+
+ DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *,
+ &clnt_info);
+
+ usr_token = smb_upcall_get_token(&clnt_info);
+ if (usr_token == 0) {
+ if (ci_password)
+ kmem_free(ci_password, ci_pwlen + 1);
+ if (cs_password)
+ kmem_free(cs_password, cs_pwlen + 1);
+ smbsr_raise_error(sr, ERRSRV, ERRbadpw);
+ /* NOTREACHED */
+ }
+
+ if (usr_token->tkn_session_key) {
+ session_key = kmem_alloc(sizeof (smb_session_key_t),
+ KM_SLEEP);
+ (void) memcpy(session_key, usr_token->tkn_session_key,
+ sizeof (smb_session_key_t));
+ }
+
+ cr = smb_cred_create(usr_token, &privileges);
+ if (cr != NULL) {
+ user = smb_user_login(sr->session, cr,
+ usr_token->tkn_domain_name,
+ usr_token->tkn_account_name,
+ usr_token->tkn_flags,
+ privileges,
+ usr_token->tkn_audit_sid);
+ smb_cred_rele(cr);
+ }
+ smb_token_free(usr_token);
+ }
+
+ if (ci_password)
+ kmem_free(ci_password, ci_pwlen + 1);
+ if (cs_password)
+ kmem_free(cs_password, cs_pwlen + 1);
+
+ if (user == NULL) {
+ if (session_key)
+ kmem_free(session_key, sizeof (smb_session_key_t));
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_HANDLE);
+ /* no return */
+ }
+
+ sr->user_cr = user->u_cred;
+ sr->smb_uid = user->u_uid;
+ sr->uid_user = user;
+ sr->session->capabilities = capabilities;
+
+ /*
+ * Check to see if SMB signing is enable, but if it is already turned
+ * on leave it.
+ * The first authenticated logon provides the MAC key and sequence
+ * numbers for signing all further session on the
+ * same network connection.
+ */
+ if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) &&
+ (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) &&
+ (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
+ session_key)
+ smb_sign_init(sr, session_key, (char *)cs_password, cs_pwlen);
+
+ if (session_key)
+ kmem_free(session_key, sizeof (smb_session_key_t));
+
+ /*
+ * NT systems use different native OS and native LanMan values
+ * dependent on whether they are acting as a client or a server.
+ * As a server, NT 4.0 responds with the following values:
+ *
+ * NativeOS: Windows NT 4.0
+ * NativeLM: NT LAN Manager 4.0
+ *
+ * We should probably use the same values as NT but this code has
+ * been using the product name and "Windows NT 4.0" for a long time
+ * and I don't know if a change would cause any problems (see the
+ * conditional test below).
+ */
+ smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
+ 3,
+ sr->andx_com,
+ -1, /* andx_off */
+ ((user->u_flags & SMB_USER_FLAG_GUEST) ? 1 : 0),
+ VAR_BCC,
+ sr,
+ "Windows NT 4.0",
+ "NT LAN Manager 4.0",
+ smb_info.si.skc_resource_domain);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
new file mode 100644
index 0000000000..728c86b8cd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
@@ -0,0 +1,128 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: set_information
+ *
+ * This message is sent to change the information about a file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 8
+ * USHORT FileAttributes; Attributes of the file
+ * UTIME LastWriteTime; Time of last write
+ * USHORT Reserved [5]; Reserved (must be 0)
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING FileName[]; File name
+ *
+ * FileName is the fully qualified name of the file relative to the Tid.
+ *
+ * Support of all parameters is optional. A server which does not
+ * implement one of the parameters will ignore that field. If the
+ * LastWriteTime field contain zero then the file's time is not changed.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_set_information(struct smb_request *sr)
+{
+ int rc;
+ unsigned short dattr;
+ timestruc_t utime;
+ char *path;
+ struct smb_node *dir_node;
+ smb_attr_t attr;
+ struct smb_node *node;
+ char *name;
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ if (smbsr_decode_vwv(sr, "wl10.", &dattr, &utime.tv_sec) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+ utime.tv_nsec = 0;
+
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
+ != 0) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, name, &node, &attr, 0, 0)) != 0) {
+ smb_node_release(dir_node);
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smb_node_release(dir_node);
+
+ smb_node_set_dosattr(node, dattr);
+
+ /*
+ * IR101794 The behaviour when the time field is set to -1
+ * is not documented, so we'll assume it should be treated
+ * like 0. We ignore utime.tv_nsec is assumed to be 0 here.
+ */
+ if (utime.tv_sec != 0 && utime.tv_sec != -1) {
+ utime.tv_sec = smb_local_time_to_gmt(utime.tv_sec);
+ smb_node_set_time(node, 0, &utime, 0, 0, SMB_AT_MTIME);
+ }
+
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ smb_node_release(node);
+ if (rc) {
+ kmem_free(name, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+ kmem_free(name, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
new file mode 100644
index 0000000000..1510f7228a
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
@@ -0,0 +1,123 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: set_information2
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 7
+ * USHORT Fid; File handle
+ * SMB_DATE CreationDate;
+ * SMB_TIME CreationTime;
+ * SMB_DATE LastAccessDate;
+ * SMB_TIME LastAccessTime;
+ * SMB_DATE LastWriteDate;
+ * SMB_TIME LastWriteTime;
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * SMB_COM_SET_INFORMATION2 sets information about the file represented by
+ * Fid. The target file is updated from the values specified. A date or
+ * time value or zero indicates to leave that specific date and time
+ * unchanged.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Fid must be open with (at least) write permission.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_set_information2(struct smb_request *sr)
+{
+ unsigned short la_ddate, la_dtime;
+ unsigned short lw_ddate, lw_dtime;
+ unsigned short cr_ddate, cr_dtime;
+ timestruc_t crtime, mtime, atime;
+ unsigned int what = 0;
+ struct smb_node *node;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "wwwwwww", &sr->smb_fid, &cr_ddate, &cr_dtime,
+ &la_ddate, &la_dtime, &lw_ddate, &lw_dtime);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ node = sr->fid_ofile->f_node;
+
+ if (node == 0 || sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
+ cmn_err(CE_NOTE, "SmbSetInfo2: access denied");
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ crtime.tv_nsec = mtime.tv_nsec = atime.tv_nsec = 0;
+
+ if (cr_ddate || cr_dtime) {
+ crtime.tv_sec = smb_local_time_to_gmt(
+ dosfs_dos_to_ux_time(cr_ddate, cr_dtime));
+ what |= SMB_AT_CRTIME;
+ }
+
+ if (lw_ddate || lw_dtime) {
+ mtime.tv_sec = smb_local_time_to_gmt(
+ dosfs_dos_to_ux_time(lw_ddate, lw_dtime));
+ what |= SMB_AT_MTIME;
+ }
+
+ if (la_ddate || la_dtime) {
+ atime.tv_sec = smb_local_time_to_gmt(
+ dosfs_dos_to_ux_time(la_ddate, la_dtime));
+ what |= SMB_AT_ATIME;
+ }
+
+ smb_node_set_time(node, &crtime, &mtime, &atime, 0, what);
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ if (rc) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c b/usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c
new file mode 100644
index 0000000000..63a7f5d314
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_share_kdoor_client.c
@@ -0,0 +1,730 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Kernel door client for LanMan share management.
+ */
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/door.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/lmerr.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/lmshare_door.h>
+#include <smbsrv/alloc.h>
+#include <smbsrv/smbinfo.h>
+
+door_handle_t lmshrd_dh;
+int lmshrd_init = 0;
+kmutex_t lmshrd_dh_mtx;
+
+
+char *lmshrd_desc[] = {
+ "",
+ "LmshrkOpenIter",
+ "LmshrkCloseIter",
+ "LmshrkIterate",
+ "LmshrkNumShares",
+ "",
+ "",
+ "LmshrkGetinfo",
+ "",
+ "",
+ "LmshrkExists",
+ "LmshrkIsSpecial",
+ "LmshrkIsRestricted",
+ "LmshrkIsAdmin",
+ "LmshrkIsValid",
+ "LmshrkIsDir",
+ "LmshrkList",
+ "LmshrkListTrans",
+ "LmshrkNumTrans",
+ "SmbGetKConfig",
+ 0
+};
+
+
+static int
+lmshrd_kclient_open()
+{
+ int err = 0;
+
+ mutex_enter(&lmshrd_dh_mtx);
+ if (lmshrd_init == 0) {
+ if ((err = door_ki_open(LMSHR_DOOR_NAME, &lmshrd_dh)) != 0)
+ cmn_err(CE_WARN, "lmshrd_kclient: open %s failed",
+ LMSHR_DOOR_NAME);
+ else
+ lmshrd_init = 1;
+ }
+ mutex_exit(&lmshrd_dh_mtx);
+
+ return (err);
+}
+
+static void
+lmshrd_kclient_close()
+{
+ mutex_enter(&lmshrd_dh_mtx);
+ if (lmshrd_init) {
+ door_ki_rele(lmshrd_dh);
+ lmshrd_init = 0;
+ }
+ mutex_exit(&lmshrd_dh_mtx);
+}
+
+/*
+ * lmshrd_kclient_start
+ *
+ * The SMB kernel module should invoke this function upon startup.
+ */
+int
+lmshrd_kclient_start()
+{
+ int rc;
+
+ mutex_init(&lmshrd_dh_mtx, NULL, MUTEX_DEFAULT, NULL);
+ rc = lmshrd_kclient_open();
+
+ return (rc);
+}
+
+/*
+ * lmshrd_kclient_stop
+ *
+ * The SMB kernel module should invoke this function upon unload.
+ */
+void
+lmshrd_kclient_stop()
+{
+ lmshrd_kclient_close();
+ mutex_destroy(&lmshrd_dh_mtx);
+}
+
+/*
+ * Return 0 upon success. Otherwise, -1.
+ */
+static int
+lmshrd_door_check_srv_status(int opcode, smb_dr_ctx_t *dec_ctx)
+{
+ int status = smb_dr_get_int32(dec_ctx);
+ int err;
+ int rc = -1;
+
+ switch (status) {
+ case LMSHR_DOOR_SRV_SUCCESS:
+ rc = 0;
+ break;
+
+ case LMSHR_DOOR_SRV_ERROR:
+ err = smb_dr_get_uint32(dec_ctx);
+ cmn_err(CE_WARN, "%s: Encountered door server error %d",
+ lmshrd_desc[opcode], err);
+ break;
+
+ default:
+ cmn_err(CE_WARN, "%s: Unknown door server status",
+ lmshrd_desc[opcode]);
+ }
+
+ if (rc != 0) {
+ if ((err = smb_dr_decode_finish(dec_ctx)) != 0)
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], err);
+ }
+
+ return (rc);
+}
+
+uint64_t
+lmshrd_open_iterator(int mode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ uint64_t lmshr_iter = 0;
+
+ int opcode = LMSHR_DOOR_OPEN_ITERATOR;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (lmshr_iter);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (lmshr_iter);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_int32(enc_ctx, mode);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (lmshr_iter);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+ }
+
+ lmshr_iter = smb_dr_get_lmshr_iterator(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (lmshr_iter);
+}
+
+
+DWORD
+lmshrd_close_iterator(uint64_t iterator)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_CLOSE_ITERATOR;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_Success);
+}
+
+DWORD
+lmshrd_iterate(uint64_t iterator, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ int opcode = LMSHR_DOOR_ITERATE;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ bzero(si, sizeof (lmshare_info_t));
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_lmshr_iterator(enc_ctx, iterator);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_Success);
+}
+
+int
+lmshrd_num_shares(void)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ unsigned int status = 0;
+ DWORD num_shares;
+ int opcode = LMSHR_DOOR_NUM_SHARES;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (-1);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (-1);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (-1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ num_shares = smb_dr_get_uint32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (num_shares);
+}
+
+DWORD
+lmshrd_getinfo(char *share_name, lmshare_info_t *si)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ DWORD rc;
+ int opcode = LMSHR_DOOR_GETINFO;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ smb_dr_get_lmshare(dec_ctx, si);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (rc);
+}
+
+int
+lmshrd_check(char *share_name, int opcode)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status, rc;
+
+ if (!lmshrd_init && lmshrd_kclient_open() != 0)
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (NERR_InternalError);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+ smb_dr_put_string(enc_ctx, share_name);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (NERR_InternalError);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_int32(dec_ctx);
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (rc);
+}
+
+int
+lmshrd_exists(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_EXISTS));
+}
+
+int
+lmshrd_is_special(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_SPECIAL));
+}
+
+int
+lmshrd_is_restricted(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_RESTRICTED));
+}
+
+int
+lmshrd_is_admin(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_ADMIN));
+}
+
+int
+lmshrd_is_valid(char *share_name)
+{
+ return (lmshrd_check(share_name, LMSHR_DOOR_IS_VALID));
+}
+
+int
+lmshrd_is_dir(char *path)
+{
+ return (lmshrd_check(path, LMSHR_DOOR_IS_DIR));
+}
+
+int
+smb_get_kconfig(smb_kmod_cfg_t *cfg)
+{
+ door_arg_t arg;
+ char *buf;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ int status;
+ int opcode = SMB_GET_KCONFIG;
+
+ if (!lmshrd_init && lmshrd_kclient_start() != 0)
+ return (-1);
+
+ buf = MEM_MALLOC("lmshrd_kclient", LMSHR_DOOR_SIZE);
+ if (!buf)
+ return (-1);
+
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+
+ if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ cmn_err(CE_WARN, "%s: Encode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ arg.data_ptr = buf;
+ arg.data_size = used;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = buf;
+ arg.rsize = LMSHR_DOOR_SIZE;
+
+ if (door_ki_upcall(lmshrd_dh, &arg) != 0) {
+ cmn_err(CE_WARN, "%s: Door call failed", lmshrd_desc[opcode]);
+ MEM_FREE("lmshrd_kclient", buf);
+ lmshrd_kclient_close();
+ return (-1);
+ }
+
+ dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ smb_dr_get_kconfig(dec_ctx, cfg);
+
+ if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
+ cmn_err(CE_WARN, "%s: Decode error %d",
+ lmshrd_desc[opcode], status);
+ MEM_FREE("lmshrd_kclient", buf);
+ return (-1);
+ }
+
+ MEM_FREE("lmshrd_kclient", buf);
+ return (0);
+}
+
+/*
+ * This is a special interface that will be utilized by ZFS to cause
+ * a share to be added/removed
+ *
+ * arg is either a lmshare_info_t or share_name from userspace.
+ * It will need to be copied into the kernel. It is lmshare_info_t
+ * for add operations and share_name for delete operations.
+ */
+int
+lmshrd_share_upcall(void *arg, boolean_t add_share)
+{
+ door_arg_t doorarg = { 0 };
+ char *buf = NULL;
+ char *str = NULL;
+ int error;
+ int rc;
+ unsigned int used;
+ smb_dr_ctx_t *dec_ctx;
+ smb_dr_ctx_t *enc_ctx;
+ lmshare_info_t *lmshare = NULL;
+ int opcode;
+
+ opcode = add_share == B_TRUE ? LMSHR_DOOR_ADD : LMSHR_DOOR_DELETE;
+
+ /* Return error if server isn't up and running */
+ if (!lmshrd_init)
+ return (NERR_ServerNotStarted);
+
+ if (lmshrd_kclient_open())
+ return (NERR_InternalError);
+
+ buf = MEM_MALLOC("lmshrd_share_upcall", LMSHR_DOOR_SIZE);
+ enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
+ smb_dr_put_uint32(enc_ctx, opcode);
+
+ switch (opcode) {
+ case LMSHR_DOOR_ADD:
+ lmshare = MEM_MALLOC("lmshrd_share_upcall",
+ sizeof (lmshare_info_t));
+
+ if (error = xcopyin(arg, lmshare, sizeof (lmshare_info_t))) {
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ MEM_FREE("lmshrd_share_upcall", buf);
+ return (error);
+ }
+ smb_dr_put_lmshare(enc_ctx, lmshare);
+ break;
+
+ case LMSHR_DOOR_DELETE:
+ str = MEM_MALLOC("lmshrd_share_upcall", MAXPATHLEN);
+ if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ MEM_FREE("lmshrd_share_upcall", str);
+ return (error);
+ }
+ smb_dr_put_string(enc_ctx, str);
+ MEM_FREE("lmshrd_share_upcall", str);
+ break;
+ }
+
+ if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (NERR_InternalError);
+ }
+
+ doorarg.data_ptr = buf;
+ doorarg.data_size = used;
+ doorarg.rbuf = buf;
+ doorarg.rsize = LMSHR_DOOR_SIZE;
+
+ if (error = door_ki_upcall(lmshrd_dh, &doorarg)) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (error);
+ }
+
+ dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
+ if (lmshrd_door_check_srv_status(opcode, dec_ctx) != 0) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (NERR_InternalError);
+ }
+
+ rc = smb_dr_get_uint32(dec_ctx);
+ if (opcode == LMSHR_DOOR_ADD)
+ smb_dr_get_lmshare(dec_ctx, lmshare);
+
+ if (smb_dr_decode_finish(dec_ctx)) {
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return (NERR_InternalError);
+ }
+
+ MEM_FREE("lmshrd_share_upcall", buf);
+ if (lmshare)
+ MEM_FREE("lmshrd_share_upcall", lmshare);
+ return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_signing.c b/usr/src/uts/common/fs/smbsrv/smb_signing.c
new file mode 100644
index 0000000000..2b079c193b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_signing.c
@@ -0,0 +1,418 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * These routines provide the SMB MAC signing for the SMB server.
+ * The routines calculate the signature of a SMB message in an mbuf chain.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/msgbuf.h>
+#include <sys/crypto/api.h>
+#include <smbsrv/smb_incl.h>
+
+#define SMB_SIG_SIZE 8
+#define SMB_SIG_OFFS 14
+
+/* This holds the MD5 mechanism */
+static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0};
+
+/*
+ * smb_sign_init
+ *
+ * Intializes MAC key based on the user session key and
+ * NTLM response and store it in the signing structure.
+ */
+void
+smb_sign_init(struct smb_request *req, smb_session_key_t *session_key,
+ char *resp, int resp_len)
+{
+ struct smb_sign *sign = &req->session->signing;
+
+ /*
+ * Initialise the crypto mechanism to MD5 if it not
+ * already initialised.
+ */
+ if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
+ crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5);
+ if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
+ /*
+ * There is no MD5 crypto mechanism
+ * so turn off signing
+ */
+ smb_info.si.skc_signing_enable = 0;
+ req->session->secmode &=
+ (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED);
+ cmn_err(CE_WARN,
+ "SmbSignInit: signing disabled (no MD5)");
+ return;
+ }
+ }
+
+ /* MAC key = concat (SessKey, NTLMResponse) */
+
+ bcopy(session_key, sign->mackey, sizeof (smb_session_key_t));
+ bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]),
+ resp_len);
+ sign->mackey_len = sizeof (smb_session_key_t) + resp_len;
+
+ req->reply_seqnum = 1;
+ sign->seqnum = 2;
+ sign->flags = SMB_SIGNING_ENABLED;
+
+ if (smb_info.si.skc_signing_check)
+ sign->flags |= SMB_SIGNING_CHECK;
+
+}
+
+/*
+ * smb_sign_calc
+ *
+ * Calculates MAC signature for the given buffer and returns
+ * it in the mac_sign parameter.
+ *
+ * The sequence number is placed in the first four bytes of the signature
+ * field of the signature and the other 4 bytes are zeroed.
+ * The signature is the first 8 bytes of the MD5 result of the
+ * concatenated MAC key and the SMB message.
+ *
+ * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
+ *
+ * where
+ *
+ * MACKey = concat( UserSessionKey, NTLMResp )
+ *
+ * and
+ *
+ * SMBMsg is the SMB message containing the sequence number.
+ *
+ * Return 0 if success else -1
+ *
+ */
+static int
+smb_sign_calc(struct mbuf_chain *mbc,
+ struct smb_sign *sign,
+ uint32_t seqnum,
+ unsigned char *mac_sign)
+{
+ uint32_t seq_buf[2] = {0, 0};
+ unsigned char mac[16];
+ struct mbuf *mbuf = mbc->chain;
+ int offset = mbc->chain_offset;
+ int size;
+ int status;
+
+ crypto_data_t data;
+ crypto_data_t digest;
+ crypto_context_t crypto_ctx;
+
+ data.cd_format = CRYPTO_DATA_RAW;
+ data.cd_offset = 0;
+ data.cd_length = (size_t)-1;
+ data.cd_miscdata = 0;
+
+ digest.cd_format = CRYPTO_DATA_RAW;
+ digest.cd_offset = 0;
+ digest.cd_length = (size_t)-1;
+ digest.cd_miscdata = 0;
+ digest.cd_raw.iov_base = (char *)mac;
+ digest.cd_raw.iov_len = sizeof (mac);
+
+ status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ /*
+ * Put the sequence number into the first 4 bytes
+ * of the signature field in little endian format.
+ * We are using a buffer to represent the signature
+ * rather than modifying the SMB message.
+ */
+#ifdef __sparc
+ {
+ uint32_t temp;
+ ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3];
+ ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2];
+ ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1];
+ ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0];
+
+ seq_buf[0] = temp;
+ }
+#else
+ seq_buf[0] = seqnum;
+#endif
+
+ /* Digest the MACKey */
+ data.cd_raw.iov_base = (char *)sign->mackey;
+ data.cd_raw.iov_len = sign->mackey_len;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ /* Find start of data in chain */
+ while (offset >= mbuf->m_len) {
+ offset -= mbuf->m_len;
+ mbuf = mbuf->m_next;
+ }
+
+ /* Digest the SMB packet up to the signature field */
+ size = SMB_SIG_OFFS;
+ while (size >= mbuf->m_len - offset) {
+ data.cd_raw.iov_base = &mbuf->m_data[offset];
+ data.cd_raw.iov_len = mbuf->m_len - offset;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ size -= mbuf->m_len - offset;
+ mbuf = mbuf->m_next;
+ offset = 0;
+ }
+ if (size > 0) {
+ data.cd_raw.iov_base = &mbuf->m_data[offset];
+ data.cd_raw.iov_len = size;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ offset += size;
+ }
+
+ /*
+ * Digest in the seq_buf instead of the signature
+ * which has the sequence number
+ */
+
+ data.cd_raw.iov_base = (char *)seq_buf;
+ data.cd_raw.iov_len = SMB_SIG_SIZE;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ /* Find the end of the signature field */
+ offset += SMB_SIG_SIZE;
+ while (offset >= mbuf->m_len) {
+ offset -= mbuf->m_len;
+ mbuf = mbuf->m_next;
+ }
+ /* Digest the rest of the SMB packet */
+ while (mbuf) {
+ data.cd_raw.iov_base = &mbuf->m_data[offset];
+ data.cd_raw.iov_len = mbuf->m_len - offset;
+ status = crypto_digest_update(&crypto_ctx, &data, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ mbuf = mbuf->m_next;
+ offset = 0;
+ }
+
+ status = crypto_digest_final(&crypto_ctx, &digest, 0);
+ if (status != CRYPTO_SUCCESS) goto error;
+
+ bcopy(mac, mac_sign, SMB_SIG_SIZE);
+
+ return (0);
+error:
+ cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status);
+ return (-1);
+
+}
+
+
+/*
+ * smb_sign_check_request
+ *
+ * Calculates MAC signature for the request mbuf chain
+ * using the next expected sequence number and compares
+ * it to the given signature.
+ *
+ * Note it does not check the signature for secondary transactions
+ * as their sequence number is the same as the original request.
+ *
+ * Return 0 if the signature verifies, otherwise, returns -1;
+ *
+ */
+int
+smb_sign_check_request(struct smb_request *req)
+{
+ struct mbuf_chain command = req->command;
+ unsigned char mac_sig[SMB_SIG_SIZE];
+ struct smb_sign *sign = &req->session->signing;
+ int rtn = 0;
+
+ /*
+ * Don't check secondary transactions - we dont know the sequence
+ * number.
+ */
+ if (req->smb_com == SMB_COM_TRANSACTION_SECONDARY ||
+ req->smb_com == SMB_COM_TRANSACTION2_SECONDARY ||
+ req->smb_com == SMB_COM_NT_TRANSACT_SECONDARY)
+ return (0);
+
+ if (sign->flags & SMB_SIGNING_CHECK) {
+
+ /* Reset the offset to begining of header */
+ command.chain_offset = req->orig_request_hdr;
+
+ /* calculate mac signature */
+ if (smb_sign_calc(&command, sign, sign->seqnum, mac_sig) != 0)
+ return (-1);
+
+ /* compare the signatures */
+ if (memcmp(mac_sig, req->smb_sig, SMB_SIG_SIZE) != 0) {
+ cmn_err(CE_WARN, "SmbSignCheckRequest: "
+ "bad signature %x %x %x %x %x %x %x %x",
+ req->smb_sig[0], req->smb_sig[1],
+ req->smb_sig[2], req->smb_sig[3],
+ req->smb_sig[4], req->smb_sig[5],
+ req->smb_sig[6], req->smb_sig[7]);
+#ifdef DBG_VERBOSE
+ /* Debug code to hunt for the sequence number */
+ for (i = sign->seqnum - 6; i <= sign->seqnum + 6; i++) {
+ smb_sign_calc(&command, sign, i, mac_sig);
+ if (memcmp(mac_sig, req->smb_sig,
+ SMB_SIG_SIZE) == 0) {
+ sign->seqnum = i;
+ goto ok;
+ }
+ }
+#endif
+ rtn = -1;
+ }
+ }
+ok:
+ /*
+ * Increament the sequence number for the reply, save the reply
+ * and set it for the next expect command.
+ * There is no reply for NT Cancel so just increament it for the
+ * next expected command.
+ */
+ sign->seqnum++;
+
+ if (req->smb_com == SMB_COM_NT_CANCEL)
+ req->reply_seqnum = 0;
+ else
+ req->reply_seqnum = sign->seqnum++;
+
+ return (rtn);
+}
+
+/*
+ * smb_sign_check_secondary
+ *
+ * Calculates MAC signature for the secondary transaction mbuf chain
+ * and compares it to the given signature.
+ * Return 0 if the signature verifies, otherwise, returns -1;
+ *
+ */
+int
+smb_sign_check_secondary(struct smb_request *req, unsigned int reply_seqnum)
+{
+ struct mbuf_chain command = req->command;
+ unsigned char mac_sig[SMB_SIG_SIZE];
+ struct smb_sign *sign = &req->session->signing;
+ int rtn = 0;
+
+ if (sign->flags & SMB_SIGNING_CHECK) {
+ /* Reset the offset to begining of header */
+ command.chain_offset = req->orig_request_hdr;
+
+ /* calculate mac signature */
+ if (smb_sign_calc(&command, sign, reply_seqnum - 1,
+ mac_sig) != 0)
+ return (-1);
+
+
+ /* compare the signatures */
+ if (memcmp(mac_sig, req->smb_sig, SMB_SIG_SIZE) != 0) {
+ cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature");
+ rtn = -1;
+ }
+ }
+ /* Save the reply sequence number */
+ req->reply_seqnum = reply_seqnum;
+
+ return (rtn);
+}
+
+
+
+
+/*
+ * smb_sign_reply
+ *
+ * Calculates MAC signature for the given mbuf chain,
+ * and write it to the signature field in the mbuf.
+ *
+ */
+void
+smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply)
+{
+ struct mbuf_chain resp;
+ struct smb_sign *sign = &req->session->signing;
+ unsigned char signature[SMB_SIG_SIZE];
+ struct mbuf *mbuf;
+ int size = SMB_SIG_SIZE;
+ unsigned char *sig_ptr = signature;
+ int offset = 0;
+
+ if (reply)
+ resp = *reply;
+ else
+ resp = req->reply;
+
+ /* Reset offset to start of reply */
+ resp.chain_offset = 0;
+ mbuf = resp.chain;
+
+ /*
+ * Calculate MAC signature
+ */
+ if (smb_sign_calc(&resp, sign, req->reply_seqnum, signature) != 0)
+ return;
+
+ /*
+ * Put signature in the response
+ *
+ * First find start of signature in chain (offset + signature offset)
+ */
+ offset += SMB_SIG_OFFS;
+ while (offset >= mbuf->m_len) {
+ offset -= mbuf->m_len;
+ mbuf = mbuf->m_next;
+ }
+
+ while (size >= mbuf->m_len - offset) {
+ (void) memcpy(&mbuf->m_data[offset],
+ sig_ptr, mbuf->m_len - offset);
+ offset = 0;
+ sig_ptr += mbuf->m_len - offset;
+ size -= mbuf->m_len - offset;
+ mbuf = mbuf->m_next;
+ }
+ if (size > 0) {
+ (void) memcpy(&mbuf->m_data[offset], sig_ptr, size);
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_svc_sm.c b/usr/src/uts/common/fs/smbsrv/smb_svc_sm.c
new file mode 100644
index 0000000000..b43388cccd
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_svc_sm.c
@@ -0,0 +1,1301 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB Service State Machine
+ *
+ * _____________
+ * T21 | | T1
+ * +---------------->| INIT |------------------+
+ * | |_____________| |
+ * ______|_____ /|\ _____\|/_____
+ * | | T14| T22 | |
+ * | ERROR | +------------ | -----------------| OPENING |
+ * |____________| | | |_____________|
+ * /|\ | ______|______ |
+ * | | | | T23 |
+ * |T20 | +-->| CLOSING |<--------+ | T2
+ * | | | |_____________|<-------+| |
+ * _______|_______ | | /|\ || _____\|/_____
+ * | |<-+ |T19 | || | |
+ * | ERROR CLOSING |-----+ T13| |+-| CONFIG WAIT |
+ * |_______________| | | |_____________|
+ * /|\ | | |
+ * | _______|_______ | |
+ * | | | | |
+ * | +---------->| SESSION CLOSE |--+ | |
+ * | | |_______________| | | | T3
+ * | | /|\ /|\ | |T24 |
+ * | | T11| |T12 | | |
+ * | | | +-----+ | |
+ * | | _______|_______ | ____\|/_____
+ * | | | | | | |
+ * | | | DISCONNECTING | +---| CONNECTING |
+ * |T18 |T17 |_______________| |____________|
+ * | | /|\ /|\ |
+ * | | | | | T4
+ * | | | | |
+ * ______|____|___ | | T9 ___\|/___
+ * | | | +---------------| |
+ * | ERROR SESSION | |T10 | ONLINE |<-+
+ * +->| CLOSE | | +-------------->|_________| |
+ * | |_______________| | | T8 | | | |
+ * |T16 | /|\ /|\ ______|____|_ | | |____| T5
+ * +-----+ | | T25 | | | |
+ * | +-------------| RECONFIGURE |<--------------+ |
+ * | +----|_____________| T6 |
+ * | | /|\ |
+ * | T7| | |
+ * | +------+ |
+ * | T15 |
+ * +--------------------------------------------------+
+ *
+ *
+ * State Descriptions:
+ *
+ * Init
+ *
+ * Ready for device open. This is the initial service state and the
+ * service returns to this state when cleanup has completed after a
+ * device close. The pseudo-driver can only be unloaded or opened in
+ * this state.
+ *
+ * Opening
+ *
+ * The pseudo-driver has been opened and SMB initialization is underway
+ *
+ * Config Wait
+ *
+ * Waiting for smbd to provide configuration information. XXX Today
+ * the kernel/user sychronization is not completely implemented and
+ * some changes might be appropriate in the future. The current
+ * code pulls configuration from smbd (see smb_get_kconfig). For
+ * dynamic configuration updates smbd will need to push config information
+ * to the kernel. This could be handled with either an ioctl or a door
+ * call. When this change is made we should change the state machine so
+ * that it also relies on the pull model. One way to handle this is to
+ * have the state machine end up in "config wait" instead of "online"
+ * when the open of the pseudo-device returns. Smbd will then know
+ * to push the current config after it has successfully opened the
+ * device. Such a change would require tweaks to the handling of
+ * svc_sm->ssc_started.
+ *
+ * Connecting
+ *
+ * Connecting to SMB port and starting service listener thread
+ *
+ * Online
+ *
+ * Online and accepting SMB sessions
+ *
+ * Reconfiguring
+ *
+ * Updating configuration after receiving a config update from smbd. This
+ * state is very similar to "online" state except that new session requests
+ * get place on a queue and initialization for those requests is deferred
+ * until configuration is complete. XXX Since dymamic configuration
+ * updates have not been implemented this state is never exercised.
+ * It's possible that we could completely eliminate it by simply grabbing
+ * a mutex for the duration of the config update. If the config update
+ * will take a long time or require sleeping then this state will
+ * be useful.
+ *
+ * Disconnecting
+ *
+ * Disconnecting from the SMB port and stopping the service listener
+ * thread.
+ *
+ * Session Close
+ *
+ * Waiting for any open sessions to close
+ *
+ * Closing
+ *
+ * Quiesce service and release any associated resources. This is the
+ * inverse of the "opening" state.
+ *
+ * Error Session Close
+ *
+ * The connection was unexpectedly dropped due to an error of some kind.
+ * Waiting for any open session to close (identical to Session Close
+ * except that we enter this state involuntarily)
+ *
+ * Error Closing
+ *
+ * Similar to Closing except that we enter this state as the result of
+ * an error (either during initialization or runtime)
+ *
+ * Error
+ *
+ * An error occurred that caused the service to shutdown but the
+ * pseudo-device is still open.
+ *
+ *
+ * State Transitions:
+ *
+ * T1 - The state machine is started by a call to smb_svcstate_sm_start. This
+ * causes a SMB_SVCEVT_OPEN event which forces a transition to "opening"
+ * state.
+ *
+ * T2 - SMB_SVCEVT_OPEN_SUCCESS indicates that the open actions completed
+ * successfully and the state machine transitions to "config wait" state.
+ *
+ * T3 - Configuration received from smbd (SMB_SVCEVT_CONFIG_SUCCESS)
+ *
+ * T4 - SMB service listener thread started and successfully bound to the
+ * socket (SMB_SVCEVT_CONNECT).
+ *
+ * T5 - Any SMB_SVCEVT_SESSION_CREATE/SMB_SVCEVT_SESSION_DELETE events are
+ * tracked on the svc_sm->ssc_active_sessions list and reflected in
+ * the svc_sm->ssc_active_session_count but we stay in "online" state
+ *
+ * T6 - Reconfiguration event (SMB_SVCEVT_CONFIG) cause a transition to
+ * "reconfiguring" state.
+ *
+ * T7 - SMB_SVCEVT_SESSION_CREATE/SMB_SVCEVT_SESSION_DELETE
+ *
+ * T8 - Configuration received from smbd (SMB_SVCEVT_CONFIG_SUCCESS) drives us
+ * back to "online" state.
+ *
+ * T9 - SMB_SVCEVT_CLOSE starts the shutdown process, starting with
+ * "disconnecting" state.
+ *
+ * T10 - SMB_SVCEVT_CLOSE starts the shutdown process, starting with
+ * "disconnecting" state.
+ *
+ * T11 - After socket disconnect SMB_SVCEVT_DISCONNECT drives the state machine
+ * to "session close" state.
+ *
+ * T12 - SMB_SVCEVT_SESSION_CLOSE does not cause a state transition if more
+ * sessions remain.
+ *
+ * T13 - When no more session remain SMB_SVCEVT_SESSION_CLOSE causes a
+ * transition to "closing" state.
+ *
+ * T14 - All close actions completed successfully (SMB_SVCEVT_CLOSE_SUCCESS).
+ * Close operations are not allowed to fail so the transition from
+ * "closing" to "init" is guaranteed.
+ *
+ * T15 - If the SMB service connection is unexpectedly dropped,
+ * SMB_SVCEVT_DISCONNECT drives the state machine to
+ * "error session close" state.
+ *
+ * T16 - SMB_SVCEVT_SESSION_CLOSE does not cause a state transition if more
+ * sessions remain.
+ *
+ * T17 - SMB_SVCEVT_CLOSE causes a state change to "session close" state. The
+ * difference between "error session close" and "session close" state is
+ * whether the pseudo device is open.
+ *
+ * T18 - When no more session remain SMB_SVCEVT_SESSION_CLOSE causes a
+ * transition to "error closing" state.
+ *
+ * T19 - SMB_SVCEVT_CLOSE causes a state change to "closing" state. The
+ * difference between "error closing" and "closing" state is
+ * whether the pseudo device is open.
+ *
+ * T20 - All close actions completed successfully (SMB_SVCEVT_CLOSE_SUCCESS).
+ * Close operations are not allowed to fail so the transition from
+ * "error closing" to "error" is guaranteed.
+ *
+ * T21 - SMB_SVCEVT_CLOSE moves everything back to "init" state
+ *
+ * T22 - SMB_SVCEVT_OPEN_FAILED causes a state change to "error closing".
+ * Moving to "error closing" state instead of "closing" causes the
+ * state machine to ultimately stop in "error" state (instead of
+ * "init").
+ *
+ * T23 - SMB_SVCEVT_CLOSE
+ *
+ * T24 - SMB_SVCEVT_CLOSE in "connecting" state causes a transition
+ * to "closing" state since the connection has not yet been established.
+ *
+ * T25 - If the SMB service connection is unexpectedly dropped,
+ * SMB_SVCEVT_DISCONNECT drives the state machine to
+ * "error session close" state.
+ *
+ * Overview:
+ *
+ * When the SMB pseudo-device gets open the state machine gets started with a
+ * call to smb_svcstate_sm_start which will block until initialization either
+ * succeeds or fails.
+ *
+ * SMB code external to the state machine generates events (defined above) by
+ * calling smb_svcstate_event and the state machine determines the new state
+ * based on the events and the current state.
+ *
+ * When the pseudo-device is closed, the state machine gets stopped with
+ * a call to smb_svcstate_sm_stop.
+ *
+ * This state machine also keeps track of the active session list. The
+ * list of sessions can be queried using the following services:
+ *
+ * smb_svcstate_lock_read(svc_sm);
+ * smb_svcstate_session_getnext(svc_sm, prev_session);
+ * (repeat until NULL is returned)
+ * smb_svcstate_unlock(svc_sm);
+ *
+ *
+ * Implemention Details:
+ *
+ * States are named SMB_SVCSTATE_<state name>
+ *
+ * Events are named SMB_SVCEVT_<event name>
+ *
+ * Each state has an associated function: smb_svcstate_<state name>
+ *
+ * This state machine implements four types of actions:
+ *
+ * State entry actions - State-specific actions that are taken when a
+ * state is entered (transitions like T5 that do not result in a real
+ * state change are not actually coded as state transitions (no call to
+ * smb_svcstate_update) and therefore will not cause state entry actions.
+ * These actions are implemented in smb_svcstate_update.
+ *
+ * Immediate event actions - An action specific to a particular event
+ * that is taken immediately, before the event is placed on the task
+ * queue. The action does not depend on the current state. These should
+ * only be implemented when absolutely necessary since the code path for
+ * immediate actions is multithreaded (smb_svcstate_event_locked).
+ *
+ * Deferred event actions - An action specific to a particular event
+ * that is handled by the taskq thread. The action does not depend on
+ * the current state and the code implementing the actions is single
+ * threaded since the taskq only has one thread. Implemented in
+ * smb_svcstate_event_handler.
+ *
+ * State specific event actions - Actions specific to events that
+ * depend on the current state. These actions are implemented
+ * in the state-specific event handler functions
+ * (smb_svcstate_<event name>)
+ *
+ * The description above makes things sound more complicated than they really
+ * are. Deferred event actions are really just a special case of state
+ * specific event actions. To find out what happens when a specific event
+ * occurs in a specific state:
+ *
+ * 1. Look at smb_svcstate_event_locked and find matching event actions (rare)
+ * 2. Look at smb_svcstate_event_handler and find matching event actions
+ * 3. Look at smb_svcstate_<current state> and find matching event actions
+ *
+ * If the event causes a state transition (this will always be found in
+ * smb_svcstate_<current_state>) then look up the new state in
+ * smb_svcstate_update which will show the state entry actions for the new
+ * state.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <sys/note.h>
+#include <sys/sdt.h>
+
+static void smb_svcstate_event_locked(smb_svc_sm_ctx_t *svc_sm,
+ smb_svcevt_t event, uintptr_t event_info);
+
+static void smb_svcstate_event_handler(void *event_ctx);
+
+static void smb_svcstate_init(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_opening(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_config_wait(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_connecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_online(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_reconfiguring(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_disconnecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_error_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_error_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_error(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx);
+
+static void smb_svcstate_update(smb_svc_sm_ctx_t *svc_sm,
+ smb_svcstate_t newstate);
+
+static void smb_svcstate_set_started(smb_svc_sm_ctx_t *svc_sm,
+ int started);
+
+static void smb_svcstate_session_start(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session);
+
+static void smb_svcstate_session_defer(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session);
+
+static void smb_svcstate_session_reject_active(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *session, char *reason);
+
+static void
+smb_svcstate_start_deferred_sessions(smb_svc_sm_ctx_t *svc_sm);
+
+static void
+smb_svcstate_reject_deferred_sessions(smb_svc_sm_ctx_t *svc_sm);
+
+static void
+smb_svcstate_close_active_sessions(smb_svc_sm_ctx_t *svc_sm);
+
+extern void smb_wakeup_session_daemon(smb_thread_t *thread, void *arg);
+extern void smb_session_daemon(smb_thread_t *thread, void *arg);
+extern int smb_get_kconfig(smb_kmod_cfg_t *cfg);
+
+char *smb_svcstate_event_name[SMB_SVCEVT_MAX_EVENT];
+char *smb_svcstate_state_name[SMB_SVCSTATE_MAX_STATE];
+
+/*
+ * SMB Service State Machine
+ */
+
+#define SMB_STOPPED 0
+#define SMB_START_SUCCESS 1
+#define SMB_START_FAILED 2
+
+int
+smb_svcstate_sm_init(smb_svc_sm_ctx_t *svc_sm)
+{
+ bzero(svc_sm, sizeof (*svc_sm));
+
+ /* Protects state context except for ssc_state and ssc_last_state */
+ rw_init(&svc_sm->ssc_state_rwlock, NULL, RW_DEFAULT, NULL);
+
+ /* Protects ssc_state and ssc_last_state */
+ mutex_init(&svc_sm->ssc_state_cv_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&svc_sm->ssc_state_cv, NULL, CV_DEFAULT, NULL);
+
+ svc_sm->ssc_state = SMB_SVCSTATE_INIT;
+ svc_sm->ssc_last_state = SMB_SVCSTATE_INIT;
+
+ list_create(&svc_sm->ssc_active_sessions, sizeof (smb_session_t),
+ offsetof(smb_session_t, s_lnd));
+ list_create(&svc_sm->ssc_deferred_sessions, sizeof (smb_session_t),
+ offsetof(smb_session_t, s_lnd));
+
+ /* Service state machine is single threaded by design */
+ svc_sm->ssc_taskq = taskq_create("smb_svc_sm", 1, minclsyspri,
+ 1, 1, 0);
+ if (svc_sm->ssc_taskq == NULL) {
+ return (ENOMEM);
+ }
+
+ /*
+ * Setup event and state name tables. Use for debug logging
+ * and/or dtrace scripts
+ */
+ smb_svcstate_event_name[SMB_SVCEVT_UNDEFINED] = "UNDEFINED";
+ smb_svcstate_event_name[SMB_SVCEVT_OPEN] = "OPEN";
+ smb_svcstate_event_name[SMB_SVCEVT_CLOSE] = "CLOSE";
+ smb_svcstate_event_name[SMB_SVCEVT_OPEN_SUCCESS] = "OPEN_SUCCESS";
+ smb_svcstate_event_name[SMB_SVCEVT_OPEN_FAILED] = "OPEN_FAILED";
+ smb_svcstate_event_name[SMB_SVCEVT_CLOSE_SUCCESS] = "CLOSE_SUCCESS";
+ smb_svcstate_event_name[SMB_SVCEVT_CONNECT] = "CONNECT";
+ smb_svcstate_event_name[SMB_SVCEVT_DISCONNECT] = "DISCONNECT";
+ smb_svcstate_event_name[SMB_SVCEVT_CONFIG] = "CONFIG";
+ smb_svcstate_event_name[SMB_SVCEVT_CONFIG_SUCCESS] = "CONFIG_SUCCESS";
+ smb_svcstate_event_name[SMB_SVCEVT_CONFIG_FAILED] = "CONFIG_FAILED";
+ smb_svcstate_event_name[SMB_SVCEVT_SESSION_CREATE] = "SESSION_CREATE";
+ smb_svcstate_event_name[SMB_SVCEVT_SESSION_DELETE] = "SESSION_DELETE";
+
+ smb_svcstate_state_name[SMB_SVCSTATE_UNDEFINED] = "UNDEFINED";
+ smb_svcstate_state_name[SMB_SVCSTATE_INIT] = "INIT";
+ smb_svcstate_state_name[SMB_SVCSTATE_OPENING] = "OPENING";
+ smb_svcstate_state_name[SMB_SVCSTATE_CONFIG_WAIT] = "CONFIG_WAIT";
+ smb_svcstate_state_name[SMB_SVCSTATE_CONNECTING] = "CONNECTING";
+ smb_svcstate_state_name[SMB_SVCSTATE_ONLINE] = "ONLINE";
+ smb_svcstate_state_name[SMB_SVCSTATE_RECONFIGURING] = "RECONFIGURING";
+ smb_svcstate_state_name[SMB_SVCSTATE_DISCONNECTING] = "DISCONNECTING";
+ smb_svcstate_state_name[SMB_SVCSTATE_SESSION_CLOSE] = "SESSION_CLOSE";
+ smb_svcstate_state_name[SMB_SVCSTATE_ERROR_SESSION_CLOSE] =
+ "ERROR_SESSION_CLOSE";
+ smb_svcstate_state_name[SMB_SVCSTATE_CLOSING] = "CLOSING";
+ smb_svcstate_state_name[SMB_SVCSTATE_ERROR_CLOSING] = "ERROR_CLOSING";
+ smb_svcstate_state_name[SMB_SVCSTATE_ERROR] = "ERROR";
+
+ return (0);
+}
+
+void
+smb_svcstate_sm_fini(smb_svc_sm_ctx_t *svc_sm)
+{
+ taskq_destroy(svc_sm->ssc_taskq);
+
+ list_destroy(&svc_sm->ssc_deferred_sessions);
+ list_destroy(&svc_sm->ssc_active_sessions);
+
+ cv_destroy(&svc_sm->ssc_state_cv);
+ mutex_destroy(&svc_sm->ssc_state_cv_mutex);
+ rw_destroy(&svc_sm->ssc_state_rwlock);
+}
+
+int
+smb_svcstate_sm_start(smb_svc_sm_ctx_t *svc_sm)
+{
+ clock_t wait_result;
+ int result;
+
+ /*
+ * Make sure state machine is idle and ready to be started.
+ */
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ while (svc_sm->ssc_started) {
+ /*
+ * Already started, possibly because we're still trying to
+ * shutdown. Wait for up to 30 seconds then return EBUSY.
+ */
+ wait_result = cv_timedwait(&svc_sm->ssc_state_cv,
+ &svc_sm->ssc_state_cv_mutex,
+ lbolt + SEC_TO_TICK(30));
+ if (wait_result == -1) {
+ /* Timeout */
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+ return (EBUSY);
+ }
+ }
+
+ /*
+ * SMB_SVCEVT_OPEN will get the state machine moving
+ */
+ smb_svcstate_event_locked(svc_sm, SMB_SVCEVT_OPEN, NULL);
+
+ /*
+ * Wait for the state machine to signal either a successful
+ * start or a start failure.
+ */
+ while (!svc_sm->ssc_started) {
+ cv_wait(&svc_sm->ssc_state_cv, &svc_sm->ssc_state_cv_mutex);
+ }
+
+ result = (svc_sm->ssc_started == SMB_START_FAILED) ?
+ svc_sm->ssc_start_error : 0;
+
+ /*
+ * If the open failed we will end up in "Error" state. Since we
+ * are returning failure to the open request on the pseudo-device
+ * we will never see a close so we need to force the device closed.
+ *
+ * A careful look at the state machine will should that we could
+ * avoid this step by transitioning from opening --> closing
+ * instead of opening --> error_closing when there is an initialization
+ * problem. The reason we shouldn't do this is because
+ * smb_svcstate_sm_busy returns "false" (not busy) when the state
+ * machine is in init state and we don't want to mistakenly indicate
+ * that we are not busy.
+ */
+ if (result != 0) {
+ smb_svcstate_event_locked(svc_sm, SMB_SVCEVT_CLOSE, NULL);
+ }
+
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+
+ return (result);
+}
+
+/*ARGSUSED*/
+void
+smb_svcstate_sm_stop(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL);
+}
+
+boolean_t
+smb_svcstate_sm_busy(void)
+{
+ return (smb_info.si_svc_sm_ctx.ssc_state != SMB_SVCSTATE_INIT);
+}
+
+void
+smb_svcstate_event(smb_svcevt_t event, uintptr_t event_info)
+{
+ smb_svc_sm_ctx_t *svc_sm = &smb_info.si_svc_sm_ctx;
+
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ smb_svcstate_event_locked(svc_sm, event, event_info);
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+}
+
+void
+smb_svcstate_lock_read(smb_svc_sm_ctx_t *svc_sm)
+{
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_READER);
+
+}
+
+void
+smb_svcstate_unlock(smb_svc_sm_ctx_t *svc_sm)
+{
+ rw_exit(&svc_sm->ssc_state_rwlock);
+}
+
+smb_session_t *
+smb_svcstate_session_getnext(smb_svc_sm_ctx_t *svc_sm, smb_session_t *prev)
+{
+ smb_session_t *result;
+
+ /* Skip sessions in "terminated" state */
+ do {
+ if (prev == NULL) {
+ result = list_head(&svc_sm->ssc_active_sessions);
+ } else {
+ result = list_next(&svc_sm->ssc_active_sessions, prev);
+ }
+ prev = result;
+ } while ((result != NULL) &&
+ (result->s_state == SMB_SESSION_STATE_TERMINATED));
+
+ return (result);
+}
+
+int
+smb_svcstate_session_count(smb_svc_sm_ctx_t *svc_sm)
+{
+ return (svc_sm->ssc_active_session_count);
+}
+
+/*
+ * Internal use only by state machine code
+ */
+
+static void
+smb_svcstate_event_locked(smb_svc_sm_ctx_t *svc_sm,
+ smb_svcevt_t event, uintptr_t event_info)
+{
+ smb_event_ctx_t *event_ctx;
+
+ event_ctx = kmem_zalloc(sizeof (*event_ctx), KM_SLEEP);
+ event_ctx->sec_event = event;
+ event_ctx->sec_info = event_info;
+
+ /*
+ * Immediate event actions that are independent of state.
+ * This code is multi-threaded and is in the context of
+ * the thread that generated the event.
+ *
+ * Don't generate events from this function (recursive mutex
+ * enter).
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /*
+ * We don't necessarily want to reflect this session in the
+ * session count just yet. We do, however, want to know
+ * that its waiting so that we can properly close down
+ * all the outstanding session as we are closing the service.
+ * The ssc_session_creates_waiting counter represents
+ * the sessions that have been dispatched to the taskq
+ * but not yet processed.
+ *
+ * Session delete events don't have the same issue because
+ * the session count won't go to zero until they are all
+ * processed.
+ */
+ svc_sm->ssc_session_creates_waiting++;
+ break;
+ default:
+ break;
+ }
+
+ (void) taskq_dispatch(svc_sm->ssc_taskq, &smb_svcstate_event_handler,
+ event_ctx, TQ_SLEEP);
+}
+
+/*
+ * Task queue gets created with only one thread so this code is inherently
+ * single threaded. State changes should still be protected with a mutex
+ * since other threads might read the state value.
+ */
+static void
+smb_svcstate_event_handler(void *event_ctx_opaque)
+{
+ smb_svc_sm_ctx_t *svc_sm = &smb_info.si_svc_sm_ctx;
+ smb_event_ctx_t *event_ctx = event_ctx_opaque;
+ smb_session_t *session;
+
+ DTRACE_PROBE2(service__event,
+ smb_svc_sm_ctx_t *, svc_sm, smb_event_ctx_t *, event_ctx);
+
+ /*
+ * Validate event
+ */
+ ASSERT(event_ctx->sec_event != SMB_SVCEVT_UNDEFINED);
+ ASSERT3U(event_ctx->sec_event, <, SMB_SVCEVT_MAX_EVENT);
+
+ /*
+ * Validate current state
+ */
+ ASSERT(svc_sm->ssc_state != SMB_SVCSTATE_UNDEFINED);
+ ASSERT3U(svc_sm->ssc_state, <, SMB_SVCSTATE_MAX_STATE);
+
+ /*
+ * Deferred event actions that are independent of state.
+ * This code is single-threaded and is in the context of
+ * the task-queue thread.
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_DISCONNECT:
+ svc_sm->ssc_disconnect_error = (int)event_ctx->sec_info;
+ break;
+ case SMB_SVCEVT_SESSION_CREATE:
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ svc_sm->ssc_session_creates_waiting--;
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+ break;
+ case SMB_SVCEVT_SESSION_DELETE:
+ session = (smb_session_t *)event_ctx->sec_info;
+ ASSERT(session->s_state == SMB_SESSION_STATE_TERMINATED);
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ list_remove(&svc_sm->ssc_active_sessions, session);
+ svc_sm->ssc_active_session_count--;
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ /*
+ * Make sure thread has exited
+ */
+ smb_thread_stop(&session->s_thread);
+
+ smb_session_delete(session);
+
+ /*
+ * State specific handlers will also process the event
+ * but the event info (session) is no longer valid.
+ */
+ event_ctx->sec_info = NULL;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Call state-specific event handler.
+ */
+ switch (svc_sm->ssc_state) {
+ case SMB_SVCSTATE_INIT:
+ smb_svcstate_init(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_OPENING:
+ smb_svcstate_opening(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_CONFIG_WAIT:
+ smb_svcstate_config_wait(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_CONNECTING:
+ smb_svcstate_connecting(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ONLINE:
+ smb_svcstate_online(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_RECONFIGURING:
+ smb_svcstate_reconfiguring(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_DISCONNECTING:
+ smb_svcstate_disconnecting(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_SESSION_CLOSE:
+ smb_svcstate_session_close(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ERROR_SESSION_CLOSE:
+ smb_svcstate_error_session_close(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_CLOSING:
+ smb_svcstate_closing(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ERROR_CLOSING:
+ smb_svcstate_error_closing(svc_sm, event_ctx);
+ break;
+ case SMB_SVCSTATE_ERROR:
+ smb_svcstate_error(svc_sm, event_ctx);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ kmem_free(event_ctx, sizeof (*event_ctx));
+}
+
+static void
+smb_svcstate_init(smb_svc_sm_ctx_t *svc_sm, smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_OPEN:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_OPENING);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_opening(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_OPEN_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CONFIG_WAIT);
+ break;
+ case SMB_SVCEVT_OPEN_FAILED:
+ /*
+ * Go to error_closed state, cleanup anything we did in open
+ * and then back to init state. We want to end up in "error"
+ * state instead of "init" state.
+ */
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_CLOSING);
+ smb_svcstate_set_started(svc_sm, SMB_START_FAILED);
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_config_wait(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CONFIG:
+ /*
+ * Update our configuration. A successful config update
+ * will trigger SMB_SVCEVT_CONFIG_SUCCESS and drive us
+ * into online state.
+ */
+ (void) smb_get_kconfig(&smb_info.si); /* XXX */
+ break;
+ case SMB_SVCEVT_CONFIG_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CONNECTING);
+ break;
+ case SMB_SVCEVT_CONFIG_FAILED:
+ /* Don't care, wait for another config attempt */
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_CLOSING);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_connecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CONNECT:
+ /*
+ * Wait until both NBT and TCP transport services
+ * are connected before going online.
+ */
+ if ((smb_info.si_connect_progress & SMB_SI_NBT_CONNECTED) &&
+ (smb_info.si_connect_progress & SMB_SI_TCP_CONNECTED)) {
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ONLINE);
+ smb_svcstate_set_started(svc_sm, SMB_START_SUCCESS);
+ }
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ svc_sm->ssc_start_error = svc_sm->ssc_disconnect_error;
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_CLOSING);
+ smb_svcstate_set_started(svc_sm, SMB_START_FAILED);
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CLOSING);
+ break;
+ case SMB_SVCEVT_SESSION_CREATE:
+ smb_svcstate_session_defer(svc_sm,
+ (smb_session_t *)event_ctx->sec_info);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_online(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *new_session;
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ new_session = (smb_session_t *)event_ctx->sec_info;
+#if 0 /* XXX PGD */
+ smb_session_config(new_session);
+#endif
+ smb_svcstate_session_start(svc_sm, new_session);
+ break;
+ case SMB_SVCEVT_CONNECT:
+ case SMB_SVCEVT_SESSION_DELETE:
+ /* No state-specific action required */
+ break;
+ case SMB_SVCEVT_CONFIG:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_RECONFIGURING);
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_DISCONNECTING);
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ /*
+ * The session service daemon unexpectedly stopped. Looks
+ * like we're done talking SMB for the day.
+ */
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_SESSION_CLOSE);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_reconfiguring(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *new_session;
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ new_session = (smb_session_t *)event_ctx->sec_info;
+ smb_svcstate_session_defer(svc_sm, new_session);
+ break;
+ case SMB_SVCEVT_SESSION_DELETE:
+ /* No state-specific action required */
+ break;
+ case SMB_SVCEVT_CONFIG:
+ /* Hopefully this won't happen but if it does we ignore it */
+ break;
+ case SMB_SVCEVT_CONFIG_SUCCESS:
+ case SMB_SVCEVT_CONFIG_FAILED:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ONLINE);
+ break;
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_DISCONNECTING);
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ /*
+ * The session service daemon unexpectedly stopped. Looks
+ * like we're done talking SMB for the day.
+ */
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR_SESSION_CLOSE);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_disconnecting(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *session;
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ session = (smb_session_t *)event_ctx->sec_info;
+
+ /* We're not online so reject the connection */
+ smb_session_reject(session, "SMB service is shutting down.");
+ smb_session_delete(session);
+ break;
+ case SMB_SVCEVT_CONNECT:
+ case SMB_SVCEVT_SESSION_DELETE:
+ /* No state-specific action required */
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_SESSION_CLOSE);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ smb_session_t *session;
+
+ /*
+ * We continue to accept "session creates" because we might
+ * accept a connection while the SMB_SVCEVT_CLOSE is
+ * queued but not yet handled.
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_SESSION_CREATE:
+ /* Event context is the new socket */
+ session = (smb_session_t *)event_ctx->sec_info;
+
+ /* We're not online so reject the connection */
+ smb_session_reject(session, "Not configured");
+ smb_session_delete(session);
+ /*FALLTHROUGH*/
+ case SMB_SVCEVT_SESSION_DELETE:
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_CLOSING);
+ }
+ break;
+ case SMB_SVCEVT_DISCONNECT:
+ /* No state-specific action required */
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_error_session_close(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ /*
+ * Since our connection dropped we shouldn't see any more
+ * "creates" in this state
+ */
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_SESSION_CLOSE);
+ break;
+ case SMB_SVCEVT_SESSION_DELETE:
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_ERROR_CLOSING);
+ }
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_INIT);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_error_closing(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CLOSING);
+ break;
+ case SMB_SVCEVT_CLOSE_SUCCESS:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_ERROR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_error(smb_svc_sm_ctx_t *svc_sm,
+ smb_event_ctx_t *event_ctx)
+{
+ ASSERT(event_ctx->sec_event == SMB_SVCEVT_CLOSE);
+
+ switch (event_ctx->sec_event) {
+ case SMB_SVCEVT_CLOSE:
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_INIT);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+smb_svcstate_update(smb_svc_sm_ctx_t *svc_sm, smb_svcstate_t new_state_arg)
+{
+ smb_svcstate_t new_state;
+ int error;
+
+ /*
+ * Validate new state
+ */
+ ASSERT(new_state_arg != SMB_SVCSTATE_UNDEFINED);
+ ASSERT3U(new_state_arg, <, SMB_SVCSTATE_MAX_STATE);
+
+ /*
+ * Update state in context. We protect this with a mutex
+ * even though the state machine code is single threaded so that
+ * other threads can check the state value atomically.
+ */
+ new_state = (new_state_arg < SMB_SVCSTATE_MAX_STATE) ?
+ new_state_arg: SMB_SVCSTATE_UNDEFINED;
+
+ DTRACE_PROBE2(service__state__change,
+ smb_svc_sm_ctx_t *, svc_sm, smb_svcstate_t, new_state);
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ svc_sm->ssc_last_state = svc_sm->ssc_state;
+ svc_sm->ssc_state = new_state;
+ cv_signal(&svc_sm->ssc_state_cv);
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+
+ /*
+ * Now perform the appropiate actions for the new state
+ */
+ switch (new_state) {
+ case SMB_SVCSTATE_INIT:
+ smb_svcstate_set_started(svc_sm, SMB_STOPPED);
+ break;
+ case SMB_SVCSTATE_OPENING:
+ /*
+ * Start all SMB subsystems and connect to socket
+ */
+ svc_sm->ssc_start_error = smb_service_open(&smb_info);
+ if (svc_sm->ssc_start_error != 0) {
+ smb_svcstate_event(SMB_SVCEVT_OPEN_FAILED, NULL);
+ } else {
+ /* Open actions successful */
+ smb_svcstate_event(SMB_SVCEVT_OPEN_SUCCESS, NULL);
+ }
+ break;
+ case SMB_SVCSTATE_CONFIG_WAIT:
+ /*
+ * Nothing in particular to do here except to note the
+ * state change. Now we wait for smbd to provide
+ * our configuration.
+ */
+ /*
+ * XXX For now this is done as part of smb_service_open()
+ * so just send the "success" event.
+ */
+ smb_svcstate_event(SMB_SVCEVT_CONFIG_SUCCESS, NULL);
+ break;
+ case SMB_SVCSTATE_CONNECTING:
+ /*
+ * When we move to a userland thread model we will rely
+ * on smbd to start the SMB socket service thread.
+ */
+ error = smb_service_connect(&smb_info);
+ if (error != 0)
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT,
+ (uintptr_t)error);
+ break;
+ case SMB_SVCSTATE_ONLINE:
+ smb_svcstate_start_deferred_sessions(svc_sm);
+ /* No actions */
+ break;
+ case SMB_SVCSTATE_RECONFIGURING:
+ (void) smb_get_kconfig(&smb_info.si); /* XXX */
+ break;
+ case SMB_SVCSTATE_DISCONNECTING:
+ smb_svcstate_reject_deferred_sessions(svc_sm);
+ smb_service_disconnect(&smb_info);
+ break;
+ case SMB_SVCSTATE_ERROR_SESSION_CLOSE:
+ smb_svcstate_reject_deferred_sessions(svc_sm);
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm,
+ SMB_SVCSTATE_ERROR_CLOSING);
+ } else {
+ smb_svcstate_close_active_sessions(svc_sm);
+ }
+ break;
+ case SMB_SVCSTATE_SESSION_CLOSE:
+ if ((svc_sm->ssc_active_session_count == 0) &&
+ (svc_sm->ssc_session_creates_waiting == 0)) {
+ smb_svcstate_update(svc_sm, SMB_SVCSTATE_CLOSING);
+ } else {
+ smb_svcstate_close_active_sessions(svc_sm);
+ }
+ break;
+ case SMB_SVCSTATE_ERROR_CLOSING:
+ case SMB_SVCSTATE_CLOSING:
+ smb_service_close(&smb_info);
+ smb_svcstate_event(SMB_SVCEVT_CLOSE_SUCCESS, NULL);
+ break;
+ case SMB_SVCSTATE_ERROR:
+ /* No actions */
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+static void
+smb_svcstate_set_started(smb_svc_sm_ctx_t *svc_sm, int started)
+{
+ mutex_enter(&svc_sm->ssc_state_cv_mutex);
+ /* Make sure we have an error code if we failed to start */
+ ASSERT(started != SMB_START_FAILED || svc_sm->ssc_start_error != 0);
+ svc_sm->ssc_started = started;
+ cv_signal(&svc_sm->ssc_state_cv);
+ mutex_exit(&svc_sm->ssc_state_cv_mutex);
+}
+
+static void
+smb_svcstate_session_start(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session)
+{
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ if (svc_sm->ssc_active_session_count >=
+ smb_info.si.skc_maxconnections) {
+ svc_sm->ssc_error_no_resources++;
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ smb_session_reject(new_session, "Too many open sessions");
+ smb_session_delete(new_session);
+ } else {
+ new_session->s_state = SMB_SESSION_STATE_CONNECTED;
+ list_insert_tail(&svc_sm->ssc_active_sessions, new_session);
+ svc_sm->ssc_active_session_count++;
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ /*
+ * Blocks until thread has started
+ */
+ if (smb_thread_start(&new_session->s_thread) != 0) {
+ smb_svcstate_session_reject_active(svc_sm, new_session,
+ "Session thread creation failed");
+ } else {
+ DTRACE_PROBE1(session__create,
+ struct session *, new_session);
+ }
+ }
+}
+
+static void
+smb_svcstate_session_defer(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *new_session)
+{
+ list_insert_tail(&svc_sm->ssc_deferred_sessions, new_session);
+ svc_sm->ssc_deferred_session_count++;
+}
+
+/*ARGSUSED*/
+static void
+smb_svcstate_session_reject_active(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *session, char *reason)
+{
+ smb_session_reject(session, reason);
+
+ smb_svcstate_event(SMB_SVCEVT_SESSION_DELETE, (uintptr_t)session);
+}
+
+static void
+smb_svcstate_start_deferred_sessions(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_session_t *session, *next_session;
+
+ /*
+ * svc_sm->ssc_deferred_sessions is private to the (single-threaded)
+ * state machine so we don't need to lock it.
+ */
+ session = list_head(&svc_sm->ssc_deferred_sessions);
+ while (session != NULL) {
+ next_session =
+ list_next(&svc_sm->ssc_deferred_sessions, session);
+ list_remove(&svc_sm->ssc_deferred_sessions, session);
+ svc_sm->ssc_deferred_session_count--;
+ smb_svcstate_session_start(svc_sm, session);
+ session = next_session;
+ }
+}
+
+static void
+smb_svcstate_reject_deferred_sessions(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_session_t *session, *next_session;
+
+
+ /*
+ * svc_sm->ssc_deferred_sessions is private to the (single-threaded)
+ * state machine so we don't need to lock it.
+ */
+ session = list_head(&svc_sm->ssc_deferred_sessions);
+ while (session != NULL) {
+ next_session =
+ list_next(&svc_sm->ssc_deferred_sessions, session);
+ list_remove(&svc_sm->ssc_deferred_sessions, session);
+ svc_sm->ssc_deferred_session_count--;
+ smb_svcstate_session_reject_active(svc_sm, session,
+ "SMB service is shutting down (deferred)");
+ session = next_session;
+ }
+}
+
+static void
+smb_svcstate_close_active_sessions(smb_svc_sm_ctx_t *svc_sm)
+{
+ smb_session_t *session;
+
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ for (session = list_head(&svc_sm->ssc_active_sessions);
+ session != NULL;
+ session = list_next(&svc_sm->ssc_active_sessions, session)) {
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ rw_exit(&svc_sm->ssc_state_rwlock);
+
+ /*
+ * As each session thread terminates it will generate
+ * a "session delete" event.
+ */
+ smb_thread_stop(&session->s_thread);
+
+ rw_enter(&svc_sm->ssc_state_rwlock, RW_WRITER);
+ }
+ rw_exit(&svc_sm->ssc_state_rwlock);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c
new file mode 100644
index 0000000000..6ef6691df3
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_create_directory.c
@@ -0,0 +1,97 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_create_directory
+ *
+ * This requests the server to create a directory relative to Tid in the
+ * SMB header, optionally assigning extended attributes to it.
+ *
+ * Client Request Value
+ * ========================== =========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_CREATE_DIRECTORY
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ *
+ * ULONG Reserved; Reserved--must be zero
+ * STRING Name[]; Directory name to create
+ * UCHAR Data[]; Optional FEAList for the new directory
+ *
+ * Response Parameter Block Description
+ * ========================== =========================================
+ *
+ * USHORT EaErrorOffset Offset into FEAList of first error which
+ * occurred while setting EAs
+ */
+
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smb_incl.h>
+
+
+extern int smb_common_create_directory(struct smb_request *sr);
+
+
+/*
+ * smb_com_trans2_create_directory
+ */
+int
+smb_com_trans2_create_directory(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc;
+ DWORD status;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%4.s",
+ sr, &sr->arg.dirop.fqi.path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) {
+ if (sr->session->capabilities & CAP_STATUS32)
+ smbsr_raise_nt_error(sr, status);
+ else
+ smbsr_raise_error(sr, ERRDOS, ERROR_INVALID_NAME);
+
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_create_directory(sr)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (smb_encode_mbc(&xa->rep_param_mb, "w", 0) < 0)
+ smbsr_encode_error(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
new file mode 100644
index 0000000000..2afbcc6786
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_dfs.c
@@ -0,0 +1,205 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+
+/*
+ * trans2_get_dfs_referral
+ *
+ * The client sends this request to ask the server to convert
+ * RequestFilename into an alternate name for this file. This request can
+ * be sent to the server if the server response to the NEGOTIATE SMB
+ * included the CAP_DFS capability. The TID of the request must be IPC$.
+ * Bit15 of Flags2 in the SMB header must be set, indicating this is a
+ * UNICODE request.
+ *
+ * Client Request Description
+ * ========================== =========================================
+ * WordCount 15
+ * TotalDataCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_GET_DFS_REFERRAL
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ * USHORT MaxReferralLevel Latest referral version number understood
+ * WCHAR RequestFileName; DFS name of file for which referral is
+ * sought
+ *
+ * Response Data Block Description
+ * ========================== =========================================
+ * USHORT PathConsumed; Number of RequestFilename bytes client
+ * USHORT NumberOfReferrals; Number of referrals contained in this
+ * response
+ * USHORT Flags; bit0 - The servers in Referrals are
+ * capable of fielding
+ * TRANS2_GET_DFS_REFERRAL.
+ * bit1 - The servers in Referrals should
+ * hold the storage for the requested file.
+ * REFERRAL_LIST Referrals[] Set of referrals for this file
+ * UNICODESTRINGE Strings Used to hold the strings pointed to by
+ * Version 2 Referrals in REFERRALS.
+ *
+ * The server response is a list of Referrals which inform the client where
+ * it should resubmit the request to obtain access to the file.
+ * PathConsumed in the response indicates to the client how many characters
+ * of RequestFilename have been consumed by the server. When the client
+ * chooses one of the referrals to use for file access, the client may need
+ * to strip the leading PathConsumed characters from the front of
+ * RequestFileName before submitting the name to the target server.
+ * Whether or not the pathname should be trimmed is indicated by the
+ * individual referral as detailed below.
+ *
+ * Flags indicates how this referral should be treated. If bit0 is clear,
+ * any entity in the Referrals list holds the storage for RequestFileName.
+ * If bit0 is set, any entity in the Referrals list has further referral
+ * information for RequestFilename – a TRANS2_GET_DFS_REFERRAL request
+ * should be sent to an entity in the Referrals list for further
+ * resolution.
+ *
+ * The format of an individual referral contains version and length
+ * information allowing the client to skip referrals it does not
+ * understand. MaxReferralLevel indicates to the server the latest version
+ * of referral which the client can digest. Since each referral has a
+ * uniform element, MaxReferralLevel is advisory only. Each element in
+ * Referrals has this envelope:
+ *
+ * REFERRAL_LIST element
+ * ======================================================================
+ *
+ * USHORT VersionNumber Version of this referral element
+ *
+ * USHORT ReferralSize Size of this referral element
+ *
+ * The following referral element versions are defined:
+ *
+ * Version 1 Referral Element Format
+ * ======================================================================
+ *
+ * USHORT ServerType Type of Node handling referral:
+ * 0 - Don't know
+ * 1 - SMB Server
+ * 2 - Netware Server
+ * 3 - Domain
+ *
+ * USHORT ReferralFlags Flags which describe this referral:
+ * 01 - Strip off PathConsumed characters
+ * before submitting RequestFileName to Node
+ *
+ * UNICODESTRING Node Name of entity to visit next
+ *
+ * Version 2 Referral Element Format
+ * ======================================================================
+ *
+ * USHORT ServerType Type of Node handling referral:
+ * 0 - Don't know
+ * 1 - SMB Server
+ * 2 - Netware Server
+ * 3 - Domain
+ *
+ * USHORT ReferralFlags Flags which describe this referral:
+ * 01 - Strip off PathConsumed characters
+ * before submitting RequestFileName to
+ * Node
+ *
+ * ULONG Proximity A hint describing the proximity of this
+ * server to the client. 0 indicates the
+ * closest, higher numbers indicate
+ * increasingly "distant" servers. The
+ * number is only relevant within the
+ * context of the servers listed in this
+ * particular SMB.
+ *
+ * ULONG TimeToLive Number of seconds for which the client
+ * can cache this referral.
+ *
+ * USHORT DfsPathOffset Offset, in bytes from the beginning of
+ * this referral, of the DFS Path that
+ * matched PathConsumed bytes of the
+ * RequestFileName.
+ *
+ * USHORT DfsAlternatePathOffset Offset, in bytes from the beginning of
+ * this referral, of an alternate name
+ * (8.3 format) of the DFS Path that
+ * matched PathConsumed bytes of the
+ * RequestFileName.
+ *
+ * USHORT NetworkAddressOffset Offset, in bytes from the beginning of
+ * this referral, of the entity to visit
+ * next.
+ *
+ * The CIFS protocol imposes no referral selection policy.
+ */
+int /*ARGSUSED*/
+smb_com_trans2_get_dfs_referral(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+
+/*
+ * SMB: trans2_report_dfs_inconsistency
+ *
+ * As part of the Distributed Name Resolution algorithm, a DFS client may
+ * discover a knowledge inconsistency between the referral server (i.e.,
+ * the server that handed out a referral), and the storage server (i.e.,
+ * the server to which the client was redirected to by the referral
+ * server). When such an inconsistency is discovered, the DFS client
+ * optionally sends this SMB to the referral server, allowing the referral
+ * server to take corrective action.
+ *
+ * Client Request Description
+ * ================================== ==================================
+ * WordCount 15
+ * MaxParameterCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_REPORT_DFS_INCONSISTENCY
+ *
+ * Parameter Block Encoding Description
+ * ================================== ==================================
+ *
+ * UNICODESTRING RequestFileName; DFS Name of file for which
+ * referral was sought
+ *
+ * The data part of this request contains the referral element (Version 1
+ * format only) believed to be in error. These are encoded as described in
+ * the TRANS2_GET_DFS_REFERRAL response. If the server returns success,
+ * the client can resubmit the TRANS2_GET_DFS_REFERRAL request to this
+ * server to get a new referral. It is not mandatory for the DFS knowledge
+ * to be automatically repaired – the client must be prepared to receive
+ * further errant referrals and must not wind up looping between this
+ * request and the TRANS2_GET_DFS_REFERRAL request.
+ *
+ * Bit15 of Flags2 in the SMB header must be set, indicating this is a
+ * UNICODE request.
+ */
+int /*ARGSUSED*/
+smb_com_trans2_report_dfs_inconsistency(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
new file mode 100644
index 0000000000..3ab7076102
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -0,0 +1,1142 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides functions for TRANS2_FIND_FIRST2 and
+ * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
+ * for the file(s) which match the file specification. The search is
+ * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
+ * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
+ * obtained for the returned files, the desired level is specified in the
+ * InformationLevel field of the requests.
+ *
+ * InformationLevel Name Value
+ * ================================= ================
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_INFO_QUERY_EAS_FROM_LIST 3
+ * SMB_FIND_FILE_DIRECTORY_INFO 0x101
+ * SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+ * SMB_FIND_FILE_NAMES_INFO 0x103
+ * SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+ *
+ * The following sections detail the data returned for each
+ * InformationLevel. The requested information is placed in the Data
+ * portion of the transaction response. Note: a client which does not
+ * support long names can only request SMB_INFO_STANDARD.
+ *
+ * A four-byte resume key precedes each data item (described below) if bit
+ * 2 in the Flags field is set, i.e. if the request indicates the server
+ * should return resume keys. Note: it is not always the case. If the
+ * data item already includes the resume key, the resume key should not be
+ * added again.
+ *
+ * 4.3.4.1 SMB_INFO_STANDARD
+ *
+ * Response Field Description
+ * ================================ ==================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation unit
+ * USHORT Attributes; File Attributes
+ * UCHAR FileNameLength; Length of filename in bytes
+ * STRING FileName; Name of found file
+ *
+ * 4.3.4.2 SMB_INFO_QUERY_EA_SIZE
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * UCHAR FileNameLength; Length of filename in bytes
+ * STRING FileName; Name of found file
+ *
+ * 4.3.4.3 SMB_INFO_QUERY_EAS_FROM_LIST
+ *
+ * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
+ * only for files which have an EA list which match the EA information in
+ * the Data part of the request.
+ *
+ * 4.3.4.4 SMB_FIND_FILE_DIRECTORY_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; file creation time
+ * LARGE_INTEGER LastAccessTime; last access time
+ * LARGE_INTEGER LastWriteTime; last write time
+ * LARGE_INTEGER ChangeTime; last attribute change time
+ * LARGE_INTEGER EndOfFile; file size
+ * LARGE_INTEGER AllocationSize; size of filesystem allocation information
+ * ULONG ExtFileAttributes; Extended file attributes
+ * (see section 3.11)
+ * ULONG FileNameLength; Length of filename in bytes
+ * STRING FileName; Name of the file
+ *
+ * 4.3.4.5 SMB_FIND_FILE_FULL_DIRECTORY_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; file creation time
+ * LARGE_INTEGER LastAccessTime; last access time
+ * LARGE_INTEGER LastWriteTime; last write time
+ * LARGE_INTEGER ChangeTime; last attribute change time
+ * LARGE_INTEGER EndOfFile; file size
+ * LARGE_INTEGER AllocationSize; size of filesystem allocation information
+ * ULONG ExtFileAttributes; Extended file attributes
+ * (see section 3.11)
+ * ULONG FileNameLength; Length of filename in bytes
+ * ULONG EaSize; Size of file's extended attributes
+ * STRING FileName; Name of the file
+ *
+ * 4.3.4.6 SMB_FIND_FILE_BOTH_DIRECTORY_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * LARGE_INTEGER CreationTime; file creation time
+ * LARGE_INTEGER LastAccessTime; last access time
+ * LARGE_INTEGER LastWriteTime; last write time
+ * LARGE_INTEGER ChangeTime; last attribute change time
+ * LARGE_INTEGER EndOfFile; file size
+ * LARGE_INTEGER AllocationSize; size of filesystem allocation information
+ * ULONG ExtFileAttributes; Extended file attributes
+ * (see section 3.11)
+ * ULONG FileNameLength; Length of FileName in bytes
+ * ULONG EaSize; Size of file's extended attributes
+ * UCHAR ShortNameLength; Length of file's short name in bytes
+ * UCHAR Reserved
+ * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode
+ * STRING FileName; Files full length name
+ *
+ * 4.3.4.7 SMB_FIND_FILE_NAMES_INFO
+ *
+ * Response Field Description
+ * ================================= ==================================
+ *
+ * ULONG NextEntryOffset; Offset from this structure to
+ * beginning of next one
+ * ULONG FileIndex;
+ * ULONG FileNameLength; Length of FileName in bytes
+ * STRING FileName; Files full length name
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/msgbuf.h>
+#include <smbsrv/smbtrans.h>
+#include <smbsrv/smb_fsops.h>
+
+int smb_trans2_find_get_maxdata(struct smb_request *, unsigned short,
+ unsigned short);
+
+int smb_trans2_find_get_dents(struct smb_request *, struct smb_xa *,
+ unsigned short, unsigned short, int, struct smb_node *,
+ unsigned short, uint32_t, int, char *, uint32_t *, int *, int *);
+
+int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *,
+ smb_attr_t *, struct smb_node *, char *, char *);
+
+int smb_trans2_find_process_ients(struct smb_request *, struct smb_xa *,
+ smb_dent_info_hdr_t *, unsigned short, unsigned short, int,
+ struct smb_node *, int *, uint32_t *);
+
+int smb_trans2_find_mbc_encode(struct smb_request *, struct smb_xa *,
+ smb_dent_info_t *, int, unsigned short, unsigned short,
+ unsigned int, struct smb_node *, struct smb_node *);
+
+/*
+ * Support for Catia Version 5 Deployment
+ */
+static int (*catia_callback)(unsigned char *, unsigned char *, int) = NULL;
+void smb_register_catia_callback(
+ int (*catia_v4tov5)(unsigned char *, unsigned char *, int));
+void smb_unregister_catia_callback();
+
+/*
+ * Patchable parameter for find maximum count
+ */
+int max_find_count = 64;
+
+/*
+ * smb_register_catia_callback
+ *
+ * This function will be invoked by the catia module to register its
+ * function that translates filename in version 4 to a format that is
+ * compatible to version 5.
+ */
+void
+smb_register_catia_callback(
+ int (*catia_v4tov5)(unsigned char *, unsigned char *, int))
+{
+ catia_callback = catia_v4tov5;
+}
+
+/*
+ * smb_unregister_catia_callback
+ *
+ * This function will unregister the catia callback prior to the catia
+ * module gets unloaded.
+ */
+void
+smb_unregister_catia_callback()
+{
+ catia_callback = 0;
+}
+
+/*
+ * smb_com_trans2_find_first2
+ *
+ * Client Request Value
+ * ============================ ==================================
+ *
+ * UCHAR WordCount 15
+ * UCHAR TotalDataCount Total size of extended attribute list
+ * UCHAR SetupCount 1
+ * UCHAR Setup[0] TRANS2_FIND_FIRST2
+ *
+ * Parameter Block Encoding Description
+ * ============================ ==================================
+ * USHORT SearchAttributes;
+ * USHORT SearchCount; Maximum number of entries to return
+ * USHORT Flags; Additional information:
+ * Bit 0 - close search after this request
+ * Bit 1 - close search if end of search
+ * reached
+ * Bit 2 - return resume keys for each
+ * entry found
+ * Bit 3 - continue search from previous
+ * ending place
+ * Bit 4 - find with backup intent
+ * USHORT InformationLevel; See below
+ * ULONG SearchStorageType;
+ * STRING FileName; Pattern for the search
+ * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is
+ * QUERY_EAS_FROM_LIST
+ *
+ * Response Parameter Block Description
+ * ============================ ==================================
+ *
+ * USHORT Sid; Search handle
+ * USHORT SearchCount; Number of entries returned
+ * USHORT EndOfSearch; Was last entry returned?
+ * USHORT EaErrorOffset; Offset into EA list if EA error
+ * USHORT LastNameOffset; Offset into data to file name of last
+ * entry, if server needs it to resume
+ * search; else 0
+ * UCHAR Data[ TotalDataCount ] Level dependent info about the matches
+ * found in the search
+ */
+int
+smb_com_trans2_find_first2(struct smb_request *sr, struct smb_xa *xa)
+{
+ int more = 0, rc;
+ unsigned short sattr, fflag, infolev;
+ int maxdata;
+ int count, maxcount = 0, wildcards;
+ uint32_t cookie;
+ char *path;
+ struct smb_node *dir_snode;
+ char *pattern;
+ unsigned short sid;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%wwww4.u", sr,
+ &sattr, &maxcount, &fflag, &infolev, &path) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
+
+ if (maxdata == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ }
+
+ /* Convert name to our form */
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
+ (void) smb_convert_unicode_wildcards(path);
+ }
+ (void) smb_rdir_open(sr, path, sattr);
+
+ /*
+ * Get a copy of information
+ */
+ pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ dir_snode = sr->sid_odir->d_dir_snode;
+ (void) strcpy(pattern, sr->sid_odir->d_pattern);
+ /* this is funky */
+ if (strcmp(pattern, "*.*") == 0)
+ (void) strncpy(pattern, "*", sizeof (pattern));
+ wildcards = sr->sid_odir->d_wildcards;
+ sattr = sr->sid_odir->d_sattr;
+ cookie = 0;
+
+ rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
+ dir_snode, sattr, maxcount, wildcards,
+ pattern, &cookie, &more, &count);
+
+ if (!count)
+ rc = ENOENT;
+
+ if (rc) {
+ smb_rdir_close(sr);
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Save the sid here because search might get closed
+ * and sr->smb_sid becomes invalid.
+ * This might not seem important because the search
+ * is going to be finished anyways, but it's just for
+ * the sake of compatibility with Windows.
+ */
+ sid = sr->smb_sid;
+
+ if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
+ (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
+ smb_rdir_close(sr);
+ else {
+ mutex_enter(&sr->sid_odir->d_mutex);
+ sr->sid_odir->d_cookie = cookie;
+ mutex_exit(&sr->sid_odir->d_mutex);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwwww",
+ sid, count, (more ? 0 : 1), 0, 0);
+
+ kmem_free(pattern, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+
+/*
+ * smb_com_trans2_find_next2
+ *
+ * Client Request Value
+ * ================================== =================================
+ *
+ * WordCount 15
+ * SetupCount 1
+ * Setup[0] TRANS2_FIND_NEXT2
+ *
+ * Parameter Block Encoding Description
+ * ================================== =================================
+ *
+ * USHORT Sid; Search handle
+ * USHORT SearchCount; Maximum number of entries to
+ * return
+ * USHORT InformationLevel; Levels described in
+ * TRANS2_FIND_FIRST2 request
+ * ULONG ResumeKey; Value returned by previous find2
+ * call
+ * USHORT Flags; Additional information: bit set-
+ * 0 - close search after this
+ * request
+ * 1 - close search if end of search
+ * reached
+ * 2 - return resume keys for each
+ * entry found
+ * 3 - resume/continue from previous
+ * ending place
+ * 4 - find with backup intent
+ * STRING FileName; Resume file name
+ *
+ * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
+ * call. If Bit3 of Flags is set, then FileName may be the NULL string,
+ * since the search is continued from the previous TRANS2_FIND request.
+ * Otherwise, FileName must not be more than 256 characters long.
+ *
+ * Response Field Description
+ * ================================== =================================
+ *
+ * USHORT SearchCount; Number of entries returned
+ * USHORT EndOfSearch; Was last entry returned?
+ * USHORT EaErrorOffset; Offset into EA list if EA error
+ * USHORT LastNameOffset; Offset into data to file name of
+ * last entry, if server needs it to
+ * resume search; else 0
+ * UCHAR Data[TotalDataCount] Level dependent info about the
+ * matches found in the search
+ */
+int
+smb_com_trans2_find_next2(struct smb_request *sr, struct smb_xa *xa)
+{
+ unsigned short fflag, infolev;
+ int maxdata, count, wildcards, more = 0, rc;
+ uint32_t cookie;
+ uint32_t maxcount = 0;
+ struct smb_node *dir_snode;
+ char *pattern;
+ unsigned short sattr;
+
+ pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ /*
+ * There is a path field as the last piece of input information:
+ *
+ * smb_decode_mbc(&xa->req_param_mb, "%www lwu", sr,
+ * &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &path)
+ *
+ * This feild has been removed because it's causing problem
+ * with Mac OS 10 and it's not used anyways.
+ * The problem is that code expects to see a 2-byte null
+ * because the strings are supposed to be Unicode, but
+ * Max OS 10 sends a 1-byte null which leads to decode error.
+ */
+ if (smb_decode_mbc(&xa->req_param_mb, "%www lw", sr,
+ &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) {
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (maxdata == 0) {
+ smb_rdir_close(sr);
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Get a copy of information
+ */
+ dir_snode = sr->sid_odir->d_dir_snode;
+ (void) strcpy(pattern, sr->sid_odir->d_pattern);
+ wildcards = sr->sid_odir->d_wildcards;
+ sattr = sr->sid_odir->d_sattr;
+ if (fflag & SMB_FIND_CONTINUE_FROM_LAST) {
+ mutex_enter(&sr->sid_odir->d_mutex);
+ cookie = sr->sid_odir->d_cookie;
+ mutex_exit(&sr->sid_odir->d_mutex);
+ }
+
+ /*
+ * XXX this is an optimization made for SFS2 filesystem, it might
+ * not be required for ZFS
+ *
+ * Break the count to smaller counts (less than the default 150)
+ * to reduce the number of transaction failures
+ * which may cause excessive delays and eventually a SMB staled
+ * connection.
+ */
+ maxcount = (maxcount > max_find_count) ? max_find_count : maxcount;
+
+ rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
+ dir_snode, sattr, maxcount, wildcards, pattern, &cookie,
+ &more, &count);
+
+ if (rc) {
+ smb_rdir_close(sr);
+ kmem_free(pattern, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
+ (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
+ smb_rdir_close(sr);
+ else {
+ mutex_enter(&sr->sid_odir->d_mutex);
+ sr->sid_odir->d_cookie = cookie;
+ mutex_exit(&sr->sid_odir->d_mutex);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
+ count, (more ? 0 : 1), 0, 0);
+
+ kmem_free(pattern, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+/*
+ * smb_trans2_find_get_maxdata
+ *
+ * This function calculates the minimum space requirement for the
+ * base on information level and fflag.
+ *
+ * When success, minimum space requirement will be returned; otherwise,
+ * 0 will be returned.
+ */
+int
+smb_trans2_find_get_maxdata(
+ struct smb_request *sr,
+ unsigned short infolev,
+ unsigned short fflag)
+{
+ int maxdata;
+
+ maxdata = smb_ascii_or_unicode_null_len(sr);
+
+ switch (infolev) {
+ case SMB_INFO_STANDARD :
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ maxdata += sizeof (int32_t);
+ maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ maxdata += sizeof (int32_t);
+ maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ maxdata += 4 + 4 + 4;
+ break;
+
+ case SMB_MAC_FIND_BOTH_HFS_INFO:
+ maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
+ 4 + 32 + 4 + 1 + 1 + 24 + 4;
+ break;
+
+ default:
+ maxdata = 0;
+ }
+
+ return (maxdata);
+}
+
+
+
+/*
+ * smb_trans2_find_get_dents
+ *
+ * This function will get all the directory entry information and mbc
+ * encode it in the xa. If there is an error, it will be returned;
+ * otherwise, 0 is returned.
+ *
+ * The more field will be updated. If the value returned is one, it means
+ * there are more entries; otherwise, the returned value will be zero. The
+ * cookie will also be updated to indicate the next start point for the
+ * search. The count value will also be updated to stores the total entries
+ * encoded.
+ */
+int smb_trans2_find_get_dents(
+ smb_request_t *sr,
+ smb_xa_t *xa,
+ unsigned short fflag,
+ unsigned short infolev,
+ int maxdata,
+ smb_node_t *dir_snode,
+ unsigned short sattr,
+ uint32_t maxcount,
+ int wildcards,
+ char *pattern,
+ uint32_t *cookie,
+ int *more,
+ int *count)
+{
+ smb_dent_info_hdr_t *ihdr;
+ smb_dent_info_t *ient;
+ int dent_buf_size;
+ int i;
+ int total;
+ int maxentries;
+ int rc;
+
+ ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP);
+ *count = 0;
+
+ if (!wildcards)
+ maxentries = maxcount = 1;
+ else {
+ maxentries = (xa->rep_data_mb.max_bytes -
+ xa->rep_data_mb.chain_offset) / maxdata;
+ if (maxcount > SMB_MAX_DENTS_IOVEC)
+ maxcount = SMB_MAX_DENTS_IOVEC;
+ if (maxentries > maxcount)
+ maxentries = maxcount;
+ }
+
+ /* Each entry will need to be aligned so add _POINTER_ALIGNMENT */
+ dent_buf_size =
+ maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT);
+ ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP);
+
+ ihdr->sattr = sattr;
+ ihdr->pattern = pattern;
+ ihdr->sr = sr;
+
+ ihdr->uio.uio_iovcnt = maxcount;
+ ihdr->uio.uio_resid = dent_buf_size;
+ ihdr->uio.uio_iov = ihdr->iov;
+ ihdr->uio.uio_offset = 0;
+
+ rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more);
+ if (rc != 0) {
+ goto out;
+ }
+
+ if (ihdr->iov->iov_len == 0)
+ *count = 0;
+ else
+ *count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag,
+ infolev, maxdata, dir_snode, more, cookie);
+ rc = 0;
+
+out:
+
+ total = maxcount - ihdr->uio.uio_iovcnt;
+ ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC));
+ for (i = 0; i < total; i++) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ient = (smb_dent_info_t *)ihdr->iov[i].iov_base;
+ ASSERT(ient);
+ smb_node_release(ient->snode);
+ }
+
+ kmem_free(ihdr->iov->iov_base, dent_buf_size);
+ kmem_free(ihdr, sizeof (smb_dent_info_hdr_t));
+ return (0);
+}
+
+
+
+/*
+ * smb_get_dents
+ *
+ * This function utilizes "smb_fsop_getdents()" to get dir entries.
+ * The "smb_gather_dents_info()" is the call back function called
+ * inside the file system. It is very important that the function
+ * does not sleep or yield since it is processed inside a file
+ * system transaction.
+ *
+ * The function returns 0 when successful and error code when failed.
+ * If more is provided, the return value of 1 is returned indicating
+ * more entries; otherwise, 0 is returned.
+ */
+int smb_get_dents(
+ smb_request_t *sr,
+ uint32_t *cookie,
+ smb_node_t *dir_snode,
+ unsigned int wildcards,
+ smb_dent_info_hdr_t *ihdr,
+ int *more)
+{
+ int rc;
+ char *namebuf;
+ smb_node_t *snode;
+ smb_attr_t file_attr;
+ uint32_t maxcnt = ihdr->uio.uio_iovcnt;
+ char shortname[MANGLE_NAMELEN], name83[MANGLE_NAMELEN];
+ fsvol_attr_t vol_attr;
+
+ namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+ if (more)
+ *more = 0;
+
+ if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) {
+ kmem_free(namebuf, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (!wildcards) {
+ /* Already found entry? */
+ if (*cookie != 0)
+ return (0);
+ shortname[0] = '\0';
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
+ dir_snode, ihdr->pattern, &snode, &file_attr, shortname,
+ name83);
+
+ if (rc) {
+ kmem_free(namebuf, MAXNAMELEN);
+ return (rc);
+ }
+
+ (void) strlcpy(namebuf, ihdr->pattern, MAXNAMELEN);
+
+ /*
+ * It is not necessary to set the "force" flag (i.e. to
+ * take into account mangling for case-insensitive collisions)
+ */
+
+ if (shortname[0] == '\0')
+ (void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid,
+ namebuf, shortname, name83, 0);
+ (void) smb_gather_dents_info((char *)ihdr,
+ snode->attr.sa_vattr.va_nodeid,
+ strlen(namebuf), namebuf, -1, (int *)&maxcnt,
+ &snode->attr, snode, shortname, name83);
+ kmem_free(namebuf, MAXNAMELEN);
+ return (0);
+ }
+
+ if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie,
+ 0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) {
+ if (rc == ENOENT) {
+ kmem_free(namebuf, MAXNAMELEN);
+ return (0);
+ }
+ kmem_free(namebuf, MAXNAMELEN);
+ return (rc);
+ }
+
+ if (*cookie != 0x7FFFFFFF && more)
+ *more = 1;
+
+ kmem_free(namebuf, MAXNAMELEN);
+ return (0);
+}
+
+
+
+
+/*
+ * smb_gather_dents_info
+ *
+ * The function will accept information of each directory entry and put
+ * the needed information in the buffer. It is passed as the call back
+ * function for smb_fsop_getdents() to gather trans2 find info.
+ *
+ * If the buffer space is not enough, -1 will be returned. Regardless
+ * of valid entry or not, 0 will be returned; however, only valid entry
+ * will be stored in the buffer.
+ */
+int /*ARGSUSED*/
+smb_gather_dents_info(
+ char *args,
+ ino_t fileid,
+ int namelen,
+ char *name,
+ uint32_t cookie,
+ int32_t *countp,
+ smb_attr_t *attr,
+ smb_node_t *snode,
+ char *shortname,
+ char *name83)
+{
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)args;
+ smb_dent_info_t *ient;
+ unsigned char *v5_name = NULL;
+ unsigned char *np = (unsigned char *)name;
+ int reclen = sizeof (smb_dent_info_t) + namelen;
+
+ v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP);
+
+ if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) {
+ kmem_free(v5_name, MAXNAMELEN-1);
+ smb_node_release(snode);
+ return (-1);
+ }
+
+ if (!smb_sattr_check(attr, name, ihdr->sattr)) {
+ kmem_free(v5_name, MAXNAMELEN-1);
+ smb_node_release(snode);
+ return (0);
+ }
+
+ /*
+ * If StorEdge is configured to support Catia Version 5 deployments,
+ * any directory entry whose name contains the special Unix character
+ * that is considered to be illegal in Windows environement will be
+ * translated based on the following
+ * Special Character Translation Table.
+ *
+ * ---------------------------
+ * Unix-char | Windows-char
+ * ---------------------------
+ * " | (0x00a8) Diaeresis
+ * * | (0x00a4) Currency Sign
+ * : | (0x00f7) Division Sign
+ * < | (0x00ab) Left-Pointing Double Angle Quotation Mark
+ * > | (0x00bb) Right-Pointing Double Angle Quotation Mark
+ * ? | (0x00bf) Inverted Question mark
+ * \ | (0x00ff) Latin Small Letter Y with Diaeresis
+ * | | (0x00a6) Broken Bar
+ */
+ if (catia_callback) {
+ /* XXX 255 should be max name len or something */
+ catia_callback(v5_name, (unsigned char *)name, 255);
+ np = v5_name;
+ reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name);
+ }
+
+ ASSERT(snode);
+ ASSERT(snode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ /*
+ * Each entry needs to be properly aligned or we may get an alignment
+ * fault on sparc.
+ */
+ ihdr->uio.uio_offset = (off_t)PTRALIGN(ihdr->uio.uio_offset);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_offset];
+
+ ient->cookie = cookie;
+ ient->attr = *attr;
+ ient->snode = snode;
+
+ (void) strcpy(ient->name, (char *)np);
+ (void) strcpy(ient->shortname, shortname);
+ (void) strcpy(ient->name83, name83);
+ ihdr->uio.uio_iov->iov_base = (char *)ient;
+ ihdr->uio.uio_iov->iov_len = reclen;
+
+ ihdr->uio.uio_iov++;
+ ihdr->uio.uio_iovcnt--;
+ ihdr->uio.uio_resid -= reclen;
+ ihdr->uio.uio_offset += reclen;
+
+ kmem_free(v5_name, MAXNAMELEN-1);
+ return (0);
+}
+
+
+
+/*
+ * smb_trans2_find_process_ients
+ *
+ * This function encodes the directory entry information store in
+ * the iov structure of the ihdr structure.
+ *
+ * The total entries encoded will be returned. If the entries encoded
+ * is less than the total entries in the iov, the more field will
+ * be updated to 1. Also, the next cookie wil be updated as well.
+ */
+int
+smb_trans2_find_process_ients(
+ struct smb_request *sr,
+ struct smb_xa *xa,
+ smb_dent_info_hdr_t *ihdr,
+ unsigned short fflag,
+ unsigned short infolev,
+ int maxdata,
+ struct smb_node *dir_snode,
+ int *more,
+ uint32_t *cookie)
+{
+ int i, err = 0;
+ smb_dent_info_t *ient;
+ uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ ? SMB_MSGBUF_UNICODE : 0;
+
+ for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0)
+ break;
+
+ /*
+ * FYI: Some observed differences between our response and
+ * Windows response which hasn't caused problem yet!
+ *
+ * 1. The NextEntryOffset field for the last entry should be 0
+ * This code always calculate the record length and put the
+ * result in this field.
+ *
+ * 2. The FileIndex field is always 0. This code put the cookie
+ * in this field.
+ */
+ err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev,
+ fflag, mb_flags, dir_snode, NULL);
+
+ if (err)
+ break;
+ }
+
+ /*
+ * Not enough space to store all the entries returned; therefore,
+ * update the more to 1.
+ */
+ if (more && err < 0) {
+ *more = 1;
+
+ /*
+ * Assume the space will be at least enough for 1 entry.
+ */
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base;
+ *cookie = ient->cookie;
+ }
+ return (i);
+}
+
+
+
+/*
+ * smb_trans2_find_mbc_encode
+ *
+ * This function encodes the mbc for one directory entry.
+ *
+ * The function returns -1 when the max data requested by client
+ * is reached. If the entry is valid and successful encoded, 0
+ * will be returned; otherwise, 1 will be returned.
+ */
+int smb_trans2_find_mbc_encode(
+ struct smb_request *sr,
+ struct smb_xa *xa,
+ smb_dent_info_t *ient,
+ int maxdata,
+ unsigned short infolev,
+ unsigned short fflag,
+ unsigned int mb_flags,
+ struct smb_node *dir_snode, /*LINTED E_FUNC_ARG_UNUSED*/
+ struct smb_node *sd_snode)
+{
+ int uni_namelen;
+ int sl, rl;
+ char buf83[26];
+ smb_msgbuf_t mb;
+ uint32_t dattr = 0;
+ uint32_t size32 = 0;
+ uint64_t size64 = 0;
+ struct smb_node *lnk_snode;
+ smb_attr_t lnkattr;
+ int rc;
+
+ uni_namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
+
+ if (uni_namelen == -1)
+ return (1);
+
+ if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + uni_namelen)) == 0)
+ return (-1);
+
+ if (ient->attr.sa_vattr.va_type == VLNK) {
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode,
+ &lnkattr, 0, 0);
+
+ /*
+ * IR 104598
+ *
+ * We normally want to resolve the object to which a symlink
+ * refers so that CIFS clients can access sub-directories and
+ * find the correct association for files. This causes a
+ * problem, however, if a symlink in a sub-directory points
+ * to a parent directory (some UNIX GUI's create a symlink in
+ * $HOME/.desktop that points to the user's home directory).
+ * Some Windows applications (i.e. virus scanning) loop/hang
+ * trying to follow this recursive path and there is little
+ * we can do because the path is constructed on the client.
+ * So we've added a flag that allows an end-user to disable
+ * symlinks to directories. Symlinks to other object types
+ * should be unaffected.
+ */
+ if (rc == 0) {
+ if (smb_info.si.skc_dirsymlink_enable ||
+ (lnkattr.sa_vattr.va_type != VDIR)) {
+ smb_node_release(ient->snode);
+ ient->snode = lnk_snode;
+ ient->attr = lnkattr;
+ } else {
+ smb_node_release(lnk_snode);
+ }
+ }
+ }
+
+ if (infolev != SMB_FIND_FILE_NAMES_INFO) {
+ size64 = smb_node_get_size(ient->snode, &ient->attr);
+ size32 = (size64 > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)size64;
+ dattr = smb_mode_to_dos_attributes(&ient->attr);
+ }
+
+ /*
+ * we don't send the '.stream' to client. User shouldn't
+ * see this directory.
+ */
+ switch (infolev) {
+ case SMB_INFO_STANDARD:
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l",
+ ient->cookie);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwbu", sr,
+ ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec :
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ ient->attr.sa_vattr.va_atime.tv_sec,
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ size32,
+ size32,
+ dattr,
+ uni_namelen,
+ ient->name);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "l", ient->cookie);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwlbu", sr,
+ ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec :
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ ient->attr.sa_vattr.va_atime.tv_sec,
+ ient->attr.sa_vattr.va_mtime.tv_sec,
+ size32,
+ size32,
+ dattr,
+ 0L, /* EA Size */
+ uni_namelen,
+ ient->name);
+ break;
+
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ /* Use maxdata instead */
+ rl = maxdata + uni_namelen;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqllu", sr,
+ rl,
+ ient->cookie,
+ ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_atime,
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_ctime,
+ size64,
+ size64,
+ dattr,
+ uni_namelen,
+ ient->name);
+ break;
+
+ case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+ /* Use maxdata instead */
+ rl = maxdata + uni_namelen;
+ bzero(buf83, sizeof (buf83));
+ smb_msgbuf_init(&mb, (unsigned char *)buf83, sizeof (buf83),
+ mb_flags);
+ if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
+ smb_msgbuf_term(&mb);
+ return (-1);
+ }
+ sl = smb_ascii_or_unicode_strlen(sr, ient->shortname);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "%llTTTTqqlllb.24cu", sr,
+ rl,
+ ient->cookie,
+ ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_atime,
+ &ient->attr.sa_vattr.va_mtime,
+ &ient->attr.sa_vattr.va_ctime,
+ size64,
+ size64,
+ dattr,
+ uni_namelen,
+ 0L,
+ sl,
+ buf83,
+ ient->name);
+
+ smb_msgbuf_term(&mb);
+ break;
+
+ case SMB_FIND_FILE_NAMES_INFO:
+ rl = maxdata + uni_namelen;
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lllu", sr,
+ rl,
+ ient->cookie,
+ uni_namelen,
+ ient->name);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Close a search started by a Trans2FindFirst2 request.
+ */
+int
+smb_com_find_close2(struct smb_request *sr)
+{
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_sid) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
+ if (sr->sid_odir == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ smb_rdir_close(sr);
+
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c
new file mode 100644
index 0000000000..64fc11c3fc
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_open2.c
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_open2
+ *
+ * This transaction is used to open or create a file having extended
+ * attributes.
+ *
+ * Client Request Value
+ * ============================ =======================================
+ *
+ * WordCount 15
+ * TotalDataCount Total size of extended attribute list
+ * DataOffset Offset to extended attribute list in
+ * this request
+ * SetupCount 1
+ * Setup[0] TRANS2_OPEN2
+ *
+ * Parameter Block Encoding Description
+ * ============================ =======================================
+ *
+ * USHORT Flags; Additional information: bit set-
+ * 0 - return additional info
+ * 1 - exclusive oplock requested
+ * 2 - batch oplock requested
+ * 3 - return total length of EAs
+ * USHORT DesiredAccess; Requested file access
+ * USHORT Reserved1; Ought to be zero. Ignored by the
+ * server.
+ * USHORT FileAttributes; Attributes for file if create
+ * SMB_TIME CreationTime; Creation time to apply to file if
+ * create
+ * SMB_DATE CreationDate; Creation date to apply to file if
+ * create
+ * USHORT OpenFunction; Open function
+ * ULONG AllocationSize; Bytes to reserve on create or truncate
+ * USHORT Reserved [5]; Must be zero
+ * STRING FileName; Name of file to open or create
+ * UCHAR Data[ TotalDataCount ] FEAList structure for file to be
+ * created
+ *
+ * If secondary requests are required, they must contain 0 parameter bytes,
+ * and the Fid in the secondary request is 0xFFFF.
+ *
+ * DesiredAccess is encoded as described in the "Access Mode Encoding"
+ * section elsewhere in this document.
+ *
+ * FileAttributes are encoded as described in the "File Attribute Encoding"
+ * section elsewhere in this document.
+ *
+ * OpenFunction specifies the action to be taken depending on whether or
+ * not the file exists (see section 3.7) .
+ *
+ * Action in the response specifies the action as a result of this request
+ * (see section 3.8).
+ *
+ * Response Parameter Block Description
+ * ========================== =========================================
+ *
+ * USHORT Fid; File handle
+ * USHORT FileAttributes; Attributes of file
+ * SMB_TIME CreationTime; Last modification time
+ * SMB_DATE CreationDate; Last modification date
+ * ULONG DataSize; Current file size
+ * USHORT GrantedAccess; Access permissions actually allowed
+ * USHORT FileType; Type of file
+ * USHORT DeviceState; State of IPC device (e.g. pipe)
+ * USHORT Action; Action taken
+ * ULONG Reserved;
+ * USHORT EaErrorOffset; Offset into EA list if EA error
+ * ULONG EaLength; Total EA length for opened file
+ *
+ * FileType returns the kind of resource actually opened:
+ *
+ * Name Value Description
+ * ======================= ====== =====================================
+ *
+ * FileTypeDisk 0 Disk file or directory as defined in
+ * the attribute field
+ * FileTypeByteModePipe 1 Named pipe in byte mode
+ * FileTypeMessageModePipe 2 Named pipe in message mode
+ * FileTypePrinter 3 Spooled printer
+ * FileTypeUnknown 0xFFFF Unrecognized resource type
+ *
+ * DeviceState is applicable only if the FileType is FileTypeByteModePipe
+ * or FileTypeMessageModePipe and is encoded as in section 3.9.
+ *
+ * If an error was detected in the incoming EA list, the offset of the
+ * error is returned in EaErrorOffset.
+ *
+ * If bit0 of Flags in the request is clear, the FileAttributes,
+ * CreationTime, CreationDate, DataSize, GrantedAccess, FileType, and
+ * DeviceState have indeterminate values in the response. Similarly, if
+ *
+ * bit3 of the request is clear, EaLength in the response has an
+ * indeterminate value in the response.
+ *
+ * This SMB can request an oplock on the opened file. Oplocks are fully
+ * described in the "Oplocks" section elsewhere in this document, and there
+ * is also discussion of oplocks in the SMB_COM_LOCKING_ANDX SMB
+ * description. Bit1 and bit2 of the Flags field are used to request
+ * oplocks during open.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int /*ARGSUSED*/
+smb_com_trans2_open2(struct smb_request *sr)
+{
+ /* TODO: smb_com_trans2_open2 */
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
new file mode 100644
index 0000000000..2d488b7f2c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
@@ -0,0 +1,559 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_query_file_information
+ *
+ * This request is used to get information about a specific file or
+ * subdirectory given a handle to it.
+ *
+ * Client Request Value
+ * ========================== ==========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_QUERY_FILE_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== ==========================================
+ *
+ * USHORT Fid; Handle of file for request
+ * USHORT InformationLevel; Level of information requested
+ *
+ * The available information levels, as well as the format of the response
+ * are identical to TRANS2_QUERY_PATH_INFORMATION.
+ */
+
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+
+
+/*
+ * smb_com_trans2_query_file_information
+ *
+ * Observation of Windows 2000 indicates the following:
+ *
+ * 1) If a file is opened with delete-on-close create options, the
+ * delete-on-close status returned by the Trans2QueryFileInfo will not
+ * be set. The delete-on-close status will only be set when the above
+ * file handle is closed.
+ *
+ * 2) If a file is not opened with delete-on-close create options but the
+ * delete-on-close is set via Trans2SetFileInfo/DispositionInfo, the
+ * delete-on-close status returned by Trans2QueryFileInfo will be set
+ * immediately.
+ */
+
+int
+smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ static smb_attr_t pipe_attr;
+ unsigned short infolev, dattr = 0;
+ off_t dsize = 0, dused = 0;
+ smb_attr_t *ap = NULL;
+ char *namep = NULL;
+ char *filename = NULL, *alt_nm_ptr = NULL;
+ int filename_len = 0;
+ struct smb_node *dir_snode = NULL;
+ timestruc_t *creation_time = NULL;
+ unsigned char delete_on_close = 0;
+ unsigned char is_dir = 0;
+ char *filebuf = NULL;
+
+ /*
+ * buffer for mangled name and shortname are allocated
+ * much higher than required space. Optimization
+ * here should be performed along with mangled_name & shortname
+ * of query path information.
+ */
+ char *mangled_name = 0;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "ww", &sr->smb_fid,
+ &infolev) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ switch (sr->fid_ofile->f_ftype) {
+ case SMB_FTYPE_DISK:
+ {
+ /*
+ * The node is only valid for SMB_FTYPE_DISK files.
+ */
+ struct smb_node *node = sr->fid_ofile->f_node;
+
+ /*
+ * For some reason NT will not show the security tab in the root
+ * directory of a mapped drive unless the filename length is
+ * greater than one.
+ * This may be a NT vs Windows9x UNICODE check.
+ * So we hack the length here to persuade NT to show the tab. It
+ * should be safe because of the null terminator character.
+ */
+ /* be careful here we need od_name now rather than node_name */
+ /* do we want to use node_name in the case of softlinks ?? */
+ namep = node->od_name;
+ filename = namep;
+ filename_len = smb_ascii_or_unicode_strlen(sr, filename);
+ if (strcmp(namep, ".") == 0 && filename_len == 1)
+ filename_len = 2;
+
+ creation_time = smb_node_get_crtime(node);
+ dattr = smb_node_get_dosattr(node);
+
+ ap = &node->attr;
+ if (ap->sa_vattr.va_type == VDIR) {
+ is_dir = 1;
+ dsize = dused = 0;
+ } else {
+ is_dir = 0;
+ dsize = ap->sa_vattr.va_size;
+ dused = ap->sa_vattr.va_blksize *
+ ap->sa_vattr.va_nblocks;
+ }
+
+ dir_snode = node->dir_snode;
+ delete_on_close =
+ (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+ }
+ break;
+
+ case SMB_FTYPE_MESG_PIPE:
+ {
+ /*
+ * The pipe is only valid for SMB_FTYPE_MESG_PIPE files.
+ */
+ mlsvc_pipe_t *pipe_info = sr->fid_ofile->f_pipe_info;
+ namep = pipe_info->pipe_name;
+
+ filename = namep;
+ filename_len = smb_ascii_or_unicode_strlen(sr, filename);
+
+ ap = &pipe_attr;
+ creation_time = (timestruc_t *)&ap->sa_vattr.va_ctime;
+ dattr = SMB_FA_NORMAL;
+ dsize = dused = 0;
+
+ delete_on_close = 0;
+ is_dir = 0;
+ }
+ break;
+
+ default:
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOTREACHED */
+ break;
+ }
+
+ filebuf = kmem_alloc(MAXNAMELEN+1, KM_SLEEP);
+ mangled_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (infolev > SMB_INFO_PASSTHROUGH)
+ infolev -= SMB_INFO_PASSTHROUGH;
+
+ switch (infolev) {
+ case FileAccessInformation:
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l",
+ sr->fid_ofile->f_granted_access);
+ break;
+
+ case SMB_INFO_STANDARD:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllw" : "yyyllw"),
+ smb_gmt_to_local_time(creation_time->tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllwl" : "yyyllwl"),
+ smb_gmt_to_local_time(creation_time->tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr, 0);
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ case SMB_INFO_QUERY_ALL_EAS:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_INFO_IS_NAME_VALID:
+ break;
+
+ case SMB_QUERY_FILE_BASIC_INFO:
+ /*
+ * NT includes 6 undocumented bytes at the end of this
+ * response, which are required by NetBench 5.01.
+ * Similar change in smb_trans2_query_path_information.c.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.",
+ creation_time,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr);
+ break;
+
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w",
+ SMB_QUERY_FILE_STANDARD_INFO);
+ /*
+ * Add 2 bytes to pad data to long. It is
+ * necessary because Win2k expects the padded bytes.
+ */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qqlbb2.",
+ dused,
+ dsize,
+ ap->sa_vattr.va_nlink,
+ delete_on_close,
+ is_dir);
+ break;
+
+ case SMB_QUERY_FILE_EA_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ * It looks like NT doesn't know what to do with the name "."
+ * so we convert it to "\\" to indicate the root directory.
+ *
+ * If the leading \ is missing, add it.
+ */
+ if (strcmp(namep, ".") == 0) {
+ filename = "\\";
+ filename_len = 2;
+ } else if (*namep != '\\') {
+ filename = filebuf;
+ (void) snprintf(filename, MAXNAMELEN + 1, "\\%s",
+ namep);
+ filename_len =
+ smb_ascii_or_unicode_strlen(sr, filename);
+ } else {
+ filename = namep;
+ filename_len =
+ smb_ascii_or_unicode_strlen(sr, filename);
+ }
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ filename_len, filename);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ /*
+ * The reply of this information level on the
+ * wire doesn't match with protocol specification.
+ * This is what spec. needs: "TTTTwqqlbbqllqqll"
+ * But this is actually is sent on the wire:
+ * "TTTTw6.qqlbb2.l"
+ * So, there is a 6-byte pad between Attributes and
+ * AllocationSize. Also there is a 2-byte pad After
+ * Directory field. Between Directory and FileNameLength
+ * there is just 4 bytes that it seems is AlignmentRequirement.
+ * There are 6 other fields between Directory and
+ * AlignmentRequirement in spec. that aren't sent
+ * on the wire.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
+ creation_time,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr,
+ (int64_t)dused,
+ (int64_t)dsize,
+ ap->sa_vattr.va_nlink,
+ delete_on_close,
+ is_dir,
+ 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu",
+ sr, filename_len, filename);
+ break;
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ /*
+ * Conform to the rule used by Windows NT/2003 servers.
+ * Shortname is created only if either the
+ * filename or extension portion of a file is made up of
+ * mixed case. This is handled in os/libnt/nt_mangle_name.c.
+ *
+ * If the shortname is generated, it will be returned as
+ * the alternative name. Otherwise, converts the original
+ * name to all upper-case and returns it as the alternative
+ * name. This is how Windows NT/2003 servers behave. However,
+ * Windows 2000 seems to preserve the case of the original
+ * name, and returns it as the alternative name.
+ */
+ alt_nm_ptr = (*mangled_name == 0) ?
+ utf8_strupr(filename) : mangled_name;
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, alt_nm_ptr), alt_nm_ptr);
+ break;
+
+ case SMB_QUERY_FILE_STREAM_INFO:
+ {
+ struct smb_node *node = sr->fid_ofile->f_node;
+ if (dir_snode == NULL) {
+ kmem_free(filebuf, MAXNAMELEN+1);
+ kmem_free(mangled_name, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRbadfile);
+ /* NOT REACHED */
+ }
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ if (SMB_IS_STREAM(node)) {
+ ASSERT(node->unnamed_stream_node);
+ ASSERT(node->unnamed_stream_node->n_magic ==
+ SMB_NODE_MAGIC);
+ ASSERT(node->unnamed_stream_node->n_state !=
+ SMB_NODE_STATE_DESTROYING);
+
+ (void) smb_encode_stream_info(sr, xa,
+ node->unnamed_stream_node, ap);
+ } else {
+ (void) smb_encode_stream_info(sr, xa, node, ap);
+ }
+ break;
+ }
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qwbbb3.",
+ dsize, 0, 0, 0, 0);
+ break;
+
+ default:
+ kmem_free(filebuf, MAXNAMELEN+1);
+ kmem_free(mangled_name, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ break;
+ }
+
+ kmem_free(filebuf, MAXNAMELEN+1);
+ kmem_free(mangled_name, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * smb_encode_stream_info
+ *
+ * This function encodes the streams information for both T2QueryFileInfo
+ * and T2QueryPathInfo. The rules about how to do this are not documented.
+ * They have been derived using observed NT behaviour and the IR's listed
+ * below.
+ *
+ * IR101680: ArcServe2000 problem. ArcServe doesn't like the null-
+ * stream data on directories that don't have any associated streams.
+ *
+ * IR103484 and KB article Q234765: Citrix problem. If there are no
+ * streams, only return the unnamed stream data if the target is a
+ * file. The Citrix Metaframe cdm.sys driver crashes the Windows server,
+ * on which it's running, if it receives the unexpected stream data
+ * for a directory.
+ *
+ * If there are streams, on files or directories, we need to return
+ * them to support Mac/DAVE clients. Mac clients make this request
+ * to see if there is a comment stream. If we don't provide the
+ * information, the client won't try to access the comment stream.
+ *
+ * If the target is a file:
+ * 1. If there are no named streams, the response should still contain
+ * an entry for the unnamed stream.
+ * 2. If there are named streams, the response should contain an entry
+ * for the unnamed stream followed by the entries for the named
+ * streams.
+ *
+ * If the target is a directory:
+ * 1. If there are no streams, the response is complete. Directories
+ * do not report the unnamed stream.
+ * 2. If there are streams, the response should contain entries for
+ * those streams but there should not be an entry for the unnamed
+ * stream.
+ *
+ * Note that the stream name lengths exclude the null terminator but
+ * the field lengths (i.e. next offset calculations) need to include
+ * the null terminator and be padded to a multiple of 8 bytes. The
+ * last entry does not seem to need any padding.
+ */
+
+void
+smb_encode_stream_info(
+ struct smb_request *sr,
+ struct smb_xa *xa,
+ struct smb_node *snode,
+ smb_attr_t *attr)
+{
+ char *stream_name;
+ uint32_t next_offset;
+ uint32_t stream_nlen;
+ uint32_t pad;
+ off_t dsize;
+ int is_dir;
+ uint32_t cookie = 0;
+ struct fs_stream_info *stream_info;
+ struct fs_stream_info *stream_info_next;
+ int rc = 0;
+ int done = 0;
+ char *fname;
+
+ stream_info = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP);
+ stream_info_next = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP);
+ is_dir = (attr->sa_vattr.va_type == VDIR) ? 1 : 0;
+ dsize = attr->sa_vattr.va_size;
+ fname = MEM_MALLOC("smb", MAXPATHLEN);
+
+ rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie, stream_info,
+ NULL, NULL);
+
+ if ((cookie == 0x7FFFFFFF) || (rc == EACCES) || (rc == ENOENT)) {
+ if (is_dir == 0) {
+ stream_name = "::$DATA";
+ stream_nlen =
+ smb_ascii_or_unicode_strlen(sr, stream_name);
+ next_offset = 0;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llqqu",
+ sr, next_offset, stream_nlen, dsize, dsize,
+ stream_name);
+ }
+ /* No named streams, we're done */
+ kmem_free(stream_info, sizeof (struct fs_stream_info));
+ kmem_free(stream_info_next, sizeof (struct fs_stream_info));
+ MEM_FREE("smb", fname);
+ return;
+ }
+
+ if (is_dir == 0) {
+ stream_name = "::$DATA";
+ stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
+
+ /*
+ * Offset calculation:
+ * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
+ */
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llqqu", sr,
+ next_offset, stream_nlen, dsize, dsize, stream_name);
+ }
+
+ while (!done) {
+ /*
+ * Named streams.
+ */
+ stream_nlen = smb_ascii_or_unicode_strlen(sr,
+ stream_info->name);
+ next_offset = 0;
+ pad = 0;
+
+ /*
+ * this is a little kludgy, since we use a cookie now and last
+ * packet does not have a pad we need to check the next item
+ * before we encode the current one
+ */
+ stream_info_next->name[0] = 0;
+ rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie,
+ stream_info_next, NULL, NULL);
+ if (cookie == 0x7FFFFFFF) {
+ done = 1;
+ } else {
+ if (cookie == 0) {
+ break;
+ }
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+ pad = smb_pad_align(next_offset, 8);
+ next_offset += pad;
+ }
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%llqqu#.",
+ sr, next_offset, stream_nlen,
+ stream_info->size, stream_info->size,
+ stream_info->name, pad);
+
+ (void) memcpy(stream_info, stream_info_next,
+ sizeof (struct fs_stream_info));
+ }
+ kmem_free(stream_info, sizeof (struct fs_stream_info));
+ kmem_free(stream_info_next, sizeof (struct fs_stream_info));
+ MEM_FREE("smb", fname);
+}
+
+/*
+ * smb_pad_align
+ *
+ * Returns the number of bytes required to get pad an offset to the
+ * specified alignment.
+ */
+uint32_t
+smb_pad_align(uint32_t offset, uint32_t align)
+{
+ uint32_t pad = offset % align;
+
+ if (pad != 0)
+ pad = align - pad;
+
+ return (pad);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
new file mode 100644
index 0000000000..aa7cc15343
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_fs_information.c
@@ -0,0 +1,434 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_query_fs_information
+ *
+ * This transaction requests information about a filesystem on the server.
+ *
+ * Client Request Value
+ * ================================== =================================
+ *
+ * WordCount; 15
+ * TotalParameterCount; 2 or 4
+ * MaxSetupCount; 0
+ * SetupCount; 1 or 2
+ * Setup[0]; TRANS2_QUERY_FS_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ================================== =================================
+ *
+ * USHORT Information Level; Level of information requested
+ *
+ * The filesystem is identified by Tid in the SMB header.
+ *
+ * MaxDataCount in the transaction request must be large enough to
+ * accommodate the response.
+ *
+ * The encoding of the response parameter block depends on the
+ * InformationLevel requested. Information levels whose values are greater
+ * than 0x102 are mapped to corresponding calls to
+ * NtQueryVolumeInformationFile calls by the server. The two levels below
+ * 0x102 are described below. The requested information is placed in the
+ * Data portion of the transaction response.
+ *
+ * InformationLevel Value
+ *
+ * ============================= ======
+ *
+ * SMB_INFO_ALLOCATION 1
+ * SMB_INFO_VOLUME 2
+ * SMB_QUERY_FS_VOLUME_INFO 0x102
+ * SMB_QUERY_FS_SIZE_INFO 0x103
+ * SMB_QUERY_FS_DEVICE_INFO 0x104
+ * SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+ *
+ * The following sections describe the InformationLevel dependent encoding
+ * of the data part of the transaction response.
+ *
+ * 4.1.6.1 SMB_INFO_ALLOCATION
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * ULONG idFileSystem; File system identifier. NT server always
+ * returns 0
+ * ULONG cSectorUnit; Number of sectors per allocation unit
+ * ULONG cUnit; Total number of allocation units
+ * ULONG cUnitAvail; Total number of available allocation units
+ * USHORT cbSector; Number of bytes per sector
+ *
+ * 4.1.6.2 SMB_INFO_VOLUME
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * ULONG ulVsn; Volume serial number
+ * UCHAR cch; Number of characters in Label
+ * STRING Label; The volume label
+ *
+ * 4.1.6.3 SMB_QUERY_FS_VOLUME_INFO
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * LARGE_INTEGER Volume Creation Time
+ * ULONG Volume Serial Number
+ * ULONG Length of Volume Label in bytes
+ *
+ * BYTE Reserved
+ *
+ * BYTE Reserved
+ *
+ * STRING Label; The volume label
+ *
+ * 4.1.6.4 SMB_QUERY_FS_SIZE_INFO
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * LARGE_INTEGER Total Number of Allocation units on the Volume
+ * LARGE_INTEGER Number of free Allocation units on the Volume
+ * ULONG Number of sectors in each Allocation unit
+ *
+ * ULONG Number of bytes in each sector
+ *
+ * 4.1.6.5 SMB_QUERY_FS_DEVICE_INFO
+ *
+ * Data Block Encoding Value
+ * ==================== ===============================================
+ *
+ * ULONG DeviceType; Values as specified below
+ * ULONG Characteristics of the device; Values as
+ * specified below
+ *
+ * For DeviceType, note that the values 0-32767 are reserved for the
+ * exclusive use of Microsoft Corporation. The following device types are
+ * currently defined:
+ *
+ * FILE_DEVICE_BEEP 0x00000001
+ *
+ * FILE_DEVICE_CD_ROM 0x00000002
+ * FILE_DEVICE_CD_ROM_FILE_SYST 0x00000003
+ * EM
+ * FILE_DEVICE_CONTROLLER 0x00000004
+ * FILE_DEVICE_DATALINK 0x00000005
+ * FILE_DEVICE_DFS 0x00000006
+ * FILE_DEVICE_DISK 0x00000007
+ * FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+ * FILE_DEVICE_FILE_SYSTEM 0x00000009
+ * FILE_DEVICE_INPORT_PORT 0x0000000a
+ * FILE_DEVICE_KEYBOARD 0x0000000b
+ * FILE_DEVICE_MAILSLOT 0x0000000c
+ * FILE_DEVICE_MIDI_IN 0x0000000d
+ * FILE_DEVICE_MIDI_OUT 0x0000000e
+ * FILE_DEVICE_MOUSE 0x0000000f
+ * FILE_DEVICE_MULTI_UNC_PROVID 0x00000010
+ * ER
+ * FILE_DEVICE_NAMED_PIPE 0x00000011
+ * FILE_DEVICE_NETWORK 0x00000012
+ * FILE_DEVICE_NETWORK_BROWSER 0x00000013
+ * FILE_DEVICE_NETWORK_FILE_SYS 0x00000014
+ * TEM
+ * FILE_DEVICE_NULL 0x00000015
+ * FILE_DEVICE_PARALLEL_PORT 0x00000016
+ * FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+ * FILE_DEVICE_PRINTER 0x00000018
+ * FILE_DEVICE_SCANNER 0x00000019
+ * FILE_DEVICE_SERIAL_MOUSE_POR 0x0000001a
+ * T
+ * FILE_DEVICE_SERIAL_PORT 0x0000001b
+ * FILE_DEVICE_SCREEN 0x0000001c
+ * FILE_DEVICE_SOUND 0x0000001d
+ * FILE_DEVICE_STREAMS 0x0000001e
+ * FILE_DEVICE_TAPE 0x0000001f
+ * FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+ * FILE_DEVICE_TRANSPORT 0x00000021
+ * FILE_DEVICE_UNKNOWN 0x00000022
+ * FILE_DEVICE_VIDEO 0x00000023
+ * FILE_DEVICE_VIRTUAL_DISK 0x00000024
+ * FILE_DEVICE_WAVE_IN 0x00000025
+ * FILE_DEVICE_WAVE_OUT 0x00000026
+ * FILE_DEVICE_8042_PORT 0x00000027
+ * FILE_DEVICE_NETWORK_REDIRECT 0x00000028
+ * OR
+ * FILE_DEVICE_BATTERY 0x00000029
+ * FILE_DEVICE_BUS_EXTENDER 0x0000002a
+ * FILE_DEVICE_MODEM 0x0000002b
+ * FILE_DEVICE_VDM 0x0000002c
+ *
+ * Some of these device types are not currently accessible over the network
+ * and may never be accessible over the network. Some may change to be
+ *
+ * accessible over the network. The values for device types that may never
+ * be accessible over the network may be redefined to be just reserved at
+ * some date in the future.
+ *
+ * Characteristics is the sum of any of the following:
+ *
+ * FILE_REMOVABLE_MEDIA 0x00000001
+ * FILE_READ_ONLY_DEVICE 0x00000002
+ * FILE_FLOPPY_DISKETTE 0x00000004
+ * FILE_WRITE_ONE_MEDIA 0x00000008
+ * FILE_REMOTE_DEVICE 0x00000010
+ * FILE_DEVICE_IS_MOUNTED 0x00000020
+ * FILE_VIRTUAL_VOLUME 0x00000040
+ *
+ * 4.1.6.6 SMB_QUERY_FS_ATTRIBUTE_INFO
+ *
+ * Data Block Encoding Description
+ * =================== ================================================
+ *
+ * ULONG File System Attributes; possible values
+ * described below
+ * LONG Maximum length of each file name component in
+ * number of bytes
+ * ULONG Length, in bytes, of the name of the file system
+ *
+ * STRING Name of the file system
+ *
+ * Where FileSystemAttributes is the sum of any of the following:
+ *
+ * FILE_CASE_SENSITIVE_SEARCH 0x00000001
+ * FILE_CASE_PRESERVED_NAMES 0x00000002
+ * FILE_PRSISTENT_ACLS 0x00000004
+ * FILE_FILE_COMPRESSION 0x00000008
+ * FILE_VOLUME_QUOTAS 0x00000010
+ * FILE_DEVICE_IS_MOUNTED 0x00000020
+ * FILE_VOLUME_IS_COMPRESSED 0x00008000
+ *
+ * 4.1.6.7 Errors
+ *
+ * ERRSRV/invnid - TID was invalid
+ * ERRSRV/baduid - UID was invalid
+ * ERRHRD/ERRnotready - the file system has been removed
+ * ERRHRD/ERRdata - disk I/O error
+ * ERRSRV/ERRaccess - user does not have the right to perform this
+ * operation
+ * ERRSRV/ERRinvdevice - resource identified by TID is not a file system
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smbinfo.h>
+
+char ntfs[] = "NTFS";
+
+
+/*
+ * is_dot_or_dotdot
+ *
+ * Inline function to detect the "." and ".." entries in a directory.
+ * Returns 1 is the name is "." or "..". Otherwise returns 0.
+ */
+int
+is_dot_or_dotdot(char *name)
+{
+ if (*name != '.')
+ return (0);
+
+ if ((name[1] == 0) || (name[1] == '.' && name[2] == 0))
+ return (1);
+
+ return (0);
+}
+
+
+/*
+ * smb_com_trans2_query_fs_information
+ */
+int
+smb_com_trans2_query_fs_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ int rc;
+ uint32_t flags;
+ char *encode_str;
+ uint64_t max_int;
+ unsigned short infolev;
+ struct statvfs64 df;
+ int sect_per_unit, length;
+ uint32_t total_units, avail_units;
+ struct smb_node *snode;
+ char *fsname = "NTFS";
+ fsvol_attr_t vol_attr;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "w", &infolev) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ snode = sr->tid_tree->t_snode;
+ if (fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr) != 0) {
+ smbsr_raise_errno(sr, ESTALE);
+ /* NOTREACHED */
+ }
+
+ switch (infolev) {
+ case SMB_INFO_ALLOCATION:
+ if ((rc = smb_fsop_statfs(sr->user_cr, snode, &df)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ max_int = 0xffffffffLL;
+
+ if (df.f_blocks > max_int)
+ df.f_blocks = max_int;
+
+ if (df.f_bavail > max_int)
+ df.f_bavail = max_int;
+
+ total_units = (uint32_t)df.f_blocks;
+ avail_units = (uint32_t)df.f_bavail;
+ length = 512;
+ sect_per_unit = df.f_frsize >> 9;
+
+ if (avail_units > total_units)
+ avail_units = 0;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "llllw",
+ 0, /* file system ID. NT rets 0 */
+ sect_per_unit, /* sectors/unit */
+ total_units, /* total units */
+ avail_units, /* avail units */
+ length); /* bytes/sector */
+ break;
+
+ case SMB_INFO_VOLUME:
+ length = strlen(vol_attr.name);
+ encode_str = "%lbs";
+ /*
+ * tree_fsd.val[0] is the 32-bit dev for the file system
+ * of the share's root smb_node.
+ *
+ * Together with tree_fsd.val[1] (the file system type), it
+ * comprises a system-wide unique file system ID.
+ */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, encode_str, sr,
+ snode->tree_fsd.val[0], length, vol_attr.name);
+ break;
+
+ case SMB_QUERY_FS_VOLUME_INFO:
+ if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
+ (sr->session->native_os == NATIVE_OS_WIN95)) {
+ length = mts_wcequiv_strlen(vol_attr.name);
+ encode_str = "%qllb.U";
+ } else {
+ length = strlen(vol_attr.name); /* label length */
+ encode_str = "%qllb.s";
+ }
+
+ /*
+ * NT has the "supports objects" flag set to 1.
+ */
+
+ /*
+ * tree_fsd.val[0] is the 32-bit dev for the file system
+ * of the share's root smb_node.
+ *
+ * Together with tree_fsd.val[1] (the file system type), it
+ * comprises a system-wide unique file system ID.
+ */
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, encode_str, sr,
+ 0ll, /* Volume creation time */
+ snode->tree_fsd.val[0], /* Volume serial number */
+ length, /* label length */
+ 0, /* Supports objects */
+ vol_attr.name);
+ break;
+
+ case SMB_QUERY_FS_SIZE_INFO:
+ if ((rc = smb_fsop_statfs(sr->user_cr, snode, &df)) != 0) {
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ length = 512;
+ sect_per_unit = df.f_frsize >> 9;
+
+ if (df.f_bavail > df.f_blocks)
+ df.f_bavail = 0;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qqll",
+ df.f_blocks, /* total units */
+ df.f_bavail, /* avail units */
+ sect_per_unit, /* sectors/unit */
+ length); /* bytes/sector */
+ break;
+ case SMB_QUERY_FS_DEVICE_INFO:
+ (void) smb_encode_mbc(&xa->rep_data_mb, "ll",
+ FILE_DEVICE_FILE_SYSTEM,
+ FILE_DEVICE_IS_MOUNTED);
+ break;
+
+ case SMB_QUERY_FS_ATTRIBUTE_INFO:
+
+ if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) ||
+ (sr->session->native_os == NATIVE_OS_WINNT) ||
+ (sr->session->native_os == NATIVE_OS_WIN2000) ||
+ (sr->session->native_os == NATIVE_OS_WIN95) ||
+ (sr->session->native_os == NATIVE_OS_MACOS)) {
+ length = mts_wcequiv_strlen(fsname);
+ encode_str = "%lllU";
+ sr->smb_flg2 |= SMB_FLAGS2_UNICODE;
+ } else {
+ length = strlen(fsname);
+ encode_str = "%llls";
+ }
+
+ flags = FILE_CASE_PRESERVED_NAMES;
+ /* flags |= FILE_UNICODE_ON_DISK; */
+
+ if (vol_attr.flags & FSOLF_SUPPORTS_ACLS)
+ flags |= FILE_PERSISTENT_ACLS;
+
+ if ((vol_attr.flags & FSOLF_CASE_INSENSITIVE) == 0)
+ flags |= FILE_CASE_SENSITIVE_SEARCH;
+
+ if (vol_attr.flags & FSOLF_STREAMS)
+ flags |= FILE_NAMED_STREAMS;
+
+ if (smb_info.si.skc_announce_quota)
+ flags |= FILE_VOLUME_QUOTAS;
+
+ (void) smb_encode_mbc(&xa->rep_data_mb, encode_str, sr,
+ flags,
+ MAXNAMELEN, /* max name */
+ length, /* label length */
+ fsname);
+ break;
+
+ default:
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ break;
+ }
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
new file mode 100644
index 0000000000..1a80d6a2c4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
@@ -0,0 +1,588 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_query_path_information
+ *
+ * This request is used to get information about a specific file or
+ * subdirectory.
+ *
+ * Client Request Value
+ * ========================== =========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_QUERY_PATH_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ *
+ * USHORT InformationLevel; Level of information requested
+ * ULONG Reserved; Must be zero
+ * STRING FileName; File or directory name
+ *
+ * The following InformationLevels may be requested:
+ *
+ * Information Level Value
+ *
+ * ================================ =====
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_INFO_QUERY_EAS_FROM_LIST 3
+ * SMB_INFO_QUERY_ALL_EAS 4
+ * SMB_INFO_IS_NAME_VALID 6
+ * SMB_QUERY_FILE_BASIC_INFO 0x101
+ * SMB_QUERY_FILE_STANDARD_INFO 0x102
+ * SMB_QUERY_FILE_EA_INFO 0x103
+ * SMB_QUERY_FILE_NAME_INFO 0x104
+ * SMB_QUERY_FILE_ALL_INFO 0x107
+ * SMB_QUERY_FILE_ALT_NAME_INFO 0x108
+ * SMB_QUERY_FILE_STREAM_INFO 0x109
+ * SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+ *
+ * The requested information is placed in the Data portion of the
+ * transaction response. For the information levels greater than 0x100,
+ * the transaction response has 1 parameter word which should be ignored by
+ * the client.
+ *
+ * The following sections describe the InformationLevel dependent encoding
+ * of the data part of the transaction response.
+ *
+ * 4.2.14.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * (SMB_INFO_QUERY_EA_SIZE)
+ *
+ * 4.2.14.2 SMB_INFO_QUERY_EAS_FROM_LIST & SMB_INFO_QUERY_ALL_EAS
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * MaxDataCount Length of EAlist found (minimum value is 4)
+ *
+ * Parameter Block Description
+ * Encoding ===============================================
+ * ====================
+ *
+ * USHORT EaErrorOffset Offset into EAList of EA error
+ *
+ * Data Block Encoding Description
+ * ==================== ===============================================
+ *
+ * ULONG ListLength; Length of the remaining data
+ * UCHAR EaList[] The extended attributes list
+ *
+ * 4.2.14.3 SMB_INFO_IS_NAME_VALID
+ *
+ * This requests checks to see if the name of the file contained in the
+ * request's Data field has a valid path syntax. No parameters or data are
+ * returned on this information request. An error is returned if the syntax
+ * of the name is incorrect. Success indicates the server accepts the path
+ * syntax, but it does not ensure the file or directory actually exists.
+ *
+ * 4.2.14.4 SMB_QUERY_FILE_BASIC_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * LARGE_INTEGER CreationTime; Time when file was created
+ * LARGE_INTEGER LastAccessTime; Time of last file access
+ * LARGE_INTEGER LastWriteTime; Time of last write to the file
+ * LARGE_INTEGER ChangeTime Time when file was last changed
+ * USHORT Attributes; File Attributes
+ *
+ * 4.2.14.5 SMB_QUERY_FILE_STANDARD_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * LARGE_INTEGER AllocationSize Allocated size of the file in number
+ * of bytes
+ * LARGE_INTEGER EndofFile; Offset to the first free byte in the
+ * file
+ * ULONG NumberOfLinks Number of hard links to the file
+ * BOOLEAN DeletePending Indicates whether the file is marked
+ * for deletion
+ * BOOLEAN Directory Indicates whether the file is a
+ * directory
+ *
+ * 4.2.14.6 SMB_QUERY_FILE_EA_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * ULONG EASize Size of the file's extended
+ * attributes in number of bytes
+ *
+ * 4.2.14.7 SMB_QUERY_FILE_NAME_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * ULONG FileNameLength Length of the file name in number of
+ * bytes
+ * STRING FileName Name of the file
+ *
+ * 4.2.14.8 SMB_QUERY_FILE_ALL_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ *
+ * LARGE_INTEGER CreationTime; Time when file was created
+ * LARGE_INTEGER LastAccessTime; Time of last file access
+ * LARGE_INTEGER LastWriteTime; Time of last write to the file
+ * LARGE_INTEGER ChangeTime Time when file was last changed
+ * USHORT Attributes; File Attributes
+ * LARGE_INTEGER AllocationSize Allocated size of the file in number
+ * of bytes
+ * LARGE_INTEGER EndofFile; Offset to the first free byte in the
+ * file
+ * ULONG NumberOfLinks Number of hard links to the file
+ * BOOLEAN DeletePending Indicates whether the file is marked
+ * for deletion
+ * BOOLEAN Directory Indicates whether the file is a
+ * directory
+ * LARGE_INTEGER Index Number A file system unique identifier
+ * ULONG EASize Size of the file's extended
+ * attributes in number of bytes
+ * ULONG AccessFlags Access that a caller has to the
+ * file; Possible values and meanings
+ * are specified below
+ * LARGE_INTEGER Index Number A file system unique identifier
+ * LARGE_INTEGER CurrentByteOffset Current byte offset within the file
+ * ULONG Mode Current Open mode of the file handle
+ * to the file; possible values and
+ * meanings are detailed below
+ * ULONG AlignmentRequirement Buffer Alignment required by device;
+ * possible values detailed below
+ * ULONG FileNameLength Length of the file name in number of
+ * bytes
+ * STRING FileName Name of the file
+ *
+ * The AccessFlags specifies the access permissions a caller has to the
+ * file and can have any suitable combination of the following values:
+ *
+ * Value Meaning
+ *
+ * ILE_READ_DATA 0x00000001 Data can be read from the file
+ * ILE_WRITE_DATA 0x00000002 Data can be written to the file
+ * ILE_APPEND_DATA 0x00000004 Data can be appended to the file
+ * ILE_READ_EA 0x00000008 Extended attributes associated
+ * with the file can be read
+ * ILE_WRITE_EA 0x00000010 Extended attributes associated
+ * with the file can be written
+ * ILE_EXECUTE 0x00000020 Data can be read into memory from
+ * the file using system paging I/O
+ * ILE_READ_ATTRIBUTES 0x00000080 Attributes associated with the
+ * file can be read
+ * ILE_WRITE_ATTRIBUTES 0x00000100 Attributes associated with the
+ * file can be written
+ * ELETE 0x00010000 The file can be deleted
+ * EAD_CONTROL 0x00020000 The access control list and
+ * ownership associated with the
+ * file can be read
+ * RITE_DAC 0x00040000 The access control list and
+ * ownership associated with the
+ * file can be written.
+ * RITE_OWNER 0x00080000 Ownership information associated
+ * with the file can be written
+ * YNCHRONIZE 0x00100000 The file handle can waited on to
+ * synchronize with the completion
+ * of an input/output request
+ *
+ * The Mode field specifies the mode in which the file is currently opened.
+ * The possible values may be a suitable and logical combination of the
+ * following:
+ *
+ * Value Meaning
+ *
+ * FILE_WRITE_THROUGH 0x00000002 File is opened in mode
+ * where data is written to
+ * file before the driver
+ * completes a write request
+ * FILE_SEQUENTIAL_ONLY 0x00000004 All access to the file is
+ * sequential
+ * FILE_SYNCHRONOUS_IO_ALERT 0x00000010 All operations on the
+ * file are performed
+ * synchronously
+ * FILE_SYNCHRONOUS_IO_NONALER 0x00000020 All operations on the
+ * T file are to be performed
+ * synchronously. Waits in
+ * the system to synchronize
+ * I/O queuing and
+ * completion are not
+ * subject to alerts.
+ *
+ * The AlignmentRequirement field specifies buffer alignment required by
+ * the device and can have any one of the following values:
+ *
+ * Value Meaning
+ *
+ * FILE_BYTE_ALIGNMENT 0x00000000 The buffer needs to be aligned
+ * on a byte boundary
+ * FILE_WORD_ALIGNMENT 0x00000001 The buffer needs to be aligned
+ * on a word boundary
+ * FILE_LONG_ALIGNMENT 0x00000003 The buffer needs to be aligned
+ * on a 4 byte boundary
+ * FILE_QUAD_ALIGNMENT 0x00000007 The buffer needs to be aligned
+ * on an 8 byte boundary
+ * FILE_OCTA_ALIGNMENT 0x0000000f The buffer needs to be aligned
+ * on a 16 byte boundary
+ * FILE_32_BYTE_ALIGNMENT 0x0000001f The buffer needs to be aligned
+ * on a 32 byte boundary
+ * FILE_64_BYTE_ALIGNMENT 0x0000003f The buffer needs to be aligned
+ * on a 64 byte boundary
+ * FILE_128_BYTE_ALIGNMENT 0x0000007f The buffer needs to be aligned
+ * on a 128 byte boundary
+ * FILE_256_BYTE_ALIGNMENT 0x000000ff The buffer needs to be aligned
+ * on a 256 byte boundary
+ * FILE_512_BYTE_ALIGNMENT 0x000001ff The buffer needs to be aligned
+ * on a 512 byte boundary
+ *
+ * 4.2.14.9 SMB_QUERY_FILE_ALT_NAME_INFO
+ *
+ * Data Block Encoding Description
+ * ===================== =================================
+ * ULONG FileNameLength Length of the file name in number of bytes
+ * STRING FileName Name of the file
+ *
+ * 4.2.14.10 SMB_QUERY_FILE_STREAM_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ * ULONG NextEntryOffset Offset to the next entry (in bytes)
+ * ULONG StreamNameLength Length of the stream name in # of bytes
+ * LARGE_INTEGER StreamSize Size of the stream in number of bytes
+ * LARGE_INTEGER AllocationSize Allocated size of stream in bytes
+ * STRING FileName Name of the stream
+ *
+ * 4.2.14.11 SMB_QUERY_FILE_COMPRESSION_INFO
+ *
+ * Data Block Encoding Description
+ * =============================== ====================================
+ * LARGE_INTEGER Size of the compressed file in
+ * CompressedFileSize number of bytes
+ * USHORT CompressionFormat compression algorithm used
+ * UCHAR CompressionUnitShift Size of the stream in number of bytes
+ * UCHAR ChunkShift Allocated size of the stream in # of bytes
+ * UCHAR ClusterShift Allocated size of the stream in # of bytes
+ * UCHAR Reserved[3] Name of the stream
+ *
+ * typedef struct {
+ * LARGE_INTEGER CompressedFileSize;
+ * USHORT CompressionFormat;
+ * UCHAR CompressionUnitShift;
+ * UCHAR ChunkShift;
+ * UCHAR ClusterShift;
+ * UCHAR Reserved[3];
+ * } FILE_COMPRESSION_INFORMATION;
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/msgbuf.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * Function: int smb_com_trans2_query_path_information(struct smb_request *)
+ */
+int
+smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ char *path, *alt_nm_ptr;
+ int rc;
+ off_t dsize, dused;
+ unsigned short infolev, dattr;
+ smb_attr_t *ap, ret_attr;
+ struct smb_node *dir_node;
+ struct smb_node *node;
+ char *name;
+ char *short_name;
+ char *name83;
+ unsigned char is_dir;
+ int len;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ short_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ name83 = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%w4.u", sr,
+ &infolev, &path) != 0) {
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Some MS clients pass NULL file names
+ * NT interprets this as "\"
+ */
+ if ((len = strlen(path)) == 0)
+ path = "\\";
+ else {
+ if ((len > 1) && (path[len - 1] == '\\')) {
+ /*
+ * Remove the terminating slash to prevent
+ * sending back '.' instead of path name.
+ */
+ path[len - 1] = 0;
+ }
+ }
+
+ ap = &ret_attr;
+ if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
+ != 0) {
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, name, &node, ap, short_name,
+ name83)) != 0) {
+ smb_node_release(dir_node);
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ smb_node_release(dir_node);
+ (void) strcpy(name, node->od_name);
+
+ dattr = smb_node_get_dosattr(node);
+ if (ap->sa_vattr.va_type == VDIR) {
+ is_dir = 1;
+ /*
+ * Win2K and NT reply with the size of directory
+ * file.
+ */
+ dsize = dused = 0;
+ } else {
+ is_dir = 0;
+ dsize = ap->sa_vattr.va_size;
+ dused = ap->sa_vattr.va_blksize * ap->sa_vattr.va_nblocks;
+ }
+
+ switch (infolev) {
+ case SMB_INFO_STANDARD:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllw" : "yyyllw"),
+ smb_gmt_to_local_time(ap->sa_crtime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ if (dsize > 0xffffffff)
+ dsize = 0xffffffff;
+ if (dused > 0xffffffff)
+ dused = 0xffffffff;
+
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95)
+ ? "YYYllwl" : "yyyllwl"),
+ smb_gmt_to_local_time(ap->sa_crtime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_atime.tv_sec),
+ smb_gmt_to_local_time(ap->sa_vattr.va_mtime.tv_sec),
+ (uint32_t)dsize,
+ (uint32_t)dused,
+ dattr, 0);
+ break;
+
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ case SMB_INFO_QUERY_ALL_EAS:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_INFO_IS_NAME_VALID:
+ break;
+
+ case SMB_QUERY_FILE_BASIC_INFO:
+ /*
+ * NT includes 6 undocumented bytes at the end of this
+ * response, which are required by NetBench 5.01.
+ * Similar change in smb_trans2_query_file_information.c.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.",
+ &ap->sa_crtime,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr);
+ break;
+
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ /*
+ * Add 2 bytes to pad data to long. It is
+ * necessary because Win2k expects the padded bytes.
+ */
+ (void) smb_encode_mbc(&xa->rep_data_mb, "qqlbb2.",
+ dused,
+ dsize,
+ ap->sa_vattr.va_nlink,
+ (node && (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0),
+ (char)(ap->sa_vattr.va_type == VDIR));
+ break;
+
+ case SMB_QUERY_FILE_EA_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ /*
+ * If you have problems here, see the changes
+ * in smb_trans2_query_file_information.c.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, name), name);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ /*
+ * The reply of this information level on the
+ * wire doesn't match with protocol specification.
+ * This is what spec. needs: "TTTTwqqlbbqllqqll"
+ * But this is actually is sent on the wire:
+ * "TTTTw6.qqlbb2.l"
+ * So, there is a 6-byte pad between Attributes and
+ * AllocationSize. Also there is a 2-byte pad After
+ * Directory field. Between Directory and FileNameLength
+ * there is just 4 bytes that it seems is AlignmentRequirement.
+ * There are 6 other fields between Directory and
+ * AlignmentRequirement in spec. that aren't sent
+ * on the wire.
+ */
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
+ &ap->sa_crtime,
+ &ap->sa_vattr.va_atime,
+ &ap->sa_vattr.va_mtime,
+ &ap->sa_vattr.va_ctime,
+ dattr,
+ dused,
+ dsize,
+ ap->sa_vattr.va_nlink,
+ 0,
+ is_dir,
+ 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, name), name);
+ break;
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ /*
+ * Conform to the rule used by Windows NT/2003 servers.
+ * Shortname is created only if either the filename or
+ * extension portion of a file is made up of mixed case.
+ *
+ * If the shortname is generated, it will be returned as
+ * the alternative name. Otherwise, converts the original
+ * name to all upper-case and returns it as the alternative
+ * name. This is how Windows NT/2003 servers behave. However,
+ * Windows 2000 seems to preserve the case of the original
+ * name, and returns it as the alternative name.
+ *
+ * Note: The shortname is returned by smb_fsop_lookup(), above.
+ * In the case that the name used by the client was originally
+ * generated in response to a case-insensitive collision, the
+ * short_name and the 8.3 name will reflect this.
+ */
+ alt_nm_ptr = ((*short_name == 0) ?
+ utf8_strupr(name) : short_name);
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb, "%lu", sr,
+ smb_ascii_or_unicode_strlen(sr, alt_nm_ptr), alt_nm_ptr);
+ break;
+
+ case SMB_QUERY_FILE_STREAM_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ smb_encode_stream_info(sr, xa, node, ap);
+ break;
+
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ (void) smb_encode_mbc(&xa->rep_param_mb, "w", 0);
+ (void) smb_encode_mbc(&xa->rep_data_mb,
+ "qwbbb3.", dsize, 0, 0, 0, 0);
+ break;
+
+ default:
+ smb_node_release(node);
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ smbsr_raise_error(sr, ERRDOS, ERRunknownlevel);
+ /* NOTREACHED */
+ break;
+ }
+ smb_node_release(node);
+ kmem_free(name, MAXNAMELEN);
+ kmem_free(short_name, MAXNAMELEN);
+ kmem_free(name83, MAXNAMELEN);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
new file mode 100644
index 0000000000..094032da1c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
@@ -0,0 +1,163 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_set_file_information
+ *
+ * This request is used to set information about a specific file or
+ * subdirectory given a handle to the file or subdirectory.
+ *
+ * Client Request Value
+ * ========================== ==========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_SET_FILE_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== ==========================================
+ *
+ * USHORT Fid; Handle of file for request
+ * USHORT InformationLevel; Level of information requested
+ * USHORT Reserved; Ignored by the server
+ *
+ * The following InformationLevels may be set:
+ *
+ * Information Level Value
+ * ================================ =====
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_SET_FILE_BASIC_INFO 0x101
+ * SMB_SET_FILE_DISPOSITION_INFO 0x102
+ * SMB_SET_FILE_ALLOCATION_INFO 0x103
+ * SMB_SET_FILE_END_OF_FILE_INFO 0x104
+ *
+ * The two levels below 0x101 are as described in the
+ * NT_SET_PATH_INFORMATION transaction. The requested information is
+ * placed in the Data portion of the transaction response. For the
+ * information levels greater than 0x100, the transaction response has 1
+ * parameter word which should be ignored by the client.
+ *
+ * 4.2.17.1 SMB_FILE_DISPOSITION_INFO
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * BOOLEAN A boolean which is TRUE if the file is marked
+ * FileIsDeleted for deletion
+ *
+ * 4.2.17.2 SMB_FILE_ALLOCATION_INFO
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * LARGE_INTEGER File Allocation size in number of bytes
+ *
+ * 4.2.17.3 SMB_FILE_END_OF_FILE_INFO
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * LARGE_INTEGER The total number of bytes that need to be
+ * traversed from the beginning of the file in
+ * order to locate the end of the file
+ *
+ * Undocumented things:
+ * Poorly documented information levels. Information must be infered
+ * from other commands.
+ *
+ * NULL Attributes means don't set them. NT sets the high bit to
+ * set attributes to 0.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * smb_com_trans2_set_file_information
+ */
+int
+smb_com_trans2_set_file_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_trans2_setinfo_t *info;
+ smb_error_t smberr;
+ DWORD status;
+ int rc;
+
+ info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
+ info->ts_xa = xa;
+
+ rc = smb_decode_mbc(&xa->req_param_mb, "ww", &sr->smb_fid,
+ &info->level);
+ if (rc != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
+ SMB_TREE_IS_READ_ONLY(sr)) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ info->node = sr->fid_ofile->f_node;
+
+ if (info->node == 0 ||
+ !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+ cmn_err(CE_NOTE, "SmbT2SetFileInfo: access denied");
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ status = smb_trans2_set_information(sr, info, &smberr);
+ if (status == NT_STATUS_DATA_ERROR) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ } else if (status == NT_STATUS_UNSUCCESSFUL) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, smberr.status,
+ smberr.errcls, smberr.errcode);
+ /* NOTREACHED */
+ }
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
new file mode 100644
index 0000000000..b41e1c426d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
@@ -0,0 +1,414 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains the common code used by
+ * Trans2SetFileInfo and Trans2SetPathInfo SMBs.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static DWORD smb_set_standard_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static DWORD smb_set_basic_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static DWORD smb_set_disposition_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static DWORD smb_set_alloc_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_info(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_addappl(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_rmvappl(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+/*LINTED E_STATIC_UNUSED*/
+static DWORD smb_set_mac_addicon(struct smb_request *sr,
+ smb_trans2_setinfo_t *info, smb_error_t *smberr);
+
+static unsigned short smb_info_passthru(unsigned short infolevel);
+
+/*
+ * smb_trans2_set_information
+ *
+ * This is a common function called by both Trans2SetFileInfo
+ * and Trans2SetPathInfo.
+ */
+DWORD
+smb_trans2_set_information(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ info->level = smb_info_passthru(info->level);
+
+ switch (info->level) {
+ case SMB_INFO_STANDARD:
+ case SMB_INFO_QUERY_EA_SIZE:
+ return (smb_set_standard_info(sr, info, smberr));
+
+ case SMB_INFO_QUERY_ALL_EAS:
+ /* This info level is not supported */
+ return (NT_STATUS_SUCCESS);
+
+ case SMB_SET_FILE_BASIC_INFO:
+ return (smb_set_basic_info(sr, info, smberr));
+
+ case SMB_SET_FILE_DISPOSITION_INFO:
+ return (smb_set_disposition_info(sr, info, smberr));
+
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ return (smb_set_alloc_info(sr, info, smberr));
+
+ default:
+ smberr->status = NT_STATUS_INVALID_INFO_CLASS;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_INVALID_PARAMETER;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * smb_info_passthru
+ *
+ * SMB_INFO_PASSTHROUGH
+ * If the server supports information level request passing through,
+ * the client may add the information level with SMB_INFO_PASSTHROUGH
+ * and submit the file information in NT data format instead of SMB
+ * data format. Please refer to MSDN for related NT file information
+ * data structure.
+ *
+ * SMB_INFO_PASSTHROUGH (1000) is defined in win32/cifs.h and the file
+ * information class values are defined in win32/ntifs.h. we have
+ * observed:
+ * 0x3EC = SMB_INFO_PASSTHROUGH + FileBasicInformation (4)
+ * 0x3F5 = SMB_INFO_PASSTHROUGH + FileDispositionInformation (13)
+ * 0x3FC = SMB_INFO_PASSTHROUGH + FileEndOfFileInformation (20)
+ *
+ * Based on network traces between two Win2K systems:
+ * FileBasicInformation <=> SMB_SET_FILE_BASIC_INFO
+ * FileDispositionInformation <=> SMB_SET_FILE_DISPOSITION_INFO
+ * FileEndOfFileInformation <=> SMB_SET_FILE_END_OF_FILE_INFO
+ */
+static unsigned short
+smb_info_passthru(unsigned short infolevel)
+{
+ if (infolevel <= SMB_INFO_PASSTHROUGH)
+ return (infolevel);
+
+ infolevel -= SMB_INFO_PASSTHROUGH;
+
+ switch (infolevel) {
+ case FileBasicInformation:
+ return (SMB_SET_FILE_BASIC_INFO);
+
+ case FileDispositionInformation:
+ return (SMB_SET_FILE_DISPOSITION_INFO);
+
+ case FileEndOfFileInformation:
+ return (SMB_SET_FILE_END_OF_FILE_INFO);
+ }
+
+ return (infolevel);
+}
+
+/*
+ * smb_set_standard_info
+ *
+ * SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
+ *
+ * Data Block Encoding Description
+ * ================================== =================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation
+ * unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * (SMB_INFO_QUERY_EA_SIZE)
+ */
+static DWORD
+smb_set_standard_info(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ uint32_t Creation, LastAccess, LastWrite; /* times */
+ uint32_t DataSize, AllocationSize;
+ unsigned short Attributes;
+ unsigned int what = 0;
+ timestruc_t crtime, mtime, atime;
+ DWORD status = NT_STATUS_SUCCESS;
+ struct smb_node *node = info->node;
+ int rc;
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "yyyllw",
+ &Creation, /* CreationDate/Time */
+ &LastAccess, /* LastAccessDate/Time */
+ &LastWrite, /* LastWriteDate/Time */
+ &DataSize, /* File Size */
+ &AllocationSize, /* Block Size */
+ &Attributes) != 0) { /* File Attributes */
+ return (NT_STATUS_DATA_ERROR);
+ }
+
+ if (DataSize != 0) {
+ node->flags |= NODE_FLAGS_SET_SIZE;
+ node->n_size = DataSize;
+ }
+
+ /*
+ * IR101794 The behaviour when the time field is set to -1
+ * is not documented, so we'll assume it should be treated
+ * like 0.
+ */
+ crtime.tv_nsec = mtime.tv_nsec = atime.tv_nsec = 0;
+ if (LastWrite != 0 && LastWrite != (uint32_t)-1) {
+ mtime.tv_sec = smb_local_time_to_gmt(LastWrite);
+ node->set_mtime = mtime;
+ what |= SMB_AT_MTIME;
+ }
+
+ if (Creation != 0 && Creation != (uint32_t)-1) {
+ crtime.tv_sec = smb_local_time_to_gmt(Creation);
+ what |= SMB_AT_CRTIME;
+ }
+
+ if (LastAccess != 0 && LastAccess != (uint32_t)-1) {
+ atime.tv_sec = smb_local_time_to_gmt(LastAccess);
+ what |= SMB_AT_ATIME;
+ }
+
+ if (Attributes != 0)
+ smb_node_set_dosattr(node, Attributes);
+
+ smb_node_set_time(node, &crtime, &mtime, &atime, 0, what);
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ if (rc) {
+ smb_errmap_unix2smb(rc, smberr);
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return (status);
+}
+
+/*
+ * smb_set_basic_info
+ *
+ * Sets basic file/path information.
+ */
+static DWORD
+smb_set_basic_info(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ uint64_t NT_Creation, NT_LastAccess, NT_LastWrite, NT_Change;
+ unsigned short Attributes;
+ unsigned int what = 0;
+ timestruc_t crtime, mtime, atime, ctime;
+ struct smb_node *node = info->node;
+ DWORD status = NT_STATUS_SUCCESS;
+ int rc;
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "qqqqw",
+ &NT_Creation, /* CreationDate/Time */
+ &NT_LastAccess, /* LastAccessDate/Time */
+ &NT_LastWrite, /* LastWriteDate/Time */
+ &NT_Change, /* LastWriteDate/Time */
+ &Attributes) != 0) { /* File Attributes */
+ return (NT_STATUS_DATA_ERROR);
+ }
+
+ /*
+ * IR101794 The behaviour when the time field is set to -1
+ * is not documented, so we'll assume it should be treated
+ * like 0.
+ */
+ if (NT_Change != 0 && NT_Change != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_Change, &ctime);
+ what |= SMB_AT_CTIME;
+ }
+
+ if (NT_Creation != 0 && NT_Creation != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_Creation, &crtime);
+ what |= SMB_AT_CRTIME;
+ }
+
+ if (NT_LastWrite != 0 && NT_LastWrite != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_LastWrite, &mtime);
+ node->set_mtime = mtime;
+ what |= SMB_AT_MTIME;
+ }
+
+ if (NT_LastAccess != 0 && NT_LastAccess != (uint64_t)-1) {
+ (void) nt_to_unix_time(NT_LastAccess, &atime);
+ what |= SMB_AT_ATIME;
+ }
+
+ if (Attributes != 0)
+ smb_node_set_dosattr(node, Attributes);
+
+ smb_node_set_time(node, &crtime, &mtime, &atime, &ctime, what);
+ rc = smb_sync_fsattr(sr, sr->user_cr, node);
+ if (rc) {
+ smb_errmap_unix2smb(rc, smberr);
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return (status);
+}
+
+
+/*
+ * smb_set_alloc_info
+ *
+ * Sets file allocation/end_of_file info
+ */
+static DWORD
+smb_set_alloc_info(
+ struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ uint64_t DataSize;
+ DWORD status = NT_STATUS_SUCCESS;
+ struct smb_node *node = info->node;
+ int rc;
+
+ if (sr->fid_ofile == NULL) {
+ smberr->status = NT_STATUS_ACCESS_DENIED;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "q", &DataSize) != 0)
+ return (NT_STATUS_DATA_ERROR);
+
+ if (node->attr.sa_vattr.va_size != DataSize) {
+ node->flags |= NODE_FLAGS_SET_SIZE;
+ node->n_size = (off_t)DataSize;
+
+ /*
+ * Ensure that the FS is consistent with the node cache
+ * because the size flag can get cleared by subsequent
+ * write requests without the inode ever being updated.
+ */
+ if ((rc = smb_set_file_size(sr)) != 0) {
+ smb_errmap_unix2smb(rc, smberr);
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * smb_set_disposition_info
+ *
+ * Set/Clear DELETE_ON_CLOSE flag for an open file.
+ * File should have been opened with DELETE access otherwise
+ * the operation is not permitted.
+ *
+ * NOTE: The node should be marked delete-on-close upon the receipt
+ * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
+ * It is different than both SmbNtCreateAndX and SmbNtTransact, which
+ * set delete-on-close on the ofile and defer setting the flag on the
+ * node until the file is closed.
+ *
+ * Observation of Windows 2000 indicates the following:
+ *
+ * 1) If a file is not opened with delete-on-close create options and
+ * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
+ * using that open file handle, any subsequent open requests will fail
+ * with DELETE_PENDING.
+ *
+ * 2) If a file is opened with delete-on-close create options and the
+ * client attempts to unset delete-on-close via Trans2SetFileInfo
+ * (SetDispositionInfo) prior to the file close, any subsequent open
+ * requests will still fail with DELETE_PENDING after the file is closed.
+ *
+ * 3) If a file is opened with delete-on-close create options and that
+ * file handle (not the last open handle and the only file handle
+ * with delete-on-close set) is closed. Any subsequent open requests
+ * will fail with DELETE_PENDING. Unsetting delete-on-close via
+ * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
+ * node delete-on-close flag, which will result in the file not being
+ * removed even after the last file handle is closed.
+ */
+static DWORD
+smb_set_disposition_info(
+ smb_request_t *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr)
+{
+ unsigned char mark_delete;
+
+ if (smb_decode_mbc(&info->ts_xa->req_data_mb, "b", &mark_delete) != 0)
+ return (NT_STATUS_DATA_ERROR);
+
+ if ((sr->fid_ofile == NULL) ||
+ !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
+ smberr->status = NT_STATUS_ACCESS_DENIED;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+
+ if (mark_delete) {
+ if (smb_node_set_delete_on_close(info->node,
+ sr->user_cr)) {
+ smberr->status = NT_STATUS_CANNOT_DELETE;
+ smberr->errcls = ERRDOS;
+ smberr->errcode = ERROR_ACCESS_DENIED;
+ return (NT_STATUS_UNSUCCESSFUL);
+ }
+ } else {
+ smb_node_reset_delete_on_close(info->node);
+ }
+ return (NT_STATUS_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
new file mode 100644
index 0000000000..02be8c53cb
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
@@ -0,0 +1,179 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: trans2_set_path_information
+ *
+ * This request is used to set information about a specific file or
+ * subdirectory.
+ *
+ * Client Request Value
+ * ========================== =========================================
+ *
+ * WordCount 15
+ * MaxSetupCount 0
+ * SetupCount 1
+ * Setup[0] TRANS2_SET_PATH_INFORMATION
+ *
+ * Parameter Block Encoding Description
+ * ========================== =========================================
+ *
+ * USHORT InformationLevel; Level of information to set
+ * ULONG Reserved; Must be zero
+ * STRING FileName; File or directory name
+ *
+ * The following InformationLevels may be set:
+ *
+ * Information Level Value
+ * ========================== =========================================
+ *
+ * SMB_INFO_STANDARD 1
+ * SMB_INFO_QUERY_EA_SIZE 2
+ * SMB_INFO_QUERY_ALL_EAS 4
+ *
+ * The response formats are:
+ *
+ * 4.2.16.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
+ *
+ * Parameter Block Encoding Description
+ * ================================== =================================
+ *
+ * USHORT Reserved 0
+ *
+ * Data Block Encoding Description
+ * ================================== =================================
+ *
+ * SMB_DATE CreationDate; Date when file was created
+ * SMB_TIME CreationTime; Time when file was created
+ * SMB_DATE LastAccessDate; Date of last file access
+ * SMB_TIME LastAccessTime; Time of last file access
+ * SMB_DATE LastWriteDate; Date of last write to the file
+ * SMB_TIME LastWriteTime; Time of last write to the file
+ * ULONG DataSize; File Size
+ * ULONG AllocationSize; Size of filesystem allocation
+ * unit
+ * USHORT Attributes; File Attributes
+ * ULONG EaSize; Size of file's EA information
+ * (SMB_INFO_QUERY_EA_SIZE)
+ *
+ * 4.2.16.2 SMB_INFO_QUERY_ALL_EAS
+ *
+ * Response Field Value
+ * ==================== ===============================================
+ *
+ * MaxDataCount Length of FEAlist found (minimum value is 4)
+ *
+ * Parameter Block Description
+ * Encoding ===============================================
+ * ====================
+ *
+ * USHORT EaErrorOffset Offset into EAList of EA error
+ *
+ * Data Block Encoding Description
+ * ==================== ===============================================
+ *
+ * ULONG ListLength; Length of the remaining data
+ * UCHAR EaList[] The extended attributes list
+ *
+ * Undocumented things:
+ * Poorly documented information levels. Information must be infered
+ * from other commands.
+ *
+ * NULL Attributes means don't set them. NT sets the high bit to
+ * set attributes to 0.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+int
+smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ smb_trans2_setinfo_t *info;
+ smb_attr_t ret_attr;
+ struct smb_node *dir_node;
+ struct smb_node *ret_snode;
+ smb_error_t smberr;
+ DWORD status;
+ int rc = 0;
+
+ info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
+ info->ts_xa = xa;
+
+ if (smb_decode_mbc(&xa->req_param_mb, "%w4.u", sr, &info->level,
+ &info->path) != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
+ SMB_TREE_IS_READ_ONLY(sr)) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ rc = smb_pathname_reduce(sr, sr->user_cr, info->path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode,
+ &dir_node, info->name);
+
+ if (rc != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dir_node, info->name, &ret_snode, &ret_attr,
+ 0, 0);
+
+ smb_node_release(dir_node);
+
+ if (rc != 0) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_errno(sr, rc);
+ }
+
+ info->node = ret_snode;
+ status = smb_trans2_set_information(sr, info, &smberr);
+ info->node = NULL;
+ smb_node_release(ret_snode);
+ if (status == NT_STATUS_DATA_ERROR) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ } else if (status == NT_STATUS_UNSUCCESSFUL) {
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ smbsr_raise_cifs_error(sr, smberr.status,
+ smberr.errcls, smberr.errcode);
+ /* NOTREACHED */
+ }
+ kmem_free(info, sizeof (smb_trans2_setinfo_t));
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
new file mode 100644
index 0000000000..85d663c88c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -0,0 +1,733 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * Tree State Machine
+ * ------------------
+ *
+ * +-----------------------------+ T0
+ * | SMB_TREE_STATE_CONNECTED |<----------- Creation/Allocation
+ * +-----------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +------------------------------+
+ * | SMB_TREE_STATE_DISCONNECTING |
+ * +------------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-----------------------------+ T3
+ * | SMB_TREE_STATE_DISCONNECTED |----------> Deletion/Free
+ * +-----------------------------+
+ *
+ * SMB_TREE_STATE_CONNECTED
+ *
+ * While in this state:
+ * - The tree is queued in the list of trees of its user.
+ * - References will be given out if the tree is looked up.
+ * - Files under that tree can be accessed.
+ *
+ * SMB_TREE_STATE_DISCONNECTING
+ *
+ * While in this state:
+ * - The tree is queued in the list of trees of its user.
+ * - References will not be given out if the tree is looked up.
+ * - The files and directories open under the tree are being closed.
+ * - The resources associated with the tree remain.
+ *
+ * SMB_TREE_STATE_DISCONNECTED
+ *
+ * While in this state:
+ * - The tree is queued in the list of trees of its user.
+ * - References will not be given out if the tree is looked up.
+ * - The tree has no more files and directories opened.
+ * - The resources associated with the tree remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_tree_connect(). A new tree is created and
+ * added to the list of trees of a user.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_tree_disconnect().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_tree_release(). The resources associated
+ * with the tree are freed as well as the tree structure. For the transition
+ * to occur, the tree must be in the SMB_TREE_STATE_DISCONNECTED state and
+ * the reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the tree structures is controlled by 3 elements:
+ * - The list of trees of the user it belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the tree structure used to protect its fields
+ * and there's a lock embedded in the list of trees of a user. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the tree into the list of trees of the user and to remove
+ * the tree from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a tree structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the user
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to a tree require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the tree
+ * is connected. The other when the user is looked up. This translates
+ * into 2 functions: smb_tree_connect() and smb_tree_lookup_by_tid().
+ *
+ * It should be noted that the reference count of a tree registers the
+ * number of references to the tree in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The tree is connected. An tree is anchored by his state. If there's
+ * no activity involving a tree currently connected, the reference
+ * count of that tree is zero.
+ *
+ * 2) The tree is queued in the list of trees of the user. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/* Static functions defined further down this file. */
+static void smb_tree_delete(smb_tree_t *);
+static smb_tree_t *smb_tree_lookup_head(smb_llist_t *);
+static smb_tree_t *smb_tree_lookup_next(smb_llist_t *, smb_tree_t *);
+
+/*
+ * smb_tree_connect
+ */
+smb_tree_t *
+smb_tree_connect(
+ smb_user_t *user,
+ uint16_t access_flags,
+ char *sharename,
+ char *resource,
+ int32_t stype,
+ smb_node_t *snode,
+ fsvol_attr_t *vol_attr)
+{
+ smb_tree_t *tree;
+ uint16_t tid;
+
+ if (smb_idpool_alloc(&user->u_tid_pool, &tid)) {
+ return (NULL);
+ }
+
+ tree = kmem_cache_alloc(smb_info.si_cache_tree, KM_SLEEP);
+ bzero(tree, sizeof (smb_tree_t));
+
+ if (smb_idpool_constructor(&tree->t_fid_pool)) {
+ smb_idpool_free(&user->u_tid_pool, tid);
+ kmem_cache_free(smb_info.si_cache_tree, tree);
+ return (NULL);
+ }
+
+ if (smb_idpool_constructor(&tree->t_sid_pool)) {
+ smb_idpool_destructor(&tree->t_fid_pool);
+ smb_idpool_free(&user->u_tid_pool, tid);
+ kmem_cache_free(smb_info.si_cache_tree, tree);
+ return (NULL);
+ }
+
+ smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
+ offsetof(smb_ofile_t, f_lnd));
+
+ smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
+ offsetof(smb_odir_t, d_lnd));
+
+ (void) strlcpy(tree->t_sharename, sharename,
+ sizeof (tree->t_sharename));
+ (void) strlcpy(tree->t_resource, resource, sizeof (tree->t_resource));
+
+ mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);
+
+ tree->t_user = user;
+ tree->t_session = user->u_session;
+ tree->t_refcnt = 1;
+ tree->t_tid = tid;
+ tree->t_access = access_flags;
+ tree->t_res_type = stype;
+ tree->t_snode = snode;
+ tree->t_state = SMB_TREE_STATE_CONNECTED;
+ tree->t_magic = SMB_TREE_MAGIC;
+
+ switch (stype & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ tree->t_fsd = snode->tree_fsd;
+
+ (void) strlcpy(tree->t_typename, vol_attr->fs_typename,
+ SMB_TREE_TYPENAME_SZ);
+ (void) utf8_strupr((char *)tree->t_typename);
+
+ if (vol_attr->flags & FSOLF_READONLY)
+ tree->t_access = SMB_TREE_READ_ONLY;
+
+ tree->t_acltype = smb_fsop_acltype(snode);
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACLONCREATE)) {
+ tree->t_flags |= SMB_TREE_FLAG_ACLONCREATE;
+ }
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) {
+ tree->t_flags |= SMB_TREE_FLAG_ACEMASKONACCESS;
+ }
+
+ if (vfs_has_feature(snode->vp->v_vfsp, VFSFT_CASEINSENSITIVE)) {
+ tree->t_flags |= SMB_TREE_FLAG_IGNORE_CASE;
+ }
+ break;
+
+ case STYPE_IPC:
+ default:
+ tree->t_typename[0] = '\0';
+ break;
+ }
+
+ smb_llist_enter(&user->u_tree_list, RW_WRITER);
+ smb_llist_insert_head(&user->u_tree_list, tree);
+ smb_llist_exit(&user->u_tree_list);
+ atomic_inc_32(&user->u_session->s_tree_cnt);
+ atomic_inc_32(&smb_info.open_trees);
+
+ return (tree);
+}
+
+/*
+ * smb_tree_disconnect
+ *
+ *
+ */
+void
+smb_tree_disconnect(
+ smb_tree_t *tree)
+{
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ mutex_enter(&tree->t_mutex);
+ ASSERT(tree->t_refcnt);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED: {
+ /*
+ * The tree is moved into a state indicating that the disconnect
+ * process has started.
+ */
+ tree->t_state = SMB_TREE_STATE_DISCONNECTING;
+ mutex_exit(&tree->t_mutex);
+ atomic_dec_32(&smb_info.open_trees);
+ /*
+ * The files opened under this tree are closed.
+ */
+ smb_ofile_close_all(tree);
+ /*
+ * The directories opened under this tree are closed.
+ */
+ smb_odir_close_all(tree);
+ mutex_enter(&tree->t_mutex);
+ tree->t_state = SMB_TREE_STATE_DISCONNECTED;
+ /*FALLTHRU*/
+ }
+ case SMB_TREE_STATE_DISCONNECTED:
+ case SMB_TREE_STATE_DISCONNECTING:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&tree->t_mutex);
+}
+
+/*
+ * smb_tree_disconnect_all
+ *
+ *
+ */
+void
+smb_tree_disconnect_all(
+ smb_user_t *user)
+{
+ smb_tree_t *tree;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ tree = smb_tree_lookup_head(&user->u_tree_list);
+ while (tree) {
+ ASSERT(tree->t_user == user);
+ smb_tree_disconnect(tree);
+ smb_tree_release(tree);
+ tree = smb_tree_lookup_head(&user->u_tree_list);
+ }
+}
+
+/*
+ * smb_tree_close_all_by_pid
+ *
+ *
+ */
+void
+smb_tree_close_all_by_pid(
+ smb_user_t *user,
+ uint16_t pid)
+{
+ smb_tree_t *tree;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ tree = smb_tree_lookup_head(&user->u_tree_list);
+ while (tree) {
+ smb_tree_t *next;
+ ASSERT(tree->t_user == user);
+ smb_ofile_close_all_by_pid(tree, pid);
+ smb_odir_close_all_by_pid(tree, pid);
+ next = smb_tree_lookup_next(&user->u_tree_list, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+/*
+ * smb_tree_release
+ *
+ *
+ */
+void
+smb_tree_release(
+ smb_tree_t *tree)
+{
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ mutex_enter(&tree->t_mutex);
+ ASSERT(tree->t_refcnt);
+ tree->t_refcnt--;
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_DISCONNECTED:
+ if (tree->t_refcnt == 0) {
+ mutex_exit(&tree->t_mutex);
+ smb_tree_delete(tree);
+ return;
+ }
+ break;
+
+ case SMB_TREE_STATE_CONNECTED:
+ case SMB_TREE_STATE_DISCONNECTING:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&tree->t_mutex);
+}
+
+/*
+ * Find the appropriate tree for this request. The request credentials
+ * set here override those set during uid lookup. In domain mode, the
+ * user and tree credentials should be the same. In share mode, the
+ * tree credentials (defined in the share definition) should override
+ * the user credentials.
+ */
+smb_tree_t *
+smb_tree_lookup_by_tid(
+ smb_user_t *user,
+ uint16_t tid)
+{
+ smb_tree_t *tree;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ smb_llist_enter(&user->u_tree_list, RW_READER);
+ tree = smb_llist_head(&user->u_tree_list);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ if (tree->t_tid == tid) {
+ mutex_enter(&tree->t_mutex);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED:
+ /* The tree exists and is still connected. */
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (tree);
+ case SMB_TREE_STATE_DISCONNECTING:
+ case SMB_TREE_STATE_DISCONNECTED:
+ /*
+ * The tree exists but is diconnected or is in
+ * the process of being destroyed.
+ */
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+ default:
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+ }
+ }
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ }
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+}
+
+/*
+ * smb_tree_lookup_first_by_name
+ *
+ * This function returns the first tree in the connected state that matches the
+ * sharename passed in. If the tree provided is NULL the search starts from
+ * the beginning of the list of trees of the user. It a tree is provided the
+ * search starts just after that tree.
+ */
+smb_tree_t *
+smb_tree_lookup_by_name(
+ smb_user_t *user,
+ char *sharename,
+ smb_tree_t *tree)
+{
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(sharename);
+
+ smb_llist_enter(&user->u_tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ } else {
+ tree = smb_llist_head(&user->u_tree_list);
+ }
+
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ if (strcmp(tree->t_sharename, sharename) == 0) {
+ mutex_enter(&tree->t_mutex);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED:
+ /* The tree exists and is still connected. */
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (tree);
+ case SMB_TREE_STATE_DISCONNECTING:
+ case SMB_TREE_STATE_DISCONNECTED:
+ /*
+ * The tree exists but is diconnected or is in
+ * the process of being destroyed.
+ */
+ mutex_exit(&tree->t_mutex);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ break;
+ }
+ }
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ }
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+}
+
+/*
+ * smb_tree_lookup_first_by_fsd
+ *
+ * This function returns the first tree in the connected state that matches the
+ * fsd passed in. If the tree provided is NULL the search starts from
+ * the beginning of the list of trees of the user. It a tree is provided the
+ * search starts just after that tree.
+ */
+smb_tree_t *
+smb_tree_lookup_by_fsd(
+ smb_user_t *user,
+ fs_desc_t *fsd,
+ smb_tree_t *tree)
+{
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(fsd);
+
+ smb_llist_enter(&user->u_tree_list, RW_READER);
+
+ if (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ } else {
+ tree = smb_llist_head(&user->u_tree_list);
+ }
+
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_user == user);
+ if (fsd_cmp(&tree->t_fsd, fsd) == 0) {
+ mutex_enter(&tree->t_mutex);
+ switch (tree->t_state) {
+ case SMB_TREE_STATE_CONNECTED:
+ /* The tree exists and is still connected. */
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ smb_llist_exit(&user->u_tree_list);
+ return (tree);
+ case SMB_TREE_STATE_DISCONNECTING:
+ case SMB_TREE_STATE_DISCONNECTED:
+ /*
+ * The tree exists but is diconnected or is in
+ * the process of being destroyed.
+ */
+ mutex_exit(&tree->t_mutex);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ break;
+ }
+ }
+ tree = smb_llist_next(&user->u_tree_list, tree);
+ }
+ smb_llist_exit(&user->u_tree_list);
+ return (NULL);
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_tree_delete
+ *
+ * This function releases all the resources associated with a tree. It also
+ * removes the tree the caller passes from the list of trees of the user.
+ *
+ * The tree to destroy must be in the "destroying state" and the reference count
+ * must be zero. This function assumes it's single threaded i.e. only one
+ * thread will attempt to destroy a specific tree (this condition should be met
+ * if the tree is is the "destroying state" and has a reference count of zero).
+ *
+ * Entry:
+ * tree Tree to destroy
+ *
+ * Exit:
+ * Nothing
+ *
+ * Return:
+ * Nothing
+ */
+static void
+smb_tree_delete(smb_tree_t *tree)
+{
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
+ ASSERT(tree->t_refcnt == 0);
+
+ /*
+ * Let's remove the tree from the list of trees of the
+ * user. This has to be done before any resources
+ * associated with the tree are released.
+ */
+ smb_llist_enter(&tree->t_user->u_tree_list, RW_WRITER);
+ smb_llist_remove(&tree->t_user->u_tree_list, tree);
+ smb_llist_exit(&tree->t_user->u_tree_list);
+
+ tree->t_magic = (uint32_t)~SMB_TREE_MAGIC;
+ smb_idpool_free(&tree->t_user->u_tid_pool, tree->t_tid);
+ atomic_dec_32(&tree->t_session->s_tree_cnt);
+
+ if (tree->t_snode) {
+ smb_node_release(tree->t_snode);
+ }
+ mutex_destroy(&tree->t_mutex);
+ /*
+ * The list of open files and open directories should be empty.
+ */
+ smb_llist_destructor(&tree->t_ofile_list);
+ smb_llist_destructor(&tree->t_odir_list);
+ smb_idpool_destructor(&tree->t_fid_pool);
+ smb_idpool_destructor(&tree->t_sid_pool);
+ kmem_cache_free(smb_info.si_cache_tree, tree);
+}
+
+/*
+ * smb_tree_lookup_head
+ *
+ * This function returns the first tree in the list that is in the
+ * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and
+ * smb_tree_release() will have to be called for the tree returned.
+ *
+ * Entry:
+ * lst List of trees (usually the list of trees of a user)
+ *
+ * Exit:
+ * Nothing
+ *
+ * Return:
+ * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found.
+ * !NULL First tree in the list in the SMB_TREE_STATE_CONNECTED state.
+ */
+static smb_tree_t *
+smb_tree_lookup_head(
+ smb_llist_t *lst)
+{
+ smb_tree_t *tree;
+
+ smb_llist_enter(lst, RW_READER);
+ tree = smb_llist_head(lst);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ mutex_enter(&tree->t_mutex);
+ if (tree->t_state == SMB_TREE_STATE_CONNECTED) {
+ tree->t_refcnt++;
+ mutex_exit(&tree->t_mutex);
+ break;
+ } else if ((tree->t_state == SMB_TREE_STATE_DISCONNECTING) ||
+ (tree->t_state == SMB_TREE_STATE_DISCONNECTED)) {
+ mutex_exit(&tree->t_mutex);
+ tree = smb_llist_next(lst, tree);
+ } else {
+ ASSERT(0);
+ mutex_exit(&tree->t_mutex);
+ tree = smb_llist_next(lst, tree);
+ }
+ }
+ smb_llist_exit(lst);
+
+ return (tree);
+}
+
+/*
+ * smb_tree_lookup_next
+ *
+ * This function returns the next tree in the list that is in the
+ * SMB_TREE_STATE_CONNECTED. A reference is taken on the tree and
+ * smb_tree_release() will have to be called for the tree returned.
+ *
+ * Entry:
+ * lst List of trees (usually the list of trees of a user).
+ * tree Starting tree.
+ *
+ * Exit:
+ * Nothing
+ *
+ * Return:
+ * NULL No tree in the SMB_TREE_STATE_CONNECTED state was found.
+ * !NULL Next tree in the list in the SMB_TREE_STATE_CONNECTED state.
+ */
+static smb_tree_t *
+smb_tree_lookup_next(
+ smb_llist_t *lst,
+ smb_tree_t *tree)
+{
+ smb_tree_t *next;
+
+ ASSERT(lst);
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ ASSERT(tree->t_refcnt);
+
+ smb_llist_enter(lst, RW_READER);
+ next = smb_llist_next(lst, tree);
+ while (next) {
+ ASSERT(next->t_magic == SMB_TREE_MAGIC);
+ mutex_enter(&next->t_mutex);
+ if (next->t_state == SMB_TREE_STATE_CONNECTED) {
+ next->t_refcnt++;
+ mutex_exit(&next->t_mutex);
+ break;
+ } else if ((next->t_state == SMB_TREE_STATE_DISCONNECTING) ||
+ (next->t_state == SMB_TREE_STATE_DISCONNECTED)) {
+ mutex_exit(&next->t_mutex);
+ next = smb_llist_next(lst, next);
+ } else {
+ ASSERT(0);
+ mutex_exit(&next->t_mutex);
+ next = smb_llist_next(lst, next);
+ }
+ }
+ smb_llist_exit(lst);
+
+ return (next);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
new file mode 100644
index 0000000000..9f8d15807e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: tree_connect
+ *
+ * When a client connects to a server resource, an SMB_COM_TREE_CONNECT
+ * message is generated to the server. This command is almost exactly like
+ * SMB_COM_TREE_CONNECT_ANDX, except that no AndX command may follow; see
+ * section 4.1.4.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 4
+ * UCHAR BufferFormat1; 0x04
+ * STRING Path[]; Server name and share name
+ * UCHAR BufferFormat2; 0x04
+ * STRING Password[]; Password
+ * UCHAR BufferFormat3; 0x04
+ * STRING Service[]; Service name
+ *
+ * The CIFS server responds with:
+ *
+ * Server Response Description
+ * ================================ =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * USHORT MaxBufferSize; Max size message the server handles
+ * USHORT Tid; Tree ID
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * If the negotiated dialect is MICROSOFT NETWORKS 1.03 or earlier,
+ * MaxBufferSize in the response message indicates the maximum size message
+ * that the server can handle. The client should not generate messages,
+ * nor expect to receive responses, larger than this. This must be
+ * constant for a given server. For newer dialects, this field is ignored.
+ *
+ * Tid should be included in any future SMBs referencing this tree
+ * connection.
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_tree_connect(struct smb_request *sr)
+{
+ /*
+ * I'm not sure it this should be "%A.sA"
+ * now that unicode is enabled.
+ */
+ if (smbsr_decode_data(sr, "%AAA", sr, &sr->arg.tcon.path,
+ &sr->arg.tcon.password, &sr->arg.tcon.service) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.tcon.flags = 0;
+
+ /*
+ * If the negotiated dialect is MICROSOFT NETWORKS 1.03
+ * or earlier, MaxBufferSize in the response message
+ * indicates the maximum size message that the server can
+ * handle. The client should not generate messages, nor
+ * expect to receive responses, larger than this. This
+ * must be constant for a given server. For newer dialects,
+ * this field is ignored.
+ *
+ * The reason for this is that the maximum buffer size is
+ * established during the NEGOTIATE.
+ */
+
+ (void) smbsr_connect_tree(sr);
+
+ smbsr_encode_result(sr, 2, 0, "bwww",
+ 2, /* wct */
+ (WORD)smb_maxbufsize, /* MaxBufferSize */
+ sr->smb_tid, /* TID */
+ 0); /* bcc */
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c b/usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c
new file mode 100644
index 0000000000..436ecf906c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect_andx.c
@@ -0,0 +1,213 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: tree_connect_andx
+ *
+ * Client Request Description
+ * ================================= =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 4
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT Flags; Additional information
+ * bit 0 set = disconnect Tid
+ * USHORT PasswordLength; Length of Password[]
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR Password[]; Password
+ * STRING Path[]; Server name and share name
+ * STRING Service[]; Service name
+ *
+ * The serving machine verifies the combination and returns an error code
+ * or an identifier. The full name is included in this request message and
+ * the identifier identifying the connection is returned in the Tid field
+ * of the SMB header. The Tid field in the client request is ignored. The
+ * meaning of this identifier (Tid) is server specific; the client must not
+ * associate any specific meaning to it.
+ *
+ * If the negotiated dialect is LANMAN1.0 or later, then it is a protocol
+ * violation for the client to send this message prior to a successful
+ * SMB_COM_SESSION_SETUP_ANDX, and the server ignores Password.
+ *
+ * If the negotiated dialect is prior to LANMAN1.0 and the client has not
+ * sent a successful SMB_COM_SESSION_SETUP_ANDX request when the tree
+ * connect arrives, a user level security mode server must nevertheless
+ * validate the client's credentials as discussed earlier in this document.
+ *
+ * Path follows UNC style syntax, that is to say it is encoded as
+ * \\server\share and it indicates the name of the resource to which the
+ * client wishes to connect.
+ *
+ * Because Password may be an authentication response, it is a variable
+ * length field with the length specified by PasswordLength. If
+ * authentication is not being used, Password should be a null terminated
+ * ASCII string with PasswordLength set to the string size including the
+ * terminating null.
+ *
+ * The server can enforce whatever policy it desires to govern share
+ * access. Typically, if the server is paused, administrative privilege is
+ * required to connect to any share; if the server is not paused,
+ * administrative privilege is required only for administrative shares (C$,
+ * etc.). Other such policies may include valid times of day, software
+ * usage license limits, number of simultaneous server users or share
+ * users, etc.
+ *
+ * The Service component indicates the type of resource the client intends
+ * to access. Valid values are:
+ *
+ * Service Description Earliest Dialect Allowed
+ * ======== ======================== ================================
+ *
+ * A: disk share PC NETWORK PROGRAM 1.0
+ * LPT1: printer PC NETWORK PROGRAM 1.0
+ * IPC named pipe MICROSOFT NETWORKS 3.0
+ * COMM communications device MICROSOFT NETWORKS 3.0
+ * ????? any type of device MICROSOFT NETWORKS 3.0
+ *
+ * If bit0 of Flags is set, the tree connection to Tid in the SMB header
+ * should be disconnected. If this tree disconnect fails, the error should
+ * be ignored.
+ *
+ * If the negotiated dialect is earlier than DOS LANMAN2.1, the response to
+ * this SMB is:
+ *
+ * Server Response Description
+ * ================================ ===================================
+ *
+ * UCHAR WordCount; Count of parameter words = 2
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT ByteCount; Count of data bytes; min = 3
+ *
+ * If the negotiated is DOS LANMAN2.1 or later, the response to this SMB
+ * is:
+ *
+ * Server Response Description
+ * ================================ ===================================
+ *
+ * UCHAR WordCount; Count of parameter words = 3
+ * UCHAR AndXCommand; Secondary (X) command; 0xFF = none
+ * UCHAR AndXReserved; Reserved (must be 0)
+ * USHORT AndXOffset; Offset to next command WordCount
+ * USHORT OptionalSupport; Optional support bits
+ * USHORT ByteCount; Count of data bytes; min = 3
+ * UCHAR Service[]; Service type connected to. Always
+ * ANSII.
+ * STRING NativeFileSystem[]; Native file system for this tree
+ *
+ * NativeFileSystem is the name of the filesystem; values to be expected
+ * include FAT, NTFS, etc.
+ *
+ * OptionalSupport bits has the encoding:
+ *
+ * Name Encoding Description
+ * ============================= ========= ==========================
+ *
+ * SMB_SUPPORT_SEARCH_BITS 0x0001
+ *
+ * SMB_SHARE_IS_IN_DFS 0x0002
+ *
+ * Some servers negotiate "DOS LANMAN2.1" dialect or later and still send
+ * the "downlevel" (i.e. wordcount==2) response. Valid AndX following
+ * commands are
+ *
+ * SMB_COM_OPEN SMB_COM_OPEN_ANDX SMB_COM_CREATE
+ * SMB_COM_CREATE_NEW SMB_COM_CREATE_DIRECTORY SMB_COM_DELETE
+ * SMB_COM_DELETE_DIRECTORY SMB_COM_FIND SMB_COM_COPY
+ * SMB_COM_FIND_UNIQUE SMB_COM_RENAME
+ * SMB_COM_CHECK_DIRECTORY SMB_COM_QUERY_INFORMATION
+ * SMB_COM_GET_PRINT_QUEUE SMB_COM_OPEN_PRINT_FILE
+ * SMB_COM_TRANSACTION SMB_COM_NO_ANDX_CMD
+ * SMB_COM_SET_INFORMATION SMB_COM_NT_RENAME
+ *
+ * 4.1.4.1 Errors
+ *
+ * ERRDOS/ERRnomem
+ * ERRDOS/ERRbadpath
+ *
+ * ERRDOS/ERRinvdevice
+ * ERRSRV/ERRaccess
+ * ERRSRV/ERRbadpw
+ * ERRSRV/ERRinvnetname
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_tree_connect_andx(struct smb_request *sr)
+{
+ unsigned char *pwbuf = NULL;
+ unsigned short pwlen = 0;
+ int rc;
+
+ rc = smbsr_decode_vwv(sr, "b.www", &sr->andx_com, &sr->andx_off,
+ &sr->arg.tcon.flags, &pwlen);
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ if (pwlen != 0) {
+ pwbuf = (unsigned char *)smbsr_malloc(&sr->request_storage,
+ pwlen);
+ bzero(pwbuf, pwlen);
+ }
+
+ if (smbsr_decode_data(sr, "%#cus", sr, pwlen, pwbuf,
+ &sr->arg.tcon.path, &sr->arg.tcon.service) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->arg.tcon.pwdlen = pwlen;
+ sr->arg.tcon.password = (char *)pwbuf;
+
+ (void) smbsr_connect_tree(sr);
+
+ if (sr->session->dialect < NT_LM_0_12) {
+ smbsr_encode_result(sr, 2, VAR_BCC, "bb.wwss",
+ (char)2, /* wct */
+ sr->andx_com,
+ VAR_BCC,
+ VAR_BCC,
+ sr->arg.tcon.service,
+ sr->tid_tree->t_typename);
+ } else {
+ smbsr_encode_result(sr, 3, VAR_BCC, "bb.wwws%u",
+ (char)3, /* wct */
+ sr->andx_com,
+ (short)64,
+ (short)SMB_TREE_SUPPORT_SEARCH_BITS,
+ VAR_BCC,
+ sr->arg.tcon.service,
+ sr,
+ sr->tid_tree->t_typename);
+ }
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c b/usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c
new file mode 100644
index 0000000000..9139930a4d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_disconnect.c
@@ -0,0 +1,110 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: tree_disconnect
+ *
+ * This message informs the server that the client no longer wishes to
+ * access the resource connected to with a prior SMB_COM_TREE_CONNECT or
+ * SMB_COM_TREE_CONNECT_ANDX.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The resource sharing connection identified by Tid in the SMB header is
+ * logically disconnected from the server. Tid is invalidated; it will not
+ * be recognized if used by the client for subsequent requests. All locks,
+ * open files, etc. created on behalf of Tid are released.
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * 4.1.5.1 Errors
+ *
+ * ERRSRV/ERRinvnid
+ * ERRSRV/ERRbaduid
+ */
+
+#include <smbsrv/smb_incl.h>
+
+/*
+ * Function: int smb_com_tree_disconnect(struct smb_request *)
+ *
+ * Please note the SDDF_SUPPRESS_UID is set for this operation;
+ * therefore, the uid_user field in sr is invalid. Do not use it
+ * or the system would panic.
+ *
+ * Please also note that in some cases, the client would not send
+ * tree disconnect call. An example of that is, the return of invalid
+ * uid for a client request i.e. read_andx, when the used has logged
+ * off. This will cause a minor memory leak for the share and some
+ * files would remain open. When the session is destroyed, the leaked
+ * and remained open files will be freed/closed. We will need to
+ * address this problem by re-architecting user/tree structures.
+ * For the time being, we will leave it till we have time.
+ */
+
+int
+smb_com_tree_disconnect(struct smb_request *sr)
+{
+ /*
+ * A Tree Disconnect request requires a valid user ID as well as a
+ * valid tree ID. However, some clients logoff a user and then try to
+ * disconnect the trees connected using the user they just logged off.
+ * There's a problem with that behavior and the tree representation
+ * of the different contexts (session, user, tree, file...). In order
+ * to find a tree a valid user has to be provided. This means, with
+ * the behavior described above, a client would receive a negative
+ * response to the TreeDisconnect request with an error code saying
+ * ERRbaduid. That response breaks some clients. To prevent that
+ * from happening, the dispatch table indicates that, for the
+ * TreeDisconnect request, the UID and the TID shouldn't be looked up
+ * in the dispatch routine. The lookup is done here. If the user or
+ * the tree cannot be identified a negative response is sent back with
+ * the error code ERRinvnid.
+ */
+ sr->uid_user = smb_user_lookup_by_uid(sr->session, &sr->user_cr,
+ sr->smb_uid);
+ if (sr->uid_user != NULL)
+ sr->tid_tree = smb_tree_lookup_by_tid(sr->uid_user,
+ sr->smb_tid);
+
+ if (sr->uid_user == NULL || sr->tid_tree == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRinvnid);
+ }
+ smbsr_rq_notify(sr, sr->session, sr->tid_tree);
+ smb_tree_disconnect(sr->tid_tree);
+ smbsr_encode_empty_result(sr);
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
new file mode 100644
index 0000000000..420c26a250
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
@@ -0,0 +1,87 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: unlock_byte_range
+ *
+ * This message is sent to unlock the given byte range. Offset, Count, and
+ * Pid must be identical to that specified in a prior successful lock. If
+ *
+ * an unlock references an address range that is not locked, no error is
+ * generated.
+ *
+ * Since Offset is a 32 bit quantity, this request is inappropriate for
+ * general locking within a very large file.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 5
+ * USHORT Fid; File handle
+ * ULONG Count; Count of bytes to unlock
+ * ULONG Offset; Offset from start of file
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+
+#include <smbsrv/smb_incl.h>
+
+int
+smb_com_unlock_byte_range(struct smb_request *sr)
+{
+ uint32_t Length;
+ uint32_t Offset;
+ DWORD result;
+
+ if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &Length, &Offset) != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node,
+ (off_t)Offset, (uint64_t)Length);
+ if (result != NT_STATUS_SUCCESS) {
+ smb_unlock_range_raise_error(sr, result);
+ /* NOT REACHED */
+ }
+
+ smbsr_encode_empty_result(sr);
+
+ return (SDRC_NORMAL_REPLY);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_upcalls.c b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c
new file mode 100644
index 0000000000..a421640b1b
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c
@@ -0,0 +1,104 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smb_vops.h>
+#include <sys/stat.h>
+
+
+void
+smb_user_nonauth_logon(uint32_t audit_sid)
+{
+ char *arg, *rsp;
+ size_t arg_size, rsp_size;
+
+ arg = smb_kdr_encode_common(SMB_DR_USER_NONAUTH_LOGON,
+ &audit_sid, xdr_uint32_t, &arg_size);
+
+ if (arg != NULL) {
+ rsp = smb_kdoor_clnt_upcall(arg, arg_size, NULL, 0, &rsp_size);
+ smb_kdoor_clnt_free(arg, arg_size, rsp, rsp_size);
+ }
+}
+
+void
+smb_user_auth_logoff(uint32_t audit_sid)
+{
+ char *arg, *rsp;
+ size_t arg_size, rsp_size;
+
+ arg = smb_kdr_encode_common(SMB_DR_USER_AUTH_LOGOFF,
+ &audit_sid, xdr_uint32_t, &arg_size);
+
+ if (arg != NULL) {
+ rsp = smb_kdoor_clnt_upcall(arg, arg_size, NULL, 0, &rsp_size);
+ smb_kdoor_clnt_free(arg, arg_size, rsp, rsp_size);
+ }
+}
+
+smb_token_t *
+smb_upcall_get_token(netr_client_t *clnt_info)
+{
+ char *argp, *rbufp;
+ size_t arg_size, rbuf_size;
+ smb_token_t *token = NULL;
+
+ argp = smb_dr_encode_arg_get_token(clnt_info, &arg_size);
+ rbufp = smb_kdoor_clnt_upcall(argp, arg_size, NULL, 0, &rbuf_size);
+ if (rbufp)
+ token = smb_dr_decode_res_token(rbufp + SMB_DR_DATA_OFFSET,
+ rbuf_size - SMB_DR_DATA_OFFSET);
+
+ smb_kdoor_clnt_free(argp, arg_size, rbufp, rbuf_size);
+ return (token);
+
+}
+
+int
+smb_upcall_set_dwncall_desc(uint32_t opcode, door_desc_t *dp, uint_t n_desc)
+{
+ char *argp, *rbufp;
+ size_t arg_size, rbuf_size;
+
+ argp = smb_dr_set_opcode(opcode, &arg_size);
+ if (argp == NULL) {
+ return (SMB_DR_OP_ERR_ENCODE);
+ }
+
+ rbufp = smb_kdoor_clnt_upcall(argp, arg_size, dp, n_desc, &rbuf_size);
+ if (rbufp == NULL) {
+ return (SMB_DR_OP_ERR);
+ }
+
+ smb_kdoor_clnt_free(argp, arg_size, rbufp, rbuf_size);
+
+ return (SMB_DR_OP_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_user.c b/usr/src/uts/common/fs/smbsrv/smb_user.c
new file mode 100644
index 0000000000..bfea00768e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c
@@ -0,0 +1,619 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * General Structures Layout
+ * -------------------------
+ *
+ * This is a simplified diagram showing the relationship between most of the
+ * main structures.
+ *
+ * +-------------------+
+ * | SMB_INFO |
+ * +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | SESSION |<----->| SESSION |......| SESSION |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | USER |<----->| USER |......| USER |
+ * +-------------------+ +-------------------+ +-------------------+
+ * |
+ * |
+ * v
+ * +-------------------+ +-------------------+ +-------------------+
+ * | TREE |<----->| TREE |......| TREE |
+ * +-------------------+ +-------------------+ +-------------------+
+ * | |
+ * | |
+ * | v
+ * | +-------+ +-------+ +-------+
+ * | | OFILE |<----->| OFILE |......| OFILE |
+ * | +-------+ +-------+ +-------+
+ * |
+ * |
+ * v
+ * +-------+ +------+ +------+
+ * | ODIR |<----->| ODIR |......| ODIR |
+ * +-------+ +------+ +------+
+ *
+ *
+ * User State Machine
+ * ------------------
+ *
+ * +-----------------------------+ T0
+ * | SMB_USER_STATE_LOGGED_IN |<----------- Creation/Allocation
+ * +-----------------------------+
+ * |
+ * | T1
+ * |
+ * v
+ * +-----------------------------+
+ * | SMB_USER_STATE_LOGGING_OFF |
+ * +-----------------------------+
+ * |
+ * | T2
+ * |
+ * v
+ * +-----------------------------+ T3
+ * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free
+ * +-----------------------------+
+ *
+ * SMB_USER_STATE_LOGGED_IN
+ *
+ * While in this state:
+ * - The user is queued in the list of users of his session.
+ * - References will be given out if the user is looked up.
+ * - The user can access files and pipes.
+ *
+ * SMB_USER_STATE_LOGGING_OFF
+ *
+ * While in this state:
+ * - The user is queued in the list of users of his session.
+ * - References will not be given out if the user is looked up.
+ * - The trees the user connected are being disconnected.
+ * - The resources associated with the user remain.
+ *
+ * SMB_USER_STATE_LOGGING_OFF
+ *
+ * While in this state:
+ * - The user is queued in the list of users of his session.
+ * - References will not be given out if the user is looked up.
+ * - The user has no more trees connected.
+ * - The resources associated with the user remain.
+ *
+ * Transition T0
+ *
+ * This transition occurs in smb_user_login(). A new user is created and
+ * added to the list of users of a session.
+ *
+ * Transition T1
+ *
+ * This transition occurs in smb_user_logoff().
+ *
+ * Transition T2
+ *
+ * This transition occurs in smb_user_release(). The resources associated
+ * with the user are deleted as well as the user. For the transition to
+ * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
+ * reference count be zero.
+ *
+ * Comments
+ * --------
+ *
+ * The state machine of the user structures is controlled by 3 elements:
+ * - The list of users of the session he belongs to.
+ * - The mutex embedded in the structure itself.
+ * - The reference count.
+ *
+ * There's a mutex embedded in the user structure used to protect its fields
+ * and there's a lock embedded in the list of users of a session. To
+ * increment or to decrement the reference count the mutex must be entered.
+ * To insert the user into the list of users of the session and to remove
+ * the user from it, the lock must be entered in RW_WRITER mode.
+ *
+ * Rules of access to a user structure:
+ *
+ * 1) In order to avoid deadlocks, when both (mutex and lock of the session
+ * list) have to be entered, the lock must be entered first.
+ *
+ * 2) All actions applied to a user require a reference count.
+ *
+ * 3) There are 2 ways of getting a reference count. One is when the user
+ * logs in. The other when the user is looked up. This translates into
+ * 3 functions: smb_user_login(), smb_user_lookup_by_uid() and
+ * smb_user_lookup_by_credentials.
+ *
+ * It should be noted that the reference count of a user registers the
+ * number of references to the user in other structures (such as an smb
+ * request). The reference count is not incremented in these 2 instances:
+ *
+ * 1) The user is logged in. An user is anchored by his state. If there's
+ * no activity involving a user currently logged in, the reference
+ * count of that user is zero.
+ *
+ * 2) The user is queued in the list of users of the session. The fact of
+ * being queued in that list is NOT registered by incrementing the
+ * reference count.
+ */
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_door_svc.h>
+
+/* Static functions defined further down this file. */
+static void smb_user_delete(smb_user_t *user);
+
+/*
+ * smb_user_login
+ *
+ *
+ */
+smb_user_t *
+smb_user_login(
+ smb_session_t *session,
+ cred_t *cr,
+ char *domain_name,
+ char *account_name,
+ uint32_t flags,
+ uint32_t privileges,
+ uint32_t audit_sid)
+{
+ smb_user_t *user;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ ASSERT(cr);
+ ASSERT(account_name);
+ ASSERT(domain_name);
+
+ user = kmem_cache_alloc(smb_info.si_cache_user, KM_SLEEP);
+ bzero(user, sizeof (smb_user_t));
+ user->u_refcnt = 1;
+ user->u_session = session;
+ user->u_logon_time = gethrestime_sec();
+ user->u_flags = flags;
+ user->u_privileges = privileges;
+ user->u_name_len = strlen(account_name) + 1;
+ user->u_domain_len = strlen(domain_name) + 1;
+ user->u_name = smb_kstrdup(account_name, user->u_name_len);
+ user->u_domain = smb_kstrdup(domain_name, user->u_domain_len);
+ user->u_cred = cr;
+ user->u_audit_sid = audit_sid;
+
+ if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
+ if (!smb_idpool_constructor(&user->u_tid_pool)) {
+ smb_llist_constructor(&user->u_tree_list,
+ sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
+ mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
+ crhold(cr);
+ user->u_state = SMB_USER_STATE_LOGGED_IN;
+ user->u_magic = SMB_USER_MAGIC;
+ smb_llist_enter(&session->s_user_list, RW_WRITER);
+ smb_llist_insert_tail(&session->s_user_list, user);
+ smb_llist_exit(&session->s_user_list);
+ atomic_inc_32(&smb_info.open_users);
+ return (user);
+ }
+ smb_idpool_free(&session->s_uid_pool, user->u_uid);
+ }
+ kmem_free(user->u_name, (size_t)user->u_name_len);
+ kmem_free(user->u_domain, (size_t)user->u_domain_len);
+ kmem_cache_free(smb_info.si_cache_user, user);
+ return (NULL);
+}
+
+/*
+ * Create a new user based on an existing user, used to support
+ * additional SessionSetupX requests for a user on a session.
+ *
+ * Assumes the caller has a reference on the original user from
+ * a user_lookup_by_x call.
+ */
+smb_user_t *
+smb_user_dup(
+ smb_user_t *orig_user)
+{
+ smb_user_t *user;
+
+ ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
+ ASSERT(orig_user->u_refcnt);
+
+ user = smb_user_login(orig_user->u_session, orig_user->u_cred,
+ orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
+ orig_user->u_privileges, orig_user->u_audit_sid);
+
+ if (user)
+ smb_user_nonauth_logon(orig_user->u_audit_sid);
+
+ return (user);
+}
+
+/*
+ * smb_user_logoff
+ *
+ *
+ */
+void
+smb_user_logoff(
+ smb_user_t *user)
+{
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ mutex_enter(&user->u_mutex);
+ ASSERT(user->u_refcnt);
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_IN: {
+ /*
+ * The user is moved into a state indicating that the log off
+ * process has started.
+ */
+ user->u_state = SMB_USER_STATE_LOGGING_OFF;
+ mutex_exit(&user->u_mutex);
+ atomic_dec_32(&smb_info.open_users);
+ /*
+ * All the trees hanging off of this user are disconnected.
+ */
+ smb_tree_disconnect_all(user);
+ smb_user_auth_logoff(user->u_audit_sid);
+ mutex_enter(&user->u_mutex);
+ user->u_state = SMB_USER_STATE_LOGGED_OFF;
+ break;
+ }
+ case SMB_USER_STATE_LOGGED_OFF:
+ case SMB_USER_STATE_LOGGING_OFF:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+}
+
+/*
+ * smb_user_logoff_all
+ *
+ *
+ */
+void
+smb_user_logoff_all(
+ smb_session_t *session)
+{
+ smb_user_t *user;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ smb_llist_enter(&session->s_user_list, RW_READER);
+ user = smb_llist_head(&session->s_user_list);
+ while (user) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_session == session);
+ mutex_enter(&user->u_mutex);
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_IN:
+ /* The user is still logged in. */
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ smb_user_logoff(user);
+ smb_user_release(user);
+ smb_llist_enter(&session->s_user_list, RW_READER);
+ user = smb_llist_head(&session->s_user_list);
+ break;
+ case SMB_USER_STATE_LOGGING_OFF:
+ case SMB_USER_STATE_LOGGED_OFF:
+ /*
+ * The user is logged off or logging off.
+ */
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(&session->s_user_list, user);
+ break;
+ default:
+ ASSERT(0);
+ mutex_exit(&user->u_mutex);
+ user = smb_llist_next(&session->s_user_list, user);
+ break;
+ }
+ }
+ smb_llist_exit(&session->s_user_list);
+}
+
+/*
+ * smb_user_release
+ *
+ *
+ */
+void
+smb_user_release(
+ smb_user_t *user)
+{
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ mutex_enter(&user->u_mutex);
+ ASSERT(user->u_refcnt);
+ user->u_refcnt--;
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_OFF:
+ if (user->u_refcnt == 0) {
+ mutex_exit(&user->u_mutex);
+ smb_user_delete(user);
+ return;
+ }
+ break;
+
+ case SMB_USER_STATE_LOGGED_IN:
+ case SMB_USER_STATE_LOGGING_OFF:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+}
+
+/*
+ * smb_user_lookup_by_uid
+ *
+ * Find the appropriate user for this request. The request credentials
+ * set here may be overridden by the tree credentials. In domain mode,
+ * the user and tree credentials should be the same. In share mode, the
+ * tree credentials (defined in the share definition) should override
+ * the user credentials.
+ */
+smb_user_t *
+smb_user_lookup_by_uid(
+ smb_session_t *session,
+ cred_t **cr,
+ uint16_t uid)
+{
+ smb_user_t *user;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+ ASSERT(cr);
+
+ smb_llist_enter(&session->s_user_list, RW_READER);
+ user = smb_llist_head(&session->s_user_list);
+ while (user) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_session == session);
+ if (user->u_uid == uid) {
+ mutex_enter(&user->u_mutex);
+ switch (user->u_state) {
+
+ case SMB_USER_STATE_LOGGED_IN:
+ /* The user exists and is still logged in. */
+ *cr = user->u_cred;
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ return (user);
+
+ case SMB_USER_STATE_LOGGING_OFF:
+ case SMB_USER_STATE_LOGGED_OFF:
+ /*
+ * The user exists but has logged off or is in
+ * the process of logging off.
+ */
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ return (NULL);
+
+ default:
+ ASSERT(0);
+ mutex_exit(&user->u_mutex);
+ smb_llist_exit(&session->s_user_list);
+ return (NULL);
+ }
+ }
+ user = smb_llist_next(&session->s_user_list, user);
+ }
+ smb_llist_exit(&session->s_user_list);
+ return (NULL);
+}
+
+/*
+ * smb_user_lookup_by_name
+ */
+smb_user_t *
+smb_user_lookup_by_name(smb_session_t *session, char *domain, char *name)
+{
+ smb_user_t *user;
+ smb_llist_t *ulist;
+
+ ulist = &session->s_user_list;
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+ while (user) {
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ if (!utf8_strcasecmp(user->u_name, name) &&
+ !utf8_strcasecmp(user->u_domain, domain)) {
+ mutex_enter(&user->u_mutex);
+ if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ break;
+ }
+ mutex_exit(&user->u_mutex);
+ }
+ user = smb_llist_next(ulist, user);
+ }
+ smb_llist_exit(ulist);
+
+ return (user);
+}
+
+/*
+ * smb_user_lookup_by_state
+ *
+ * This function returns the first user in the logged in state. If the user
+ * provided is NULL the search starts from the beginning of the list passed
+ * in. It a user is provided the search starts just after that user.
+ */
+smb_user_t *
+smb_user_lookup_by_state(
+ smb_session_t *session,
+ smb_user_t *user)
+{
+ smb_llist_t *lst;
+ smb_user_t *next;
+
+ ASSERT(session);
+ ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+
+ lst = &session->s_user_list;
+
+ smb_llist_enter(lst, RW_READER);
+ if (user) {
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt);
+ next = smb_llist_next(lst, user);
+ } else {
+ next = smb_llist_head(lst);
+ }
+ while (next) {
+ ASSERT(next->u_magic == SMB_USER_MAGIC);
+ ASSERT(next->u_session == session);
+ mutex_enter(&next->u_mutex);
+ if (next->u_state == SMB_USER_STATE_LOGGED_IN) {
+ next->u_refcnt++;
+ mutex_exit(&next->u_mutex);
+ break;
+ } else {
+ ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) ||
+ (next->u_state == SMB_USER_STATE_LOGGED_OFF));
+ mutex_exit(&next->u_mutex);
+ next = smb_llist_next(lst, next);
+ }
+ }
+ smb_llist_exit(lst);
+
+ return (next);
+}
+
+/*
+ * smb_user_disconnect_share
+ *
+ * This function disconnects all the trees that have the sharename passed in.
+ */
+void
+smb_user_disconnect_share(
+ smb_user_t *user,
+ char *sharename)
+{
+ smb_tree_t *tree;
+ smb_tree_t *next;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt);
+
+ tree = smb_tree_lookup_by_name(user, sharename, NULL);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ smb_tree_disconnect(tree);
+ smbsr_rq_notify(NULL, user->u_session, tree);
+ next = smb_tree_lookup_by_name(user, sharename,
+ tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+/*
+ * smb_user_disconnect_share
+ *
+ * This function disconnects all the trees that match fsd passed in.
+ */
+void
+smb_user_disconnect_volume(
+ smb_user_t *user,
+ fs_desc_t *fsd)
+{
+ smb_tree_t *tree;
+ smb_tree_t *next;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt);
+
+ tree = smb_tree_lookup_by_fsd(user, fsd, NULL);
+ while (tree) {
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+ smb_tree_disconnect(tree);
+ smbsr_rq_notify(NULL, user->u_session, tree);
+ next = smb_tree_lookup_by_fsd(user, fsd, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+}
+
+/* *************************** Static Functions ***************************** */
+
+/*
+ * smb_user_delete
+ *
+ *
+ */
+static void
+smb_user_delete(
+ smb_user_t *user)
+{
+ smb_session_t *session;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+ ASSERT(user->u_refcnt == 0);
+ ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
+
+ session = user->u_session;
+ /*
+ * Let's remove the user from the list of users of the session. This
+ * has to be done before any resources associated with the user are
+ * deleted.
+ */
+ smb_llist_enter(&session->s_user_list, RW_WRITER);
+ smb_llist_remove(&session->s_user_list, user);
+ smb_llist_exit(&session->s_user_list);
+
+ user->u_magic = (uint32_t)~SMB_USER_MAGIC;
+ mutex_destroy(&user->u_mutex);
+ smb_llist_destructor(&user->u_tree_list);
+ smb_idpool_destructor(&user->u_tid_pool);
+ smb_idpool_free(&session->s_uid_pool, user->u_uid);
+ crfree(user->u_cred);
+ kmem_free(user->u_name, (size_t)user->u_name_len);
+ kmem_free(user->u_domain, (size_t)user->u_domain_len);
+ kmem_cache_free(smb_info.si_cache_user, user);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c
new file mode 100644
index 0000000000..beb39a6e51
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c
@@ -0,0 +1,2172 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/tzfile.h>
+#include <sys/atomic.h>
+#include <sys/kidmap.h>
+#include <sys/time.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/string.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_vops.h>
+
+#include <smbsrv/smb_idmap.h>
+
+#include <sys/sid.h>
+#include <sys/priv_names.h>
+
+#ifdef DEBUG
+uint_t smb_tsd_key;
+#endif
+
+static boolean_t
+smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks);
+
+time_t tzh_leapcnt = 0;
+
+struct tm
+*smb_gmtime_r(time_t *clock, struct tm *result);
+
+time_t
+smb_timegm(struct tm *tm);
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+static int days_in_month[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+int
+smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
+{
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ return (mts_wcequiv_strlen(str));
+ return (strlen(str));
+}
+
+int
+smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
+{
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ return (mts_wcequiv_strlen(str) + 2);
+ return (strlen(str) + 1);
+}
+
+int
+smb_ascii_or_unicode_null_len(struct smb_request *sr)
+{
+ if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
+ return (2);
+ return (1);
+}
+
+void
+smb_set_gmtoff(uint32_t goff)
+{
+ (void) atomic_swap_32(&smb_info.si_gmtoff, goff);
+}
+
+uint32_t
+smb_get_gmtoff(void)
+{
+ return (atomic_or_32_nv(&smb_info.si_gmtoff, 0));
+}
+
+uint32_t
+smb_gmt_to_local_time(uint32_t gmt)
+{
+ return (gmt + smb_get_gmtoff());
+}
+
+uint32_t
+smb_local_time_to_gmt(uint32_t local)
+{
+ return (local - smb_get_gmtoff());
+}
+
+
+int
+smb_component_match(
+ struct smb_request *sr,
+ ino64_t fileid,
+ struct smb_odir *od,
+ smb_odir_context_t *pc)
+{
+ int ci = (fsd_chkcap(&sr->tid_tree->t_fsd, FSOLF_CASE_INSENSITIVE) > 0);
+
+ int ignore_case = (ci || (SMB_TREE_CASE_INSENSITIVE(sr)));
+
+ return (smb_match_name(fileid, pc->dc_name, pc->dc_shortname,
+ pc->dc_name83, od->d_pattern, ignore_case));
+}
+
+int
+smb_convert_unicode_wildcards(char *path)
+{
+ int wildcards = 0;
+ char *ptr = path;
+ char nch;
+
+ /*
+ * Special case "<" for "dir *."
+ */
+ if (strcmp(path, "<") == 0) {
+ return (1);
+ }
+ while (*ptr) {
+ nch = *(ptr + 1);
+ switch (*ptr) {
+ case '*' : /* Count non-unicode wildcards while we're at it */
+ case '?' :
+ wildcards++;
+ break;
+ case '<' :
+ if (nch == '.') {
+ *(ptr++) = '*';
+ wildcards++;
+ }
+ break;
+ case '>' :
+ *ptr = '?';
+ wildcards++;
+ break;
+ case '\"' :
+ *ptr = '.';
+ break;
+ }
+ ptr++;
+ }
+ /* NT DOS wildcards... */
+ if (strcmp(path, "????????.???") == 0) {
+ (void) strcpy(path, "*");
+ } else if (strncmp(path, "????????.", 9) == 0) {
+ *path = '*';
+ (void) strcpy(path+1, path+8);
+ }
+
+ return (wildcards);
+}
+
+
+
+/*
+ * smb_mode_to_dos_attributes
+ *
+ * This function converts unix mode from smb_attr_t structure to dos attr.
+ *
+ * The reason dos_attr is returned as uint32_t, unlike sattr as
+ * unsigned short is the smb_trans_find_first2/next encodes dattr in
+ * BOTH DIR info as long.
+ */
+uint32_t
+smb_mode_to_dos_attributes(smb_attr_t *ap)
+{
+ uint32_t dos_attr = 0;
+
+ dos_attr = ap->sa_dosattr;
+ if (dos_attr == 0)
+ dos_attr = SMB_FA_NORMAL;
+
+ return (dos_attr);
+}
+
+
+
+/*
+ * smb_sattr_check
+ *
+ * This function checks if the file has the attributes indicated by
+ * the search attribute, "sattr". The normal files, which includes
+ * FSA_READONLY and FSA_ARCHIVE, should always pass the check. If the
+ * special attributes: SMB_FA_DIRECTORY, SMB_FA_HIDDEN or
+ * SMB_FA_SYSTEM are set, then the special mode FSA_DIR, FSA_HIDDEN,
+ * and FSA_SYSTEM will also pass accordingly. The following
+ * examples will show how this works:
+ *
+ * fileA: FSA_READONLY
+ * fileB: 0 (no attributes = normal file)
+ * fileC: FSA_READONLY, FSA_ARCHIVE
+ * fileD: FSA_HIDDEN
+ * fileE: FSA_READONLY, FSA_HIDDEN, FSA_SYSTEM
+ * dirA: FSA_DIRECTORY
+ *
+ * *search attribute: 0
+ * Returns: fileA, fileB and fileC.
+ * *search attribute: SMB_FA_HIDDEN
+ * Returns: fileA, fileB, fileC and fileD.
+ * *search attribute: SMB_FA_SYSTEM
+ * Returns: fileA, fileB and fileC.
+ * *search attribute: SMB_FA_DIRECTORY
+ * Returns: fileA, fileB, fileC and dirA.
+ * *search attribute: SMB_FA_HIDDEN and SMB_FA_SYSTEM
+ * Returns: fileA, fileB, fileC, fileD and fileE.
+ *
+ * As you can see, the special attributes are inclusive, which means the
+ * files that has all their special attributes included in the search
+ * attribute and normal files will be returned. The FSA_READONLY and
+ * FSA_ARCHIVE attributes are completely ignored since they are being
+ * treated as normal file.
+ *
+ * If check passed, 1 is returned; otherwise, 0 is returned.
+ */
+int
+smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr)
+{
+ if (name) {
+ if (is_dot_or_dotdot(name) && !(sattr & SMB_FA_HIDDEN))
+ return (0);
+ }
+
+ /*
+ * The FSA_READONLY and FSA_ARCHIVE bits are being treated
+ * as normal file; therefore, they are ignored.
+ */
+
+ if ((ap->sa_vattr.va_type == VDIR) && !(sattr & SMB_FA_DIRECTORY))
+ return (0);
+
+ if ((ap->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
+ !(sattr & SMB_FA_HIDDEN))
+ return (0);
+
+ if ((ap->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
+ !(sattr & SMB_FA_SYSTEM))
+ return (0);
+
+ return (1);
+}
+
+
+/*
+ * smb_stream_parse_name
+ *
+ * calling function is responsible for passing valid buffers with
+ * adequate sizes.
+ *
+ * path is a NULL terminated string which could be a
+ * stream path. If it's a stream path it could be
+ * in one of the following formats:
+ * . path:stream
+ * . path:stream:$DATA
+ * unnamed stream is part of the path and there is
+ * exactly one ':' in between the unamed and name
+ * streams
+ *
+ * u_stream_name will contain the unamed stream portion upon
+ * successful return.
+ * this is the portion between last '\' and
+ * the first ':'
+ *
+ * stream_name will contain the named stream portion upon
+ * successful return.
+ * this is the portion between the first ':' and the
+ * end of the 'name' string.
+ *
+ * '::' - is a non-stream and is commonly used by Windows to designate
+ * the unamed stream in the form "::$DATA"
+ *
+ * on return the named stream always has a ":$DATA" appended if there
+ * isn't one already
+ *
+ * Return Codes:
+ *
+ * 0 - given path doesn't contain any streams
+ * 1 - given path had a stream
+ */
+int
+smb_stream_parse_name(char *path, char *u_stream_name,
+ char *stream_name)
+{
+ char *colonp;
+ char *slashp;
+
+ if (path == 0)
+ return (0);
+
+ /*
+ * if there is no colon in the path or it's the last char
+ * then it's not a stream name
+ */
+ colonp = strchr(path, ':');
+ if ((colonp == 0) || (*(colonp+1) == 0))
+ return (0);
+
+ /* "::" always means the unamed stream */
+ if (strstr(path, "::"))
+ return (0);
+
+ if (stream_name) {
+ /*
+ * stream name is the portion between ':' and the
+ * end of 'path' string (including the starting ':')
+ */
+ (void) strcpy(stream_name, colonp);
+
+ if (strstr(stream_name, ":$DATA") == 0)
+ (void) strcat(stream_name, ":$DATA");
+ }
+
+ if (u_stream_name) {
+ /*
+ * uname stream is the portion between last '\'
+ * and the ':'
+ */
+ slashp = strrchr(path, '\\');
+ slashp = (slashp == 0) ? path : slashp + 1;
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ (void) strlcpy(u_stream_name, slashp, colonp - slashp + 1);
+ }
+ return (1);
+}
+
+int
+microtime(timestruc_t *tvp)
+{
+ tvp->tv_sec = gethrestime_sec();
+ tvp->tv_nsec = 0;
+ return (0);
+}
+
+int32_t
+clock_get_milli_uptime()
+{
+ return (TICK_TO_MSEC(lbolt));
+}
+
+int /*ARGSUSED*/
+smb_noop(void *p, size_t size, int foo)
+{
+ return (0);
+}
+
+/*
+ * smb_idpool_increment
+ *
+ * This function increments the ID pool by doubling the current size. This
+ * function assumes the caller entered the mutex of the pool.
+ */
+static int
+smb_idpool_increment(
+ smb_idpool_t *pool)
+{
+ uint8_t *new_pool;
+ uint32_t new_size;
+
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+
+ new_size = pool->id_size * 2;
+ if (new_size <= SMB_IDPOOL_MAX_SIZE) {
+ new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP);
+ if (new_pool) {
+ bzero(new_pool, new_size / 8);
+ bcopy(pool->id_pool, new_pool, pool->id_size / 8);
+ kmem_free(pool->id_pool, pool->id_size / 8);
+ pool->id_pool = new_pool;
+ pool->id_free_counter += new_size - pool->id_size;
+ pool->id_max_free_counter += new_size - pool->id_size;
+ pool->id_size = new_size;
+ pool->id_idx_msk = (new_size / 8) - 1;
+ if (new_size >= SMB_IDPOOL_MAX_SIZE) {
+ /* id -1 made unavailable */
+ pool->id_pool[pool->id_idx_msk] = 0x80;
+ pool->id_free_counter--;
+ pool->id_max_free_counter--;
+ }
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * smb_idpool_constructor
+ *
+ * This function initializes the pool structure provided.
+ */
+int
+smb_idpool_constructor(
+ smb_idpool_t *pool)
+{
+
+ ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC);
+
+ pool->id_size = SMB_IDPOOL_MIN_SIZE;
+ pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1;
+ pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
+ pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
+ pool->id_bit = 0x02;
+ pool->id_bit_idx = 1;
+ pool->id_idx = 0;
+ pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8),
+ KM_SLEEP);
+ bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8));
+ /* -1 id made unavailable */
+ pool->id_pool[0] = 0x01; /* id 0 made unavailable */
+ mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL);
+ pool->id_magic = SMB_IDPOOL_MAGIC;
+ return (0);
+}
+
+/*
+ * smb_idpool_destructor
+ *
+ * This function tears down and frees the resources associated with the
+ * pool provided.
+ */
+void
+smb_idpool_destructor(
+ smb_idpool_t *pool)
+{
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+ ASSERT(pool->id_free_counter == pool->id_max_free_counter);
+ pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC;
+ mutex_destroy(&pool->id_mutex);
+ kmem_free(pool->id_pool, (size_t)(pool->id_size / 8));
+}
+
+/*
+ * smb_idpool_alloc
+ *
+ * This function allocates an ID from the pool provided.
+ */
+int
+smb_idpool_alloc(
+ smb_idpool_t *pool,
+ uint16_t *id)
+{
+ uint32_t i;
+ uint8_t bit;
+ uint8_t bit_idx;
+ uint8_t byte;
+
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+
+ mutex_enter(&pool->id_mutex);
+ if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
+ mutex_exit(&pool->id_mutex);
+ return (-1);
+ }
+
+ i = pool->id_size;
+ while (i) {
+ bit = pool->id_bit;
+ bit_idx = pool->id_bit_idx;
+ byte = pool->id_pool[pool->id_idx];
+ while (bit) {
+ if (byte & bit) {
+ bit = bit << 1;
+ bit_idx++;
+ continue;
+ }
+ pool->id_pool[pool->id_idx] |= bit;
+ *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
+ pool->id_free_counter--;
+ pool->id_bit = bit;
+ pool->id_bit_idx = bit_idx;
+ mutex_exit(&pool->id_mutex);
+ return (0);
+ }
+ pool->id_bit = 1;
+ pool->id_bit_idx = 0;
+ pool->id_idx++;
+ pool->id_idx &= pool->id_idx_msk;
+ --i;
+ }
+ /*
+ * This section of code shouldn't be reached. If there are IDs
+ * available and none could be found there's a problem.
+ */
+ ASSERT(0);
+ mutex_exit(&pool->id_mutex);
+ return (-1);
+}
+
+/*
+ * smb_idpool_free
+ *
+ * This function frees the ID provided.
+ */
+void
+smb_idpool_free(
+ smb_idpool_t *pool,
+ uint16_t id)
+{
+ ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
+ ASSERT(id != 0);
+ ASSERT(id != 0xFFFF);
+
+ mutex_enter(&pool->id_mutex);
+ if (pool->id_pool[id >> 3] & (1 << (id & 7))) {
+ pool->id_pool[id >> 3] &= ~(1 << (id & 7));
+ pool->id_free_counter++;
+ ASSERT(pool->id_free_counter <= pool->id_max_free_counter);
+ mutex_exit(&pool->id_mutex);
+ return;
+ }
+ /* Freeing a free ID. */
+ ASSERT(0);
+ mutex_exit(&pool->id_mutex);
+}
+
+/*
+ * smb_llist_constructor
+ *
+ * This function initializes a locked list.
+ */
+void
+smb_llist_constructor(
+ smb_llist_t *ll,
+ size_t size,
+ size_t offset)
+{
+ rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL);
+ list_create(&ll->ll_list, size, offset);
+ ll->ll_count = 0;
+ ll->ll_wrop = 0;
+}
+
+/*
+ * smb_llist_destructor
+ *
+ * This function destroys a locked list.
+ */
+void
+smb_llist_destructor(
+ smb_llist_t *ll)
+{
+ ASSERT(ll->ll_count == 0);
+
+ rw_destroy(&ll->ll_lock);
+ list_destroy(&ll->ll_list);
+}
+
+/*
+ * smb_llist_upgrade
+ *
+ * This function tries to upgrade the lock of the locked list. It assumes the
+ * locked has already been entered in RW_READER mode. It first tries using the
+ * Solaris function rw_tryupgrade(). If that call fails the lock is released
+ * and reentered in RW_WRITER mode. In that last case a window is opened during
+ * which the contents of the list may have changed. The return code indicates
+ * whether or not the list was modified when the lock was exited.
+ */
+int smb_llist_upgrade(
+ smb_llist_t *ll)
+{
+ uint64_t wrop;
+
+ if (rw_tryupgrade(&ll->ll_lock) != 0) {
+ return (0);
+ }
+ wrop = ll->ll_wrop;
+ rw_exit(&ll->ll_lock);
+ rw_enter(&ll->ll_lock, RW_WRITER);
+ return (wrop != ll->ll_wrop);
+}
+
+/*
+ * smb_llist_insert_head
+ *
+ * This function inserts the object passed a the beginning of the list. This
+ * function assumes the lock of the list has already been entered.
+ */
+void
+smb_llist_insert_head(
+ smb_llist_t *ll,
+ void *obj)
+{
+ list_insert_head(&ll->ll_list, obj);
+ ++ll->ll_wrop;
+ ++ll->ll_count;
+}
+
+/*
+ * smb_llist_insert_tail
+ *
+ * This function appends to the object passed to the list. This function assumes
+ * the lock of the list has already been entered.
+ *
+ */
+void
+smb_llist_insert_tail(
+ smb_llist_t *ll,
+ void *obj)
+{
+ list_insert_tail(&ll->ll_list, obj);
+ ++ll->ll_wrop;
+ ++ll->ll_count;
+}
+
+/*
+ * smb_llist_remove
+ *
+ * This function removes the object passed from the list. This function assumes
+ * the lock of the list has already been entered.
+ */
+void
+smb_llist_remove(
+ smb_llist_t *ll,
+ void *obj)
+{
+ list_remove(&ll->ll_list, obj);
+ ++ll->ll_wrop;
+ --ll->ll_count;
+}
+
+/*
+ * smb_llist_get_count
+ *
+ * This function returns the number of elements in the specified list.
+ */
+uint32_t
+smb_llist_get_count(
+ smb_llist_t *ll)
+{
+ return (ll->ll_count);
+}
+
+/*
+ * smb_slist_constructor
+ *
+ * Synchronized list constructor.
+ */
+void
+smb_slist_constructor(
+ smb_slist_t *sl,
+ size_t size,
+ size_t offset)
+{
+ mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL);
+ list_create(&sl->sl_list, size, offset);
+ sl->sl_count = 0;
+ sl->sl_waiting = B_FALSE;
+}
+
+/*
+ * smb_slist_destructor
+ *
+ * Synchronized list destructor.
+ */
+void
+smb_slist_destructor(
+ smb_slist_t *sl)
+{
+ ASSERT(sl->sl_count == 0);
+
+ mutex_destroy(&sl->sl_mutex);
+ cv_destroy(&sl->sl_cv);
+ list_destroy(&sl->sl_list);
+}
+
+/*
+ * smb_slist_insert_head
+ *
+ * This function inserts the object passed a the beginning of the list.
+ */
+void
+smb_slist_insert_head(
+ smb_slist_t *sl,
+ void *obj)
+{
+ mutex_enter(&sl->sl_mutex);
+ list_insert_head(&sl->sl_list, obj);
+ ++sl->sl_count;
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_slist_insert_tail
+ *
+ * This function appends the object passed to the list.
+ */
+void
+smb_slist_insert_tail(
+ smb_slist_t *sl,
+ void *obj)
+{
+ mutex_enter(&sl->sl_mutex);
+ list_insert_tail(&sl->sl_list, obj);
+ ++sl->sl_count;
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_llist_remove
+ *
+ * This function removes the object passed by the caller from the list.
+ */
+void
+smb_slist_remove(
+ smb_slist_t *sl,
+ void *obj)
+{
+ mutex_enter(&sl->sl_mutex);
+ list_remove(&sl->sl_list, obj);
+ if ((--sl->sl_count == 0) && (sl->sl_waiting)) {
+ sl->sl_waiting = B_FALSE;
+ cv_broadcast(&sl->sl_cv);
+ }
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_slist_move_tail
+ *
+ * This function transfers all the contents of the synchronized list to the
+ * list_t provided. It returns the number of objects transferred.
+ */
+uint32_t
+smb_slist_move_tail(
+ list_t *lst,
+ smb_slist_t *sl)
+{
+ uint32_t rv;
+
+ mutex_enter(&sl->sl_mutex);
+ rv = sl->sl_count;
+ if (sl->sl_count) {
+ list_move_tail(lst, &sl->sl_list);
+ sl->sl_count = 0;
+ if (sl->sl_waiting) {
+ sl->sl_waiting = B_FALSE;
+ cv_broadcast(&sl->sl_cv);
+ }
+ }
+ mutex_exit(&sl->sl_mutex);
+ return (rv);
+}
+
+/*
+ * smb_slist_obj_move
+ *
+ * This function moves an object from one list to the end of the other list. It
+ * assumes the mutex of each list has been entered.
+ */
+void
+smb_slist_obj_move(
+ smb_slist_t *dst,
+ smb_slist_t *src,
+ void *obj)
+{
+ ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset);
+ ASSERT(dst->sl_list.list_size == src->sl_list.list_size);
+
+ list_remove(&src->sl_list, obj);
+ list_insert_tail(&dst->sl_list, obj);
+ dst->sl_count++;
+ src->sl_count--;
+ if ((src->sl_count == 0) && (src->sl_waiting)) {
+ src->sl_waiting = B_FALSE;
+ cv_broadcast(&src->sl_cv);
+ }
+}
+
+/*
+ * smb_slist_wait_for_empty
+ *
+ * This function waits for a list to be emptied.
+ */
+void
+smb_slist_wait_for_empty(
+ smb_slist_t *sl)
+{
+ mutex_enter(&sl->sl_mutex);
+ while (sl->sl_count) {
+ sl->sl_waiting = B_TRUE;
+ cv_wait(&sl->sl_cv, &sl->sl_mutex);
+ }
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_slist_exit
+ *
+ * This function exits the muetx of the list and signal the condition variable
+ * if the list is empty.
+ */
+void
+smb_slist_exit(smb_slist_t *sl)
+{
+ if ((sl->sl_count == 0) && (sl->sl_waiting)) {
+ sl->sl_waiting = B_FALSE;
+ cv_broadcast(&sl->sl_cv);
+ }
+ mutex_exit(&sl->sl_mutex);
+}
+
+/*
+ * smb_thread_entry_point
+ *
+ * Common entry point for all the threads created through smb_thread_start. The
+ * state of teh thread is set to "running" at the beginning and moved to
+ * "exiting" just before calling thread_exit(). The condition variable is
+ * also signaled.
+ */
+static void
+smb_thread_entry_point(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+ mutex_enter(&thread->sth_mtx);
+ ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING);
+ thread->sth_th = curthread;
+ thread->sth_did = thread->sth_th->t_did;
+
+ if (!thread->sth_kill) {
+ thread->sth_state = SMB_THREAD_STATE_RUNNING;
+ cv_signal(&thread->sth_cv);
+ mutex_exit(&thread->sth_mtx);
+ thread->sth_ep(thread, thread->sth_ep_arg);
+ mutex_enter(&thread->sth_mtx);
+ }
+ thread->sth_th = NULL;
+ thread->sth_state = SMB_THREAD_STATE_EXITING;
+ cv_broadcast(&thread->sth_cv);
+ mutex_exit(&thread->sth_mtx);
+ thread_exit();
+}
+
+/*
+ * smb_thread_init
+ */
+void
+smb_thread_init(
+ smb_thread_t *thread,
+ char *name,
+ smb_thread_ep_t ep,
+ void *ep_arg,
+ smb_thread_aw_t aw,
+ void *aw_arg)
+{
+ ASSERT(thread->sth_magic != SMB_THREAD_MAGIC);
+
+ bzero(thread, sizeof (*thread));
+
+ (void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name));
+ thread->sth_ep = ep;
+ thread->sth_ep_arg = ep_arg;
+ thread->sth_aw = aw;
+ thread->sth_aw_arg = aw_arg;
+ thread->sth_state = SMB_THREAD_STATE_EXITED;
+ mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL);
+ thread->sth_magic = SMB_THREAD_MAGIC;
+}
+
+/*
+ * smb_thread_destroy
+ */
+void
+smb_thread_destroy(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+ ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED);
+ thread->sth_magic = 0;
+ mutex_destroy(&thread->sth_mtx);
+ cv_destroy(&thread->sth_cv);
+}
+
+/*
+ * smb_thread_start
+ *
+ * This function starts a thread with the parameters provided. It waits until
+ * the state of the thread has been moved to running.
+ */
+/*ARGSUSED*/
+int
+smb_thread_start(
+ smb_thread_t *thread)
+{
+ int rc = 0;
+ kthread_t *tmpthread;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ switch (thread->sth_state) {
+ case SMB_THREAD_STATE_EXITED:
+ thread->sth_state = SMB_THREAD_STATE_STARTING;
+ mutex_exit(&thread->sth_mtx);
+ tmpthread = thread_create(NULL, 0, smb_thread_entry_point,
+ thread, 0, &p0, TS_RUN, minclsyspri);
+ ASSERT(tmpthread != NULL);
+ mutex_enter(&thread->sth_mtx);
+ while (thread->sth_state == SMB_THREAD_STATE_STARTING)
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ if (thread->sth_state != SMB_THREAD_STATE_RUNNING)
+ rc = -1;
+ break;
+ default:
+ ASSERT(0);
+ rc = -1;
+ break;
+ }
+ mutex_exit(&thread->sth_mtx);
+ return (rc);
+}
+
+/*
+ * smb_thread_stop
+ *
+ * This function signals a thread to kill itself and waits until the "exiting"
+ * state has been reached.
+ */
+void
+smb_thread_stop(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ switch (thread->sth_state) {
+ case SMB_THREAD_STATE_RUNNING:
+ case SMB_THREAD_STATE_STARTING:
+ if (!thread->sth_kill) {
+ thread->sth_kill = B_TRUE;
+ if (thread->sth_aw)
+ thread->sth_aw(thread, thread->sth_aw_arg);
+ cv_broadcast(&thread->sth_cv);
+ while (thread->sth_state != SMB_THREAD_STATE_EXITING)
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ mutex_exit(&thread->sth_mtx);
+ thread_join(thread->sth_did);
+ mutex_enter(&thread->sth_mtx);
+ thread->sth_state = SMB_THREAD_STATE_EXITED;
+ thread->sth_did = 0;
+ thread->sth_kill = B_FALSE;
+ cv_broadcast(&thread->sth_cv);
+ break;
+ }
+ /*FALLTHRU*/
+
+ case SMB_THREAD_STATE_EXITING:
+ if (thread->sth_kill) {
+ while (thread->sth_state != SMB_THREAD_STATE_EXITED)
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ } else {
+ thread->sth_state = SMB_THREAD_STATE_EXITED;
+ thread->sth_did = 0;
+ }
+ break;
+
+ case SMB_THREAD_STATE_EXITED:
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+ mutex_exit(&thread->sth_mtx);
+}
+
+/*
+ * smb_thread_signal
+ *
+ * This function signals a thread.
+ */
+void
+smb_thread_signal(
+ smb_thread_t *thread)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ switch (thread->sth_state) {
+ case SMB_THREAD_STATE_RUNNING:
+ if (thread->sth_aw)
+ thread->sth_aw(thread, thread->sth_aw_arg);
+ cv_signal(&thread->sth_cv);
+ break;
+
+ default:
+ break;
+ }
+ mutex_exit(&thread->sth_mtx);
+}
+
+boolean_t
+smb_thread_continue(smb_thread_t *thread)
+{
+ boolean_t result;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ result = smb_thread_continue_timedwait_locked(thread, 0);
+ mutex_exit(&thread->sth_mtx);
+
+ return (result);
+}
+
+boolean_t
+smb_thread_continue_nowait(smb_thread_t *thread)
+{
+ boolean_t result;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ /*
+ * Setting ticks=-1 requests a non-blocking check. We will
+ * still block if the thread is in "suspend" state.
+ */
+ result = smb_thread_continue_timedwait_locked(thread, -1);
+ mutex_exit(&thread->sth_mtx);
+
+ return (result);
+}
+
+boolean_t
+smb_thread_continue_timedwait(smb_thread_t *thread, int seconds)
+{
+ boolean_t result;
+
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ result = smb_thread_continue_timedwait_locked(thread,
+ SEC_TO_TICK(seconds));
+ mutex_exit(&thread->sth_mtx);
+
+ return (result);
+}
+
+/*
+ * smb_thread_continue_timedwait_locked
+ *
+ * Internal only. Ticks==-1 means don't block, Ticks == 0 means wait
+ * indefinitely
+ */
+static boolean_t
+smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks)
+{
+ boolean_t result;
+ clock_t finish_time = lbolt + ticks;
+
+ /* -1 means don't block */
+ if (ticks != -1 && !thread->sth_kill) {
+ if (ticks == 0) {
+ cv_wait(&thread->sth_cv, &thread->sth_mtx);
+ } else {
+ (void) cv_timedwait(&thread->sth_cv, &thread->sth_mtx,
+ finish_time);
+ }
+ }
+ result = (thread->sth_kill == 0);
+
+ return (result);
+}
+
+void
+smb_thread_set_awaken(smb_thread_t *thread, smb_thread_aw_t new_aw_fn,
+ void *new_aw_arg)
+{
+ ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
+
+ mutex_enter(&thread->sth_mtx);
+ thread->sth_aw = new_aw_fn;
+ thread->sth_aw_arg = new_aw_arg;
+ mutex_exit(&thread->sth_mtx);
+}
+
+/*
+ * smb_rwx_init
+ */
+void
+smb_rwx_init(
+ smb_rwx_t *rwx)
+{
+ bzero(rwx, sizeof (smb_rwx_t));
+ cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL);
+ mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
+ rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
+}
+
+/*
+ * smb_rwx_destroy
+ */
+void
+smb_rwx_destroy(
+ smb_rwx_t *rwx)
+{
+ mutex_destroy(&rwx->rwx_mutex);
+ cv_destroy(&rwx->rwx_cv);
+ rw_destroy(&rwx->rwx_lock);
+}
+
+/*
+ * smb_rwx_rwexit
+ */
+void
+smb_rwx_rwexit(
+ smb_rwx_t *rwx)
+{
+ if (rw_write_held(&rwx->rwx_lock)) {
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+ mutex_enter(&rwx->rwx_mutex);
+ if (rwx->rwx_waiting) {
+ rwx->rwx_waiting = B_FALSE;
+ cv_broadcast(&rwx->rwx_cv);
+ }
+ mutex_exit(&rwx->rwx_mutex);
+ }
+ rw_exit(&rwx->rwx_lock);
+}
+
+/*
+ * smb_rwx_rwupgrade
+ */
+krw_t
+smb_rwx_rwupgrade(
+ smb_rwx_t *rwx)
+{
+ if (rw_write_held(&rwx->rwx_lock)) {
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+ return (RW_WRITER);
+ }
+ if (!rw_tryupgrade(&rwx->rwx_lock)) {
+ rw_exit(&rwx->rwx_lock);
+ rw_enter(&rwx->rwx_lock, RW_WRITER);
+ }
+ return (RW_READER);
+}
+
+/*
+ * smb_rwx_rwrestore
+ */
+void
+smb_rwx_rwdowngrade(
+ smb_rwx_t *rwx,
+ krw_t mode)
+{
+ ASSERT(rw_write_held(&rwx->rwx_lock));
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+
+ if (mode == RW_WRITER) {
+ return;
+ }
+ ASSERT(mode == RW_READER);
+ mutex_enter(&rwx->rwx_mutex);
+ if (rwx->rwx_waiting) {
+ rwx->rwx_waiting = B_FALSE;
+ cv_broadcast(&rwx->rwx_cv);
+ }
+ mutex_exit(&rwx->rwx_mutex);
+ rw_downgrade(&rwx->rwx_lock);
+}
+
+/*
+ * smb_rwx_wait
+ *
+ * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
+ * mode. It will:
+ *
+ * 1) release the lock and save its current mode.
+ * 2) wait until the condition variable is signaled. This can happen for
+ * 2 reasons: When a writer releases the lock or when the time out (if
+ * provided) expires.
+ * 3) re-acquire the lock in the mode saved in (1).
+ */
+int
+smb_rwx_rwwait(
+ smb_rwx_t *rwx,
+ clock_t timeout)
+{
+ int rc;
+ krw_t mode;
+
+ mutex_enter(&rwx->rwx_mutex);
+ rwx->rwx_waiting = B_TRUE;
+ mutex_exit(&rwx->rwx_mutex);
+
+ if (rw_write_held(&rwx->rwx_lock)) {
+ ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
+ mode = RW_WRITER;
+ } else {
+ ASSERT(rw_read_held(&rwx->rwx_lock));
+ mode = RW_READER;
+ }
+ rw_exit(&rwx->rwx_lock);
+
+ mutex_enter(&rwx->rwx_mutex);
+ if (rwx->rwx_waiting) {
+ if (timeout == -1) {
+ rc = 1;
+ cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
+ } else {
+ rc = cv_timedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
+ lbolt + timeout);
+ }
+ }
+ mutex_exit(&rwx->rwx_mutex);
+
+ rw_enter(&rwx->rwx_lock, mode);
+ return (rc);
+}
+
+/*
+ * SMB ID mapping
+ *
+ * Solaris ID mapping service (aka Winchester) works with domain SIDs
+ * and RIDs where domain SIDs are in string format. CIFS service works
+ * with binary SIDs understandable by CIFS clients. A layer of SMB ID
+ * mapping functions are implemeted to hide the SID conversion details
+ * and also hide the handling of array of batch mapping requests.
+ */
+
+static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
+
+/*
+ * smb_idmap_getid
+ *
+ * Maps the given Windows SID to a Solaris ID using the
+ * simple mapping API.
+ */
+idmap_stat
+smb_idmap_getid(nt_sid_t *sid, uid_t *id, int *idtype)
+{
+ smb_idmap_t sim;
+ nt_sid_t *tmpsid;
+
+ tmpsid = nt_sid_dup(sid);
+ (void) nt_sid_split(tmpsid, &sim.sim_rid);
+ sim.sim_domsid = nt_sid_format(tmpsid);
+ MEM_FREE("smbsrv", tmpsid);
+ sim.sim_id = id;
+
+ switch (*idtype) {
+ case SMB_IDMAP_USER:
+ sim.sim_stat = kidmap_getuidbysid(sim.sim_domsid,
+ sim.sim_rid, sim.sim_id);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ sim.sim_stat = kidmap_getgidbysid(sim.sim_domsid,
+ sim.sim_rid, sim.sim_id);
+ break;
+
+ case SMB_IDMAP_UNKNOWN:
+ sim.sim_stat = kidmap_getpidbysid(sim.sim_domsid,
+ sim.sim_rid, sim.sim_id, &sim.sim_idtype);
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ *idtype = sim.sim_idtype;
+ MEM_FREE("smbsrv", sim.sim_domsid);
+
+ return (sim.sim_stat);
+}
+
+/*
+ * smb_idmap_getsid
+ *
+ * Maps the given Solaris ID to a Windows SID using the
+ * simple mapping API.
+ */
+idmap_stat
+smb_idmap_getsid(uid_t id, int idtype, nt_sid_t **sid)
+{
+ smb_idmap_t sim;
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ sim.sim_stat = kidmap_getsidbyuid(id,
+ (const char **)&sim.sim_domsid, &sim.sim_rid);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ sim.sim_stat = kidmap_getsidbygid(id,
+ (const char **)&sim.sim_domsid, &sim.sim_rid);
+ break;
+
+ case SMB_IDMAP_EVERYONE:
+ /* Everyone S-1-1-0 */
+ sim.sim_domsid = "S-1-1";
+ sim.sim_rid = 0;
+ sim.sim_stat = IDMAP_SUCCESS;
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ if (sim.sim_stat != IDMAP_SUCCESS)
+ return (sim.sim_stat);
+
+ if (sim.sim_domsid == NULL) {
+ return (IDMAP_ERR_NOMAPPING);
+ }
+
+ sim.sim_sid = nt_sid_strtosid(sim.sim_domsid);
+ if (sim.sim_sid == NULL) {
+ return (IDMAP_ERR_INTERNAL);
+ }
+
+ *sid = nt_sid_splice(sim.sim_sid, sim.sim_rid);
+ MEM_FREE("smbsrv", sim.sim_sid);
+ if (*sid == NULL)
+ sim.sim_stat = IDMAP_ERR_INTERNAL;
+
+ return (sim.sim_stat);
+}
+
+/*
+ * smb_idmap_batch_create
+ *
+ * Creates and initializes the context for batch ID mapping.
+ */
+idmap_stat
+smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
+{
+ ASSERT(sib);
+
+ bzero(sib, sizeof (smb_idmap_batch_t));
+
+ sib->sib_idmaph = kidmap_get_create();
+ if (sib->sib_idmaph == NULL)
+ return (IDMAP_ERR_INTERNAL);
+
+ sib->sib_flags = flags;
+ sib->sib_nmap = nmap;
+ sib->sib_size = nmap * sizeof (smb_idmap_t);
+ sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
+
+ return (IDMAP_SUCCESS);
+}
+
+/*
+ * smb_idmap_batch_destroy
+ *
+ * Frees the batch ID mapping context.
+ * If ID mapping is Solaris -> Windows it frees memories
+ * allocated for binary SIDs.
+ */
+void
+smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
+{
+ nt_sid_t *sid;
+ char *domsid;
+ int i;
+
+ ASSERT(sib);
+ ASSERT(sib->sib_maps);
+
+ if (sib->sib_idmaph)
+ kidmap_get_destroy(sib->sib_idmaph);
+
+ if (sib->sib_flags & SMB_IDMAP_ID2SID) {
+ /*
+ * SIDs are allocated only when mapping
+ * UID/GID to SIDs
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ sid = sib->sib_maps[i].sim_sid;
+ if (sid)
+ MEM_FREE("smbsrv", sid);
+ }
+ } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
+ /*
+ * SID prefixes are allocated only when mapping
+ * SIDs to UID/GID
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ domsid = sib->sib_maps[i].sim_domsid;
+ if (domsid)
+ MEM_FREE("smbsrv", domsid);
+ }
+ }
+
+ if (sib->sib_size && sib->sib_maps)
+ kmem_free(sib->sib_maps, sib->sib_size);
+}
+
+/*
+ * smb_idmap_batch_getid
+ *
+ * Queue a request to map the given SID to a UID or GID.
+ *
+ * sim->sim_id should point to variable that's supposed to
+ * hold the returned UID/GID. This needs to be setup by caller
+ * of this function.
+ *
+ * If requested ID type is known, it's passed as 'idtype',
+ * if it's unknown it'll be returned in sim->sim_idtype.
+ */
+idmap_stat
+smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
+ nt_sid_t *sid, int idtype)
+{
+ nt_sid_t *tmpsid;
+ idmap_stat idm_stat;
+
+ ASSERT(idmaph);
+ ASSERT(sim);
+ ASSERT(sid);
+
+ tmpsid = nt_sid_dup(sid);
+ (void) nt_sid_split(tmpsid, &sim->sim_rid);
+ sim->sim_domsid = nt_sid_format(tmpsid);
+ MEM_FREE("smbsrv", tmpsid);
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, sim->sim_id, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, sim->sim_id, &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_UNKNOWN:
+ idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
+ sim->sim_rid, sim->sim_id, &sim->sim_idtype,
+ &sim->sim_stat);
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ return (idm_stat);
+}
+
+/*
+ * smb_idmap_batch_getsid
+ *
+ * Queue a request to map the given UID/GID to a SID.
+ *
+ * sim->sim_domsid and sim->sim_rid will contain the mapping
+ * result upon successful process of the batched request.
+ */
+idmap_stat
+smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
+ uid_t id, int idtype)
+{
+ idmap_stat idm_stat;
+
+ switch (idtype) {
+ case SMB_IDMAP_USER:
+ idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
+ (const char **)&sim->sim_domsid, &sim->sim_rid,
+ &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_GROUP:
+ idm_stat = kidmap_batch_getsidbygid(idmaph, id,
+ (const char **)&sim->sim_domsid, &sim->sim_rid,
+ &sim->sim_stat);
+ break;
+
+ case SMB_IDMAP_EVERYONE:
+ /* Everyone S-1-1-0 */
+ sim->sim_domsid = "S-1-1";
+ sim->sim_rid = 0;
+ sim->sim_stat = IDMAP_SUCCESS;
+ idm_stat = IDMAP_SUCCESS;
+ break;
+
+ default:
+ ASSERT(0);
+ return (IDMAP_ERR_ARG);
+ }
+
+ return (idm_stat);
+}
+
+/*
+ * smb_idmap_batch_binsid
+ *
+ * Convert sidrids to binary sids
+ *
+ * Returns 0 if successful and non-zero upon failure.
+ */
+static int
+smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
+{
+ nt_sid_t *sid;
+ smb_idmap_t *sim;
+ int i;
+
+ if (sib->sib_flags & SMB_IDMAP_SID2ID)
+ /* This operation is not required */
+ return (0);
+
+ sim = sib->sib_maps;
+ for (i = 0; i < sib->sib_nmap; sim++, i++) {
+ ASSERT(sim->sim_domsid);
+ if (sim->sim_domsid == NULL) {
+ return (1);
+ }
+
+ sid = nt_sid_strtosid(sim->sim_domsid);
+ if (sid == NULL) {
+ return (1);
+ }
+
+ sim->sim_sid = nt_sid_splice(sid, sim->sim_rid);
+ MEM_FREE("smbsrv", sid);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_idmap_batch_getmappings
+ *
+ * trigger ID mapping service to get the mappings for queued
+ * requests.
+ *
+ * Checks the result of all the queued requests.
+ * If this is a Solaris -> Windows mapping it generates
+ * binary SIDs from returned (domsid, rid) pairs.
+ */
+idmap_stat
+smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
+{
+ idmap_stat idm_stat = IDMAP_SUCCESS;
+ int i;
+
+ idm_stat = kidmap_get_mappings(sib->sib_idmaph);
+ if (idm_stat != IDMAP_SUCCESS) {
+ return (idm_stat);
+ }
+
+ /*
+ * Check the status for all the queued requests
+ */
+ for (i = 0; i < sib->sib_nmap; i++) {
+ if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) {
+ return (sib->sib_maps[i].sim_stat);
+ }
+ }
+
+ if (smb_idmap_batch_binsid(sib) != 0) {
+ idm_stat = IDMAP_ERR_OTHER;
+ }
+
+ return (idm_stat);
+}
+
+uint64_t
+unix_to_nt_time(timestruc_t *unix_time)
+{
+ uint64_t nt_time;
+
+ nt_time = unix_time->tv_sec;
+ nt_time *= 10000000; /* seconds to 100ns */
+ nt_time += unix_time->tv_nsec / 100;
+ return (nt_time + NT_TIME_BIAS);
+}
+
+uint32_t
+nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time)
+{
+ uint32_t seconds;
+
+ nt_time -= NT_TIME_BIAS;
+ seconds = nt_time / 10000000;
+ if (unix_time) {
+ unix_time->tv_sec = seconds;
+ unix_time->tv_nsec = (nt_time % 10000000) * 100;
+ }
+ return (seconds);
+}
+
+int32_t /*ARGSUSED*/
+dosfs_dos_to_ux_time(int32_t date, int time)
+{
+ struct tm atm;
+
+ atm.tm_year = ((date >> 9) & 0x3F) + 80;
+ atm.tm_mon = ((date >> 5) & 0x0F) - 1;
+ atm.tm_mday = ((date >> 0) & 0x1F);
+ atm.tm_hour = ((time >> 11) & 0x1F);
+ atm.tm_min = ((time >> 5) & 0x3F);
+ atm.tm_sec = ((time >> 0) & 0x1F) << 1;
+
+ return (smb_timegm(&atm));
+}
+
+int32_t /*ARGSUSED*/
+dosfs_ux_to_dos_time(int32_t ux_time, short *date_p, short *time_p)
+{
+ struct tm atm;
+ int i;
+ time_t tmp_time;
+
+ tmp_time = (time_t)ux_time;
+ (void) smb_gmtime_r(&tmp_time, &atm);
+
+ if (date_p) {
+ i = 0;
+ i += atm.tm_year - 80;
+ i <<= 4;
+ i += atm.tm_mon + 1;
+ i <<= 5;
+ i += atm.tm_mday;
+
+ *date_p = (short)i;
+ }
+ if (time_p) {
+ i = 0;
+ i += atm.tm_hour;
+ i <<= 6;
+ i += atm.tm_min;
+ i <<= 5;
+ i += atm.tm_sec >> 1;
+
+ *time_p = (short)i;
+ }
+ return (ux_time);
+}
+
+
+/*
+ * smb_gmtime_r
+ *
+ * Thread-safe version of smb_gmtime. Returns a null pointer if either
+ * input parameter is a null pointer. Otherwise returns a pointer
+ * to result.
+ *
+ * Day of the week calculation: the Epoch was a thursday.
+ *
+ * There are no timezone corrections so tm_isdst and tm_gmtoff are
+ * always zero, and the zone is always WET.
+ */
+struct tm *
+smb_gmtime_r(time_t *clock, struct tm *result)
+{
+ time_t tsec;
+ int year;
+ int month;
+ int sec_per_month;
+
+ if (clock == 0 || result == 0)
+ return (0);
+
+ bzero(result, sizeof (struct tm));
+ tsec = *clock;
+ tsec -= tzh_leapcnt;
+
+ result->tm_wday = tsec / SECSPERDAY;
+ result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK;
+
+ year = EPOCH_YEAR;
+ while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) :
+ (SECSPERDAY * DAYSPERNYEAR))) {
+ if (isleap(year))
+ tsec -= SECSPERDAY * DAYSPERLYEAR;
+ else
+ tsec -= SECSPERDAY * DAYSPERNYEAR;
+
+ ++year;
+ }
+
+ result->tm_year = year - TM_YEAR_BASE;
+ result->tm_yday = tsec / SECSPERDAY;
+
+ for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) {
+ sec_per_month = days_in_month[month] * SECSPERDAY;
+
+ if (month == TM_FEBRUARY && isleap(year))
+ sec_per_month += SECSPERDAY;
+
+ if (tsec < sec_per_month)
+ break;
+
+ tsec -= sec_per_month;
+ }
+
+ result->tm_mon = month;
+ result->tm_mday = (tsec / SECSPERDAY) + 1;
+ tsec %= SECSPERDAY;
+ result->tm_sec = tsec % 60;
+ tsec /= 60;
+ result->tm_min = tsec % 60;
+ tsec /= 60;
+ result->tm_hour = (int)tsec;
+
+ return (result);
+}
+
+
+/*
+ * smb_timegm
+ *
+ * Converts the broken-down time in tm to a time value, i.e. the number
+ * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
+ * not a POSIX or ANSI function. Per the man page, the input values of
+ * tm_wday and tm_yday are ignored and, as the input data is assumed to
+ * represent GMT, we force tm_isdst and tm_gmtoff to 0.
+ *
+ * Before returning the clock time, we use smb_gmtime_r to set up tm_wday
+ * and tm_yday, and bring the other fields within normal range. I don't
+ * think this is really how it should be done but it's convenient for
+ * now.
+ */
+time_t
+smb_timegm(struct tm *tm)
+{
+ time_t tsec;
+ int dd;
+ int mm;
+ int yy;
+ int year;
+
+ if (tm == 0)
+ return (-1);
+
+ year = tm->tm_year + TM_YEAR_BASE;
+ tsec = tzh_leapcnt;
+
+ for (yy = EPOCH_YEAR; yy < year; ++yy) {
+ if (isleap(yy))
+ tsec += SECSPERDAY * DAYSPERLYEAR;
+ else
+ tsec += SECSPERDAY * DAYSPERNYEAR;
+ }
+
+ for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) {
+ dd = days_in_month[mm] * SECSPERDAY;
+
+ if (mm == TM_FEBRUARY && isleap(year))
+ dd += SECSPERDAY;
+
+ tsec += dd;
+ }
+
+ tsec += (tm->tm_mday - 1) * SECSPERDAY;
+ tsec += tm->tm_sec;
+ tsec += tm->tm_min * SECSPERMIN;
+ tsec += tm->tm_hour * SECSPERHOUR;
+
+ tm->tm_isdst = 0;
+ (void) smb_gmtime_r(&tsec, tm);
+ return (tsec);
+}
+
+#ifdef DEBUG
+uint32_t smb_audit_flags = SMB_AUDIT_NODE;
+#else
+uint32_t smb_audit_flags = 0;
+#endif
+
+void
+smb_audit_buf_node_create(smb_node_t *node)
+{
+ smb_audit_buf_node_t *abn;
+
+ if (smb_audit_flags & SMB_AUDIT_NODE) {
+ abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), KM_SLEEP);
+ abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
+ node->n_audit_buf = abn;
+ }
+}
+
+void
+smb_audit_buf_node_destroy(smb_node_t *node)
+{
+ smb_audit_buf_node_t *abn;
+
+ abn = node->n_audit_buf;
+
+ if (abn) {
+ node->n_audit_buf = NULL;
+ kmem_free(abn, sizeof (smb_audit_buf_node_t));
+ }
+}
+
+/*
+ * smb_cred_set_sid
+ *
+ * Initialize the ksid based on the given smb_id_t.
+ */
+static void
+smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
+{
+ nt_sid_t *domain_sid = NULL;
+ char *domain_sid_buf = NULL;
+ int rc;
+
+ ASSERT(id);
+ ASSERT(id->i_sidattr.sid);
+
+ ksid->ks_id = id->i_id;
+ domain_sid = nt_sid_dup(id->i_sidattr.sid);
+ rc = nt_sid_split(domain_sid, &ksid->ks_rid);
+ ASSERT(rc == 0);
+
+ ksid->ks_attr = id->i_sidattr.attrs;
+ domain_sid_buf = nt_sid_format(domain_sid);
+ ksid->ks_domain = ksid_lookupdomain(domain_sid_buf);
+ MEM_FREE("smbsrv", domain_sid);
+ MEM_FREE("smbsrv", domain_sid_buf);
+}
+
+/*
+ * smb_cred_set_sidlist
+ *
+ * Allocate and initialize the ksidlist based on the Windows group list of the
+ * access token.
+ */
+static ksidlist_t *
+smb_cred_set_sidlist(smb_win_grps_t *token_grps)
+{
+ int i;
+ ksidlist_t *lp;
+
+ lp = kmem_zalloc(KSIDLIST_MEM(token_grps->wg_count), KM_SLEEP);
+ lp->ksl_ref = 1;
+ lp->ksl_nsid = token_grps->wg_count;
+ lp->ksl_neid = 0;
+
+ for (i = 0; i < lp->ksl_nsid; i++) {
+ smb_cred_set_sid(&token_grps->wg_groups[i],
+ &lp->ksl_sids[i]);
+ if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
+ lp->ksl_neid++;
+ }
+
+ return (lp);
+}
+
+/*
+ * smb_cred_create
+ *
+ * The credential of the given SMB user will be allocated and initialized based
+ * on the given access token.
+ */
+cred_t *
+smb_cred_create(smb_token_t *token, uint32_t *privileges)
+{
+ ksid_t ksid;
+ ksidlist_t *ksidlist = NULL;
+ smb_posix_grps_t *posix_grps;
+ cred_t *cr;
+
+ ASSERT(token);
+ ASSERT(token->tkn_posix_grps);
+ ASSERT(privileges);
+
+ cr = crget();
+ ASSERT(cr != NULL);
+
+ posix_grps = token->tkn_posix_grps;
+ if (crsetugid(cr, token->tkn_user->i_id,
+ token->tkn_primary_grp->i_id) != 0) {
+ crfree(cr);
+ return (NULL);
+ }
+
+ if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
+ crfree(cr);
+ return (NULL);
+ }
+
+ smb_cred_set_sid(token->tkn_user, &ksid);
+ crsetsid(cr, &ksid, KSID_USER);
+ smb_cred_set_sid(token->tkn_primary_grp, &ksid);
+ crsetsid(cr, &ksid, KSID_GROUP);
+ smb_cred_set_sid(token->tkn_owner, &ksid);
+ crsetsid(cr, &ksid, KSID_OWNER);
+ ksidlist = smb_cred_set_sidlist(token->tkn_win_grps);
+ crsetsidlist(cr, ksidlist);
+
+ *privileges = 0;
+
+ /*
+ * Support for backup and restore privileges will be disabled until
+ * the BACKUP_SEMANTICS and backup intent attributes are supported.
+ */
+#ifdef SUPPORT_FILE_OPEN_FOR_BACKUP
+ if (smb_token_query_privilege(token, SE_BACKUP_LUID)) {
+ *privileges |= SMB_USER_PRIV_BACKUP;
+ (void) crsetpriv(cr, PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
+ }
+
+ if (smb_token_query_privilege(token, SE_RESTORE_LUID)) {
+ *privileges |= SMB_USER_PRIV_RESTORE;
+ (void) crsetpriv(cr, PRIV_FILE_DAC_WRITE,
+ PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
+ PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
+ PRIV_FILE_OWNER, PRIV_FILE_SETID, PRIV_SYS_LINKDIR,
+ PRIV_SYS_MOUNT, NULL);
+ }
+#endif /* SUPPORT_FILE_OPEN_FOR_BACKUP */
+
+ if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
+ *privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
+ (void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL);
+ }
+
+ if (smb_token_query_privilege(token, SE_SECURITY_LUID)) {
+ *privileges |= SMB_USER_PRIV_SECURITY;
+ }
+ return (cr);
+}
+
+/*
+ * smb_cred_rele
+ *
+ * The reference count of the user's credential will get decremented if it
+ * is non-zero. Otherwise, the credential will be freed.
+ */
+void
+smb_cred_rele(cred_t *cr)
+{
+ ASSERT(cr);
+ crfree(cr);
+}
+
+/*
+ * smb_cred_is_member
+ *
+ * Same as smb_token_is_member. The only difference is that
+ * we compare the given SID against user SID and the ksidlist
+ * of the user's cred.
+ */
+int
+smb_cred_is_member(cred_t *cr, nt_sid_t *sid)
+{
+ ksidlist_t *ksidlist;
+ ksid_t ksid1, *ksid2;
+ smb_id_t id;
+ int i, rc = 0;
+
+ ASSERT(cr);
+
+ bzero(&id, sizeof (smb_id_t));
+ id.i_sidattr.sid = sid;
+ smb_cred_set_sid(&id, &ksid1);
+
+ ksidlist = crgetsidlist(cr);
+ ASSERT(ksidlist);
+ ASSERT(ksid1.ks_domain);
+ ASSERT(ksid1.ks_domain->kd_name);
+
+ i = 0;
+ ksid2 = crgetsid(cr, KSID_USER);
+ do {
+ ASSERT(ksid2->ks_domain);
+ ASSERT(ksid2->ks_domain->kd_name);
+
+ if (strcmp(ksid1.ks_domain->kd_name,
+ ksid2->ks_domain->kd_name) == 0 &&
+ ksid1.ks_rid == ksid2->ks_rid) {
+ rc = 1;
+ break;
+ }
+
+ ksid2 = &ksidlist->ksl_sids[i];
+ } while (i++ < ksidlist->ksl_nsid);
+
+ ksid_rele(&ksid1);
+ return (rc);
+}
+
+/*
+ * smb_kstrdup
+ *
+ * Duplicate the given string s.
+ */
+char *
+smb_kstrdup(const char *s, size_t n)
+{
+ char *s2;
+
+ ASSERT(s);
+ ASSERT(n);
+ s2 = kmem_alloc(n, KM_SLEEP);
+ (void) strcpy(s2, s);
+ return (s2);
+}
+
+/*
+ * smb_sync_fsattr
+ *
+ * Sync file's attributes with file system.
+ * The sync takes place based on node->what and node->flags
+ * values.
+ */
+int
+smb_sync_fsattr(struct smb_request *sr, cred_t *cr, smb_node_t *node)
+{
+ uint32_t what;
+ int rc = 0;
+
+ if (node->flags & NODE_READ_ONLY)
+ return (0);
+
+ if (node->flags & NODE_FLAGS_SET_SIZE) {
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+ node->what |= SMB_AT_SIZE;
+ node->attr.sa_vattr.va_size = node->n_size;
+ }
+
+ if (node->what) {
+ /*
+ * This is to prevent another thread from starting
+ * a setattr should this one go to sleep
+ */
+ what = node->what;
+ node->what = 0;
+
+ node->attr.sa_mask = what;
+
+ rc = smb_fsop_setattr(sr, cr, node, &node->attr, &node->attr);
+
+ if (rc) {
+ /* setattr failed, restore the dirty state? */
+ node->what = what;
+ }
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_share_export()
+ *
+ * This function handles kernel processing at share enable time.
+ *
+ * At share-enable time (LMSHRD_ADD), the file system corresponding to
+ * the share is checked for characteristics that are required for SMB
+ * sharing. If this check passes, then a hold is taken on the root vnode
+ * of the file system (or a reference count on the corresponding smb_vfs_t
+ * is bumped), preventing an unmount. (See smb_vfs_hold()).
+ */
+
+int
+smb_share_export(char *path)
+{
+ int error;
+ smb_node_t *fnode = NULL;
+ smb_node_t *dnode;
+ smb_attr_t ret_attr;
+ char last_comp[MAXNAMELEN];
+
+ error = smb_pathname_reduce(NULL, kcred, path, NULL, NULL, &dnode,
+ last_comp);
+
+ if (error)
+ return (error);
+
+ error = smb_fsop_lookup(NULL, kcred, SMB_FOLLOW_LINKS, NULL, dnode,
+ last_comp, &fnode, &ret_attr, NULL, NULL);
+
+ smb_node_release(dnode);
+
+ if (error)
+ return (error);
+
+ ASSERT(fnode->vp && fnode->vp->v_vfsp);
+
+#ifdef SMB_ENFORCE_NODEV
+ if (vfs_optionisset(fnode->vp->v_vfsp, MNTOPT_NODEVICES, NULL) == 0)
+ return (EINVAL);
+#endif /* SMB_ENFORCE_NODEV */
+
+ if (!smb_vfs_hold(fnode->vp->v_vfsp)) {
+ smb_node_release(fnode);
+ return (ENOMEM);
+ }
+
+ /*
+ * The refcount on the smb_vfs has been incremented.
+ * If it wasn't already, a hold has also been taken
+ * on the root vnode of the file system.
+ */
+
+ smb_node_release(fnode);
+ return (0);
+}
+
+/*
+ * smb_share_unexport()
+ *
+ * This function handles kernel processing at share disable time.
+ *
+ * At share-disable time (LMSHRD_DELETE), the reference count on the
+ * corresponding smb_vfs_t is decremented. If this is the last share
+ * on the file system, the hold on the root vnode of the file system
+ * will be released. (See smb_vfs_rele().)
+ */
+
+int
+smb_share_unexport(char *path, char *sharename)
+{
+ int error;
+ smb_node_t *fnode = NULL;
+ smb_node_t *dnode;
+ smb_attr_t ret_attr;
+ char last_comp[MAXNAMELEN];
+
+ error = smb_pathname_reduce(NULL, kcred, path, NULL, NULL, &dnode,
+ last_comp);
+
+ if (error)
+ return (error);
+
+ error = smb_fsop_lookup(NULL, kcred, SMB_FOLLOW_LINKS, NULL, dnode,
+ last_comp, &fnode, &ret_attr, NULL, NULL);
+
+ smb_node_release(dnode);
+
+ if (error)
+ return (error);
+
+ ASSERT(fnode->vp && fnode->vp->v_vfsp);
+
+ smb_session_disconnect_share(sharename);
+ smb_vfs_rele(fnode->vp->v_vfsp);
+ smb_node_release(fnode);
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vfs.c b/usr/src/uts/common/fs/smbsrv/smb_vfs.c
new file mode 100644
index 0000000000..38928bfe2a
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_vfs.c
@@ -0,0 +1,161 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <sys/vfs.h>
+
+static smb_vfs_t *smb_vfs_lookup(vnode_t *);
+
+/*
+ * smb_vfs_hold
+ *
+ * Increments the reference count of the fs passed in. If no smb_vfs_t structure
+ * has been created yet for the fs passed in it is created.
+ */
+boolean_t
+smb_vfs_hold(vfs_t *vfsp)
+{
+ smb_vfs_t *smb_vfs;
+ vnode_t *rootvp;
+
+ if ((vfsp == NULL) || VFS_ROOT(vfsp, &rootvp))
+ return (B_FALSE);
+
+ smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
+ smb_vfs = smb_vfs_lookup(rootvp);
+ if (smb_vfs) {
+ DTRACE_PROBE1(smb_vfs_hold_hit, smb_vfs_t *, smb_vfs);
+ smb_llist_exit(&smb_info.si_vfs_list);
+ VN_RELE(rootvp);
+ return (B_TRUE);
+ }
+ smb_vfs = kmem_cache_alloc(smb_info.si_cache_vfs, KM_SLEEP);
+
+ bzero(smb_vfs, sizeof (smb_vfs_t));
+
+ smb_vfs->sv_magic = SMB_VFS_MAGIC;
+ smb_vfs->sv_refcnt = 1;
+ smb_vfs->sv_vfsp = vfsp;
+ /*
+ * We have a hold on the root vnode of the file system
+ * from the VFS_ROOT call above.
+ */
+ smb_vfs->sv_rootvp = rootvp;
+ smb_llist_insert_head(&smb_info.si_vfs_list, smb_vfs);
+ DTRACE_PROBE1(smb_vfs_hold_miss, smb_vfs_t *, smb_vfs);
+ smb_llist_exit(&smb_info.si_vfs_list);
+ return (B_TRUE);
+}
+
+/*
+ * smb_vfs_rele
+ *
+ * Decrements the reference count of the fs passed in. If the reference count
+ * drops to zero the smb_vfs_t structure associated with the fs is freed.
+ */
+void
+smb_vfs_rele(vfs_t *vfsp)
+{
+ smb_vfs_t *smb_vfs;
+ vnode_t *rootvp;
+
+ ASSERT(vfsp);
+
+ if (VFS_ROOT(vfsp, &rootvp))
+ return;
+
+ smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
+ smb_vfs = smb_vfs_lookup(rootvp);
+ DTRACE_PROBE2(smb_vfs_release, smb_vfs_t *, smb_vfs, vnode_t *, rootvp);
+ VN_RELE(rootvp);
+ if (smb_vfs) {
+ --smb_vfs->sv_refcnt;
+ ASSERT(smb_vfs->sv_refcnt);
+ if (--smb_vfs->sv_refcnt == 0) {
+ smb_llist_remove(&smb_info.si_vfs_list, smb_vfs);
+ smb_llist_exit(&smb_info.si_vfs_list);
+ ASSERT(rootvp == smb_vfs->sv_rootvp);
+ VN_RELE(smb_vfs->sv_rootvp);
+ smb_vfs->sv_magic = (uint32_t)~SMB_VFS_MAGIC;
+ kmem_cache_free(smb_info.si_cache_vfs, smb_vfs);
+ return;
+ }
+ }
+ smb_llist_exit(&smb_info.si_vfs_list);
+}
+
+/*
+ * smb_vfs_rele_all()
+ *
+ * Release all holds on root vnodes of file systems which were taken
+ * due to the existence of at least one enabled share on the file system.
+ * Called at driver close time.
+ */
+void
+smb_vfs_rele_all()
+{
+ smb_vfs_t *smb_vfs;
+
+ smb_llist_enter(&smb_info.si_vfs_list, RW_WRITER);
+ while ((smb_vfs = smb_llist_head(&smb_info.si_vfs_list)) != NULL) {
+
+ ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC);
+ DTRACE_PROBE1(smb_vfs_rele_all_hit, smb_vfs_t *, smb_vfs);
+ smb_llist_remove(&smb_info.si_vfs_list, smb_vfs);
+ VN_RELE(smb_vfs->sv_rootvp);
+ kmem_cache_free(smb_info.si_cache_vfs, smb_vfs);
+ }
+ smb_llist_exit(&smb_info.si_vfs_list);
+}
+
+/*
+ * smb_vfs_lookup
+ *
+ * Goes through the list of smb_vfs_t structure and returns the one matching
+ * the vnode passed in. If no match is found a NULL pointer is returned.
+ *
+ * The list of smb_vfs_t structures has to have been entered prior calling
+ * this function.
+ */
+static smb_vfs_t *
+smb_vfs_lookup(vnode_t *rootvp)
+{
+ smb_vfs_t *smb_vfs;
+
+ smb_vfs = smb_llist_head(&smb_info.si_vfs_list);
+ while (smb_vfs) {
+ ASSERT(smb_vfs->sv_magic == SMB_VFS_MAGIC);
+ if (smb_vfs->sv_rootvp == rootvp) {
+ smb_vfs->sv_refcnt++;
+ ASSERT(smb_vfs->sv_refcnt);
+ return (smb_vfs);
+ }
+ smb_vfs = smb_llist_next(&smb_info.si_vfs_list, smb_vfs);
+ }
+ return (NULL);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c
new file mode 100644
index 0000000000..b71174e9d5
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c
@@ -0,0 +1,1878 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/statvfs.h>
+#include <sys/vnode.h>
+#include <sys/thread.h>
+#include <sys/pathname.h>
+#include <sys/cred.h>
+#include <sys/extdirent.h>
+#include <acl/acl_common.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/string.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/smbtrans.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+static int
+smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
+ cred_t *cr, caller_context_t *ct, int flags);
+
+static int
+smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
+ ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr,
+ caller_context_t *ct, char *dirbuf, int num_bytes);
+
+static int
+smb_vop_getdents_entries(smb_node_t *dir_snode, uint32_t *cookiep,
+ int32_t *dircountp, char *arg, uint32_t flags, struct smb_request *sr,
+ cred_t *cr, caller_context_t *ct, char *dirbuf, int *maxentries,
+ int num_bytes, char *);
+
+extern int
+smb_gather_dents_info(char *args, ino_t fileid, int namelen,
+ char *name, uint32_t cookie, int32_t *countp,
+ smb_attr_t *attr, struct smb_node *snode,
+ char *shortname, char *name83);
+
+static void
+smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
+
+#define SMB_AT_MAX 16
+static uint_t smb_attrmap[SMB_AT_MAX] = {
+ 0,
+ AT_TYPE,
+ AT_MODE,
+ AT_UID,
+ AT_GID,
+ AT_FSID,
+ AT_NODEID,
+ AT_NLINK,
+ AT_SIZE,
+ AT_ATIME,
+ AT_MTIME,
+ AT_CTIME,
+ AT_RDEV,
+ AT_BLKSIZE,
+ AT_NBLOCKS,
+ AT_SEQ
+};
+
+int
+smb_vop_open(vnode_t **vpp, int mode, cred_t *cred, caller_context_t *ct)
+{
+ return (VOP_OPEN(vpp, mode, cred, ct));
+}
+
+int
+smb_vop_close(vnode_t *vp, int mode, cred_t *cred, caller_context_t *ct)
+{
+ return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, ct));
+}
+
+/*
+ * The smb_vop_* functions have minimal knowledge of CIFS semantics and
+ * serve as an interface to the VFS layer.
+ *
+ * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
+ * (Higher-level CIFS service code should never skip the smb_fsop_* layer
+ * to call smb_vop_* layer functions directly.)
+ */
+
+/*
+ * XXX - Extended attributes support in the file system assumed.
+ * This is needed for full NT Streams functionality.
+ */
+
+int
+smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
+{
+ int error;
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READ(vp, uiop, 0, cr, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ return (error);
+}
+
+int
+smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ int ioflag = 0;
+
+ *lcount = uiop->uio_resid;
+
+ if (*flag == FSSTAB_FILE_SYNC)
+ ioflag = FSYNC;
+
+ uiop->uio_llimit = MAXOFFSET_T;
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ error = VOP_WRITE(vp, uiop, ioflag, cr, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+
+ *lcount -= uiop->uio_resid;
+
+ return (error);
+}
+
+/*
+ * smb_vop_getattr()
+ *
+ * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
+ * service (instead of calling VOP_GETATTR directly) to retrieve attributes
+ * due to special processing needed for streams files.
+ *
+ * All attributes are retrieved.
+ *
+ * A named stream's attributes (as far as CIFS is concerned) are those of the
+ * unnamed (i.e. data) stream (minus the size attribute), and the size of the
+ * named stream. Though the file system may store attributes other than size
+ * with the named stream, these should not be used by CIFS for any purpose.
+ *
+ * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
+ * the corresponding unnamed stream).
+ */
+
+int
+smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
+ int flags, cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ vnode_t *use_vp;
+ smb_attr_t tmp_attr;
+ xvattr_t tmp_xvattr;
+ xoptattr_t *xoap = NULL;
+
+ if (unnamed_vp)
+ use_vp = unnamed_vp;
+ else
+ use_vp = vp;
+
+ if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
+ xva_init(&tmp_xvattr);
+ xoap = xva_getxoptattr(&tmp_xvattr);
+
+ ASSERT(xoap);
+
+ smb_sa_to_va_mask(ret_attr->sa_mask,
+ &tmp_xvattr.xva_vattr.va_mask);
+
+ XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
+ XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
+ XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
+ XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
+ XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
+
+ if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags,
+ cr, ct)) != 0)
+ return (error);
+
+ ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
+
+ /*
+ * Copy special attributes to ret_attr parameter
+ */
+
+ ret_attr->sa_dosattr = 0;
+
+ ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR);
+
+ xoap = xva_getxoptattr(&tmp_xvattr);
+ ASSERT(xoap);
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) {
+ if (xoap->xoa_readonly)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) {
+ if (xoap->xoa_hidden)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
+ }
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) {
+ if (xoap->xoa_system)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
+ }
+
+ if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) {
+ if (xoap->xoa_archive)
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
+ }
+
+ ret_attr->sa_crtime = xoap->xoa_createtime;
+
+ if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
+ /*
+ * Retrieve stream size attribute into temporary
+ * structure, in case the underlying file system
+ * returns attributes other than the size (we do not
+ * want to have ret_attr's other fields get
+ * overwritten).
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ tmp_xvattr.xva_vattr.va_mask = AT_SIZE;
+
+ if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr,
+ flags, cr, ct)) != 0)
+ return (error);
+
+ ret_attr->sa_vattr.va_size =
+ tmp_xvattr.xva_vattr.va_size;
+
+ }
+
+ if (ret_attr->sa_vattr.va_type == VDIR) {
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ return (error);
+ }
+
+ /*
+ * Support for file systems without VFSFT_XVATTR
+ */
+
+ smb_sa_to_va_mask(ret_attr->sa_mask,
+ &ret_attr->sa_vattr.va_mask);
+
+ error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, ct);
+
+ if (error != 0)
+ return (error);
+
+ /*
+ * "Fake" DOS attributes and create time, filesystem doesn't support
+ * them.
+ */
+
+ ret_attr->sa_dosattr = 0;
+ ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime;
+
+ if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
+ /*
+ * Retrieve stream size attribute into temporary structure,
+ * in case the underlying file system returns attributes
+ * other than the size (we do not want to have ret_attr's
+ * other fields get overwritten).
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ tmp_attr.sa_vattr.va_mask = AT_SIZE;
+ error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, ct);
+
+ if (error != 0)
+ return (error);
+
+
+ ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
+ }
+
+ if (ret_attr->sa_vattr.va_type == VDIR) {
+ ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_setattr()
+ *
+ * smb_fsop_setattr()/smb_vop_setattr() should always be called from the CIFS
+ * service to set attributes due to special processing for streams files.
+ *
+ * When smb_vop_setattr() is called on a named stream file, all indicated
+ * attributes except the size are set on the unnamed stream file. The size
+ * (if indicated) is set on the named stream file.
+ */
+
+int
+smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
+ int flags, cred_t *cr, caller_context_t *ct)
+{
+ int error = 0;
+ int at_size = 0;
+ vnode_t *use_vp;
+ xvattr_t tmp_xvattr;
+ xoptattr_t *xoap = NULL;
+ uint_t xva_mask;
+
+ if (unnamed_vp) {
+ use_vp = unnamed_vp;
+ if (set_attr->sa_mask & SMB_AT_SIZE) {
+ at_size = 1;
+ set_attr->sa_mask &= ~SMB_AT_SIZE;
+ }
+ } else {
+ use_vp = vp;
+ }
+
+ /*
+ * The caller should not be setting sa_vattr.va_mask,
+ * but rather sa_mask.
+ */
+
+ set_attr->sa_vattr.va_mask = 0;
+
+ if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
+ /*
+ * Initialize xvattr, including bzero
+ */
+ xva_init(&tmp_xvattr);
+ xoap = xva_getxoptattr(&tmp_xvattr);
+
+ ASSERT(xoap);
+
+ /*
+ * Copy caller-specified classic attributes to tmp_xvattr.
+ * First save tmp_xvattr's mask (set in xva_init()).
+ * This is |'d in later.
+ */
+
+ xva_mask = tmp_xvattr.xva_vattr.va_mask;
+ tmp_xvattr.xva_vattr = set_attr->sa_vattr;
+
+ smb_sa_to_va_mask(set_attr->sa_mask,
+ &tmp_xvattr.xva_vattr.va_mask);
+
+ /*
+ * "|" in the original xva_mask.
+ */
+
+ tmp_xvattr.xva_vattr.va_mask |= xva_mask;
+
+ if (set_attr->sa_mask & SMB_AT_DOSATTR) {
+ XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
+ XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
+ XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
+ XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
+
+ /*
+ * set_attr->sa_dosattr: If a given bit is not set,
+ * that indicates that the corresponding field needs
+ * to be updated with a "0" value. This is done
+ * implicitly as the xoap->xoa_* fields were bzero'd.
+ */
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE)
+ xoap->xoa_archive = 1;
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM)
+ xoap->xoa_system = 1;
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY)
+ xoap->xoa_readonly = 1;
+
+ if (set_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN)
+ xoap->xoa_hidden = 1;
+ }
+
+ if (set_attr->sa_mask & SMB_AT_CRTIME) {
+ XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
+ xoap->xoa_createtime = set_attr->sa_crtime;
+ }
+
+ if ((error = VOP_SETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags,
+ cr, ct)) != 0)
+ return (error);
+
+ /*
+ * If the size of the stream needs to be set, set it on
+ * the stream file directly. (All other indicated attributes
+ * are set on the stream's unnamed stream, above.)
+ */
+
+ if (at_size) {
+ /*
+ * set_attr->sa_vattr.va_size already contains the
+ * size as set by the caller
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ set_attr->sa_vattr.va_mask = AT_SIZE;
+ error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags,
+ cr, ct);
+ }
+
+ return (error);
+ }
+
+ /*
+ * Support for file systems without VFSFT_XVATTR
+ */
+
+ smb_sa_to_va_mask(set_attr->sa_mask, &set_attr->sa_vattr.va_mask);
+
+ /*
+ * set_attr->sa_vattr already contains new values
+ * as set by the caller
+ */
+
+ error = VOP_SETATTR(use_vp, &set_attr->sa_vattr, flags, cr, ct);
+
+ if (error != 0)
+ return (error);
+
+ if (at_size) {
+ /*
+ * set_attr->sa_vattr.va_size already contains the
+ * size as set by the caller
+ *
+ * Note that vp is used here, and not use_vp.
+ * Also, only AT_SIZE is needed.
+ */
+
+ set_attr->sa_vattr.va_mask = AT_SIZE;
+ error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, ct);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_access
+ *
+ * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
+ * against file's ACL or Unix permissions. CIFS on the other hand needs to
+ * know if the requested operation can succeed for the given object, this
+ * requires more checks in case of DELETE bit since permissions on the parent
+ * directory are important as well. Based on Windows rules if parent's ACL
+ * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
+ * permissions.
+ */
+int
+smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
+{
+ int error = 0;
+
+ if (mode == 0)
+ return (0);
+
+ if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
+ if (dir_vp) {
+ error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
+ cr, NULL);
+
+ if (error == 0)
+ mode &= ~ACE_DELETE;
+ }
+ }
+
+ if (mode) {
+ error = VOP_ACCESS(vp, mode, flags, cr, NULL);
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_lookup
+ *
+ * dvp: directory vnode (in)
+ * name: name of file to be looked up (in)
+ * vpp: looked-up vnode (out)
+ * od_name: on-disk name of file (out).
+ * This parameter is optional. If a pointer is passed in, it
+ * must be allocated with MAXNAMELEN bytes
+ * rootvp: vnode of the tree root (in)
+ * This parameter is always passed in non-NULL except at the time
+ * of share set up.
+ */
+
+int
+smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp, char *od_name,
+ int flags, vnode_t *rootvp, cred_t *cr, caller_context_t *ct)
+{
+ int error = 0;
+ int option_flags = 0;
+ pathname_t rpn;
+
+ if (*name == '\0')
+ return (EINVAL);
+
+ ASSERT(vpp);
+ *vpp = NULL;
+
+ if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) {
+ if (rootvp && (dvp == rootvp)) {
+ VN_HOLD(dvp);
+ *vpp = dvp;
+ return (0);
+ }
+
+ if (dvp->v_flag & VROOT) {
+ vfs_t *vfsp;
+ vnode_t *cvp = dvp;
+
+ /*
+ * Set dvp and check for races with forced unmount
+ * (see lookuppnvp())
+ */
+
+ vfsp = cvp->v_vfsp;
+ vfs_rlock_wait(vfsp);
+ if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
+ (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
+ vfs_unlock(vfsp);
+ return (EIO);
+ }
+ vfs_unlock(vfsp);
+ }
+ }
+
+
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ pn_alloc(&rpn);
+
+ error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr,
+ ct, NULL, &rpn);
+
+ if ((error == 0) && od_name) {
+ bzero(od_name, MAXNAMELEN);
+ if (option_flags == FIGNORECASE)
+ (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN);
+ else
+ (void) strlcpy(od_name, name, MAXNAMELEN);
+ }
+
+ pn_free(&rpn);
+ return (error);
+}
+
+int
+smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
+ int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap)
+{
+ int error;
+ int option_flags = 0;
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
+
+ error = VOP_CREATE(dvp, name, &attr->sa_vattr, EXCL,
+ attr->sa_vattr.va_mode, vpp, cr, option_flags, ct, vsap);
+
+ return (error);
+}
+
+int
+smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ int option_flags = 0;
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ error = VOP_REMOVE(dvp, name, cr, ct, option_flags);
+
+ return (error);
+}
+
+/*
+ * smb_vop_rename()
+ *
+ * The rename is for files in the same tree (identical TID) only.
+ */
+
+int
+smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp,
+ char *to_name, int flags, cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ int option_flags = 0;
+
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr,
+ ct, option_flags);
+
+ return (error);
+}
+
+int
+smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
+ int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap)
+{
+ int error;
+ int option_flags = 0;
+
+
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
+
+ error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, ct,
+ option_flags, vsap);
+
+ return (error);
+}
+
+/*
+ * smb_vop_rmdir()
+ *
+ * Only simple rmdir supported, consistent with NT semantics
+ * (can only remove an empty directory).
+ *
+ */
+
+int
+smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ int option_flags = 0;
+
+ if (flags & SMB_IGNORE_CASE)
+ option_flags = FIGNORECASE;
+
+ /*
+ * Comments adapted from rfs_rmdir().
+ *
+ * VOP_RMDIR now takes a new third argument (the current
+ * directory of the process). That's because rmdir
+ * wants to return EINVAL if one tries to remove ".".
+ * Of course, SMB servers do not know what their
+ * clients' current directories are. We fake it by
+ * supplying a vnode known to exist and illegal to
+ * remove.
+ */
+
+ error = VOP_RMDIR(dvp, name, rootdir, cr, ct, option_flags);
+ return (error);
+}
+
+int
+smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ return (VOP_FSYNC(vp, 1, cr, ct));
+}
+
+/*
+ * smb_vop_readdir()
+ *
+ * Upon return, the "name" field will contain either the on-disk name or, if
+ * it needs mangling or has a case-insensitive collision, the mangled
+ * "shortname."
+ *
+ * vpp is an optional parameter. If non-NULL, it will contain a pointer to
+ * the vnode for the name that is looked up (the vnode will be returned held).
+ *
+ * od_name is an optional parameter (NULL can be passed if the on-disk name
+ * is not needed by the caller).
+ */
+
+int
+smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
+ ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int num_bytes;
+ int error = 0;
+ char *dirbuf = NULL;
+
+ ASSERT(dvp);
+ ASSERT(cookiep);
+ ASSERT(name);
+ ASSERT(namelen);
+ ASSERT(inop);
+ ASSERT(cr);
+ ASSERT(ct);
+
+ if (dvp->v_type != VDIR) {
+ *namelen = 0;
+ return (ENOTDIR);
+ }
+
+ if (vpp)
+ *vpp = NULL;
+
+ dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
+ num_bytes = SMB_MINLEN_RDDIR_BUF;
+
+ /*
+ * The goal is to retrieve the first valid entry from *cookiep
+ * forward. smb_vop_readdir_readpage() collects an
+ * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information.
+ * smb_vop_readdir_entry() attempts to find the first valid entry
+ * in that page.
+ */
+
+ while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
+ &num_bytes, cr, ct, flags)) == 0) {
+
+ if (num_bytes <= 0)
+ break;
+
+ name[0] = '\0';
+
+ error = smb_vop_readdir_entry(dvp, cookiep, name, namelen,
+ inop, vpp, od_name, flags, cr, ct, dirbuf,
+ num_bytes);
+
+ if (error)
+ break;
+
+ if (*name)
+ break;
+
+ bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ num_bytes = SMB_MINLEN_RDDIR_BUF;
+ }
+
+
+ if (error) {
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ *namelen = 0;
+ return (error);
+ }
+
+ if (num_bytes == 0) { /* EOF */
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ *cookiep = SMB_EOF;
+ *namelen = 0;
+ return (0);
+ }
+
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+ return (0);
+}
+
+/*
+ * smb_vop_readdir_readpage()
+ *
+ * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The
+ * directory entries are returned in an fs-independent format by the
+ * underlying file system. That is, the "page" of information returned is
+ * not literally stored on-disk in the format returned.)
+ *
+ * Much of the following is borrowed from getdents64()
+ *
+ * MAXGETDENTS_SIZE is defined in getdents.c
+ */
+
+#define MAXGETDENTS_SIZE (64 * 1024)
+
+static int
+smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
+ cred_t *cr, caller_context_t *ct, int flags)
+{
+ int error = 0;
+ int rdirent_flags = 0;
+ int sink;
+ struct uio auio;
+ struct iovec aiov;
+
+ if (vp->v_type != VDIR)
+ return (ENOTDIR);
+
+ /* entflags not working for streams so don't try to use them */
+ if (!(flags & SMB_STREAM_RDDIR) &&
+ (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) {
+ /*
+ * Setting V_RDDIR_ENTFLAGS will cause the buffer to
+ * be filled with edirent_t structures (instead of
+ * dirent64_t structures).
+ */
+ rdirent_flags = V_RDDIR_ENTFLAGS;
+
+ if (*count < sizeof (edirent_t))
+ return (EINVAL);
+ } else {
+ if (*count < sizeof (dirent64_t))
+ return (EINVAL);
+ }
+
+ if (*count > MAXGETDENTS_SIZE)
+ *count = MAXGETDENTS_SIZE;
+
+ aiov.iov_base = buf;
+ aiov.iov_len = *count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_loffset = (uint64_t)offset;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_resid = *count;
+ auio.uio_fmode = 0;
+
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(vp, &auio, cr, &sink, ct, rdirent_flags);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
+
+ if (error) {
+ if (error == ENOENT) {
+ /* Fake EOF if offset is bad due to dropping of lock */
+ *count = 0;
+ return (0);
+ } else {
+ return (error);
+ }
+ }
+
+ /*
+ * Windows cannot handle an offset > SMB_EOF.
+ * Pretend we are at EOF.
+ */
+
+ if (auio.uio_loffset > SMB_EOF) {
+ *count = 0;
+ return (0);
+ }
+
+ *count = *count - auio.uio_resid;
+ return (0);
+}
+
+/*
+ * smb_vop_readdir_entry()
+ *
+ * This function retrieves the first valid entry from the
+ * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage()
+ * to smb_vop_readdir().
+ *
+ * Both dirent64_t and edirent_t structures need to be handled. The former is
+ * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter
+ * is required for proper handling of case collisions on file systems that
+ * support case-insensitivity. edirent_t structures are also used for
+ * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported.
+ */
+
+static int
+smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
+ ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr,
+ caller_context_t *ct, char *dirbuf, int num_bytes)
+{
+ uint32_t next_cookie;
+ int ebufsize;
+ int error = 0;
+ int len;
+ int rc;
+ char shortname[MANGLE_NAMELEN];
+ char name83[MANGLE_NAMELEN];
+ char *ebuf = NULL;
+ edirent_t *edp;
+ dirent64_t *dp = NULL;
+ vnode_t *vp = NULL;
+
+ ASSERT(dirbuf);
+
+ /*
+ * Use edirent_t structure for both
+ * entflags not working for streams so don't try to use them
+ */
+ if (!(flags & SMB_STREAM_RDDIR) &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)dirbuf;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dp = (dirent64_t *)dirbuf;
+ ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
+ ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)ebuf;
+ }
+
+ while (edp) {
+ if (dp)
+ DP_TO_EDP(dp, edp);
+
+ next_cookie = (uint32_t)edp->ed_off;
+ if (edp->ed_ino == 0) {
+ *cookiep = next_cookie;
+
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ continue;
+ }
+
+ len = strlen(edp->ed_name);
+
+ if (*namelen < len) {
+ *namelen = 0;
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (EOVERFLOW);
+ }
+
+ /*
+ * Do not pass SMB_IGNORE_CASE to smb_vop_lookup
+ */
+
+ error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp,
+ od_name, 0, NULL, cr, ct);
+
+ if (error) {
+ if (error == ENOENT) {
+ *cookiep = (uint32_t)next_cookie;
+
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ continue;
+ }
+
+
+ *namelen = 0;
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (error);
+ }
+
+ if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) {
+ rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
+ shortname, name83, 1);
+
+ if (rc == 1) { /* success */
+ (void) strlcpy(name, shortname, *namelen + 1);
+ *namelen = strlen(shortname);
+ } else {
+ (void) strlcpy(name, edp->ed_name,
+ *namelen + 1);
+ name[*namelen] = '\0';
+ }
+
+ } else {
+ (void) strlcpy(name, edp->ed_name, *namelen + 1);
+ *namelen = len;
+ }
+
+ if (vpp == NULL)
+ VN_RELE(vp);
+
+ if (inop)
+ *inop = edp->ed_ino;
+
+ *cookiep = (uint32_t)next_cookie;
+ break;
+ }
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (error);
+}
+
+/*
+ * smb_sa_to_va_mask
+ *
+ * Set va_mask by running through the SMB_AT_* #define's and
+ * setting those bits that correspond to the SMB_AT_* bits
+ * set in sa_mask.
+ */
+
+void
+smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp)
+{
+ int i;
+ uint_t smask;
+
+ smask = (sa_mask);
+ for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) {
+ if (smask & 1)
+ *(va_maskp) |= smb_attrmap[i];
+
+ smask >>= 1;
+ }
+}
+
+/*
+ * smb_vop_getdents()
+ *
+ * Upon success, the smb_node corresponding to each entry returned will
+ * have a reference taken on it. These will be released in
+ * smb_trans2_find_get_dents().
+ *
+ * If an error is returned from this routine, a list of already processed
+ * entries will be returned. The smb_nodes corresponding to these entries
+ * will be referenced, and will be released in smb_trans2_find_get_dents().
+ *
+ * The returned dp->d_name field will contain either the on-disk name or, if
+ * it needs mangling or has a case-insensitive collision, the mangled
+ * "shortname." In this case, the on-disk name can be retrieved from the
+ * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()).
+ */
+
+int /*ARGSUSED*/
+smb_vop_getdents(
+ smb_node_t *dir_snode,
+ uint32_t *cookiep,
+ uint64_t *verifierp,
+ int32_t *dircountp,
+ char *arg,
+ char *pattern,
+ uint32_t flags,
+ smb_request_t *sr,
+ cred_t *cr,
+ caller_context_t *ct)
+{
+ int error = 0;
+ int maxentries;
+ int num_bytes;
+ int resid;
+ char *dirbuf = NULL;
+ vnode_t *dvp;
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg;
+
+ dvp = dir_snode->vp;
+
+ resid = ihdr->uio.uio_resid;
+ maxentries = resid / SMB_MAX_DENT_INFO_SIZE;
+
+ bzero(ihdr->iov->iov_base, resid);
+
+ dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
+
+ while (maxentries) {
+
+ bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
+
+ num_bytes = SMB_MINLEN_RDDIR_BUF;
+ error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
+ &num_bytes, cr, ct, flags);
+
+ if (error || (num_bytes <= 0))
+ break;
+
+ error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp,
+ arg, flags, sr, cr, ct, dirbuf, &maxentries, num_bytes,
+ pattern);
+
+ if (error)
+ goto out;
+ }
+
+ if (num_bytes < 0) {
+ error = -1;
+ } else if (num_bytes == 0) {
+ *cookiep = SMB_EOF;
+ error = 0;
+ } else {
+ error = 0;
+ }
+
+out:
+ if (dirbuf)
+ kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
+
+ return (error);
+}
+
+/*
+ * smb_vop_getdents_entries()
+ *
+ * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer
+ * returned by smb_vop_readdir_readpage() to smb_vop_getdents().
+ *
+ * Both dirent64_t and edirent_t structures need to be handled. The former is
+ * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter
+ * is required for properly handling case collisions on file systems that
+ * support case-insensitivity. edirent_t is also used on case-sensitive
+ * file systems where VFSFT_DIRENTFLAGS is available.
+ */
+
+static int
+smb_vop_getdents_entries(
+ smb_node_t *dir_snode,
+ uint32_t *cookiep,
+ int32_t *dircountp,
+ char *arg,
+ uint32_t flags,
+ struct smb_request *sr,
+ cred_t *cr,
+ caller_context_t *ct,
+ char *dirbuf,
+ int *maxentries,
+ int num_bytes,
+ char *pattern)
+{
+ uint32_t next_cookie;
+ int ebufsize;
+ char *tmp_name;
+ int error;
+ int rc;
+ char shortname[MANGLE_NAMELEN];
+ char name83[MANGLE_NAMELEN];
+ char *ebuf = NULL;
+ dirent64_t *dp = NULL;
+ edirent_t *edp;
+ smb_node_t *ret_snode;
+ smb_attr_t ret_attr;
+ vnode_t *dvp;
+ vnode_t *fvp;
+
+ ASSERT(dirbuf);
+
+ dvp = dir_snode->vp;
+
+ if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)dirbuf;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ dp = (dirent64_t *)dirbuf;
+ ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
+ ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ edp = (edirent_t *)ebuf;
+ }
+
+ while (edp) {
+ if (dp)
+ DP_TO_EDP(dp, edp);
+
+ if (*maxentries == 0)
+ break;
+
+ next_cookie = (uint32_t)edp->ed_off;
+
+ if (edp->ed_ino == 0) {
+ *cookiep = next_cookie;
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ continue;
+ }
+
+ error = smb_vop_lookup(dvp, edp->ed_name, &fvp,
+ NULL, 0, NULL, cr, ct);
+
+ if (error) {
+ if (error == ENOENT) {
+ *cookiep = next_cookie;
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf,
+ num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf,
+ num_bytes);
+ }
+ continue;
+ }
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (error);
+ }
+
+ ret_snode = smb_node_lookup(sr, NULL, cr, fvp,
+ edp->ed_name, dir_snode, NULL, &ret_attr);
+
+ if (ret_snode == NULL) {
+ VN_RELE(fvp);
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (ENOMEM);
+ }
+
+ if (smb_match_name(edp->ed_ino, edp->ed_name, shortname,
+ name83, pattern, (flags & SMB_IGNORE_CASE))) {
+
+ tmp_name = edp->ed_name;
+
+ if ((flags & SMB_IGNORE_CASE) &&
+ ED_CASE_CONFLICTS(edp)) {
+ rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
+ shortname, name83, 1);
+ if (rc == 1)
+ tmp_name = shortname;
+ } else {
+ rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
+ shortname, name83, 0);
+ }
+
+ if (rc != 1) {
+ (void) strlcpy(shortname, edp->ed_name,
+ MANGLE_NAMELEN);
+ (void) strlcpy(name83, edp->ed_name,
+ MANGLE_NAMELEN);
+ shortname[MANGLE_NAMELEN - 1] = '\0';
+ name83[MANGLE_NAMELEN - 1] = '\0';
+ }
+
+ error = smb_gather_dents_info(arg, edp->ed_ino,
+ strlen(tmp_name), tmp_name, next_cookie, dircountp,
+ &ret_attr, ret_snode, shortname, name83);
+
+ if (error > 0) {
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+ return (error);
+ }
+
+ /*
+ * Treat errors from smb_gather_dents_info() that are
+ * < 0 the same as EOF.
+ */
+ if (error < 0) {
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+ *maxentries = 0;
+ return (0);
+ }
+ (*maxentries)--;
+ } else {
+ smb_node_release(ret_snode);
+ }
+
+ *cookiep = next_cookie;
+
+ if (dp) {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ DP_ADVANCE(dp, dirbuf, num_bytes);
+ if (dp == NULL)
+ edp = NULL;
+ } else {
+ /*LINTED E_BAD_PTR_CAST_ALIGN*/
+ EDP_ADVANCE(edp, dirbuf, num_bytes);
+ }
+ }
+
+ if (ebuf)
+ kmem_free(ebuf, ebufsize);
+
+ return (0);
+}
+
+/*
+ * smb_vop_stream_lookup()
+ *
+ * The name returned in od_name is the on-disk name of the stream with the
+ * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN
+ * by the caller.
+ */
+
+int
+smb_vop_stream_lookup(vnode_t *fvp, char *stream_name, vnode_t **vpp,
+ char *od_name, vnode_t **xattrdirvpp, int flags, vnode_t *rootvp,
+ cred_t *cr, caller_context_t *ct)
+{
+ char *solaris_stream_name;
+ char *name;
+ int error;
+
+ if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
+ LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0)
+ return (error);
+
+ /*
+ * Prepend SMB_STREAM_PREFIX to stream name
+ */
+
+ solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
+ stream_name);
+
+ /*
+ * "name" will hold the on-disk name returned from smb_vop_lookup
+ * for the stream, including the SMB_STREAM_PREFIX.
+ */
+
+ name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+
+ if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp,
+ name, flags, rootvp, cr, ct)) != 0) {
+ VN_RELE(*xattrdirvpp);
+ } else {
+ (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]),
+ MAXNAMELEN);
+ }
+
+ kmem_free(solaris_stream_name, MAXNAMELEN);
+ kmem_free(name, MAXNAMELEN);
+
+ return (error);
+}
+
+int
+smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr,
+ vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ char *solaris_stream_name;
+ int error;
+
+ if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
+ LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0)
+ return (error);
+
+ /*
+ * Prepend SMB_STREAM_PREFIX to stream name
+ */
+
+ solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
+ stream_name);
+
+ if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr,
+ vpp, flags, cr, ct, NULL)) != 0)
+ VN_RELE(*xattrdirvpp);
+
+ kmem_free(solaris_stream_name, MAXNAMELEN);
+
+ return (error);
+}
+
+int
+smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ char *solaris_stream_name;
+ vnode_t *xattrdirvp;
+ int error;
+
+ if ((error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr,
+ ct)) != 0)
+ return (error);
+
+ /*
+ * Prepend SMB_STREAM_PREFIX to stream name
+ */
+
+ solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
+ stream_name);
+
+ /* XXX might have to use kcred */
+ error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr, ct);
+
+ kmem_free(solaris_stream_name, MAXNAMELEN);
+
+ return (error);
+}
+
+/*
+ * smb_vop_stream_readdir()
+ *
+ * Note: stream_info.size is not filled in in this routine.
+ * It needs to be filled in by the caller due to the parameters for getattr.
+ *
+ * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX
+ * removed.
+ */
+
+int
+smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep,
+ struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp,
+ int flags, cred_t *cr, caller_context_t *ct)
+{
+ int nsize = MAXNAMELEN-1;
+ int error = 0;
+ ino64_t ino;
+ char *tmp_name;
+ vnode_t *xattrdirvp;
+ vnode_t *vp;
+
+ if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR,
+ cr, ct)) != 0)
+ return (error);
+
+ bzero(stream_info->name, sizeof (stream_info->name));
+ stream_info->size = 0;
+
+ tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+
+ for (;;) {
+ error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize,
+ &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr, ct);
+
+ if (error || (*cookiep == SMB_EOF))
+ break;
+
+ if (strncmp(tmp_name, SMB_STREAM_PREFIX,
+ SMB_STREAM_PREFIX_LEN)) {
+ VN_RELE(vp);
+ continue;
+ }
+
+ tmp_name[nsize] = '\0';
+ (void) strlcpy(stream_info->name,
+ &(tmp_name[SMB_STREAM_PREFIX_LEN]),
+ sizeof (stream_info->name));
+
+ nsize -= SMB_STREAM_PREFIX_LEN;
+ break;
+ }
+
+ if ((error == 0) && nsize) {
+ if (vpp)
+ *vpp = vp;
+ else
+ VN_RELE(vp);
+
+ if (xattrdirvpp)
+ *xattrdirvpp = xattrdirvp;
+ else
+ VN_RELE(xattrdirvp);
+
+ }
+
+ kmem_free(tmp_name, MAXNAMELEN);
+
+ return (error);
+}
+
+int
+smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+
+ error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, ct,
+ NULL, NULL);
+ return (error);
+}
+
+/*
+ * smb_vop_traverse_check()
+ *
+ * This function checks to see if the passed-in vnode has a file system
+ * mounted on it. If it does, the mount point is "traversed" and the
+ * vnode for the root of the file system is returned.
+ */
+
+int
+smb_vop_traverse_check(vnode_t **vpp)
+{
+ int error;
+
+ if (vn_mountedvfs(*vpp) == 0)
+ return (0);
+
+ /*
+ * traverse() may return a different held vnode, even in the error case.
+ * If it returns a different vnode, it will have released the original.
+ */
+
+ error = traverse(vpp);
+
+ return (error);
+}
+
+int /*ARGSUSED*/
+smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr)
+{
+ int error;
+
+ error = VFS_STATVFS(vp->v_vfsp, statp);
+
+ return (error);
+}
+
+/*
+ * smb_vop_acl_from_vsa
+ *
+ * Converts given vsecattr_t structure to a acl_t structure.
+ *
+ * The allocated memory for retuned acl_t should be freed by
+ * calling acl_free().
+ */
+static acl_t *
+smb_vop_acl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
+{
+ int aclbsize = 0; /* size of acl list in bytes */
+ int dfaclbsize = 0; /* size of default acl list in bytes */
+ int numacls;
+ acl_t *acl_info;
+
+ ASSERT(vsecattr);
+
+ acl_info = acl_alloc(acl_type);
+ if (acl_info == NULL)
+ return (NULL);
+
+ acl_info->acl_flags = 0;
+
+ switch (acl_type) {
+
+ case ACLENT_T:
+ numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
+ aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
+ dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
+
+ acl_info->acl_cnt = numacls;
+ acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
+ KM_SLEEP);
+ (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
+ aclbsize);
+ (void) memcpy((char *)acl_info->acl_aclp + aclbsize,
+ vsecattr->vsa_dfaclentp, dfaclbsize);
+
+ if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
+ acl_info->acl_flags |= ACL_IS_TRIVIAL;
+
+ break;
+
+ case ACE_T:
+ aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ acl_info->acl_cnt = vsecattr->vsa_aclcnt;
+ acl_info->acl_flags = vsecattr->vsa_aclflags;
+ acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
+ (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
+ aclbsize);
+ if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
+ acl_info->acl_flags |= ACL_IS_TRIVIAL;
+
+ break;
+
+ default:
+ acl_free(acl_info);
+ return (NULL);
+ }
+
+ if (aclbsize && vsecattr->vsa_aclentp)
+ kmem_free(vsecattr->vsa_aclentp, aclbsize);
+ if (dfaclbsize && vsecattr->vsa_dfaclentp)
+ kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
+
+ return (acl_info);
+}
+
+/*
+ * smb_vop_acl_to_vsa
+ *
+ * Converts given acl_t structure to a vsecattr_t structure.
+ *
+ * IMPORTANT:
+ * Upon successful return the memory allocated for vsa_aclentp
+ * should be freed by calling kmem_free(). The size is returned
+ * in aclbsize.
+ */
+int
+smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
+{
+ int error = 0;
+ int numacls;
+ aclent_t *aclp;
+
+ ASSERT(acl_info);
+ ASSERT(vsecattr);
+ ASSERT(aclbsize);
+
+ bzero(vsecattr, sizeof (vsecattr_t));
+ *aclbsize = 0;
+
+ switch (acl_info->acl_type) {
+ case ACLENT_T:
+ numacls = acl_info->acl_cnt;
+ /*
+ * Minimum ACL size is three entries so might as well
+ * bail out here. Also limit request size to prevent user
+ * from allocating too much kernel memory. Maximum size
+ * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
+ * for the default ACL part.
+ */
+ if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
+ error = EINVAL;
+ break;
+ }
+
+ vsecattr->vsa_mask = VSA_ACL;
+
+ vsecattr->vsa_aclcnt = numacls;
+ *aclbsize = numacls * sizeof (aclent_t);
+ vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
+ (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
+ *aclbsize);
+
+ /* Sort the acl list */
+ ksort((caddr_t)vsecattr->vsa_aclentp,
+ vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
+
+ /* Break into acl and default acl lists */
+ for (numacls = 0, aclp = vsecattr->vsa_aclentp;
+ numacls < vsecattr->vsa_aclcnt;
+ aclp++, numacls++) {
+ if (aclp->a_type & ACL_DEFAULT)
+ break;
+ }
+
+ /* Find where defaults start (if any) */
+ if (numacls < vsecattr->vsa_aclcnt) {
+ vsecattr->vsa_mask |= VSA_DFACL;
+ vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
+ vsecattr->vsa_dfaclentp = aclp;
+ vsecattr->vsa_aclcnt = numacls;
+ }
+
+ /* Adjust if they're all defaults */
+ if (vsecattr->vsa_aclcnt == 0) {
+ vsecattr->vsa_mask &= ~VSA_ACL;
+ vsecattr->vsa_aclentp = NULL;
+ }
+
+ /* Only directories can have defaults */
+ if (vsecattr->vsa_dfaclcnt &&
+ (acl_info->acl_flags & ACL_IS_DIR)) {
+ error = ENOTDIR;
+ }
+
+ break;
+
+ case ACE_T:
+ if (acl_info->acl_cnt < 1 ||
+ acl_info->acl_cnt > MAX_ACL_ENTRIES) {
+ error = EINVAL;
+ break;
+ }
+
+ vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsecattr->vsa_aclcnt = acl_info->acl_cnt;
+ vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
+ *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
+ vsecattr->vsa_aclentsz = *aclbsize;
+ vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
+ (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
+ *aclbsize);
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+
+ return (error);
+}
+
+/*
+ * smb_vop_acl_read
+ *
+ * Reads the ACL of the specified file into 'aclp'.
+ * acl_type is the type of ACL which the filesystem supports.
+ *
+ * Caller has to free the allocated memory for aclp by calling
+ * acl_free().
+ */
+int
+smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ vsecattr_t vsecattr;
+
+ ASSERT(vp);
+ ASSERT(aclp);
+
+ *aclp = NULL;
+ bzero(&vsecattr, sizeof (vsecattr_t));
+
+ switch (acl_type) {
+ case ACLENT_T:
+ vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
+ VSA_DFACLCNT;
+ break;
+
+ case ACE_T:
+ vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, ct))
+ return (error);
+
+ *aclp = smb_vop_acl_from_vsa(&vsecattr, acl_type);
+ if (vp->v_type == VDIR)
+ (*aclp)->acl_flags |= ACL_IS_DIR;
+
+ return (0);
+}
+
+/*
+ * smb_vop_acl_write
+ *
+ * Writes the given ACL in aclp for the specified file.
+ */
+int
+smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ vsecattr_t vsecattr;
+ int aclbsize;
+
+ ASSERT(vp);
+ ASSERT(aclp);
+
+ error = smb_vop_acl_to_vsa(aclp, &vsecattr, &aclbsize);
+
+ if (error == 0) {
+ (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, ct);
+ VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
+ }
+
+ if (aclbsize && vsecattr.vsa_aclentp)
+ kmem_free(vsecattr.vsa_aclentp, aclbsize);
+
+ return (error);
+}
+
+/*
+ * smb_vop_acl_type
+ *
+ * Determines the ACL type for the given vnode.
+ * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL.
+ */
+acl_type_t
+smb_vop_acl_type(vnode_t *vp)
+{
+ int error;
+ ulong_t whichacl;
+
+ error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL);
+ if (error != 0) {
+ /*
+ * If we got an error, then the filesystem
+ * likely does not understand the _PC_ACL_ENABLED
+ * pathconf. In this case, we fall back to trying
+ * POSIX-draft (aka UFS-style) ACLs.
+ */
+ whichacl = _ACL_ACLENT_ENABLED;
+ }
+
+ if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
+ /*
+ * If the file system supports neither ACE nor
+ * ACLENT ACLs we will fall back to UFS-style ACLs
+ * like we did above if there was an error upon
+ * calling VOP_PATHCONF.
+ *
+ * ACE and ACLENT type ACLs are the only interfaces
+ * supported thus far. If any other bits are set on
+ * 'whichacl' upon return from VOP_PATHCONF, we will
+ * ignore them.
+ */
+ whichacl = _ACL_ACLENT_ENABLED;
+ }
+
+ if (whichacl == _ACL_ACLENT_ENABLED)
+ return (ACLENT_T);
+
+ return (ACE_T);
+}
+
+static int zfs_perms[] = {
+ ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS,
+ ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD,
+ ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL,
+ ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE
+};
+
+static int unix_perms[] = { VREAD, VWRITE, VEXEC };
+/*
+ * smb_vop_eaccess
+ *
+ * Returns the effective permission of the given credential for the
+ * specified object.
+ *
+ * This is just a workaround. We need VFS/FS support for this.
+ */
+void
+smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr)
+{
+ int error, i;
+ int pnum;
+
+ *mode = 0;
+
+ if (flags == V_ACE_MASK) {
+ pnum = sizeof (zfs_perms) / sizeof (int);
+
+ for (i = 0; i < pnum; i++) {
+ error = smb_vop_access(vp, zfs_perms[i], flags,
+ dir_vp, cr);
+ if (error == 0)
+ *mode |= zfs_perms[i];
+ }
+ } else {
+ pnum = sizeof (unix_perms) / sizeof (int);
+
+ for (i = 0; i < pnum; i++) {
+ error = smb_vop_access(vp, unix_perms[i], flags,
+ dir_vp, cr);
+ if (error == 0)
+ *mode |= unix_perms[i];
+ }
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_winpipe.c b/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
new file mode 100755
index 0000000000..361485783c
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_winpipe.c
@@ -0,0 +1,431 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contain routines to initialize the doors interfaces for
+ * CIFS winpipe calls.
+ */
+
+#define START_UPDOOR_SIZE 16384
+#define START_INPIPE_SIZE 16384
+
+#include <smbsrv/smb_incl.h>
+
+#include <sys/stat.h>
+#include <sys/door.h>
+#include <sys/door_data.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc_util.h>
+#include <sys/uio.h>
+
+
+static door_handle_t *smb_winpipe_dh = NULL;
+static uint64_t smb_winpipe_ncall = 0;
+static kmutex_t smb_winpipe_mutex;
+static kcondvar_t smb_winpipe_cv;
+
+static int smb_winpipe_upcall(mlsvc_pipe_t *, smb_dr_user_ctx_t *,
+ mlsvc_stream_t *, uint16_t, uint32_t, unsigned char *, smb_pipe_t *);
+
+static smb_dr_user_ctx_t *smb_winpipe_ctx_alloc(struct smb_request *);
+static void smb_winpipe_ctx_free(smb_dr_user_ctx_t *);
+static uint8_t *smb_winpipe_ctx_mkselfrel(smb_dr_user_ctx_t *, uint32_t *);
+
+
+void
+smb_winpipe_init(void)
+{
+ mutex_init(&smb_winpipe_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&smb_winpipe_cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+smb_winpipe_fini(void)
+{
+ smb_winpipe_close();
+ cv_destroy(&smb_winpipe_cv);
+ mutex_destroy(&smb_winpipe_mutex);
+}
+
+int
+smb_winpipe_open(void)
+{
+ door_handle_t *dh;
+ int rc;
+
+ mutex_enter(&smb_winpipe_mutex);
+
+ if (smb_winpipe_dh == NULL) {
+ dh = kmem_zalloc(sizeof (door_handle_t), KM_SLEEP);
+
+ rc = door_ki_open(SMB_WINPIPE_DOOR_UP_PATH, dh);
+ if (rc) {
+ kmem_free(dh, sizeof (door_handle_t));
+ mutex_exit(&smb_winpipe_mutex);
+ cmn_err(CE_WARN, "smb_winpipe_open: rc=%d", rc);
+ return (-1);
+ }
+
+ smb_winpipe_ncall = 0;
+ smb_winpipe_dh = dh;
+ }
+
+ mutex_exit(&smb_winpipe_mutex);
+ return (0);
+}
+
+void
+smb_winpipe_close(void)
+{
+ mutex_enter(&smb_winpipe_mutex);
+
+ while (smb_winpipe_ncall > 0)
+ cv_wait(&smb_winpipe_cv, &smb_winpipe_mutex);
+
+ if (smb_winpipe_dh) {
+ kmem_free(smb_winpipe_dh, sizeof (door_handle_t));
+ smb_winpipe_dh = NULL;
+ }
+
+ mutex_exit(&smb_winpipe_mutex);
+}
+
+/*
+ * Winpipe call interface: called by smb_rpc_transact and smb_rpc_read.
+ * Serialization and call reference accounting handled here.
+ *
+ * The sr will be null on a flush operation, which will result in ctx
+ * being null. A null ctx must be handled by smb_winpipe_upcall.
+ */
+int
+smb_winpipe_call(struct smb_request *sr,
+ mlsvc_pipe_t *pi,
+ mlsvc_stream_t *streamin,
+ uint16_t call_type,
+ uint32_t *nbytes)
+{
+ smb_dr_user_ctx_t *ctx;
+ unsigned char *lbuf;
+ smb_pipe_t *pp;
+ int rc;
+
+ mutex_enter(&smb_winpipe_mutex);
+
+ if (smb_winpipe_dh == NULL) {
+ mutex_exit(&smb_winpipe_mutex);
+ return (-1);
+ }
+
+ ++smb_winpipe_ncall;
+ mutex_exit(&smb_winpipe_mutex);
+
+ lbuf = kmem_zalloc(START_UPDOOR_SIZE, KM_SLEEP);
+ pp = kmem_zalloc(START_INPIPE_SIZE, KM_SLEEP);
+ ctx = smb_winpipe_ctx_alloc(sr);
+
+ rc = smb_winpipe_upcall(pi, ctx, streamin, call_type, *nbytes,
+ lbuf, pp);
+
+ if (rc == 0) {
+ switch (call_type) {
+ case SMB_RPC_TRANSACT:
+ case SMB_RPC_READ:
+ case SMB_RPC_FLUSH:
+ *nbytes = pp->sp_datalen;
+ break;
+
+ default:
+ /*
+ * A write just queues the data and returns.
+ */
+ break;
+ }
+ }
+
+ smb_winpipe_ctx_free(ctx);
+ kmem_free(pp, START_INPIPE_SIZE);
+ kmem_free(lbuf, START_UPDOOR_SIZE);
+
+ mutex_enter(&smb_winpipe_mutex);
+ --smb_winpipe_ncall;
+ cv_signal(&smb_winpipe_cv);
+ mutex_exit(&smb_winpipe_mutex);
+ return (rc);
+}
+
+/*
+ * Door upcall wrapper - handles data marshalling.
+ * This function should only be called by smb_winpipe_call.
+ */
+static int
+smb_winpipe_upcall(mlsvc_pipe_t *pipe_info,
+ smb_dr_user_ctx_t *user_ctx,
+ mlsvc_stream_t *streamin,
+ uint16_t call_type,
+ uint32_t req_cnt,
+ unsigned char *lbuf,
+ smb_pipe_t *pp)
+{
+ door_arg_t da;
+ int user_ctx_bytes;
+ mlsvc_door_hdr_t mdhin, mdhout;
+ smb_pipe_t newpipe;
+ int total_bytes = 0;
+ int cnt;
+ int bytes_off = 0;
+ ulong_t save_resid;
+ uint32_t tmp_resid;
+ uint8_t *user_ctx_selfrel;
+
+ /*
+ * copy the pipe hdr into flat buf, this contains the thread id,
+ * version and a couple of reserved fields for future expansion
+ */
+ mdhin.md_tid = (uint64_t)curthread->t_did;
+ mdhin.md_version = SMB_MLSVC_DOOR_VERSION;
+ /*
+ * rpc_transact, rpc_read or rpc_write
+ */
+ mdhin.md_call_type = call_type;
+ mdhin.md_length = req_cnt;
+ mdhin.md_reserved = 0;
+ bcopy(&mdhin.md_tid, lbuf, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ bcopy(&mdhin.md_version, lbuf + bytes_off, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(&mdhin.md_call_type, lbuf + bytes_off, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(&mdhin.md_length, lbuf + bytes_off, sizeof (uint32_t));
+ bytes_off += sizeof (uint32_t);
+ bcopy(&mdhin.md_reserved, lbuf + bytes_off, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ total_bytes = bytes_off;
+
+ /*
+ * Most of the marshalling isn't needed for flush.
+ * The pipe-id is needed to find the rpc_context and
+ * free the input and output pipes.
+ */
+ if (call_type == SMB_RPC_FLUSH) {
+ bcopy(&pipe_info->fid, lbuf + total_bytes, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ } else {
+ user_ctx_selfrel = smb_winpipe_ctx_mkselfrel(user_ctx,
+ (uint32_t *)&cnt);
+
+ if (user_ctx_selfrel == NULL) {
+ return (-1);
+ }
+
+ bcopy(user_ctx_selfrel, lbuf + total_bytes, cnt);
+ kmem_free(user_ctx_selfrel, cnt);
+ total_bytes += cnt;
+ /*
+ * based on uio stuff and smb_pipe_t size
+ * calculate size of buffer needed
+ */
+ newpipe.sp_pipeid = pipe_info->fid;
+ (void) strlcpy(newpipe.sp_pipename, pipe_info->pipe_name,
+ SMB_MAX_PIPENAMELEN);
+ bcopy(newpipe.sp_pipename, lbuf + total_bytes,
+ SMB_MAX_PIPENAMELEN);
+ bcopy(&newpipe.sp_pipeid, lbuf + total_bytes +
+ SMB_MAX_PIPENAMELEN, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t) + SMB_MAX_PIPENAMELEN;
+ }
+
+ /* copy the pipe data len into flat buf */
+ if ((mdhin.md_call_type == SMB_RPC_TRANSACT) ||
+ (mdhin.md_call_type == SMB_RPC_WRITE)) {
+ /* we only want the least 4 significant bytes here */
+ tmp_resid = (uint32_t)streamin->uio.uio_resid;
+ bcopy(&tmp_resid, lbuf + total_bytes, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ save_resid = streamin->uio.uio_resid;
+ (void) uiomove((caddr_t)(lbuf + total_bytes),
+ streamin->uio.uio_resid, UIO_WRITE, &streamin->uio);
+ total_bytes += (save_resid - streamin->uio.uio_resid);
+ } else if (mdhin.md_call_type == SMB_RPC_READ) {
+ bzero(lbuf + total_bytes, sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ }
+
+ da.data_ptr = (char *)lbuf;
+ da.data_size = total_bytes;
+ da.desc_ptr = NULL;
+ da.desc_num = 0;
+ da.rbuf = (char *)lbuf;
+ da.rsize = START_UPDOOR_SIZE;
+
+ if (door_ki_upcall(*smb_winpipe_dh, &da) != 0) {
+ return (-1);
+ }
+ /* RPC_WRITE just queues the data and returns */
+ if (mdhin.md_call_type == SMB_RPC_WRITE) {
+ return (0);
+ }
+ bytes_off = 0;
+ bcopy(da.data_ptr, &mdhout.md_tid, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_version, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_call_type, sizeof (uint16_t));
+ bytes_off += sizeof (uint16_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_length, sizeof (uint32_t));
+ bytes_off += sizeof (uint32_t);
+ bcopy(da.data_ptr+bytes_off, &mdhout.md_reserved, sizeof (uint64_t));
+ bytes_off += sizeof (uint64_t);
+ user_ctx_bytes = 0;
+ total_bytes = user_ctx_bytes + bytes_off;
+
+ bzero(pp, START_INPIPE_SIZE);
+ bcopy(da.data_ptr+total_bytes, pp->sp_pipename, SMB_MAX_PIPENAMELEN);
+ total_bytes += SMB_MAX_PIPENAMELEN;
+ bcopy(da.data_ptr+total_bytes, &(pp->sp_pipeid), sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+ bcopy(da.data_ptr + total_bytes, &(pp->sp_datalen), sizeof (uint32_t));
+ total_bytes += sizeof (uint32_t);
+
+ if (pp->sp_datalen > 0) {
+ pipe_info->outlen = pp->sp_datalen;
+ pipe_info->output = kmem_alloc(pipe_info->outlen, KM_SLEEP);
+ bcopy((char *)(da.data_ptr + total_bytes),
+ pipe_info->output, pipe_info->outlen);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Allocate a user context structure and initialize it based on the
+ * specified SMB request data. Resources allocated here must be
+ * released using smb_winpipe_ctx_free.
+ *
+ * If sr is null, a null pointer is returned.
+ */
+static smb_dr_user_ctx_t *
+smb_winpipe_ctx_alloc(struct smb_request *sr)
+{
+ smb_session_t *session;
+ smb_user_t *user;
+ smb_dr_user_ctx_t *ctx;
+
+ if (sr == NULL)
+ return (NULL);
+
+ user = sr->uid_user;
+ session = user->u_session;
+
+ ASSERT(user);
+ ASSERT(user->u_domain);
+ ASSERT(user->u_name);
+ ASSERT(session);
+ ASSERT(session->workstation);
+
+ ctx = kmem_zalloc(sizeof (smb_dr_user_ctx_t), KM_SLEEP);
+
+ ctx->du_session_id = session->s_kid;
+ ctx->du_native_os = session->native_os;
+ ctx->du_ipaddr = session->ipaddr;
+ ctx->du_uid = user->u_uid;
+ ctx->du_logon_time = user->u_logon_time;
+ ctx->du_flags = user->u_flags;
+
+ ctx->du_domain_len = user->u_domain_len;
+ ctx->du_domain = kmem_alloc(ctx->du_domain_len, KM_SLEEP);
+ (void) strlcpy(ctx->du_domain, user->u_domain, ctx->du_domain_len);
+
+ ctx->du_account_len = user->u_name_len;
+ ctx->du_account = kmem_alloc(ctx->du_account_len, KM_SLEEP);
+ (void) strlcpy(ctx->du_account, user->u_name, ctx->du_account_len);
+
+ ctx->du_workstation_len = strlen(session->workstation) + 1;
+ ctx->du_workstation = kmem_alloc(ctx->du_workstation_len,
+ KM_SLEEP);
+ (void) strlcpy(ctx->du_workstation, session->workstation,
+ ctx->du_workstation_len);
+
+ return (ctx);
+}
+
+
+/*
+ * Free resources associated with a user context structure.
+ */
+static void
+smb_winpipe_ctx_free(smb_dr_user_ctx_t *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ ASSERT(ctx->du_domain);
+ ASSERT(ctx->du_account);
+ ASSERT(ctx->du_workstation);
+
+ kmem_free(ctx->du_domain, ctx->du_domain_len);
+ kmem_free(ctx->du_account, ctx->du_account_len);
+ kmem_free(ctx->du_workstation, ctx->du_workstation_len);
+ kmem_free(ctx, sizeof (smb_dr_user_ctx_t));
+}
+
+/*
+ * Convert a user context structure from absolute to self-relative format.
+ *
+ * On success, a pointer to an allocated XDR encoded buffer is returned,
+ * with the buffer size in ret_len. The caller is responsible for freeing
+ * this buffer when it is no longer required. If the return value is NULL,
+ * it is not valid to interpret ret_len.
+ */
+static uint8_t *
+smb_winpipe_ctx_mkselfrel(smb_dr_user_ctx_t *ctx, uint32_t *ret_len)
+{
+ XDR xdrs;
+ uint8_t *buf;
+ uint32_t len;
+
+ if (ctx == NULL || ret_len == NULL) {
+ return (NULL);
+ }
+
+ len = xdr_sizeof(xdr_smb_dr_user_ctx_t, ctx);
+ buf = kmem_zalloc(len, KM_SLEEP);
+ xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_ENCODE);
+
+ if (!xdr_smb_dr_user_ctx_t(&xdrs, ctx)) {
+ kmem_free(buf, len);
+ len = 0;
+ buf = NULL;
+ }
+
+ xdr_destroy(&xdrs);
+ *ret_len = len;
+ return (buf);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write.c b/usr/src/uts/common/fs/smbsrv/smb_write.c
new file mode 100644
index 0000000000..e6874397b4
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c
@@ -0,0 +1,565 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sdt.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/netbios.h>
+
+
+#define SMB_WRMODE_WRITE_THRU 0x0001
+#define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU)
+
+
+typedef struct smb_write_param {
+ struct vardata_block w_vdb;
+ uint64_t w_offset;
+ uint16_t w_mode;
+ uint16_t w_count;
+} smb_write_param_t;
+
+
+int smb_write_common(struct smb_request *sr, smb_write_param_t *param);
+int smb_write_truncate(struct smb_request *sr, smb_write_param_t *param);
+int smb_set_file_size(struct smb_request *sr);
+
+
+/*
+ * Write count bytes at the specified offset in a file. The offset is
+ * limited to 32-bits. If the count is zero, the file is truncated to
+ * the length specified by the offset.
+ *
+ * The response count indicates the actual number of bytes written, which
+ * will equal the requested count on success. If request and response
+ * counts differ but there is no error, the client will assume that the
+ * server encountered a resource issue.
+ */
+int
+smb_com_write(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t off;
+ int rc;
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &param->w_count, &off);
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ param->w_offset = (uint64_t)off;
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ if (param->w_count == 0) {
+ rc = smb_write_truncate(sr, param);
+ } else {
+ rc = smbsr_decode_data(sr, "D", &param->w_vdb);
+
+ if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ rc = smb_write_common(sr, param);
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Write count bytes to a file and then close the file. This function
+ * can only be used to write to 32-bit offsets and the client must set
+ * WordCount (6 or 12) correctly in order to locate the data to be
+ * written. If an error occurs on the write, the file should still be
+ * closed. If Count is 0, the file is truncated (or extended) to offset.
+ *
+ * If the last_write time is non-zero, last_write should be used to set
+ * the mtime. Otherwise the file system stamps the mtime. Failure to
+ * set mtime should not result in an error response.
+ */
+int
+smb_com_write_and_close(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t last_write;
+ uint32_t off;
+ int rc = 0;
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ if (sr->smb_wct == 12) {
+ rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
+ &param->w_count, &off, &last_write);
+ } else {
+ rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
+ &param->w_count, &off, &last_write);
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ param->w_offset = (uint64_t)off;
+
+ if (param->w_count == 0) {
+ rc = smb_write_truncate(sr, param);
+ } else {
+ /*
+ * There may be a bug here: should this be "3.#B"?
+ */
+ rc = smbsr_decode_data(sr, ".#B", param->w_count,
+ &param->w_vdb);
+
+ if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ rc = smb_write_common(sr, param);
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ if ((rc = smb_common_close(sr, last_write)) != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Write count bytes to a file at the specified offset and then unlock
+ * them. Write behind is safe because the client should have the range
+ * locked and this request is allowed to extend the file - note that
+ * offest is limited to 32-bits. It is an error for count to be zero.
+ *
+ * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
+ * files. Reject any attempt to use it on other shares.
+ *
+ * The response count indicates the actual number of bytes written, which
+ * will equal the requested count on success. If request and response
+ * counts differ but there is no error, the client will assume that the
+ * server encountered a resource issue.
+ */
+int
+smb_com_write_and_unlock(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t off;
+ uint32_t result;
+ uint16_t remcnt;
+ int rc = 0;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
+ smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
+ /* NOTREACHED */
+ }
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &param->w_count, &off,
+ &remcnt);
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (param->w_count == 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "D", &param->w_vdb);
+
+ if ((rc != 0) || (param->w_count != param->w_vdb.len)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_offset = (uint64_t)off;
+ param->w_vdb.uio.uio_offset = (off_t)param->w_offset;
+
+ if ((rc = smb_write_common(sr, param)) != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+
+ result = smb_unlock_range(sr, sr->fid_ofile->f_node, param->w_offset,
+ (uint64_t)param->w_count);
+ if (result != NT_STATUS_SUCCESS) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smb_unlock_range_raise_error(sr, result);
+ /* NOTREACHED */
+ }
+
+ smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Write bytes to a file (SMB Core). This request was extended in
+ * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
+ * 14, instead of 12, and including additional offset information.
+ *
+ * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
+ * to truncate a file. A zero length merely transfers zero bytes.
+ *
+ * If bit 0 of WriteMode is set, Fid must refer to a disk file and
+ * the data must be on stable storage before responding.
+ */
+int
+smb_com_write_andx(struct smb_request *sr)
+{
+ smb_write_param_t *param;
+ uint32_t off_low;
+ uint32_t off_high;
+ uint16_t data_offset;
+ uint16_t remcnt;
+ int rc = 0;
+
+ param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
+
+ if (sr->smb_wct == 14) {
+ rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid,
+ &off_low, &param->w_mode, &remcnt, &param->w_count,
+ &data_offset, &off_high);
+
+ data_offset -= 63;
+ param->w_offset = ((uint64_t)off_high << 32) | off_low;
+ } else {
+ rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid,
+ &off_low, &param->w_mode, &remcnt, &param->w_count,
+ &data_offset);
+
+ param->w_offset = (uint64_t)off_low;
+ data_offset -= 59;
+ }
+
+ if (rc != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ if (SMB_WRMODE_IS_STABLE(param->w_mode) &&
+ STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_error(sr, ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+
+ rc = smbsr_decode_data(sr, "#.#B", data_offset, param->w_count,
+ &param->w_vdb);
+ if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ param->w_vdb.uio.uio_offset = param->w_offset;
+
+ if (param->w_count != 0) {
+ if ((rc = smb_write_common(sr, param)) != 0) {
+ kmem_free(param, sizeof (smb_write_param_t));
+ smbsr_raise_errno(sr, rc);
+ /* NOTREACHED */
+ }
+ }
+
+ smbsr_encode_result(sr, 6, 0, "bb1.ww6.w",
+ 6, sr->andx_com, 15, param->w_count, 0);
+
+ kmem_free(param, sizeof (smb_write_param_t));
+ return (SDRC_NORMAL_REPLY);
+}
+
+/*
+ * Common function for writing files or IPC/MSRPC named pipes.
+ *
+ * Returns errno values.
+ */
+int
+smb_write_common(struct smb_request *sr, smb_write_param_t *param)
+{
+ struct smb_ofile *ofile = sr->fid_ofile;
+ smb_node_t *node;
+ uint32_t stability = FSSTAB_UNSTABLE;
+ uint32_t lcount;
+ int rc = 0;
+
+ switch (sr->tid_tree->t_res_type & STYPE_MASK) {
+ case STYPE_DISKTREE:
+ node = ofile->f_node;
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, node, param->w_offset,
+ param->w_count, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, rc,
+ ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ if (SMB_WRMODE_IS_STABLE(param->w_mode) ||
+ (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
+ stability = FSSTAB_FILE_SYNC;
+ }
+
+ rc = smb_fsop_write(sr, sr->user_cr, node,
+ &param->w_vdb.uio, &lcount, &node->attr, &stability);
+
+ if (rc)
+ return (rc);
+
+ node->flags |= NODE_FLAGS_SYNCATIME;
+
+ if (node->flags & NODE_FLAGS_SET_SIZE) {
+ if ((param->w_offset + lcount) >= node->n_size) {
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+ node->n_size = param->w_offset + lcount;
+ }
+ }
+
+ param->w_count = (uint16_t)lcount;
+ break;
+
+ case STYPE_IPC:
+ param->w_count = (uint16_t)param->w_vdb.uio.uio_resid;
+
+ if ((rc = smb_rpc_write(sr, &param->w_vdb.uio)) != 0)
+ param->w_count = 0;
+ break;
+
+ default:
+ rc = EACCES;
+ break;
+ }
+
+ if (rc != 0)
+ return (rc);
+
+ mutex_enter(&ofile->f_mutex);
+ ofile->f_seek_pos = param->w_offset + param->w_count;
+ mutex_exit(&ofile->f_mutex);
+ return (rc);
+}
+
+/*
+ * Truncate a disk file to the specified offset.
+ * Typically, w_count will be zero here.
+ *
+ * Returns errno values.
+ */
+int
+smb_write_truncate(struct smb_request *sr, smb_write_param_t *param)
+{
+ struct smb_ofile *ofile = sr->fid_ofile;
+ smb_node_t *node = ofile->f_node;
+ int rc;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0)
+ return (0);
+
+ if (node->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, node, param->w_offset,
+ param->w_count, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, rc,
+ ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+ }
+
+ /*
+ * XXX what if the file has been opened only with
+ * FILE_APPEND_DATA?
+ */
+ rc = smb_ofile_access(ofile, sr->user_cr, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ /* NOTREACHED */
+ }
+
+ node->flags |= NODE_FLAGS_SET_SIZE;
+ node->n_size = param->w_offset;
+
+ if ((rc = smb_set_file_size(sr)) != 0)
+ return (rc);
+
+ mutex_enter(&ofile->f_mutex);
+ ofile->f_seek_pos = param->w_offset + param->w_count;
+ mutex_exit(&ofile->f_mutex);
+ return (0);
+}
+
+/*
+ * Set the file size using the value in the node. The file will only be
+ * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node
+ * pointer, we just return success.
+ *
+ * The node attributes are refreshed here from the file system. So any
+ * attributes that are affected by file size changes, i.e. the mtime,
+ * will be current.
+ *
+ * Note that smb_write_andx cannot be used to reduce the file size so,
+ * if this is required, smb_write is called with a count of zero and
+ * the appropriate file length in offset. The file should be resized
+ * to the length specified by the offset.
+ *
+ * Returns 0 on success. Otherwise returns EACCES.
+ */
+int
+smb_set_file_size(struct smb_request *sr)
+{
+ struct smb_node *node;
+ smb_attr_t new_attr;
+ uint32_t dosattr;
+
+ if ((node = sr->fid_ofile->f_node) == 0)
+ return (0);
+
+ if ((node->flags & NODE_FLAGS_SET_SIZE) == 0)
+ return (0);
+
+ node->flags &= ~NODE_FLAGS_SET_SIZE;
+
+ dosattr = smb_node_get_dosattr(node);
+
+ if (dosattr & SMB_FA_READONLY) {
+ if (((node->flags & NODE_FLAGS_CREATED) == 0) ||
+ (sr->session->s_kid != node->n_orig_session_id))
+ return (EACCES);
+ }
+
+ bzero(&new_attr, sizeof (new_attr));
+ new_attr.sa_vattr.va_size = node->n_size;
+ new_attr.sa_mask = SMB_AT_SIZE;
+
+ (void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr,
+ &node->attr);
+
+ return (0);
+}
+
+/*
+ * write_complete is sent acknowledge completion of raw write requests.
+ * We never send raw write commands to other servers so, if we receive a
+ * write_complete, we treat it as an error.
+ */
+int
+smb_com_write_complete(struct smb_request *sr)
+{
+ smbsr_decode_error(sr);
+ /* NOT REACHED */
+ return (0);
+}
+
+/*
+ * The Write Block Multiplexed protocol is used to maximize performance
+ * when writing a large block of data.
+ *
+ * The mpx sub protocol is not supported because we support only
+ * connection oriented transports and NT supports SMB_COM_READ_MPX
+ * only over connectionless transports.
+ */
+int /*ARGSUSED*/
+smb_com_write_mpx(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
+
+int /*ARGSUSED*/
+smb_com_write_mpx_secondary(struct smb_request *sr)
+{
+ return (SDRC_UNIMPLEMENTED);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
new file mode 100644
index 0000000000..5d02179cc2
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
@@ -0,0 +1,606 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB: write_raw
+ * 5.27 WRITE_RAW: Write Raw Bytes
+ *
+ * The Write Block Raw protocol is used to maximize the performance of
+ * writing a large block of data from the client to the server. The Write
+ * Block Raw command's scope includes files, Named Pipes, and spooled
+ * output (can be used in place COM_WRITE_PRINT_FILE ).
+ *
+ * Client Request Description
+ * ========================== =========================================
+ *
+ * UCHAR WordCount; Count of parameter words = 12
+ * USHORT Fid; File handle
+ * USHORT Count; Total bytes, including this buffer
+ * USHORT Reserved;
+ * ULONG Offset; Offset in file to begin write
+ * ULONG Timeout;
+ * USHORT WriteMode; Write mode:
+ * bit 0 - complete write to disk and send
+ * final result response
+ * bit 1 - return Remaining (pipe/dev)
+ * (see WriteAndX for #defines)
+ * ULONG Reserved2;
+ * USHORT DataLength; Number of data bytes this buffer
+ * USHORT DataOffset; Offset (from header start) to data
+ * USHORT ByteCount; Count of data bytes
+ * UCHAR Pad[]; Pad to SHORT or LONG
+ * UCHAR Data[]; Data (# = DataLength)
+ *
+ * First Server Response Description
+ * ============================== =====================================
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Remaining; Bytes remaining to be read if pipe
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * Final Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR Command (in SMB header) SMB_COM_WRITE_COMPLETE
+ *
+ * UCHAR WordCount; Count of parameter words = 1
+ * USHORT Count; Total number of bytes written
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * The first response format will be that of the final server response in
+ * the case where the server gets an error while writing the data sent
+ * along with the request. Thus Count is the number of bytes which did get
+ * written any time an error is returned. If an error occurs after the
+ * first response has been sent allowing the client to send the remaining
+ * data, the final response should not be sent unless write through is set.
+ * Rather the server should return this "write behind" error on the next
+ * access to the Fid.
+ *
+ * The client must guarantee that there is (and will be) no other request
+ * on the connection for the duration of this request. The server will
+ * reserve enough resources to receive the data and respond with a response
+ * SMB as defined above. The client then sends the raw data in one send.
+ * Thus the server is able to receive up to 65,535 bytes of data directly
+ * into the server buffer. The amount of data transferred is expected to
+ * be larger than the negotiated buffer size for this protocol.
+ *
+ * The reason that no other requests can be active on the connection for
+ * the duration of the request is that if other receives are present on the
+ * connection, there is normally no way to guarantee that the data will be
+ * received into the correct server buffer, rather the data may fill one
+ * (or more) of the other buffers. Also if the client is sending other
+ * requests on the connection, a request may land in the buffer that the
+ * server has allocated for the this SMB's data.
+ *
+ * Whether or not SMB_COM_WRITE_RAW is supported is returned in the
+ * response to SMB_COM_NEGOTIATE. SMB_COM_WRITE_RAW is not supported for
+ * connectionless clients.
+ *
+ * When write through is not specified ((WriteMode & 01) == 0) this SMB is
+ * assumed to be a form of write behind. The transport layer guarantees
+ * delivery of all secondary requests from the client. Thus no "got the
+ * data you sent" SMB is needed. If an error should occur at the server
+ * end, all bytes must be received and thrown away. If an error occurs
+ * while writing data to disk such as disk full, the next access of the
+ * file handle (another write, close, read, etc.) will return the fact that
+ * the error occurred.
+ *
+ * If write through is specified ((WriteMode & 01) != 0), the server will
+ * receive the data, write it to disk and then send a final response
+ * indicating the result of the write. The total number of bytes written
+ * is also returned in this response in the Count field.
+ *
+ * The flow for the SMB_COM_WRITE_RAW SMB is:
+ *
+ * client -----> SMB_COM_WRITE_RAW request (optional data) >-------> server
+ * client <------------------< OK send (more) data <---------------- server
+ * client ----------------------> raw data >----------------------> server
+ * client <---< data on disk or error (write through only) <------- server
+ *
+ * This protocol is set up such that the SMB_COM_WRITE_RAW request may also
+ * carry data. This is an optimization in that up to the server's buffer
+ * size (MaxCount from SMB_COM_NEGOTIATE response), minus the size of the
+ * SMB_COM_WRITE_RAW SMB request, may be sent along with the request. Thus
+ * if the server is busy and unable to support the raw write of the
+ * remaining data, the data sent along with the request has been delivered
+ * and need not be sent again. The server will write any data sent in the
+ * request (and wait for it to be on the disk or device if write through is
+ * set), prior to sending the response.
+ *
+ * The specific responses error class ERRSRV, error codes ERRusempx and
+ * ERRusestd, indicate that the server is temporarily out of the resources
+ *
+ * needed to support the raw write of the remaining data, but that any data
+ * sent along with the request has been successfully written. The client
+ * should then write the remaining data using a different type of SMB write
+ * request, or delay and retry using SMB_COM_WRITE_RAW. If a write error
+ * occurs writing the initial data, it will be returned and the write raw
+ * request is implicitly denied.
+ *
+ * The return field Remaining is returned for named pipes only. It is used
+ * to return the number of bytes currently available in the pipe. This
+ * information can then be used by the client to know when a subsequent
+ * (non blocking) read of the pipe may return some data. Of course when
+ * the read request is actually received by the server there may be more or
+ * less actual data in the pipe (more data has been written to the pipe /
+ * device or another reader drained it). If the information is currently
+ * not available or the request is NOT for a pipe or the server does not
+ * support this feature, a -1 value should be returned.
+ *
+ * If the negotiated dialect is NT LM 0.12 or later, and the response to
+ * the SMB_COM_NEGOTIATE SMB has CAP_LARGE_FILES set in the Capabilities
+ * field, an additional request format is allowed which accommodates very
+ * large files having 64 bit offsets:
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 14
+ * USHORT Fid; File handle
+ * USHORT Count; Total bytes, including this
+ * buffer
+ * USHORT Reserved;
+ * ULONG Offset; Offset in file to begin write
+ * ULONG Timeout;
+ * USHORT WriteMode; Write mode:
+ * bit 0 - complete write to disk
+ * and send final result response
+ * bit 1 - return Remaining
+ * (pipe/dev)
+ * ULONG Reserved2;
+ * USHORT DataLength; Number of data bytes this buffer
+ * USHORT DataOffset; Offset (from header start) to
+ * data
+ * ULONG OffsetHigh; Upper 32 bits of offset
+ * USHORT ByteCount; Count of data bytes
+ * UCHAR Pad[]; Pad to SHORT or LONG
+ * UCHAR Data[]; Data (# = DataLength)
+ *
+ * In this case the final offset in the file is formed by combining
+ * OffsetHigh and Offset, the resulting offset must not be negative.
+ */
+
+#include <sys/sdt.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/netbios.h>
+
+extern uint32_t smb_keep_alive;
+
+static int smb_write_raw_helper(struct smb_request *sr, struct uio *uiop,
+ unsigned int stability, offset_t *offp, uint32_t *lcountp);
+
+static int smb_transfer_write_raw_data(smb_request_t *sr,
+ uint16_t addl_xfer_count);
+
+#define WR_MODE_WR_THRU 1
+
+int
+smb_com_write_raw(struct smb_request *sr)
+{
+ int rc = 0;
+ int session_send_rc = 0;
+ unsigned short addl_xfer_count;
+ unsigned short count;
+ unsigned short write_mode, data_offset, data_length;
+ offset_t off;
+ uint32_t off_low, off_high, timeout;
+ uint32_t lcount = 0;
+ uint32_t addl_lcount = 0;
+ struct uio uio;
+ iovec_t iovec;
+ unsigned int stability;
+ struct mbuf_chain reply;
+ smb_node_t *fnode;
+
+ if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
+ return (SDRC_DROP_VC);
+ }
+
+ if (sr->smb_wct == 12) {
+ off_high = 0;
+ rc = smbsr_decode_vwv(sr, "ww2.llw4.ww", &sr->smb_fid, &count,
+ &off_low, &timeout, &write_mode, &data_length,
+ &data_offset);
+ data_offset -= 59;
+ } else {
+ rc = smbsr_decode_vwv(sr, "ww2.llw4.wwl", &sr->smb_fid, &count,
+ &off_low, &timeout, &write_mode, &data_length,
+ &data_offset, &off_high);
+ data_offset -= 63;
+ }
+
+ if (rc != 0) {
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ off = ((offset_t)off_high << 32) | off_low;
+ addl_xfer_count = count - data_length;
+
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ if (sr->fid_ofile == NULL) {
+ smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
+ ERRDOS, ERRbadfid);
+ /* NOTREACHED */
+ }
+
+ fnode = sr->fid_ofile->f_node;
+ stability = ((write_mode & WR_MODE_WR_THRU) ||
+ (fnode->flags & NODE_FLAGS_WRITE_THROUGH)) ?
+ FSSTAB_FILE_SYNC : FSSTAB_UNSTABLE;
+
+ if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ /*
+ * See comments in smb_write.c
+ */
+ if (fnode->attr.sa_vattr.va_type != VDIR) {
+ rc = smb_lock_range_access(sr, fnode, off,
+ count, FILE_WRITE_DATA);
+ if (rc != NT_STATUS_SUCCESS) {
+ smbsr_raise_cifs_error(sr, rc,
+ ERRSRV, ERRaccess);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ /*
+ * Make sure any raw write data that is supposed to be
+ * contained in this SMB is actually present.
+ */
+ if (sr->smb_data.chain_offset + data_offset + data_length >
+ sr->smb_data.max_bytes) {
+ /* Error handling code will wake up the session daemon */
+ smbsr_decode_error(sr);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Init uio (resid will get filled in later)
+ */
+ uio.uio_iov = &iovec;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_loffset = off;
+
+ /*
+ * Send response if there is additional data to transfer. This
+ * will prompt the client to send the remaining data.
+ */
+ if (addl_xfer_count != 0) {
+ MBC_INIT(&reply, MLEN);
+ (void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT "bww",
+ sr->first_smb_com,
+ sr->smb_rcls,
+ sr->smb_reh,
+ sr->smb_err,
+ sr->smb_flg | SMB_FLAGS_REPLY,
+ sr->smb_flg2,
+ sr->smb_pid_high,
+ sr->smb_sig,
+ sr->smb_tid,
+ sr->smb_pid,
+ sr->smb_uid,
+ sr->smb_mid, 1, -1, 0);
+
+ if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
+ smb_sign_reply(sr, &reply);
+
+ session_send_rc = smb_session_send(sr->session, 0, &reply);
+
+ /*
+ * If the session response failed we're not going to
+ * return an error just yet -- we can still write the
+ * data we received along with the SMB even if the
+ * response failed. If it failed, we need to force the
+ * stability level to "write-through".
+ */
+ stability =
+ (session_send_rc == 0) ? stability : FSSTAB_FILE_SYNC;
+ }
+
+ /*
+ * While the response is in flight (and the data begins to arrive)
+ * write out the first data segment. Start by setting up the
+ * iovec list for the first transfer.
+ */
+ iovec.iov_base = sr->smb_data.chain->m_data +
+ sr->smb_data.chain_offset + data_offset;
+ iovec.iov_len = data_length;
+ uio.uio_resid = data_length;
+
+ /*
+ * smb_write_raw_helper will call smb_rpc_write or
+ * smb_fsop_write as appropriate, handle the NODE_FLAGS_SET_SIZE
+ * flag (if set) and update the other f_node fields. It's possible
+ * that data_length may be 0 for this transfer but we still want
+ * process it since it will update the file state (seek position,
+ * file size (possibly), etc).
+ */
+ rc = smb_write_raw_helper(sr, &uio, stability, &off, &lcount);
+
+ /*
+ * If our initial session response failed then we're done. Return
+ * failure. The client will know we wrote some of the data because
+ * of the transfer count (count - lcount) in the response.
+ */
+ if (session_send_rc != 0) {
+ sr->smb_rcls = ERRSRV;
+ sr->smb_err = ERRusestd;
+ goto write_raw_transfer_failed;
+ }
+
+ /*
+ * If we have more data to read then go get it
+ */
+ if (addl_xfer_count) {
+ /*
+ * This is the only place where a worker thread should
+ * directly read from the session socket. If the data
+ * is read successfully then the buffer (sr->sr_raw_data_buf)
+ * will need to be freed after the data is written.
+ */
+ if (smb_transfer_write_raw_data(sr, addl_xfer_count) != 0) {
+ /*
+ * Raw data transfer failed
+ */
+ goto write_raw_transfer_failed;
+ }
+
+ /*
+ * Fill in next iov entry
+ */
+ iovec.iov_base = sr->sr_raw_data_buf;
+ iovec.iov_len = addl_xfer_count;
+ uio.uio_resid = addl_xfer_count;
+ }
+
+ /*
+ * Wake up session daemon since we now have all of our data and
+ * it's safe for the session daemon to resume processing SMB's.
+ */
+ sr->session->s_write_raw_status = 0;
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+
+ /*
+ * If we didn't write all the data from the first segment then
+ * there's not much point in continuing (we still wanted to
+ * read any additional data above since we don't necessarily
+ * want to drop the connection and we need to read through
+ * to the next SMB).
+ */
+ if ((rc != 0) || (lcount != data_length)) {
+ goto notify_write_raw_complete;
+ }
+
+ /*
+ * Write any additional data
+ */
+ if (addl_xfer_count) {
+ rc = smb_write_raw_helper(sr, &uio, stability, &off,
+ &addl_lcount);
+ }
+
+ /*
+ * If we were called in "Write-behind" mode ((write_mode & 1) == 0)
+ * and the transfer was successful then we don't need to send
+ * any further response. If we were called in "Write-Through" mode
+ * ((write_mode & 1) == 1) or if the transfer failed we need to
+ * send a completion notification. The "count" value will indicate
+ * whether the transfer was successful.
+ */
+ if ((rc != 0) || (write_mode & WR_MODE_WR_THRU) ||
+ (lcount + addl_lcount != count)) {
+ goto notify_write_raw_complete;
+ }
+
+ /*
+ * Free raw write buffer (allocated in smb_transfer_write_raw_data)
+ */
+ kmem_free(sr->sr_raw_data_buf, sr->sr_raw_data_length);
+
+ (void) smb_session_send(sr->session, SESSION_KEEP_ALIVE, NULL);
+ return (SDRC_NO_REPLY);
+
+write_raw_transfer_failed:
+ /*
+ * Raw data transfer failed, wake up session
+ * daemon
+ */
+ sr->session->s_write_raw_status = 20;
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+
+notify_write_raw_complete:
+ /*
+ * If we had an error fill in the appropriate error code
+ */
+ if (rc != 0) {
+ (void) smbsr_set_errno(sr, rc);
+ }
+ /*
+ * Free raw write buffer if present (from smb_transfer_write_raw_data)
+ */
+ if (sr->sr_raw_data_buf != NULL) {
+ kmem_free(sr->sr_raw_data_buf, sr->sr_raw_data_length);
+ }
+ /* Write complete notification */
+ sr->first_smb_com = SMB_COM_WRITE_COMPLETE;
+ smbsr_encode_result(sr, 1, 0, "bww", 1,
+ count - (lcount + addl_lcount), 0);
+ return (SDRC_NORMAL_REPLY);
+}
+
+
+
+/*
+ * smb_write_raw_helper
+ *
+ * This function will call smb_rpc_write or smb_fsop_write as appropriate,
+ * handle the NODE_FLAGS_SET_SIZE flag (if set) and update the other f_node
+ * fields. It's possible that data_length may be 0 for this transfer but
+ * we still want process it since it will update the file state (seek
+ * position, file size (possibly), etc).
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+static int
+smb_write_raw_helper(struct smb_request *sr, struct uio *uiop,
+ unsigned int stability, offset_t *offp, uint32_t *lcountp)
+{
+ smb_node_t *fnode;
+ int rc = 0;
+
+ if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
+ *lcountp = uiop->uio_resid;
+
+ if ((rc = smb_rpc_write(sr, uiop)) != 0)
+ *lcountp = 0;
+ } else {
+ fnode = sr->fid_ofile->f_node;
+ rc = smb_fsop_write(sr, sr->user_cr, fnode,
+ uiop, lcountp, &fnode->attr, &stability);
+
+ if (rc == 0) {
+
+ fnode->flags |= NODE_FLAGS_SYNCATIME;
+
+ if (fnode->flags & NODE_FLAGS_SET_SIZE) {
+ if ((*offp + *lcountp) >= fnode->n_size) {
+ fnode->flags &= ~NODE_FLAGS_SET_SIZE;
+ fnode->n_size = *offp + *lcountp;
+ }
+ }
+ }
+ }
+
+ *offp += *lcountp;
+ mutex_enter(&sr->fid_ofile->f_mutex);
+ sr->fid_ofile->f_seek_pos = *offp;
+ mutex_exit(&sr->fid_ofile->f_mutex);
+
+ return (rc);
+}
+
+
+/*
+ * smb_handle_write_raw
+ *
+ * Called from smb_session_daemon() when the SMB command is SMB_COM_WRITE_RAW.
+ * Dispatches the command to the worker thread and waits until the worker
+ * has completed processing the command.
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+int
+smb_handle_write_raw(smb_session_t *session, smb_request_t *sr)
+{
+ int drop_reason = 0;
+
+ /*
+ * Set flag to indicate that we are waiting for raw data. The
+ * worker thread will actually retrieve the raw data directly
+ * from the socket. This should be the only case when a worker
+ * thread reads from the session socket. When the data is read
+ * the worker will clear the flag.
+ */
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ session->s_state = SMB_SESSION_STATE_WRITE_RAW_ACTIVE;
+ smb_rwx_rwexit(&session->s_lock);
+ sr->sr_state = SMB_REQ_STATE_SUBMITTED;
+ (void) taskq_dispatch(smb_info.thread_pool, smb_session_worker,
+ sr, TQ_SLEEP);
+ smb_rwx_rwenter(&session->s_lock, RW_READER);
+ while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
+ (void) smb_rwx_rwwait(&session->s_lock, -1);
+ }
+ drop_reason = session->s_write_raw_status;
+ break;
+ default:
+ drop_reason = 21;
+ break;
+ }
+ smb_rwx_rwexit(&session->s_lock);
+ return (drop_reason);
+}
+
+/*
+ * smb_transfer_write_raw_data
+ *
+ * Handles the second transfer phase of SMB_COM_WRITE_RAW. smb_com_write_raw()
+ * will process the parameters and data from the SMB and send the initial
+ * SMB response. This function reads the remaining data from the socket
+ * as it arrives from the client.
+ *
+ * Clients may send KEEP_ALIVE messages (when using NBT) between the first
+ * and second parts of write raw requests. The only session transport
+ * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE.
+ *
+ * Returns 0 for success, non-zero for failure
+ */
+int
+smb_transfer_write_raw_data(smb_request_t *sr, uint16_t addl_xfer_count)
+{
+ smb_session_t *session = sr->session;
+ smb_xprt_t hdr;
+ uint8_t *data_buf;
+
+ do {
+ if (smb_session_xprt_gethdr(session, &hdr) != 0)
+ return (-1);
+
+ if ((hdr.xh_type == SESSION_MESSAGE) ||
+ (hdr.xh_type == SESSION_KEEP_ALIVE)) {
+ session->keep_alive = smb_keep_alive;
+ } else {
+ return (-1);
+ }
+ } while (hdr.xh_type == SESSION_KEEP_ALIVE);
+
+ if (hdr.xh_length < addl_xfer_count) {
+ /*
+ * Less data than we were expecting.
+ */
+ return (-1);
+ }
+
+ data_buf = kmem_alloc(hdr.xh_length, KM_SLEEP);
+
+ if (smb_sorecv(session->sock, data_buf, hdr.xh_length) != 0) {
+ kmem_free(data_buf, hdr.xh_length);
+ sr->sr_raw_data_buf = NULL;
+ sr->sr_raw_data_length = 0;
+ return (-1);
+ }
+
+ sr->sr_raw_data_buf = data_buf;
+ sr->sr_raw_data_length = hdr.xh_length;
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_xlate.c b/usr/src/uts/common/fs/smbsrv/smb_xlate.c
new file mode 100644
index 0000000000..ffe1aa199d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_xlate.c
@@ -0,0 +1,250 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_incl.h>
+
+struct xlate_table {
+ int code;
+ char *str;
+};
+
+struct xlate_table smb_xlate_com[] = {
+ { SMB_COM_CREATE_DIRECTORY, "CREATE_DIRECTORY" },
+ { SMB_COM_DELETE_DIRECTORY, "DELETE_DIRECTORY" },
+ { SMB_COM_OPEN, "OPEN" },
+ { SMB_COM_CREATE, "COM_CREATE" },
+ { SMB_COM_CLOSE, "CLOSE" },
+ { SMB_COM_FLUSH, "FLUSH" },
+ { SMB_COM_DELETE, "DELETE" },
+ { SMB_COM_RENAME, "RENAME" },
+ { SMB_COM_QUERY_INFORMATION, "QUERY_INFORMATION" },
+ { SMB_COM_SET_INFORMATION, "SET_INFORMATION" },
+ { SMB_COM_READ, "READ" },
+ { SMB_COM_WRITE, "WRITE" },
+ { SMB_COM_LOCK_BYTE_RANGE, "LOCK_BYTE_RANGE" },
+ { SMB_COM_UNLOCK_BYTE_RANGE, "UNLOCK_BYTE_RANGE" },
+ { SMB_COM_CREATE_TEMPORARY, "CREATE_TEMPORARY" },
+ { SMB_COM_CREATE_NEW, "CREATE_NEW" },
+ { SMB_COM_CHECK_DIRECTORY, "CHECK_DIRECTORY" },
+ { SMB_COM_PROCESS_EXIT, "PROCESS_EXIT" },
+ { SMB_COM_SEEK, "SEEK" },
+ { SMB_COM_LOCK_AND_READ, "LOCK_AND_READ" },
+ { SMB_COM_WRITE_AND_UNLOCK, "WRITE_AND_UNLOCK" },
+ { SMB_COM_READ_RAW, "READ_RAW" },
+ { SMB_COM_READ_MPX, "READ_MPX" },
+ { SMB_COM_READ_MPX_SECONDARY, "READ_MPX_SECONDARY" },
+ { SMB_COM_WRITE_RAW, "WRITE_RAW" },
+ { SMB_COM_WRITE_MPX, "WRITE_MPX" },
+ { SMB_COM_WRITE_COMPLETE, "WRITE_COMPLETE" },
+ { SMB_COM_SET_INFORMATION2, "SET_INFORMATION2" },
+ { SMB_COM_QUERY_INFORMATION2, "QUERY_INFORMATION2" },
+ { SMB_COM_LOCKING_ANDX, "LOCKING_ANDX" },
+ { SMB_COM_TRANSACTION, "TRANSACTION" },
+ { SMB_COM_TRANSACTION_SECONDARY, "TRANSACTION_SECONDARY" },
+ { SMB_COM_IOCTL, "IOCTL" },
+ { SMB_COM_IOCTL_SECONDARY, "IOCTL_SECONDARY" },
+ { SMB_COM_COPY, "COPY" },
+ { SMB_COM_MOVE, "MOVE" },
+ { SMB_COM_ECHO, "ECHO" },
+ { SMB_COM_WRITE_AND_CLOSE, "WRITE_AND_CLOSE" },
+ { SMB_COM_OPEN_ANDX, "OPEN_ANDX" },
+ { SMB_COM_READ_ANDX, "READ_ANDX" },
+ { SMB_COM_WRITE_ANDX, "WRITE_ANDX" },
+ { SMB_COM_CLOSE_AND_TREE_DISC, "CLOSE_AND_TREE_DISC" },
+ { SMB_COM_TRANSACTION2, "TRANSACTION2" },
+ { SMB_COM_TRANSACTION2_SECONDARY, "TRANSACTION2_SECONDARY" },
+ { SMB_COM_FIND_CLOSE2, "FIND_CLOSE2" },
+ { SMB_COM_FIND_NOTIFY_CLOSE, "FIND_NOTIFY_CLOSE" },
+ { SMB_COM_TREE_CONNECT, "TREE_CONNECT" },
+ { SMB_COM_TREE_DISCONNECT, "TREE_DISCONNECT" },
+ { SMB_COM_NEGOTIATE, "NEGOTIATE" },
+ { SMB_COM_SESSION_SETUP_ANDX, "SESSION_SETUP_ANDX" },
+ { SMB_COM_LOGOFF_ANDX, "LOGOFF_ANDX" },
+ { SMB_COM_TREE_CONNECT_ANDX, "TREE_CONNECT_ANDX" },
+ { SMB_COM_QUERY_INFORMATION_DISK, "QUERY_INFORMATION_DISK" },
+ { SMB_COM_SEARCH, "SEARCH" },
+ { SMB_COM_FIND, "FIND" },
+ { SMB_COM_FIND_UNIQUE, "FIND_UNIQUE" },
+ { SMB_COM_NT_TRANSACT, "NT_TRANSACT" },
+ { SMB_COM_NT_TRANSACT_SECONDARY, "NT_TRANSACT_SECONDARY" },
+ { SMB_COM_NT_CREATE_ANDX, "NT_CREATE_ANDX" },
+ { SMB_COM_NT_CANCEL, "NT_CANCEL" },
+ { SMB_COM_OPEN_PRINT_FILE, "OPEN_PRINT_FILE" },
+ { SMB_COM_WRITE_PRINT_FILE, "WRITE_PRINT_FILE" },
+ { SMB_COM_CLOSE_PRINT_FILE, "CLOSE_PRINT_FILE" },
+ { SMB_COM_GET_PRINT_QUEUE, "GET_PRINT_QUEUE" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_rcls[] = {
+ { SUCCESS, "SUCCESS" },
+ { ERRDOS, "ERRDOS" },
+ { ERRSRV, "ERRSRV" },
+ { ERRHRD, "ERRHRD" },
+ { ERRCMD, "ERRCMD" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_errdos[] = {
+ { ERRbadfunc, "ERRbadfunc" },
+ { ERRbadfile, "ERRbadfile" },
+ { ERRbadpath, "ERRbadpath" },
+ { ERRnofids, "ERRnofids" },
+ { ERRnoaccess, "ERRnoaccess" },
+ { ERRbadfid, "ERRbadfid" },
+ { ERRbadmcb, "ERRbadmcb" },
+ { ERRnomem, "ERRnomem" },
+ { ERRbadmem, "ERRbadmem" },
+ { ERRbadenv, "ERRbadenv" },
+ { ERRbadformat, "ERRbadformat" },
+ { ERRbadaccess, "ERRbadaccess" },
+ { ERRbaddata, "ERRbaddata" },
+ { ERRbaddrive, "ERRbaddrive" },
+ { ERRremcd, "ERRremcd" },
+ { ERRdiffdevice, "ERRdiffdevice" },
+ { ERRnofiles, "ERRnofiles" },
+ { ERRbadshare, "ERRbadshare" },
+ { ERRlock, "ERRlock" },
+ { ERRfilexists, "ERRfilexists" },
+ { ERRbadpipe, "ERRbadpipe" },
+ { ERRpipebusy, "ERRpipebusy" },
+ { ERRpipeclosing, "ERRpipeclosing" },
+ { ERRnotconnected, "ERRnotconnected" },
+ { ERRmoredata, "ERRmoredata" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_errsrv[] = {
+ { ERRerror, "ERRerror" },
+ { ERRbadpw, "ERRbadpw" },
+ { ERRaccess, "ERRaccess" },
+ { ERRinvnid, "ERRinvnid" },
+ { ERRinvnetname, "ERRinvnetname" },
+ { ERRinvdevice, "ERRinvdevice" },
+ { ERRqfull, "ERRqfull" },
+ { ERRqtoobig, "ERRqtoobig" },
+ { ERRqeof, "ERRqeof" },
+ { ERRinvpfid, "ERRinvpfid" },
+ { ERRsmbcmd, "ERRsmbcmd" },
+ { ERRsrverror, "ERRsrverror" },
+ { ERRfilespecs, "ERRfilespecs" },
+ { ERRbadpermits, "ERRbadpermits" },
+ { ERRsetattrmode, "ERRsetattrmode" },
+ { ERRpaused, "ERRpaused" },
+ { ERRmsgoff, "ERRmsgoff" },
+ { ERRnoroom, "ERRnoroom" },
+ { ERRrmuns, "ERRrmuns" },
+ { ERRtimeout, "ERRtimeout" },
+ { ERRnoresource, "ERRnoresource" },
+ { ERRtoomanyuids, "ERRtoomanyuids" },
+ { ERRbaduid, "ERRbaduid" },
+ { ERRusempx, "ERRusempx" },
+ { ERRusestd, "ERRusestd" },
+ { ERRcontmpx, "ERRcontmpx" },
+ { ERRnosupport, "ERRnosupport" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_errhrd[] = {
+ { ERRnowrite, "ERRnowrite" },
+ { ERRbadunit, "ERRbadunit" },
+ { ERRnotready, "ERRnotready" },
+ { ERRbadcmd, "ERRbadcmd" },
+ { ERRdata, "ERRdata" },
+ { ERRbadreq, "ERRbadreq" },
+ { ERRseek, "ERRseek" },
+ { ERRbadmedia, "ERRbadmedia" },
+ { ERRbadsector, "ERRbadsector" },
+ { ERRnopaper, "ERRnopaper" },
+ { ERRwrite, "ERRwrite" },
+ { ERRread, "ERRread" },
+ { ERRgeneral, "ERRgeneral" },
+ { ERRbadshare, "ERRbadshare" },
+ { ERRlock, "ERRlock" },
+ { ERRwrongdisk, "ERRwrongdisk" },
+ { ERRFCBUnavail, "ERRFCBUnavail" },
+ { ERRsharebufexc, "ERRsharebufexc" },
+ { 0 }
+};
+
+struct xlate_table smb_xlate_dialect[] = {
+ { DIALECT_UNKNOWN, "DIALECT_UNKNOWN" },
+ { PC_NETWORK_PROGRAM_1_0, "PC NETWORK PROGRAM 1.0" },
+ { PCLAN1_0, "PCLAN1.0" },
+ { MICROSOFT_NETWORKS_1_03, "MICROSOFT NETWORKS 1.03" },
+ { MICROSOFT_NETWORKS_3_0, "MICROSOFT NETWORKS 3.0" },
+ { LANMAN1_0, "LANMAN1.0" },
+ { LM1_2X002, "LM1.2X002" },
+ { DOS_LM1_2X002, "DOS LM1.2X002" },
+ { DOS_LANMAN2_1, "DOS LANMAN2.1" },
+ { LANMAN2_1, "LANMAN2.1" },
+ { Windows_for_Workgroups_3_1a, "Windows for Workgroups 3.1a" },
+ { NT_LM_0_12, "NT LM 0.12" },
+ { 0 }
+};
+
+static char *
+smb_xlate_cd_to_str(struct xlate_table *xl, int cd)
+{
+ static char no_answer[32];
+
+ for (; xl->str; xl++)
+ if (xl->code == cd)
+ return (xl->str);
+
+ (void) sprintf(no_answer, "-%x-", cd);
+
+ return (no_answer);
+}
+
+static int
+smb_xlate_str_to_cd(struct xlate_table *xl, char *str)
+{
+ for (; xl->str; xl++)
+ if (strcmp(xl->str, str) == 0)
+ return (xl->code);
+ return (-1);
+}
+
+
+char *
+smb_xlate_com_cd_to_str(int com)
+{
+ return (smb_xlate_cd_to_str(smb_xlate_com, com));
+}
+
+char *
+smb_xlate_dialect_cd_to_str(int dialect)
+{
+ return (smb_xlate_cd_to_str(smb_xlate_dialect, dialect));
+}
+
+int
+smb_xlate_dialect_str_to_cd(char *str)
+{
+ return (smb_xlate_str_to_cd(smb_xlate_dialect, str));
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smbsrv.conf b/usr/src/uts/common/fs/smbsrv/smbsrv.conf
new file mode 100644
index 0000000000..11ecccbccf
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smbsrv.conf
@@ -0,0 +1,27 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+name="smbsrv" parent="pseudo";
diff --git a/usr/src/uts/common/fs/sockfs/nl7c.c b/usr/src/uts/common/fs/sockfs/nl7c.c
index 19900ed654..002d111c3a 100644
--- a/usr/src/uts/common/fs/sockfs/nl7c.c
+++ b/usr/src/uts/common/fs/sockfs/nl7c.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,21 +31,21 @@
* (Hypertext Transfer Protocol, see HTTP/1.1 RFC2616) in a semantically
* transparent manner.
*
- * Neither the requesting user agent (client, e.g. web broweser) nor the
+ * Neither the requesting user agent (client, e.g. web browser) nor the
* origin server (e.g. webserver) that provided the response cached by
* NL7C are impacted in any way.
*
* Note, currently NL7C only processes HTTP messages via the embedded
* URI of scheme http (not https nor any other), additional scheme are
- * intended to be supproted as is practical such that much of the NL7C
- * framework may appear more gerneral purpose then would be needed just
+ * intended to be supported as is practical such that much of the NL7C
+ * framework may appear more general purpose then would be needed just
* for an HTTP gateway cache.
*
* NL7C replaces NCA (Network Cache and Accelerator) and in the future
* NCAS (NCA/SSL).
*
* Further, NL7C uses all NCA configuration files, see "/etc/nca/", the
- * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatability.
+ * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatibility.
*/
#include <sys/systm.h>
@@ -351,7 +351,7 @@ inet_atob(char *s, nl7c_addr_t *p)
* IPaddr - an IPv4 numeric dot address (e.g. 192.168.84.71) or '*' for
* INADDR_ANY, or an IPv6 numeric address or "::" for IN6ADDR_ANY.
*
- * / - IPaddr/Port seperator.
+ * / - IPaddr/Port separator.
*
* Port - a TCP decimal port number.
*
@@ -517,7 +517,7 @@ ncaportconf_read(void)
if (addrp != NULL) {
kmem_free(addrp, sizeof (*addrp));
}
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -620,7 +620,7 @@ ncakmodconf_read(void)
}
done:
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
@@ -797,7 +797,7 @@ ncalogdconf_read(void)
/* Opening delimiter, skip */
/*EMPTY*/;
} else if (c == '"' || c == ' ') {
- /* List delim or filename seperator */
+ /* List delim or filename separator */
*fnvp++ = strdup(file);
fp = file;
} else if (fp < &file[sizeof (file) - 1]) {
@@ -820,7 +820,7 @@ ncalogdconf_read(void)
}
done:
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
if (nl7c_logd_enabled) {
@@ -912,7 +912,7 @@ nl7c_init()
*
* 2) URI scheme not reqcognized.
*
- * 3) A request which can't be procesed.
+ * 3) A request which can't be processed.
*
* 4) A request which could be processed but NL7C dosen't currently have
* the response data. In which case NL7C will parse the returned response
@@ -980,9 +980,9 @@ nl7c_process(struct sonode *so, boolean_t nonblocking)
* First time through, if no data left over from a previous
* kstrgetmsg() then try to get some, else just process it.
*
- * Thereafter, rmp = NULL after the successfull kstrgetmsg()
+ * Thereafter, rmp = NULL after the successful kstrgetmsg()
* so try to get some new data and append to list (i.e. until
- * enough fragments are collected for a successfull parse).
+ * enough fragments are collected for a successful parse).
*/
if (rmp == NULL) {
diff --git a/usr/src/uts/common/fs/sockfs/nl7clogd.c b/usr/src/uts/common/fs/sockfs/nl7clogd.c
index f7a1a8afe9..1580a08c6c 100644
--- a/usr/src/uts/common/fs/sockfs/nl7clogd.c
+++ b/usr/src/uts/common/fs/sockfs/nl7clogd.c
@@ -57,7 +57,7 @@ static void logit_flush(void *);
* in the "/var/nca" directory.
*
* NL7C reuses the NCA logging APIs defined in <inet/nca/ncalogd.h>, at
- * some future date (when NCA is depricated or improvements are needed)
+ * some future date (when NCA is deprecated or improvements are needed)
* these need to be moved into NL7C.
*
* NL7C implements logging differently in 2 ways, 1st the initialization
@@ -278,7 +278,7 @@ next:
mutex_exit(lock);
/* Close current file */
ret = VOP_CLOSE(nca_fio_vp(&fio), FCREAT|FWRITE|FAPPEND|FTRUNC,
- 1, (offset_t)0, kcred);
+ 1, (offset_t)0, kcred, NULL);
nca_fio_vp(&fio) = NULL;
if (ret) {
cmn_err(CE_WARN, "nl7c_logd: close of %s failed (error %d)",
@@ -319,13 +319,13 @@ next:
/* Turn on directio */
(void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO,
- DIRECTIO_ON, 0, kcred, NULL);
+ DIRECTIO_ON, 0, kcred, NULL, NULL);
/* Start writing from the begining of the file */
nca_fio_offset(&fio) = 0;
/* Remove the current symlink */
- (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred);
+ (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred, NULL, 0);
attr.va_mask = AT_MODE | AT_TYPE;
attr.va_mode = 0777;
@@ -333,7 +333,7 @@ next:
/* Create symlink to the new log file */
ret = VOP_SYMLINK(nca_fio_dvp(&fio), symlink,
- &attr, nca_fio_name(&fio), kcred);
+ &attr, nca_fio_name(&fio), kcred, NULL, 0);
if (ret) {
cmn_err(CE_WARN, "nl7c_logd: symlink of %s to %s failed",
symlink, nca_fio_name(&fio));
@@ -469,9 +469,9 @@ nl7c_logd_init(int fsz, caddr_t *fnv)
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_loffset = 0;
uio.uio_fmode = 0;
- ret = VOP_READLINK(svp, &uio, kcred);
+ ret = VOP_READLINK(svp, &uio, kcred, NULL);
if (ret) {
- (void) VOP_REMOVE(dvp, symlink, kcred);
+ (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
goto fresh_start;
}
@@ -498,9 +498,9 @@ nl7c_logd_init(int fsz, caddr_t *fnv)
goto error;
}
nca_fio_vp(&fio) = vp;
- (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL);
+ (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL, NULL);
attr.va_mask = AT_SIZE;
- ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, 0);
+ ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, NULL, NULL);
if (ret) {
cmn_err(CE_WARN, "nl7c_logd_init: getattr of %s failed", *fnp);
goto error;
@@ -520,8 +520,9 @@ fresh_start:
attr.va_mask = AT_MODE | AT_TYPE;
attr.va_mode = 0777;
attr.va_type = VLNK;
- (void) VOP_REMOVE(dvp, symlink, kcred);
- ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred);
+ (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
+ ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred, NULL,
+ 0);
if (ret) {
cmn_err(CE_WARN, "nl7c_logd_init: symlink of %s to %s failed",
symlink_path, nca_fio_name(&fio));
@@ -537,7 +538,7 @@ fresh_start:
/* Turn on directio */
(void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO,
- DIRECTIO_ON, 0, kcred, NULL);
+ DIRECTIO_ON, 0, kcred, NULL, NULL);
finish:
log_buf_kmc = kmem_cache_create("NL7C_log_buf_kmc", sizeof (log_buf_t),
diff --git a/usr/src/uts/common/fs/sockfs/socksctp.c b/usr/src/uts/common/fs/sockfs/socksctp.c
index fbaf68195e..68212f5d15 100644
--- a/usr/src/uts/common/fs/sockfs/socksctp.c
+++ b/usr/src/uts/common/fs/sockfs/socksctp.c
@@ -403,7 +403,7 @@ sosctp_create(vnode_t *accessvp, int domain, int type, int protocol,
*/
if ((cr = CRED()) == NULL)
cr = kcred;
- if ((error = VOP_OPEN(&vp, soflags, cr)) != 0) {
+ if ((error = VOP_OPEN(&vp, soflags, cr, NULL)) != 0) {
VN_RELE(vp);
*errorp = error;
return (NULL);
@@ -457,7 +457,7 @@ sosctp_free(struct sonode *so)
mp->b_next = NULL;
nso = *(struct sonode **)mp->b_rptr;
- (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED());
+ (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED(), NULL);
vn_invalid(SOTOV(nso));
VN_RELE(SOTOV(nso));
@@ -531,7 +531,7 @@ sosctp_accept(struct sonode *lso, int fflag, struct sonode **nsop)
if (error != 0) {
vnode_t *nvp;
nvp = SOTOV(nso);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
/*
@@ -1104,7 +1104,7 @@ sosctp_uiomove(mblk_t *hdr_mp, ssize_t count, ssize_t blk_size, int wroff,
/*
* As a message can be splitted up and sent in different
* packets, each mblk will have the extra space before
- * data to accomodate what SCTP wants to put in there.
+ * data to accommodate what SCTP wants to put in there.
*/
while ((mp = allocb_cred(size + wroff, cr)) == NULL) {
if ((uiop->uio_fmode & (FNDELAY|FNONBLOCK)) ||
diff --git a/usr/src/uts/common/fs/sockfs/socksctpvnops.c b/usr/src/uts/common/fs/sockfs/socksctpvnops.c
index ea3c49ce6e..214cf4f859 100644
--- a/usr/src/uts/common/fs/sockfs/socksctpvnops.c
+++ b/usr/src/uts/common/fs/sockfs/socksctpvnops.c
@@ -64,19 +64,21 @@
/*
* SCTP sockfs vnode operations
*/
-static int socksctpv_open(struct vnode **, int, struct cred *);
+static int socksctpv_open(struct vnode **, int, struct cred *,
+ caller_context_t *);
static int socksctpv_close(struct vnode *, int, int, offset_t,
- struct cred *);
+ struct cred *, caller_context_t *);
static int socksctpv_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksctpv_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksctpv_ioctl(struct vnode *, int, intptr_t, int,
- struct cred *, int32_t *);
-static int socksctp_setfl(vnode_t *, int, int, cred_t *);
-static void socksctpv_inactive(struct vnode *, struct cred *);
+ struct cred *, int32_t *, caller_context_t *);
+static int socksctp_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+static void socksctpv_inactive(struct vnode *, struct cred *,
+ caller_context_t *);
static int socksctpv_poll(struct vnode *, short, int, short *,
- struct pollhead **);
+ struct pollhead **, caller_context_t *);
const fs_operation_def_t socksctp_vnodeops_template[] = {
VOPNAME_OPEN, { .vop_open = socksctpv_open },
@@ -98,8 +100,10 @@ const fs_operation_def_t socksctp_vnodeops_template[] = {
};
struct vnodeops *socksctp_vnodeops;
+/*ARGSUSED3*/
static int
-socksctpv_open(struct vnode **vpp, int flag, struct cred *cr)
+socksctpv_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -157,7 +161,7 @@ socksctpv_open(struct vnode **vpp, int flag, struct cred *cr)
/*ARGSUSED*/
static int
socksctpv_close(struct vnode *vp, int flag, int count, offset_t offset,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -244,7 +248,7 @@ socksctpv_close(struct vnode *vp, int flag, int count, offset_t offset,
/*ARGSUSED2*/
static int
socksctpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
struct nmsghdr lmsg;
@@ -267,7 +271,7 @@ socksctpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
/*ARGSUSED2*/
static int
socksctpv_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sctp_sonode *ss;
struct sonode *so;
@@ -361,7 +365,7 @@ error_ret:
/*ARGSUSED4*/
static int
socksctpv_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
- struct cred *cr, int32_t *rvalp)
+ struct cred *cr, int32_t *rvalp, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -720,7 +724,8 @@ peelerr:
*/
/* ARGSUSED */
static int
-socksctp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+socksctp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sonode *so;
@@ -741,7 +746,7 @@ socksctp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
/*ARGSUSED*/
static void
-socksctpv_inactive(struct vnode *vp, struct cred *cr)
+socksctpv_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
@@ -804,9 +809,10 @@ socksctpv_inactive(struct vnode *vp, struct cred *cr)
/*
* Check socktpi_poll() on why so_lock is not held in this function.
*/
+/*ARGSUSED5*/
static int
socksctpv_poll(struct vnode *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
struct sonode *so;
struct sctp_sonode *ss;
diff --git a/usr/src/uts/common/fs/sockfs/socksdp.c b/usr/src/uts/common/fs/sockfs/socksdp.c
index fab7c9d861..09ab4d0b49 100755
--- a/usr/src/uts/common/fs/sockfs/socksdp.c
+++ b/usr/src/uts/common/fs/sockfs/socksdp.c
@@ -345,7 +345,7 @@ sosdp_create(vnode_t *accessvp, int domain, int type, int protocol,
*/
if ((cr = CRED()) == NULL)
cr = kcred;
- if ((error = VOP_OPEN(&vp, soflags, cr)) != 0) {
+ if ((error = VOP_OPEN(&vp, soflags, cr, NULL)) != 0) {
VN_RELE(vp);
*errorp = error;
return (NULL);
@@ -391,7 +391,7 @@ sosdp_free(struct sonode *so)
mp->b_next = NULL;
nso = *(struct sonode **)mp->b_rptr;
- (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED());
+ (void) VOP_CLOSE(SOTOV(nso), 0, 1, 0, CRED(), NULL);
vn_invalid(SOTOV(nso));
VN_RELE(SOTOV(nso));
diff --git a/usr/src/uts/common/fs/sockfs/socksdpvnops.c b/usr/src/uts/common/fs/sockfs/socksdpvnops.c
index 667010ddea..0993bff6a4 100755
--- a/usr/src/uts/common/fs/sockfs/socksdpvnops.c
+++ b/usr/src/uts/common/fs/sockfs/socksdpvnops.c
@@ -63,19 +63,21 @@
/*
* SDP sockfs vnode operations
*/
-static int socksdpv_open(struct vnode **, int, struct cred *);
+static int socksdpv_open(struct vnode **, int, struct cred *,
+ caller_context_t *);
static int socksdpv_close(struct vnode *, int, int, offset_t,
- struct cred *);
+ struct cred *, caller_context_t *);
static int socksdpv_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksdpv_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socksdpv_ioctl(struct vnode *, int, intptr_t, int,
- struct cred *, int32_t *);
-static int socksdp_setfl(vnode_t *, int, int, cred_t *);
-static void socksdpv_inactive(struct vnode *, struct cred *);
+ struct cred *, int32_t *, caller_context_t *);
+static int socksdp_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+static void socksdpv_inactive(struct vnode *, struct cred *,
+ caller_context_t *);
static int socksdpv_poll(struct vnode *, short, int, short *,
- struct pollhead **);
+ struct pollhead **, caller_context_t *);
const fs_operation_def_t socksdp_vnodeops_template[] = {
VOPNAME_OPEN, { .vop_open = socksdpv_open },
@@ -97,8 +99,10 @@ const fs_operation_def_t socksdp_vnodeops_template[] = {
};
struct vnodeops *socksdp_vnodeops;
+/*ARGSUSED3*/
static int
-socksdpv_open(struct vnode **vpp, int flag, struct cred *cr)
+socksdpv_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so;
struct sdp_sonode *ss;
@@ -149,7 +153,7 @@ socksdpv_open(struct vnode **vpp, int flag, struct cred *cr)
/*ARGSUSED*/
static int
socksdpv_close(struct vnode *vp, int flag, int count, offset_t offset,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
int sendsig = 0;
int error = 0;
@@ -212,7 +216,7 @@ socksdpv_close(struct vnode *vp, int flag, int count, offset_t offset,
/*ARGSUSED2*/
static int
socksdpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
struct nmsghdr lmsg;
@@ -235,7 +239,7 @@ socksdpv_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
/*ARGSUSED2*/
static int
socksdpv_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so;
ssize_t count;
@@ -281,7 +285,7 @@ socksdpv_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cr,
/*ARGSUSED4*/
static int
socksdpv_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
- struct cred *cr, int32_t *rvalp)
+ struct cred *cr, int32_t *rvalp, caller_context_t *ct)
{
struct sonode *so;
struct sdp_sonode *ss;
@@ -400,7 +404,8 @@ socksdpv_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
*/
/* ARGSUSED */
static int
-socksdp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+socksdp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sonode *so;
@@ -421,7 +426,7 @@ socksdp_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
/*ARGSUSED*/
static void
-socksdpv_inactive(struct vnode *vp, struct cred *cr)
+socksdpv_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct sonode *so;
@@ -457,9 +462,10 @@ socksdpv_inactive(struct vnode *vp, struct cred *cr)
/*
* Check socktpi_poll() on why so_lock is not held in this function.
*/
+/*ARGSUSED5*/
static int
socksdpv_poll(struct vnode *vp, short events, int anyyet, short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp, caller_context_t *ct)
{
struct sonode *so;
struct sdp_sonode *ss;
diff --git a/usr/src/uts/common/fs/sockfs/socksubr.c b/usr/src/uts/common/fs/sockfs/socksubr.c
index ad90f21a36..cbacac2495 100644
--- a/usr/src/uts/common/fs/sockfs/socksubr.c
+++ b/usr/src/uts/common/fs/sockfs/socksubr.c
@@ -918,7 +918,7 @@ so_ux_lookup(struct sonode *so, struct sockaddr_un *soun, int checkaccess,
* vnode. This check is not done in BSD but it is required
* by X/Open.
*/
- if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED())) {
+ if (error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL)) {
eprintsoline(so, error);
goto done2;
}
diff --git a/usr/src/uts/common/fs/sockfs/socksyscalls.c b/usr/src/uts/common/fs/sockfs/socksyscalls.c
index 757a353982..90ddae2a95 100644
--- a/usr/src/uts/common/fs/sockfs/socksyscalls.c
+++ b/usr/src/uts/common/fs/sockfs/socksyscalls.c
@@ -185,7 +185,7 @@ so_socket(int domain, int type, int protocol, char *devpath, int version)
&protocol,
(t_uscalar_t)sizeof (protocol));
if (error) {
- (void) VOP_CLOSE(vp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
VN_RELE(vp);
/*
* Setsockopt often fails with ENOPROTOOPT but socket()
@@ -199,7 +199,7 @@ so_socket(int domain, int type, int protocol, char *devpath, int version)
}
}
if (error = falloc(vp, FWRITE|FREAD, &fp, &fd)) {
- (void) VOP_CLOSE(vp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
VN_RELE(vp);
return (set_errno(error));
}
@@ -533,14 +533,14 @@ so_socketpair(int sv[2])
mutex_exit(&so2->so_lock);
nvp = SOTOV(nso);
if (error != 0) {
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
eprintsoline(so2, error);
goto done;
}
if (error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd)) {
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
eprintsoline(nso, error);
goto done;
@@ -720,13 +720,13 @@ accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
nso->so_faddr_sa, (socklen_t)nso->so_faddr_len);
if (error) {
setf(nfd, NULL);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
return (set_errno(error));
}
if (error = falloc(NULL, FWRITE|FREAD, &nfp, NULL)) {
setf(nfd, NULL);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
eprintsoline(so, error);
return (set_errno(error));
@@ -754,7 +754,8 @@ accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
* This code is a simplification of the F_SETFL code in fcntl()
* Ignore any errors from VOP_SETFL.
*/
- if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred)) != 0) {
+ if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
+ != 0) {
eprintsoline(so, error);
error = 0;
} else {
@@ -1734,7 +1735,7 @@ done:
* processed by a thread, it produces a number of mblk_t structures to
* be consumed by the sendfile thread. snf_deque and snf_enque are
* used for consuming and producing mblks. Size of the filesystem
- * read is determined by the tuneable (sendfile_read_size). A single
+ * read is determined by the tunable (sendfile_read_size). A single
* mblk holds sendfile_read_size worth of data (except the last
* read of the file) which is sent down as a whole to the network.
* sendfile_read_size is set to 1 MB as this seems to be the optimal
@@ -1752,7 +1753,7 @@ done:
* a) One of the threads need to clean the mblks.
* b) When one thread encounters an error, the other should stop.
*
- * For (a), we don't want to penalise the reader thread as it could do
+ * For (a), we don't want to penalize the reader thread as it could do
* some useful work processing other requests. For (b), the error can
* be detected by examining sr_read_error or sr_write_error.
* sr_lock protects sr_read_error and sr_write_error. If both reader and
@@ -1795,7 +1796,7 @@ done:
* control, it would take 25ms to get new data ready for transmission.
* We have to make sure that network is not idling, while we are initiating
* new transfers. So, at 100MB/sec, to keep network busy we would need
- * 2.5MB of data. Roundig off, we keep the low water mark to be 3MB of data.
+ * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
* We need to pick a high water mark so that the woken up thread would
* do considerable work before blocking again to prevent thrashing. Currently,
* we pick this to be 10 times that of the low water mark.
@@ -1946,7 +1947,7 @@ snf_async_read(snf_req_t *sr)
* Ignore the error for filesystems that doesn't support DIRECTIO.
*/
(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
- kcred, NULL);
+ kcred, NULL, NULL);
while ((size != 0) && (sr->sr_write_error == 0)) {
@@ -1970,7 +1971,7 @@ snf_async_read(snf_req_t *sr)
fileoff += ret_size;
}
(void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
- kcred, NULL);
+ kcred, NULL, NULL);
mutex_enter(&sr->sr_lock);
sr->sr_read_error = error;
sr->sr_read_error |= SR_READ_DONE;
@@ -2301,7 +2302,7 @@ snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(fvp, &va, 0, kcred);
+ error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
if (error)
break;
/* Read as much as possible. */
@@ -2401,7 +2402,7 @@ snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
fileoff += iosize;
(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(fvp, &va, 0, kcred);
+ error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
if (error)
break;
/* Read as much as possible. */
@@ -2466,7 +2467,7 @@ sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
goto out;
}
fvp = rfp->f_vnode;
- if (VOP_REALVP(fvp, &realvp) == 0)
+ if (VOP_REALVP(fvp, &realvp, NULL) == 0)
fvp = realvp;
/*
* Grab the lock as a reader to prevent the file size
@@ -2474,7 +2475,7 @@ sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
*/
(void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(fvp, &va, 0, kcred);
+ error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
va_size = va.va_size;
if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
@@ -2560,7 +2561,7 @@ sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
#endif /* _SYSCALL32_IMPL */
/*
- * Function wrappers (mostly arround the sonode switch) for
+ * Function wrappers (mostly around the sonode switch) for
* backward compatibility.
*/
diff --git a/usr/src/uts/common/fs/sockfs/socktpi.c b/usr/src/uts/common/fs/sockfs/socktpi.c
index 65a10f0690..a198c17176 100644
--- a/usr/src/uts/common/fs/sockfs/socktpi.c
+++ b/usr/src/uts/common/fs/sockfs/socktpi.c
@@ -287,14 +287,14 @@ sotpi_create(vnode_t *accessvp, int domain, int type, int protocol, int version,
so->so_kssl_ent = NULL;
so->so_kssl_ctx = NULL;
- if (error = socktpi_open(&vp, flags, CRED())) {
+ if (error = socktpi_open(&vp, flags, CRED(), NULL)) {
VN_RELE(vp);
*errorp = error;
return (NULL);
}
if (error = so_strinit(so, tso)) {
- (void) VOP_CLOSE(vp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(vp, 0, 1, 0, CRED(), NULL);
VN_RELE(vp);
*errorp = error;
return (NULL);
@@ -1753,7 +1753,7 @@ again:
*/
mutex_exit(&nso->so_lock);
(void) VOP_CLOSE(nvp, 0, 1, (offset_t)0,
- CRED());
+ CRED(), NULL);
VN_RELE(nvp);
goto again;
}
@@ -1900,7 +1900,7 @@ e_disc_unl:
pr_disc_vp_unl:
eprintsoline(so, error);
disconnect_vp_unlocked:
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
disconnect_unlocked:
(void) sodisconnect(so, SEQ_number, 0);
@@ -1912,7 +1912,7 @@ disconnect_vp:
(void) sodisconnect(so, SEQ_number, _SODISCONNECT_LOCK_HELD);
so_unlock_single(so, SOLOCKED);
mutex_exit(&so->so_lock);
- (void) VOP_CLOSE(nvp, 0, 1, 0, CRED());
+ (void) VOP_CLOSE(nvp, 0, 1, 0, CRED(), NULL);
VN_RELE(nvp);
return (error);
diff --git a/usr/src/uts/common/fs/sockfs/sockvnops.c b/usr/src/uts/common/fs/sockfs/sockvnops.c
index 3ab7626e6f..6c122c679d 100644
--- a/usr/src/uts/common/fs/sockfs/sockvnops.c
+++ b/usr/src/uts/common/fs/sockfs/sockvnops.c
@@ -95,16 +95,17 @@
#include <inet/kssl/ksslapi.h>
-static int socktpi_close(struct vnode *, int, int, offset_t, struct cred *);
+static int socktpi_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *);
static int socktpi_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socktpi_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int socktpi_plumbioctl(struct vnode *, int, intptr_t, int, struct cred *,
int32_t *);
-static void socktpi_inactive(struct vnode *, struct cred *);
+static void socktpi_inactive(struct vnode *, struct cred *, caller_context_t *);
static int socktpi_poll(struct vnode *, short, int, short *,
- struct pollhead **);
+ struct pollhead **, caller_context_t *);
struct vnodeops *socktpi_vnodeops;
@@ -148,7 +149,8 @@ boolean_t socktpi_direct = B_TRUE;
* open/closes for a given vnode which is probably not needed.
*/
int
-socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
+socktpi_open(struct vnode **vpp, int flag, struct cred *cr,
+ caller_context_t *ct)
{
major_t maj;
dev_t newdev;
@@ -196,7 +198,7 @@ socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
* this is a post SVR4 tty driver - a socket can not
* be a controlling terminal. Fail the open.
*/
- (void) socktpi_close(vp, flag, 1, (offset_t)0, cr);
+ (void) socktpi_close(vp, flag, 1, (offset_t)0, cr, ct);
return (ENOTTY); /* XXX */
}
@@ -249,7 +251,7 @@ socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
_SIOCSOCKFALLBACK, 0, 0, K_TO_K,
CRED(), &rval)) != 0) {
(void) socktpi_close(vp, flag,
- 1, (offset_t)0, cr);
+ 1, (offset_t)0, cr, ct);
return (error);
}
}
@@ -273,7 +275,7 @@ socktpi_open(struct vnode **vpp, int flag, struct cred *cr)
so_unlock_single(so, SOLOCKED);
mutex_exit(&so->so_lock);
(void) socktpi_close(vp, flag, 1,
- (offset_t)0, cr);
+ (offset_t)0, cr, ct);
return (error);
/*NOTREACHED*/
}
@@ -297,7 +299,8 @@ socktpi_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so;
dev_t dev;
@@ -402,7 +405,7 @@ socktpi_read(
struct uio *uiop,
int ioflag,
struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
struct nmsghdr lmsg;
@@ -428,11 +431,11 @@ socktpi_read(
/* ARGSUSED2 */
static int
socktpi_write(
- struct vnode *vp,
- struct uio *uiop,
- int ioflag,
- struct cred *cr,
- struct caller_context *ct)
+ struct vnode *vp,
+ struct uio *uiop,
+ int ioflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
int so_state;
@@ -531,9 +534,10 @@ so_copyout(const void *from, void *to, size_t size, int tokernel)
return (xcopyout(from, to, size));
}
+/*ARGSUSED6*/
int
socktpi_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
- struct cred *cr, int32_t *rvalp)
+ struct cred *cr, int32_t *rvalp, caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
int error = 0;
@@ -941,7 +945,8 @@ socktpi_plumbioctl(struct vnode *vp, int cmd, intptr_t arg, int mode,
*/
/* ARGSUSED */
int
-socktpi_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr)
+socktpi_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct)
{
struct sonode *so;
int error = 0;
@@ -1003,7 +1008,8 @@ socktpi_getattr(
struct vnode *vp,
struct vattr *vap,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
dev_t fsid;
struct sonode *so;
@@ -1081,7 +1087,7 @@ socktpi_setattr(
struct vattr *vap,
int flags,
struct cred *cr,
- caller_context_t *ct)
+ caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
@@ -1101,13 +1107,14 @@ socktpi_setattr(
}
int
-socktpi_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+socktpi_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *accessvp;
struct sonode *so = VTOSO(vp);
if ((accessvp = so->so_accessvp) != NULL)
- return (VOP_ACCESS(accessvp, mode, flags, cr));
+ return (VOP_ACCESS(accessvp, mode, flags, cr, ct));
else
return (0); /* Allow all access. */
}
@@ -1120,14 +1127,15 @@ socktpi_access(struct vnode *vp, int mode, int flags, struct cred *cr)
*/
/* ARGSUSED */
int
-socktpi_fsync(struct vnode *vp, int syncflag, struct cred *cr)
+socktpi_fsync(struct vnode *vp, int syncflag, struct cred *cr,
+ caller_context_t *ct)
{
return (EINVAL);
}
/* ARGSUSED */
static void
-socktpi_inactive(struct vnode *vp, struct cred *cr)
+socktpi_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct sonode *so = VTOSO(vp);
@@ -1156,7 +1164,7 @@ socktpi_inactive(struct vnode *vp, struct cred *cr)
/* ARGSUSED */
int
-socktpi_fid(struct vnode *vp, struct fid *fidp)
+socktpi_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
return (EINVAL);
}
@@ -1167,7 +1175,8 @@ socktpi_fid(struct vnode *vp, struct fid *fidp)
*/
/*ARGSUSED*/
int
-socktpi_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+socktpi_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
return (ESPIPE);
}
@@ -1202,13 +1211,15 @@ socktpi_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
* for SS_HASCONNIND and set appropriate events to ensure poll_common()
* will not sleep.
*/
+/*ARGSUSED5*/
static int
socktpi_poll(
struct vnode *vp,
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
short origevents = events;
struct sonode *so = VTOSO(vp);
diff --git a/usr/src/uts/common/fs/specfs/specsubr.c b/usr/src/uts/common/fs/specfs/specsubr.c
index 85d9089b82..de5bf62e44 100644
--- a/usr/src/uts/common/fs/specfs/specsubr.c
+++ b/usr/src/uts/common/fs/specfs/specsubr.c
@@ -142,7 +142,7 @@ specvp(
* been required if the snode is in the cache.
*/
va.va_mask = AT_FSID | AT_TIMES;
- rc = VOP_GETATTR(vp, &va, 0, cr); /* XXX may block! */
+ rc = VOP_GETATTR(vp, &va, 0, cr, NULL); /* XXX may block! */
mutex_enter(&stable_lock);
if ((sp = sfind(dev, type, vp)) == NULL) {
@@ -465,7 +465,7 @@ devi_stillreferenced(dev_info_t *dip)
/*
* Given an snode, returns the open count and the dip
* associated with that snode
- * Assumes the caller holds the approriate locks
+ * Assumes the caller holds the appropriate locks
* to prevent snode and/or dip from going away.
* Returns:
* -1 No associated dip
@@ -862,7 +862,7 @@ device_close(struct vnode *vp, int flag, struct cred *cr)
* can, for example, change floppy disks.
*/
(void) spec_putpage(cvp, (offset_t)0,
- (size_t)0, B_INVAL|B_FORCE, cr);
+ (size_t)0, B_INVAL|B_FORCE, cr, NULL);
bflush(dev);
binval(dev);
error = dev_close(dev, flag, OTYP_BLK, cr);
diff --git a/usr/src/uts/common/fs/specfs/specvfsops.c b/usr/src/uts/common/fs/specfs/specvfsops.c
index e943a700a0..98342f4424 100644
--- a/usr/src/uts/common/fs/specfs/specvfsops.c
+++ b/usr/src/uts/common/fs/specfs/specvfsops.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -98,7 +97,7 @@ _info(struct modinfo *modinfop)
* N.B.
* No _fini routine. This module cannot be unloaded once loaded.
* The NO_UNLOAD_STUB in modstub.s must change if this module ever
- * is modififed to become unloadable.
+ * is modified to become unloadable.
*/
kmutex_t spec_syncbusy; /* initialized in specinit() */
@@ -158,7 +157,8 @@ spec_sync(struct vfs *vfsp,
for (sp = sync_list; sp != NULL; sp = spnext) {
spnext = sp->s_list;
vp = STOV(sp);
- (void) VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (uint_t)0, B_ASYNC, cr,
+ NULL);
VN_RELE(vp); /* Release our hold on vnode */
}
mutex_exit(&spec_syncbusy);
diff --git a/usr/src/uts/common/fs/specfs/specvnops.c b/usr/src/uts/common/fs/specfs/specvnops.c
index 07b5e6106d..d452246135 100644
--- a/usr/src/uts/common/fs/specfs/specvnops.c
+++ b/usr/src/uts/common/fs/specfs/specvnops.c
@@ -96,50 +96,59 @@
#include <sys/contract/device_impl.h>
-static int spec_open(struct vnode **, int, struct cred *);
-static int spec_close(struct vnode *, int, int, offset_t, struct cred *);
+static int spec_open(struct vnode **, int, struct cred *, caller_context_t *);
+static int spec_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *);
static int spec_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ caller_context_t *);
static int spec_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
-static int spec_ioctl(struct vnode *, int, intptr_t, int, struct cred *, int *);
-static int spec_getattr(struct vnode *, struct vattr *, int, struct cred *);
+ caller_context_t *);
+static int spec_ioctl(struct vnode *, int, intptr_t, int, struct cred *, int *,
+ caller_context_t *);
+static int spec_getattr(struct vnode *, struct vattr *, int, struct cred *,
+ caller_context_t *);
static int spec_setattr(struct vnode *, struct vattr *, int, struct cred *,
caller_context_t *);
-static int spec_access(struct vnode *, int, int, struct cred *);
-static int spec_create(struct vnode *, char *, vattr_t *, enum vcexcl,
- int, struct vnode **, struct cred *, int);
-static int spec_fsync(struct vnode *, int, struct cred *);
-static void spec_inactive(struct vnode *, struct cred *);
-static int spec_fid(struct vnode *, struct fid *);
-static int spec_seek(struct vnode *, offset_t, offset_t *);
+static int spec_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *);
+static int spec_create(struct vnode *, char *, vattr_t *, enum vcexcl, int,
+ struct vnode **, struct cred *, int, caller_context_t *, vsecattr_t *);
+static int spec_fsync(struct vnode *, int, struct cred *, caller_context_t *);
+static void spec_inactive(struct vnode *, struct cred *, caller_context_t *);
+static int spec_fid(struct vnode *, struct fid *, caller_context_t *);
+static int spec_seek(struct vnode *, offset_t, offset_t *, caller_context_t *);
static int spec_frlock(struct vnode *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, struct cred *);
-static int spec_realvp(struct vnode *, struct vnode **);
+ struct flk_callback *, struct cred *, caller_context_t *);
+static int spec_realvp(struct vnode *, struct vnode **, caller_context_t *);
static int spec_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t **,
- size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
+ size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
+ caller_context_t *);
static int spec_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
struct cred *);
static struct buf *spec_startio(struct vnode *, page_t *, u_offset_t, size_t,
int);
static int spec_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
- page_t **, size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
+ page_t **, size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
static int spec_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int spec_addmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int spec_delmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uint_t, uint_t, uint_t, struct cred *);
+ uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
-static int spec_poll(struct vnode *, short, int, short *, struct pollhead **);
-static int spec_dump(struct vnode *, caddr_t, int, int);
+static int spec_poll(struct vnode *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+static int spec_dump(struct vnode *, caddr_t, int, int, caller_context_t *);
static int spec_pageio(struct vnode *, page_t *, u_offset_t, size_t, int,
- cred_t *);
+ cred_t *, caller_context_t *);
-static int spec_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int spec_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int spec_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+static int spec_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int spec_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int spec_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
#define SN_HOLD(csp) { \
mutex_enter(&csp->s_lock); \
@@ -549,7 +558,7 @@ spec_clone(struct vnode **vpp, dev_t newdev, int vtype, struct stdata *stp)
}
static int
-spec_open(struct vnode **vpp, int flag, struct cred *cr)
+spec_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *cc)
{
major_t maj;
dev_t dev, newdev;
@@ -785,7 +794,7 @@ streams_open:
/* STREAM is of type S_IFCHR */
if (contract_device_open(newdev, S_IFCHR, &ct) != 0) {
UNLOCK_CSP(csp);
- (void) spec_close(vp, flag, 1, 0, cr);
+ (void) spec_close(vp, flag, 1, 0, cr, cc);
return (EIO);
}
}
@@ -807,7 +816,7 @@ streams_open:
ASSERT(ttoproc(curthread));
(void) contract_abandon(ct, ttoproc(curthread), 0);
}
- (void) spec_close(vp, flag, 1, 0, cr);
+ (void) spec_close(vp, flag, 1, 0, cr, cc);
return (EINTR);
}
@@ -826,7 +835,7 @@ streams_open:
mutex_exit(&stp->sd_lock);
UNLOCK_CSP(csp);
- (void) spec_close(vp, flag, 1, 0, cr);
+ (void) spec_close(vp, flag, 1, 0, cr, cc);
} else {
UNLOCK_CSP(csp);
SN_RELE(csp);
@@ -842,7 +851,8 @@ spec_close(
int flag,
int count,
offset_t offset,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *cvp;
struct snode *sp, *csp;
@@ -943,7 +953,7 @@ spec_read(
struct uio *uiop,
int ioflag,
struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int error;
struct snode *sp = VTOS(vp);
@@ -1049,7 +1059,7 @@ spec_write(
struct uio *uiop,
int ioflag,
struct cred *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int error;
struct snode *sp = VTOS(vp);
@@ -1214,9 +1224,10 @@ spec_write(
return (error);
}
+/*ARGSUSED6*/
static int
spec_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode, struct cred *cr,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
struct snode *sp;
dev_t dev;
@@ -1242,7 +1253,12 @@ spec_ioctl(struct vnode *vp, int cmd, intptr_t arg, int mode, struct cred *cr,
}
static int
-spec_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
+spec_getattr(
+ struct vnode *vp,
+ struct vattr *vap,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
int error;
struct snode *sp;
@@ -1302,7 +1318,7 @@ spec_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr)
*/
vap->va_nblocks = 0;
} else {
- error = VOP_GETATTR(realvp, vap, flags, cr);
+ error = VOP_GETATTR(realvp, vap, flags, cr, ct);
if (error != 0)
return (error);
}
@@ -1331,7 +1347,7 @@ spec_setattr(
struct vattr *vap,
int flags,
struct cred *cr,
- caller_context_t *ctp)
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *realvp;
@@ -1353,7 +1369,7 @@ spec_setattr(
if ((realvp = sp->s_realvp) == NULL)
error = 0; /* no real vnode to update */
else
- error = VOP_SETATTR(realvp, vap, flags, cr, ctp);
+ error = VOP_SETATTR(realvp, vap, flags, cr, ct);
if (error == 0) {
/*
* If times were changed, update snode.
@@ -1371,7 +1387,12 @@ spec_setattr(
}
static int
-spec_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+spec_access(
+ struct vnode *vp,
+ int mode,
+ int flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
@@ -1381,7 +1402,7 @@ spec_access(struct vnode *vp, int mode, int flags, struct cred *cr)
return (ENXIO);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_ACCESS(realvp, mode, flags, cr));
+ return (VOP_ACCESS(realvp, mode, flags, cr, ct));
else
return (0); /* Allow all access. */
}
@@ -1392,8 +1413,17 @@ spec_access(struct vnode *vp, int mode, int flags, struct cred *cr)
*/
/*ARGSUSED*/
static int
-spec_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
- int mode, struct vnode **vpp, struct cred *cr, int flag)
+spec_create(
+ struct vnode *dvp,
+ char *name,
+ vattr_t *vap,
+ enum vcexcl excl,
+ int mode,
+ struct vnode **vpp,
+ struct cred *cr,
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int error;
struct snode *sp = VTOS(dvp);
@@ -1404,7 +1434,7 @@ spec_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
ASSERT(dvp && (dvp->v_flag & VROOT) && *name == '\0');
if (excl == NONEXCL) {
- if (mode && (error = spec_access(dvp, mode, 0, cr)))
+ if (mode && (error = spec_access(dvp, mode, 0, cr, ct)))
return (error);
VN_HOLD(dvp);
return (0);
@@ -1418,7 +1448,11 @@ spec_create(struct vnode *dvp, char *name, vattr_t *vap, enum vcexcl excl,
* already set in the vnode.
*/
static int
-spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
+spec_fsync(
+ struct vnode *vp,
+ int syncflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *realvp;
@@ -1440,7 +1474,7 @@ spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
if (vp->v_type == VBLK && cvp != vp && vn_has_cached_data(cvp) &&
(cvp->v_flag & VISSWAP) == 0)
- (void) VOP_PUTPAGE(cvp, (offset_t)0, 0, 0, cr);
+ (void) VOP_PUTPAGE(cvp, (offset_t)0, 0, 0, cr, ct);
/*
* For devices that support it, force write cache to stable storage.
@@ -1473,7 +1507,7 @@ spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
return (0);
vatmp.va_mask = AT_ATIME|AT_MTIME;
- if (VOP_GETATTR(realvp, &vatmp, 0, cr) == 0) {
+ if (VOP_GETATTR(realvp, &vatmp, 0, cr, ct) == 0) {
mutex_enter(&sp->s_lock);
if (vatmp.va_atime.tv_sec > sp->s_atime)
@@ -1491,15 +1525,15 @@ spec_fsync(struct vnode *vp, int syncflag, struct cred *cr)
mutex_exit(&sp->s_lock);
va.va_mask = AT_ATIME|AT_MTIME;
- (void) VOP_SETATTR(realvp, &va, 0, cr, NULL);
+ (void) VOP_SETATTR(realvp, &va, 0, cr, ct);
}
- (void) VOP_FSYNC(realvp, syncflag, cr);
+ (void) VOP_FSYNC(realvp, syncflag, cr, ct);
return (0);
}
/*ARGSUSED*/
static void
-spec_inactive(struct vnode *vp, struct cred *cr)
+spec_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *cvp;
@@ -1550,7 +1584,7 @@ spec_inactive(struct vnode *vp, struct cred *cr)
* The user may not own the device, but we
* want to update the attributes anyway.
*/
- if (VOP_GETATTR(rvp, &vatmp, 0, kcred) == 0) {
+ if (VOP_GETATTR(rvp, &vatmp, 0, kcred, ct) == 0) {
if (vatmp.va_atime.tv_sec > sp->s_atime)
va.va_atime = vatmp.va_atime;
else {
@@ -1565,7 +1599,7 @@ spec_inactive(struct vnode *vp, struct cred *cr)
}
va.va_mask = AT_ATIME|AT_MTIME;
- (void) VOP_SETATTR(rvp, &va, 0, kcred, NULL);
+ (void) VOP_SETATTR(rvp, &va, 0, kcred, ct);
}
}
}
@@ -1619,20 +1653,24 @@ spec_inactive(struct vnode *vp, struct cred *cr)
}
static int
-spec_fid(struct vnode *vp, struct fid *fidp)
+spec_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_FID(realvp, fidp));
+ return (VOP_FID(realvp, fidp, ct));
else
return (EINVAL);
}
/*ARGSUSED1*/
static int
-spec_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+spec_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
offset_t maxoff = spec_maxoffset(vp);
@@ -1650,7 +1688,8 @@ spec_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct snode *csp;
@@ -1662,17 +1701,17 @@ spec_frlock(
if (csp->s_mapcnt > 0)
return (EAGAIN);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
static int
-spec_realvp(struct vnode *vp, struct vnode **vpp)
+spec_realvp(struct vnode *vp, struct vnode **vpp, caller_context_t *ct)
{
struct vnode *rvp;
if ((rvp = VTOS(vp)->s_realvp) != NULL) {
vp = rvp;
- if (VOP_REALVP(vp, &rvp) == 0)
+ if (VOP_REALVP(vp, &rvp, ct) == 0)
vp = rvp;
}
@@ -1684,6 +1723,7 @@ spec_realvp(struct vnode *vp, struct vnode **vpp)
* Return all the pages from [off..off + len] in block
* or character device.
*/
+/*ARGSUSED*/
static int
spec_getpage(
struct vnode *vp,
@@ -1695,7 +1735,8 @@ spec_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
int err;
@@ -1942,13 +1983,15 @@ again:
* len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
* (from pageout).
*/
+/*ARGSUSED5*/
int
spec_putpage(
struct vnode *vp,
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct snode *sp = VTOS(vp);
struct vnode *cvp;
@@ -2142,13 +2185,14 @@ spec_poll(
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
dev_t dev;
int error;
if (vp->v_type == VBLK)
- error = fs_poll(vp, events, anyyet, reventsp, phpp);
+ error = fs_poll(vp, events, anyyet, reventsp, phpp, ct);
else {
ASSERT(vp->v_type == VCHR);
dev = vp->v_rdev;
@@ -2159,7 +2203,7 @@ spec_poll(
} else if (devopsp[getmajor(dev)]->devo_cb_ops->cb_chpoll) {
error = cdev_poll(dev, events, anyyet, reventsp, phpp);
} else {
- error = fs_poll(vp, events, anyyet, reventsp, phpp);
+ error = fs_poll(vp, events, anyyet, reventsp, phpp, ct);
}
}
return (error);
@@ -2310,6 +2354,7 @@ spec_char_map(
maxprot, flags, cred));
}
+/*ARGSUSED9*/
static int
spec_map(
struct vnode *vp,
@@ -2320,7 +2365,8 @@ spec_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
int error = 0;
struct snode *sp = VTOS(vp);
@@ -2405,7 +2451,8 @@ spec_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
int error = 0;
struct snode *csp = VTOS(vp);
@@ -2443,7 +2490,8 @@ spec_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct snode *csp = VTOS(vp);
ulong_t npages;
@@ -2498,8 +2546,14 @@ spec_delmap(
return (0);
}
+/*ARGSUSED4*/
static int
-spec_dump(struct vnode *vp, caddr_t addr, int bn, int count)
+spec_dump(
+ struct vnode *vp,
+ caddr_t addr,
+ int bn,
+ int count,
+ caller_context_t *ct)
{
/* allow dump to succeed even if device fenced off */
@@ -2522,7 +2576,8 @@ spec_pageio(
u_offset_t io_off,
size_t io_len,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
struct buf *bp = NULL;
int err = 0;
@@ -2546,7 +2601,12 @@ spec_pageio(
* Set ACL on underlying vnode if one exists, or return ENOSYS otherwise.
*/
int
-spec_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
+spec_setsecattr(
+ struct vnode *vp,
+ vsecattr_t *vsap,
+ int flag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
@@ -2564,9 +2624,9 @@ spec_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
* here privately to avoid serializing specfs reads and writes.
*/
if ((realvp = sp->s_realvp) != NULL) {
- (void) VOP_RWLOCK(realvp, V_WRITELOCK_TRUE, NULL);
- error = VOP_SETSECATTR(realvp, vsap, flag, cr);
- (void) VOP_RWUNLOCK(realvp, V_WRITELOCK_TRUE, NULL);
+ (void) VOP_RWLOCK(realvp, V_WRITELOCK_TRUE, ct);
+ error = VOP_SETSECATTR(realvp, vsap, flag, cr, ct);
+ (void) VOP_RWUNLOCK(realvp, V_WRITELOCK_TRUE, ct);
return (error);
} else
return (fs_nosys());
@@ -2577,7 +2637,12 @@ spec_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
* the permissions returned by spec_getattr() otherwise.
*/
int
-spec_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
+spec_getsecattr(
+ struct vnode *vp,
+ vsecattr_t *vsap,
+ int flag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct vnode *realvp;
struct snode *sp = VTOS(vp);
@@ -2587,13 +2652,18 @@ spec_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
return (ENXIO);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_GETSECATTR(realvp, vsap, flag, cr));
+ return (VOP_GETSECATTR(realvp, vsap, flag, cr, ct));
else
- return (fs_fab_acl(vp, vsap, flag, cr));
+ return (fs_fab_acl(vp, vsap, flag, cr, ct));
}
int
-spec_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+spec_pathconf(
+ vnode_t *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
{
vnode_t *realvp;
struct snode *sp = VTOS(vp);
@@ -2603,7 +2673,7 @@ spec_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
return (ENXIO);
if ((realvp = sp->s_realvp) != NULL)
- return (VOP_PATHCONF(realvp, cmd, valp, cr));
+ return (VOP_PATHCONF(realvp, cmd, valp, cr, ct));
else
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
diff --git a/usr/src/uts/common/fs/swapfs/swap_subr.c b/usr/src/uts/common/fs/swapfs/swap_subr.c
index e589c38073..dbbf57a50a 100644
--- a/usr/src/uts/common/fs/swapfs/swap_subr.c
+++ b/usr/src/uts/common/fs/swapfs/swap_subr.c
@@ -257,7 +257,7 @@ swap_sync(struct vfs *vfsp, short flag, struct cred *cr)
if (vp) {
VN_HOLD(vp);
(void) VOP_PUTPAGE(vp, (offset_t)0, 0,
- (B_ASYNC | B_FREE), kcred);
+ (B_ASYNC | B_FREE), kcred, NULL);
VN_RELE(vp);
}
}
diff --git a/usr/src/uts/common/fs/swapfs/swap_vnops.c b/usr/src/uts/common/fs/swapfs/swap_vnops.c
index 53bdae350c..4e69206084 100644
--- a/usr/src/uts/common/fs/swapfs/swap_vnops.c
+++ b/usr/src/uts/common/fs/swapfs/swap_vnops.c
@@ -55,13 +55,14 @@
* Define the routines within this file.
*/
static int swap_getpage(struct vnode *vp, offset_t off, size_t len,
- uint_t *protp, struct page **plarr, size_t plsz,
- struct seg *seg, caddr_t addr, enum seg_rw rw, struct cred *cr);
+ uint_t *protp, struct page **plarr, size_t plsz, struct seg *seg,
+ caddr_t addr, enum seg_rw rw, struct cred *cr, caller_context_t *ct);
static int swap_putpage(struct vnode *vp, offset_t off, size_t len,
- int flags, struct cred *cr);
-static void swap_inactive(struct vnode *vp, struct cred *cr);
+ int flags, struct cred *cr, caller_context_t *ct);
+static void swap_inactive(struct vnode *vp, struct cred *cr,
+ caller_context_t *ct);
static void swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
static int swap_getapage(struct vnode *vp, u_offset_t off, size_t len,
uint_t *protp, page_t **plarr, size_t plsz,
@@ -94,7 +95,8 @@ vnodeops_t *swap_vnodeops;
static void
swap_inactive(
struct vnode *vp,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
SWAPFS_PRINT(SWAP_VOPS, "swap_inactive: vp %x\n", vp, 0, 0, 0, 0);
}
@@ -102,6 +104,7 @@ swap_inactive(
/*
* Return all the pages from [off..off+len] in given file
*/
+/*ARGSUSED*/
static int
swap_getpage(
struct vnode *vp,
@@ -113,7 +116,8 @@ swap_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
int err;
@@ -236,7 +240,7 @@ again:
flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
err = VOP_PAGEIO(pvp, pp, poff,
- PAGESIZE, flags, cr);
+ PAGESIZE, flags, cr, NULL);
if (!err) {
ahm = &anonhash_lock[AH_LOCK(vp, off)];
@@ -412,7 +416,8 @@ swap_getconpage(
}
if (pvp) {
- err = VOP_PAGEIO(pvp, pp, poff, PAGESIZE, B_READ, cr);
+ err = VOP_PAGEIO(pvp, pp, poff, PAGESIZE, B_READ, cr,
+ NULL);
} else {
pagezero(pp, 0, PAGESIZE);
}
@@ -464,7 +469,8 @@ swap_putpage(
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
page_t *pp;
u_offset_t io_off;
@@ -709,7 +715,7 @@ swap_putapage(
}
err = VOP_PAGEIO(klvp, pplist, klstart, klsz,
- B_WRITE | flags, cr);
+ B_WRITE | flags, cr, NULL);
if ((flags & B_ASYNC) == 0)
pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
@@ -731,7 +737,13 @@ out:
}
static void
-swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
+swap_dispose(
+ vnode_t *vp,
+ page_t *pp,
+ int fl,
+ int dn,
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
u_offset_t off = pp->p_offset;
@@ -751,7 +763,7 @@ swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr)
err = swap_getphysname(vp, off, &pvp, &poff);
if (!err && pvp != NULL)
- VOP_DISPOSE(pvp, pp, fl, dn, cr);
+ VOP_DISPOSE(pvp, pp, fl, dn, cr, ct);
else
- fs_dispose(vp, pp, fl, dn, cr);
+ fs_dispose(vp, pp, fl, dn, cr, ct);
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_dir.c b/usr/src/uts/common/fs/tmpfs/tmp_dir.c
index 682cac326b..f6621c8097 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_dir.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_dir.c
@@ -237,7 +237,8 @@ tdirenter(
struct tmpnode *tp, /* source tmpnode, if link/rename */
struct vattr *va,
struct tmpnode **tpp, /* return tmpnode, if create/mkdir */
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ctp)
{
struct tdirent *tdp;
struct tmpnode *found = NULL;
@@ -346,7 +347,7 @@ tdirenter(
if (error == 0) {
if (found != NULL) {
vnevent_rename_dest(TNTOV(found),
- TNTOV(dir), name);
+ TNTOV(dir), name, ctp);
}
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
index f798cb8ed4..4ee833094f 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
@@ -338,7 +338,7 @@ tmp_mount(
* Get the mode, uid, and gid from the underlying mount point.
*/
rattr.va_mask = AT_MODE|AT_UID|AT_GID; /* Hint to getattr */
- got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr);
+ got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr, NULL);
rw_enter(&tp->tn_rwlock, RW_WRITER);
TNTOV(tp)->v_flag |= VROOT;
@@ -371,6 +371,9 @@ tmp_mount(
error = 0;
out:
+ if (error == 0)
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
+
return (error);
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
index c2d921bba9..7be9c2bdda 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
@@ -73,7 +73,7 @@ static int tmp_putapage(struct vnode *, page_t *, u_offset_t *, size_t *,
/* ARGSUSED1 */
static int
-tmp_open(struct vnode **vpp, int flag, struct cred *cred)
+tmp_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
{
/*
* swapon to a tmpfs file is not supported so access
@@ -86,8 +86,13 @@ tmp_open(struct vnode **vpp, int flag, struct cred *cred)
/* ARGSUSED1 */
static int
-tmp_close(struct vnode *vp, int flag, int count,
- offset_t offset, struct cred *cred)
+tmp_close(
+ struct vnode *vp,
+ int flag,
+ int count,
+ offset_t offset,
+ struct cred *cred,
+ caller_context_t *ct)
{
cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
@@ -269,7 +274,7 @@ wrtmp(
/*
* We have to drop the contents lock to allow the VM
- * system to reaquire it in tmp_getpage()
+ * system to reacquire it in tmp_getpage()
*/
rw_exit(&tp->tn_contents);
@@ -496,7 +501,7 @@ rdtmp(
/*
* We have to drop the contents lock to prevent the VM
- * system from trying to reaquire it in tmp_getpage()
+ * system from trying to reacquire it in tmp_getpage()
* should the uiomove cause a pagefault.
*/
rw_exit(&tp->tn_contents);
@@ -621,15 +626,26 @@ tmp_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
/* ARGSUSED */
static int
-tmp_ioctl(struct vnode *vp, int com, intptr_t data, int flag,
- struct cred *cred, int *rvalp)
+tmp_ioctl(
+ struct vnode *vp,
+ int com,
+ intptr_t data,
+ int flag,
+ struct cred *cred,
+ int *rvalp,
+ caller_context_t *ct)
{
return (ENOTTY);
}
/* ARGSUSED2 */
static int
-tmp_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cred)
+tmp_getattr(
+ struct vnode *vp,
+ struct vattr *vap,
+ int flags,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct vnode *mvp;
@@ -651,7 +667,7 @@ tmp_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cred)
mutex_exit(&tp->tn_tlock);
bzero(&va, sizeof (struct vattr));
va.va_mask = AT_UID|AT_GID;
- attrs = VOP_GETATTR(mvp, &va, 0, cred);
+ attrs = VOP_GETATTR(mvp, &va, 0, cred, ct);
} else {
mutex_exit(&tp->tn_tlock);
}
@@ -703,7 +719,7 @@ tmp_setattr(
/*
* Cannot set these attributes
*/
- if (vap->va_mask & AT_NOSET)
+ if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR))
return (EINVAL);
mutex_enter(&tp->tn_tlock);
@@ -763,7 +779,12 @@ out1:
/* ARGSUSED2 */
static int
-tmp_access(struct vnode *vp, int mode, int flags, struct cred *cred)
+tmp_access(
+ struct vnode *vp,
+ int mode,
+ int flags,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
int error;
@@ -783,7 +804,10 @@ tmp_lookup(
struct pathname *pnp,
int flags,
struct vnode *rdir,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *ntp = NULL;
@@ -795,6 +819,12 @@ tmp_lookup(
struct tmpnode *xdp;
struct tmount *tm;
+ /*
+ * don't allow attributes if not mounted XATTR support
+ */
+ if (!(dvp->v_vfsp->vfs_flag & VFS_XATTR))
+ return (EINVAL);
+
if (tp->tn_flags & ISXATTR)
/* No attributes on attributes */
return (EINVAL);
@@ -894,7 +924,9 @@ tmp_create(
int mode,
struct vnode **vpp,
struct cred *cred,
- int flag)
+ int flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
struct tmpnode *parent;
struct tmount *tm;
@@ -977,7 +1009,7 @@ again:
}
if (error == 0) {
- vnevent_create(*vpp);
+ vnevent_create(*vpp, ct);
}
return (0);
}
@@ -988,7 +1020,7 @@ again:
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, nm, DE_CREATE,
(struct tmpnode *)NULL, (struct tmpnode *)NULL,
- vap, &self, cred);
+ vap, &self, cred, ct);
rw_exit(&parent->tn_rwlock);
if (error) {
@@ -1026,8 +1058,14 @@ again:
return (0);
}
+/* ARGSUSED3 */
static int
-tmp_remove(struct vnode *dvp, char *nm, struct cred *cred)
+tmp_remove(
+ struct vnode *dvp,
+ char *nm,
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
int error;
@@ -1047,7 +1085,7 @@ tmp_remove(struct vnode *dvp, char *nm, struct cred *cred)
rw_exit(&tp->tn_rwlock);
rw_exit(&parent->tn_rwlock);
- vnevent_remove(TNTOV(tp), dvp, nm);
+ vnevent_remove(TNTOV(tp), dvp, nm, ct);
tmpnode_rele(tp);
TRACE_3(TR_FAC_TMPFS, TR_TMPFS_REMOVE,
@@ -1055,8 +1093,15 @@ tmp_remove(struct vnode *dvp, char *nm, struct cred *cred)
return (error);
}
+/* ARGSUSED4 */
static int
-tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred)
+tmp_link(
+ struct vnode *dvp,
+ struct vnode *srcvp,
+ char *tnm,
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent;
struct tmpnode *from;
@@ -1065,7 +1110,7 @@ tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred)
struct tmpnode *found = NULL;
struct vnode *realvp;
- if (VOP_REALVP(srcvp, &realvp) == 0)
+ if (VOP_REALVP(srcvp, &realvp, ct) == 0)
srcvp = realvp;
parent = (struct tmpnode *)VTOTN(dvp);
@@ -1095,21 +1140,24 @@ tmp_link(struct vnode *dvp, struct vnode *srcvp, char *tnm, struct cred *cred)
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, tnm, DE_LINK, (struct tmpnode *)NULL,
- from, NULL, (struct tmpnode **)NULL, cred);
+ from, NULL, (struct tmpnode **)NULL, cred, ct);
rw_exit(&parent->tn_rwlock);
if (error == 0) {
- vnevent_link(srcvp);
+ vnevent_link(srcvp, ct);
}
return (error);
}
+/* ARGSUSED5 */
static int
tmp_rename(
struct vnode *odvp, /* source parent vnode */
char *onm, /* source name */
struct vnode *ndvp, /* destination parent vnode */
char *nnm, /* destination name */
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *fromparent;
struct tmpnode *toparent;
@@ -1119,7 +1167,7 @@ tmp_rename(
int samedir = 0; /* set if odvp == ndvp */
struct vnode *realvp;
- if (VOP_REALVP(ndvp, &realvp) == 0)
+ if (VOP_REALVP(ndvp, &realvp, ct) == 0)
ndvp = realvp;
fromparent = (struct tmpnode *)VTOTN(odvp);
@@ -1178,7 +1226,7 @@ tmp_rename(
rw_enter(&toparent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, toparent, nnm, DE_RENAME,
fromparent, fromtp, (struct vattr *)NULL,
- (struct tmpnode **)NULL, cred);
+ (struct tmpnode **)NULL, cred, ct);
rw_exit(&toparent->tn_rwlock);
if (error) {
@@ -1191,14 +1239,14 @@ tmp_rename(
error = 0;
goto done;
}
- vnevent_rename_src(TNTOV(fromtp), odvp, onm);
+ vnevent_rename_src(TNTOV(fromtp), odvp, onm, ct);
/*
* Notify the target directory if not same as
* source directory.
*/
if (ndvp != odvp) {
- vnevent_rename_dest_dir(ndvp);
+ vnevent_rename_dest_dir(ndvp, ct);
}
/*
@@ -1232,13 +1280,17 @@ done:
return (error);
}
+/* ARGSUSED5 */
static int
tmp_mkdir(
struct vnode *dvp,
char *nm,
struct vattr *va,
struct vnode **vpp,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *self = NULL;
@@ -1269,7 +1321,7 @@ tmp_mkdir(
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, nm, DE_MKDIR,
(struct tmpnode *)NULL, (struct tmpnode *)NULL, va,
- &self, cred);
+ &self, cred, ct);
if (error) {
rw_exit(&parent->tn_rwlock);
if (self)
@@ -1281,12 +1333,15 @@ tmp_mkdir(
return (0);
}
+/* ARGSUSED4 */
static int
tmp_rmdir(
struct vnode *dvp,
char *nm,
struct vnode *cdir,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *self = NULL;
@@ -1354,16 +1409,21 @@ done:
done1:
rw_exit(&self->tn_rwlock);
rw_exit(&parent->tn_rwlock);
- vnevent_rmdir(TNTOV(self), dvp, nm);
+ vnevent_rmdir(TNTOV(self), dvp, nm, ct);
tmpnode_rele(self);
return (error);
}
/* ARGSUSED2 */
-
static int
-tmp_readdir(struct vnode *vp, struct uio *uiop, struct cred *cred, int *eofp)
+tmp_readdir(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct tdirent *tdp;
@@ -1467,13 +1527,16 @@ tmp_readdir(struct vnode *vp, struct uio *uiop, struct cred *cred, int *eofp)
return (error);
}
+/* ARGSUSED5 */
static int
tmp_symlink(
struct vnode *dvp,
char *lnm,
struct vattr *tva,
char *tnm,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct,
+ int flags)
{
struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
struct tmpnode *self = (struct tmpnode *)NULL;
@@ -1503,7 +1566,7 @@ tmp_symlink(
rw_enter(&parent->tn_rwlock, RW_WRITER);
error = tdirenter(tm, parent, lnm, DE_CREATE, (struct tmpnode *)NULL,
- (struct tmpnode *)NULL, tva, &self, cred);
+ (struct tmpnode *)NULL, tva, &self, cred, ct);
rw_exit(&parent->tn_rwlock);
if (error) {
@@ -1527,7 +1590,11 @@ tmp_symlink(
/* ARGSUSED2 */
static int
-tmp_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
+tmp_readlink(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cred,
+ caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
int error = 0;
@@ -1546,14 +1613,18 @@ tmp_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
/* ARGSUSED */
static int
-tmp_fsync(struct vnode *vp, int syncflag, struct cred *cred)
+tmp_fsync(
+ struct vnode *vp,
+ int syncflag,
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
/* ARGSUSED */
static void
-tmp_inactive(struct vnode *vp, struct cred *cred)
+tmp_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct tmount *tm = (struct tmount *)VFSTOTM(vp->v_vfsp);
@@ -1634,8 +1705,9 @@ top:
tmp_memfree(tp, sizeof (struct tmpnode));
}
+/* ARGSUSED2 */
static int
-tmp_fid(struct vnode *vp, struct fid *fidp)
+tmp_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
struct tfid *tfid;
@@ -1659,6 +1731,7 @@ tmp_fid(struct vnode *vp, struct fid *fidp)
/*
* Return all the pages from [off..off+len] in given file
*/
+/* ARGSUSED */
static int
tmp_getpage(
struct vnode *vp,
@@ -1670,7 +1743,8 @@ tmp_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
int err = 0;
struct tmpnode *tp = VTOTN(vp);
@@ -1788,7 +1862,7 @@ again:
if (pvp) {
flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
err = VOP_PAGEIO(pvp, pp, (u_offset_t)poff, PAGESIZE,
- flags, cr);
+ flags, cr, NULL);
if (flags & B_ASYNC)
pp = NULL;
} else if (rw != S_CREATE) {
@@ -1820,7 +1894,8 @@ tmp_putpage(
offset_t off,
size_t len,
int flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
register page_t *pp;
u_offset_t io_off;
@@ -2037,7 +2112,7 @@ tmp_putapage(
/* Do i/o on the remaining kluster */
err = VOP_PAGEIO(pvp, pplist, (u_offset_t)pstart, io_len,
- B_WRITE | flags, cr);
+ B_WRITE | flags, cr, NULL);
if ((flags & B_ASYNC) == 0) {
pvn_write_done(pplist, ((err) ? B_ERROR : 0) | B_WRITE | flags);
@@ -2056,6 +2131,7 @@ out:
return (err);
}
+/* ARGSUSED */
static int
tmp_map(
struct vnode *vp,
@@ -2066,7 +2142,8 @@ tmp_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
@@ -2139,7 +2216,8 @@ tmp_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -2155,7 +2233,8 @@ tmp_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- struct cred *cred)
+ struct cred *cred,
+ caller_context_t *ct)
{
return (0);
}
@@ -2243,7 +2322,11 @@ tmp_space(
/* ARGSUSED */
static int
-tmp_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+tmp_seek(
+ struct vnode *vp,
+ offset_t ooff,
+ offset_t *noffp,
+ caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -2272,7 +2355,12 @@ tmp_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
}
static int
-tmp_pathconf(struct vnode *vp, int cmd, ulong_t *valp, cred_t *cr)
+tmp_pathconf(
+ struct vnode *vp,
+ int cmd,
+ ulong_t *valp,
+ cred_t *cr,
+ caller_context_t *ct)
{
struct tmpnode *tp = NULL;
int error;
@@ -2296,8 +2384,14 @@ tmp_pathconf(struct vnode *vp, int cmd, ulong_t *valp, cred_t *cr)
error = EINVAL;
}
break;
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_type == VREG || vp->v_type == VDIR);
+ error = 0;
+ break;
default:
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
return (error);
}
diff --git a/usr/src/uts/common/fs/udfs/udf_dir.c b/usr/src/uts/common/fs/udfs/udf_dir.c
index d470a2588a..40b0a7d4aa 100644
--- a/usr/src/uts/common/fs/udfs/udf_dir.c
+++ b/usr/src/uts/common/fs/udfs/udf_dir.c
@@ -327,9 +327,16 @@ done:
}
int
-ud_direnter(struct ud_inode *tdp,
- char *namep, enum de_op op, struct ud_inode *sdp, struct ud_inode *sip,
- struct vattr *vap, struct ud_inode **ipp, struct cred *cr)
+ud_direnter(
+ struct ud_inode *tdp,
+ char *namep,
+ enum de_op op,
+ struct ud_inode *sdp,
+ struct ud_inode *sip,
+ struct vattr *vap,
+ struct ud_inode **ipp,
+ struct cred *cr,
+ caller_context_t *ctp)
{
struct udf_vfs *udf_vfsp;
struct ud_inode *tip;
@@ -556,11 +563,11 @@ out:
if (err == 0) {
if (tip) {
vnevent_rename_dest(ITOV(tip), ITOV(tdp),
- namep);
+ namep, ctp);
}
if (sdp != tdp) {
- vnevent_rename_dest_dir(ITOV(tdp));
+ vnevent_rename_dest_dir(ITOV(tdp), ctp);
}
}
@@ -594,9 +601,14 @@ out2:
* function seems to be really weird
*/
int
-ud_dirremove(struct ud_inode *dp,
- char *namep, struct ud_inode *oip, struct vnode *cdir,
- enum dr_op op, struct cred *cr)
+ud_dirremove(
+ struct ud_inode *dp,
+ char *namep,
+ struct ud_inode *oip,
+ struct vnode *cdir,
+ enum dr_op op,
+ struct cred *cr,
+ caller_context_t *ctp)
{
struct udf_vfs *udf_vfsp;
int32_t namelen, err = 0;
@@ -852,9 +864,9 @@ out_novfs:
*/
if (err == 0) {
if (op == DR_REMOVE) {
- vnevent_remove(ITOV(ip), ITOV(dp), namep);
+ vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
} else if (op == DR_RMDIR) {
- vnevent_rmdir(ITOV(ip), ITOV(dp), namep);
+ vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
}
}
VN_RELE(ITOV(ip));
diff --git a/usr/src/uts/common/fs/udfs/udf_subr.c b/usr/src/uts/common/fs/udfs/udf_subr.c
index b8ab49457f..dd06e0d884 100644
--- a/usr/src/uts/common/fs/udfs/udf_subr.c
+++ b/usr/src/uts/common/fs/udfs/udf_subr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -223,7 +222,7 @@ ud_xlate_to_daddr(struct udf_vfs *udf_vfsp,
continue;
}
if ((end_req < begin_bad) ||
- (begin_req >= end_bad)) {
+ (begin_req >= end_bad)) {
continue;
}
@@ -232,7 +231,7 @@ ud_xlate_to_daddr(struct udf_vfs *udf_vfsp,
end_req = begin_bad;
} else {
retblkno = SWAP_32(te->sent_ml) +
- begin_req - begin_bad;
+ begin_req - begin_bad;
if (end_req < end_bad) {
*count = end_req - begin_req;
} else {
@@ -319,10 +318,10 @@ ud_ip_off2bno(struct ud_inode *ip, uint32_t offset, uint32_t *bno)
for (i = 0; i < ip->i_ext_used; i++) {
iext = &ip->i_ext[i];
if ((iext->ib_offset <= offset) &&
- (offset < (iext->ib_offset + iext->ib_count))) {
+ (offset < (iext->ib_offset + iext->ib_count))) {
*bno = iext->ib_block +
- ((offset - iext->ib_offset) >>
- ip->i_udf->udf_l2b_shift);
+ ((offset - iext->ib_offset) >>
+ ip->i_udf->udf_l2b_shift);
break;
}
}
@@ -338,8 +337,6 @@ static uint32_t cum_sec_leap[] = {
0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680
};
-#define SECS_PER_MIN 60
-#define SECS_PER_HOUR 3600
#define DAYS_PER_YEAR 365
#define SEC_PER_DAY 0x15180
@@ -363,8 +360,8 @@ ud_dtime2utime(struct timespec32 *utime,
utime->tv_sec = cp[dtime->ts_month - 1];
utime->tv_sec += (dtime->ts_day - 1) * SEC_PER_DAY;
utime->tv_sec += ((dtime->ts_hour * 60) +
- dtime->ts_min) * 60 +
- dtime->ts_sec;
+ dtime->ts_min) * 60 +
+ dtime->ts_sec;
tzone = SWAP_16(dtime->ts_tzone);
if ((tzone & TMODE) == 0x1000) {
@@ -384,15 +381,15 @@ ud_dtime2utime(struct timespec32 *utime,
}
utime->tv_nsec = ((((dtime->ts_csec * 100) +
- dtime->ts_husec) * 100) +
- dtime->ts_usec) * 1000;
+ dtime->ts_husec) * 100) +
+ dtime->ts_usec) * 1000;
if (year >= 1970) {
utime->tv_sec += (year - 1970) * SEC_PER_YEAR;
utime->tv_sec += ((year - 1969) / 4) * SEC_PER_DAY;
} else {
utime->tv_sec = ((1970 - year) * SEC_PER_YEAR +
- ((1972 - year) / 4) * SEC_PER_DAY -
- utime->tv_sec) * -1;
+ ((1972 - year) / 4) * SEC_PER_DAY -
+ utime->tv_sec) * -1;
if (utime->tv_nsec) {
utime->tv_sec++;
utime->tv_nsec = 1000 * 1000 * 1000 - utime->tv_nsec;
@@ -498,7 +495,7 @@ ud_syncip(struct ud_inode *ip, int32_t flags, int32_t waitfor)
} else {
rw_exit(&ip->i_contents);
error = VOP_PUTPAGE(vp, (offset_t)0,
- (uint32_t)0, flags, CRED());
+ (uint32_t)0, flags, CRED(), NULL);
rw_enter(&ip->i_contents, RW_WRITER);
}
@@ -561,10 +558,10 @@ ud_sbwrite(struct udf_vfs *udf_vfsp)
ud_update_regid(&iu->lvidiu_regid);
ud_make_tag(udf_vfsp, &lvid->lvid_tag,
- UD_LOG_VOL_INT, udf_vfsp->udf_iseq_loc,
- sizeof (struct log_vol_int_desc) - 8 +
- 8 * udf_vfsp->udf_npart +
- SWAP_32(lvid->lvid_liu));
+ UD_LOG_VOL_INT, udf_vfsp->udf_iseq_loc,
+ sizeof (struct log_vol_int_desc) - 8 +
+ 8 * udf_vfsp->udf_npart +
+ SWAP_32(lvid->lvid_liu));
/*
* Don't release the buffer after writing to the disk
@@ -627,7 +624,7 @@ ud_update(int32_t flag)
*/
mutex_enter(&udf_vfs_mutex);
for (udfsp = udf_vfs_instances;
- udfsp != NULL; udfsp = udfsp->udf_next) {
+ udfsp != NULL; udfsp = udfsp->udf_next) {
vfsp = udfsp->udf_vfs;
if (vfs_lock(vfsp) != 0) {
continue;
@@ -762,7 +759,7 @@ ud_still_mounted(struct check_node *checkp)
mutex_enter(&udf_vfs_mutex);
for (udf_vfsp = udf_vfs_instances;
- udf_vfsp != NULL; udf_vfsp = udf_vfsp->udf_next) {
+ udf_vfsp != NULL; udf_vfsp = udf_vfsp->udf_next) {
if (udf_vfsp != checkp->udf_vfs) {
continue;
}
@@ -802,7 +799,7 @@ ud_checkclean(struct vfs *vfsp,
* ignore if buffers or inodes are busy
*/
if ((bcheck(dev, udf_vfsp->udf_iseq)) ||
- (ud_icheck(udf_vfsp))) {
+ (ud_icheck(udf_vfsp))) {
return;
}
mutex_enter(&udf_vfsp->udf_lock);
@@ -856,8 +853,8 @@ ud_flushi(int32_t flag)
lip = NULL;
for (ip = ih->ih_chain[0], lip = NULL;
- ip && ip != (struct ud_inode *)ih;
- ip = ip->i_forw) {
+ ip && ip != (struct ud_inode *)ih;
+ ip = ip->i_forw) {
int flag = ip->i_flag;
vp = ITOV(ip);
@@ -867,9 +864,9 @@ ud_flushi(int32_t flag)
* Skip read-only vnodes
*/
if ((flag & IREF) == 0 ||
- (!vn_has_cached_data(vp) &&
- ((flag & (IMOD|IACC|IUPD|ICHG)) == 0)) ||
- (vp->v_vfsp == NULL) || vn_is_readonly(vp)) {
+ (!vn_has_cached_data(vp) &&
+ ((flag & (IMOD|IACC|IUPD|ICHG)) == 0)) ||
+ (vp->v_vfsp == NULL) || vn_is_readonly(vp)) {
continue;
}
@@ -1010,7 +1007,7 @@ ud_get_next_fid(struct ud_inode *ip, struct fbuf **fbp, uint32_t offset,
if ((offset % lbsize) ||
- (offset == 0)) {
+ (offset == 0)) {
sz = end - beg;
} else {
sz = 0;
@@ -1276,14 +1273,14 @@ ud_verify_tag_and_desc(struct tag *tag, uint16_t id, uint32_t blockno,
eah = (struct ext_attr_hdr *)tag;
if (SWAP_32(eah->eah_aal) > desc_len) {
cmn_err(CE_NOTE,
- "eah_all(0x%x) exceeds desc. len(0x%x) blockno 0x%x\n",
+ "eah_all(0x%x) exceeds desc. len(0x%x) blockno 0x%x\n",
SWAP_32(eah->eah_aal), desc_len, blockno);
- return (1);
+ return (1);
}
ea_off = GET_32(&eah->eah_ial);
if (ea_off >= desc_len) {
cmn_err(CE_NOTE,
- "ea_off(0x%x) is not less than ea_len(0x%x) blockno 0x%x\n",
+ "ea_off(0x%x) is not less than ea_len(0x%x) blockno 0x%x\n",
ea_off, desc_len, blockno);
return (1);
}
@@ -1293,8 +1290,8 @@ ud_verify_tag_and_desc(struct tag *tag, uint16_t id, uint32_t blockno,
}
if (SWAP_32(blockno) != tag->tag_loc) {
cmn_err(CE_NOTE,
- "Tag Location mismatch blockno %x tag_blockno %x\n",
- blockno, SWAP_32(tag->tag_loc));
+ "Tag Location mismatch blockno %x tag_blockno %x\n",
+ blockno, SWAP_32(tag->tag_loc));
return (1);
}
return (0);
@@ -1455,41 +1452,41 @@ ud_utf82utf16(uint8_t *s_8, uint16_t *c_16, int32_t count)
c_32 = *s_8 & 0x7F;
} else if (extra_bytes == 1) {
if (((*s_8 & 0xE0) != 0xC0) ||
- ((*(s_8 + 1) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x1F;
} else if (extra_bytes == 2) {
if (((*s_8 & 0xF0) != 0xE0) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x0F;
} else if (extra_bytes == 3) {
if (((*s_8 & 0xF8) != 0xF0) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80) ||
- ((*(s_8 + 3) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80) ||
+ ((*(s_8 + 3) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x07;
} else if (extra_bytes == 4) {
if (((*s_8 & 0xFC) != 0xF8) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80) ||
- ((*(s_8 + 3) & 0xC0) != 0x80) ||
- ((*(s_8 + 4) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80) ||
+ ((*(s_8 + 3) & 0xC0) != 0x80) ||
+ ((*(s_8 + 4) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x03;
} else if (extra_bytes == 5) {
if (((*s_8 & 0xFE) != 0xFC) ||
- ((*(s_8 + 1) & 0xC0) != 0x80) ||
- ((*(s_8 + 2) & 0xC0) != 0x80) ||
- ((*(s_8 + 3) & 0xC0) != 0x80) ||
- ((*(s_8 + 4) & 0xC0) != 0x80) ||
- ((*(s_8 + 5) & 0xC0) != 0x80)) {
+ ((*(s_8 + 1) & 0xC0) != 0x80) ||
+ ((*(s_8 + 2) & 0xC0) != 0x80) ||
+ ((*(s_8 + 3) & 0xC0) != 0x80) ||
+ ((*(s_8 + 4) & 0xC0) != 0x80) ||
+ ((*(s_8 + 5) & 0xC0) != 0x80)) {
return (0);
}
c_32 = *s_8 & 0x01;
@@ -1560,7 +1557,7 @@ ud_compress(int32_t in_len, int32_t *out_len,
comp_id = 8;
for (in_index = 0; in_index < in_len; in_index += c_tx_sz) {
if ((c_tx_sz = ud_utf82utf16(&in_str[in_index],
- &w2_char, in_len - in_index)) == 0) {
+ &w2_char, in_len - in_index)) == 0) {
error = EINVAL;
goto end;
}
@@ -1576,7 +1573,7 @@ ud_compress(int32_t in_len, int32_t *out_len,
w2_str[out_index++] = w2_char;
}
if (((comp_id == 0x10) && (out_index > ((out_str_len - 2)/2))) ||
- ((comp_id == 0x8) && (out_index > (out_str_len - 2)))) {
+ ((comp_id == 0x8) && (out_index > (out_str_len - 2)))) {
error = ENAMETOOLONG;
goto end;
}
@@ -1669,9 +1666,9 @@ ud_utf162utf8(uint16_t c_16, uint8_t *s_8)
}
/*
- * Convert to a form that can be transfered to the user
+ * Convert to a form that can be transferred to the user
* Assumption's
- * in_length < 256, out_str is atleast 255 bytes long
+ * in_length < 256, out_str is at least 255 bytes long
* The converted byte stream length is returned in out_len
*/
#define MAX_ALLOWABLE_STRING 250
@@ -1703,16 +1700,16 @@ ud_uncompress(int32_t in_len, int32_t *out_len,
*/
if (comp_id == 8) {
if ((in_str[1] == DOT) &&
- ((in_len == 2) || ((in_len == 3) &&
- (in_str[2] == DOT)))) {
+ ((in_len == 2) || ((in_len == 3) &&
+ (in_str[2] == DOT)))) {
out_str[k++] = UNDERBAR;
len_till_now = 1;
goto make_append_crc;
}
} else if (comp_id == 0x10) {
if (((in_str[1] << 8 | in_str[2]) == DOT) &&
- ((in_len == 3) || ((in_len == 5) &&
- ((in_str[3] << 8 | in_str[4]) == DOT)))) {
+ ((in_len == 3) || ((in_len == 5) &&
+ ((in_str[3] << 8 | in_str[4]) == DOT)))) {
out_str[k++] = UNDERBAR;
len_till_now = 1;
goto make_append_crc;
@@ -1746,12 +1743,12 @@ ud_uncompress(int32_t in_len, int32_t *out_len,
* Get rid of invalid characters
*/
if ((w2_char == SLASH) ||
- (w2_char == NULL)) {
+ (w2_char == NULL)) {
make_crc = 1;
if (((comp_id == 8) &&
- (lic != (index - 1))) ||
- (comp_id == 0x10) &&
- (lic != (index - 2))) {
+ (lic != (index - 1))) ||
+ (comp_id == 0x10) &&
+ (lic != (index - 2))) {
w2_char = UNDERBAR;
lic = index;
} else {
@@ -1776,13 +1773,13 @@ ud_uncompress(int32_t in_len, int32_t *out_len,
* the maximum allowed string length
*/
if ((crc_start_loc == 0) &&
- ((len_till_now + c_tx_sz) > MAX_ALLOWABLE_STRING)) {
+ ((len_till_now + c_tx_sz) > MAX_ALLOWABLE_STRING)) {
crc_start_loc = len_till_now;
}
if ((len_till_now + c_tx_sz) < MAXNAMELEN) {
(void) strncpy((caddr_t)&out_str[len_till_now],
- (caddr_t)utf8, c_tx_sz);
+ (caddr_t)utf8, c_tx_sz);
len_till_now += c_tx_sz;
} else {
break;
@@ -1835,7 +1832,7 @@ begin:
bp = bread(dev, blkno, bsize);
if (((bp->b_flags & B_ERROR) == 0) &&
- (bp->b_bcount != bsize)) {
+ (bp->b_bcount != bsize)) {
/*
* Buffer cache returned a
* wrong number of bytes
diff --git a/usr/src/uts/common/fs/udfs/udf_vfsops.c b/usr/src/uts/common/fs/udfs/udf_vfsops.c
index 79e76d2715..95f98d6229 100644
--- a/usr/src/uts/common/fs/udfs/udf_vfsops.c
+++ b/usr/src/uts/common/fs/udfs/udf_vfsops.c
@@ -282,7 +282,7 @@ udf_mount(struct vfs *vfsp, struct vnode *mvp,
oflag = FREAD | FWRITE;
aflag = VREAD | VWRITE;
}
- if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 ||
+ if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
goto out;
}
@@ -365,8 +365,8 @@ udf_unmount(struct vfs *vfsp, int fflag, struct cred *cr)
ud_destroy_fsp(udf_vfsp);
- (void) VOP_PUTPAGE(bvp, (offset_t)0, (uint32_t)0, B_INVAL, cr);
- (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr);
+ (void) VOP_PUTPAGE(bvp, (offset_t)0, (uint32_t)0, B_INVAL, cr, NULL);
+ (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr, NULL);
(void) bfinval(vfsp->vfs_dev, 1);
VN_RELE(bvp);
@@ -555,7 +555,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
(void) dnlc_purge_vfsp(vfsp, 0);
vp = common_specvp(vp);
(void) VOP_PUTPAGE(vp, (offset_t)0,
- (uint32_t)0, B_INVAL, CRED());
+ (uint32_t)0, B_INVAL, CRED(), NULL);
binval(vfsp->vfs_dev);
ovflags = vfsp->vfs_flag;
@@ -566,7 +566,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
ud_update(0);
vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
- (offset_t)0, CRED());
+ (offset_t)0, CRED(), NULL);
return (0);
}
@@ -630,7 +630,8 @@ ud_mountfs(struct vfs *vfsp,
* operations.
*/
error = VOP_OPEN(&devvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, cr);
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
+ cr, NULL);
if (error) {
goto out;
}
@@ -677,7 +678,7 @@ ud_mountfs(struct vfs *vfsp,
if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
(void) dnlc_purge_vfsp(vfsp, 0);
(void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0,
- B_INVAL, CRED());
+ B_INVAL, CRED(), NULL);
(void) ud_iflush(vfsp);
bflush(dev);
binval(dev);
@@ -769,7 +770,7 @@ remountout:
* they really should be using the raw device.
*/
(void) VOP_PUTPAGE(common_specvp(devvp), (offset_t)0,
- (uint32_t)0, B_INVAL, cr);
+ (uint32_t)0, B_INVAL, cr, NULL);
/*
@@ -936,7 +937,7 @@ out:
ud_destroy_fsp(udf_vfsp);
if (needclose) {
(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
- FREAD : FREAD|FWRITE, 1, (offset_t)0, cr);
+ FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
bflush(dev);
binval(dev);
}
diff --git a/usr/src/uts/common/fs/udfs/udf_vnops.c b/usr/src/uts/common/fs/udfs/udf_vnops.c
index defbd544f5..2a2822eb3f 100644
--- a/usr/src/uts/common/fs/udfs/udf_vnops.c
+++ b/usr/src/uts/common/fs/udfs/udf_vnops.c
@@ -84,70 +84,79 @@
#include <sys/fs/udf_inode.h>
static int32_t udf_open(struct vnode **,
- int32_t, struct cred *);
+ int32_t, struct cred *, caller_context_t *);
static int32_t udf_close(struct vnode *,
- int32_t, int32_t, offset_t, struct cred *);
+ int32_t, int32_t, offset_t, struct cred *, caller_context_t *);
static int32_t udf_read(struct vnode *,
- struct uio *, int32_t, struct cred *, struct caller_context *);
+ struct uio *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_write(struct vnode *,
- struct uio *, int32_t, struct cred *, struct caller_context *);
+ struct uio *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_ioctl(struct vnode *,
- int32_t, intptr_t, int32_t, struct cred *, int32_t *);
+ int32_t, intptr_t, int32_t, struct cred *, int32_t *,
+ caller_context_t *);
static int32_t udf_getattr(struct vnode *,
- struct vattr *, int32_t, struct cred *);
+ struct vattr *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_setattr(struct vnode *,
struct vattr *, int32_t, struct cred *, caller_context_t *);
static int32_t udf_access(struct vnode *,
- int32_t, int32_t, struct cred *);
+ int32_t, int32_t, struct cred *, caller_context_t *);
static int32_t udf_lookup(struct vnode *,
char *, struct vnode **, struct pathname *,
- int32_t, struct vnode *, struct cred *);
+ int32_t, struct vnode *, struct cred *,
+ caller_context_t *, int *, pathname_t *);
static int32_t udf_create(struct vnode *,
char *, struct vattr *, enum vcexcl,
- int32_t, struct vnode **, struct cred *, int32_t);
+ int32_t, struct vnode **, struct cred *, int32_t,
+ caller_context_t *, vsecattr_t *);
static int32_t udf_remove(struct vnode *,
- char *, struct cred *);
+ char *, struct cred *, caller_context_t *, int);
static int32_t udf_link(struct vnode *,
- struct vnode *, char *, struct cred *);
+ struct vnode *, char *, struct cred *, caller_context_t *, int);
static int32_t udf_rename(struct vnode *,
- char *, struct vnode *, char *, struct cred *);
+ char *, struct vnode *, char *, struct cred *, caller_context_t *, int);
static int32_t udf_mkdir(struct vnode *,
- char *, struct vattr *, struct vnode **, struct cred *);
+ char *, struct vattr *, struct vnode **, struct cred *,
+ caller_context_t *, int, vsecattr_t *);
static int32_t udf_rmdir(struct vnode *,
- char *, struct vnode *, struct cred *);
+ char *, struct vnode *, struct cred *, caller_context_t *, int);
static int32_t udf_readdir(struct vnode *,
- struct uio *, struct cred *, int32_t *);
+ struct uio *, struct cred *, int32_t *, caller_context_t *, int);
static int32_t udf_symlink(struct vnode *,
- char *, struct vattr *, char *, struct cred *);
+ char *, struct vattr *, char *, struct cred *, caller_context_t *, int);
static int32_t udf_readlink(struct vnode *,
- struct uio *, struct cred *);
+ struct uio *, struct cred *, caller_context_t *);
static int32_t udf_fsync(struct vnode *,
- int32_t, struct cred *);
+ int32_t, struct cred *, caller_context_t *);
static void udf_inactive(struct vnode *,
- struct cred *);
-static int32_t udf_fid(struct vnode *, struct fid *);
+ struct cred *, caller_context_t *);
+static int32_t udf_fid(struct vnode *, struct fid *, caller_context_t *);
static int udf_rwlock(struct vnode *, int32_t, caller_context_t *);
static void udf_rwunlock(struct vnode *, int32_t, caller_context_t *);
-static int32_t udf_seek(struct vnode *, offset_t, offset_t *);
+static int32_t udf_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
static int32_t udf_frlock(struct vnode *, int32_t,
- struct flock64 *, int32_t, offset_t, struct flk_callback *, cred_t *);
+ struct flock64 *, int32_t, offset_t, struct flk_callback *, cred_t *,
+ caller_context_t *);
static int32_t udf_space(struct vnode *, int32_t,
struct flock64 *, int32_t, offset_t, cred_t *, caller_context_t *);
static int32_t udf_getpage(struct vnode *, offset_t,
size_t, uint32_t *, struct page **, size_t,
- struct seg *, caddr_t, enum seg_rw, struct cred *);
+ struct seg *, caddr_t, enum seg_rw, struct cred *, caller_context_t *);
static int32_t udf_putpage(struct vnode *, offset_t,
- size_t, int32_t, struct cred *);
+ size_t, int32_t, struct cred *, caller_context_t *);
static int32_t udf_map(struct vnode *, offset_t, struct as *,
- caddr_t *, size_t, uint8_t, uint8_t, uint32_t, struct cred *);
+ caddr_t *, size_t, uint8_t, uint8_t, uint32_t, struct cred *,
+ caller_context_t *);
static int32_t udf_addmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uint8_t, uint8_t, uint32_t, struct cred *);
+ caddr_t, size_t, uint8_t, uint8_t, uint32_t, struct cred *,
+ caller_context_t *);
static int32_t udf_delmap(struct vnode *, offset_t, struct as *,
- caddr_t, size_t, uint32_t, uint32_t, uint32_t, struct cred *);
+ caddr_t, size_t, uint32_t, uint32_t, uint32_t, struct cred *,
+ caller_context_t *);
static int32_t udf_l_pathconf(struct vnode *, int32_t,
- ulong_t *, struct cred *);
+ ulong_t *, struct cred *, caller_context_t *);
static int32_t udf_pageio(struct vnode *, struct page *,
- u_offset_t, size_t, int32_t, struct cred *);
+ u_offset_t, size_t, int32_t, struct cred *, caller_context_t *);
int32_t ud_getpage_miss(struct vnode *, u_offset_t,
size_t, struct seg *, caddr_t, page_t *pl[],
@@ -227,7 +236,11 @@ const fs_operation_def_t udf_vnodeops_template[] = {
/* ARGSUSED */
static int32_t
-udf_open(struct vnode **vpp, int32_t flag, struct cred *cr)
+udf_open(
+ struct vnode **vpp,
+ int32_t flag,
+ struct cred *cr,
+ caller_context_t *ct)
{
ud_printf("udf_open\n");
@@ -236,8 +249,13 @@ udf_open(struct vnode **vpp, int32_t flag, struct cred *cr)
/* ARGSUSED */
static int32_t
-udf_close(struct vnode *vp, int32_t flag,
- int32_t count, offset_t offset, struct cred *cr)
+udf_close(
+ struct vnode *vp,
+ int32_t flag,
+ int32_t count,
+ offset_t offset,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -265,9 +283,14 @@ udf_close(struct vnode *vp, int32_t flag,
return (0);
}
+/* ARGSUSED */
static int32_t
-udf_read(struct vnode *vp, struct uio *uiop,
- int32_t ioflag, struct cred *cr, struct caller_context *ct)
+udf_read(
+ struct vnode *vp,
+ struct uio *uiop,
+ int32_t ioflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error;
@@ -309,9 +332,14 @@ int32_t ud_HW = 96 * 1024;
int32_t ud_LW = 64 * 1024;
int32_t ud_throttles = 0;
+/* ARGSUSED */
static int32_t
-udf_write(struct vnode *vp, struct uio *uiop,
- int32_t ioflag, struct cred *cr, struct caller_context *ct)
+udf_write(
+ struct vnode *vp,
+ struct uio *uiop,
+ int32_t ioflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error = 0;
@@ -369,16 +397,26 @@ end:
/* ARGSUSED */
static int32_t
-udf_ioctl(struct vnode *vp, int32_t cmd, intptr_t arg,
- int32_t flag, struct cred *cr, int32_t *rvalp)
+udf_ioctl(
+ struct vnode *vp,
+ int32_t cmd,
+ intptr_t arg,
+ int32_t flag,
+ struct cred *cr,
+ int32_t *rvalp,
+ caller_context_t *ct)
{
return (ENOTTY);
}
/* ARGSUSED */
static int32_t
-udf_getattr(struct vnode *vp,
- struct vattr *vap, int32_t flags, struct cred *cr)
+udf_getattr(
+ struct vnode *vp,
+ struct vattr *vap,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -566,8 +604,12 @@ update_inode:
/* ARGSUSED */
static int32_t
-udf_access(struct vnode *vp,
- int32_t mode, int32_t flags, struct cred *cr)
+udf_access(
+ struct vnode *vp,
+ int32_t mode,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error;
@@ -587,9 +629,17 @@ int32_t udfs_stickyhack = 1;
/* ARGSUSED */
static int32_t
-udf_lookup(struct vnode *dvp,
- char *nm, struct vnode **vpp, struct pathname *pnp,
- int32_t flags, struct vnode *rdir, struct cred *cr)
+udf_lookup(
+ struct vnode *dvp,
+ char *nm,
+ struct vnode **vpp,
+ struct pathname *pnp,
+ int32_t flags,
+ struct vnode *rdir,
+ struct cred *cr,
+ caller_context_t *ct,
+ int *direntflags,
+ pathname_t *realpnp)
{
int32_t error;
struct vnode *vp;
@@ -656,9 +706,17 @@ out:
/* ARGSUSED */
static int32_t
-udf_create(struct vnode *dvp,
- char *name, struct vattr *vap, enum vcexcl excl,
- int32_t mode, struct vnode **vpp, struct cred *cr, int32_t flag)
+udf_create(
+ struct vnode *dvp,
+ char *name,
+ struct vattr *vap,
+ enum vcexcl excl,
+ int32_t mode,
+ struct vnode **vpp,
+ struct cred *cr,
+ int32_t flag,
+ caller_context_t *ct,
+ vsecattr_t *vsecp)
{
int32_t error;
struct ud_inode *ip = VTOI(dvp), *xip;
@@ -679,8 +737,8 @@ udf_create(struct vnode *dvp,
xip = NULL;
rw_enter(&ip->i_rwlock, RW_WRITER);
error = ud_direnter(ip, name, DE_CREATE,
- (struct ud_inode *)0, (struct ud_inode *)0,
- vap, &xip, cr);
+ (struct ud_inode *)0, (struct ud_inode *)0,
+ vap, &xip, cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
ip = xip;
@@ -732,7 +790,7 @@ udf_create(struct vnode *dvp,
(void) ud_itrunc(ip, 0, 0, cr);
rw_exit(&ip->i_rwlock);
}
- vnevent_create(ITOV(ip));
+ vnevent_create(ITOV(ip), ct);
}
}
@@ -769,8 +827,14 @@ out:
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_remove(struct vnode *vp, char *nm, struct cred *cr)
+udf_remove(
+ struct vnode *vp,
+ char *nm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error;
struct ud_inode *ip = VTOI(vp);
@@ -779,16 +843,22 @@ udf_remove(struct vnode *vp, char *nm, struct cred *cr)
rw_enter(&ip->i_rwlock, RW_WRITER);
error = ud_dirremove(ip, nm,
- (struct ud_inode *)0, (struct vnode *)0, DR_REMOVE, cr);
+ (struct ud_inode *)0, (struct vnode *)0, DR_REMOVE, cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_link(struct vnode *tdvp,
- struct vnode *svp, char *tnm, struct cred *cr)
+udf_link(
+ struct vnode *tdvp,
+ struct vnode *svp,
+ char *tnm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error;
struct vnode *realvp;
@@ -796,7 +866,7 @@ udf_link(struct vnode *tdvp,
struct ud_inode *tdp;
ud_printf("udf_link\n");
- if (VOP_REALVP(svp, &realvp) == 0) {
+ if (VOP_REALVP(svp, &realvp, ct) == 0) {
svp = realvp;
}
@@ -816,13 +886,13 @@ udf_link(struct vnode *tdvp,
rw_enter(&tdp->i_rwlock, RW_WRITER);
error = ud_direnter(tdp, tnm, DE_LINK, (struct ud_inode *)0,
- sip, (struct vattr *)0, (struct ud_inode **)0, cr);
+ sip, (struct vattr *)0, (struct ud_inode **)0, cr, ct);
rw_exit(&tdp->i_rwlock);
ITIMES(sip);
ITIMES(tdp);
if (error == 0) {
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
return (error);
@@ -830,9 +900,14 @@ udf_link(struct vnode *tdvp,
/* ARGSUSED */
static int32_t
-udf_rename(struct vnode *sdvp,
- char *snm, struct vnode *tdvp,
- char *tnm, struct cred *cr)
+udf_rename(
+ struct vnode *sdvp,
+ char *snm,
+ struct vnode *tdvp,
+ char *tnm,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error = 0;
struct udf_vfs *udf_vfsp;
@@ -842,7 +917,7 @@ udf_rename(struct vnode *sdvp,
ud_printf("udf_rename\n");
- if (VOP_REALVP(tdvp, &realvp) == 0) {
+ if (VOP_REALVP(tdvp, &realvp, ct) == 0) {
tdvp = realvp;
}
@@ -906,7 +981,7 @@ udf_rename(struct vnode *sdvp,
*/
rw_enter(&tdp->i_rwlock, RW_WRITER);
if (error = ud_direnter(tdp, tnm, DE_RENAME, sdp, sip,
- (struct vattr *)0, (struct ud_inode **)0, cr)) {
+ (struct vattr *)0, (struct ud_inode **)0, cr, ct)) {
/*
* ESAME isn't really an error; it indicates that the
* operation should not be done because the source and target
@@ -918,7 +993,7 @@ udf_rename(struct vnode *sdvp,
rw_exit(&tdp->i_rwlock);
goto errout;
}
- vnevent_rename_src(ITOV(sip), sdvp, snm);
+ vnevent_rename_src(ITOV(sip), sdvp, snm, ct);
rw_exit(&tdp->i_rwlock);
rw_enter(&sdp->i_rwlock, RW_WRITER);
@@ -930,7 +1005,7 @@ udf_rename(struct vnode *sdvp,
* the source inode.
*/
if ((error = ud_dirremove(sdp, snm, sip, (struct vnode *)0,
- DR_RENAME, cr)) == ENOENT) {
+ DR_RENAME, cr, ct)) == ENOENT) {
error = 0;
}
rw_exit(&sdp->i_rwlock);
@@ -943,10 +1018,17 @@ errout:
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_mkdir(struct vnode *dvp,
- char *dirname, struct vattr *vap,
- struct vnode **vpp, struct cred *cr)
+udf_mkdir(
+ struct vnode *dvp,
+ char *dirname,
+ struct vattr *vap,
+ struct vnode **vpp,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp)
{
int32_t error;
struct ud_inode *ip;
@@ -959,7 +1041,7 @@ udf_mkdir(struct vnode *dvp,
ip = VTOI(dvp);
rw_enter(&ip->i_rwlock, RW_WRITER);
error = ud_direnter(ip, dirname, DE_MKDIR,
- (struct ud_inode *)0, (struct ud_inode *)0, vap, &xip, cr);
+ (struct ud_inode *)0, (struct ud_inode *)0, vap, &xip, cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
if (error == 0) {
@@ -974,9 +1056,15 @@ udf_mkdir(struct vnode *dvp,
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_rmdir(struct vnode *vp,
- char *nm, struct vnode *cdir, struct cred *cr)
+udf_rmdir(
+ struct vnode *vp,
+ char *nm,
+ struct vnode *cdir,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error;
struct ud_inode *ip = VTOI(vp);
@@ -984,7 +1072,8 @@ udf_rmdir(struct vnode *vp,
ud_printf("udf_rmdir\n");
rw_enter(&ip->i_rwlock, RW_WRITER);
- error = ud_dirremove(ip, nm, (struct ud_inode *)0, cdir, DR_RMDIR, cr);
+ error = ud_dirremove(ip, nm, (struct ud_inode *)0, cdir, DR_RMDIR,
+ cr, ct);
rw_exit(&ip->i_rwlock);
ITIMES(ip);
@@ -993,8 +1082,13 @@ udf_rmdir(struct vnode *vp,
/* ARGSUSED */
static int32_t
-udf_readdir(struct vnode *vp,
- struct uio *uiop, struct cred *cr, int32_t *eofp)
+udf_readdir(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ int32_t *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct ud_inode *ip;
struct dirent64 *nd;
@@ -1142,9 +1236,14 @@ end:
/* ARGSUSED */
static int32_t
-udf_symlink(struct vnode *dvp,
- char *linkname, struct vattr *vap,
- char *target, struct cred *cr)
+udf_symlink(
+ struct vnode *dvp,
+ char *linkname,
+ struct vattr *vap,
+ char *target,
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
int32_t error = 0, outlen;
uint32_t ioflag = 0;
@@ -1161,7 +1260,7 @@ udf_symlink(struct vnode *dvp,
rw_enter(&dip->i_rwlock, RW_WRITER);
error = ud_direnter(dip, linkname, DE_CREATE,
- (struct ud_inode *)0, (struct ud_inode *)0, vap, &ip, cr);
+ (struct ud_inode *)0, (struct ud_inode *)0, vap, &ip, cr, ct);
rw_exit(&dip->i_rwlock);
if (error == 0) {
dname = kmem_zalloc(1024, KM_SLEEP);
@@ -1246,7 +1345,7 @@ udf_symlink(struct vnode *dvp,
rw_exit(&ip->i_contents);
rw_enter(&dip->i_rwlock, RW_WRITER);
(void) ud_dirremove(dip, linkname, (struct ud_inode *)0,
- (struct vnode *)0, DR_REMOVE, cr);
+ (struct vnode *)0, DR_REMOVE, cr, ct);
rw_exit(&dip->i_rwlock);
goto update_inode;
}
@@ -1271,8 +1370,11 @@ update_inode:
/* ARGSUSED */
static int32_t
-udf_readlink(struct vnode *vp,
- struct uio *uiop, struct cred *cr)
+udf_readlink(
+ struct vnode *vp,
+ struct uio *uiop,
+ struct cred *cr,
+ caller_context_t *ct)
{
int32_t error = 0, off, id_len, size, len;
int8_t *dname = NULL, *uname = NULL;
@@ -1374,8 +1476,11 @@ end:
/* ARGSUSED */
static int32_t
-udf_fsync(struct vnode *vp,
- int32_t syncflag, struct cred *cr)
+udf_fsync(
+ struct vnode *vp,
+ int32_t syncflag,
+ struct cred *cr,
+ caller_context_t *ct)
{
int32_t error = 0;
struct ud_inode *ip = VTOI(vp);
@@ -1397,15 +1502,16 @@ udf_fsync(struct vnode *vp,
/* ARGSUSED */
static void
-udf_inactive(struct vnode *vp, struct cred *cr)
+udf_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
ud_printf("udf_iinactive\n");
ud_iinactive(VTOI(vp), cr);
}
+/* ARGSUSED */
static int32_t
-udf_fid(struct vnode *vp, struct fid *fidp)
+udf_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct udf_fid *udfidp;
struct ud_inode *ip = VTOI(vp);
@@ -1466,15 +1572,21 @@ udf_rwunlock(struct vnode *vp, int32_t write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int32_t
-udf_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+udf_seek(struct vnode *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
static int32_t
-udf_frlock(struct vnode *vp, int32_t cmd, struct flock64 *bfp,
- int32_t flag, offset_t offset, struct flk_callback *flk_cbp,
- cred_t *cr)
+udf_frlock(
+ struct vnode *vp,
+ int32_t cmd,
+ struct flock64 *bfp,
+ int32_t flag,
+ offset_t offset,
+ struct flk_callback *flk_cbp,
+ cred_t *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -1492,7 +1604,7 @@ udf_frlock(struct vnode *vp, int32_t cmd, struct flock64 *bfp,
return (EAGAIN);
}
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
/*ARGSUSED6*/
@@ -1521,10 +1633,18 @@ udf_space(
/* ARGSUSED */
static int32_t
-udf_getpage(struct vnode *vp, offset_t off,
- size_t len, uint32_t *protp, struct page **plarr,
- size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, struct cred *cr)
+udf_getpage(
+ struct vnode *vp,
+ offset_t off,
+ size_t len,
+ uint32_t *protp,
+ struct page **plarr,
+ size_t plsz,
+ struct seg *seg,
+ caddr_t addr,
+ enum seg_rw rw,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
int32_t error, has_holes, beyond_eof, seqmode, dolock;
@@ -1798,8 +1918,13 @@ int32_t ud_delay = 1;
/* ARGSUSED */
static int32_t
-udf_putpage(struct vnode *vp, offset_t off,
- size_t len, int32_t flags, struct cred *cr)
+udf_putpage(
+ struct vnode *vp,
+ offset_t off,
+ size_t len,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip;
int32_t error = 0;
@@ -1879,11 +2004,19 @@ out:
return (error);
}
+/* ARGSUSED */
static int32_t
-udf_map(struct vnode *vp, offset_t off,
- struct as *as, caddr_t *addrp, size_t len,
- uint8_t prot, uint8_t maxprot, uint32_t flags,
- struct cred *cr)
+udf_map(
+ struct vnode *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t *addrp,
+ size_t len,
+ uint8_t prot,
+ uint8_t maxprot,
+ uint32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
int32_t error = 0;
@@ -1949,10 +2082,16 @@ end:
/* ARGSUSED */
static int32_t
-udf_addmap(struct vnode *vp, offset_t off,
- struct as *as, caddr_t addr, size_t len,
- uint8_t prot, uint8_t maxprot, uint32_t flags,
- struct cred *cr)
+udf_addmap(struct vnode *vp,
+ offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint8_t prot,
+ uint8_t maxprot,
+ uint32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -1971,10 +2110,16 @@ udf_addmap(struct vnode *vp, offset_t off,
/* ARGSUSED */
static int32_t
-udf_delmap(struct vnode *vp, offset_t off,
- struct as *as, caddr_t addr, size_t len,
- uint32_t prot, uint32_t maxprot, uint32_t flags,
- struct cred *cr)
+udf_delmap(
+ struct vnode *vp, offset_t off,
+ struct as *as,
+ caddr_t addr,
+ size_t len,
+ uint32_t prot,
+ uint32_t maxprot,
+ uint32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
struct ud_inode *ip = VTOI(vp);
@@ -1992,9 +2137,14 @@ udf_delmap(struct vnode *vp, offset_t off,
return (0);
}
+/* ARGSUSED */
static int32_t
-udf_l_pathconf(struct vnode *vp, int32_t cmd,
- ulong_t *valp, struct cred *cr)
+udf_l_pathconf(
+ struct vnode *vp,
+ int32_t cmd,
+ ulong_t *valp,
+ struct cred *cr,
+ caller_context_t *ct)
{
int32_t error = 0;
@@ -2010,7 +2160,7 @@ udf_l_pathconf(struct vnode *vp, int32_t cmd,
*/
*valp = 41;
} else {
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
return (error);
@@ -2027,9 +2177,14 @@ _NOTE(SCHEME_PROTECTS_DATA("safe sharing", ud_pageio_writes))
*/
/* ARGSUSED */
static int32_t
-udf_pageio(struct vnode *vp, struct page *pp,
- u_offset_t io_off, size_t io_len,
- int32_t flags, struct cred *cr)
+udf_pageio(
+ struct vnode *vp,
+ struct page *pp,
+ u_offset_t io_off,
+ size_t io_len,
+ int32_t flags,
+ struct cred *cr,
+ caller_context_t *ct)
{
daddr_t bn;
struct buf *bp;
diff --git a/usr/src/uts/common/fs/ufs/quotacalls.c b/usr/src/uts/common/fs/ufs/quotacalls.c
index 6474acbfff..4c97cd9149 100644
--- a/usr/src/uts/common/fs/ufs/quotacalls.c
+++ b/usr/src/uts/common/fs/ufs/quotacalls.c
@@ -271,7 +271,7 @@ opendq(
" from quota file\n");
rw_exit(&qip->i_contents);
(void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)qip->i_size,
- B_INVAL, kcred);
+ B_INVAL, kcred, NULL);
} else {
rw_exit(&qip->i_contents);
}
@@ -642,7 +642,7 @@ setquota(int cmd, uid_t uid, struct ufsvfs *ufsvfsp,
rw_exit(&qip->i_contents);
(void) VOP_PUTPAGE(ITOV(qip), dqoff(dqp->dq_uid) & ~qip->i_fs->fs_bmask,
- qip->i_fs->fs_bsize, B_INVAL, kcred);
+ qip->i_fs->fs_bsize, B_INVAL, kcred, NULL);
/*
* We must set the dq_mof even if not we are not logging in case
diff --git a/usr/src/uts/common/fs/ufs/ufs_directio.c b/usr/src/uts/common/fs/ufs/ufs_directio.c
index b60537ba75..7e908772bc 100644
--- a/usr/src/uts/common/fs/ufs/ufs_directio.c
+++ b/usr/src/uts/common/fs/ufs/ufs_directio.c
@@ -600,7 +600,8 @@ skip_alloc:
rw_exit(&ip->i_contents);
rw_enter(&ip->i_contents, RW_WRITER);
}
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
+ B_INVAL, cr, NULL);
if (vn_has_cached_data(vp))
goto errout;
if (!exclusive)
@@ -737,7 +738,7 @@ skip_alloc:
rw_exit(&ip->i_contents);
rw_enter(&ip->i_contents, RW_WRITER);
(void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
- B_INVAL, cr);
+ B_INVAL, cr, NULL);
ufs_directio_kstats.nflushes.value.ui64++;
rw_downgrade(&ip->i_contents);
}
@@ -912,7 +913,8 @@ ufs_directio_read(struct inode *ip, uio_t *uio, cred_t *cr, int *statusp)
if (vn_has_cached_data(vp)) {
rw_exit(&ip->i_contents);
rw_enter(&ip->i_contents, RW_WRITER);
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
+ B_INVAL, cr, NULL);
if (vn_has_cached_data(vp))
return (0);
rw_downgrade(&ip->i_contents);
diff --git a/usr/src/uts/common/fs/ufs/ufs_extvnops.c b/usr/src/uts/common/fs/ufs/ufs_extvnops.c
index 4533f8db07..08ece1de79 100644
--- a/usr/src/uts/common/fs/ufs/ufs_extvnops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_extvnops.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -244,7 +243,7 @@ ufs_alloc_data(
size_t done_len, io_len;
int contig;
u_offset_t uoff, io_off;
- int error = 0; /* No error occured */
+ int error = 0; /* No error occurred */
int offsetn; /* Start point this IO */
int nbytes; /* Number bytes in this IO */
daddr_t bn;
@@ -502,7 +501,7 @@ ufs_alloc_data(
* was written.
*
*/
- (void) VOP_PUTPAGE(vnodep, 0, 0, B_INVAL, credp);
+ (void) VOP_PUTPAGE(vnodep, 0, 0, B_INVAL, credp, NULL);
rw_exit(&ip->i_contents);
rw_exit(&ip->i_ufsvfs->vfs_dqrwlock);
diff --git a/usr/src/uts/common/fs/ufs/ufs_filio.c b/usr/src/uts/common/fs/ufs/ufs_filio.c
index 6a6bc4c421..04a68104ff 100644
--- a/usr/src/uts/common/fs/ufs/ufs_filio.c
+++ b/usr/src/uts/common/fs/ufs/ufs_filio.c
@@ -171,10 +171,10 @@ ufs_fioio(
* Adapted from vn_open: check access and then open the file
*/
vpio = ITOV(ipio);
- if (error = VOP_ACCESS(vpio, VREAD, 0, cr))
+ if (error = VOP_ACCESS(vpio, VREAD, 0, cr, NULL))
goto errout;
- if (error = VOP_OPEN(&vpio, FREAD, cr))
+ if (error = VOP_OPEN(&vpio, FREAD, cr, NULL))
goto errout;
/*
diff --git a/usr/src/uts/common/fs/ufs/ufs_lockfs.c b/usr/src/uts/common/fs/ufs/ufs_lockfs.c
index 6055532000..b7a7179c28 100644
--- a/usr/src/uts/common/fs/ufs/ufs_lockfs.c
+++ b/usr/src/uts/common/fs/ufs/ufs_lockfs.c
@@ -367,7 +367,7 @@ ufs_flush(struct vfs *vfsp)
* flush w/invalidate block device pages and buf cache
*/
if ((error = VOP_PUTPAGE(common_specvp(ufsvfsp->vfs_devvp),
- (offset_t)0, 0, B_INVAL, CRED())) > 0)
+ (offset_t)0, 0, B_INVAL, CRED(), NULL)) > 0)
saverror = error;
(void) bflush((dev_t)vfsp->vfs_dev);
diff --git a/usr/src/uts/common/fs/ufs/ufs_subr.c b/usr/src/uts/common/fs/ufs/ufs_subr.c
index f6daee5dc1..e2d1f6577b 100644
--- a/usr/src/uts/common/fs/ufs/ufs_subr.c
+++ b/usr/src/uts/common/fs/ufs/ufs_subr.c
@@ -489,7 +489,8 @@ ufs_syncip(struct inode *ip, int flags, int waitfor, top_t topid)
TRANS_BEGIN_ASYNC(ufsvfsp, TOP_PUTPAGE,
TOP_PUTPAGE_SIZE(ip));
}
- error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, flags, CRED());
+ error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
+ flags, CRED(), NULL);
if (dotrans) {
TRANS_END_ASYNC(ufsvfsp, TOP_PUTPAGE,
TOP_PUTPAGE_SIZE(ip));
diff --git a/usr/src/uts/common/fs/ufs/ufs_vfsops.c b/usr/src/uts/common/fs/ufs/ufs_vfsops.c
index 23c2d1798a..80151eaa32 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vfsops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vfsops.c
@@ -361,7 +361,7 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
oflag = FREAD | FWRITE;
aflag = VREAD | VWRITE;
}
- if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 ||
+ if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
(error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
pn_free(&dpn);
VN_RELE(bvp);
@@ -407,6 +407,8 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
if (error) {
VN_RELE(bvp);
}
+ if (error == 0)
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
return (error);
}
/*
@@ -449,7 +451,8 @@ ufs_mountroot(struct vfs *vfsp, enum whymountroot why)
vp = ((struct ufsvfs *)vfsp->vfs_data)->vfs_devvp;
(void) dnlc_purge_vfsp(vfsp, 0);
vp = common_specvp(vp);
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, CRED());
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL,
+ CRED(), NULL);
(void) bfinval(vfsp->vfs_dev, 0);
fsp = getfs(vfsp);
@@ -484,7 +487,7 @@ ufs_mountroot(struct vfs *vfsp, enum whymountroot why)
vp = ((struct ufsvfs *)vfsp->vfs_data)->vfs_devvp;
(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
- (offset_t)0, CRED());
+ (offset_t)0, CRED(), NULL);
return (0);
}
error = vfs_lock(vfsp);
@@ -496,10 +499,10 @@ ufs_mountroot(struct vfs *vfsp, enum whymountroot why)
/* If RO media, don't call clkset() (see below) */
doclkset = 1;
if (why == ROOT_INIT) {
- error = VOP_OPEN(&devvp, FREAD|FWRITE, CRED());
+ error = VOP_OPEN(&devvp, FREAD|FWRITE, CRED(), NULL);
if (error == 0) {
(void) VOP_CLOSE(devvp, FREAD|FWRITE, 1,
- (offset_t)0, CRED());
+ (offset_t)0, CRED(), NULL);
} else {
doclkset = 0;
}
@@ -788,7 +791,8 @@ mountfs(struct vfs *vfsp, enum whymountroot why, struct vnode *devvp,
* operations.
*/
error = VOP_OPEN(&devvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, cr);
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
+ cr, NULL);
if (error)
goto out;
needclose = 1;
@@ -822,7 +826,7 @@ mountfs(struct vfs *vfsp, enum whymountroot why, struct vnode *devvp,
* they really should be using the raw device.
*/
(void) VOP_PUTPAGE(common_specvp(devvp), (offset_t)0,
- (size_t)0, B_INVAL, cr);
+ (size_t)0, B_INVAL, cr, NULL);
/*
* read in superblock
@@ -1321,7 +1325,7 @@ out:
}
if (needclose) {
(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
- FREAD : FREAD|FWRITE, 1, (offset_t)0, cr);
+ FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
bflush(dev);
(void) bfinval(dev, 1);
}
@@ -1628,8 +1632,8 @@ ufs_unmount(struct vfs *vfsp, int fflag, struct cred *cr)
brelse(bp); /* free the superblock buf */
(void) VOP_PUTPAGE(common_specvp(bvp), (offset_t)0, (size_t)0,
- B_INVAL, cr);
- (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr);
+ B_INVAL, cr, NULL);
+ (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr, NULL);
bflush(dev);
(void) bfinval(dev, 1);
VN_RELE(bvp);
@@ -1696,7 +1700,7 @@ out:
ufs_trans_onerror();
/*
- * if we have a seperate /usr it will never unmount
+ * if we have a separate /usr it will never unmount
* when halting. In order to not re-read all the
* cylinder group summary info on mounting after
* reboot the logging of summary info is re-enabled
@@ -2099,7 +2103,7 @@ ufs_remountroot(struct vfs *vfsp)
new_rootvp = makespecvp(new_rootdev, VBLK);
error = VOP_OPEN(&new_rootvp,
- (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, CRED());
+ (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, CRED(), NULL);
if (error) {
cmn_err(CE_CONT,
"Cannot open mirrored root device, error %d\n", error);
@@ -2245,7 +2249,7 @@ ufs_remountroot(struct vfs *vfsp)
vfs_unlock(vfsp);
- error = VOP_CLOSE(old_rootvp, FREAD, 1, (offset_t)0, CRED());
+ error = VOP_CLOSE(old_rootvp, FREAD, 1, (offset_t)0, CRED(), NULL);
if (error) {
cmn_err(CE_CONT,
"close of root device component failed, error %d\n",
diff --git a/usr/src/uts/common/fs/ufs/ufs_vnops.c b/usr/src/uts/common/fs/ufs/ufs_vnops.c
index 414aa037c4..4c712bbd75 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vnops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c
@@ -103,64 +103,80 @@ static struct instats ins;
static int ufs_getpage_ra(struct vnode *, u_offset_t, struct seg *, caddr_t);
static int ufs_getpage_miss(struct vnode *, u_offset_t, size_t, struct seg *,
caddr_t, struct page **, size_t, enum seg_rw, int);
-static int ufs_open(struct vnode **, int, struct cred *);
-static int ufs_close(struct vnode *, int, int, offset_t, struct cred *);
+static int ufs_open(struct vnode **, int, struct cred *, caller_context_t *);
+static int ufs_close(struct vnode *, int, int, offset_t, struct cred *,
+ caller_context_t *);
static int ufs_read(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
+ struct caller_context *);
static int ufs_write(struct vnode *, struct uio *, int, struct cred *,
- struct caller_context *);
-static int ufs_ioctl(struct vnode *, int, intptr_t, int, struct cred *, int *);
-static int ufs_getattr(struct vnode *, struct vattr *, int, struct cred *);
+ struct caller_context *);
+static int ufs_ioctl(struct vnode *, int, intptr_t, int, struct cred *,
+ int *, caller_context_t *);
+static int ufs_getattr(struct vnode *, struct vattr *, int, struct cred *,
+ caller_context_t *);
static int ufs_setattr(struct vnode *, struct vattr *, int, struct cred *,
- caller_context_t *);
-static int ufs_access(struct vnode *, int, int, struct cred *);
+ caller_context_t *);
+static int ufs_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *);
static int ufs_lookup(struct vnode *, char *, struct vnode **,
- struct pathname *, int, struct vnode *, struct cred *);
+ struct pathname *, int, struct vnode *, struct cred *,
+ caller_context_t *, int *, pathname_t *);
static int ufs_create(struct vnode *, char *, struct vattr *, enum vcexcl,
- int, struct vnode **, struct cred *, int);
-static int ufs_remove(struct vnode *, char *, struct cred *);
-static int ufs_link(struct vnode *, struct vnode *, char *, struct cred *);
+ int, struct vnode **, struct cred *, int,
+ caller_context_t *, vsecattr_t *);
+static int ufs_remove(struct vnode *, char *, struct cred *,
+ caller_context_t *, int);
+static int ufs_link(struct vnode *, struct vnode *, char *, struct cred *,
+ caller_context_t *, int);
static int ufs_rename(struct vnode *, char *, struct vnode *, char *,
- struct cred *);
+ struct cred *, caller_context_t *, int);
static int ufs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
- struct cred *);
-static int ufs_rmdir(struct vnode *, char *, struct vnode *, struct cred *);
-static int ufs_readdir(struct vnode *, struct uio *, struct cred *, int *);
+ struct cred *, caller_context_t *, int, vsecattr_t *);
+static int ufs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
+ caller_context_t *, int);
+static int ufs_readdir(struct vnode *, struct uio *, struct cred *, int *,
+ caller_context_t *, int);
static int ufs_symlink(struct vnode *, char *, struct vattr *, char *,
- struct cred *);
-static int ufs_readlink(struct vnode *, struct uio *, struct cred *);
-static int ufs_fsync(struct vnode *, int, struct cred *);
-static void ufs_inactive(struct vnode *, struct cred *);
-static int ufs_fid(struct vnode *, struct fid *);
+ struct cred *, caller_context_t *, int);
+static int ufs_readlink(struct vnode *, struct uio *, struct cred *,
+ caller_context_t *);
+static int ufs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
+static void ufs_inactive(struct vnode *, struct cred *, caller_context_t *);
+static int ufs_fid(struct vnode *, struct fid *, caller_context_t *);
static int ufs_rwlock(struct vnode *, int, caller_context_t *);
static void ufs_rwunlock(struct vnode *, int, caller_context_t *);
-static int ufs_seek(struct vnode *, offset_t, offset_t *);
+static int ufs_seek(struct vnode *, offset_t, offset_t *, caller_context_t *);
static int ufs_frlock(struct vnode *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, struct cred *);
+ struct flk_callback *, struct cred *,
+ caller_context_t *);
static int ufs_space(struct vnode *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
static int ufs_getpage(struct vnode *, offset_t, size_t, uint_t *,
struct page **, size_t, struct seg *, caddr_t,
- enum seg_rw, struct cred *);
-static int ufs_putpage(struct vnode *, offset_t, size_t, int, struct cred *);
+ enum seg_rw, struct cred *, caller_context_t *);
+static int ufs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
+ caller_context_t *);
static int ufs_putpages(struct vnode *, offset_t, size_t, int, struct cred *);
static int ufs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int ufs_addmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uchar_t, uchar_t, uint_t, struct cred *);
+ uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
static int ufs_delmap(struct vnode *, offset_t, struct as *, caddr_t, size_t,
- uint_t, uint_t, uint_t, struct cred *);
-static int ufs_poll(vnode_t *, short, int, short *, struct pollhead **);
-static int ufs_dump(vnode_t *, caddr_t, int, int);
-static int ufs_l_pathconf(struct vnode *, int, ulong_t *, struct cred *);
+ uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
+static int ufs_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+static int ufs_dump(vnode_t *, caddr_t, int, int, caller_context_t *);
+static int ufs_l_pathconf(struct vnode *, int, ulong_t *, struct cred *,
+ caller_context_t *);
static int ufs_pageio(struct vnode *, struct page *, u_offset_t, size_t, int,
- struct cred *);
-static int ufs_dump(vnode_t *, caddr_t, int, int);
-static int ufs_dumpctl(vnode_t *, int, int *);
+ struct cred *, caller_context_t *);
+static int ufs_dumpctl(vnode_t *, int, int *, caller_context_t *);
static daddr32_t *save_dblks(struct inode *, struct ufsvfs *, daddr32_t *,
- daddr32_t *, int, int);
-static int ufs_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
-static int ufs_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *);
+ daddr32_t *, int, int);
+static int ufs_getsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
+static int ufs_setsecattr(struct vnode *, vsecattr_t *, int, struct cred *,
+ caller_context_t *);
extern int as_map_locked(struct as *, caddr_t, size_t, int ((*)()), void *);
@@ -246,7 +262,7 @@ static struct dump *dump_info = NULL;
/* ARGSUSED */
static int
-ufs_open(struct vnode **vpp, int flag, struct cred *cr)
+ufs_open(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *ct)
{
return (0);
}
@@ -254,7 +270,7 @@ ufs_open(struct vnode **vpp, int flag, struct cred *cr)
/*ARGSUSED*/
static int
ufs_close(struct vnode *vp, int flag, int count, offset_t offset,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
cleanshares(vp, ttoproc(curthread)->p_pid);
@@ -966,7 +982,7 @@ wrip(struct inode *ip, struct uio *uio, int ioflag, struct cred *cr)
* 2) uiomove() causes a page fault.
*
* We have to drop the contents lock to prevent the VM
- * system from trying to reaquire it in ufs_getpage()
+ * system from trying to reacquire it in ufs_getpage()
* should the uiomove cause a pagefault.
*
* We have to drop the reader vfs_dqrwlock here as well.
@@ -1521,7 +1537,8 @@ ufs_ioctl(
intptr_t arg,
int flag,
struct cred *cr,
- int *rvalp)
+ int *rvalp,
+ caller_context_t *ct)
{
struct lockfs lockfs, lockfs_out;
struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs;
@@ -1916,7 +1933,7 @@ ufs_ioctl(
/* ARGSUSED */
static int
ufs_getattr(struct vnode *vp, struct vattr *vap, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp;
@@ -2042,10 +2059,8 @@ ufs_setattr(
/*
* Cannot set these attributes.
*/
- if (mask & AT_NOSET) {
- error = EINVAL;
- goto out;
- }
+ if ((mask & AT_NOSET) || (mask & AT_XVATTR))
+ return (EINVAL);
/*
* check for forced unmount
@@ -2349,7 +2364,8 @@ out:
/*ARGSUSED*/
static int
-ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
+ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
int error;
@@ -2379,7 +2395,8 @@ ufs_access(struct vnode *vp, int mode, int flags, struct cred *cr)
/* ARGSUSED */
static int
-ufs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cr)
+ufs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp;
@@ -2505,7 +2522,7 @@ again:
(void) VOP_PUTPAGE(ITOV(ip),
(offset_t)0, PAGESIZE,
(B_DONTNEED | B_FREE | B_FORCE | B_ASYNC),
- cr);
+ cr, ct);
} else {
int i;
/* error, clear garbage left behind */
@@ -2534,7 +2551,8 @@ nolockout:
/* ARGSUSED */
static int
-ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr)
+ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
@@ -2552,7 +2570,7 @@ ufs_fsync(struct vnode *vp, int syncflag, struct cred *cr)
if (vn_has_cached_data(vp) && !(syncflag & FNODSYNC) &&
(vp->v_type != VCHR) && !(IS_SWAPVP(vp))) {
error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
- 0, CRED());
+ 0, CRED(), ct);
if (error)
goto out;
}
@@ -2627,7 +2645,7 @@ out:
/*ARGSUSED*/
static void
-ufs_inactive(struct vnode *vp, struct cred *cr)
+ufs_inactive(struct vnode *vp, struct cred *cr, caller_context_t *ct)
{
ufs_iinactive(VTOI(vp));
}
@@ -2639,7 +2657,8 @@ int ufs_lookup_idle_count = 2; /* Number of inodes to idle each time */
/* ARGSUSED */
static int
ufs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
- struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cr)
+ struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cr,
+ caller_context_t *ct, int *direntflags, pathname_t *realpnp)
{
struct inode *ip;
struct inode *sip;
@@ -2658,6 +2677,12 @@ ufs_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
if (flags & LOOKUP_XATTR) {
/*
+ * If not mounted with XATTR support then return EINVAL
+ */
+
+ if (!(ip->i_ufsvfs->vfs_vfs->vfs_flag & VFS_XATTR))
+ return (EINVAL);
+ /*
* We don't allow recursive attributes...
* Maybe someday we will.
*/
@@ -2796,9 +2821,11 @@ out:
return (error);
}
+/*ARGSUSED*/
static int
ufs_create(struct vnode *dvp, char *name, struct vattr *vap, enum vcexcl excl,
- int mode, struct vnode **vpp, struct cred *cr, int flag)
+ int mode, struct vnode **vpp, struct cred *cr, int flag,
+ caller_context_t *ct, vsecattr_t *vsecp)
{
struct inode *ip;
struct inode *xip;
@@ -2988,7 +3015,7 @@ again:
}
if (error == 0) {
- vnevent_create(ITOV(ip));
+ vnevent_create(ITOV(ip), ct);
}
}
}
@@ -3082,7 +3109,8 @@ out:
extern int ufs_idle_max;
/*ARGSUSED*/
static int
-ufs_remove(struct vnode *vp, char *nm, struct cred *cr)
+ufs_remove(struct vnode *vp, char *nm, struct cred *cr,
+ caller_context_t *ct, int flags)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
@@ -3135,7 +3163,7 @@ retry_remove:
if (rmvp != NULL) {
/* Only send the event if there were no errors */
if (error == 0)
- vnevent_remove(rmvp, vp, nm);
+ vnevent_remove(rmvp, vp, nm, ct);
VN_RELE(rmvp);
}
out:
@@ -3146,8 +3174,10 @@ out:
* Link a file or a directory. Only privileged processes are allowed to
* make links to directories.
*/
+/*ARGSUSED*/
static int
-ufs_link(struct vnode *tdvp, struct vnode *svp, char *tnm, struct cred *cr)
+ufs_link(struct vnode *tdvp, struct vnode *svp, char *tnm, struct cred *cr,
+ caller_context_t *ct, int flags)
{
struct inode *sip;
struct inode *tdp = VTOI(tdvp);
@@ -3169,7 +3199,7 @@ retry_link:
TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_LINK,
trans_size = (int)TOP_LINK_SIZE(VTOI(tdvp)));
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
/*
@@ -3216,7 +3246,7 @@ unlock:
}
if (!error) {
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
out:
return (error);
@@ -3247,7 +3277,9 @@ ufs_rename(
char *snm, /* old (source) entry name */
struct vnode *tdvp, /* new (target) parent vnode */
char *tnm, /* new (target) entry name */
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct,
+ int flags)
{
struct inode *sip = NULL; /* source inode */
struct inode *ip = NULL; /* check inode */
@@ -3278,7 +3310,7 @@ retry_rename:
TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_RENAME,
trans_size = (int)TOP_RENAME_SIZE(sdp));
- if (VOP_REALVP(tdvp, &realvp) == 0)
+ if (VOP_REALVP(tdvp, &realvp, ct) == 0)
tdvp = realvp;
tdp = VTOI(tdvp);
@@ -3598,14 +3630,14 @@ unlock:
*/
if (error == 0) {
if (tvp != NULL)
- vnevent_rename_dest(tvp, tdvp, tnm);
+ vnevent_rename_dest(tvp, tdvp, tnm, ct);
/*
* Notify the target directory of the rename event
* if source and target directories are not same.
*/
if (sdvp != tdvp)
- vnevent_rename_dest_dir(tdvp);
+ vnevent_rename_dest_dir(tdvp, ct);
/*
* Note that if ufs_direnter_lr() returned ESAME then
@@ -3613,7 +3645,7 @@ unlock:
* to be a problem for anticipated usage by consumers.
*/
if (sip != NULL)
- vnevent_rename_src(ITOV(sip), sdvp, snm);
+ vnevent_rename_src(ITOV(sip), sdvp, snm, ct);
}
if (tvp != NULL)
@@ -3629,7 +3661,8 @@ out:
/*ARGSUSED*/
static int
ufs_mkdir(struct vnode *dvp, char *dirname, struct vattr *vap,
- struct vnode **vpp, struct cred *cr)
+ struct vnode **vpp, struct cred *cr, caller_context_t *ct, int flags,
+ vsecattr_t *vsecp)
{
struct inode *ip;
struct inode *xip;
@@ -3705,7 +3738,8 @@ out:
/*ARGSUSED*/
static int
-ufs_rmdir(struct vnode *vp, char *nm, struct vnode *cdir, struct cred *cr)
+ufs_rmdir(struct vnode *vp, char *nm, struct vnode *cdir, struct cred *cr,
+ caller_context_t *ct, int flags)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
@@ -3759,7 +3793,7 @@ retry_rmdir:
if (rmvp != NULL) {
/* Only send the event if there were no errors */
if (error == 0)
- vnevent_rmdir(rmvp, vp, nm);
+ vnevent_rmdir(rmvp, vp, nm, ct);
VN_RELE(rmvp);
}
out:
@@ -3772,7 +3806,9 @@ ufs_readdir(
struct vnode *vp,
struct uio *uiop,
struct cred *cr,
- int *eofp)
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
struct iovec *iovp;
struct inode *ip;
@@ -3980,7 +4016,9 @@ ufs_symlink(
char *linkname, /* name of symbolic link */
struct vattr *vap, /* attributes */
char *target, /* target path */
- struct cred *cr) /* user credentials */
+ struct cred *cr, /* user credentials */
+ caller_context_t *ct,
+ int flags)
{
struct inode *ip, *dip = VTOI(dvp);
struct ufsvfs *ufsvfsp = dip->i_ufsvfs;
@@ -4203,10 +4241,9 @@ ufs_rdwri(enum uio_rw rw, int ioflag, struct inode *ip, caddr_t base,
return (error);
}
+/*ARGSUSED*/
static int
-ufs_fid(vp, fidp)
- struct vnode *vp;
- struct fid *fidp;
+ufs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
{
struct ufid *ufid;
struct inode *ip = VTOI(vp);
@@ -4297,7 +4334,8 @@ ufs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
/* ARGSUSED */
static int
-ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
+ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
}
@@ -4305,7 +4343,8 @@ ufs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
/* ARGSUSED */
static int
ufs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
- offset_t offset, struct flk_callback *flk_cbp, struct cred *cr)
+ offset_t offset, struct flk_callback *flk_cbp, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
@@ -4321,7 +4360,7 @@ ufs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
*/
if (ip->i_mapcnt > 0 && MANDLOCK(vp, ip->i_mode))
return (EAGAIN);
- return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
+ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
}
/* ARGSUSED */
@@ -4383,10 +4422,11 @@ ufs_space(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
* the time this thread tests the i_nextrio value and then reads it
* again to use it as the offset for the read ahead.
*/
+/*ARGSUSED*/
static int
ufs_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
page_t *plarr[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, struct cred *cr)
+ enum seg_rw rw, struct cred *cr, caller_context_t *ct)
{
u_offset_t uoff = (u_offset_t)off; /* type conversion */
u_offset_t pgoff;
@@ -4966,7 +5006,7 @@ int ufs_delay = 1;
/*ARGSUSED*/
static int
ufs_putpage(struct vnode *vp, offset_t off, size_t len, int flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
int err = 0;
@@ -5435,7 +5475,8 @@ ufs_map(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct segvn_crargs vn_a;
struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs;
@@ -5538,7 +5579,8 @@ ufs_addmap(struct vnode *vp,
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- struct cred *cr)
+ struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
@@ -5556,7 +5598,7 @@ ufs_addmap(struct vnode *vp,
static int
ufs_delmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
@@ -5577,7 +5619,8 @@ struct pollhead ufs_pollhd;
/* ARGSUSED */
int
-ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp)
+ufs_poll(vnode_t *vp, short ev, int any, short *revp, struct pollhead **phpp,
+ caller_context_t *ct)
{
struct ufsvfs *ufsvfsp;
@@ -5622,7 +5665,8 @@ out:
/* ARGSUSED */
static int
-ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
+ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr,
+ caller_context_t *ct)
{
struct ufsvfs *ufsvfsp = VTOI(vp)->i_ufsvfs;
struct ulockfs *ulp = NULL;
@@ -5694,7 +5738,7 @@ ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
error = 0;
}
} else {
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
break;
@@ -5706,8 +5750,14 @@ ufs_l_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr)
*valp = (ulong_t)ip->i_fs->fs_bsize;
break;
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_type == VREG || vp->v_type == VDIR);
+ break;
+
default:
- error = fs_pathconf(vp, cmd, valp, cr);
+ error = fs_pathconf(vp, cmd, valp, cr, ct);
}
if (ulp != NULL) {
@@ -5721,7 +5771,7 @@ int ufs_pageio_writes, ufs_pageio_reads;
/*ARGSUSED*/
static int
ufs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
- int flags, struct cred *cr)
+ int flags, struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ufsvfs *ufsvfsp;
@@ -5940,8 +5990,9 @@ ufs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
* directly to the device. It uses a private dump data structure,
* set up by dump_ctl, to locate the correct disk block to which to dump.
*/
+/*ARGSUSED*/
static int
-ufs_dump(vnode_t *vp, caddr_t addr, int ldbn, int dblks)
+ufs_dump(vnode_t *vp, caddr_t addr, int ldbn, int dblks, caller_context_t *ct)
{
u_offset_t file_size;
struct inode *ip = VTOI(vp);
@@ -6019,8 +6070,9 @@ ufs_dump(vnode_t *vp, caddr_t addr, int ldbn, int dblks)
* if found, the starting file-relative DEV_BSIZE lbn is written
* to *bklp; that lbn is intended for use with VOP_DUMP()
*/
+/*ARGSUSED*/
static int
-ufs_dumpctl(vnode_t *vp, int action, int *blkp)
+ufs_dumpctl(vnode_t *vp, int action, int *blkp, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
ufsvfs_t *ufsvfsp = ip->i_ufsvfs;
@@ -6199,7 +6251,7 @@ save_dblks(struct inode *ip, struct ufsvfs *ufsvfsp, daddr32_t *storeblk,
/* ARGSUSED */
static int
ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ulockfs *ulp;
@@ -6230,7 +6282,8 @@ ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,
/* ARGSUSED */
static int
-ufs_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr)
+ufs_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr,
+ caller_context_t *ct)
{
struct inode *ip = VTOI(vp);
struct ulockfs *ulp = NULL;
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c
index a1b7059e9b..3b0f7afec0 100644
--- a/usr/src/uts/common/fs/vfs.c
+++ b/usr/src/uts/common/fs/vfs.c
@@ -83,6 +83,7 @@
#include <sys/objfs.h>
#include <sys/console.h>
#include <sys/reboot.h>
+#include <sys/attr.h>
#include <vm/page.h>
@@ -120,6 +121,8 @@ static kmutex_t vfs_miplist_mutex;
static struct ipmnt *vfs_miplist = NULL;
static struct ipmnt *vfs_miplist_end = NULL;
+static kmem_cache_t *vfs_cache; /* Pointer to VFS kmem cache */
+
/*
* VFS global data.
*/
@@ -257,6 +260,21 @@ fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
int
fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
{
+ /*
+ * In order to handle system attribute fids in a manner
+ * transparent to the underlying fs, we embed the fid for
+ * the sysattr parent object in the sysattr fid and tack on
+ * some extra bytes that only the sysattr layer knows about.
+ *
+ * This guarantees that sysattr fids are larger than other fids
+ * for this vfs. If the vfs supports sysattrs (implied
+ * by VFSFT_XVATTR support), we cannot have a size collision
+ * with XATTR_FIDSZ.
+ */
+ if (vfs_has_feature(vfsp, VFSFT_XVATTR) &&
+ fidp->fid_len == XATTR_FIDSZ)
+ return (xattr_dir_vget(vfsp, vpp, fidp));
+
return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
}
@@ -442,7 +460,7 @@ vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
op = vfsp->vfs_op;
membar_consumer();
- if ((vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) &&
+ if (vfsp->vfs_femhead == NULL &&
casptr(&vfsp->vfs_op, op, vfsops) == op) {
return;
}
@@ -459,8 +477,7 @@ vfs_getops(vfs_t *vfsp)
op = vfsp->vfs_op;
membar_consumer();
- if ((vfsp->vfs_implp == NULL || vfsp->vfs_femhead == NULL) &&
- op == vfsp->vfs_op) {
+ if (vfsp->vfs_femhead == NULL && op == vfsp->vfs_op) {
return (op);
} else {
return (fsem_getvfsops(vfsp));
@@ -494,25 +511,16 @@ vfs_can_sync(vfs_t *vfsp)
void
vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
{
+ /* Other initialization has been moved to vfs_alloc() */
vfsp->vfs_count = 0;
vfsp->vfs_next = vfsp;
vfsp->vfs_prev = vfsp;
vfsp->vfs_zone_next = vfsp;
vfsp->vfs_zone_prev = vfsp;
- vfsp->vfs_flag = 0;
+ sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
+ vfsimpl_setup(vfsp);
vfsp->vfs_data = (data);
- vfsp->vfs_resource = NULL;
- vfsp->vfs_mntpt = NULL;
- vfsp->vfs_mntopts.mo_count = 0;
- vfsp->vfs_mntopts.mo_list = NULL;
- vfsp->vfs_implp = NULL;
- vfsp->vfs_zone = NULL;
- /*
- * Note: Don't initialize any member of the vfs_impl_t structure
- * here as it could be a problem for unbundled file systems.
- */
vfs_setops((vfsp), (op));
- sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
}
/*
@@ -522,11 +530,22 @@ vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
void
vfsimpl_setup(vfs_t *vfsp)
{
+ int i;
+
+ if (vfsp->vfs_implp != NULL) {
+ return;
+ }
+
vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
- /* Note that this are #define'd in vfs.h */
- vfsp->vfs_femhead = NULL;
+ /* Note that these are #define'd in vfs.h */
vfsp->vfs_vskap = NULL;
vfsp->vfs_fstypevsp = NULL;
+
+ /* Set size of counted array, then zero the array */
+ vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
+ for (i = 1; i < VFS_FEATURE_MAXSZ; i++) {
+ vfsp->vfs_featureset[i] = 0;
+ }
}
/*
@@ -542,13 +561,6 @@ vfsimpl_teardown(vfs_t *vfsp)
if (vip == NULL)
return;
- if (vip->vi_femhead) {
- ASSERT(vip->vi_femhead->femh_list == NULL);
- mutex_destroy(&vip->vi_femhead->femh_lock);
- kmem_free(vip->vi_femhead, sizeof (*(vip->vi_femhead)));
- vip->vi_femhead = NULL;
- }
-
kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
vfsp->vfs_implp = NULL;
}
@@ -1308,22 +1320,21 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
goto errout;
}
/*
- * Changing the NBMAND setting on remounts is permitted
- * but logged since it can lead to unexpected behavior.
- * We also counsel against using it for / and /usr.
+ * Disallow changing the NBMAND disposition of the file
+ * system on remounts.
*/
if ((nbmand && ((vp->v_vfsp->vfs_flag & VFS_NBMAND) == 0)) ||
(!nbmand && (vp->v_vfsp->vfs_flag & VFS_NBMAND))) {
- cmn_err(CE_WARN, "domount: nbmand turned %s via "
- "remounting %s", nbmand ? "on" : "off",
- refstr_value(vp->v_vfsp->vfs_mntpt));
+ vn_vfsunlock(vp);
+ error = EINVAL;
+ goto errout;
}
vfsp = vp->v_vfsp;
ovflags = vfsp->vfs_flag;
vfsp->vfs_flag |= VFS_REMOUNT;
vfsp->vfs_flag &= ~VFS_RDONLY;
} else {
- vfsp = kmem_alloc(sizeof (vfs_t), KM_SLEEP);
+ vfsp = vfs_alloc(KM_SLEEP);
VFS_INIT(vfsp, vfsops, NULL);
}
@@ -1350,9 +1361,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
vfsp->vfs_flag = ovflags;
if (splice)
vn_vfsunlock(vp);
- if (vfsp->vfs_implp)
- vfsimpl_teardown(vfsp);
- kmem_free(vfsp, sizeof (struct vfs));
+ vfs_free(vfsp);
goto errout;
}
} else {
@@ -1444,7 +1453,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
/*
* going to mount on this vnode, so notify.
*/
- vnevent_mountedover(vp);
+ vnevent_mountedover(vp, NULL);
error = VFS_MOUNT(vfsp, vp, uap, credp);
if (uap->flags & MS_RDONLY)
@@ -1472,9 +1481,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
} else {
vfs_unlock(vfsp);
vfs_freemnttab(vfsp);
- if (vfsp->vfs_implp)
- vfsimpl_teardown(vfsp);
- kmem_free(vfsp, sizeof (struct vfs));
+ vfs_free(vfsp);
}
} else {
/*
@@ -2597,7 +2604,8 @@ vfs_mntdummywrite(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred,
*/
/* ARGSUSED */
static int
-vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
bzero(vap, sizeof (vattr_t));
vap->va_type = VREG;
@@ -3996,12 +4004,14 @@ vfsinit(void)
NULL, NULL
};
- /* Initialize the vnode cache (file systems may use it during init). */
+ /* Create vfs cache */
+ vfs_cache = kmem_cache_create("vfs_cache", sizeof (struct vfs),
+ sizeof (uintptr_t), NULL, NULL, NULL, NULL, NULL, 0);
+ /* Initialize the vnode cache (file systems may use it during init). */
vn_create_cache();
/* Setup event monitor framework */
-
fem_init();
/* Initialize the dummy stray file system type. */
@@ -4044,6 +4054,52 @@ vfsinit(void)
EIO_vfs.vfs_vskap = NULL;
EIO_vfs.vfs_flag |= VFS_STATS;
}
+
+ xattr_init();
+}
+
+vfs_t *
+vfs_alloc(int kmflag)
+{
+ vfs_t *vfsp;
+
+ vfsp = kmem_cache_alloc(vfs_cache, kmflag);
+
+ /*
+ * Do the simplest initialization here.
+ * Everything else gets done in vfs_init()
+ */
+ bzero(vfsp, sizeof (vfs_t));
+ return (vfsp);
+}
+
+void
+vfs_free(vfs_t *vfsp)
+{
+ /*
+ * One would be tempted to assert that "vfsp->vfs_count == 0".
+ * The problem is that this gets called out of domount() with
+ * a partially initialized vfs and a vfs_count of 1. This is
+ * also called from vfs_rele() with a vfs_count of 0. We can't
+ * call VFS_RELE() from domount() if VFS_MOUNT() hasn't successfully
+ * returned. This is because VFS_MOUNT() fully initializes the
+ * vfs structure and its associated data. VFS_RELE() will call
+ * VFS_FREEVFS() which may panic the system if the data structures
+ * aren't fully initialized from a successful VFS_MOUNT()).
+ */
+
+ /* If FEM was in use, make sure everything gets cleaned up */
+ if (vfsp->vfs_femhead) {
+ ASSERT(vfsp->vfs_femhead->femh_list == NULL);
+ mutex_destroy(&vfsp->vfs_femhead->femh_lock);
+ kmem_free(vfsp->vfs_femhead, sizeof (*(vfsp->vfs_femhead)));
+ vfsp->vfs_femhead = NULL;
+ }
+
+ if (vfsp->vfs_implp)
+ vfsimpl_teardown(vfsp);
+ sema_destroy(&vfsp->vfs_reflock);
+ kmem_cache_free(vfs_cache, vfsp);
}
/*
@@ -4070,10 +4126,7 @@ vfs_rele(vfs_t *vfsp)
if (vfsp->vfs_zone)
zone_rele(vfsp->vfs_zone);
vfs_freemnttab(vfsp);
- if (vfsp->vfs_implp)
- vfsimpl_teardown(vfsp);
- sema_destroy(&vfsp->vfs_reflock);
- kmem_free(vfsp, sizeof (*vfsp));
+ vfs_free(vfsp);
}
}
@@ -4346,3 +4399,40 @@ getrootfs(char **fstypp, char **fsmodp)
*fsmodp = "nfs";
}
#endif
+
+/*
+ * VFS feature routines
+ */
+
+#define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF)
+#define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL)
+
+/* Register a feature in the vfs */
+void
+vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return;
+
+ vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
+}
+
+/*
+ * Query a vfs for a feature.
+ * Returns 1 if feature is present, 0 if not
+ */
+int
+vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+ int ret = 0;
+
+ /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+ if (vfsp->vfs_implp == NULL)
+ return (ret);
+
+ if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
+ ret = 1;
+
+ return (ret);
+}
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c
index 2e0364a2d4..5431d1ed09 100644
--- a/usr/src/uts/common/fs/vnode.c
+++ b/usr/src/uts/common/fs/vnode.c
@@ -361,6 +361,36 @@ static const fs_operation_trans_def_t vn_ops_table[] = {
NULL, 0, NULL, NULL
};
+/* Extensible attribute (xva) routines. */
+
+/*
+ * Zero out the structure, set the size of the requested/returned bitmaps,
+ * set AT_XVATTR in the embedded vattr_t's va_mask, and set up the pointer
+ * to the returned attributes array.
+ */
+void
+xva_init(xvattr_t *xvap)
+{
+ bzero(xvap, sizeof (xvattr_t));
+ xvap->xva_mapsize = XVA_MAPSIZE;
+ xvap->xva_magic = XVA_MAGIC;
+ xvap->xva_vattr.va_mask = AT_XVATTR;
+ xvap->xva_rtnattrmapp = &(xvap->xva_rtnattrmap)[0];
+}
+
+/*
+ * If AT_XVATTR is set, returns a pointer to the embedded xoptattr_t
+ * structure. Otherwise, returns NULL.
+ */
+xoptattr_t *
+xva_getxoptattr(xvattr_t *xvap)
+{
+ xoptattr_t *xoap = NULL;
+ if (xvap->xva_vattr.va_mask & AT_XVATTR)
+ xoap = &xvap->xva_xoptattrs;
+ return (xoap);
+}
+
/*
* Used by the AVL routines to compare two vsk_anchor_t structures in the tree.
* We use the f_fsid reported by VFS_STATVFS() since we use that for the
@@ -740,7 +770,7 @@ vn_rdwr(
if (error != 0)
goto done;
if (nbl_conflict(vp, rw == UIO_WRITE ? NBL_WRITE : NBL_READ,
- uio.uio_offset, uio.uio_resid, svmand)) {
+ uio.uio_offset, uio.uio_resid, svmand, NULL)) {
error = EACCES;
goto done;
}
@@ -757,8 +787,8 @@ vn_rdwr(
uio.uio_extflg = UIO_COPY_CACHED;
error = VOP_READ(vp, &uio, ioflag, cr, NULL);
}
- VOP_RWUNLOCK(vp, rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE,
- NULL);
+ VOP_RWUNLOCK(vp,
+ rw == UIO_WRITE ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE, NULL);
if (residp)
*residp = uio.uio_resid;
else if (uio.uio_resid)
@@ -789,7 +819,7 @@ vn_rele(vnode_t *vp)
mutex_enter(&vp->v_lock);
if (vp->v_count == 1) {
mutex_exit(&vp->v_lock);
- VOP_INACTIVE(vp, CRED());
+ VOP_INACTIVE(vp, CRED(), NULL);
} else {
vp->v_count--;
mutex_exit(&vp->v_lock);
@@ -812,7 +842,7 @@ vn_rele_stream(vnode_t *vp)
vp->v_stream = NULL;
if (vp->v_count == 1) {
mutex_exit(&vp->v_lock);
- VOP_INACTIVE(vp, CRED());
+ VOP_INACTIVE(vp, CRED(), NULL);
} else {
vp->v_count--;
mutex_exit(&vp->v_lock);
@@ -829,8 +859,8 @@ vn_open(
enum create crwhy,
mode_t umask)
{
- return (vn_openat(pnamep, seg, filemode,
- createmode, vpp, crwhy, umask, NULL));
+ return (vn_openat(pnamep, seg, filemode, createmode, vpp, crwhy,
+ umask, NULL, -1));
}
@@ -849,21 +879,30 @@ vn_openat(
struct vnode **vpp,
enum create crwhy,
mode_t umask,
- struct vnode *startvp)
+ struct vnode *startvp,
+ int fd)
{
struct vnode *vp;
int mode;
+ int accessflags;
int error;
int in_crit = 0;
+ int open_done = 0;
+ int shrlock_done = 0;
struct vattr vattr;
enum symfollow follow;
int estale_retry = 0;
+ struct shrlock shr;
+ struct shr_locowner shr_own;
mode = 0;
+ accessflags = 0;
if (filemode & FREAD)
mode |= VREAD;
if (filemode & (FWRITE|FTRUNC))
mode |= VWRITE;
+ if (filemode & FXATTRDIROPEN)
+ mode |= VEXEC;
/* symlink interpretation */
if (filemode & FNOFOLLOW)
@@ -871,6 +910,9 @@ vn_openat(
else
follow = FOLLOW;
+ if (filemode & FAPPEND)
+ accessflags |= V_APPEND;
+
top:
if (filemode & FCREAT) {
enum vcexcl excl;
@@ -914,7 +956,8 @@ top:
if (!(filemode & FOFFMAX) && (vp->v_type == VREG)) {
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if ((error = VOP_GETATTR(vp, &vattr, 0,
+ CRED(), NULL))) {
goto out;
}
if (vattr.va_size > (u_offset_t)MAXOFF32_T) {
@@ -944,36 +987,19 @@ top:
goto out;
}
/*
- * Can't truncate files on which mandatory locking
- * or non-blocking mandatory locking is in effect.
+ * Can't truncate files on which
+ * sysv mandatory locking is in effect.
*/
if (filemode & FTRUNC) {
vnode_t *rvp;
- if (VOP_REALVP(vp, &rvp) != 0)
+ if (VOP_REALVP(vp, &rvp, NULL) != 0)
rvp = vp;
- if (nbl_need_check(vp)) {
- nbl_start_crit(vp, RW_READER);
- in_crit = 1;
- vattr.va_mask = AT_MODE|AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0,
- CRED())) == 0) {
- if (rvp->v_filocks != NULL)
- if (MANDLOCK(vp,
- vattr.va_mode))
- error = EAGAIN;
- if (!error) {
- if (nbl_conflict(vp,
- NBL_WRITE, 0,
- vattr.va_size, 0))
- error = EACCES;
- }
- }
- } else if (rvp->v_filocks != NULL) {
+ if (rvp->v_filocks != NULL) {
vattr.va_mask = AT_MODE;
- if ((error = VOP_GETATTR(vp, &vattr,
- 0, CRED())) == 0 && MANDLOCK(vp,
- vattr.va_mode))
+ if ((error = VOP_GETATTR(vp,
+ &vattr, 0, CRED(), NULL)) == 0 &&
+ MANDLOCK(vp, vattr.va_mode))
error = EAGAIN;
}
}
@@ -983,7 +1009,7 @@ top:
/*
* Check permissions.
*/
- if (error = VOP_ACCESS(vp, mode, 0, CRED()))
+ if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
goto out;
}
@@ -996,7 +1022,7 @@ top:
}
if (filemode & FNOLINKS) {
vattr.va_mask = AT_NLINK;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
goto out;
}
if (vattr.va_nlink != 1) {
@@ -1020,25 +1046,66 @@ top:
if (vp->v_type == VSOCK) {
struct vnode *nvp;
- error = VOP_REALVP(vp, &nvp);
+ error = VOP_REALVP(vp, &nvp, NULL);
if (error != 0 || nvp == NULL || nvp == vp ||
nvp->v_type != VSOCK) {
error = EOPNOTSUPP;
goto out;
}
}
+
+ if ((vp->v_type == VREG) && nbl_need_check(vp)) {
+ /* get share reservation */
+ shr.s_access = 0;
+ if (filemode & FWRITE)
+ shr.s_access |= F_WRACC;
+ if (filemode & FREAD)
+ shr.s_access |= F_RDACC;
+ shr.s_deny = 0;
+ shr.s_sysid = 0;
+ shr.s_pid = ttoproc(curthread)->p_pid;
+ shr_own.sl_pid = shr.s_pid;
+ shr_own.sl_id = fd;
+ shr.s_own_len = sizeof (shr_own);
+ shr.s_owner = (caddr_t)&shr_own;
+ error = VOP_SHRLOCK(vp, F_SHARE_NBMAND, &shr, filemode, CRED(),
+ NULL);
+ if (error)
+ goto out;
+ shrlock_done = 1;
+
+ /* nbmand conflict check if truncating file */
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+
+ vattr.va_mask = AT_SIZE;
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ goto out;
+ if (nbl_conflict(vp, NBL_WRITE, 0, vattr.va_size, 0,
+ NULL)) {
+ error = EACCES;
+ goto out;
+ }
+ }
+ }
+
/*
* Do opening protocol.
*/
- error = VOP_OPEN(&vp, filemode, CRED());
+ error = VOP_OPEN(&vp, filemode, CRED(), NULL);
+ if (error)
+ goto out;
+ open_done = 1;
+
/*
* Truncate if required.
*/
- if (error == 0 && (filemode & FTRUNC) && !(filemode & FCREAT)) {
+ if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
vattr.va_size = 0;
vattr.va_mask = AT_SIZE;
if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
- (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED());
+ goto out;
}
out:
ASSERT(vp->v_count > 0);
@@ -1048,6 +1115,18 @@ out:
in_crit = 0;
}
if (error) {
+ if (open_done) {
+ (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
+ NULL);
+ open_done = 0;
+ shrlock_done = 0;
+ }
+ if (shrlock_done) {
+ (void) VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, CRED(),
+ NULL);
+ shrlock_done = 0;
+ }
+
/*
* The following clause was added to handle a problem
* with NFS consistency. It is possible that a lookup
@@ -1068,6 +1147,49 @@ out:
return (error);
}
+/*
+ * The following two accessor functions are for the NFSv4 server. Since there
+ * is no VOP_OPEN_UP/DOWNGRADE we need a way for the NFS server to keep the
+ * vnode open counts correct when a client "upgrades" an open or does an
+ * open_downgrade. In NFS, an upgrade or downgrade can not only change the
+ * open mode (add or subtract read or write), but also change the share/deny
+ * modes. However, share reservations are not integrated with OPEN, yet, so
+ * we need to handle each separately. These functions are cleaner than having
+ * the NFS server manipulate the counts directly, however, nobody else should
+ * use these functions.
+ */
+void
+vn_open_upgrade(
+ vnode_t *vp,
+ int filemode)
+{
+ ASSERT(vp->v_type == VREG);
+
+ if (filemode & FREAD)
+ atomic_add_32(&(vp->v_rdcnt), 1);
+ if (filemode & FWRITE)
+ atomic_add_32(&(vp->v_wrcnt), 1);
+
+}
+
+void
+vn_open_downgrade(
+ vnode_t *vp,
+ int filemode)
+{
+ ASSERT(vp->v_type == VREG);
+
+ if (filemode & FREAD) {
+ ASSERT(vp->v_rdcnt > 0);
+ atomic_add_32(&(vp->v_rdcnt), -1);
+ }
+ if (filemode & FWRITE) {
+ ASSERT(vp->v_wrcnt > 0);
+ atomic_add_32(&(vp->v_wrcnt), -1);
+ }
+
+}
+
int
vn_create(
char *pnamep,
@@ -1080,8 +1202,8 @@ vn_create(
int flag,
mode_t umask)
{
- return (vn_createat(pnamep, seg, vap, excl, mode, vpp,
- why, flag, umask, NULL));
+ return (vn_createat(pnamep, seg, vap, excl, mode, vpp, why, flag,
+ umask, NULL));
}
/*
@@ -1171,7 +1293,7 @@ top:
vsec.vsa_dfaclcnt = 0;
vsec.vsa_dfaclentp = NULL;
vsec.vsa_mask = VSA_DFACLCNT;
- error = VOP_GETSECATTR(dvp, &vsec, 0, CRED());
+ error = VOP_GETSECATTR(dvp, &vsec, 0, CRED(), NULL);
/*
* If error is ENOSYS then treat it as no error
* Don't want to force all file systems to support
@@ -1230,7 +1352,7 @@ top:
* applied, return error.
*/
vp = *vpp;
- if (VOP_REALVP(vp, &rvp) != 0)
+ if (VOP_REALVP(vp, &rvp, NULL) != 0)
rvp = vp;
if ((vap->va_mask & AT_SIZE) && nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
@@ -1238,7 +1360,7 @@ top:
}
if (rvp->v_filocks != NULL || rvp->v_shrlocks != NULL) {
vattr.va_mask = AT_MODE|AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED())) {
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) {
goto out;
}
if (MANDLOCK(vp, vattr.va_mode)) {
@@ -1259,7 +1381,7 @@ top:
vap->va_size - vattr.va_size :
vattr.va_size - vap->va_size;
if (nbl_conflict(vp, NBL_WRITE, offset,
- length, 0)) {
+ length, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1281,9 +1403,8 @@ top:
*/
if (vp->v_flag & VROOT) {
ASSERT(why != CRMKDIR);
- error =
- VOP_CREATE(vp, "", vap, excl, mode, vpp, CRED(),
- flag);
+ error = VOP_CREATE(vp, "", vap, excl, mode, vpp,
+ CRED(), flag, NULL, NULL);
/*
* If the create succeeded, it will have created
* a new reference to the vnode. Give up the
@@ -1307,7 +1428,8 @@ top:
!(flag & FOFFMAX) &&
(vp->v_type == VREG)) {
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if ((error = VOP_GETATTR(vp, &vattr, 0,
+ CRED(), NULL))) {
goto out;
}
if ((vattr.va_size > (u_offset_t)MAXOFF32_T)) {
@@ -1324,10 +1446,17 @@ top:
int must_be_dir = pn_fixslash(&pn); /* trailing '/'? */
if (why == CRMKDIR)
- error = VOP_MKDIR(dvp, pn.pn_path, vap, vpp, CRED());
+ /*
+ * N.B., if vn_createat() ever requests
+ * case-insensitive behavior then it will need
+ * to be passed to VOP_MKDIR(). VOP_CREATE()
+ * will already get it via "flag"
+ */
+ error = VOP_MKDIR(dvp, pn.pn_path, vap, vpp, CRED(),
+ NULL, 0, NULL);
else if (!must_be_dir)
error = VOP_CREATE(dvp, pn.pn_path, vap,
- excl, mode, vpp, CRED(), flag);
+ excl, mode, vpp, CRED(), flag, NULL, NULL);
else
error = ENOTDIR;
}
@@ -1389,11 +1518,11 @@ top:
* in the same vfs and that it is writeable.
*/
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(fvp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(fvp, &vattr, 0, CRED(), NULL))
goto out;
fsid = vattr.va_fsid;
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(tdvp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(tdvp, &vattr, 0, CRED(), NULL))
goto out;
if (fsid != vattr.va_fsid) {
error = EXDEV;
@@ -1407,7 +1536,7 @@ top:
* Do the link.
*/
(void) pn_fixslash(&pn);
- error = VOP_LINK(tdvp, fvp, pn.pn_path, CRED());
+ error = VOP_LINK(tdvp, fvp, pn.pn_path, CRED(), NULL, 0);
out:
pn_free(&pn);
if (fvp)
@@ -1434,13 +1563,14 @@ vn_renameat(vnode_t *fdvp, char *fname, vnode_t *tdvp,
struct pathname fpn; /* from pathname */
struct pathname tpn; /* to pathname */
dev_t fsid;
- int in_crit = 0;
+ int in_crit_src, in_crit_targ;
vnode_t *fromvp, *fvp;
- vnode_t *tovp;
+ vnode_t *tovp, *targvp;
int estale_retry = 0;
top:
- fvp = fromvp = tovp = NULL;
+ fvp = fromvp = tovp = targvp = NULL;
+ in_crit_src = in_crit_targ = 0;
/*
* Get to and from pathnames.
*/
@@ -1483,7 +1613,7 @@ top:
if (audit_active)
audit_setfsat_path(3);
#endif /* C2_AUDIT */
- if (error = lookuppnat(&tpn, NULL, NO_FOLLOW, &tovp, NULLVPP, tdvp)) {
+ if (error = lookuppnat(&tpn, NULL, NO_FOLLOW, &tovp, &targvp, tdvp)) {
goto out;
}
@@ -1494,11 +1624,11 @@ top:
*/
if (fromvp != tovp) {
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(fromvp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(fromvp, &vattr, 0, CRED(), NULL))
goto out;
fsid = vattr.va_fsid;
vattr.va_mask = AT_FSID;
- if (error = VOP_GETATTR(tovp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(tovp, &vattr, 0, CRED(), NULL))
goto out;
if (fsid != vattr.va_fsid) {
error = EXDEV;
@@ -1511,10 +1641,19 @@ top:
goto out;
}
+ if (targvp && (fvp != targvp)) {
+ nbl_start_crit(targvp, RW_READER);
+ in_crit_targ = 1;
+ if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
+ error = EACCES;
+ goto out;
+ }
+ }
+
if (nbl_need_check(fvp)) {
nbl_start_crit(fvp, RW_READER);
- in_crit = 1;
- if (nbl_conflict(fvp, NBL_RENAME, 0, 0, 0)) {
+ in_crit_src = 1;
+ if (nbl_conflict(fvp, NBL_RENAME, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1524,19 +1663,22 @@ top:
* Do the rename.
*/
(void) pn_fixslash(&tpn);
- error = VOP_RENAME(fromvp, fpn.pn_path, tovp, tpn.pn_path, CRED());
+ error = VOP_RENAME(fromvp, fpn.pn_path, tovp, tpn.pn_path, CRED(),
+ NULL, 0);
out:
pn_free(&fpn);
pn_free(&tpn);
- if (in_crit) {
+ if (in_crit_src)
nbl_end_crit(fvp);
- in_crit = 0;
- }
+ if (in_crit_targ)
+ nbl_end_crit(targvp);
if (fromvp)
VN_RELE(fromvp);
if (tovp)
VN_RELE(tovp);
+ if (targvp)
+ VN_RELE(targvp);
if (fvp)
VN_RELE(fvp);
if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
@@ -1691,7 +1833,7 @@ top:
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0)) {
+ if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
error = EACCES;
goto out;
}
@@ -1715,14 +1857,15 @@ top:
cwd = PTOU(pp)->u_cdir;
VN_HOLD(cwd);
mutex_exit(&pp->p_lock);
- error = VOP_RMDIR(dvp, pn.pn_path, cwd, CRED());
+ error = VOP_RMDIR(dvp, pn.pn_path, cwd, CRED(),
+ NULL, 0);
VN_RELE(cwd);
}
} else {
/*
* Unlink(2) can be applied to anything.
*/
- error = VOP_REMOVE(dvp, pn.pn_path, CRED());
+ error = VOP_REMOVE(dvp, pn.pn_path, CRED(), NULL, 0);
}
out:
@@ -1750,9 +1893,9 @@ vn_compare(vnode_t *vp1, vnode_t *vp2)
{
vnode_t *realvp;
- if (vp1 != NULL && VOP_REALVP(vp1, &realvp) == 0)
+ if (vp1 != NULL && VOP_REALVP(vp1, &realvp, NULL) == 0)
vp1 = realvp;
- if (vp2 != NULL && VOP_REALVP(vp2, &realvp) == 0)
+ if (vp2 != NULL && VOP_REALVP(vp2, &realvp, NULL) == 0)
vp2 = realvp;
return (VN_CMP(vp1, vp2));
}
@@ -2170,6 +2313,7 @@ vn_reinit(vnode_t *vp)
vp->v_msflags = 0;
vp->v_msnext = NULL;
vp->v_msprev = NULL;
+ vp->v_xattrdir = NULL;
/* Handles v_femhead, v_path, and the r/w/map counts */
vn_recycle(vp);
@@ -2194,6 +2338,9 @@ vn_alloc(int kmflag)
void
vn_free(vnode_t *vp)
{
+ ASSERT(vp->v_shrlocks == NULL);
+ ASSERT(vp->v_filocks == NULL);
+
/*
* Some file systems call vn_free() with v_count of zero,
* some with v_count of 1. In any case, the value should
@@ -2275,84 +2422,85 @@ vn_invalid(vnode_t *vp)
/* Vnode event notification */
int
-vnevent_support(vnode_t *vp)
+vnevent_support(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL)
return (EINVAL);
- return (VOP_VNEVENT(vp, VE_SUPPORT, NULL, NULL));
+ return (VOP_VNEVENT(vp, VE_SUPPORT, NULL, NULL, ct));
}
void
-vnevent_rename_src(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_rename_src(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RENAME_SRC, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_RENAME_SRC, dvp, name, ct);
}
void
-vnevent_rename_dest(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_rename_dest(vnode_t *vp, vnode_t *dvp, char *name,
+ caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RENAME_DEST, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_RENAME_DEST, dvp, name, ct);
}
void
-vnevent_rename_dest_dir(vnode_t *vp)
+vnevent_rename_dest_dir(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RENAME_DEST_DIR, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_RENAME_DEST_DIR, NULL, NULL, ct);
}
void
-vnevent_remove(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_remove(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_REMOVE, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_REMOVE, dvp, name, ct);
}
void
-vnevent_rmdir(vnode_t *vp, vnode_t *dvp, char *name)
+vnevent_rmdir(vnode_t *vp, vnode_t *dvp, char *name, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_RMDIR, dvp, name);
+ (void) VOP_VNEVENT(vp, VE_RMDIR, dvp, name, ct);
}
void
-vnevent_create(vnode_t *vp)
+vnevent_create(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_CREATE, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_CREATE, NULL, NULL, ct);
}
void
-vnevent_link(vnode_t *vp)
+vnevent_link(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_LINK, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_LINK, NULL, NULL, ct);
}
void
-vnevent_mountedover(vnode_t *vp)
+vnevent_mountedover(vnode_t *vp, caller_context_t *ct)
{
if (vp == NULL || vp->v_femhead == NULL) {
return;
}
- (void) VOP_VNEVENT(vp, VE_MOUNTEDOVER, NULL, NULL);
+ (void) VOP_VNEVENT(vp, VE_MOUNTEDOVER, NULL, NULL, ct);
}
/*
@@ -2400,7 +2548,7 @@ vn_can_change_zones(vnode_t *vp)
/*
* We always want to look at the underlying vnode if there is one.
*/
- if (VOP_REALVP(vp, &rvp) != 0)
+ if (VOP_REALVP(vp, &rvp, NULL) != 0)
rvp = vp;
/*
* Some pseudo filesystems (including doorfs) don't actually register
@@ -2433,6 +2581,45 @@ vn_mountedvfs(vnode_t *vp)
}
/*
+ * vn_has_other_opens() checks whether a particular file is opened by more than
+ * just the caller and whether the open is for read and/or write.
+ * This routine is for calling after the caller has already called VOP_OPEN()
+ * and the caller wishes to know if they are the only one with it open for
+ * the mode(s) specified.
+ *
+ * Vnode counts are only kept on regular files (v_type=VREG).
+ */
+int
+vn_has_other_opens(
+ vnode_t *vp,
+ v_mode_t mode)
+{
+
+ ASSERT(vp != NULL);
+
+ switch (mode) {
+ case V_WRITE:
+ if (vp->v_wrcnt > 1)
+ return (V_TRUE);
+ break;
+ case V_RDORWR:
+ if ((vp->v_rdcnt > 1) || (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_RDANDWR:
+ if ((vp->v_rdcnt > 1) && (vp->v_wrcnt > 1))
+ return (V_TRUE);
+ break;
+ case V_READ:
+ if (vp->v_rdcnt > 1)
+ return (V_TRUE);
+ break;
+ }
+
+ return (V_FALSE);
+}
+
+/*
* vn_is_opened() checks whether a particular file is opened and
* whether the open is for read and/or write.
*
@@ -2821,7 +3008,8 @@ int
fop_open(
vnode_t **vpp,
int mode,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int ret;
vnode_t *vp = *vpp;
@@ -2848,7 +3036,7 @@ fop_open(
VOPXID_MAP_CR(vp, cr);
- ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr);
+ ret = (*(*(vpp))->v_op->vop_open)(vpp, mode, cr, ct);
if (ret) {
/*
@@ -2892,13 +3080,14 @@ fop_close(
int flag,
int count,
offset_t offset,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr);
+ err = (*(vp)->v_op->vop_close)(vp, flag, count, offset, cr, ct);
VOPSTATS_UPDATE(vp, close);
/*
* Check passed in count to handle possible dups. Vnode counts are only
@@ -2923,7 +3112,7 @@ fop_read(
uio_t *uiop,
int ioflag,
cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int err;
ssize_t resid_start = uiop->uio_resid;
@@ -2942,7 +3131,7 @@ fop_write(
uio_t *uiop,
int ioflag,
cred_t *cr,
- struct caller_context *ct)
+ caller_context_t *ct)
{
int err;
ssize_t resid_start = uiop->uio_resid;
@@ -2962,13 +3151,14 @@ fop_ioctl(
intptr_t arg,
int flag,
cred_t *cr,
- int *rvalp)
+ int *rvalp,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp);
+ err = (*(vp)->v_op->vop_ioctl)(vp, cmd, arg, flag, cr, rvalp, ct);
VOPSTATS_UPDATE(vp, ioctl);
return (err);
}
@@ -2978,13 +3168,14 @@ fop_setfl(
vnode_t *vp,
int oflags,
int nflags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr);
+ err = (*(vp)->v_op->vop_setfl)(vp, oflags, nflags, cr, ct);
VOPSTATS_UPDATE(vp, setfl);
return (err);
}
@@ -2994,13 +3185,30 @@ fop_getattr(
vnode_t *vp,
vattr_t *vap,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr);
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_getattr)(vp, vap, flags, cr, ct);
VOPSTATS_UPDATE(vp, getattr);
return (err);
}
@@ -3017,6 +3225,22 @@ fop_setattr(
VOPXID_MAP_CR(vp, cr);
+ /*
+ * If this file system doesn't understand the xvattr extensions
+ * then turn off the xvattr bit.
+ */
+ if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) {
+ vap->va_mask &= ~AT_XVATTR;
+ }
+
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flags & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
err = (*(vp)->v_op->vop_setattr)(vp, vap, flags, cr, ct);
VOPSTATS_UPDATE(vp, setattr);
return (err);
@@ -3027,13 +3251,19 @@ fop_access(
vnode_t *vp,
int mode,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
+ if ((flags & V_ACE_MASK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr);
+ err = (*(vp)->v_op->vop_access)(vp, mode, flags, cr, ct);
VOPSTATS_UPDATE(vp, access);
return (err);
}
@@ -3046,13 +3276,32 @@ fop_lookup(
pathname_t *pnp,
int flags,
vnode_t *rdir,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int *deflags, /* Returned per-dirent flags */
+ pathname_t *ppnp) /* Returned case-preserved name in directory */
{
int ret;
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly. It is required
+ * that if the vfs supports case-insensitive lookup, it also
+ * supports extended dirent flags.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(dvp, cr);
- ret = (*(dvp)->v_op->vop_lookup)(dvp, nm, vpp, pnp, flags, rdir, cr);
+ if ((flags & LOOKUP_XATTR) && (flags & LOOKUP_HAVE_SYSATTR_DIR) == 0) {
+ ret = xattr_dir_lookup(dvp, vpp, flags, cr);
+ } else {
+ ret = (*(dvp)->v_op->vop_lookup)
+ (dvp, nm, vpp, pnp, flags, rdir, cr, ct, deflags, ppnp);
+ }
if (ret == 0 && *vpp) {
VOPSTATS_UPDATE(*vpp, lookup);
if ((*vpp)->v_path == NULL) {
@@ -3072,14 +3321,29 @@ fop_create(
int mode,
vnode_t **vpp,
cred_t *cr,
- int flag)
+ int flags,
+ caller_context_t *ct,
+ vsecattr_t *vsecp) /* ACL to set during create */
{
int ret;
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(dvp, cr);
ret = (*(dvp)->v_op->vop_create)
- (dvp, name, vap, excl, mode, vpp, cr, flag);
+ (dvp, name, vap, excl, mode, vpp, cr, flags, ct, vsecp);
if (ret == 0 && *vpp) {
VOPSTATS_UPDATE(*vpp, create);
if ((*vpp)->v_path == NULL) {
@@ -3094,13 +3358,24 @@ int
fop_remove(
vnode_t *dvp,
char *nm,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
int err;
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(dvp, cr);
- err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr);
+ err = (*(dvp)->v_op->vop_remove)(dvp, nm, cr, ct, flags);
VOPSTATS_UPDATE(dvp, remove);
return (err);
}
@@ -3110,13 +3385,24 @@ fop_link(
vnode_t *tdvp,
vnode_t *svp,
char *tnm,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
int err;
+ /*
+ * If the target file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(tdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(tdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(tdvp, cr);
- err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr);
+ err = (*(tdvp)->v_op->vop_link)(tdvp, svp, tnm, cr, ct, flags);
VOPSTATS_UPDATE(tdvp, link);
return (err);
}
@@ -3127,13 +3413,25 @@ fop_rename(
char *snm,
vnode_t *tdvp,
char *tnm,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
int err;
+ /*
+ * If the file system involved does not support
+ * case-insensitive access and said access is requested, fail
+ * quickly.
+ */
+ if (flags & FIGNORECASE &&
+ ((vfs_has_feature(sdvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(sdvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0)))
+ return (EINVAL);
+
VOPXID_MAP_CR(tdvp, cr);
- err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr);
+ err = (*(sdvp)->v_op->vop_rename)(sdvp, snm, tdvp, tnm, cr, ct, flags);
VOPSTATS_UPDATE(sdvp, rename);
return (err);
}
@@ -3144,13 +3442,30 @@ fop_mkdir(
char *dirname,
vattr_t *vap,
vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags,
+ vsecattr_t *vsecp) /* ACL to set during create */
{
int ret;
+ if (vsecp != NULL &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_ACLONCREATE) == 0) {
+ return (EINVAL);
+ }
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(dvp, cr);
- ret = (*(dvp)->v_op->vop_mkdir)(dvp, dirname, vap, vpp, cr);
+ ret = (*(dvp)->v_op->vop_mkdir)
+ (dvp, dirname, vap, vpp, cr, ct, flags, vsecp);
if (ret == 0 && *vpp) {
VOPSTATS_UPDATE(*vpp, mkdir);
if ((*vpp)->v_path == NULL) {
@@ -3167,13 +3482,24 @@ fop_rmdir(
vnode_t *dvp,
char *nm,
vnode_t *cdir,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
int err;
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(dvp, cr);
- err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr);
+ err = (*(dvp)->v_op->vop_rmdir)(dvp, nm, cdir, cr, ct, flags);
VOPSTATS_UPDATE(dvp, rmdir);
return (err);
}
@@ -3183,14 +3509,24 @@ fop_readdir(
vnode_t *vp,
uio_t *uiop,
cred_t *cr,
- int *eofp)
+ int *eofp,
+ caller_context_t *ct,
+ int flags)
{
int err;
ssize_t resid_start = uiop->uio_resid;
+ /*
+ * If this file system doesn't support retrieving directory
+ * entry flags and said access is requested, fail quickly.
+ */
+ if (flags & V_RDDIR_ENTFLAGS &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS) == 0)
+ return (EINVAL);
+
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp);
+ err = (*(vp)->v_op->vop_readdir)(vp, uiop, cr, eofp, ct, flags);
VOPSTATS_UPDATE_IO(vp, readdir,
readdir_bytes, (resid_start - uiop->uio_resid));
return (err);
@@ -3202,13 +3538,25 @@ fop_symlink(
char *linkname,
vattr_t *vap,
char *target,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct,
+ int flags)
{
int err;
+ /*
+ * If this file system doesn't support case-insensitive access
+ * and said access is requested, fail quickly.
+ */
+ if (flags & FIGNORECASE &&
+ (vfs_has_feature(dvp->v_vfsp, VFSFT_CASEINSENSITIVE) == 0 &&
+ vfs_has_feature(dvp->v_vfsp, VFSFT_NOCASESENSITIVE) == 0))
+ return (EINVAL);
+
VOPXID_MAP_CR(dvp, cr);
- err = (*(dvp)->v_op->vop_symlink) (dvp, linkname, vap, target, cr);
+ err = (*(dvp)->v_op->vop_symlink)
+ (dvp, linkname, vap, target, cr, ct, flags);
VOPSTATS_UPDATE(dvp, symlink);
return (err);
}
@@ -3217,13 +3565,14 @@ int
fop_readlink(
vnode_t *vp,
uio_t *uiop,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr);
+ err = (*(vp)->v_op->vop_readlink)(vp, uiop, cr, ct);
VOPSTATS_UPDATE(vp, readlink);
return (err);
}
@@ -3232,13 +3581,14 @@ int
fop_fsync(
vnode_t *vp,
int syncflag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr);
+ err = (*(vp)->v_op->vop_fsync)(vp, syncflag, cr, ct);
VOPSTATS_UPDATE(vp, fsync);
return (err);
}
@@ -3246,24 +3596,26 @@ fop_fsync(
void
fop_inactive(
vnode_t *vp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
/* Need to update stats before vop call since we may lose the vnode */
VOPSTATS_UPDATE(vp, inactive);
VOPXID_MAP_CR(vp, cr);
- (*(vp)->v_op->vop_inactive)(vp, cr);
+ (*(vp)->v_op->vop_inactive)(vp, cr, ct);
}
int
fop_fid(
vnode_t *vp,
- fid_t *fidp)
+ fid_t *fidp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_fid)(vp, fidp);
+ err = (*(vp)->v_op->vop_fid)(vp, fidp, ct);
VOPSTATS_UPDATE(vp, fid);
return (err);
}
@@ -3295,11 +3647,12 @@ int
fop_seek(
vnode_t *vp,
offset_t ooff,
- offset_t *noffp)
+ offset_t *noffp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp);
+ err = (*(vp)->v_op->vop_seek)(vp, ooff, noffp, ct);
VOPSTATS_UPDATE(vp, seek);
return (err);
}
@@ -3307,11 +3660,12 @@ fop_seek(
int
fop_cmp(
vnode_t *vp1,
- vnode_t *vp2)
+ vnode_t *vp2,
+ caller_context_t *ct)
{
int err;
- err = (*(vp1)->v_op->vop_cmp)(vp1, vp2);
+ err = (*(vp1)->v_op->vop_cmp)(vp1, vp2, ct);
VOPSTATS_UPDATE(vp1, cmp);
return (err);
}
@@ -3324,14 +3678,15 @@ fop_frlock(
int flag,
offset_t offset,
struct flk_callback *flk_cbp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
err = (*(vp)->v_op->vop_frlock)
- (vp, cmd, bfp, flag, offset, flk_cbp, cr);
+ (vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
VOPSTATS_UPDATE(vp, frlock);
return (err);
}
@@ -3358,11 +3713,12 @@ fop_space(
int
fop_realvp(
vnode_t *vp,
- vnode_t **vpp)
+ vnode_t **vpp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_realvp)(vp, vpp);
+ err = (*(vp)->v_op->vop_realvp)(vp, vpp, ct);
VOPSTATS_UPDATE(vp, realvp);
return (err);
}
@@ -3378,14 +3734,15 @@ fop_getpage(
struct seg *seg,
caddr_t addr,
enum seg_rw rw,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
err = (*(vp)->v_op->vop_getpage)
- (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr);
+ (vp, off, len, protp, plarr, plsz, seg, addr, rw, cr, ct);
VOPSTATS_UPDATE(vp, getpage);
return (err);
}
@@ -3396,13 +3753,14 @@ fop_putpage(
offset_t off,
size_t len,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr);
+ err = (*(vp)->v_op->vop_putpage)(vp, off, len, flags, cr, ct);
VOPSTATS_UPDATE(vp, putpage);
return (err);
}
@@ -3417,14 +3775,15 @@ fop_map(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
err = (*(vp)->v_op->vop_map)
- (vp, off, as, addrp, len, prot, maxprot, flags, cr);
+ (vp, off, as, addrp, len, prot, maxprot, flags, cr, ct);
VOPSTATS_UPDATE(vp, map);
return (err);
}
@@ -3439,7 +3798,8 @@ fop_addmap(
uchar_t prot,
uchar_t maxprot,
uint_t flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int error;
u_longlong_t delta;
@@ -3447,7 +3807,7 @@ fop_addmap(
VOPXID_MAP_CR(vp, cr);
error = (*(vp)->v_op->vop_addmap)
- (vp, off, as, addr, len, prot, maxprot, flags, cr);
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
if ((!error) && (vp->v_type == VREG)) {
delta = (u_longlong_t)btopr(len);
@@ -3488,7 +3848,8 @@ fop_delmap(
uint_t prot,
uint_t maxprot,
uint_t flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int error;
u_longlong_t delta;
@@ -3496,7 +3857,7 @@ fop_delmap(
VOPXID_MAP_CR(vp, cr);
error = (*(vp)->v_op->vop_delmap)
- (vp, off, as, addr, len, prot, maxprot, flags, cr);
+ (vp, off, as, addr, len, prot, maxprot, flags, cr, ct);
/*
* NFS calls into delmap twice, the first time
@@ -3539,11 +3900,12 @@ fop_poll(
short events,
int anyyet,
short *reventsp,
- struct pollhead **phpp)
+ struct pollhead **phpp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp);
+ err = (*(vp)->v_op->vop_poll)(vp, events, anyyet, reventsp, phpp, ct);
VOPSTATS_UPDATE(vp, poll);
return (err);
}
@@ -3553,11 +3915,12 @@ fop_dump(
vnode_t *vp,
caddr_t addr,
int lbdn,
- int dblks)
+ int dblks,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks);
+ err = (*(vp)->v_op->vop_dump)(vp, addr, lbdn, dblks, ct);
VOPSTATS_UPDATE(vp, dump);
return (err);
}
@@ -3567,13 +3930,14 @@ fop_pathconf(
vnode_t *vp,
int cmd,
ulong_t *valp,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr);
+ err = (*(vp)->v_op->vop_pathconf)(vp, cmd, valp, cr, ct);
VOPSTATS_UPDATE(vp, pathconf);
return (err);
}
@@ -3585,13 +3949,14 @@ fop_pageio(
u_offset_t io_off,
size_t io_len,
int flags,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr);
+ err = (*(vp)->v_op->vop_pageio)(vp, pp, io_off, io_len, flags, cr, ct);
VOPSTATS_UPDATE(vp, pageio);
return (err);
}
@@ -3600,10 +3965,11 @@ int
fop_dumpctl(
vnode_t *vp,
int action,
- int *blkp)
+ int *blkp,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp);
+ err = (*(vp)->v_op->vop_dumpctl)(vp, action, blkp, ct);
VOPSTATS_UPDATE(vp, dumpctl);
return (err);
}
@@ -3614,14 +3980,15 @@ fop_dispose(
page_t *pp,
int flag,
int dn,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
/* Must do stats first since it's possible to lose the vnode */
VOPSTATS_UPDATE(vp, dispose);
VOPXID_MAP_CR(vp, cr);
- (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr);
+ (*(vp)->v_op->vop_dispose)(vp, pp, flag, dn, cr, ct);
}
int
@@ -3629,13 +3996,22 @@ fop_setsecattr(
vnode_t *vp,
vsecattr_t *vsap,
int flag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr);
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+ err = (*(vp)->v_op->vop_setsecattr) (vp, vsap, flag, cr, ct);
VOPSTATS_UPDATE(vp, setsecattr);
return (err);
}
@@ -3645,13 +4021,23 @@ fop_getsecattr(
vnode_t *vp,
vsecattr_t *vsap,
int flag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
+ /*
+ * We're only allowed to skip the ACL check iff we used a 32 bit
+ * ACE mask with VOP_ACCESS() to determine permissions.
+ */
+ if ((flag & ATTR_NOACLCHECK) &&
+ vfs_has_feature(vp->v_vfsp, VFSFT_ACEMASKONACCESS) == 0) {
+ return (EINVAL);
+ }
+
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr);
+ err = (*(vp)->v_op->vop_getsecattr) (vp, vsap, flag, cr, ct);
VOPSTATS_UPDATE(vp, getsecattr);
return (err);
}
@@ -3662,23 +4048,25 @@ fop_shrlock(
int cmd,
struct shrlock *shr,
int flag,
- cred_t *cr)
+ cred_t *cr,
+ caller_context_t *ct)
{
int err;
VOPXID_MAP_CR(vp, cr);
- err = (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr);
+ err = (*(vp)->v_op->vop_shrlock)(vp, cmd, shr, flag, cr, ct);
VOPSTATS_UPDATE(vp, shrlock);
return (err);
}
int
-fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm)
+fop_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *fnm,
+ caller_context_t *ct)
{
int err;
- err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm);
+ err = (*(vp)->v_op->vop_vnevent)(vp, vnevent, dvp, fnm, ct);
VOPSTATS_UPDATE(vp, vnevent);
return (err);
}
diff --git a/usr/src/uts/common/fs/xattr.c b/usr/src/uts/common/fs/xattr.c
new file mode 100644
index 0000000000..65e0cd80d0
--- /dev/null
+++ b/usr/src/uts/common/fs/xattr.c
@@ -0,0 +1,1428 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/cred.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/pathname.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/acl.h>
+#include <sys/file.h>
+#include <sys/sunddi.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/vnode.h>
+#include <sys/mode.h>
+#include <sys/nvpair.h>
+#include <sys/attr.h>
+#include <sys/gfs.h>
+#include <sys/mutex.h>
+#include <fs/fs_subr.h>
+#include <sys/kidmap.h>
+
+typedef struct {
+ gfs_file_t gfs_private;
+ xattr_view_t xattr_view;
+} xattr_file_t;
+
+/* ARGSUSED */
+static int
+xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
+{
+ xattr_file_t *np = (*vpp)->v_data;
+
+ if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
+ return (EACCES);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ xattr_file_t *np = vp->v_data;
+
+ if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))
+ return (EACCES);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_close(vnode_t *vp, int flags, int count, offset_t off,
+ cred_t *cr, caller_context_t *ct)
+{
+ cleanlocks(vp, ddi_get_pid(), 0);
+ cleanshares(vp, ddi_get_pid());
+ return (0);
+}
+
+static int
+xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
+{
+ xattr_fid_t *xfidp;
+ vnode_t *pvp, *savevp;
+ int error;
+ uint16_t orig_len;
+
+ if (fidp->fid_len < XATTR_FIDSZ) {
+ fidp->fid_len = XATTR_FIDSZ;
+ return (ENOSPC);
+ }
+
+ savevp = pvp = gfs_file_parent(vp);
+ mutex_enter(&savevp->v_lock);
+ if (pvp->v_flag & V_XATTRDIR) {
+ pvp = gfs_file_parent(pvp);
+ }
+ mutex_exit(&savevp->v_lock);
+
+ xfidp = (xattr_fid_t *)fidp;
+ orig_len = fidp->fid_len;
+ fidp->fid_len = sizeof (xfidp->parent_fid);
+
+ error = VOP_FID(pvp, fidp, ct);
+ if (error) {
+ fidp->fid_len = orig_len;
+ return (error);
+ }
+
+ xfidp->parent_len = fidp->fid_len;
+ fidp->fid_len = XATTR_FIDSZ;
+ xfidp->dir_offset = gfs_file_inode(vp);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
+ cred_t *cr, caller_context_t *ct)
+{
+ int error;
+ f_attr_t attr;
+ uint64_t fsid;
+ dev_t mdev;
+ xvattr_t xvattr;
+ xoptattr_t *xoap; /* Pointer to optional attributes */
+ vnode_t *ppvp;
+ const char *domain;
+ uint32_t rid;
+
+ xva_init(&xvattr);
+
+ if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
+ return (EINVAL);
+
+ /*
+ * For detecting ephemeral uid/gid
+ */
+ xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID);
+
+ /*
+ * We need to access the real fs object.
+ * vp points to a GFS file; ppvp points to the real object.
+ */
+ ppvp = gfs_file_parent(gfs_file_parent(vp));
+
+ /*
+ * Iterate through the attrs associated with this view
+ */
+
+ for (attr = 0; attr < F_ATTR_ALL; attr++) {
+ if (xattr_view != attr_to_xattr_view(attr)) {
+ continue;
+ }
+
+ switch (attr) {
+ case F_SYSTEM:
+ XVA_SET_REQ(&xvattr, XAT_SYSTEM);
+ break;
+ case F_READONLY:
+ XVA_SET_REQ(&xvattr, XAT_READONLY);
+ break;
+ case F_HIDDEN:
+ XVA_SET_REQ(&xvattr, XAT_HIDDEN);
+ break;
+ case F_ARCHIVE:
+ XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
+ break;
+ case F_IMMUTABLE:
+ XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
+ break;
+ case F_APPENDONLY:
+ XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
+ break;
+ case F_NOUNLINK:
+ XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
+ break;
+ case F_OPAQUE:
+ XVA_SET_REQ(&xvattr, XAT_OPAQUE);
+ break;
+ case F_NODUMP:
+ XVA_SET_REQ(&xvattr, XAT_NODUMP);
+ break;
+ case F_AV_QUARANTINED:
+ XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
+ break;
+ case F_AV_MODIFIED:
+ XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
+ break;
+ case F_AV_SCANSTAMP:
+ if (ppvp->v_type == VREG)
+ XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
+ break;
+ case F_CRTIME:
+ XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+ break;
+ case F_FSID:
+ fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) |
+ (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] &
+ 0xffffffff));
+ VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
+ fsid) == 0);
+ break;
+ case F_MDEV:
+ mdev = ((int16_t)vp->v_vfsp->vfs_dev);
+ VERIFY(nvlist_add_uint16(nvlp, attr_to_name(attr),
+ mdev) == 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
+ if (error)
+ return (error);
+
+ /*
+ * Process all the optional attributes together here. Notice that
+ * xoap was set when the optional attribute bits were set above.
+ */
+ if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) {
+ if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_READONLY),
+ xoap->xoa_readonly) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_HIDDEN),
+ xoap->xoa_hidden) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_SYSTEM),
+ xoap->xoa_system) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_ARCHIVE),
+ xoap->xoa_archive) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_IMMUTABLE),
+ xoap->xoa_immutable) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_NOUNLINK),
+ xoap->xoa_nounlink) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_APPENDONLY),
+ xoap->xoa_appendonly) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_NODUMP),
+ xoap->xoa_nodump) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_OPAQUE),
+ xoap->xoa_opaque) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_AV_QUARANTINED),
+ xoap->xoa_av_quarantined) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) {
+ VERIFY(nvlist_add_boolean_value(nvlp,
+ attr_to_name(F_AV_MODIFIED),
+ xoap->xoa_av_modified) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) {
+ VERIFY(nvlist_add_uint8_array(nvlp,
+ attr_to_name(F_AV_SCANSTAMP),
+ xoap->xoa_av_scanstamp,
+ sizeof (xoap->xoa_av_scanstamp)) == 0);
+ }
+ if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) {
+ VERIFY(nvlist_add_uint64_array(nvlp,
+ attr_to_name(F_CRTIME),
+ (uint64_t *)&(xoap->xoa_createtime),
+ sizeof (xoap->xoa_createtime) /
+ sizeof (uint64_t)) == 0);
+ }
+ }
+ /*
+ * Check for optional ownersid/groupsid
+ */
+
+ if (xvattr.xva_vattr.va_uid > MAXUID) {
+ nvlist_t *nvl_sid;
+
+ if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
+ return (ENOMEM);
+
+ if (kidmap_getsidbyuid(xvattr.xva_vattr.va_uid,
+ &domain, &rid) == 0) {
+ VERIFY(nvlist_add_string(nvl_sid,
+ SID_DOMAIN, domain) == 0);
+ VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
+ VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID),
+ nvl_sid) == 0);
+ }
+ nvlist_free(nvl_sid);
+ }
+ if (xvattr.xva_vattr.va_gid > MAXUID) {
+ nvlist_t *nvl_sid;
+
+ if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
+ return (ENOMEM);
+
+ if (kidmap_getsidbygid(xvattr.xva_vattr.va_gid,
+ &domain, &rid) == 0) {
+ VERIFY(nvlist_add_string(nvl_sid,
+ SID_DOMAIN, domain) == 0);
+ VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
+ VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID),
+ nvl_sid) == 0);
+ }
+ nvlist_free(nvl_sid);
+ }
+
+ return (0);
+}
+
+/*
+ * The size of a sysattr file is the size of the nvlist that will be
+ * returned by xattr_file_read(). A call to xattr_file_write() could
+ * change the size of that nvlist. That size is not stored persistently
+ * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
+ */
+static int
+xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size,
+ cred_t *cr, caller_context_t *ct)
+{
+ nvlist_t *nvl;
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) {
+ return (ENOMEM);
+ }
+
+ if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
+ nvlist_free(nvl);
+ return (EFAULT);
+ }
+
+ VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0);
+ nvlist_free(nvl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ xattr_file_t *np = vp->v_data;
+ timestruc_t now;
+ size_t size;
+ int error;
+ vnode_t *pvp;
+ vattr_t pvattr;
+
+ vap->va_type = VREG;
+ vap->va_mode = MAKEIMODE(vap->va_type,
+ (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644));
+ vap->va_nodeid = gfs_file_inode(vp);
+ vap->va_nlink = 1;
+ pvp = gfs_file_parent(vp);
+ (void) memset(&pvattr, 0, sizeof (pvattr));
+ pvattr.va_mask = AT_CTIME|AT_MTIME;
+ error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct);
+ if (error) {
+ return (error);
+ }
+ vap->va_ctime = pvattr.va_ctime;
+ vap->va_mtime = pvattr.va_mtime;
+ gethrestime(&now);
+ vap->va_atime = now;
+ vap->va_uid = 0;
+ vap->va_gid = 0;
+ vap->va_rdev = 0;
+ vap->va_blksize = DEV_BSIZE;
+ vap->va_seq = 0;
+ vap->va_fsid = vp->v_vfsp->vfs_dev;
+ error = xattr_file_size(vp, np->xattr_view, &size, cr, ct);
+ vap->va_size = size;
+ vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
+ caller_context_t *ct)
+{
+ xattr_file_t *np = vp->v_data;
+ xattr_view_t xattr_view = np->xattr_view;
+ char *buf;
+ size_t filesize;
+ nvlist_t *nvl;
+ int error;
+
+ /*
+ * Validate file offset and fasttrack empty reads
+ */
+ if (uiop->uio_loffset < (offset_t)0)
+ return (EINVAL);
+
+ if (uiop->uio_resid == 0)
+ return (0);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP))
+ return (ENOMEM);
+
+ if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
+ nvlist_free(nvl);
+ return (EFAULT);
+ }
+
+ VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0);
+
+ if (uiop->uio_loffset >= filesize) {
+ nvlist_free(nvl);
+ return (0);
+ }
+
+ buf = kmem_alloc(filesize, KM_SLEEP);
+ VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR,
+ KM_SLEEP) == 0);
+
+ error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop);
+ kmem_free(buf, filesize);
+ nvlist_free(nvl);
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error = 0;
+ char *buf;
+ char *domain;
+ uint32_t rid;
+ ssize_t size = uiop->uio_resid;
+ nvlist_t *nvp;
+ nvpair_t *pair = NULL;
+ vnode_t *ppvp;
+ xvattr_t xvattr;
+ xoptattr_t *xoap = NULL; /* Pointer to optional attributes */
+
+ /*
+ * Validate file offset and size.
+ */
+ if (uiop->uio_loffset < (offset_t)0)
+ return (EINVAL);
+
+ if (size == 0)
+ return (EINVAL);
+
+ xva_init(&xvattr);
+
+ if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
+ return (EINVAL);
+ }
+
+ /*
+ * Copy and unpack the nvlist
+ */
+ buf = kmem_alloc(size, KM_SLEEP);
+ if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) {
+ return (EFAULT);
+ }
+
+ if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) {
+ kmem_free(buf, size);
+ uiop->uio_resid = size;
+ return (EINVAL);
+ }
+ kmem_free(buf, size);
+
+ /*
+ * Fasttrack empty writes (nvlist with no nvpairs)
+ */
+ if (nvlist_next_nvpair(nvp, NULL) == 0)
+ return (0);
+
+ ppvp = gfs_file_parent(gfs_file_parent(vp));
+
+ while (pair = nvlist_next_nvpair(nvp, pair)) {
+ data_type_t type;
+ f_attr_t attr;
+ boolean_t value;
+ uint64_t *time, *times;
+ uint_t elem, nelems;
+ nvlist_t *nvp_sid;
+ uint8_t *scanstamp;
+
+ /*
+ * Validate the name and type of each attribute.
+ * Log any unknown names and continue. This will
+ * help if additional attributes are added later.
+ */
+ type = nvpair_type(pair);
+ if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
+ cmn_err(CE_WARN, "Unknown attribute %s",
+ nvpair_name(pair));
+ continue;
+ }
+
+ /*
+ * Verify nvlist type matches required type and view is OK
+ */
+
+ if (type != attr_to_data_type(attr) ||
+ (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ /*
+ * For OWNERSID/GROUPSID make sure the target
+ * file system support ephemeral ID's
+ */
+ if ((attr == F_OWNERSID || attr == F_GROUPSID) &&
+ (!(vp->v_vfsp->vfs_flag & VFS_XID))) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ /*
+ * Retrieve data from nvpair
+ */
+ switch (type) {
+ case DATA_TYPE_BOOLEAN_VALUE:
+ if (nvpair_value_boolean_value(pair, &value)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ case DATA_TYPE_UINT64_ARRAY:
+ if (nvpair_value_uint64_array(pair, &times, &nelems)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ case DATA_TYPE_NVLIST:
+ if (nvpair_value_nvlist(pair, &nvp_sid)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ case DATA_TYPE_UINT8_ARRAY:
+ if (nvpair_value_uint8_array(pair,
+ &scanstamp, &nelems)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ default:
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ switch (attr) {
+ /*
+ * If we have several similar optional attributes to
+ * process then we should do it all together here so that
+ * xoap and the requested bitmap can be set in one place.
+ */
+ case F_READONLY:
+ XVA_SET_REQ(&xvattr, XAT_READONLY);
+ xoap->xoa_readonly = value;
+ break;
+ case F_HIDDEN:
+ XVA_SET_REQ(&xvattr, XAT_HIDDEN);
+ xoap->xoa_hidden = value;
+ break;
+ case F_SYSTEM:
+ XVA_SET_REQ(&xvattr, XAT_SYSTEM);
+ xoap->xoa_system = value;
+ break;
+ case F_ARCHIVE:
+ XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
+ xoap->xoa_archive = value;
+ break;
+ case F_IMMUTABLE:
+ XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
+ xoap->xoa_immutable = value;
+ break;
+ case F_NOUNLINK:
+ XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
+ xoap->xoa_nounlink = value;
+ break;
+ case F_APPENDONLY:
+ XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
+ xoap->xoa_appendonly = value;
+ break;
+ case F_NODUMP:
+ XVA_SET_REQ(&xvattr, XAT_NODUMP);
+ xoap->xoa_nodump = value;
+ break;
+ case F_AV_QUARANTINED:
+ XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
+ xoap->xoa_av_quarantined = value;
+ break;
+ case F_AV_MODIFIED:
+ XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
+ xoap->xoa_av_modified = value;
+ break;
+ case F_CRTIME:
+ XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+ time = (uint64_t *)&(xoap->xoa_createtime);
+ for (elem = 0; elem < nelems; elem++)
+ *time++ = times[elem];
+ break;
+ case F_OWNERSID:
+ case F_GROUPSID:
+ if (nvlist_lookup_string(nvp_sid, SID_DOMAIN,
+ &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID,
+ &rid)) {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+
+ /*
+ * Now map domain+rid to ephemeral id's
+ *
+ * If mapping fails, then the uid/gid will
+ * be set to UID_NOBODY by Winchester.
+ */
+
+ if (attr == F_OWNERSID) {
+ (void) kidmap_getuidbysid(domain, rid,
+ &xvattr.xva_vattr.va_uid);
+ xvattr.xva_vattr.va_mask |= AT_UID;
+ } else {
+ (void) kidmap_getgidbysid(domain, rid,
+ &xvattr.xva_vattr.va_gid);
+ xvattr.xva_vattr.va_mask |= AT_GID;
+ }
+ break;
+ case F_AV_SCANSTAMP:
+ if (ppvp->v_type == VREG) {
+ XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
+ (void) memcpy(xoap->xoa_av_scanstamp,
+ scanstamp, nelems);
+ } else {
+ nvlist_free(nvp);
+ return (EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ppvp = gfs_file_parent(gfs_file_parent(vp));
+ error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
+ if (error)
+ uiop->uio_resid = size;
+
+ nvlist_free(nvp);
+ return (error);
+}
+
+static int
+xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ switch (cmd) {
+ case _PC_XATTR_EXISTS:
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = 0;
+ return (0);
+ default:
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
+ }
+}
+
+vnodeops_t *xattr_file_ops;
+
+static const fs_operation_def_t xattr_file_tops[] = {
+ { VOPNAME_OPEN, { .vop_open = xattr_file_open } },
+ { VOPNAME_CLOSE, { .vop_close = xattr_file_close } },
+ { VOPNAME_READ, { .vop_read = xattr_file_read } },
+ { VOPNAME_WRITE, { .vop_write = xattr_file_write } },
+ { VOPNAME_IOCTL, { .error = fs_ioctl } },
+ { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } },
+ { VOPNAME_ACCESS, { .vop_access = xattr_file_access } },
+ { VOPNAME_READDIR, { .error = fs_notdir } },
+ { VOPNAME_SEEK, { .vop_seek = fs_seek } },
+ { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } },
+ { VOPNAME_FID, { .vop_fid = xattr_common_fid } },
+ { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } },
+ { VOPNAME_PUTPAGE, { .error = fs_putpage } },
+ { VOPNAME_FSYNC, { .error = fs_fsync } },
+ { NULL }
+};
+
+vnode_t *
+xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view)
+{
+ vnode_t *vp;
+ xattr_file_t *np;
+
+ vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops);
+ np = vp->v_data;
+ np->xattr_view = xattr_view;
+ vp->v_flag |= V_SYSATTR;
+ return (vp);
+}
+
+vnode_t *
+xattr_mkfile_ro(vnode_t *pvp)
+{
+ return (xattr_mkfile(pvp, XATTR_VIEW_READONLY));
+}
+
+vnode_t *
+xattr_mkfile_rw(vnode_t *pvp)
+{
+ return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE));
+}
+
+vnodeops_t *xattr_dir_ops;
+
+static gfs_dirent_t xattr_dirents[] = {
+ { VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, },
+ { VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, },
+ { NULL },
+};
+
+#define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
+
+static int
+is_sattr_name(char *s)
+{
+ int i;
+
+ for (i = 0; i < XATTRDIR_NENTS; ++i) {
+ if (strcmp(s, xattr_dirents[i].gfse_name) == 0) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
+ cred_t *cr, caller_context_t *ct)
+{
+ xvattr_t xvattr;
+ vnode_t *pdvp;
+ int error;
+
+ /*
+ * Only copy system attrs if the views are the same
+ */
+ if (strcmp(snm, tnm) != 0)
+ return (EINVAL);
+
+ xva_init(&xvattr);
+
+ XVA_SET_REQ(&xvattr, XAT_SYSTEM);
+ XVA_SET_REQ(&xvattr, XAT_READONLY);
+ XVA_SET_REQ(&xvattr, XAT_HIDDEN);
+ XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
+ XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
+ XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
+ XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
+ XVA_SET_REQ(&xvattr, XAT_NODUMP);
+ XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
+ XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
+ XVA_SET_REQ(&xvattr, XAT_CREATETIME);
+
+ pdvp = gfs_file_parent(sdvp);
+ error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
+ if (error)
+ return (error);
+
+ pdvp = gfs_file_parent(tdvp);
+ error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
+ return (error);
+}
+
+static int
+xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
+ cred_t *cr, caller_context_t *ct)
+{
+ vnode_t *pvp;
+ int error;
+ struct pathname pn;
+ char *startnm = "";
+
+ *realdvp = NULL;
+
+ pvp = gfs_file_parent(dvp);
+
+ error = pn_get(startnm, UIO_SYSSPACE, &pn);
+ if (error) {
+ VN_RELE(pvp);
+ return (error);
+ }
+
+ /*
+ * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
+ * infinite loop with fop_lookup calling back to xattr_dir_lookup.
+ */
+ lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR;
+ error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags,
+ rootvp, cr, ct, NULL, NULL);
+ pn_free(&pn);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
+{
+ if (flags & FWRITE) {
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr,
+ caller_context_t *ct)
+{
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ timestruc_t now;
+ vnode_t *pvp;
+ int error;
+ vattr_t pvattr;
+
+ error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_GETATTR(pvp, vap, 0, cr, ct);
+ VN_RELE(pvp);
+ if (error) {
+ return (error);
+ }
+ vap->va_nlink += XATTRDIR_NENTS;
+ vap->va_size += XATTRDIR_NENTS;
+ return (0);
+ }
+
+ /*
+ * There is no real xattr directory. Cobble together
+ * an entry using info from the parent object.
+ */
+ pvp = gfs_file_parent(vp);
+ (void) memset(&pvattr, 0, sizeof (pvattr));
+ pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME;
+ error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct);
+ if (error) {
+ return (error);
+ }
+ *vap = pvattr;
+ vap->va_type = VDIR;
+ vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777);
+ vap->va_fsid = vp->v_vfsp->vfs_dev;
+ vap->va_nodeid = gfs_file_inode(vp);
+ vap->va_nlink = XATTRDIR_NENTS+2;
+ vap->va_size = vap->va_nlink;
+ gethrestime(&now);
+ vap->va_atime = now;
+ vap->va_blksize = 0;
+ vap->va_nblocks = 0;
+ vap->va_seq = 0;
+ return (0);
+}
+
+static int
+xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ vnode_t *realvp;
+ int error;
+
+ /*
+ * If there is a real xattr directory, do the setattr there.
+ * Otherwise, just return success. The GFS directory is transient,
+ * and any setattr changes can disappear anyway.
+ */
+ error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_SETATTR(realvp, vap, flags, cr, ct);
+ VN_RELE(realvp);
+ }
+ if (error == ENOENT) {
+ error = 0;
+ }
+ return (error);
+}
+
+/* ARGSUSED */
+static int
+xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
+{
+ int error;
+ vnode_t *realvp = NULL;
+
+ if (mode & VWRITE) {
+ return (EACCES);
+ }
+
+ error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
+
+ if (realvp)
+ VN_RELE(realvp);
+
+ /*
+ * No real xattr dir isn't an error
+ * an error of EINVAL indicates attributes on attributes
+ * are not supported. In that case just allow access to the
+ * transient directory.
+ */
+ return ((error == ENOENT || error == EINVAL) ? 0 : error);
+}
+
+static int
+xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
+{
+ vnode_t *pvp;
+ int error;
+
+ *vpp = NULL;
+
+ /*
+ * Don't allow creation of extended attributes with sysattr names.
+ */
+ if (is_sattr_name(name)) {
+ return (gfs_dir_lookup(dvp, name, vpp, cr));
+ }
+
+ error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
+ cr, ct);
+ if (error == 0) {
+ error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag,
+ ct, vsecp);
+ VN_RELE(pvp);
+ }
+ return (error);
+}
+
+static int
+xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
+ int flags)
+{
+ vnode_t *pvp;
+ int error;
+
+ if (is_sattr_name(name)) {
+ return (EACCES);
+ }
+
+ error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_REMOVE(pvp, name, cr, ct, flags);
+ VN_RELE(pvp);
+ }
+ return (error);
+}
+
+static int
+xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
+ caller_context_t *ct, int flags)
+{
+ vnode_t *pvp;
+ int error;
+
+ if (svp->v_flag & V_SYSATTR) {
+ return (EINVAL);
+ }
+
+ error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ error = VOP_LINK(pvp, svp, name, cr, ct, flags);
+ VN_RELE(pvp);
+ }
+ return (error);
+}
+
+static int
+xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
+ cred_t *cr, caller_context_t *ct, int flags)
+{
+ vnode_t *spvp, *tpvp;
+ int error;
+ int held_tgt;
+
+ if (is_sattr_name(snm) || is_sattr_name(tnm))
+ return (xattr_copy(sdvp, snm, tdvp, tnm, cr, ct));
+ /*
+ * We know that sdvp is a GFS dir, or we wouldn't be here.
+ * Get the real unnamed directory.
+ */
+ error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct);
+ if (error) {
+ return (error);
+ }
+
+ if (sdvp == tdvp) {
+ /*
+ * If the source and target are the same GFS directory, the
+ * underlying unnamed source and target dir will be the same.
+ */
+ tpvp = spvp;
+ VN_HOLD(tpvp);
+ held_tgt = 1;
+ } else if (tdvp->v_flag & V_SYSATTR) {
+ /*
+ * If the target dir is a different GFS directory,
+ * find its underlying unnamed dir.
+ */
+ error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct);
+ if (error) {
+ VN_RELE(spvp);
+ return (error);
+ }
+ held_tgt = 1;
+ } else {
+ /*
+ * Target dir is outside of GFS, pass it on through.
+ */
+ tpvp = tdvp;
+ held_tgt = 0;
+ }
+
+ error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags);
+
+ if (held_tgt) {
+ VN_RELE(tpvp);
+ }
+ VN_RELE(spvp);
+
+ return (error);
+}
+
+static int
+xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
+{
+ vnode_t *pvp;
+ int error;
+ int local_eof = 0;
+ int reset_off = 0;
+ int has_xattrs = 0;
+
+ if (eofp == NULL) {
+ eofp = &local_eof;
+ }
+
+ /*
+ * See if there is a real extended attribute directory.
+ */
+ error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
+ if (error == 0) {
+ has_xattrs = 1;
+ }
+
+ /*
+ * Start by reading up the static entries.
+ */
+ if (uiop->uio_loffset == 0) {
+ if (has_xattrs) {
+ /*
+ * If there is a real xattr dir, skip . and ..
+ * in the GFS dir. We'll pick them up below
+ * when we call into the underlying fs.
+ */
+ uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET;
+ }
+ error = gfs_dir_readdir(dvp, uiop, eofp, NULL, cr, ct);
+ if (error) {
+ if (has_xattrs) {
+ VN_RELE(pvp);
+ }
+ return (error);
+ }
+ /*
+ * We must read all of the static entries in the first
+ * call. Otherwise we won't know if uio_loffset in a
+ * subsequent call refers to the static entries or to those
+ * in an underlying fs.
+ */
+ ASSERT(*eofp);
+ reset_off = 1;
+ }
+
+ if (!has_xattrs) {
+ *eofp = 1;
+ return (0);
+ }
+
+ *eofp = 0;
+ if (reset_off) {
+ uiop->uio_loffset = 0;
+ }
+ (void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL);
+ error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags);
+ VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL);
+ VN_RELE(pvp);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static void
+xattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ gfs_file_t *fp;
+
+ fp = gfs_dir_inactive(vp);
+ if (fp != NULL) {
+ kmem_free(fp, fp->gfs_size);
+ }
+}
+
+static int
+xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
+{
+ switch (cmd) {
+ case _PC_XATTR_EXISTS:
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ *valp = 0;
+ return (0);
+ default:
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
+ }
+}
+
+static const fs_operation_def_t xattr_dir_tops[] = {
+ { VOPNAME_OPEN, { .vop_open = xattr_dir_open } },
+ { VOPNAME_CLOSE, { .vop_close = xattr_dir_close } },
+ { VOPNAME_IOCTL, { .error = fs_inval } },
+ { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } },
+ { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } },
+ { VOPNAME_ACCESS, { .vop_access = xattr_dir_access } },
+ { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } },
+ { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } },
+ { VOPNAME_CREATE, { .vop_create = xattr_dir_create } },
+ { VOPNAME_REMOVE, { .vop_remove = xattr_dir_remove } },
+ { VOPNAME_LINK, { .vop_link = xattr_dir_link } },
+ { VOPNAME_RENAME, { .vop_rename = xattr_dir_rename } },
+ { VOPNAME_MKDIR, { .error = fs_inval } },
+ { VOPNAME_SEEK, { .vop_seek = fs_seek } },
+ { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } },
+ { VOPNAME_FID, { .vop_fid = xattr_common_fid } },
+ { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } },
+ { NULL, NULL }
+};
+
+static gfs_opsvec_t xattr_opsvec[] = {
+ { "xattr dir", xattr_dir_tops, &xattr_dir_ops },
+ { "system attributes", xattr_file_tops, &xattr_file_ops },
+ { NULL, NULL, NULL }
+};
+
+static int
+xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
+ cred_t *cr)
+{
+ vnode_t *pvp;
+ struct pathname pn;
+ int error;
+
+ *vpp = NULL;
+ *inop = 0;
+
+ error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
+ cr, NULL);
+
+ /*
+ * Return ENOENT for EACCES requests during lookup. Once an
+ * attribute create is attempted EACCES will be returned.
+ */
+ if (error) {
+ if (error == EACCES)
+ return (ENOENT);
+ return (error);
+ }
+
+ error = pn_get((char *)nm, UIO_SYSSPACE, &pn);
+ if (error == 0) {
+ error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, 0, rootvp,
+ cr, NULL, NULL, NULL);
+ pn_free(&pn);
+ }
+ VN_RELE(pvp);
+
+ return (error);
+}
+
+/* ARGSUSED */
+static ino64_t
+xattrdir_do_ino(vnode_t *vp, int index)
+{
+ /*
+ * We use index 0 for the directory fid. Start
+ * the file numbering at 1.
+ */
+ return ((ino64_t)index+1);
+}
+
+void
+xattr_init(void)
+{
+ VERIFY(gfs_make_opsvec(xattr_opsvec) == 0);
+}
+
+int
+xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
+{
+ int error = 0;
+
+ *vpp = NULL;
+
+ if (dvp->v_type != VDIR && dvp->v_type != VREG)
+ return (EINVAL);
+
+ mutex_enter(&dvp->v_lock);
+
+ /*
+ * If we're already in sysattr space, don't allow creation
+ * of another level of sysattrs.
+ */
+ if (dvp->v_flag & V_SYSATTR) {
+ mutex_exit(&dvp->v_lock);
+ return (EINVAL);
+ }
+
+ if (dvp->v_xattrdir != NULL) {
+ *vpp = dvp->v_xattrdir;
+ VN_HOLD(*vpp);
+ } else {
+ ulong_t val;
+ int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
+ int sysattrs_allowed = 1;
+
+ /*
+ * We have to drop the lock on dvp. gfs_dir_create will
+ * grab it for a VN_HOLD.
+ */
+ mutex_exit(&dvp->v_lock);
+
+ /*
+ * If dvp allows xattr creation, but not sysattr
+ * creation, return the real xattr dir vp. We can't
+ * use the vfs feature mask here because _PC_SATTR_ENABLED
+ * has vnode-level granularity (e.g. .zfs).
+ */
+ error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
+ if (error != 0 || val == 0)
+ sysattrs_allowed = 0;
+
+ if (!xattrs_allowed && !sysattrs_allowed)
+ return (EINVAL);
+
+ if (!sysattrs_allowed) {
+ struct pathname pn;
+ char *nm = "";
+
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error)
+ return (error);
+ error = VOP_LOOKUP(dvp, nm, vpp, &pn,
+ flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
+ NULL, NULL);
+ pn_free(&pn);
+ return (error);
+ }
+
+ /*
+ * Note that we act as if we were given CREATE_XATTR_DIR,
+ * but only for creation of the GFS directory.
+ */
+ *vpp = gfs_dir_create(
+ sizeof (gfs_dir_t), dvp, xattr_dir_ops, xattr_dirents,
+ xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
+ mutex_enter(&dvp->v_lock);
+ if (dvp->v_xattrdir != NULL) {
+ /*
+ * We lost the race to create the xattr dir.
+ * Destroy this one, use the winner. We can't
+ * just call VN_RELE(*vpp), because the vnode
+ * is only partially initialized.
+ */
+ gfs_dir_t *dp = (*vpp)->v_data;
+
+ ASSERT((*vpp)->v_count == 1);
+ vn_free(*vpp);
+
+ mutex_destroy(&dp->gfsd_lock);
+ kmem_free(dp->gfsd_static,
+ dp->gfsd_nstatic * sizeof (gfs_dirent_t));
+ kmem_free(dp, dp->gfsd_file.gfs_size);
+
+ /*
+ * There is an implied VN_HOLD(dvp) here. We should
+ * be doing a VN_RELE(dvp) to clean up the reference
+ * from *vpp, and then a VN_HOLD(dvp) for the new
+ * reference. Instead, we just leave the count alone.
+ */
+
+ *vpp = dvp->v_xattrdir;
+ VN_HOLD(*vpp);
+ } else {
+ (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR);
+ dvp->v_xattrdir = *vpp;
+ }
+ }
+ mutex_exit(&dvp->v_lock);
+
+ return (error);
+}
+
+int
+xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
+{
+ int error;
+ vnode_t *pvp, *dvp;
+ xattr_fid_t *xfidp;
+ struct pathname pn;
+ char *nm;
+ uint16_t orig_len;
+
+ *vpp = NULL;
+
+ if (fidp->fid_len < XATTR_FIDSZ)
+ return (EINVAL);
+
+ xfidp = (xattr_fid_t *)fidp;
+ orig_len = fidp->fid_len;
+ fidp->fid_len = xfidp->parent_len;
+
+ error = VFS_VGET(vfsp, &pvp, fidp);
+ fidp->fid_len = orig_len;
+ if (error)
+ return (error);
+
+ /*
+ * Start by getting the GFS sysattr directory. We might need
+ * to recreate it during the VOP_LOOKUP.
+ */
+ nm = "";
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error) {
+ VN_RELE(pvp);
+ return (EINVAL);
+ }
+
+ error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR,
+ rootvp, CRED(), NULL, NULL, NULL);
+ pn_free(&pn);
+ VN_RELE(pvp);
+ if (error)
+ return (error);
+
+ if (xfidp->dir_offset == 0) {
+ /*
+ * If we were looking for the directory, we're done.
+ */
+ *vpp = dvp;
+ return (0);
+ }
+
+ if (xfidp->dir_offset > XATTRDIR_NENTS) {
+ VN_RELE(dvp);
+ return (EINVAL);
+ }
+
+ nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name;
+
+ error = pn_get(nm, UIO_SYSSPACE, &pn);
+ if (error) {
+ VN_RELE(dvp);
+ return (EINVAL);
+ }
+
+ error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL,
+ NULL, NULL);
+
+ pn_free(&pn);
+ VN_RELE(dvp);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c
index b41458bd15..170f5cc320 100644
--- a/usr/src/uts/common/fs/zfs/dmu.c
+++ b/usr/src/uts/common/fs/zfs/dmu.c
@@ -65,7 +65,7 @@ const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES] = {
{ zap_byteswap, TRUE, "DSL props" },
{ byteswap_uint64_array, TRUE, "DSL dataset" },
{ zfs_znode_byteswap, TRUE, "ZFS znode" },
- { zfs_acl_byteswap, TRUE, "ZFS ACL" },
+ { zfs_oldacl_byteswap, TRUE, "ZFS V0 ACL" },
{ byteswap_uint8_array, FALSE, "ZFS plain file" },
{ zap_byteswap, TRUE, "ZFS directory" },
{ zap_byteswap, TRUE, "ZFS master node" },
@@ -79,7 +79,11 @@ const dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES] = {
{ byteswap_uint8_array, TRUE, "SPA history" },
{ byteswap_uint64_array, TRUE, "SPA history offsets" },
{ zap_byteswap, TRUE, "Pool properties" },
- { zap_byteswap, TRUE, "DSL permissions" }
+ { zap_byteswap, TRUE, "DSL permissions" },
+ { zfs_acl_byteswap, TRUE, "ZFS ACL" },
+ { byteswap_uint8_array, TRUE, "ZFS SYSACL" },
+ { byteswap_uint8_array, TRUE, "FUID table" },
+ { byteswap_uint8_array, TRUE, "FUID table size" },
};
int
diff --git a/usr/src/uts/common/fs/zfs/dsl_deleg.c b/usr/src/uts/common/fs/zfs/dsl_deleg.c
index 6f071afab8..3a9ffa430d 100644
--- a/usr/src/uts/common/fs/zfs/dsl_deleg.c
+++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c
@@ -31,7 +31,7 @@
* it is a local or descendent permission. The first letter
* identifies the type of entry.
*
- * ul$<id> identifies permssions granted locally for this userid.
+ * ul$<id> identifies permissions granted locally for this userid.
* ud$<id> identifies permissions granted on descendent datasets for
* this userid.
* Ul$<id> identifies permission sets granted locally for this userid.
@@ -55,7 +55,7 @@
* s-$@<name> permissions defined in specified set @<name>
* S-$@<name> Sets defined in named set @<name>
*
- * Each of the above entiies points to another zap attribute that contains one
+ * Each of the above entities points to another zap attribute that contains one
* attribute for each allowed permission, such as create, destroy,...
* All of the "upper" case class types will specify permission set names
* rather than permissions.
diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c
index fcf756b267..ef248f26e3 100644
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c
+++ b/usr/src/uts/common/fs/zfs/dsl_prop.c
@@ -44,8 +44,13 @@ dodefault(const char *propname, int intsz, int numint, void *buf)
{
zfs_prop_t prop;
+ /*
+ * The setonce properties are read-only, BUT they still
+ * have a default value that can be used as the initial
+ * value.
+ */
if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
- zfs_prop_readonly(prop))
+ (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
return (ENOENT);
if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
@@ -93,8 +98,7 @@ dsl_prop_get_impl(dsl_dir_t *dd, const char *propname,
/*
* Break out of this loop for non-inheritable properties.
*/
- if (prop != ZPROP_INVAL &&
- !zfs_prop_inheritable(prop))
+ if (prop != ZPROP_INVAL && !zfs_prop_inheritable(prop))
break;
}
if (err == ENOENT)
@@ -418,14 +422,12 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
{
dsl_dataset_t *ds = os->os->os_dsl_dataset;
dsl_dir_t *dd = ds->ds_dir;
+ boolean_t snapshot;
int err = 0;
dsl_pool_t *dp;
objset_t *mos;
- if (dsl_dataset_is_snapshot(ds)) {
- VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
- return (0);
- }
+ snapshot = dsl_dataset_is_snapshot(ds);
VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
@@ -453,6 +455,10 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
dd != ds->ds_dir)
continue;
+ if (snapshot &&
+ !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT))
+ continue;
+
if (nvlist_lookup_nvlist(*nvp, za.za_name,
&propval) == 0)
continue;
diff --git a/usr/src/uts/common/fs/zfs/spa_config.c b/usr/src/uts/common/fs/zfs/spa_config.c
index 599f960cb7..6ce83e0d14 100644
--- a/usr/src/uts/common/fs/zfs/spa_config.c
+++ b/usr/src/uts/common/fs/zfs/spa_config.c
@@ -197,13 +197,13 @@ spa_config_sync(void)
if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
0, RLIM64_INFINITY, kcred, NULL) == 0 &&
- VOP_FSYNC(vp, FSYNC, kcred) == 0) {
+ VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
(void) snprintf(pathname2, sizeof (pathname2), "%s/%s",
spa_config_dir, ZPOOL_CACHE_FILE);
(void) vn_rename(pathname, pathname2, UIO_SYSSPACE);
}
- (void) VOP_CLOSE(vp, oflags, 1, 0, kcred);
+ (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
VN_RELE(vp);
out:
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h
index 6e6495e2ec..3300e901a1 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h
@@ -92,7 +92,7 @@ typedef enum dmu_object_type {
DMU_OT_DSL_DATASET, /* UINT64 */
/* zpl: */
DMU_OT_ZNODE, /* ZNODE */
- DMU_OT_ACL, /* ACL */
+ DMU_OT_OLDACL, /* Old ACL */
DMU_OT_PLAIN_FILE_CONTENTS, /* UINT8 */
DMU_OT_DIRECTORY_CONTENTS, /* ZAP */
DMU_OT_MASTER_NODE, /* ZAP */
@@ -110,6 +110,10 @@ typedef enum dmu_object_type {
DMU_OT_SPA_HISTORY_OFFSETS, /* spa_his_phys_t */
DMU_OT_POOL_PROPS, /* ZAP */
DMU_OT_DSL_PERMS, /* ZAP */
+ DMU_OT_ACL, /* ACL */
+ DMU_OT_SYSACL, /* SYSACL */
+ DMU_OT_FUID, /* FUID table (Packed NVLIST UINT8) */
+ DMU_OT_FUID_SIZE, /* FUID table size UINT64 */
DMU_OT_NUMTYPES
} dmu_object_type_t;
@@ -128,6 +132,7 @@ void byteswap_uint32_array(void *buf, size_t size);
void byteswap_uint16_array(void *buf, size_t size);
void byteswap_uint8_array(void *buf, size_t size);
void zap_byteswap(void *buf, size_t size);
+void zfs_oldacl_byteswap(void *buf, size_t size);
void zfs_acl_byteswap(void *buf, size_t size);
void zfs_znode_byteswap(void *buf, size_t size);
@@ -545,7 +550,7 @@ uint64_t dmu_tx_get_txg(dmu_tx_t *tx);
* Synchronous write.
* If a parent zio is provided this function initiates a write on the
* provided buffer as a child of the parent zio.
- * In the absense of a parent zio, the write is completed synchronously.
+ * In the absence of a parent zio, the write is completed synchronously.
* At write completion, blk is filled with the bp of the written block.
* Note that while the data covered by this function will be on stable
* storage when the write completes this new data does not become a
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
index 1d01123c77..a29e44e67d 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
@@ -50,6 +50,7 @@ extern "C" {
#define ZFS_DELEG_PERM_RECEIVE "receive"
#define ZFS_DELEG_PERM_ALLOW "allow"
#define ZFS_DELEG_PERM_USERPROP "userprop"
+#define ZFS_DELEG_PERM_VSCAN "vscan"
/*
* Note: the names of properties that are marked delegatable are also
diff --git a/usr/src/uts/common/fs/zfs/sys/zap.h b/usr/src/uts/common/fs/zfs/sys/zap.h
index d194705987..b762a93da5 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap.h
@@ -31,7 +31,7 @@
/*
* ZAP - ZFS Attribute Processor
*
- * The ZAP is a module which sits on top of the DMU (Data Managemnt
+ * The ZAP is a module which sits on top of the DMU (Data Management
* Unit) and implements a higher-level storage primitive using DMU
* objects. Its primary consumer is the ZPL (ZFS Posix Layer).
*
@@ -91,10 +91,38 @@ extern "C" {
#define ZAP_MAXVALUELEN 1024
/*
+ * The matchtype specifies which entry will be accessed.
+ * MT_EXACT: only find an exact match (non-normalized)
+ * MT_FIRST: find the "first" normalized (case and Unicode
+ * form) match; the designated "first" match will not change as long
+ * as the set of entries with this normalization doesn't change
+ * MT_BEST: if there is an exact match, find that, otherwise find the
+ * first normalized match
+ */
+typedef enum matchtype
+{
+ MT_EXACT,
+ MT_BEST,
+ MT_FIRST
+} matchtype_t;
+
+/*
* Create a new zapobj with no attributes and return its object number.
+ * MT_EXACT will cause the zap object to only support MT_EXACT lookups,
+ * otherwise any matchtype can be used for lookups.
+ *
+ * normflags specifies what normalization will be done. values are:
+ * 0: no normalization (legacy on-disk format, supports MT_EXACT matching
+ * only)
+ * U8_TEXTPREP_TOLOWER: case normalization will be performed.
+ * MT_FIRST/MT_BEST matching will find entries that match without
+ * regard to case (eg. looking for "foo" can find an entry "Foo").
+ * Eventually, other flags will permit unicode normalization as well.
*/
uint64_t zap_create(objset_t *ds, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+uint64_t zap_create_norm(objset_t *ds, int normflags, dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
/*
* Create a new zapobj with no attributes from the given (unallocated)
@@ -102,6 +130,9 @@ uint64_t zap_create(objset_t *ds, dmu_object_type_t ot,
*/
int zap_create_claim(objset_t *ds, uint64_t obj, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+int zap_create_claim_norm(objset_t *ds, uint64_t obj,
+ int normflags, dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
/*
* The zapobj passed in must be a valid ZAP object for all of the
@@ -140,9 +171,20 @@ int zap_destroy(objset_t *ds, uint64_t zapobj, dmu_tx_t *tx);
* If the attribute is longer than the buffer, as many integers as will
* fit will be transferred to 'buf'. If the entire attribute was not
* transferred, the call will return EOVERFLOW.
+ *
+ * If rn_len is nonzero, realname will be set to the name of the found
+ * entry (which may be different from the requested name if matchtype is
+ * not MT_EXACT).
+ *
+ * If normalization_conflictp is not NULL, it will be set if there is
+ * another name with the same case/unicode normalized form.
*/
int zap_lookup(objset_t *ds, uint64_t zapobj, const char *name,
uint64_t integer_size, uint64_t num_integers, void *buf);
+int zap_lookup_norm(objset_t *ds, uint64_t zapobj, const char *name,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ matchtype_t mt, char *realname, int rn_len,
+ boolean_t *normalization_conflictp);
/*
* Create an attribute with the given name and value.
@@ -182,6 +224,8 @@ int zap_length(objset_t *ds, uint64_t zapobj, const char *name,
* return ENOENT.
*/
int zap_remove(objset_t *ds, uint64_t zapobj, const char *name, dmu_tx_t *tx);
+int zap_remove_norm(objset_t *ds, uint64_t zapobj, const char *name,
+ matchtype_t mt, dmu_tx_t *tx);
/*
* Returns (in *count) the number of attributes in the specified zap
@@ -213,6 +257,11 @@ typedef struct zap_cursor {
typedef struct {
int za_integer_length;
+ /*
+ * za_normalization_conflict will be set if there are additional
+ * entries with this normalized form (eg, "foo" and "Foo").
+ */
+ boolean_t za_normalization_conflict;
uint64_t za_num_integers;
uint64_t za_first_integer; /* no sign extension for <8byte ints */
char za_name[MAXNAMELEN];
diff --git a/usr/src/uts/common/fs/zfs/sys/zap_impl.h b/usr/src/uts/common/fs/zfs/sys/zap_impl.h
index 4e43f4ae49..8cc1108846 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,7 +59,8 @@ typedef struct mzap_ent_phys {
typedef struct mzap_phys {
uint64_t mz_block_type; /* ZBT_MICRO */
uint64_t mz_salt;
- uint64_t mz_pad[6];
+ uint64_t mz_normflags;
+ uint64_t mz_pad[5];
mzap_ent_phys_t mz_chunk[1];
/* actually variable size depending on block size */
} mzap_phys_t;
@@ -127,6 +128,7 @@ typedef struct zap_phys {
uint64_t zap_num_leafs; /* number of leafs */
uint64_t zap_num_entries; /* number of entries */
uint64_t zap_salt; /* salt to stir into hash function */
+ uint64_t zap_normflags; /* flags for u8_textprep_str() */
/*
* This structure is followed by padding, and then the embedded
* pointer table. The embedded pointer table takes up second
@@ -142,7 +144,8 @@ typedef struct zap {
uint64_t zap_object;
struct dmu_buf *zap_dbuf;
krwlock_t zap_rwlock;
- int zap_ismicro;
+ boolean_t zap_ismicro;
+ int zap_normflags;
uint64_t zap_salt;
union {
struct {
@@ -165,34 +168,45 @@ typedef struct zap {
} zap_u;
} zap_t;
+typedef struct zap_name {
+ zap_t *zn_zap;
+ const char *zn_name_orij;
+ uint64_t zn_hash;
+ matchtype_t zn_matchtype;
+ const char *zn_name_norm;
+ char zn_normbuf[ZAP_MAXNAMELEN];
+} zap_name_t;
+
#define zap_f zap_u.zap_fat
#define zap_m zap_u.zap_micro
-uint64_t zap_hash(zap_t *zap, const char *name);
+boolean_t zap_match(zap_name_t *zn, const char *matchname);
int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
krw_t lti, int fatreader, zap_t **zapp);
void zap_unlockdir(zap_t *zap);
void zap_evict(dmu_buf_t *db, void *vmzap);
+zap_name_t *zap_name_alloc(zap_t *zap, const char *name, matchtype_t mt);
+void zap_name_free(zap_name_t *zn);
#define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n))))
void fzap_byteswap(void *buf, size_t size);
int fzap_count(zap_t *zap, uint64_t *count);
-int fzap_lookup(zap_t *zap, const char *name,
- uint64_t integer_size, uint64_t num_integers, void *buf);
-int fzap_add(zap_t *zap, const char *name,
- uint64_t integer_size, uint64_t num_integers,
+int fzap_lookup(zap_name_t *zn,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ char *realname, int rn_len, boolean_t *normalization_conflictp);
+int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers,
const void *val, dmu_tx_t *tx);
-int fzap_update(zap_t *zap, const char *name,
+int fzap_update(zap_name_t *zn,
int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx);
-int fzap_length(zap_t *zap, const char *name,
+int fzap_length(zap_name_t *zn,
uint64_t *integer_size, uint64_t *num_integers);
-int fzap_remove(zap_t *zap, const char *name, dmu_tx_t *tx);
+int fzap_remove(zap_name_t *zn, dmu_tx_t *tx);
int fzap_cursor_retrieve(zap_t *zap, zap_cursor_t *zc, zap_attribute_t *za);
void fzap_get_stats(zap_t *zap, zap_stats_t *zs);
void zap_put_leaf(struct zap_leaf *l);
-int fzap_add_cd(zap_t *zap, const char *name,
+int fzap_add_cd(zap_name_t *zn,
uint64_t integer_size, uint64_t num_integers,
const void *val, uint32_t cd, dmu_tx_t *tx);
void fzap_upgrade(zap_t *zap, dmu_tx_t *tx);
diff --git a/usr/src/uts/common/fs/zfs/sys/zap_leaf.h b/usr/src/uts/common/fs/zfs/sys/zap_leaf.h
index 147fb72124..6cee851f1f 100644
--- a/usr/src/uts/common/fs/zfs/sys/zap_leaf.h
+++ b/usr/src/uts/common/fs/zfs/sys/zap_leaf.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -92,6 +92,8 @@ typedef enum zap_chunk_type {
ZAP_CHUNK_TYPE_MAX = 250
} zap_chunk_type_t;
+#define ZLF_ENTRIES_CDSORTED (1<<0)
+
/*
* TAKE NOTE:
* If zap_leaf_phys_t is modified, zap_leaf_byteswap() must be modified.
@@ -109,7 +111,8 @@ typedef struct zap_leaf_phys {
/* above is accessable to zap, below is zap_leaf private */
uint16_t lh_freelist; /* chunk head of free list */
- uint8_t lh_pad2[12];
+ uint8_t lh_flags; /* ZLF_* flags */
+ uint8_t lh_pad2[11];
} l_hdr; /* 2 24-byte chunks */
/*
@@ -174,7 +177,7 @@ typedef struct zap_entry_handle {
* value must equal zap_hash(name).
*/
extern int zap_leaf_lookup(zap_leaf_t *l,
- const char *name, uint64_t h, zap_entry_handle_t *zeh);
+ zap_name_t *zn, zap_entry_handle_t *zeh);
/*
* Return a handle to the entry with this hash+cd, or the entry with the
@@ -219,12 +222,19 @@ extern int zap_entry_create(zap_leaf_t *l,
zap_entry_handle_t *zeh);
/*
+ * Return true if there are additional entries with the same normalized
+ * form.
+ */
+extern boolean_t zap_entry_normalization_conflict(zap_entry_handle_t *zeh,
+ zap_name_t *zn, const char *name, zap_t *zap);
+
+/*
* Other stuff.
*/
-extern void zap_leaf_init(zap_leaf_t *l);
+extern void zap_leaf_init(zap_leaf_t *l, int version);
extern void zap_leaf_byteswap(zap_leaf_phys_t *buf, int len);
-extern void zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl);
+extern void zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl, int version);
extern void zap_leaf_stats(zap_t *zap, zap_leaf_t *l, zap_stats_t *zs);
#ifdef __cplusplus
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
index e3a653c5fa..6a7724cee4 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,6 +34,7 @@
#endif
#include <sys/acl.h>
#include <sys/dmu.h>
+#include <sys/zfs_fuid.h>
#ifdef __cplusplus
extern "C" {
@@ -44,30 +45,129 @@ struct znode_phys;
#define ACCESS_UNDETERMINED -1
#define ACE_SLOT_CNT 6
+#define ZFS_ACL_VERSION_INITIAL 0ULL
+#define ZFS_ACL_VERSION_FUID 1ULL
+#define ZFS_ACL_VERSION ZFS_ACL_VERSION_FUID
-typedef struct zfs_znode_acl {
+/*
+ * ZFS ACLs are store in various forms.
+ * Files created with ACL version ZFS_ACL_VERSION_INITIAL
+ * will all be created with fixed length ACEs of type
+ * zfs_oldace_t.
+ *
+ * Files with ACL version ZFS_ACL_VERSION_FUID will be created
+ * with various sized ACEs. The abstraction entries will utilize
+ * zfs_ace_hdr_t, normal user/group entries will use zfs_ace_t
+ * and some specialized CIFS ACEs will use zfs_object_ace_t.
+ */
+
+/*
+ * All ACEs have a common hdr. For
+ * owner@, group@, and everyone@ this is all
+ * thats needed.
+ */
+typedef struct zfs_ace_hdr {
+ uint16_t z_type;
+ uint16_t z_flags;
+ uint32_t z_access_mask;
+} zfs_ace_hdr_t;
+
+typedef zfs_ace_hdr_t zfs_ace_abstract_t;
+
+/*
+ * Standard ACE
+ */
+typedef struct zfs_ace {
+ zfs_ace_hdr_t z_hdr;
+ uint64_t z_fuid;
+} zfs_ace_t;
+
+/*
+ * The following type only applies to ACE_ACCESS_ALLOWED|DENIED_OBJECT_ACE_TYPE
+ * and will only be set/retrieved in a CIFS context.
+ */
+
+typedef struct zfs_object_ace {
+ zfs_ace_t z_ace;
+ uint8_t z_object_type[16]; /* object type */
+ uint8_t z_inherit_type[16]; /* inherited object type */
+} zfs_object_ace_t;
+
+typedef struct zfs_oldace {
+ uint32_t z_fuid; /* "who" */
+ uint32_t z_access_mask; /* access mask */
+ uint16_t z_flags; /* flags, i.e inheritance */
+ uint16_t z_type; /* type of entry allow/deny */
+} zfs_oldace_t;
+
+typedef struct zfs_acl_phys_v0 {
+ uint64_t z_acl_extern_obj; /* ext acl pieces */
+ uint32_t z_acl_count; /* Number of ACEs */
+ uint16_t z_acl_version; /* acl version */
+ uint16_t z_acl_pad; /* pad */
+ zfs_oldace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
+} zfs_acl_phys_v0_t;
+
+#define ZFS_ACE_SPACE (sizeof (zfs_oldace_t) * ACE_SLOT_CNT)
+
+typedef struct zfs_acl_phys {
uint64_t z_acl_extern_obj; /* ext acl pieces */
- uint32_t z_acl_count; /* Number of ACEs */
+ uint32_t z_acl_size; /* Number of bytes in ACL */
uint16_t z_acl_version; /* acl version */
- uint16_t z_acl_pad; /* pad */
- ace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */
-} zfs_znode_acl_t;
-
-#define ACL_DATA_ALLOCED 0x1
+ uint16_t z_acl_count; /* ace count */
+ uint8_t z_ace_data[ZFS_ACE_SPACE]; /* space for embedded ACEs */
+} zfs_acl_phys_t;
+
+
+
+typedef struct acl_ops {
+ uint32_t (*ace_mask_get) (void *acep); /* get access mask */
+ void (*ace_mask_set) (void *acep,
+ uint32_t mask); /* set access mask */
+ uint16_t (*ace_flags_get) (void *acep); /* get flags */
+ void (*ace_flags_set) (void *acep,
+ uint16_t flags); /* set flags */
+ uint16_t (*ace_type_get)(void *acep); /* get type */
+ void (*ace_type_set)(void *acep,
+ uint16_t type); /* set type */
+ uint64_t (*ace_who_get)(void *acep); /* get who/fuid */
+ void (*ace_who_set)(void *acep,
+ uint64_t who); /* set who/fuid */
+ size_t (*ace_size)(void *acep); /* how big is this ace */
+ size_t (*ace_abstract_size)(void); /* sizeof abstract entry */
+ int (*ace_mask_off)(void); /* off of access mask in ace */
+ int (*ace_data)(void *acep, void **datap);
+ /* ptr to data if any */
+} acl_ops_t;
/*
- * Max ACL size is prepended deny for all entries + the
- * canonical six tacked on * the end.
+ * A zfs_acl_t structure is composed of a list of zfs_acl_node_t's.
+ * Each node will have one or more ACEs associated with it. You will
+ * only have multiple nodes during a chmod operation. Normally only
+ * one node is required.
*/
-#define MAX_ACL_SIZE (MAX_ACL_ENTRIES * 2 + 6)
+typedef struct zfs_acl_node {
+ list_node_t z_next; /* Next chunk of ACEs */
+ void *z_acldata; /* pointer into actual ACE(s) */
+ void *z_allocdata; /* pointer to kmem allocated memory */
+ size_t z_allocsize; /* Size of blob in bytes */
+ size_t z_size; /* length of ACL data */
+ int z_ace_count; /* number of ACEs in this acl node */
+ int z_ace_idx; /* ace iterator positioned on */
+} zfs_acl_node_t;
typedef struct zfs_acl {
- int z_slots; /* number of allocated slots for ACEs */
- int z_acl_count;
- uint_t z_state;
- ace_t *z_acl;
+ int z_acl_count; /* Number of ACEs */
+ size_t z_acl_bytes; /* Number of bytes in ACL */
+ uint_t z_version; /* version of ACL */
+ void *z_next_ace; /* pointer to next ACE */
+ int z_hints; /* ACL hints (ZFS_INHERIT_ACE ...) */
+ zfs_acl_node_t *z_curr_node; /* current node iterator is handling */
+ list_t z_acl; /* chunks of ACE data */
+ acl_ops_t z_ops; /* ACL operations */
} zfs_acl_t;
+#define ACL_DATA_ALLOCED 0x1
#define ZFS_ACL_SIZE(aclcnt) (sizeof (ace_t) * (aclcnt))
/*
@@ -84,24 +184,26 @@ typedef struct zfs_acl {
#define ZFS_ACL_SECURE 4
struct znode;
+struct zfsvfs;
#ifdef _KERNEL
void zfs_perm_init(struct znode *, struct znode *, int, vattr_t *,
- dmu_tx_t *, cred_t *);
-int zfs_getacl(struct znode *, vsecattr_t *, cred_t *);
-int zfs_mode_update(struct znode *, uint64_t, dmu_tx_t *);
-int zfs_setacl(struct znode *, vsecattr_t *, cred_t *);
+ dmu_tx_t *, cred_t *, zfs_acl_t *, zfs_fuid_info_t **);
+int zfs_getacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
+int zfs_setacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
void zfs_acl_rele(void *);
-void zfs_ace_byteswap(ace_t *, int);
-extern int zfs_zaccess(struct znode *, int, cred_t *);
-extern int zfs_zaccess_rwx(struct znode *, mode_t, cred_t *);
+void zfs_oldace_byteswap(ace_t *, int);
+void zfs_ace_byteswap(void *, size_t, boolean_t);
+extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *);
+extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *);
+extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *);
extern int zfs_acl_access(struct znode *, int, cred_t *);
int zfs_acl_chmod_setattr(struct znode *, uint64_t, dmu_tx_t *);
int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *);
int zfs_zaccess_rename(struct znode *, struct znode *,
struct znode *, struct znode *, cred_t *cr);
-int zfs_zaccess_v4_perm(struct znode *, int, cred_t *);
void zfs_acl_free(zfs_acl_t *);
+int zfs_vsec_2_aclp(struct zfsvfs *, vtype_t, vsecattr_t *, zfs_acl_t **);
#endif
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h b/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h
index 8f1cb74d94..78f52bf22c 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ctldir.h
@@ -58,7 +58,8 @@ int zfsctl_umount_snapshots(vfs_t *, int, cred_t *);
int zfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr);
int zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr);
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp);
int zfsctl_make_fid(zfsvfs_t *zfsvfsp, uint64_t object, uint32_t gen,
fid_t *fidp);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_dir.h b/usr/src/uts/common/fs/zfs/sys/zfs_dir.h
index f60d614953..0ad129092c 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_dir.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_dir.h
@@ -28,6 +28,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
+#include <sys/pathname.h>
#include <sys/dmu.h>
#include <sys/zfs_znode.h>
@@ -41,6 +42,8 @@ extern "C" {
#define ZSHARED 0x0004 /* shared access (zfs_dirlook()) */
#define ZXATTR 0x0008 /* we want the xattr dir */
#define ZRENAMING 0x0010 /* znode is being renamed */
+#define ZCILOOK 0x0020 /* case-insensitive lookup requested */
+#define ZCIEXACT 0x0040 /* c-i requires c-s match (rename) */
/* mknode flags */
#define IS_ROOT_NODE 0x01 /* create a root node */
@@ -48,15 +51,18 @@ extern "C" {
#define IS_REPLAY 0x04 /* we are replaying intent log */
extern int zfs_dirent_lock(zfs_dirlock_t **, znode_t *, char *, znode_t **,
- int);
+ int, int *, pathname_t *);
extern void zfs_dirent_unlock(zfs_dirlock_t *);
extern int zfs_link_create(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int);
extern int zfs_link_destroy(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int,
boolean_t *);
-extern int zfs_dirlook(znode_t *, char *, vnode_t **);
+extern int zfs_dirlook(znode_t *, char *, vnode_t **, int, int *,
+ pathname_t *);
extern void zfs_mknode(znode_t *, vattr_t *, uint64_t *,
- dmu_tx_t *, cred_t *, uint_t, znode_t **, int);
+ dmu_tx_t *, cred_t *, uint_t, znode_t **, int,
+ zfs_acl_t *, zfs_fuid_info_t **);
extern void zfs_rmnode(znode_t *);
+extern void zfs_dl_name_switch(zfs_dirlock_t *dl, char *new, char **old);
extern boolean_t zfs_dirempty(znode_t *);
extern void zfs_unlinked_add(znode_t *, dmu_tx_t *);
extern void zfs_unlinked_drain(zfsvfs_t *zfsvfs);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h b/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h
new file mode 100644
index 0000000000..3f46ff7e3e
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_fuid.h
@@ -0,0 +1,131 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_FS_ZFS_FUID_H
+#define _SYS_FS_ZFS_FUID_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#include <sys/sid.h>
+#include <sys/dmu.h>
+#include <sys/zfs_vfsops.h>
+#endif
+
+#ifdef _KERNEL
+typedef struct zfs_fuid_hdl {
+ idmap_get_handle_t *z_hdl;
+ boolean_t z_map_needed; /* is mapping required */
+ idmap_stat z_status; /* needed for kidmap interface */
+} zfs_fuid_hdl_t;
+
+typedef enum {
+ ZFS_OWNER,
+ ZFS_GROUP,
+ ZFS_ACE_USER,
+ ZFS_ACE_GROUP
+} zfs_fuid_type_t;
+
+#endif
+
+
+#define FUID_INDEX(x) (x >> 32)
+#define FUID_RID(x) (x & 0xffffffff)
+#define FUID_ENCODE(idx, rid) ((idx << 32) | rid)
+/*
+ * FUIDs cause problems for the intent log
+ * we need to replay the creation of the FUID,
+ * but we can't count on the idmapper to be around
+ * and during replay the FUID index may be different than
+ * before. Also, if an ACL has 100 ACEs and 12 different
+ * domains we don't want to log 100 domain strings, but rather
+ * just the unique 12.
+ */
+
+/*
+ * The FUIDs in the log will index into
+ * domain string table and the bottom half will be the rid.
+ * Used for mapping ephemeral uid/gid during ACL setting to FUIDs
+ */
+typedef struct zfs_fuid {
+ list_node_t z_next;
+ uint64_t z_id; /* uid/gid being converted to fuid */
+ uint64_t z_domidx; /* index in AVL domain table */
+ uint64_t z_logfuid; /* index for domain in log */
+} zfs_fuid_t;
+
+/* list of unique domains */
+typedef struct zfs_fuid_domain {
+ list_node_t z_next;
+ uint64_t z_domidx; /* AVL tree idx */
+ const char *z_domain; /* domain string */
+} zfs_fuid_domain_t;
+
+/*
+ * FUID information necessary for logging create, setattr, and setacl.
+ */
+typedef struct zfs_fuid_info {
+ list_t z_fuids;
+ list_t z_domains;
+ uint64_t z_fuid_owner;
+ uint64_t z_fuid_group;
+ char **z_domain_table; /* Used during replay */
+ uint32_t z_fuid_cnt; /* How many fuids in z_fuids */
+ uint32_t z_domain_cnt; /* How many domains */
+ size_t z_domain_str_sz; /* len of domain strings z_domain list */
+} zfs_fuid_info_t;
+
+#ifdef _KERNEL
+struct znode;
+extern void zfs_fuid_map_id(zfsvfs_t *, uint64_t, zfs_fuid_type_t, uid_t *);
+extern void zfs_fuid_destroy(zfsvfs_t *);
+extern uint64_t zfs_fuid_create_cred(zfsvfs_t *, uint64_t, zfs_fuid_type_t,
+ dmu_tx_t *, cred_t *, zfs_fuid_info_t **);
+extern uint64_t zfs_fuid_create(zfsvfs_t *, uint64_t, zfs_fuid_type_t,
+ dmu_tx_t *, zfs_fuid_info_t **);
+extern void zfs_fuid_queue_map_id(zfsvfs_t *zfsvfs, zfs_fuid_hdl_t *,
+ uint64_t, zfs_fuid_type_t, uid_t *);
+extern void zfs_fuid_map_ids(struct znode *zp, uid_t *uid, uid_t *gid);
+extern void zfs_fuid_get_mappings(zfs_fuid_hdl_t *);
+extern char *zfs_fuid_find_by_idx(zfsvfs_t *, uint64_t);
+int zfs_fuid_find_by_domain(zfsvfs_t *, const char *, char **, dmu_tx_t *);
+extern zfs_fuid_info_t *zfs_fuid_info_alloc(void);
+extern void zfs_fuid_info_free();
+extern boolean_t zfs_groupmember(zfsvfs_t *, uint64_t, cred_t *);
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_FS_ZFS_FUID_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_i18n.h b/usr/src/uts/common/fs/zfs/sys/zfs_i18n.h
new file mode 100644
index 0000000000..96fe54a230
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_i18n.h
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_ZFS_I18N_H
+#define _SYS_ZFS_I18N_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sunddi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * z_case behaviors
+ * The first two describe the extent of case insensitivity.
+ * The third describes matching behavior when mixed sensitivity
+ * is allowed.
+ */
+#define ZFS_CI_ONLY 0x01 /* all lookups case-insensitive */
+#define ZFS_CI_MIXD 0x02 /* some lookups case-insensitive */
+
+/*
+ * ZFS_UTF8_ONLY
+ * If set, the file system should reject non-utf8 characters in names.
+ */
+#define ZFS_UTF8_ONLY 0x04
+
+enum zfs_case {
+ ZFS_CASE_SENSITIVE,
+ ZFS_CASE_INSENSITIVE,
+ ZFS_CASE_MIXED
+};
+
+enum zfs_normal {
+ ZFS_NORMALIZE_NONE,
+ ZFS_NORMALIZE_D,
+ ZFS_NORMALIZE_KC,
+ ZFS_NORMALIZE_C,
+ ZFS_NORMALIZE_KD
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZFS_I18N_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
index e1bb9f0514..93c8d76bc0 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -33,6 +33,10 @@
#include <sys/zio.h>
#include <sys/dsl_deleg.h>
+#ifdef _KERNEL
+#include <sys/nvpair.h>
+#endif /* _KERNEL */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -152,6 +156,11 @@ typedef struct zfs_cmd {
#ifdef _KERNEL
+typedef struct zfs_creat {
+ int zct_norm;
+ nvlist_t *zct_props;
+} zfs_creat_t;
+
extern dev_info_t *zfs_dip;
extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr);
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
index ea55a86b9e..b21dadaa15 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
@@ -49,9 +49,17 @@ struct zfsvfs {
uint64_t z_unlinkedobj; /* id of unlinked zapobj */
uint64_t z_max_blksz; /* maximum block size for files */
uint64_t z_assign; /* TXG_NOWAIT or set by zil_replay() */
+ uint64_t z_fuid_obj; /* fuid table object number */
+ avl_tree_t z_fuid_idx; /* fuid tree keyed by index */
+ avl_tree_t z_fuid_domain; /* fuid tree keyed by domain */
+ krwlock_t z_fuid_lock; /* fuid lock */
+ boolean_t z_fuid_loaded; /* fuid tables are loaded */
+ struct zfs_fuid_info *z_fuid_replay; /* fuid info for replay */
zilog_t *z_log; /* intent log pointer */
uint_t z_acl_mode; /* acl chmod/mode behavior */
uint_t z_acl_inherit; /* acl inheritance behavior */
+ uint_t z_case; /* case-insensitive behavior */
+ int z_norm; /* normalization flags */
boolean_t z_atime; /* enable atimes mount option */
boolean_t z_unmounted; /* unmounted */
rrwlock_t z_teardown_lock;
@@ -61,6 +69,8 @@ struct zfsvfs {
vnode_t *z_ctldir; /* .zfs directory pointer */
boolean_t z_show_ctldir; /* expose .zfs in the root dir */
boolean_t z_issnap; /* true if this is a snapshot */
+ boolean_t z_vscan; /* virus scan on/off */
+ boolean_t z_use_fuids; /* version allows fuids */
uint64_t z_version;
#define ZFS_OBJ_MTX_SZ 64
kmutex_t z_hold_mtx[ZFS_OBJ_MTX_SZ]; /* znode hold locks */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
index 8b4ee46218..b9e0c95290 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
@@ -31,6 +31,7 @@
#ifdef _KERNEL
#include <sys/isa_defs.h>
#include <sys/types32.h>
+#include <sys/attr.h>
#include <sys/list.h>
#include <sys/dmu.h>
#include <sys/zfs_vfsops.h>
@@ -44,21 +45,62 @@ extern "C" {
#endif
/*
+ * Additional file level attributes, that are stored
+ * in the upper half of zp_flags
+ */
+#define ZFS_READONLY 0x0000000100000000
+#define ZFS_HIDDEN 0x0000000200000000
+#define ZFS_SYSTEM 0x0000000400000000
+#define ZFS_ARCHIVE 0x0000000800000000
+#define ZFS_IMMUTABLE 0x0000001000000000
+#define ZFS_NOUNLINK 0x0000002000000000
+#define ZFS_APPENDONLY 0x0000004000000000
+#define ZFS_NODUMP 0x0000008000000000
+#define ZFS_OPAQUE 0x0000010000000000
+#define ZFS_AV_QUARANTINED 0x0000020000000000
+#define ZFS_AV_MODIFIED 0x0000040000000000
+
+#define ZFS_ATTR_SET(zp, attr, value) \
+{ \
+ if (value) \
+ zp->z_phys->zp_flags |= attr; \
+ else \
+ zp->z_phys->zp_flags &= ~attr; \
+}
+
+/*
* Define special zfs pflags
*/
-#define ZFS_XATTR 0x1 /* is an extended attribute */
-#define ZFS_INHERIT_ACE 0x2 /* ace has inheritable ACEs */
-#define ZFS_ACL_TRIVIAL 0x4 /* files ACL is trivial */
+#define ZFS_XATTR 0x1 /* is an extended attribute */
+#define ZFS_INHERIT_ACE 0x2 /* ace has inheritable ACEs */
+#define ZFS_ACL_TRIVIAL 0x4 /* files ACL is trivial */
+#define ZFS_ACL_OBJ_ACE 0x8 /* ACL has CMPLX Object ACE */
+#define ZFS_ACL_PROTECTED 0x10 /* ACL protected */
+#define ZFS_ACL_DEFAULTED 0x20 /* ACL should be defaulted */
+#define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */
+#define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */
+
+/*
+ * Is ID ephemeral?
+ */
+#define IS_EPHEMERAL(x) (x > MAXUID)
+
+/*
+ * Should we use FUIDs?
+ */
+#define USE_FUIDS(version, os) (version >= ZPL_VERSION_FUID &&\
+ spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
#define MASTER_NODE_OBJ 1
/*
- * special attributes for master node.
+ * Special attributes for master node.
*/
#define ZFS_FSID "FSID"
#define ZFS_UNLINKED_SET "DELETE_QUEUE"
#define ZFS_ROOT_OBJ "ROOT"
#define ZPL_VERSION_STR "VERSION"
+#define ZFS_FUID_TABLES "FUID"
#define ZFS_MAX_BLOCKSIZE (SPA_MAXBLOCKSIZE)
@@ -107,8 +149,9 @@ typedef struct znode_phys {
uint64_t zp_flags; /* 120 - persistent flags */
uint64_t zp_uid; /* 128 - file owner */
uint64_t zp_gid; /* 136 - owning group */
- uint64_t zp_pad[4]; /* 144 - future */
- zfs_znode_acl_t zp_acl; /* 176 - 263 ACL */
+ uint64_t zp_zap; /* 144 - extra attributes */
+ uint64_t zp_pad[3]; /* 152 - future */
+ zfs_acl_phys_t zp_acl; /* 176 - 263 ACL */
/*
* Data may pad out any remaining bytes in the znode buffer, eg:
*
@@ -116,7 +159,9 @@ typedef struct znode_phys {
* |<-- dnode (192) --->|<----------- "bonus" buffer (320) ---------->|
* |<---- znode (264) ---->|<---- data (56) ---->|
*
- * At present, we only use this space to store symbolic links.
+ * At present, we use this space for the following:
+ * - symbolic links
+ * - 32-byte anti-virus scanstamp (regular files only)
*/
} znode_phys_t;
@@ -253,7 +298,8 @@ typedef struct znode {
extern int zfs_init_fs(zfsvfs_t *, znode_t **, cred_t *);
extern void zfs_set_dataprop(objset_t *);
-extern void zfs_create_fs(objset_t *os, cred_t *cr, uint64_t, dmu_tx_t *tx);
+extern void zfs_create_fs(objset_t *os, cred_t *cr, uint64_t, int,
+ dmu_tx_t *tx);
extern void zfs_time_stamper(znode_t *, uint_t, dmu_tx_t *);
extern void zfs_time_stamper_locked(znode_t *, uint_t, dmu_tx_t *);
extern void zfs_grow_blocksize(znode_t *, uint64_t, dmu_tx_t *);
@@ -271,25 +317,31 @@ extern int zfs_sync(vfs_t *vfsp, short flag, cred_t *cr);
extern dev_t zfs_cmpldev(uint64_t);
extern int zfs_get_version(objset_t *os, uint64_t *version);
extern int zfs_set_version(const char *name, uint64_t newvers);
-
-extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *dzp, znode_t *zp, char *name);
-extern void zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern int zfs_get_stats(objset_t *os, nvlist_t *nv);
+
+extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+ znode_t *dzp, znode_t *zp, char *name, vsecattr_t *, zfs_fuid_info_t *,
+ vattr_t *vap);
+extern int zfs_log_create_txtype(zil_create_t, vsecattr_t *vsecp,
+ vattr_t *vap);
+extern void zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, char *name);
-extern void zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern void zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name);
-extern void zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern void zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name, char *link);
-extern void zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+extern void zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *sdzp, char *sname, znode_t *tdzp, char *dname, znode_t *szp);
extern void zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
znode_t *zp, offset_t off, ssize_t len, int ioflag);
extern void zfs_log_truncate(zilog_t *zilog, dmu_tx_t *tx, int txtype,
znode_t *zp, uint64_t off, uint64_t len);
extern void zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, vattr_t *vap, uint_t mask_applied);
-extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, int aclcnt, ace_t *z_ace);
+ znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp);
+extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
+ vsecattr_t *vsecp, zfs_fuid_info_t *fuidp);
+extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap);
+extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx);
extern zil_get_data_t zfs_get_data;
extern zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE];
diff --git a/usr/src/uts/common/fs/zfs/sys/zil.h b/usr/src/uts/common/fs/zfs/sys/zil.h
index 55de6b6f27..b5b665c26c 100644
--- a/usr/src/uts/common/fs/zfs/sys/zil.h
+++ b/usr/src/uts/common/fs/zfs/sys/zil.h
@@ -88,22 +88,53 @@ typedef struct zil_trailer {
#define ZIL_ZC_OBJSET 2
#define ZIL_ZC_SEQ 3
+typedef enum zil_create {
+ Z_FILE,
+ Z_DIR,
+ Z_XATTRDIR,
+} zil_create_t;
+
+/*
+ * size of xvattr log section.
+ * its composed of lr_attr_t + xvattr bitmap + 2 64 bit timestamps
+ * for create time and a single 64 bit integer for all of the attributes,
+ * and 4 64 bit integers (32 bytes) for the scanstamp.
+ *
+ */
+
+#define ZIL_XVAT_SIZE(mapsize) \
+ sizeof (lr_attr_t) + (sizeof (uint32_t) * (mapsize - 1)) + \
+ (sizeof (uint64_t) * 7)
/*
* Intent log transaction types and record structures
*/
-#define TX_CREATE 1 /* Create file */
-#define TX_MKDIR 2 /* Make directory */
-#define TX_MKXATTR 3 /* Make XATTR directory */
-#define TX_SYMLINK 4 /* Create symbolic link to a file */
-#define TX_REMOVE 5 /* Remove file */
-#define TX_RMDIR 6 /* Remove directory */
-#define TX_LINK 7 /* Create hard link to a file */
-#define TX_RENAME 8 /* Rename a file */
-#define TX_WRITE 9 /* File write */
-#define TX_TRUNCATE 10 /* Truncate a file */
-#define TX_SETATTR 11 /* Set file attributes */
-#define TX_ACL 12 /* Set acl */
-#define TX_MAX_TYPE 13 /* Max transaction type */
+#define TX_CREATE 1 /* Create file */
+#define TX_MKDIR 2 /* Make directory */
+#define TX_MKXATTR 3 /* Make XATTR directory */
+#define TX_SYMLINK 4 /* Create symbolic link to a file */
+#define TX_REMOVE 5 /* Remove file */
+#define TX_RMDIR 6 /* Remove directory */
+#define TX_LINK 7 /* Create hard link to a file */
+#define TX_RENAME 8 /* Rename a file */
+#define TX_WRITE 9 /* File write */
+#define TX_TRUNCATE 10 /* Truncate a file */
+#define TX_SETATTR 11 /* Set file attributes */
+#define TX_ACL_V0 12 /* Set old formatted ACL */
+#define TX_ACL 13 /* Set ACL */
+#define TX_CREATE_ACL 14 /* create with ACL */
+#define TX_CREATE_ATTR 15 /* create + attrs */
+#define TX_CREATE_ACL_ATTR 16 /* create with ACL + attrs */
+#define TX_MKDIR_ACL 17 /* mkdir with ACL */
+#define TX_MKDIR_ATTR 18 /* mkdir with attr */
+#define TX_MKDIR_ACL_ATTR 19 /* mkdir with ACL + attrs */
+#define TX_MAX_TYPE 20 /* Max transaction type */
+
+/*
+ * The transactions for mkdir, symlink, remove, rmdir, link, and rename
+ * may have the following bit set, indicating the original request
+ * specified case-insensitive handling of names.
+ */
+#define TX_CI ((uint64_t)0x1 << 63) /* case-insensitive behavior requested */
/*
* Format of log records.
@@ -124,6 +155,23 @@ typedef struct { /* common log record header */
uint64_t lrc_seq; /* see comment above */
} lr_t;
+/*
+ * Handle option extended vattr attributes.
+ *
+ * Whenever new attributes are added the version number
+ * will need to be updated as will code in
+ * zfs_log.c and zfs_replay.c
+ */
+typedef struct {
+ uint32_t lr_attr_masksize; /* number of elements in array */
+ uint32_t lr_attr_bitmap; /* First entry of array */
+ /* remainder of array and any additional fields */
+} lr_attr_t;
+
+/*
+ * log record for creates without optional ACL.
+ * This log record does support optional xvattr_t attributes.
+ */
typedef struct {
lr_t lr_common; /* common portion of log record */
uint64_t lr_doid; /* object id of directory */
@@ -136,8 +184,42 @@ typedef struct {
uint64_t lr_rdev; /* rdev of object to create */
/* name of object to create follows this */
/* for symlinks, link content follows name */
+ /* for creates with xvattr data, the name follows the xvattr info */
} lr_create_t;
+/*
+ * FUID ACL record will be an array of ACEs from the original ACL.
+ * If this array includes ephemeral IDs, the record will also include
+ * an array of log-specific FUIDs to replace the ephemeral IDs.
+ * Only one copy of each unique domain will be present, so the log-specific
+ * FUIDs will use an index into a compressed domain table. On replay this
+ * information will be used to construct real FUIDs (and bypass idmap,
+ * since it may not be available).
+ */
+
+/*
+ * Log record for creates with optional ACL
+ * This log record is also used for recording any FUID
+ * information needed for replaying the create. If the
+ * file doesn't have any actual ACEs then the lr_aclcnt
+ * would be zero.
+ */
+typedef struct {
+ lr_create_t lr_create; /* common create portion */
+ uint64_t lr_aclcnt; /* number of ACEs in ACL */
+ uint64_t lr_domcnt; /* number of unique domains */
+ uint64_t lr_fuidcnt; /* number of real fuids */
+ uint64_t lr_acl_bytes; /* number of bytes in ACL */
+ uint64_t lr_acl_flags; /* ACL flags */
+ /* lr_acl_bytes number of variable sized ace's follows */
+ /* if create is also setting xvattr's, then acl data follows xvattr */
+ /* if ACE FUIDs are needed then they will follow the xvattr_t */
+ /* Following the FUIDs will be the domain table information. */
+ /* The FUIDs for the owner and group will be in the lr_create */
+ /* portion of the record. */
+ /* name follows ACL data */
+} lr_acl_create_t;
+
typedef struct {
lr_t lr_common; /* common portion of log record */
uint64_t lr_doid; /* obj id of directory */
@@ -185,6 +267,7 @@ typedef struct {
uint64_t lr_size; /* size to set */
uint64_t lr_atime[2]; /* access time */
uint64_t lr_mtime[2]; /* modification time */
+ /* optional attribute lr_attr_t may be here */
} lr_setattr_t;
typedef struct {
@@ -192,6 +275,17 @@ typedef struct {
uint64_t lr_foid; /* obj id of file */
uint64_t lr_aclcnt; /* number of acl entries */
/* lr_aclcnt number of ace_t entries follow this */
+} lr_acl_v0_t;
+
+typedef struct {
+ lr_t lr_common; /* common portion of log record */
+ uint64_t lr_foid; /* obj id of file */
+ uint64_t lr_aclcnt; /* number of ACEs in ACL */
+ uint64_t lr_domcnt; /* number of unique domains */
+ uint64_t lr_fuidcnt; /* number of real fuids */
+ uint64_t lr_acl_bytes; /* number of bytes in ACL */
+ uint64_t lr_acl_flags; /* ACL flags */
+ /* lr_acl_bytes number of variable sized ace's follows */
} lr_acl_t;
/*
@@ -253,7 +347,7 @@ extern void zil_replay(objset_t *os, void *arg, uint64_t *txgp,
extern void zil_destroy(zilog_t *zilog, boolean_t keep_first);
extern void zil_rollback_destroy(zilog_t *zilog, dmu_tx_t *tx);
-extern itx_t *zil_itx_create(int txtype, size_t lrsize);
+extern itx_t *zil_itx_create(uint64_t txtype, size_t lrsize);
extern uint64_t zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx);
extern void zil_commit(zilog_t *zilog, uint64_t seq, uint64_t oid);
diff --git a/usr/src/uts/common/fs/zfs/vdev_file.c b/usr/src/uts/common/fs/zfs/vdev_file.c
index 6f099b6629..b212161c64 100644
--- a/usr/src/uts/common/fs/zfs/vdev_file.c
+++ b/usr/src/uts/common/fs/zfs/vdev_file.c
@@ -61,7 +61,7 @@ vdev_file_open_common(vdev_t *vd)
*/
ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE,
- spa_mode | FOFFMAX, 0, &vp, 0, 0, rootdir);
+ spa_mode | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
if (error) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
@@ -99,7 +99,7 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
* Determine the physical size of the file.
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred);
+ error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL);
if (error) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
return (error);
@@ -120,8 +120,8 @@ vdev_file_close(vdev_t *vd)
return;
if (vf->vf_vnode != NULL) {
- (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred);
- (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred);
+ (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
+ (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred, NULL);
VN_RELE(vf->vf_vnode);
}
@@ -233,7 +233,7 @@ vdev_file_io_start(zio_t *zio)
switch (zio->io_cmd) {
case DKIOCFLUSHWRITECACHE:
zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC,
- kcred);
+ kcred, NULL);
dprintf("fsync(%s) = %d\n", vdev_description(vd),
zio->io_error);
break;
diff --git a/usr/src/uts/common/fs/zfs/zap.c b/usr/src/uts/common/fs/zfs/zap.c
index 7dfe44baba..db0162b0ee 100644
--- a/usr/src/uts/common/fs/zfs/zap.c
+++ b/usr/src/uts/common/fs/zfs/zap.c
@@ -102,6 +102,7 @@ fzap_upgrade(zap_t *zap, dmu_tx_t *tx)
zp->zap_num_leafs = 1;
zp->zap_num_entries = 0;
zp->zap_salt = zap->zap_salt;
+ zp->zap_normflags = zap->zap_normflags;
/* block 1 will be the first leaf */
for (i = 0; i < (1<<zp->zap_ptrtbl.zt_shift); i++)
@@ -118,7 +119,7 @@ fzap_upgrade(zap_t *zap, dmu_tx_t *tx)
l->l_dbuf = db;
l->l_phys = db->db_data;
- zap_leaf_init(l);
+ zap_leaf_init(l, spa_version(dmu_objset_spa(zap->zap_objset)));
kmem_free(l, sizeof (zap_leaf_t));
dmu_buf_rele(db, FTAG);
@@ -398,7 +399,7 @@ zap_create_leaf(zap_t *zap, dmu_tx_t *tx)
ASSERT(winner == NULL);
dmu_buf_will_dirty(l->l_dbuf, tx);
- zap_leaf_init(l);
+ zap_leaf_init(l, spa_version(dmu_objset_spa(zap->zap_objset)));
zap->zap_f.zap_phys->zap_num_leafs++;
@@ -642,7 +643,7 @@ zap_expand_leaf(zap_t *zap, zap_leaf_t *l, uint64_t hash, dmu_tx_t *tx,
}
nl = zap_create_leaf(zap, tx);
- zap_leaf_split(l, nl);
+ zap_leaf_split(l, nl, spa_version(dmu_objset_spa(zap->zap_objset)));
/* set sibling pointers */
for (i = 0; i < (1ULL<<prefix_diff); i++) {
@@ -720,53 +721,58 @@ fzap_checksize(const char *name, uint64_t integer_size, uint64_t num_integers)
}
/*
- * Routines for maniplulating attributes.
+ * Routines for manipulating attributes.
*/
int
-fzap_lookup(zap_t *zap, const char *name,
- uint64_t integer_size, uint64_t num_integers, void *buf)
+fzap_lookup(zap_name_t *zn,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ char *realname, int rn_len, boolean_t *ncp)
{
zap_leaf_t *l;
int err;
- uint64_t hash;
zap_entry_handle_t zeh;
- err = fzap_checksize(name, integer_size, num_integers);
+ err = fzap_checksize(zn->zn_name_orij, integer_size, num_integers);
if (err != 0)
return (err);
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, NULL, RW_READER, &l);
+ err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, NULL, RW_READER, &l);
if (err != 0)
return (err);
- err = zap_leaf_lookup(l, name, hash, &zeh);
- if (err == 0)
+ err = zap_leaf_lookup(l, zn, &zeh);
+ if (err == 0) {
err = zap_entry_read(&zeh, integer_size, num_integers, buf);
+ (void) zap_entry_read_name(&zeh, rn_len, realname);
+ if (ncp) {
+ *ncp = zap_entry_normalization_conflict(&zeh,
+ zn, NULL, zn->zn_zap);
+ }
+ }
zap_put_leaf(l);
return (err);
}
int
-fzap_add_cd(zap_t *zap, const char *name,
+fzap_add_cd(zap_name_t *zn,
uint64_t integer_size, uint64_t num_integers,
const void *val, uint32_t cd, dmu_tx_t *tx)
{
zap_leaf_t *l;
- uint64_t hash;
int err;
zap_entry_handle_t zeh;
+ zap_t *zap = zn->zn_zap;
ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
ASSERT(!zap->zap_ismicro);
- ASSERT(fzap_checksize(name, integer_size, num_integers) == 0);
+ ASSERT(fzap_checksize(zn->zn_name_orij,
+ integer_size, num_integers) == 0);
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+ err = zap_deref_leaf(zap, zn->zn_hash, tx, RW_WRITER, &l);
if (err != 0)
return (err);
retry:
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
if (err == 0) {
err = EEXIST;
goto out;
@@ -774,13 +780,13 @@ retry:
if (err != ENOENT)
goto out;
- err = zap_entry_create(l, name, hash, cd,
+ err = zap_entry_create(l, zn->zn_name_orij, zn->zn_hash, cd,
integer_size, num_integers, val, &zeh);
if (err == 0) {
zap_increment_num_entries(zap, 1, tx);
} else if (err == EAGAIN) {
- err = zap_expand_leaf(zap, l, hash, tx, &l);
+ err = zap_expand_leaf(zap, l, zn->zn_hash, tx, &l);
if (err == 0)
goto retry;
}
@@ -791,46 +797,43 @@ out:
}
int
-fzap_add(zap_t *zap, const char *name,
+fzap_add(zap_name_t *zn,
uint64_t integer_size, uint64_t num_integers,
const void *val, dmu_tx_t *tx)
{
- int err = fzap_checksize(name, integer_size, num_integers);
+ int err = fzap_checksize(zn->zn_name_orij, integer_size, num_integers);
if (err != 0)
return (err);
- return (fzap_add_cd(zap, name, integer_size, num_integers,
+ return (fzap_add_cd(zn, integer_size, num_integers,
val, ZAP_MAXCD, tx));
}
int
-fzap_update(zap_t *zap, const char *name,
+fzap_update(zap_name_t *zn,
int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx)
{
zap_leaf_t *l;
- uint64_t hash;
int err, create;
zap_entry_handle_t zeh;
+ zap_t *zap = zn->zn_zap;
ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
- err = fzap_checksize(name, integer_size, num_integers);
+ err = fzap_checksize(zn->zn_name_orij, integer_size, num_integers);
if (err != 0)
return (err);
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+ err = zap_deref_leaf(zap, zn->zn_hash, tx, RW_WRITER, &l);
if (err != 0)
return (err);
retry:
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
create = (err == ENOENT);
ASSERT(err == 0 || err == ENOENT);
- /* XXX If this leaf is chained, split it if we can. */
-
if (create) {
- err = zap_entry_create(l, name, hash, ZAP_MAXCD,
- integer_size, num_integers, val, &zeh);
+ err = zap_entry_create(l, zn->zn_name_orij, zn->zn_hash,
+ ZAP_MAXCD, integer_size, num_integers, val, &zeh);
if (err == 0)
zap_increment_num_entries(zap, 1, tx);
} else {
@@ -838,7 +841,7 @@ retry:
}
if (err == EAGAIN) {
- err = zap_expand_leaf(zap, l, hash, tx, &l);
+ err = zap_expand_leaf(zap, l, zn->zn_hash, tx, &l);
if (err == 0)
goto retry;
}
@@ -848,19 +851,17 @@ retry:
}
int
-fzap_length(zap_t *zap, const char *name,
+fzap_length(zap_name_t *zn,
uint64_t *integer_size, uint64_t *num_integers)
{
zap_leaf_t *l;
int err;
- uint64_t hash;
zap_entry_handle_t zeh;
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, NULL, RW_READER, &l);
+ err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, NULL, RW_READER, &l);
if (err != 0)
return (err);
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
if (err != 0)
goto out;
@@ -874,25 +875,21 @@ out:
}
int
-fzap_remove(zap_t *zap, const char *name, dmu_tx_t *tx)
+fzap_remove(zap_name_t *zn, dmu_tx_t *tx)
{
zap_leaf_t *l;
- uint64_t hash;
int err;
zap_entry_handle_t zeh;
- hash = zap_hash(zap, name);
- err = zap_deref_leaf(zap, hash, tx, RW_WRITER, &l);
+ err = zap_deref_leaf(zn->zn_zap, zn->zn_hash, tx, RW_WRITER, &l);
if (err != 0)
return (err);
- err = zap_leaf_lookup(l, name, hash, &zeh);
+ err = zap_leaf_lookup(l, zn, &zeh);
if (err == 0) {
zap_entry_remove(&zeh);
- zap_increment_num_entries(zap, -1, tx);
+ zap_increment_num_entries(zn->zn_zap, -1, tx);
}
zap_put_leaf(l);
- dprintf("fzap_remove: ds=%p obj=%llu name=%s err=%d\n",
- zap->zap_objset, zap->zap_object, name, err);
return (err);
}
@@ -986,6 +983,10 @@ again:
err = zap_entry_read_name(&zeh,
sizeof (za->za_name), za->za_name);
ASSERT(err == 0);
+
+ za->za_normalization_conflict =
+ zap_entry_normalization_conflict(&zeh,
+ NULL, za->za_name, zap);
}
rw_exit(&zc->zc_leaf->l_rwlock);
return (err);
diff --git a/usr/src/uts/common/fs/zfs/zap_leaf.c b/usr/src/uts/common/fs/zfs/zap_leaf.c
index 5dff514530..d048bbc77c 100644
--- a/usr/src/uts/common/fs/zfs/zap_leaf.c
+++ b/usr/src/uts/common/fs/zfs/zap_leaf.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -38,6 +38,8 @@
#include <sys/spa.h>
#include <sys/dmu.h>
+static uint16_t *zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry);
+
#define CHAIN_END 0xffff /* end of the chunk chain */
/* half the (current) minimum block size */
@@ -150,7 +152,7 @@ zap_leaf_byteswap(zap_leaf_phys_t *buf, int size)
}
void
-zap_leaf_init(zap_leaf_t *l)
+zap_leaf_init(zap_leaf_t *l, int version)
{
int i;
@@ -165,6 +167,8 @@ zap_leaf_init(zap_leaf_t *l)
l->l_phys->l_hdr.lh_block_type = ZBT_LEAF;
l->l_phys->l_hdr.lh_magic = ZAP_LEAF_MAGIC;
l->l_phys->l_hdr.lh_nfree = ZAP_LEAF_NUMCHUNKS(l);
+ if (version >= SPA_VERSION_NORMALIZATION)
+ l->l_phys->l_hdr.lh_flags |= ZLF_ENTRIES_CDSORTED;
}
/*
@@ -327,19 +331,30 @@ zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
/*
* Only to be used on 8-bit arrays.
* array_len is actual len in bytes (not encoded le_value_length).
- * buf is null-terminated.
+ * namenorm is null-terminated.
*/
-static int
-zap_leaf_array_equal(zap_leaf_t *l, int chunk,
- int array_len, const char *buf)
+static boolean_t
+zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn, int chunk, int array_len)
{
int bseen = 0;
+ if (zn->zn_matchtype == MT_FIRST) {
+ char *thisname = kmem_alloc(array_len, KM_SLEEP);
+ boolean_t match;
+
+ zap_leaf_array_read(l, chunk, 1, array_len, 1,
+ array_len, thisname);
+ match = zap_match(zn, thisname);
+ kmem_free(thisname, array_len);
+ return (match);
+ }
+
+ /* Fast path for exact matching */
while (bseen < array_len) {
struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
int toread = MIN(array_len - bseen, ZAP_LEAF_ARRAY_BYTES);
ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
- if (bcmp(la->la_array, buf + bseen, toread))
+ if (bcmp(la->la_array, zn->zn_name_orij + bseen, toread))
break;
chunk = la->la_next;
bseen += toread;
@@ -352,15 +367,15 @@ zap_leaf_array_equal(zap_leaf_t *l, int chunk,
*/
int
-zap_leaf_lookup(zap_leaf_t *l,
- const char *name, uint64_t h, zap_entry_handle_t *zeh)
+zap_leaf_lookup(zap_leaf_t *l, zap_name_t *zn, zap_entry_handle_t *zeh)
{
uint16_t *chunkp;
struct zap_leaf_entry *le;
ASSERT3U(l->l_phys->l_hdr.lh_magic, ==, ZAP_LEAF_MAGIC);
- for (chunkp = LEAF_HASH_ENTPTR(l, h);
+again:
+ for (chunkp = LEAF_HASH_ENTPTR(l, zn->zn_hash);
*chunkp != CHAIN_END; chunkp = &le->le_next) {
uint16_t chunk = *chunkp;
le = ZAP_LEAF_ENTRY(l, chunk);
@@ -368,11 +383,18 @@ zap_leaf_lookup(zap_leaf_t *l,
ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
- if (le->le_hash != h)
+ if (le->le_hash != zn->zn_hash)
continue;
- if (zap_leaf_array_equal(l, le->le_name_chunk,
- le->le_name_length, name)) {
+ /*
+ * NB: the entry chain is always sorted by cd on
+ * normalized zap objects, so this will find the
+ * lowest-cd match for MT_FIRST.
+ */
+ ASSERT(zn->zn_matchtype == MT_EXACT ||
+ (l->l_phys->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED));
+ if (zap_leaf_array_match(l, zn, le->le_name_chunk,
+ le->le_name_length)) {
zeh->zeh_num_integers = le->le_value_length;
zeh->zeh_integer_size = le->le_int_size;
zeh->zeh_cd = le->le_cd;
@@ -383,6 +405,15 @@ zap_leaf_lookup(zap_leaf_t *l,
}
}
+ /*
+ * NB: we could of course do this in one pass, but that would be
+ * a pain. We'll see if MT_BEST is even used much.
+ */
+ if (zn->zn_matchtype == MT_BEST) {
+ zn->zn_matchtype = MT_FIRST;
+ goto again;
+ }
+
return (ENOENT);
}
@@ -539,22 +570,41 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
return (E2BIG);
if (cd == ZAP_MAXCD) {
- for (cd = 0; cd < ZAP_MAXCD; cd++) {
+ /* find the lowest unused cd */
+ if (l->l_phys->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED) {
+ cd = 0;
+
for (chunk = *LEAF_HASH_ENTPTR(l, h);
chunk != CHAIN_END; chunk = le->le_next) {
le = ZAP_LEAF_ENTRY(l, chunk);
- if (le->le_hash == h &&
- le->le_cd == cd) {
+ if (le->le_cd > cd)
break;
+ if (le->le_hash == h) {
+ ASSERT3U(cd, ==, le->le_cd);
+ cd++;
}
}
- /* If this cd is not in use, we are good. */
- if (chunk == CHAIN_END)
- break;
+ } else {
+ /* old unsorted format; do it the O(n^2) way */
+ for (cd = 0; cd < ZAP_MAXCD; cd++) {
+ for (chunk = *LEAF_HASH_ENTPTR(l, h);
+ chunk != CHAIN_END; chunk = le->le_next) {
+ le = ZAP_LEAF_ENTRY(l, chunk);
+ if (le->le_hash == h &&
+ le->le_cd == cd) {
+ break;
+ }
+ }
+ /* If this cd is not in use, we are good. */
+ if (chunk == CHAIN_END)
+ break;
+ }
}
- /* If we tried all the cd's, we lose. */
- if (cd == ZAP_MAXCD)
- return (ENOSPC);
+ /*
+ * we would run out of space in a block before we could
+ * have ZAP_MAXCD entries
+ */
+ ASSERT3U(cd, <, ZAP_MAXCD);
}
if (l->l_phys->l_hdr.lh_nfree < numchunks)
@@ -574,9 +624,8 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
le->le_cd = cd;
/* link it into the hash chain */
- chunkp = LEAF_HASH_ENTPTR(l, h);
- le->le_next = *chunkp;
- *chunkp = chunk;
+ /* XXX if we did the search above, we could just use that */
+ chunkp = zap_leaf_rehash_entry(l, chunk);
l->l_phys->l_hdr.lh_nentries++;
@@ -591,16 +640,76 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
}
/*
+ * Determine if there is another entry with the same normalized form.
+ * For performance purposes, either zn or name must be provided (the
+ * other can be NULL). Note, there usually won't be any hash
+ * conflicts, in which case we don't need the concatenated/normalized
+ * form of the name. But all callers have one of these on hand anyway,
+ * so might as well take advantage. A cleaner but slower interface
+ * would accept neither argument, and compute the normalized name as
+ * needed (using zap_name_alloc(zap_entry_read_name(zeh))).
+ */
+boolean_t
+zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn,
+ const char *name, zap_t *zap)
+{
+ uint64_t chunk;
+ struct zap_leaf_entry *le;
+ boolean_t allocdzn = B_FALSE;
+
+ if (zap->zap_normflags == 0)
+ return (B_FALSE);
+
+ for (chunk = *LEAF_HASH_ENTPTR(zeh->zeh_leaf, zeh->zeh_hash);
+ chunk != CHAIN_END; chunk = le->le_next) {
+ le = ZAP_LEAF_ENTRY(zeh->zeh_leaf, chunk);
+ if (le->le_hash != zeh->zeh_hash)
+ continue;
+ if (le->le_cd == zeh->zeh_cd)
+ continue;
+
+ if (zn == NULL) {
+ zn = zap_name_alloc(zap, name, MT_FIRST);
+ allocdzn = B_TRUE;
+ }
+ if (zap_leaf_array_match(zeh->zeh_leaf, zn,
+ le->le_name_chunk, le->le_name_length)) {
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_TRUE);
+ }
+ }
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_FALSE);
+}
+
+/*
* Routines for transferring entries between leafs.
*/
-static void
+static uint16_t *
zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry)
{
struct zap_leaf_entry *le = ZAP_LEAF_ENTRY(l, entry);
- uint16_t *ptr = LEAF_HASH_ENTPTR(l, le->le_hash);
- le->le_next = *ptr;
- *ptr = entry;
+ struct zap_leaf_entry *le2;
+ uint16_t *chunkp;
+
+ /*
+ * keep the entry chain sorted by cd
+ * NB: this will not cause problems for unsorted leafs, though
+ * it is unnecessary there.
+ */
+ for (chunkp = LEAF_HASH_ENTPTR(l, le->le_hash);
+ *chunkp != CHAIN_END; chunkp = &le2->le_next) {
+ le2 = ZAP_LEAF_ENTRY(l, *chunkp);
+ if (le2->le_cd > le->le_cd)
+ break;
+ }
+
+ le->le_next = *chunkp;
+ *chunkp = entry;
+ return (chunkp);
}
static uint16_t
@@ -644,7 +753,7 @@ zap_leaf_transfer_entry(zap_leaf_t *l, int entry, zap_leaf_t *nl)
nle = ZAP_LEAF_ENTRY(nl, chunk);
*nle = *le; /* structure assignment */
- zap_leaf_rehash_entry(nl, chunk);
+ (void) zap_leaf_rehash_entry(nl, chunk);
nle->le_name_chunk = zap_leaf_transfer_array(l, le->le_name_chunk, nl);
nle->le_value_chunk =
@@ -660,7 +769,7 @@ zap_leaf_transfer_entry(zap_leaf_t *l, int entry, zap_leaf_t *nl)
* Transfer the entries whose hash prefix ends in 1 to the new leaf.
*/
void
-zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl)
+zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl, int version)
{
int i;
int bit = 64 - 1 - l->l_phys->l_hdr.lh_prefix_len;
@@ -674,6 +783,9 @@ zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl)
/* break existing hash chains */
zap_memset(l->l_phys->l_hash, CHAIN_END, 2*ZAP_LEAF_HASH_NUMENTRIES(l));
+ if (version >= SPA_VERSION_NORMALIZATION)
+ l->l_phys->l_hdr.lh_flags |= ZLF_ENTRIES_CDSORTED;
+
/*
* Transfer entries whose hash bit 'bit' is set to nl; rehash
* the remaining entries
@@ -691,7 +803,7 @@ zap_leaf_split(zap_leaf_t *l, zap_leaf_t *nl)
if (le->le_hash & (1ULL << bit))
zap_leaf_transfer_entry(l, i, nl);
else
- zap_leaf_rehash_entry(l, i);
+ (void) zap_leaf_rehash_entry(l, i);
}
}
diff --git a/usr/src/uts/common/fs/zfs/zap_micro.c b/usr/src/uts/common/fs/zfs/zap_micro.c
index 8fce0ba400..f185a7754f 100644
--- a/usr/src/uts/common/fs/zfs/zap_micro.c
+++ b/usr/src/uts/common/fs/zfs/zap_micro.c
@@ -33,11 +33,103 @@
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
#include <sys/avl.h>
-
+#include <sys/zfs_i18n.h>
static void mzap_upgrade(zap_t *zap, dmu_tx_t *tx);
+static uint64_t
+zap_hash(zap_t *zap, const char *normname)
+{
+ const uint8_t *cp;
+ uint8_t c;
+ uint64_t crc = zap->zap_salt;
+
+ /* NB: name must already be normalized, if necessary */
+
+ ASSERT(crc != 0);
+ ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
+ for (cp = (const uint8_t *)normname; (c = *cp) != '\0'; cp++) {
+ crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ c) & 0xFF];
+ }
+
+ /*
+ * Only use 28 bits, since we need 4 bits in the cookie for the
+ * collision differentiator. We MUST use the high bits, since
+ * those are the ones that we first pay attention to when
+ * chosing the bucket.
+ */
+ crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1);
+
+ return (crc);
+}
+
+static int
+zap_normalize(zap_t *zap, const char *name, char *namenorm)
+{
+ size_t inlen, outlen;
+ int err;
+
+ inlen = strlen(name) + 1;
+ outlen = ZAP_MAXNAMELEN;
+
+ err = 0;
+ (void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
+ zap->zap_normflags | U8_TEXTPREP_IGNORE_NULL, U8_UNICODE_LATEST,
+ &err);
+
+ return (err);
+}
+
+boolean_t
+zap_match(zap_name_t *zn, const char *matchname)
+{
+ if (zn->zn_matchtype == MT_FIRST) {
+ char norm[ZAP_MAXNAMELEN];
+
+ if (zap_normalize(zn->zn_zap, matchname, norm) != 0)
+ return (B_FALSE);
+
+ return (strcmp(zn->zn_name_norm, norm) == 0);
+ } else {
+ /* MT_BEST or MT_EXACT */
+ return (strcmp(zn->zn_name_orij, matchname) == 0);
+ }
+}
+
+void
+zap_name_free(zap_name_t *zn)
+{
+ kmem_free(zn, sizeof (zap_name_t));
+}
+
+/* XXX combine this with zap_lockdir()? */
+zap_name_t *
+zap_name_alloc(zap_t *zap, const char *name, matchtype_t mt)
+{
+ zap_name_t *zn = kmem_alloc(sizeof (zap_name_t), KM_SLEEP);
+
+ zn->zn_zap = zap;
+ zn->zn_name_orij = name;
+ zn->zn_matchtype = mt;
+ if (zap->zap_normflags) {
+ if (zap_normalize(zap, name, zn->zn_normbuf) != 0) {
+ zap_name_free(zn);
+ return (NULL);
+ }
+ zn->zn_name_norm = zn->zn_normbuf;
+ } else {
+ if (mt != MT_EXACT) {
+ zap_name_free(zn);
+ return (NULL);
+ }
+ zn->zn_name_norm = zn->zn_name_orij;
+ }
+
+ zn->zn_hash = zap_hash(zap, zn->zn_name_norm);
+ return (zn);
+}
+
static void
mzap_byteswap(mzap_phys_t *buf, size_t size)
{
@@ -93,7 +185,6 @@ mze_insert(zap_t *zap, int chunkid, uint64_t hash, mzap_ent_phys_t *mzep)
ASSERT(zap->zap_ismicro);
ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
ASSERT(mzep->mze_cd < ZAP_MAXCD);
- ASSERT3U(zap_hash(zap, mzep->mze_name), ==, hash);
mze = kmem_alloc(sizeof (mzap_ent_t), KM_SLEEP);
mze->mze_chunkid = chunkid;
@@ -103,30 +194,34 @@ mze_insert(zap_t *zap, int chunkid, uint64_t hash, mzap_ent_phys_t *mzep)
}
static mzap_ent_t *
-mze_find(zap_t *zap, const char *name, uint64_t hash)
+mze_find(zap_name_t *zn)
{
mzap_ent_t mze_tofind;
mzap_ent_t *mze;
avl_index_t idx;
- avl_tree_t *avl = &zap->zap_m.zap_avl;
+ avl_tree_t *avl = &zn->zn_zap->zap_m.zap_avl;
- ASSERT(zap->zap_ismicro);
- ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
- ASSERT3U(zap_hash(zap, name), ==, hash);
+ ASSERT(zn->zn_zap->zap_ismicro);
+ ASSERT(RW_LOCK_HELD(&zn->zn_zap->zap_rwlock));
- if (strlen(name) >= sizeof (mze_tofind.mze_phys.mze_name))
+ if (strlen(zn->zn_name_norm) >= sizeof (mze_tofind.mze_phys.mze_name))
return (NULL);
- mze_tofind.mze_hash = hash;
+ mze_tofind.mze_hash = zn->zn_hash;
mze_tofind.mze_phys.mze_cd = 0;
+again:
mze = avl_find(avl, &mze_tofind, &idx);
if (mze == NULL)
mze = avl_nearest(avl, idx, AVL_AFTER);
- for (; mze && mze->mze_hash == hash; mze = AVL_NEXT(avl, mze)) {
- if (strcmp(name, mze->mze_phys.mze_name) == 0)
+ for (; mze && mze->mze_hash == zn->zn_hash; mze = AVL_NEXT(avl, mze)) {
+ if (zap_match(zn, mze->mze_phys.mze_name))
return (mze);
}
+ if (zn->zn_matchtype == MT_BEST) {
+ zn->zn_matchtype = MT_FIRST;
+ goto again;
+ }
return (NULL);
}
@@ -193,7 +288,7 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
zap->zap_object = obj;
zap->zap_dbuf = db;
- if (((uint64_t *)db->db_data)[0] != ZBT_MICRO) {
+ if (*(uint64_t *)db->db_data != ZBT_MICRO) {
mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
zap->zap_f.zap_block_shift = highbit(db->db_size) - 1;
} else {
@@ -218,6 +313,7 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
if (zap->zap_ismicro) {
zap->zap_salt = zap->zap_m.zap_phys->mz_salt;
+ zap->zap_normflags = zap->zap_m.zap_phys->mz_normflags;
zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1;
avl_create(&zap->zap_m.zap_avl, mze_compare,
sizeof (mzap_ent_t), offsetof(mzap_ent_t, mze_node));
@@ -226,13 +322,18 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
mzap_ent_phys_t *mze =
&zap->zap_m.zap_phys->mz_chunk[i];
if (mze->mze_name[0]) {
+ zap_name_t *zn;
+
zap->zap_m.zap_num_entries++;
- mze_insert(zap, i,
- zap_hash(zap, mze->mze_name), mze);
+ zn = zap_name_alloc(zap, mze->mze_name,
+ MT_EXACT);
+ mze_insert(zap, i, zn->zn_hash, mze);
+ zap_name_free(zn);
}
}
} else {
zap->zap_salt = zap->zap_f.zap_phys->zap_salt;
+ zap->zap_normflags = zap->zap_f.zap_phys->zap_normflags;
ASSERT3U(sizeof (struct zap_leaf_header), ==,
2*ZAP_LEAF_CHUNKSIZE);
@@ -357,6 +458,7 @@ mzap_upgrade(zap_t *zap, dmu_tx_t *tx)
dprintf("upgrading obj=%llu with %u chunks\n",
zap->zap_object, nchunks);
+ /* XXX destroy the avl later, so we can use the stored hash value */
mze_destroy(zap);
fzap_upgrade(zap, tx);
@@ -364,48 +466,28 @@ mzap_upgrade(zap_t *zap, dmu_tx_t *tx)
for (i = 0; i < nchunks; i++) {
int err;
mzap_ent_phys_t *mze = &mzp->mz_chunk[i];
+ zap_name_t *zn;
if (mze->mze_name[0] == 0)
continue;
dprintf("adding %s=%llu\n",
mze->mze_name, mze->mze_value);
- err = fzap_add_cd(zap,
- mze->mze_name, 8, 1, &mze->mze_value,
+ zn = zap_name_alloc(zap, mze->mze_name, MT_EXACT);
+ err = fzap_add_cd(zn, 8, 1, &mze->mze_value,
mze->mze_cd, tx);
+ zap_name_free(zn);
ASSERT3U(err, ==, 0);
}
kmem_free(mzp, sz);
}
-uint64_t
-zap_hash(zap_t *zap, const char *name)
-{
- const uint8_t *cp;
- uint8_t c;
- uint64_t crc = zap->zap_salt;
-
- ASSERT(crc != 0);
- ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
- for (cp = (const uint8_t *)name; (c = *cp) != '\0'; cp++)
- crc = (crc >> 8) ^ zfs_crc64_table[(crc ^ c) & 0xFF];
-
- /*
- * Only use 28 bits, since we need 4 bits in the cookie for the
- * collision differentiator. We MUST use the high bits, since
- * those are the onces that we first pay attention to when
- * chosing the bucket.
- */
- crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1);
-
- return (crc);
-}
-
-
static void
-mzap_create_impl(objset_t *os, uint64_t obj, dmu_tx_t *tx)
+mzap_create_impl(objset_t *os, uint64_t obj, int normflags, dmu_tx_t *tx)
{
dmu_buf_t *db;
mzap_phys_t *zp;
+ ASSERT(normflags == 0 ||
+ spa_version(dmu_objset_spa(os)) >= SPA_VERSION_NORMALIZATION);
VERIFY(0 == dmu_buf_hold(os, obj, 0, FTAG, &db));
#ifdef ZFS_DEBUG
@@ -420,7 +502,7 @@ mzap_create_impl(objset_t *os, uint64_t obj, dmu_tx_t *tx)
zp = db->db_data;
zp->mz_block_type = ZBT_MICRO;
zp->mz_salt = ((uintptr_t)db ^ (uintptr_t)tx ^ (obj << 1)) | 1ULL;
- ASSERT(zp->mz_salt != 0);
+ zp->mz_normflags = normflags;
dmu_buf_rele(db, FTAG);
}
@@ -428,12 +510,21 @@ int
zap_create_claim(objset_t *os, uint64_t obj, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
{
+ return (zap_create_claim_norm(os, obj,
+ 0, ot, bonustype, bonuslen, tx));
+}
+
+int
+zap_create_claim_norm(objset_t *os, uint64_t obj, int normflags,
+ dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
int err;
err = dmu_object_claim(os, obj, ot, 0, bonustype, bonuslen, tx);
if (err != 0)
return (err);
- mzap_create_impl(os, obj, tx);
+ mzap_create_impl(os, obj, normflags, tx);
return (0);
}
@@ -441,9 +532,16 @@ uint64_t
zap_create(objset_t *os, dmu_object_type_t ot,
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
{
+ return (zap_create_norm(os, 0, ot, bonustype, bonuslen, tx));
+}
+
+uint64_t
+zap_create_norm(objset_t *os, int normflags, dmu_object_type_t ot,
+ dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
uint64_t obj = dmu_object_alloc(os, ot, 0, bonustype, bonuslen, tx);
- mzap_create_impl(os, obj, tx);
+ mzap_create_impl(os, obj, normflags, tx);
return (obj);
}
@@ -494,36 +592,102 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count)
}
/*
- * Routines for maniplulating attributes.
+ * zn may be NULL; if not specified, it will be computed if needed.
+ * See also the comment above zap_entry_normalization_conflict().
+ */
+static boolean_t
+mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze)
+{
+ mzap_ent_t *other;
+ int direction = AVL_BEFORE;
+ boolean_t allocdzn = B_FALSE;
+
+ if (zap->zap_normflags == 0)
+ return (B_FALSE);
+
+again:
+ for (other = avl_walk(&zap->zap_m.zap_avl, mze, direction);
+ other && other->mze_hash == mze->mze_hash;
+ other = avl_walk(&zap->zap_m.zap_avl, other, direction)) {
+
+ if (zn == NULL) {
+ zn = zap_name_alloc(zap, mze->mze_phys.mze_name,
+ MT_FIRST);
+ allocdzn = B_TRUE;
+ }
+ if (zap_match(zn, other->mze_phys.mze_name)) {
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_TRUE);
+ }
+ }
+
+ if (direction == AVL_BEFORE) {
+ direction = AVL_AFTER;
+ goto again;
+ }
+
+ if (allocdzn)
+ zap_name_free(zn);
+ return (B_FALSE);
+}
+
+/*
+ * Routines for manipulating attributes.
*/
int
zap_lookup(objset_t *os, uint64_t zapobj, const char *name,
uint64_t integer_size, uint64_t num_integers, void *buf)
{
+ return (zap_lookup_norm(os, zapobj, name, integer_size,
+ num_integers, buf, MT_EXACT, NULL, 0, NULL));
+}
+
+int
+zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name,
+ uint64_t integer_size, uint64_t num_integers, void *buf,
+ matchtype_t mt, char *realname, int rn_len,
+ boolean_t *ncp)
+{
zap_t *zap;
int err;
mzap_ent_t *mze;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, mt);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
+
if (!zap->zap_ismicro) {
- err = fzap_lookup(zap, name,
- integer_size, num_integers, buf);
+ err = fzap_lookup(zn, integer_size, num_integers, buf,
+ realname, rn_len, ncp);
} else {
- mze = mze_find(zap, name, zap_hash(zap, name));
+ mze = mze_find(zn);
if (mze == NULL) {
err = ENOENT;
} else {
- if (num_integers < 1)
+ if (num_integers < 1) {
err = EOVERFLOW;
- else if (integer_size != 8)
+ } else if (integer_size != 8) {
err = EINVAL;
- else
+ } else {
*(uint64_t *)buf = mze->mze_phys.mze_value;
+ (void) strlcpy(realname,
+ mze->mze_phys.mze_name, rn_len);
+ if (ncp) {
+ *ncp = mzap_normalization_conflict(zap,
+ zn, mze);
+ }
+ }
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -535,14 +699,20 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
zap_t *zap;
int err;
mzap_ent_t *mze;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_length(zap, name, integer_size, num_integers);
+ err = fzap_length(zn, integer_size, num_integers);
} else {
- mze = mze_find(zap, name, zap_hash(zap, name));
+ mze = mze_find(zn);
if (mze == NULL) {
err = ENOENT;
} else {
@@ -552,28 +722,31 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
*num_integers = 1;
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
static void
-mzap_addent(zap_t *zap, const char *name, uint64_t hash, uint64_t value)
+mzap_addent(zap_name_t *zn, uint64_t value)
{
int i;
+ zap_t *zap = zn->zn_zap;
int start = zap->zap_m.zap_alloc_next;
uint32_t cd;
- dprintf("obj=%llu %s=%llu\n", zap->zap_object, name, value);
+ dprintf("obj=%llu %s=%llu\n", zap->zap_object,
+ zn->zn_name_orij, value);
ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
#ifdef ZFS_DEBUG
for (i = 0; i < zap->zap_m.zap_num_chunks; i++) {
mzap_ent_phys_t *mze = &zap->zap_m.zap_phys->mz_chunk[i];
- ASSERT(strcmp(name, mze->mze_name) != 0);
+ ASSERT(strcmp(zn->zn_name_orij, mze->mze_name) != 0);
}
#endif
- cd = mze_find_unused_cd(zap, hash);
+ cd = mze_find_unused_cd(zap, zn->zn_hash);
/* given the limited size of the microzap, this can't happen */
ASSERT(cd != ZAP_MAXCD);
@@ -583,13 +756,13 @@ again:
if (mze->mze_name[0] == 0) {
mze->mze_value = value;
mze->mze_cd = cd;
- (void) strcpy(mze->mze_name, name);
+ (void) strcpy(mze->mze_name, zn->zn_name_orij);
zap->zap_m.zap_num_entries++;
zap->zap_m.zap_alloc_next = i+1;
if (zap->zap_m.zap_alloc_next ==
zap->zap_m.zap_num_chunks)
zap->zap_m.zap_alloc_next = 0;
- mze_insert(zap, i, hash, mze);
+ mze_insert(zap, i, zn->zn_hash, mze);
return;
}
}
@@ -609,28 +782,33 @@ zap_add(objset_t *os, uint64_t zapobj, const char *name,
int err;
mzap_ent_t *mze;
const uint64_t *intval = val;
- uint64_t hash;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_add(zap, name, integer_size, num_integers, val, tx);
+ err = fzap_add(zn, integer_size, num_integers, val, tx);
} else if (integer_size != 8 || num_integers != 1 ||
strlen(name) >= MZAP_NAME_LEN) {
dprintf("upgrading obj %llu: intsz=%u numint=%llu name=%s\n",
zapobj, integer_size, num_integers, name);
mzap_upgrade(zap, tx);
- err = fzap_add(zap, name, integer_size, num_integers, val, tx);
+ err = fzap_add(zn, integer_size, num_integers, val, tx);
} else {
- hash = zap_hash(zap, name);
- mze = mze_find(zap, name, hash);
+ mze = mze_find(zn);
if (mze != NULL) {
err = EEXIST;
} else {
- mzap_addent(zap, name, hash, *intval);
+ mzap_addent(zn, *intval);
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -642,34 +820,36 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
zap_t *zap;
mzap_ent_t *mze;
const uint64_t *intval = val;
- uint64_t hash;
+ zap_name_t *zn;
int err;
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, &zap);
if (err)
return (err);
- ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
+ zn = zap_name_alloc(zap, name, MT_EXACT);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_update(zap, name,
- integer_size, num_integers, val, tx);
+ err = fzap_update(zn, integer_size, num_integers, val, tx);
} else if (integer_size != 8 || num_integers != 1 ||
strlen(name) >= MZAP_NAME_LEN) {
dprintf("upgrading obj %llu: intsz=%u numint=%llu name=%s\n",
zapobj, integer_size, num_integers, name);
mzap_upgrade(zap, tx);
- err = fzap_update(zap, name,
- integer_size, num_integers, val, tx);
+ err = fzap_update(zn, integer_size, num_integers, val, tx);
} else {
- hash = zap_hash(zap, name);
- mze = mze_find(zap, name, hash);
+ mze = mze_find(zn);
if (mze != NULL) {
mze->mze_phys.mze_value = *intval;
zap->zap_m.zap_phys->mz_chunk
[mze->mze_chunkid].mze_value = *intval;
} else {
- mzap_addent(zap, name, hash, *intval);
+ mzap_addent(zn, *intval);
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -677,28 +857,40 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
int
zap_remove(objset_t *os, uint64_t zapobj, const char *name, dmu_tx_t *tx)
{
+ return (zap_remove_norm(os, zapobj, name, MT_EXACT, tx));
+}
+
+int
+zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
+ matchtype_t mt, dmu_tx_t *tx)
+{
zap_t *zap;
int err;
mzap_ent_t *mze;
+ zap_name_t *zn;
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, &zap);
if (err)
return (err);
+ zn = zap_name_alloc(zap, name, mt);
+ if (zn == NULL) {
+ zap_unlockdir(zap);
+ return (ENOTSUP);
+ }
if (!zap->zap_ismicro) {
- err = fzap_remove(zap, name, tx);
+ err = fzap_remove(zn, tx);
} else {
- mze = mze_find(zap, name, zap_hash(zap, name));
+ mze = mze_find(zn);
if (mze == NULL) {
- dprintf("fail: %s\n", name);
err = ENOENT;
} else {
- dprintf("success: %s\n", name);
zap->zap_m.zap_num_entries--;
bzero(&zap->zap_m.zap_phys->mz_chunk[mze->mze_chunkid],
sizeof (mzap_ent_phys_t));
mze_remove(zap, mze);
}
}
+ zap_name_free(zn);
zap_unlockdir(zap);
return (err);
}
@@ -795,14 +987,17 @@ zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za)
mze_tofind.mze_phys.mze_cd = zc->zc_cd;
mze = avl_find(&zc->zc_zap->zap_m.zap_avl, &mze_tofind, &idx);
- ASSERT(mze == NULL || 0 == bcmp(&mze->mze_phys,
- &zc->zc_zap->zap_m.zap_phys->mz_chunk[mze->mze_chunkid],
- sizeof (mze->mze_phys)));
if (mze == NULL) {
mze = avl_nearest(&zc->zc_zap->zap_m.zap_avl,
idx, AVL_AFTER);
}
if (mze) {
+ ASSERT(0 == bcmp(&mze->mze_phys,
+ &zc->zc_zap->zap_m.zap_phys->mz_chunk
+ [mze->mze_chunkid], sizeof (mze->mze_phys)));
+
+ za->za_normalization_conflict =
+ mzap_normalization_conflict(zc->zc_zap, NULL, mze);
za->za_integer_length = 8;
za->za_num_integers = 1;
za->za_first_integer = mze->mze_phys.mze_value;
diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c
index f78a9cd000..34057b6d72 100644
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c
@@ -33,6 +33,7 @@
#include <sys/resource.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
+#include <sys/sid.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/kmem.h>
@@ -44,17 +45,19 @@
#include <sys/mode.h>
#include <sys/policy.h>
#include <sys/zfs_znode.h>
+#include <sys/zfs_fuid.h>
#include <sys/zfs_acl.h>
#include <sys/zfs_dir.h>
#include <sys/zfs_vfsops.h>
#include <sys/dmu.h>
+#include <sys/dnode.h>
#include <sys/zap.h>
-#include <util/qsort.h>
#include "fs/fs_subr.h"
#include <acl/acl_common.h>
#define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE
#define DENY ACE_ACCESS_DENIED_ACE_TYPE
+#define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
#define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP)
#define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
@@ -63,8 +66,15 @@
ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
#define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
-#define WRITE_MASK (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS| \
- ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|ACE_WRITE_OWNER)
+#define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
+
+#define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
+ ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
+ ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
+ ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
+
+#define WRITE_MASK (WRITE_MASK_DATA|ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|\
+ ACE_WRITE_OWNER)
#define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
@@ -73,59 +83,634 @@
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
#define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
- ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
+ ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
#define SECURE_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER)
-#define OGE_PAD 6 /* traditional owner/group/everyone ACES */
+#define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
+ ZFS_ACL_PROTECTED)
+
+#define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
+ ZFS_ACL_OBJ_ACE)
+
+static uint16_t
+zfs_ace_v0_get_type(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_type);
+}
+
+static uint16_t
+zfs_ace_v0_get_flags(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_flags);
+}
+
+static uint32_t
+zfs_ace_v0_get_mask(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_access_mask);
+}
+
+static uint64_t
+zfs_ace_v0_get_who(void *acep)
+{
+ return (((zfs_oldace_t *)acep)->z_fuid);
+}
-static int zfs_ace_can_use(znode_t *zp, ace_t *);
+static void
+zfs_ace_v0_set_type(void *acep, uint16_t type)
+{
+ ((zfs_oldace_t *)acep)->z_type = type;
+}
+
+static void
+zfs_ace_v0_set_flags(void *acep, uint16_t flags)
+{
+ ((zfs_oldace_t *)acep)->z_flags = flags;
+}
+
+static void
+zfs_ace_v0_set_mask(void *acep, uint32_t mask)
+{
+ ((zfs_oldace_t *)acep)->z_access_mask = mask;
+}
+
+static void
+zfs_ace_v0_set_who(void *acep, uint64_t who)
+{
+ ((zfs_oldace_t *)acep)->z_fuid = who;
+}
+
+/*ARGSUSED*/
+static size_t
+zfs_ace_v0_size(void *acep)
+{
+ return (sizeof (zfs_oldace_t));
+}
+
+static size_t
+zfs_ace_v0_abstract_size(void)
+{
+ return (sizeof (zfs_oldace_t));
+}
+
+static int
+zfs_ace_v0_mask_off(void)
+{
+ return (offsetof(zfs_oldace_t, z_access_mask));
+}
+
+/*ARGSUSED*/
+static int
+zfs_ace_v0_data(void *acep, void **datap)
+{
+ *datap = NULL;
+ return (0);
+}
+
+static acl_ops_t zfs_acl_v0_ops = {
+ zfs_ace_v0_get_mask,
+ zfs_ace_v0_set_mask,
+ zfs_ace_v0_get_flags,
+ zfs_ace_v0_set_flags,
+ zfs_ace_v0_get_type,
+ zfs_ace_v0_set_type,
+ zfs_ace_v0_get_who,
+ zfs_ace_v0_set_who,
+ zfs_ace_v0_size,
+ zfs_ace_v0_abstract_size,
+ zfs_ace_v0_mask_off,
+ zfs_ace_v0_data
+};
+
+static uint16_t
+zfs_ace_fuid_get_type(void *acep)
+{
+ return (((zfs_ace_hdr_t *)acep)->z_type);
+}
+
+static uint16_t
+zfs_ace_fuid_get_flags(void *acep)
+{
+ return (((zfs_ace_hdr_t *)acep)->z_flags);
+}
+
+static uint32_t
+zfs_ace_fuid_get_mask(void *acep)
+{
+ return (((zfs_ace_hdr_t *)acep)->z_access_mask);
+}
+
+static uint64_t
+zfs_ace_fuid_get_who(void *args)
+{
+ uint16_t entry_type;
+ zfs_ace_t *acep = args;
+
+ entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+
+ if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
+ entry_type == ACE_EVERYONE)
+ return (-1);
+ return (((zfs_ace_t *)acep)->z_fuid);
+}
+
+static void
+zfs_ace_fuid_set_type(void *acep, uint16_t type)
+{
+ ((zfs_ace_hdr_t *)acep)->z_type = type;
+}
+
+static void
+zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
+{
+ ((zfs_ace_hdr_t *)acep)->z_flags = flags;
+}
+
+static void
+zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
+{
+ ((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
+}
+
+static void
+zfs_ace_fuid_set_who(void *arg, uint64_t who)
+{
+ zfs_ace_t *acep = arg;
+
+ uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+
+ if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
+ entry_type == ACE_EVERYONE)
+ return;
+ acep->z_fuid = who;
+}
+
+static size_t
+zfs_ace_fuid_size(void *acep)
+{
+ zfs_ace_hdr_t *zacep = acep;
+ uint16_t entry_type;
+
+ switch (zacep->z_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ return (sizeof (zfs_object_ace_t));
+ case ALLOW:
+ case DENY:
+ entry_type =
+ (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
+ if (entry_type == ACE_OWNER ||
+ entry_type == (ACE_GROUP | ACE_IDENTIFIER_GROUP) ||
+ entry_type == ACE_EVERYONE)
+ return (sizeof (zfs_ace_hdr_t));
+ /*FALLTHROUGH*/
+ default:
+ return (sizeof (zfs_ace_t));
+ }
+}
+
+static size_t
+zfs_ace_fuid_abstract_size(void)
+{
+ return (sizeof (zfs_ace_hdr_t));
+}
+
+static int
+zfs_ace_fuid_mask_off(void)
+{
+ return (offsetof(zfs_ace_hdr_t, z_access_mask));
+}
+
+static int
+zfs_ace_fuid_data(void *acep, void **datap)
+{
+ zfs_ace_t *zacep = acep;
+ zfs_object_ace_t *zobjp;
+
+ switch (zacep->z_hdr.z_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ zobjp = acep;
+ *datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
+ return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
+ default:
+ *datap = NULL;
+ return (0);
+ }
+}
+
+static acl_ops_t zfs_acl_fuid_ops = {
+ zfs_ace_fuid_get_mask,
+ zfs_ace_fuid_set_mask,
+ zfs_ace_fuid_get_flags,
+ zfs_ace_fuid_set_flags,
+ zfs_ace_fuid_get_type,
+ zfs_ace_fuid_set_type,
+ zfs_ace_fuid_get_who,
+ zfs_ace_fuid_set_who,
+ zfs_ace_fuid_size,
+ zfs_ace_fuid_abstract_size,
+ zfs_ace_fuid_mask_off,
+ zfs_ace_fuid_data
+};
+
+static int
+zfs_acl_version(int version)
+{
+ if (version < ZPL_VERSION_FUID)
+ return (ZFS_ACL_VERSION_INITIAL);
+ else
+ return (ZFS_ACL_VERSION_FUID);
+}
+
+static int
+zfs_acl_version_zp(znode_t *zp)
+{
+ return (zfs_acl_version(zp->z_zfsvfs->z_version));
+}
static zfs_acl_t *
-zfs_acl_alloc(int slots)
+zfs_acl_alloc(int vers)
{
zfs_acl_t *aclp;
aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
- if (slots != 0) {
- aclp->z_acl = kmem_alloc(ZFS_ACL_SIZE(slots), KM_SLEEP);
- aclp->z_acl_count = 0;
- aclp->z_state = ACL_DATA_ALLOCED;
- } else {
- aclp->z_state = 0;
- }
- aclp->z_slots = slots;
+ list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
+ offsetof(zfs_acl_node_t, z_next));
+ aclp->z_version = vers;
+ if (vers == ZFS_ACL_VERSION_FUID)
+ aclp->z_ops = zfs_acl_fuid_ops;
+ else
+ aclp->z_ops = zfs_acl_v0_ops;
return (aclp);
}
+static zfs_acl_node_t *
+zfs_acl_node_alloc(size_t bytes)
+{
+ zfs_acl_node_t *aclnode;
+
+ aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
+ if (bytes) {
+ aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
+ aclnode->z_allocdata = aclnode->z_acldata;
+ aclnode->z_allocsize = bytes;
+ aclnode->z_size = bytes;
+ }
+
+ return (aclnode);
+}
+
+static void
+zfs_acl_node_free(zfs_acl_node_t *aclnode)
+{
+ if (aclnode->z_allocsize)
+ kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
+ kmem_free(aclnode, sizeof (zfs_acl_node_t));
+}
+
void
zfs_acl_free(zfs_acl_t *aclp)
{
- if (aclp->z_state == ACL_DATA_ALLOCED) {
- kmem_free(aclp->z_acl, ZFS_ACL_SIZE(aclp->z_slots));
+ zfs_acl_node_t *aclnode;
+
+ while (aclnode = list_head(&aclp->z_acl)) {
+ list_remove(&aclp->z_acl, aclnode);
+ zfs_acl_node_free(aclnode);
}
+
+ list_destroy(&aclp->z_acl);
kmem_free(aclp, sizeof (zfs_acl_t));
}
-static uint32_t
-zfs_v4_to_unix(uint32_t access_mask)
+static boolean_t
+zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
{
- uint32_t new_mask = 0;
+ /*
+ * first check type of entry
+ */
+
+ switch (iflags & ACE_TYPE_FLAGS) {
+ case ACE_OWNER:
+ case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+ case ACE_IDENTIFIER_GROUP:
+ case ACE_EVERYONE:
+ case 0: /* User entry */
+ break;
+ default:
+ return (B_FALSE);
+
+ }
/*
- * This is used for mapping v4 permissions into permissions
- * that can be passed to secpolicy_vnode_access()
+ * next check inheritance level flags
*/
- if (access_mask & (ACE_READ_DATA | ACE_LIST_DIRECTORY |
- ACE_READ_ATTRIBUTES | ACE_READ_ACL))
- new_mask |= S_IROTH;
- if (access_mask & (ACE_WRITE_DATA | ACE_APPEND_DATA |
- ACE_WRITE_ATTRIBUTES | ACE_ADD_FILE | ACE_WRITE_NAMED_ATTRS))
- new_mask |= S_IWOTH;
- if (access_mask & (ACE_EXECUTE | ACE_READ_NAMED_ATTRS))
- new_mask |= S_IXOTH;
- return (new_mask);
+ if (type != ALLOW && type > MAX_ACE_TYPE) {
+ return (B_FALSE);
+ }
+
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ if (aclp->z_version < ZFS_ACL_VERSION_FUID)
+ return (B_FALSE);
+ aclp->z_hints |= ZFS_ACL_OBJ_ACE;
+ }
+
+ /*
+ * Only directories should have inheritance flags.
+ */
+ if (obj_type != VDIR && (iflags &
+ (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
+ ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
+ return (B_FALSE);
+ }
+
+ if (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
+ aclp->z_hints |= ZFS_INHERIT_ACE;
+
+ if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
+ if ((iflags & (ACE_FILE_INHERIT_ACE|
+ ACE_DIRECTORY_INHERIT_ACE)) == 0) {
+ return (B_FALSE);
+ }
+ }
+
+ return (B_TRUE);
+}
+
+static void *
+zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
+ uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
+{
+ zfs_acl_node_t *aclnode;
+
+ if (start == NULL) {
+ aclnode = list_head(&aclp->z_acl);
+ if (aclnode == NULL)
+ return (NULL);
+
+ aclp->z_next_ace = aclnode->z_acldata;
+ aclp->z_curr_node = aclnode;
+ aclnode->z_ace_idx = 0;
+ }
+
+ aclnode = aclp->z_curr_node;
+
+ if (aclnode == NULL)
+ return (NULL);
+
+ if (aclnode->z_ace_idx >= aclnode->z_ace_count) {
+ aclnode = list_next(&aclp->z_acl, aclnode);
+ if (aclnode == NULL)
+ return (NULL);
+ else {
+ aclp->z_curr_node = aclnode;
+ aclnode->z_ace_idx = 0;
+ aclp->z_next_ace = aclnode->z_acldata;
+ }
+ }
+
+ if (aclnode->z_ace_idx < aclnode->z_ace_count) {
+ void *acep = aclp->z_next_ace;
+ *iflags = aclp->z_ops.ace_flags_get(acep);
+ *type = aclp->z_ops.ace_type_get(acep);
+ *access_mask = aclp->z_ops.ace_mask_get(acep);
+ *who = aclp->z_ops.ace_who_get(acep);
+ aclp->z_next_ace = (caddr_t)aclp->z_next_ace +
+ aclp->z_ops.ace_size(acep);
+ aclnode->z_ace_idx++;
+ return ((void *)acep);
+ }
+ return (NULL);
+}
+
+/*ARGSUSED*/
+static uint64_t
+zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
+ uint16_t *flags, uint16_t *type, uint32_t *mask)
+{
+ zfs_acl_t *aclp = datap;
+ zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
+ uint64_t who;
+
+ acep = zfs_acl_next_ace(aclp, acep, &who, mask,
+ flags, type);
+ return ((uint64_t)(uintptr_t)acep);
+}
+
+static zfs_acl_node_t *
+zfs_acl_curr_node(zfs_acl_t *aclp)
+{
+ ASSERT(aclp->z_curr_node);
+ return (aclp->z_curr_node);
+}
+
+/*
+ * Copy ACE to internal ZFS format.
+ * While processing the ACL each ACE will be validated for correctness.
+ * ACE FUIDs will be created later.
+ */
+int
+zfs_copy_ace_2_fuid(vtype_t obj_type, zfs_acl_t *aclp, void *datap,
+ zfs_ace_t *z_acl, int aclcnt, size_t *size)
+{
+ int i;
+ uint16_t entry_type;
+ zfs_ace_t *aceptr = z_acl;
+ ace_t *acep = datap;
+ zfs_object_ace_t *zobjacep;
+ ace_object_t *aceobjp;
+
+ for (i = 0; i != aclcnt; i++) {
+ aceptr->z_hdr.z_access_mask = acep->a_access_mask;
+ aceptr->z_hdr.z_flags = acep->a_flags;
+ aceptr->z_hdr.z_type = acep->a_type;
+ entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
+ if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
+ entry_type != ACE_EVERYONE)
+ aceptr->z_fuid = (uint64_t)acep->a_who;
+ /*
+ * Make sure ACE is valid
+ */
+ if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
+ aceptr->z_hdr.z_flags) != B_TRUE)
+ return (EINVAL);
+
+ switch (acep->a_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ zobjacep = (zfs_object_ace_t *)aceptr;
+ aceobjp = (ace_object_t *)acep;
+
+ bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
+ sizeof (aceobjp->a_obj_type));
+ bcopy(aceobjp->a_inherit_obj_type,
+ zobjacep->z_inherit_type,
+ sizeof (aceobjp->a_inherit_obj_type));
+ acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
+ break;
+ default:
+ acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
+ }
+
+ aceptr = (zfs_ace_t *)((caddr_t)aceptr +
+ aclp->z_ops.ace_size(aceptr));
+ }
+
+ *size = (caddr_t)aceptr - (caddr_t)z_acl;
+
+ return (0);
+}
+
+/*
+ * Copy ZFS ACEs to fixed size ace_t layout
+ */
+static void
+zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *datap, int filter)
+{
+ uint64_t who;
+ uint32_t access_mask;
+ uint16_t iflags, type;
+ zfs_ace_hdr_t *zacep = NULL;
+ ace_t *acep = datap;
+ ace_object_t *objacep;
+ zfs_object_ace_t *zobjacep;
+ zfs_fuid_hdl_t hdl = { 0 };
+ size_t ace_size;
+ uint16_t entry_type;
+
+ while (zacep = zfs_acl_next_ace(aclp, zacep,
+ &who, &access_mask, &iflags, &type)) {
+
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ if (filter) {
+ continue;
+ }
+ zobjacep = (zfs_object_ace_t *)zacep;
+ objacep = (ace_object_t *)acep;
+ bcopy(zobjacep->z_object_type,
+ objacep->a_obj_type,
+ sizeof (zobjacep->z_object_type));
+ bcopy(zobjacep->z_inherit_type,
+ objacep->a_inherit_obj_type,
+ sizeof (zobjacep->z_inherit_type));
+ ace_size = sizeof (ace_object_t);
+ break;
+ default:
+ ace_size = sizeof (ace_t);
+ break;
+ }
+
+ entry_type = (iflags & ACE_TYPE_FLAGS);
+ if ((entry_type != ACE_OWNER &&
+ entry_type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
+ entry_type != ACE_EVERYONE))
+ zfs_fuid_queue_map_id(zfsvfs, &hdl, who,
+ (entry_type & ACE_IDENTIFIER_GROUP) ?
+ ZFS_ACE_GROUP : ZFS_ACE_USER, &acep->a_who);
+ else
+ acep->a_who = (uid_t)(int64_t)who;
+ acep->a_access_mask = access_mask;
+ acep->a_flags = iflags;
+ acep->a_type = type;
+ acep = (ace_t *)((caddr_t)acep + ace_size);
+ }
+ zfs_fuid_get_mappings(&hdl);
+}
+
+static int
+zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
+ zfs_oldace_t *z_acl, int aclcnt, size_t *size)
+{
+ int i;
+ zfs_oldace_t *aceptr = z_acl;
+
+ for (i = 0; i != aclcnt; i++, aceptr++) {
+ aceptr->z_access_mask = acep[i].a_access_mask;
+ aceptr->z_type = acep[i].a_type;
+ aceptr->z_flags = acep[i].a_flags;
+ aceptr->z_fuid = acep[i].a_who;
+ /*
+ * Make sure ACE is valid
+ */
+ if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
+ aceptr->z_flags) != B_TRUE)
+ return (EINVAL);
+ }
+ *size = (caddr_t)aceptr - (caddr_t)z_acl;
+ return (0);
+}
+
+/*
+ * convert old ACL format to new
+ */
+void
+zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp)
+{
+ zfs_oldace_t *oldaclp;
+ int i;
+ uint16_t type, iflags;
+ uint32_t access_mask;
+ uint64_t who;
+ void *cookie = NULL;
+ zfs_acl_node_t *aclnode, *newaclnode;
+
+ ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
+ /*
+ * First create the ACE in a contiguous piece of memory
+ * for zfs_copy_ace_2_fuid().
+ *
+ * We only convert an ACL once, so this won't happen
+ * everytime.
+ */
+ oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
+ KM_SLEEP);
+ i = 0;
+ while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
+ &access_mask, &iflags, &type)) {
+ oldaclp[i].z_flags = iflags;
+ oldaclp[i].z_type = type;
+ oldaclp[i].z_fuid = who;
+ oldaclp[i++].z_access_mask = access_mask;
+ }
+
+ newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
+ sizeof (zfs_object_ace_t));
+ aclp->z_ops = zfs_acl_fuid_ops;
+ VERIFY(zfs_copy_ace_2_fuid(ZTOV(zp)->v_type, aclp, oldaclp,
+ newaclnode->z_acldata, aclp->z_acl_count,
+ &newaclnode->z_size) == 0);
+ aclp->z_acl_bytes = newaclnode->z_size;
+ newaclnode->z_ace_count = aclp->z_acl_count;
+ aclp->z_version = ZFS_ACL_VERSION;
+ kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
+
+ /*
+ * Release all previous ACL nodes
+ */
+
+ while (aclnode = list_head(&aclp->z_acl)) {
+ list_remove(&aclp->z_acl, aclnode);
+ if (aclnode->z_allocsize)
+ kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
+ kmem_free(aclnode, sizeof (zfs_acl_node_t));
+ }
+ list_insert_head(&aclp->z_acl, newaclnode);
}
/*
@@ -136,164 +721,207 @@ zfs_unix_to_v4(uint32_t access_mask)
{
uint32_t new_mask = 0;
- if (access_mask & 01)
- new_mask |= (ACE_EXECUTE);
- if (access_mask & 02) {
- new_mask |= (ACE_WRITE_DATA);
- } if (access_mask & 04) {
+ if (access_mask & S_IXOTH)
+ new_mask |= ACE_EXECUTE;
+ if (access_mask & S_IWOTH)
+ new_mask |= ACE_WRITE_DATA;
+ if (access_mask & S_IROTH)
new_mask |= ACE_READ_DATA;
- }
return (new_mask);
}
static void
-zfs_set_ace(ace_t *zacep, uint32_t access_mask, int access_type,
- uid_t uid, int entry_type)
+zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
+ uint16_t access_type, uint64_t fuid, uint16_t entry_type)
{
- zacep->a_access_mask = access_mask;
- zacep->a_type = access_type;
- zacep->a_who = uid;
- zacep->a_flags = entry_type;
+ uint16_t type = entry_type & ACE_TYPE_FLAGS;
+
+ aclp->z_ops.ace_mask_set(acep, access_mask);
+ aclp->z_ops.ace_type_set(acep, access_type);
+ aclp->z_ops.ace_flags_set(acep, entry_type);
+ if ((type != ACE_OWNER && type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
+ type != ACE_EVERYONE))
+ aclp->z_ops.ace_who_set(acep, fuid);
}
+/*
+ * Determine mode of file based on ACL.
+ * Also, create FUIDs for any User/Group ACEs
+ */
static uint64_t
-zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp)
+zfs_mode_fuid_compute(znode_t *zp, zfs_acl_t *aclp, zfs_fuid_info_t **fuidp,
+ dmu_tx_t *tx)
{
- int i;
- int entry_type;
- mode_t mode = (zp->z_phys->zp_mode &
- (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
- mode_t seen = 0;
- ace_t *acep;
+ int entry_type;
+ mode_t mode;
+ mode_t seen = 0;
+ zfs_ace_hdr_t *acep = NULL;
+ uint64_t who;
+ uint16_t iflags, type;
+ uint32_t access_mask;
- for (i = 0, acep = aclp->z_acl;
- i != aclp->z_acl_count; i++, acep++) {
+ mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
+
+ while (acep = zfs_acl_next_ace(aclp, acep, &who,
+ &access_mask, &iflags, &type)) {
+ entry_type = (iflags & ACE_TYPE_FLAGS);
/*
* Skip over inherit only ACEs
*/
- if (acep->a_flags & ACE_INHERIT_ONLY_ACE)
+ if (entry_type == ACE_INHERIT_ONLY_ACE)
continue;
- entry_type = (acep->a_flags & ACE_TYPE_FLAGS);
if (entry_type == ACE_OWNER) {
- if ((acep->a_access_mask & ACE_READ_DATA) &&
+ if ((access_mask & ACE_READ_DATA) &&
(!(seen & S_IRUSR))) {
seen |= S_IRUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRUSR;
}
}
- if ((acep->a_access_mask & ACE_WRITE_DATA) &&
+ if ((access_mask & ACE_WRITE_DATA) &&
(!(seen & S_IWUSR))) {
seen |= S_IWUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWUSR;
}
}
- if ((acep->a_access_mask & ACE_EXECUTE) &&
+ if ((access_mask & ACE_EXECUTE) &&
(!(seen & S_IXUSR))) {
seen |= S_IXUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXUSR;
}
}
} else if (entry_type == OWNING_GROUP) {
- if ((acep->a_access_mask & ACE_READ_DATA) &&
+ if ((access_mask & ACE_READ_DATA) &&
(!(seen & S_IRGRP))) {
seen |= S_IRGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRGRP;
}
}
- if ((acep->a_access_mask & ACE_WRITE_DATA) &&
+ if ((access_mask & ACE_WRITE_DATA) &&
(!(seen & S_IWGRP))) {
seen |= S_IWGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWGRP;
}
}
- if ((acep->a_access_mask & ACE_EXECUTE) &&
+ if ((access_mask & ACE_EXECUTE) &&
(!(seen & S_IXGRP))) {
seen |= S_IXGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXGRP;
}
}
} else if (entry_type == ACE_EVERYONE) {
- if ((acep->a_access_mask & ACE_READ_DATA)) {
+ if ((access_mask & ACE_READ_DATA)) {
if (!(seen & S_IRUSR)) {
seen |= S_IRUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRUSR;
}
}
if (!(seen & S_IRGRP)) {
seen |= S_IRGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IRGRP;
}
}
if (!(seen & S_IROTH)) {
seen |= S_IROTH;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IROTH;
}
}
}
- if ((acep->a_access_mask & ACE_WRITE_DATA)) {
+ if ((access_mask & ACE_WRITE_DATA)) {
if (!(seen & S_IWUSR)) {
seen |= S_IWUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWUSR;
}
}
if (!(seen & S_IWGRP)) {
seen |= S_IWGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWGRP;
}
}
if (!(seen & S_IWOTH)) {
seen |= S_IWOTH;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IWOTH;
}
}
}
- if ((acep->a_access_mask & ACE_EXECUTE)) {
+ if ((access_mask & ACE_EXECUTE)) {
if (!(seen & S_IXUSR)) {
seen |= S_IXUSR;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXUSR;
}
}
if (!(seen & S_IXGRP)) {
seen |= S_IXGRP;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXGRP;
}
}
if (!(seen & S_IXOTH)) {
seen |= S_IXOTH;
- if (acep->a_type == ALLOW) {
+ if (type == ALLOW) {
mode |= S_IXOTH;
}
}
}
}
+ /*
+ * Now handle FUID create for user/group ACEs
+ */
+ if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
+ aclp->z_ops.ace_who_set(acep,
+ zfs_fuid_create(zp->z_zfsvfs, who,
+ entry_type == 0 ? ZFS_ACE_USER : ZFS_ACE_GROUP, tx,
+ fuidp));
+ }
}
return (mode);
}
static zfs_acl_t *
-zfs_acl_node_read_internal(znode_t *zp)
+zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify)
{
zfs_acl_t *aclp;
+ zfs_acl_node_t *aclnode;
- aclp = zfs_acl_alloc(0);
- aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
- aclp->z_acl = &zp->z_phys->zp_acl.z_ace_data[0];
+ aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
+
+ /*
+ * Version 0 to 1 znode_acl_phys has the size/count fields swapped.
+ * Version 0 didn't have a size field, only a count.
+ */
+ if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
+ aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size;
+ aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count);
+ } else {
+ aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
+ aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size;
+ }
+
+ aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0);
+ aclnode->z_ace_count = aclp->z_acl_count;
+ if (will_modify) {
+ bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata,
+ aclp->z_acl_bytes);
+ } else {
+ aclnode->z_size = aclp->z_acl_bytes;
+ aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0];
+ }
+
+ list_insert_head(&aclp->z_acl, aclnode);
return (aclp);
}
@@ -302,144 +930,127 @@ zfs_acl_node_read_internal(znode_t *zp)
* Read an external acl object.
*/
static int
-zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp)
+zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
{
uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
zfs_acl_t *aclp;
+ size_t aclsize;
+ size_t acl_count;
+ zfs_acl_node_t *aclnode;
int error;
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) {
- *aclpp = zfs_acl_node_read_internal(zp);
+ *aclpp = zfs_acl_node_read_internal(zp, will_modify);
return (0);
}
- aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_count);
+ aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
+ if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
+ zfs_acl_phys_v0_t *zacl0 =
+ (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl;
+ aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count);
+ acl_count = zacl0->z_acl_count;
+ } else {
+ aclsize = zp->z_phys->zp_acl.z_acl_size;
+ acl_count = zp->z_phys->zp_acl.z_acl_count;
+ if (aclsize == 0)
+ aclsize = acl_count * sizeof (zfs_ace_t);
+ }
+ aclnode = zfs_acl_node_alloc(aclsize);
+ list_insert_head(&aclp->z_acl, aclnode);
error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0,
- ZFS_ACL_SIZE(zp->z_phys->zp_acl.z_acl_count), aclp->z_acl);
+ aclsize, aclnode->z_acldata);
+ aclnode->z_ace_count = acl_count;
+ aclp->z_acl_count = acl_count;
+ aclp->z_acl_bytes = aclsize;
+
if (error != 0) {
zfs_acl_free(aclp);
return (error);
}
- aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
-
*aclpp = aclp;
return (0);
}
-static boolean_t
-zfs_acl_valid(znode_t *zp, ace_t *uace, int aclcnt, int *inherit)
-{
- ace_t *acep;
- int i;
-
- *inherit = 0;
-
- if (aclcnt > MAX_ACL_ENTRIES || aclcnt <= 0) {
- return (B_FALSE);
- }
-
- for (i = 0, acep = uace; i != aclcnt; i++, acep++) {
-
- /*
- * first check type of entry
- */
-
- switch (acep->a_flags & ACE_TYPE_FLAGS) {
- case ACE_OWNER:
- acep->a_who = (uid_t)-1;
- break;
- case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
- case ACE_IDENTIFIER_GROUP:
- if (acep->a_flags & ACE_GROUP) {
- acep->a_who = (uid_t)-1;
- }
- break;
- case ACE_EVERYONE:
- acep->a_who = (uid_t)-1;
- break;
- }
-
- /*
- * next check inheritance level flags
- */
-
- if (acep->a_type != ALLOW && acep->a_type != DENY)
- return (B_FALSE);
-
- /*
- * Only directories should have inheritance flags.
- */
- if (ZTOV(zp)->v_type != VDIR && (acep->a_flags &
- (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
- ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
- return (B_FALSE);
- }
-
- if (acep->a_flags &
- (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
- *inherit = 1;
-
- if (acep->a_flags &
- (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
- if ((acep->a_flags & (ACE_FILE_INHERIT_ACE|
- ACE_DIRECTORY_INHERIT_ACE)) == 0) {
- return (B_FALSE);
- }
- }
- }
-
- return (B_TRUE);
-}
/*
- * common code for setting acl's.
+ * common code for setting ACLs.
*
* This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
* zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
* already checked the acl and knows whether to inherit.
*/
int
-zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, dmu_tx_t *tx, int *ihp)
+zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, zfs_fuid_info_t **fuidp,
+ dmu_tx_t *tx)
{
- int inherit = 0;
int error;
znode_phys_t *zphys = zp->z_phys;
- zfs_znode_acl_t *zacl = &zphys->zp_acl;
- uint32_t acl_phys_size = ZFS_ACL_SIZE(aclp->z_acl_count);
+ zfs_acl_phys_t *zacl = &zphys->zp_acl;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
uint64_t aoid = zphys->zp_acl.z_acl_extern_obj;
+ uint64_t off = 0;
+ dmu_object_type_t otype;
+ zfs_acl_node_t *aclnode;
ASSERT(MUTEX_HELD(&zp->z_lock));
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
- if (ihp)
- inherit = *ihp; /* already determined by caller */
- else if (!zfs_acl_valid(zp, aclp->z_acl,
- aclp->z_acl_count, &inherit)) {
- return (EINVAL);
- }
-
dmu_buf_will_dirty(zp->z_dbuf, tx);
+ zphys->zp_mode = zfs_mode_fuid_compute(zp, aclp, fuidp, tx);
+
/*
- * Will ACL fit internally?
+ * Decide which opbject type to use. If we are forced to
+ * use old ACL format than transform ACL into zfs_oldace_t
+ * layout.
*/
- if (aclp->z_acl_count > ACE_SLOT_CNT) {
+ if (!zfsvfs->z_use_fuids) {
+ otype = DMU_OT_OLDACL;
+ } else {
+ if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
+ (zfsvfs->z_version >= ZPL_VERSION_FUID))
+ zfs_acl_xform(zp, aclp);
+ ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
+ otype = DMU_OT_ACL;
+ }
+
+ if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+ /*
+ * If ACL was previously external and we are now
+ * converting to new ACL format then release old
+ * ACL object and create a new one.
+ */
+ if (aoid && aclp->z_version != zacl->z_acl_version) {
+ error = dmu_object_free(zfsvfs->z_os,
+ zp->z_phys->zp_acl.z_acl_extern_obj, tx);
+ if (error)
+ return (error);
+ aoid = 0;
+ }
if (aoid == 0) {
aoid = dmu_object_alloc(zfsvfs->z_os,
- DMU_OT_ACL, acl_phys_size, DMU_OT_NONE, 0, tx);
+ otype, aclp->z_acl_bytes,
+ otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE,
+ otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx);
} else {
(void) dmu_object_set_blocksize(zfsvfs->z_os, aoid,
- acl_phys_size, 0, tx);
+ aclp->z_acl_bytes, 0, tx);
}
zphys->zp_acl.z_acl_extern_obj = aoid;
- zphys->zp_acl.z_acl_count = aclp->z_acl_count;
- dmu_write(zfsvfs->z_os, aoid, 0,
- acl_phys_size, aclp->z_acl, tx);
+ for (aclnode = list_head(&aclp->z_acl); aclnode;
+ aclnode = list_next(&aclp->z_acl, aclnode)) {
+ if (aclnode->z_ace_count == 0)
+ continue;
+ dmu_write(zfsvfs->z_os, aoid, off,
+ aclnode->z_size, aclnode->z_acldata, tx);
+ off += aclnode->z_size;
+ }
} else {
+ void *start = zacl->z_ace_data;
/*
* Migrating back embedded?
*/
@@ -450,64 +1061,75 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, dmu_tx_t *tx, int *ihp)
return (error);
zphys->zp_acl.z_acl_extern_obj = 0;
}
- bcopy(aclp->z_acl, zacl->z_ace_data,
- aclp->z_acl_count * sizeof (ace_t));
- zacl->z_acl_count = aclp->z_acl_count;
+
+ for (aclnode = list_head(&aclp->z_acl); aclnode;
+ aclnode = list_next(&aclp->z_acl, aclnode)) {
+ if (aclnode->z_ace_count == 0)
+ continue;
+ bcopy(aclnode->z_acldata, start, aclnode->z_size);
+ start = (caddr_t)start + aclnode->z_size;
+ }
}
- zp->z_phys->zp_flags &= ~(ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE);
- if (inherit) {
- zp->z_phys->zp_flags |= ZFS_INHERIT_ACE;
- } else if (ace_trivial(zacl->z_ace_data, zacl->z_acl_count) == 0) {
- zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
+ /*
+ * If Old version then swap count/bytes to match old
+ * layout of znode_acl_phys_t.
+ */
+ if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
+ zphys->zp_acl.z_acl_size = aclp->z_acl_count;
+ zphys->zp_acl.z_acl_count = aclp->z_acl_bytes;
+ } else {
+ zphys->zp_acl.z_acl_size = aclp->z_acl_bytes;
+ zphys->zp_acl.z_acl_count = aclp->z_acl_count;
}
- zphys->zp_mode = zfs_mode_compute(zp, aclp);
- zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
+ zphys->zp_acl.z_acl_version = aclp->z_version;
+
+ /*
+ * Replace ACL wide bits, but first clear them.
+ */
+ zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS;
+
+ zp->z_phys->zp_flags |= aclp->z_hints;
+ if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0)
+ zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
+
+ zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
return (0);
}
/*
- * Create space for slots_needed ACEs to be append
- * to aclp.
+ * Remove ACE from aclp
*/
static void
-zfs_acl_append(zfs_acl_t *aclp, int slots_needed)
+zfs_ace_remove(zfs_acl_t *aclp, void *acep)
{
- ace_t *newacep;
- ace_t *oldaclp;
- int slot_cnt;
- int slots_left = aclp->z_slots - aclp->z_acl_count;
+ zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp);
+ size_t length;
- if (aclp->z_state == ACL_DATA_ALLOCED)
- ASSERT(aclp->z_slots >= aclp->z_acl_count);
- if (slots_left < slots_needed || aclp->z_state != ACL_DATA_ALLOCED) {
- slot_cnt = aclp->z_slots + 1 + (slots_needed - slots_left);
- newacep = kmem_alloc(ZFS_ACL_SIZE(slot_cnt), KM_SLEEP);
- bcopy(aclp->z_acl, newacep,
- ZFS_ACL_SIZE(aclp->z_acl_count));
- oldaclp = aclp->z_acl;
- if (aclp->z_state == ACL_DATA_ALLOCED)
- kmem_free(oldaclp, ZFS_ACL_SIZE(aclp->z_slots));
- aclp->z_acl = newacep;
- aclp->z_slots = slot_cnt;
- aclp->z_state = ACL_DATA_ALLOCED;
+ /*
+ * If first entry then just alter acldata ptr
+ *
+ * Otherwise split node in two
+ */
+ if (currnode->z_ace_count > 1) {
+ length = currnode->z_size - ((caddr_t)aclp->z_next_ace -
+ (caddr_t)currnode->z_acldata);
+ (void) memmove(acep, aclp->z_next_ace, length);
+ currnode->z_size = currnode->z_size -
+ aclp->z_ops.ace_size(acep);
+ aclp->z_next_ace = acep;
+ aclp->z_acl_bytes -= ((caddr_t)aclp->z_next_ace -
+ (caddr_t)currnode->z_acldata);
+ } else {
+ list_remove(&aclp->z_acl, currnode);
+ aclp->z_next_ace = NULL;
+ aclp->z_acl_bytes = 0;
}
-}
-
-/*
- * Remove "slot" ACE from aclp
- */
-static void
-zfs_ace_remove(zfs_acl_t *aclp, int slot)
-{
- if (aclp->z_acl_count > 1) {
- (void) memmove(&aclp->z_acl[slot],
- &aclp->z_acl[slot +1], sizeof (ace_t) *
- (--aclp->z_acl_count - slot));
- } else
- aclp->z_acl_count--;
+ currnode->z_ace_count--;
+ currnode->z_ace_idx--;
+ aclp->z_acl_count--;
}
/*
@@ -516,16 +1138,24 @@ zfs_ace_remove(zfs_acl_t *aclp, int slot)
* This applies the "groupmask" value for aclmode property.
*/
static void
-zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
+zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep,
+ mode_t mode, uint64_t owner)
{
-
int rmask, wmask, xmask;
int user_ace;
+ uint16_t aceflags;
+ uint32_t origmask, acepmask;
+ uint64_t fuid;
+
+ aceflags = aclp->z_ops.ace_flags_get(acep);
+ fuid = aclp->z_ops.ace_who_get(acep);
+ origmask = aclp->z_ops.ace_mask_get(origacep);
+ acepmask = aclp->z_ops.ace_mask_get(acep);
- user_ace = (!(acep->a_flags &
+ user_ace = (!(aceflags &
(ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
- if (user_ace && (acep->a_who == owner)) {
+ if (user_ace && (fuid == owner)) {
rmask = S_IRUSR;
wmask = S_IWUSR;
xmask = S_IXUSR;
@@ -535,33 +1165,38 @@ zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
xmask = S_IXGRP;
}
- if (origacep->a_access_mask & ACE_READ_DATA) {
- if (mode & rmask)
- acep->a_access_mask &= ~ACE_READ_DATA;
- else
- acep->a_access_mask |= ACE_READ_DATA;
+ if (origmask & ACE_READ_DATA) {
+ if (mode & rmask) {
+ acepmask &= ~ACE_READ_DATA;
+ } else {
+ acepmask |= ACE_READ_DATA;
+ }
}
- if (origacep->a_access_mask & ACE_WRITE_DATA) {
- if (mode & wmask)
- acep->a_access_mask &= ~ACE_WRITE_DATA;
- else
- acep->a_access_mask |= ACE_WRITE_DATA;
+ if (origmask & ACE_WRITE_DATA) {
+ if (mode & wmask) {
+ acepmask &= ~ACE_WRITE_DATA;
+ } else {
+ acepmask |= ACE_WRITE_DATA;
+ }
}
- if (origacep->a_access_mask & ACE_APPEND_DATA) {
- if (mode & wmask)
- acep->a_access_mask &= ~ACE_APPEND_DATA;
- else
- acep->a_access_mask |= ACE_APPEND_DATA;
+ if (origmask & ACE_APPEND_DATA) {
+ if (mode & wmask) {
+ acepmask &= ~ACE_APPEND_DATA;
+ } else {
+ acepmask |= ACE_APPEND_DATA;
+ }
}
- if (origacep->a_access_mask & ACE_EXECUTE) {
- if (mode & xmask)
- acep->a_access_mask &= ~ACE_EXECUTE;
- else
- acep->a_access_mask |= ACE_EXECUTE;
+ if (origmask & ACE_EXECUTE) {
+ if (mode & xmask) {
+ acepmask &= ~ACE_EXECUTE;
+ } else {
+ acepmask |= ACE_EXECUTE;
+ }
}
+ aclp->z_ops.ace_mask_set(acep, acepmask);
}
/*
@@ -570,116 +1205,156 @@ zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
static void
zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
{
- int cnt;
- ace_t *acep;
+ zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
+ void *acep;
+ int maskoff = aclp->z_ops.ace_mask_off();
+ size_t abstract_size = aclp->z_ops.ace_abstract_size();
- cnt = aclp->z_acl_count -1;
- acep = aclp->z_acl;
+ ASSERT(aclnode != NULL);
+
+ acep = (void *)((caddr_t)aclnode->z_acldata +
+ aclnode->z_size - (abstract_size * 6));
/*
* Fixup final ACEs to match the mode
*/
- ASSERT(cnt >= 5);
- adjust_ace_pair(&acep[cnt - 1], mode); /* everyone@ */
- adjust_ace_pair(&acep[cnt - 3], (mode & 0070) >> 3); /* group@ */
- adjust_ace_pair(&acep[cnt - 5], (mode & 0700) >> 6); /* owner@ */
+ adjust_ace_pair_common(acep, maskoff, abstract_size,
+ (mode & 0700) >> 6); /* owner@ */
+
+ acep = (caddr_t)acep + (abstract_size * 2);
+
+ adjust_ace_pair_common(acep, maskoff, abstract_size,
+ (mode & 0070) >> 3); /* group@ */
+
+ acep = (caddr_t)acep + (abstract_size * 2);
+ adjust_ace_pair_common(acep, maskoff,
+ abstract_size, mode); /* everyone@ */
}
static int
-zfs_acl_ace_match(ace_t *acep, int allow_deny, int type, int mask)
+zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny,
+ int entry_type, int accessmask)
{
- return (acep->a_access_mask == mask && acep->a_type == allow_deny &&
- ((acep->a_flags & ACE_TYPE_FLAGS) == type));
+ uint32_t mask = aclp->z_ops.ace_mask_get(acep);
+ uint16_t type = aclp->z_ops.ace_type_get(acep);
+ uint16_t flags = aclp->z_ops.ace_flags_get(acep);
+
+ return (mask == accessmask && type == allow_deny &&
+ ((flags & ACE_TYPE_FLAGS) == entry_type));
}
/*
* Can prepended ACE be reused?
*/
static int
-zfs_reuse_deny(ace_t *acep, int i)
+zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep)
{
int okay_masks;
+ uint16_t prevtype;
+ uint16_t prevflags;
+ uint16_t flags;
+ uint32_t mask, prevmask;
- if (i < 1)
+ if (prevacep == NULL)
return (B_FALSE);
- if (acep[i-1].a_type != DENY)
+ prevtype = aclp->z_ops.ace_type_get(prevacep);
+ prevflags = aclp->z_ops.ace_flags_get(prevacep);
+ flags = aclp->z_ops.ace_flags_get(acep);
+ mask = aclp->z_ops.ace_mask_get(acep);
+ prevmask = aclp->z_ops.ace_mask_get(prevacep);
+
+ if (prevtype != DENY)
return (B_FALSE);
- if (acep[i-1].a_flags != (acep[i].a_flags & ACE_IDENTIFIER_GROUP))
+ if (prevflags != (flags & ACE_IDENTIFIER_GROUP))
return (B_FALSE);
- okay_masks = (acep[i].a_access_mask & OKAY_MASK_BITS);
+ okay_masks = (mask & OKAY_MASK_BITS);
- if (acep[i-1].a_access_mask & ~okay_masks)
+ if (prevmask & ~okay_masks)
return (B_FALSE);
return (B_TRUE);
}
+
/*
- * Create space to prepend an ACE
+ * Insert new ACL node into chain of zfs_acl_node_t's
+ *
+ * This will result in two possible results.
+ * 1. If the ACL is currently just a single zfs_acl_node and
+ * we are prepending the entry then current acl node will have
+ * a new node inserted above it.
+ *
+ * 2. If we are inserting in the middle of current acl node then
+ * the current node will be split in two and new node will be inserted
+ * in between the two split nodes.
*/
-static void
-zfs_acl_prepend(zfs_acl_t *aclp, int i)
-{
- ace_t *oldaclp = NULL;
- ace_t *to, *from;
- int slots_left = aclp->z_slots - aclp->z_acl_count;
- int oldslots;
- int need_free = 0;
-
- if (aclp->z_state == ACL_DATA_ALLOCED)
- ASSERT(aclp->z_slots >= aclp->z_acl_count);
-
- if (slots_left == 0 || aclp->z_state != ACL_DATA_ALLOCED) {
-
- to = kmem_alloc(ZFS_ACL_SIZE(aclp->z_acl_count +
- OGE_PAD), KM_SLEEP);
- if (aclp->z_state == ACL_DATA_ALLOCED)
- need_free++;
- from = aclp->z_acl;
- oldaclp = aclp->z_acl;
- (void) memmove(to, from,
- sizeof (ace_t) * aclp->z_acl_count);
- aclp->z_state = ACL_DATA_ALLOCED;
- } else {
- from = aclp->z_acl;
- to = aclp->z_acl;
+static zfs_acl_node_t *
+zfs_acl_ace_insert(zfs_acl_t *aclp, void *acep)
+{
+ zfs_acl_node_t *newnode;
+ zfs_acl_node_t *trailernode = NULL;
+ zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp);
+ int curr_idx = aclp->z_curr_node->z_ace_idx;
+ int trailer_count;
+ size_t oldsize;
+
+ newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep));
+ newnode->z_ace_count = 1;
+
+ oldsize = currnode->z_size;
+
+ if (curr_idx != 1) {
+ trailernode = zfs_acl_node_alloc(0);
+ trailernode->z_acldata = acep;
+
+ trailer_count = currnode->z_ace_count - curr_idx + 1;
+ currnode->z_ace_count = curr_idx - 1;
+ currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata;
+ trailernode->z_size = oldsize - currnode->z_size;
+ trailernode->z_ace_count = trailer_count;
}
-
- (void) memmove(&to[i + 1], &from[i],
- sizeof (ace_t) * (aclp->z_acl_count - i));
-
- if (oldaclp) {
- aclp->z_acl = to;
- oldslots = aclp->z_slots;
- aclp->z_slots = aclp->z_acl_count + OGE_PAD;
- if (need_free)
- kmem_free(oldaclp, ZFS_ACL_SIZE(oldslots));
+ aclp->z_acl_count += 1;
+ aclp->z_acl_bytes += aclp->z_ops.ace_size(acep);
+
+ if (curr_idx == 1)
+ list_insert_before(&aclp->z_acl, currnode, newnode);
+ else
+ list_insert_after(&aclp->z_acl, currnode, newnode);
+ if (trailernode) {
+ list_insert_after(&aclp->z_acl, newnode, trailernode);
+ aclp->z_curr_node = trailernode;
+ trailernode->z_ace_idx = 1;
}
+ return (newnode);
}
/*
* Prepend deny ACE
*/
-static void
-zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, int i,
+static void *
+zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, void *acep,
mode_t mode)
{
- ace_t *acep;
-
- zfs_acl_prepend(aclp, i);
-
- acep = aclp->z_acl;
- zfs_set_ace(&acep[i], 0, DENY, acep[i + 1].a_who,
- (acep[i + 1].a_flags & ACE_TYPE_FLAGS));
- zfs_acl_prepend_fixup(&acep[i], &acep[i+1], mode, zp->z_phys->zp_uid);
- aclp->z_acl_count++;
+ zfs_acl_node_t *aclnode;
+ void *newacep;
+ uint64_t fuid;
+ uint16_t flags;
+
+ aclnode = zfs_acl_ace_insert(aclp, acep);
+ newacep = aclnode->z_acldata;
+ fuid = aclp->z_ops.ace_who_get(acep);
+ flags = aclp->z_ops.ace_flags_get(acep);
+ zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS));
+ zfs_acl_prepend_fixup(aclp, newacep, acep, mode, zp->z_phys->zp_uid);
+
+ return (newacep);
}
/*
@@ -687,41 +1362,72 @@ zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, int i,
* and original ACE with inheritance flags stripped off.
*/
static void
-zfs_acl_split_ace(zfs_acl_t *aclp, int i)
+zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep)
{
- ace_t *acep = aclp->z_acl;
-
- zfs_acl_prepend(aclp, i);
- acep = aclp->z_acl;
- acep[i] = acep[i + 1];
- acep[i].a_flags |= ACE_INHERIT_ONLY_ACE;
- acep[i + 1].a_flags &= ~ALL_INHERIT;
- aclp->z_acl_count++;
+ zfs_acl_node_t *aclnode;
+ zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp);
+ void *newacep;
+ uint16_t type, flags;
+ uint32_t mask;
+ uint64_t fuid;
+
+ type = aclp->z_ops.ace_type_get(acep);
+ flags = aclp->z_ops.ace_flags_get(acep);
+ mask = aclp->z_ops.ace_mask_get(acep);
+ fuid = aclp->z_ops.ace_who_get(acep);
+
+ aclnode = zfs_acl_ace_insert(aclp, acep);
+ newacep = aclnode->z_acldata;
+
+ aclp->z_ops.ace_type_set(newacep, type);
+ aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE);
+ aclp->z_ops.ace_mask_set(newacep, mask);
+ aclp->z_ops.ace_type_set(newacep, type);
+ aclp->z_ops.ace_who_set(newacep, fuid);
+ aclp->z_next_ace = acep;
+ flags &= ~ALL_INHERIT;
+ aclp->z_ops.ace_flags_set(acep, flags);
+ currnode->z_ace_idx -= 1;
}
/*
* Are ACES started at index i, the canonical six ACES?
*/
static int
-zfs_have_canonical_six(zfs_acl_t *aclp, int i)
+zfs_have_canonical_six(zfs_acl_t *aclp)
{
- ace_t *acep = aclp->z_acl;
+ void *acep;
+ zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
+ int i = 0;
+ size_t abstract_size = aclp->z_ops.ace_abstract_size();
+
+ ASSERT(aclnode != NULL);
- if ((zfs_acl_ace_match(&acep[i],
+ if (aclnode->z_ace_count < 6)
+ return (0);
+
+ acep = (void *)((caddr_t)aclnode->z_acldata +
+ aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6));
+
+ if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
DENY, ACE_OWNER, 0) &&
- zfs_acl_ace_match(&acep[i + 1], ALLOW, ACE_OWNER,
- OWNER_ALLOW_MASK) && zfs_acl_ace_match(&acep[i + 2],
- DENY, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 3],
- ALLOW, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 4],
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
+ ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) &&
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY,
+ OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep +
+ (abstract_size * i++),
+ ALLOW, OWNING_GROUP, 0) &&
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) &&
- zfs_acl_ace_match(&acep[i + 5], ALLOW, ACE_EVERYONE,
- EVERYONE_ALLOW_MASK))) {
+ zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
+ ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) {
return (1);
} else {
return (0);
}
}
+
/*
* Apply step 1g, to group entries
*
@@ -731,32 +1437,36 @@ zfs_have_canonical_six(zfs_acl_t *aclp, int i)
* group has.
*/
static void
-zfs_fixup_group_entries(ace_t *acep, mode_t mode)
+zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep,
+ mode_t mode)
{
+ uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep);
+ uint32_t mask = aclp->z_ops.ace_mask_get(acep);
+ uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep);
mode_t extramode = (mode >> 3) & 07;
mode_t ownermode = (mode >> 6);
- if (acep[0].a_flags & ACE_IDENTIFIER_GROUP) {
+ if (prevflags & ACE_IDENTIFIER_GROUP) {
extramode &= ~ownermode;
if (extramode) {
- if (extramode & 04) {
- acep[0].a_access_mask &= ~ACE_READ_DATA;
- acep[1].a_access_mask &= ~ACE_READ_DATA;
+ if (extramode & S_IROTH) {
+ prevmask &= ~ACE_READ_DATA;
+ mask &= ~ACE_READ_DATA;
}
- if (extramode & 02) {
- acep[0].a_access_mask &=
- ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
- acep[1].a_access_mask &=
- ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+ if (extramode & S_IWOTH) {
+ prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+ mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
}
- if (extramode & 01) {
- acep[0].a_access_mask &= ~ACE_EXECUTE;
- acep[1].a_access_mask &= ~ACE_EXECUTE;
+ if (extramode & S_IXOTH) {
+ prevmask &= ~ACE_EXECUTE;
+ mask &= ~ACE_EXECUTE;
}
}
}
+ aclp->z_ops.ace_mask_set(acep, mask);
+ aclp->z_ops.ace_mask_set(prevacep, prevmask);
}
/*
@@ -768,58 +1478,64 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
dmu_tx_t *tx)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- ace_t *acep;
+ void *acep = NULL, *prevacep = NULL;
+ uint64_t who;
int i;
int error;
int entry_type;
int reuse_deny;
int need_canonical_six = 1;
- int inherit = 0;
- int iflags;
+ uint16_t iflags, type;
+ uint32_t access_mask;
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
ASSERT(MUTEX_HELD(&zp->z_lock));
- i = 0;
- while (i < aclp->z_acl_count) {
- acep = aclp->z_acl;
- entry_type = (acep[i].a_flags & ACE_TYPE_FLAGS);
- iflags = (acep[i].a_flags & ALL_INHERIT);
+ aclp->z_hints = (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
+ while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+ &iflags, &type)) {
+
+ entry_type = (iflags & ACE_TYPE_FLAGS);
+ iflags = (iflags & ALL_INHERIT);
- if ((acep[i].a_type != ALLOW && acep[i].a_type != DENY) ||
+ if ((type != ALLOW && type != DENY) ||
(iflags & ACE_INHERIT_ONLY_ACE)) {
- i++;
if (iflags)
- inherit = 1;
- continue;
+ aclp->z_hints |= ZFS_INHERIT_ACE;
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ aclp->z_hints |= ZFS_ACL_OBJ_ACE;
+ break;
+ }
+ goto nextace;
}
-
if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) {
- zfs_ace_remove(aclp, i);
- continue;
+ zfs_ace_remove(aclp, acep);
+ goto nextace;
}
-
/*
* Need to split ace into two?
*/
if ((iflags & (ACE_FILE_INHERIT_ACE|
ACE_DIRECTORY_INHERIT_ACE)) &&
(!(iflags & ACE_INHERIT_ONLY_ACE))) {
- zfs_acl_split_ace(aclp, i);
- i++;
- inherit = 1;
- continue;
+ zfs_acl_split_ace(aclp, acep);
+ aclp->z_hints |= ZFS_INHERIT_ACE;
+ goto nextace;
}
if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
(entry_type == OWNING_GROUP)) {
- acep[i].a_access_mask &= ~OGE_CLEAR;
- i++;
- continue;
-
+ access_mask &= ~OGE_CLEAR;
+ aclp->z_ops.ace_mask_set(acep, access_mask);
+ goto nextace;
} else {
- if (acep[i].a_type == ALLOW) {
+ reuse_deny = B_TRUE;
+ if (type == ALLOW) {
/*
* Check preceding ACE if any, to see
@@ -829,25 +1545,27 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
*/
if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) {
- reuse_deny = zfs_reuse_deny(acep, i);
+ reuse_deny = zfs_reuse_deny(aclp, acep,
+ prevacep);
if (reuse_deny == B_FALSE) {
- zfs_acl_prepend_deny(zp, aclp,
- i, mode);
- i++;
- acep = aclp->z_acl;
+ prevacep =
+ zfs_acl_prepend_deny(zp,
+ aclp, acep, mode);
} else {
zfs_acl_prepend_fixup(
- &acep[i - 1],
- &acep[i], mode,
+ aclp, prevacep,
+ acep, mode,
zp->z_phys->zp_uid);
}
- zfs_fixup_group_entries(&acep[i - 1],
- mode);
+ zfs_fixup_group_entries(aclp, acep,
+ prevacep, mode);
+
}
}
- i++;
}
+nextace:
+ prevacep = acep;
}
/*
@@ -855,37 +1573,46 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
*/
if (aclp->z_acl_count >= 6) {
- i = aclp->z_acl_count - 6;
-
- if (zfs_have_canonical_six(aclp, i)) {
+ if (zfs_have_canonical_six(aclp)) {
need_canonical_six = 0;
}
}
if (need_canonical_six) {
-
- zfs_acl_append(aclp, 6);
- i = aclp->z_acl_count;
- acep = aclp->z_acl;
- zfs_set_ace(&acep[i++], 0, DENY, -1, ACE_OWNER);
- zfs_set_ace(&acep[i++], OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
- zfs_set_ace(&acep[i++], 0, DENY, -1, OWNING_GROUP);
- zfs_set_ace(&acep[i++], 0, ALLOW, -1, OWNING_GROUP);
- zfs_set_ace(&acep[i++], EVERYONE_DENY_MASK,
- DENY, -1, ACE_EVERYONE);
- zfs_set_ace(&acep[i++], EVERYONE_ALLOW_MASK,
- ALLOW, -1, ACE_EVERYONE);
+ size_t abstract_size = aclp->z_ops.ace_abstract_size();
+ void *zacep;
+ zfs_acl_node_t *aclnode =
+ zfs_acl_node_alloc(abstract_size * 6);
+
+ aclnode->z_size = abstract_size * 6;
+ aclnode->z_ace_count = 6;
+ aclp->z_acl_bytes += aclnode->z_size;
+ list_insert_tail(&aclp->z_acl, aclnode);
+
+ zacep = aclnode->z_acldata;
+
+ i = 0;
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ 0, DENY, -1, ACE_OWNER);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
+ DENY, -1, OWNING_GROUP);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
+ ALLOW, -1, OWNING_GROUP);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE);
+ zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
+ EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE);
aclp->z_acl_count += 6;
}
zfs_acl_fixup_canonical_six(aclp, mode);
-
zp->z_phys->zp_mode = mode;
- error = zfs_aclset_common(zp, aclp, tx, &inherit);
+ error = zfs_aclset_common(zp, aclp, NULL, tx);
return (error);
}
-
int
zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
{
@@ -894,7 +1621,7 @@ zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
ASSERT(MUTEX_HELD(&zp->z_lock));
mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_node_read(zp, &aclp);
+ error = zfs_acl_node_read(zp, &aclp, B_TRUE);
if (error == 0)
error = zfs_acl_chmod(zp, mode, aclp, tx);
mutex_exit(&zp->z_acl_lock);
@@ -907,11 +1634,32 @@ zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
* strip off write_owner and write_acl
*/
static void
-zfs_securemode_update(zfsvfs_t *zfsvfs, ace_t *acep)
+zfs_securemode_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep)
{
+ uint32_t mask = aclp->z_ops.ace_mask_get(acep);
+
if ((zfsvfs->z_acl_inherit == ZFS_ACL_SECURE) &&
- (acep->a_type == ALLOW))
- acep->a_access_mask &= ~SECURE_CLEAR;
+ (aclp->z_ops.ace_type_get(acep) == ALLOW)) {
+ mask &= ~SECURE_CLEAR;
+ aclp->z_ops.ace_mask_set(acep, mask);
+ }
+}
+
+/*
+ * Should ACE be inherited?
+ */
+static int
+zfs_ace_can_use(znode_t *zp, uint16_t acep_flags)
+{
+ int vtype = ZTOV(zp)->v_type;
+ int iflags = (acep_flags & 0xf);
+
+ if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
+ return (1);
+ else if (iflags & ACE_FILE_INHERIT_ACE)
+ return (!((vtype == VDIR) &&
+ (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
+ return (0);
}
/*
@@ -921,90 +1669,108 @@ static zfs_acl_t *
zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- ace_t *pacep;
- ace_t *acep;
- int ace_cnt = 0;
- int pace_cnt;
- int i, j;
+ void *pacep;
+ void *acep, *acep2;
+ zfs_acl_node_t *aclnode, *aclnode2;
zfs_acl_t *aclp = NULL;
-
- i = j = 0;
- pace_cnt = paclp->z_acl_count;
- pacep = paclp->z_acl;
+ uint64_t who;
+ uint32_t access_mask;
+ uint16_t iflags, newflags, type;
+ size_t ace_size;
+ void *data1, *data2;
+ size_t data1sz, data2sz;
+
+ pacep = NULL;
+ aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
if (zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
- for (i = 0; i != pace_cnt; i++) {
+ while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
+ &access_mask, &iflags, &type)) {
if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
- pacep[i].a_type == ALLOW)
+ type == ALLOW)
continue;
- if (zfs_ace_can_use(zp, &pacep[i])) {
- ace_cnt++;
- if (!(pacep[i].a_flags &
- ACE_NO_PROPAGATE_INHERIT_ACE))
- ace_cnt++;
- }
- }
- }
+ ace_size = aclp->z_ops.ace_size(pacep);
- aclp = zfs_acl_alloc(ace_cnt + OGE_PAD);
- if (ace_cnt && zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
- acep = aclp->z_acl;
- pacep = paclp->z_acl;
- for (i = 0; i != pace_cnt; i++) {
+ if (zfs_ace_can_use(zp, iflags)) {
+ aclnode =
+ zfs_acl_node_alloc(ace_size);
- if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
- pacep[i].a_type == ALLOW)
- continue;
-
- if (zfs_ace_can_use(zp, &pacep[i])) {
+ list_insert_tail(&aclp->z_acl, aclnode);
+ acep = aclnode->z_acldata;
+ zfs_set_ace(aclp, acep, access_mask, type,
+ who, iflags|ACE_INHERITED_ACE);
/*
- * Now create entry for inherited ace
+ * Copy special opaque data if any
*/
-
- acep[j] = pacep[i];
-
- /*
- * When AUDIT/ALARM a_types are supported
- * they should be inherited here.
- */
-
- if ((pacep[i].a_flags &
+ if ((data1sz = paclp->z_ops.ace_data(pacep,
+ &data1)) != 0) {
+ VERIFY((data2sz =
+ aclp->z_ops.ace_data(acep,
+ &data2)) == data1sz);
+ bcopy(data1, data2, data2sz);
+ }
+ aclp->z_acl_count++;
+ aclnode->z_ace_count++;
+ aclp->z_acl_bytes += aclnode->z_size;
+ newflags = aclp->z_ops.ace_flags_get(acep);
+ if ((iflags &
ACE_NO_PROPAGATE_INHERIT_ACE) ||
(ZTOV(zp)->v_type != VDIR)) {
- acep[j].a_flags &= ~ALL_INHERIT;
- zfs_securemode_update(zfsvfs, &acep[j]);
- j++;
+ newflags &= ~ALL_INHERIT;
+ aclp->z_ops.ace_flags_set(acep,
+ newflags|ACE_INHERITED_ACE);
+ zfs_securemode_update(zfsvfs,
+ aclp, acep);
continue;
}
ASSERT(ZTOV(zp)->v_type == VDIR);
- /*
- * If we are inheriting an ACE targeted for
- * only files, then make sure inherit_only
- * is on for future propagation.
- */
- if ((pacep[i].a_flags & (ACE_FILE_INHERIT_ACE |
+ newflags = aclp->z_ops.ace_flags_get(acep);
+ if ((iflags & (ACE_FILE_INHERIT_ACE |
ACE_DIRECTORY_INHERIT_ACE)) !=
ACE_FILE_INHERIT_ACE) {
- j++;
- acep[j] = acep[j-1];
- acep[j-1].a_flags |=
- ACE_INHERIT_ONLY_ACE;
- acep[j].a_flags &= ~ALL_INHERIT;
+ aclnode2 = zfs_acl_node_alloc(ace_size);
+ list_insert_tail(&aclp->z_acl,
+ aclnode2);
+ acep2 = aclnode2->z_acldata;
+ zfs_set_ace(aclp, acep2,
+ access_mask, type, who,
+ iflags|ACE_INHERITED_ACE);
+ newflags |= ACE_INHERIT_ONLY_ACE;
+ aclp->z_ops.ace_flags_set(acep,
+ newflags);
+ newflags &= ~ALL_INHERIT;
+ aclp->z_ops.ace_flags_set(acep2,
+ newflags|ACE_INHERITED_ACE);
+
+ /*
+ * Copy special opaque data if any
+ */
+ if ((data1sz =
+ aclp->z_ops.ace_data(acep,
+ &data1)) != 0) {
+ VERIFY((data2sz =
+ aclp->z_ops.ace_data(acep2,
+ &data2)) == data1sz);
+ bcopy(data1, data2, data1sz);
+ }
+ aclp->z_acl_count++;
+ aclnode2->z_ace_count++;
+ aclp->z_acl_bytes += aclnode->z_size;
+ zfs_securemode_update(zfsvfs,
+ aclp, acep2);
} else {
- acep[j].a_flags |= ACE_INHERIT_ONLY_ACE;
+ newflags |= ACE_INHERIT_ONLY_ACE;
+ aclp->z_ops.ace_flags_set(acep,
+ newflags|ACE_INHERITED_ACE);
}
- zfs_securemode_update(zfsvfs, &acep[j]);
- j++;
+
}
}
}
- aclp->z_acl_count = j;
- ASSERT(aclp->z_slots >= aclp->z_acl_count);
-
return (aclp);
}
@@ -1014,14 +1780,21 @@ zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
*/
void
zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
- vattr_t *vap, dmu_tx_t *tx, cred_t *cr)
+ vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
+ zfs_acl_t *setaclp, zfs_fuid_info_t **fuidp)
{
uint64_t mode;
- uid_t uid;
- gid_t gid;
+ uint64_t uid;
+ uint64_t gid;
int error;
int pull_down;
- zfs_acl_t *aclp, *paclp;
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+ zfs_acl_t *aclp = NULL;
+ zfs_acl_t *paclp;
+ xvattr_t *xvap = (xvattr_t *)vap;
+
+ if (setaclp)
+ aclp = setaclp;
mode = MAKEIMODE(vap->va_type, vap->va_mode);
@@ -1030,18 +1803,25 @@ zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
*/
if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
((flag & IS_XATTR) && (vap->va_type == VDIR))) {
- uid = vap->va_uid;
- gid = vap->va_gid;
+ uid = zfs_fuid_create(zfsvfs, vap->va_uid,
+ ZFS_OWNER, tx, fuidp);
+ gid = zfs_fuid_create(zfsvfs, vap->va_gid,
+ ZFS_GROUP, tx, fuidp);
} else {
- uid = crgetuid(cr);
+ uid = zfs_fuid_create_cred(zfsvfs, crgetuid(cr),
+ ZFS_OWNER, tx, cr, fuidp);
if ((vap->va_mask & AT_GID) &&
((vap->va_gid == parent->z_phys->zp_gid) ||
groupmember(vap->va_gid, cr) ||
- secpolicy_vnode_create_gid(cr) == 0))
- gid = vap->va_gid;
- else
+ secpolicy_vnode_create_gid(cr) == 0)) {
+ gid = zfs_fuid_create_cred(zfsvfs, vap->va_gid,
+ ZFS_GROUP, tx, cr, fuidp);
+ } else {
gid = (parent->z_phys->zp_mode & S_ISGID) ?
parent->z_phys->zp_gid : crgetgid(cr);
+ gid = zfs_fuid_create_cred(zfsvfs, gid,
+ ZFS_GROUP, tx, cr, fuidp);
+ }
}
/*
@@ -1063,85 +1843,133 @@ zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
zp->z_phys->zp_gid = gid;
zp->z_phys->zp_mode = mode;
- mutex_enter(&parent->z_lock);
- pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
- if (pull_down) {
- mutex_enter(&parent->z_acl_lock);
- VERIFY(0 == zfs_acl_node_read(parent, &paclp));
- mutex_exit(&parent->z_acl_lock);
- aclp = zfs_acl_inherit(zp, paclp);
- zfs_acl_free(paclp);
+ if (aclp == NULL) {
+ mutex_enter(&parent->z_lock);
+ pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
+ if (pull_down) {
+ mutex_enter(&parent->z_acl_lock);
+ VERIFY(0 == zfs_acl_node_read(parent, &paclp, B_FALSE));
+ mutex_exit(&parent->z_acl_lock);
+ aclp = zfs_acl_inherit(zp, paclp);
+ zfs_acl_free(paclp);
+ } else {
+ aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
+ }
+ mutex_exit(&parent->z_lock);
+ mutex_enter(&zp->z_lock);
+ mutex_enter(&zp->z_acl_lock);
+ error = zfs_acl_chmod(zp, mode, aclp, tx);
} else {
- aclp = zfs_acl_alloc(6);
+ mutex_enter(&zp->z_lock);
+ mutex_enter(&zp->z_acl_lock);
}
- mutex_exit(&parent->z_lock);
- mutex_enter(&zp->z_lock);
- mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_chmod(zp, mode, aclp, tx);
+
+ /* Force auto_inherit on all new directory objects */
+ if (vap->va_type == VDIR)
+ aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
+
+ error = zfs_aclset_common(zp, aclp, fuidp, tx);
+
+ /* Set optional attributes if any */
+ if (vap->va_mask & AT_XVATTR)
+ zfs_xvattr_set(zp, xvap);
+
mutex_exit(&zp->z_lock);
mutex_exit(&zp->z_acl_lock);
ASSERT3U(error, ==, 0);
- zfs_acl_free(aclp);
-}
-
-/*
- * Should ACE be inherited?
- */
-static int
-zfs_ace_can_use(znode_t *zp, ace_t *acep)
-{
- int vtype = ZTOV(zp)->v_type;
-
- int iflags = (acep->a_flags & 0xf);
- if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
- return (1);
- else if (iflags & ACE_FILE_INHERIT_ACE)
- return (!((vtype == VDIR) &&
- (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
- return (0);
+ if (aclp != setaclp) {
+ zfs_acl_free(aclp);
+ }
}
/*
* Retrieve a files ACL
*/
int
-zfs_getacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
+zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
{
zfs_acl_t *aclp;
- ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
+ ulong_t mask;
int error;
+ int count = 0;
+ int largeace = 0;
- if (error = zfs_zaccess(zp, ACE_READ_ACL, cr)) {
- /*
- * If owner of file then allow reading of the
- * ACL.
- */
- if (crgetuid(cr) != zp->z_phys->zp_uid)
- return (error);
- }
+ mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
+ VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
+
+ if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
+ return (error);
if (mask == 0)
return (ENOSYS);
mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_node_read(zp, &aclp);
+ error = zfs_acl_node_read(zp, &aclp, B_FALSE);
if (error != 0) {
mutex_exit(&zp->z_acl_lock);
return (error);
}
+ /*
+ * Scan ACL to determine number of ACEs
+ */
+ if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) &&
+ !(mask & VSA_ACE_ALLTYPES)) {
+ void *zacep = NULL;
+ uint64_t who;
+ uint32_t access_mask;
+ uint16_t type, iflags;
+
+ while (zacep = zfs_acl_next_ace(aclp, zacep,
+ &who, &access_mask, &iflags, &type)) {
+ switch (type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ largeace++;
+ continue;
+ default:
+ count++;
+ }
+ }
+ vsecp->vsa_aclcnt = count;
+ } else
+ count = aclp->z_acl_count;
if (mask & VSA_ACECNT) {
- vsecp->vsa_aclcnt = aclp->z_acl_count;
+ vsecp->vsa_aclcnt = count;
}
if (mask & VSA_ACE) {
- vsecp->vsa_aclentp = kmem_alloc(aclp->z_acl_count *
- sizeof (ace_t), KM_SLEEP);
- bcopy(aclp->z_acl, vsecp->vsa_aclentp,
- aclp->z_acl_count * sizeof (ace_t));
+ size_t aclsz;
+
+ zfs_acl_node_t *aclnode = list_head(&aclp->z_acl);
+
+ aclsz = count * sizeof (ace_t) +
+ sizeof (ace_object_t) * largeace;
+
+ vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
+ vsecp->vsa_aclentsz = aclsz;
+
+ if (aclp->z_version == ZFS_ACL_VERSION_FUID)
+ zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp,
+ vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
+ else {
+ bcopy(aclnode->z_acldata, vsecp->vsa_aclentp,
+ count * sizeof (ace_t));
+ }
+ }
+ if (mask & VSA_ACE_ACLFLAGS) {
+ vsecp->vsa_aclflags = 0;
+ if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED)
+ vsecp->vsa_aclflags |= ACL_DEFAULTED;
+ if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED)
+ vsecp->vsa_aclflags |= ACL_PROTECTED;
+ if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT)
+ vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
}
mutex_exit(&zp->z_acl_lock);
@@ -1151,36 +1979,99 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
return (0);
}
+int
+zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
+ vsecattr_t *vsecp, zfs_acl_t **zaclp)
+{
+ zfs_acl_t *aclp;
+ zfs_acl_node_t *aclnode;
+ int aclcnt = vsecp->vsa_aclcnt;
+ int error;
+
+ if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
+ return (EINVAL);
+
+ aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
+
+ aclp->z_hints = 0;
+ aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
+ if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
+ if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
+ (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
+ aclcnt, &aclnode->z_size)) != 0) {
+ zfs_acl_free(aclp);
+ zfs_acl_node_free(aclnode);
+ return (error);
+ }
+ } else {
+ if ((error = zfs_copy_ace_2_fuid(obj_type, aclp,
+ vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
+ &aclnode->z_size)) != 0) {
+ zfs_acl_free(aclp);
+ zfs_acl_node_free(aclnode);
+ return (error);
+ }
+ }
+ aclp->z_acl_bytes = aclnode->z_size;
+ aclnode->z_ace_count = aclcnt;
+ aclp->z_acl_count = aclcnt;
+ list_insert_head(&aclp->z_acl, aclnode);
+
+ /*
+ * If flags are being set then add them to z_hints
+ */
+ if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
+ if (vsecp->vsa_aclflags & ACL_PROTECTED)
+ aclp->z_hints |= ZFS_ACL_PROTECTED;
+ if (vsecp->vsa_aclflags & ACL_DEFAULTED)
+ aclp->z_hints |= ZFS_ACL_DEFAULTED;
+ if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
+ aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
+ }
+
+ *zaclp = aclp;
+
+ return (0);
+}
+
/*
* Set a files ACL
*/
int
-zfs_setacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
+zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
zilog_t *zilog = zfsvfs->z_log;
- ace_t *acep = vsecp->vsa_aclentp;
- int aclcnt = vsecp->vsa_aclcnt;
ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
dmu_tx_t *tx;
int error;
- int inherit;
zfs_acl_t *aclp;
+ zfs_fuid_info_t *fuidp = NULL;
if (mask == 0)
return (ENOSYS);
- if (!zfs_acl_valid(zp, acep, aclcnt, &inherit))
- return (EINVAL);
+ if (zp->z_phys->zp_flags & ZFS_IMMUTABLE)
+ return (EPERM);
+
+ if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
+ return (error);
+
+ error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, &aclp);
+ if (error)
+ return (error);
+
+ /*
+ * If ACL wide flags aren't being set then preserve any
+ * existing flags.
+ */
+ if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
+ aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
+ }
top:
- error = zfs_zaccess_v4_perm(zp, ACE_WRITE_ACL, cr);
- if (error == EACCES || error == ACCESS_UNDETERMINED) {
- if ((error = secpolicy_vnode_setdac(cr,
- zp->z_phys->zp_uid)) != 0) {
- return (error);
- }
- } else if (error) {
- return (error == EROFS ? error : EPERM);
+ if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) {
+ zfs_acl_free(aclp);
+ return (error);
}
mutex_enter(&zp->z_lock);
@@ -1190,10 +2081,32 @@ top:
dmu_tx_hold_bonus(tx, zp->z_id);
if (zp->z_phys->zp_acl.z_acl_extern_obj) {
- dmu_tx_hold_write(tx, zp->z_phys->zp_acl.z_acl_extern_obj,
- 0, ZFS_ACL_SIZE(aclcnt));
- } else if (aclcnt > ACE_SLOT_CNT) {
- dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, ZFS_ACL_SIZE(aclcnt));
+ /* Are we upgrading ACL? */
+ if (zfsvfs->z_version <= ZPL_VERSION_FUID &&
+ zp->z_phys->zp_acl.z_acl_version ==
+ ZFS_ACL_VERSION_INITIAL) {
+ dmu_tx_hold_free(tx,
+ zp->z_phys->zp_acl.z_acl_extern_obj,
+ 0, DMU_OBJECT_END);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+ 0, sizeof (zfs_object_ace_t) * 2048 + 6);
+ } else {
+ dmu_tx_hold_write(tx,
+ zp->z_phys->zp_acl.z_acl_extern_obj,
+ 0, aclp->z_acl_bytes);
+ }
+ } else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
+ }
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
}
error = dmu_tx_assign(tx, zfsvfs->z_assign);
@@ -1207,17 +2120,18 @@ top:
goto top;
}
dmu_tx_abort(tx);
+ zfs_acl_free(aclp);
return (error);
}
- aclp = zfs_acl_alloc(aclcnt);
- bcopy(acep, aclp->z_acl, sizeof (ace_t) * aclcnt);
- aclp->z_acl_count = aclcnt;
- error = zfs_aclset_common(zp, aclp, tx, &inherit);
+ error = zfs_aclset_common(zp, aclp, &fuidp, tx);
ASSERT(error == 0);
+ zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
+
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
zfs_acl_free(aclp);
- zfs_log_acl(zilog, tx, TX_ACL, zp, aclcnt, acep);
dmu_tx_commit(tx);
done:
mutex_exit(&zp->z_acl_lock);
@@ -1226,46 +2140,34 @@ done:
return (error);
}
+/*
+ * working_mode returns the permissions that were not granted
+ */
static int
-zfs_ace_access(ace_t *zacep, int *working_mode)
-{
- if (*working_mode == 0) {
- return (0);
- }
-
- if (zacep->a_access_mask & *working_mode) {
- if (zacep->a_type == ALLOW) {
- *working_mode &=
- ~(*working_mode & zacep->a_access_mask);
- if (*working_mode == 0)
- return (0);
- } else if (zacep->a_type == DENY) {
- return (EACCES);
- }
- }
-
- /*
- * haven't been specifcally denied at this point
- * so return UNDETERMINED.
- */
-
- return (ACCESS_UNDETERMINED);
-}
-
-
-static int
-zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
+zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
+ boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
{
zfs_acl_t *aclp;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- ace_t *zacep;
- gid_t gid;
- int cnt;
- int i;
int error;
int access_deny = ACCESS_UNDETERMINED;
- uint_t entry_type;
uid_t uid = crgetuid(cr);
+ uint64_t who;
+ uint16_t type, iflags;
+ uint16_t entry_type;
+ uint32_t access_mask;
+ zfs_ace_hdr_t *acep = NULL;
+ boolean_t checkit;
+ uid_t fowner;
+ uid_t gowner;
+
+ /*
+ * Short circuit empty requests
+ */
+ if (v4_mode == 0)
+ return (0);
+
+ *check_privs = B_TRUE;
if (zfsvfs->z_assign >= TXG_INITIAL) { /* ZIL replay */
*working_mode = 0;
@@ -1277,68 +2179,109 @@ zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
if ((v4_mode & WRITE_MASK) &&
(zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
(!IS_DEVVP(ZTOV(zp)))) {
+ *check_privs = B_FALSE;
return (EROFS);
}
+ /*
+ * Only check for READONLY on non-directories.
+ */
+ if ((v4_mode & WRITE_MASK_DATA) &&
+ (((ZTOV(zp)->v_type != VDIR) &&
+ (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
+ (ZTOV(zp)->v_type == VDIR &&
+ (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) {
+ *check_privs = B_FALSE;
+ return (EPERM);
+ }
+
+ if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
+ (zp->z_phys->zp_flags & ZFS_NOUNLINK)) {
+ *check_privs = B_FALSE;
+ return (EPERM);
+ }
+
+ if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
+ (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) {
+ *check_privs = B_FALSE;
+ return (EACCES);
+ }
+
+ /*
+ * The caller requested that the ACL check be skipped. This
+ * would only happen if the caller checked VOP_ACCESS() with a
+ * 32 bit ACE mask and already had the appropriate permissions.
+ */
+ if (skipaclchk) {
+ *working_mode = 0;
+ return (0);
+ }
+
+ zfs_fuid_map_ids(zp, &fowner, &gowner);
+
mutex_enter(&zp->z_acl_lock);
- error = zfs_acl_node_read(zp, &aclp);
+ error = zfs_acl_node_read(zp, &aclp, B_FALSE);
if (error != 0) {
mutex_exit(&zp->z_acl_lock);
return (error);
}
+ while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+ &iflags, &type)) {
- zacep = aclp->z_acl;
- cnt = aclp->z_acl_count;
-
- for (i = 0; i != cnt; i++) {
+ if (iflags & ACE_INHERIT_ONLY_ACE)
+ continue;
- DTRACE_PROBE2(zfs__access__common,
- ace_t *, &zacep[i], int, *working_mode);
+ entry_type = (iflags & ACE_TYPE_FLAGS);
- if (zacep[i].a_flags & ACE_INHERIT_ONLY_ACE)
- continue;
+ checkit = B_FALSE;
- entry_type = (zacep[i].a_flags & ACE_TYPE_FLAGS);
switch (entry_type) {
case ACE_OWNER:
- if (uid == zp->z_phys->zp_uid) {
- access_deny = zfs_ace_access(&zacep[i],
- working_mode);
- }
+ if (uid == fowner)
+ checkit = B_TRUE;
break;
- case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+ case OWNING_GROUP:
+ who = gowner;
+ /*FALLTHROUGH*/
case ACE_IDENTIFIER_GROUP:
- /*
- * Owning group gid is in znode not ACL
- */
- if (entry_type == (ACE_IDENTIFIER_GROUP | ACE_GROUP))
- gid = zp->z_phys->zp_gid;
- else
- gid = zacep[i].a_who;
-
- if (groupmember(gid, cr)) {
- access_deny = zfs_ace_access(&zacep[i],
- working_mode);
- }
+ checkit = zfs_groupmember(zfsvfs, who, cr);
break;
case ACE_EVERYONE:
- access_deny = zfs_ace_access(&zacep[i], working_mode);
+ checkit = B_TRUE;
break;
/* USER Entry */
default:
if (entry_type == 0) {
- if (uid == zacep[i].a_who) {
- access_deny = zfs_ace_access(&zacep[i],
- working_mode);
- }
+ uid_t newid;
+
+ zfs_fuid_map_id(zfsvfs, who,
+ ZFS_ACE_USER, &newid);
+ if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
+ uid == newid)
+ checkit = B_TRUE;
break;
+ } else {
+ zfs_acl_free(aclp);
+ mutex_exit(&zp->z_acl_lock);
+ return (EIO);
+ }
+ }
+
+ if (checkit) {
+ if (access_mask & *working_mode) {
+ if (type == ALLOW) {
+ *working_mode &=
+ ~(*working_mode & access_mask);
+ if (*working_mode == 0) {
+ access_deny = 0;
+ }
+ } else if (type == DENY) {
+ access_deny = EACCES;
+ }
}
- zfs_acl_free(aclp);
- mutex_exit(&zp->z_acl_lock);
- return (EIO);
}
if (access_deny != ACCESS_UNDETERMINED)
@@ -1347,23 +2290,35 @@ zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
mutex_exit(&zp->z_acl_lock);
zfs_acl_free(aclp);
-
+out:
return (access_deny);
}
+static int
+zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
+ cred_t *cr)
+{
+ if (*working_mode != ACE_WRITE_DATA)
+ return (EACCES);
+
+ return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
+ check_privs, B_FALSE, cr));
+}
/*
* Determine whether Access should be granted/denied, invoking least
* priv subsytem when a deny is determined.
*/
int
-zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
+zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
{
- int working_mode;
- int error;
- int is_attr;
- znode_t *xzp;
- znode_t *check_zp = zp;
+ uint32_t working_mode;
+ int error;
+ int is_attr;
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+ boolean_t check_privs;
+ znode_t *xzp;
+ znode_t *check_zp = zp;
is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) &&
(ZTOV(zp)->v_type == VDIR));
@@ -1376,7 +2331,9 @@ zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
zp->z_phys->zp_parent, &xzp)) != 0) {
return (error);
}
+
check_zp = xzp;
+
/*
* fixup mode to map to xattr perms
*/
@@ -1392,18 +2349,76 @@ zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
}
}
- error = zfs_zaccess_common(check_zp, mode, &working_mode, cr);
+ if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
+ &check_privs, skipaclchk, cr)) == 0) {
+ if (is_attr)
+ VN_RELE(ZTOV(xzp));
+ return (0);
+ }
- if (error == EROFS) {
+ if (error && check_privs == B_FALSE) {
if (is_attr)
VN_RELE(ZTOV(xzp));
return (error);
}
- if (error || working_mode) {
- working_mode = (zfs_v4_to_unix(working_mode) << 6);
- error = secpolicy_vnode_access(cr, ZTOV(check_zp),
- check_zp->z_phys->zp_uid, working_mode);
+ if (error && (flags & V_APPEND)) {
+ error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
+ }
+
+ if (error && check_privs) {
+ uid_t owner;
+ mode_t checkmode = 0;
+
+ zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid,
+ ZFS_OWNER, &owner);
+
+ /*
+ * First check for implicit owner permission on
+ * read_acl/read_attributes
+ */
+
+ error = 0;
+ ASSERT(working_mode != 0);
+
+ if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
+ owner == crgetuid(cr)))
+ working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
+
+ if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
+ ACE_READ_ACL|ACE_READ_ATTRIBUTES))
+ checkmode |= VREAD;
+ if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
+ ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES))
+ checkmode |= VWRITE;
+ if (working_mode & ACE_EXECUTE)
+ checkmode |= VEXEC;
+
+ if (checkmode)
+ error = secpolicy_vnode_access(cr, ZTOV(check_zp),
+ owner, checkmode);
+
+ if (error == 0 && (working_mode & ACE_WRITE_OWNER))
+ error = secpolicy_vnode_create_gid(cr);
+ if (error == 0 && (working_mode & ACE_WRITE_ACL))
+ error = secpolicy_vnode_setdac(cr, owner);
+
+ if (error == 0 && (working_mode &
+ (ACE_DELETE|ACE_DELETE_CHILD)))
+ error = secpolicy_vnode_remove(cr);
+
+ if (error == 0 && (working_mode & ACE_SYNCHRONIZE))
+ error = secpolicy_vnode_owner(cr, owner);
+
+ if (error == 0) {
+ /*
+ * See if any bits other than those already checked
+ * for are still present. If so then return EACCES
+ */
+ if (working_mode & ~(ZFS_CHECKED_MASKS)) {
+ error = EACCES;
+ }
+ }
}
if (is_attr)
@@ -1413,38 +2428,36 @@ zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
}
/*
- * Special zaccess function to check for special nfsv4 perm.
- * doesn't call secpolicy_vnode_access() for failure, since that
- * would probably be the wrong policy function to call.
- * instead its up to the caller to handle that situation.
+ * Translate traditional unix VREAD/VWRITE/VEXEC mode into
+ * native ACL format and call zfs_zaccess()
*/
-
int
-zfs_zaccess_v4_perm(znode_t *zp, int mode, cred_t *cr)
+zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
{
- int working_mode = 0;
- return (zfs_zaccess_common(zp, mode, &working_mode, cr));
+ return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
}
/*
- * Translate tradition unix VREAD/VWRITE/VEXEC mode into
- * native ACL format and call zfs_zaccess()
+ * Access function for secpolicy_vnode_setattr
*/
int
-zfs_zaccess_rwx(znode_t *zp, mode_t mode, cred_t *cr)
+zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
{
int v4_mode = zfs_unix_to_v4(mode >> 6);
- return (zfs_zaccess(zp, v4_mode, cr));
+ return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
}
static int
zfs_delete_final_check(znode_t *zp, znode_t *dzp, cred_t *cr)
{
int error;
+ uid_t downer;
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+
+ zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, ZFS_OWNER, &downer);
- error = secpolicy_vnode_access(cr, ZTOV(zp),
- dzp->z_phys->zp_uid, S_IWRITE|S_IEXEC);
+ error = secpolicy_vnode_access(cr, ZTOV(zp), downer, S_IWRITE|S_IEXEC);
if (error == 0)
error = zfs_sticky_remove_access(dzp, zp, cr);
@@ -1490,9 +2503,11 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp, cred_t *cr)
int
zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
{
- int dzp_working_mode = 0;
- int zp_working_mode = 0;
+ uint32_t dzp_working_mode = 0;
+ uint32_t zp_working_mode = 0;
int dzp_error, zp_error;
+ boolean_t dzpcheck_privs = B_TRUE;
+ boolean_t zpcheck_privs = B_TRUE;
/*
* Arghh, this check is going to require a couple of questions
@@ -1505,11 +2520,16 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
* by secpolicy_vnode_access().
*/
+ if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
+ return (EPERM);
+
dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
- &dzp_working_mode, cr);
- zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, cr);
+ &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
+ zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
+ &zpcheck_privs, B_FALSE, cr);
- if (dzp_error == EROFS || zp_error == EROFS)
+ if ((dzp_error && dzpcheck_privs == B_FALSE) ||
+ (zp_error && zpcheck_privs == B_FALSE))
return (dzp_error);
/*
@@ -1550,9 +2570,9 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
*/
dzp_error = zfs_zaccess_common(dzp, ACE_WRITE_DATA|ACE_EXECUTE,
- &dzp_working_mode, cr);
+ &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
- if (dzp_error == EROFS)
+ if (dzp_error && dzpcheck_privs == B_FALSE)
return (dzp_error);
if ((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) == 0)
@@ -1576,6 +2596,9 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
int add_perm;
int error;
+ if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED)
+ return (EACCES);
+
add_perm = (ZTOV(szp)->v_type == VDIR) ?
ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
@@ -1604,7 +2627,7 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
/*
* Now check for add permissions
*/
- error = zfs_zaccess(tdzp, add_perm, cr);
+ error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
return (error);
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_byteswap.c b/usr/src/uts/common/fs/zfs/zfs_byteswap.c
index c8450d488b..ab97f83eb0 100644
--- a/usr/src/uts/common/fs/zfs/zfs_byteswap.c
+++ b/usr/src/uts/common/fs/zfs/zfs_byteswap.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,7 +32,7 @@
#include <sys/zfs_acl.h>
void
-zfs_ace_byteswap(ace_t *ace, int ace_cnt)
+zfs_oldace_byteswap(ace_t *ace, int ace_cnt)
{
int i;
@@ -45,9 +44,74 @@ zfs_ace_byteswap(ace_t *ace, int ace_cnt)
}
}
+/*
+ * swap ace_t and ace_oject_t
+ */
+void
+zfs_ace_byteswap(void *buf, size_t size, boolean_t zfs_layout)
+{
+ caddr_t end;
+ caddr_t ptr;
+ zfs_ace_t *zacep;
+ ace_t *acep;
+ uint16_t entry_type;
+ size_t entry_size;
+ int ace_type;
+
+ end = (caddr_t)buf + size;
+ ptr = buf;
+
+ while (ptr < end) {
+ if (zfs_layout) {
+ zacep = (zfs_ace_t *)ptr;
+ zacep->z_hdr.z_access_mask =
+ BSWAP_32(zacep->z_hdr.z_access_mask);
+ zacep->z_hdr.z_flags = BSWAP_16(zacep->z_hdr.z_flags);
+ ace_type = zacep->z_hdr.z_type =
+ BSWAP_16(zacep->z_hdr.z_type);
+ entry_type = zacep->z_hdr.z_flags & ACE_TYPE_FLAGS;
+ } else {
+ acep = (ace_t *)ptr;
+ acep->a_access_mask = BSWAP_32(acep->a_access_mask);
+ acep->a_flags = BSWAP_16(acep->a_flags);
+ ace_type = acep->a_type = BSWAP_16(acep->a_type);
+ acep->a_who = BSWAP_32(acep->a_who);
+ entry_type = acep->a_flags & ACE_TYPE_FLAGS;
+ }
+ switch (entry_type) {
+ case ACE_OWNER:
+ case ACE_EVERYONE:
+ case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
+ entry_size = zfs_layout ?
+ sizeof (zfs_ace_hdr_t) : sizeof (ace_t);
+ break;
+ case ACE_IDENTIFIER_GROUP:
+ default:
+ if (zfs_layout) {
+ zacep->z_fuid = BSWAP_64(zacep->z_fuid);
+ }
+ switch (ace_type) {
+ case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+ case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+ case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
+ entry_size = zfs_layout ?
+ sizeof (zfs_object_ace_t) :
+ sizeof (ace_object_t);
+ break;
+ default:
+ entry_size = zfs_layout ? sizeof (zfs_ace_t) :
+ sizeof (ace_t);
+ break;
+ }
+ }
+ ptr = ptr + entry_size;
+ }
+}
+
/* ARGSUSED */
void
-zfs_acl_byteswap(void *buf, size_t size)
+zfs_oldacl_byteswap(void *buf, size_t size)
{
int cnt;
@@ -58,7 +122,14 @@ zfs_acl_byteswap(void *buf, size_t size)
cnt = size / sizeof (ace_t);
- zfs_ace_byteswap((ace_t *)buf, cnt);
+ zfs_oldace_byteswap((ace_t *)buf, cnt);
+}
+
+/* ARGSUSED */
+void
+zfs_acl_byteswap(void *buf, size_t size)
+{
+ zfs_ace_byteswap(buf, size, B_TRUE);
}
void
@@ -86,14 +157,19 @@ zfs_znode_byteswap(void *buf, size_t size)
zp->zp_flags = BSWAP_64(zp->zp_flags);
zp->zp_uid = BSWAP_64(zp->zp_uid);
zp->zp_gid = BSWAP_64(zp->zp_gid);
+ zp->zp_zap = BSWAP_64(zp->zp_zap);
zp->zp_pad[0] = BSWAP_64(zp->zp_pad[0]);
zp->zp_pad[1] = BSWAP_64(zp->zp_pad[1]);
zp->zp_pad[2] = BSWAP_64(zp->zp_pad[2]);
- zp->zp_pad[3] = BSWAP_64(zp->zp_pad[3]);
zp->zp_acl.z_acl_extern_obj = BSWAP_64(zp->zp_acl.z_acl_extern_obj);
- zp->zp_acl.z_acl_count = BSWAP_32(zp->zp_acl.z_acl_count);
+ zp->zp_acl.z_acl_size = BSWAP_32(zp->zp_acl.z_acl_size);
zp->zp_acl.z_acl_version = BSWAP_16(zp->zp_acl.z_acl_version);
- zp->zp_acl.z_acl_pad = BSWAP_16(zp->zp_acl.z_acl_pad);
- zfs_ace_byteswap(&zp->zp_acl.z_ace_data[0], ACE_SLOT_CNT);
+ zp->zp_acl.z_acl_count = BSWAP_16(zp->zp_acl.z_acl_count);
+ if (zp->zp_acl.z_acl_version == ZFS_ACL_VERSION) {
+ zfs_acl_byteswap((void *)&zp->zp_acl.z_ace_data[0],
+ ZFS_ACE_SPACE);
+ } else
+ zfs_oldace_byteswap((ace_t *)&zp->zp_acl.z_ace_data[0],
+ ACE_SLOT_CNT);
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_ctldir.c b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
index 3b2cc409e0..b272d16ddb 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ctldir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
@@ -243,7 +243,7 @@ zfsctl_root(znode_t *zp)
*/
/* ARGSUSED */
static int
-zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr)
+zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
{
if (flags & FWRITE)
return (EACCES);
@@ -257,7 +257,7 @@ zfsctl_common_open(vnode_t **vpp, int flags, cred_t *cr)
/* ARGSUSED */
static int
zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct)
{
return (0);
}
@@ -267,7 +267,8 @@ zfsctl_common_close(vnode_t *vpp, int flags, int count, offset_t off,
*/
/* ARGSUSED */
static int
-zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+zfsctl_common_access(vnode_t *vp, int mode, int flags, cred_t *cr,
+ caller_context_t *ct)
{
if (mode & VWRITE)
return (EACCES);
@@ -306,8 +307,9 @@ zfsctl_common_getattr(vnode_t *vp, vattr_t *vap)
vap->va_mtime = vap->va_ctime = zcp->zc_cmtime;
}
+/*ARGSUSED*/
static int
-zfsctl_common_fid(vnode_t *vp, fid_t *fidp)
+zfsctl_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
zfsctl_node_t *zcp = vp->v_data;
@@ -357,7 +359,8 @@ zfsctl_common_fid(vnode_t *vp, fid_t *fidp)
*/
/* ARGSUSED */
static int
-zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
@@ -377,17 +380,24 @@ zfsctl_root_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
int
zfsctl_root_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
int err;
+ /*
+ * No extended attributes allowed under .zfs
+ */
+ if (flags & LOOKUP_XATTR)
+ return (EINVAL);
+
ZFS_ENTER(zfsvfs);
if (strcmp(nm, "..") == 0) {
err = VFS_ROOT(dvp->v_vfsp, vpp);
} else {
- err = gfs_dir_lookup(dvp, nm, vpp);
+ err = gfs_dir_lookup(dvp, nm, vpp, cr);
}
ZFS_EXIT(zfsvfs);
@@ -449,7 +459,7 @@ zfsctl_unmount_snap(vnode_t *dvp, const char *name, int force, cred_t *cr)
return (err);
}
ASSERT(sep->se_root->v_count == 1);
- gfs_vop_inactive(sep->se_root, cr);
+ gfs_vop_inactive(sep->se_root, cr, NULL);
avl_remove(&sdp->sd_snaps, sep);
kmem_free(sep->se_name, strlen(sep->se_name) + 1);
@@ -512,9 +522,10 @@ zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
vfs_unlock(vfsp);
}
+/*ARGSUSED*/
static int
zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr)
+ cred_t *cr, caller_context_t *ct, int flags)
{
zfsctl_snapdir_t *sdp = sdvp->v_data;
zfs_snapentry_t search, *sep;
@@ -560,7 +571,8 @@ zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
/* ARGSUSED */
static int
-zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
+zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
+ caller_context_t *ct, int flags)
{
zfsctl_snapdir_t *sdp = dvp->v_data;
char snapname[MAXNAMELEN];
@@ -594,7 +606,7 @@ zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
/* ARGSUSED */
static int
zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
- cred_t *cr)
+ cred_t *cr, caller_context_t *cc, int flags, vsecattr_t *vsecp)
{
zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
char name[MAXNAMELEN];
@@ -628,7 +640,8 @@ zfsctl_snapdir_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
/* ARGSUSED */
static int
zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
zfsctl_snapdir_t *sdp = dvp->v_data;
objset_t *snap;
@@ -642,6 +655,12 @@ zfsctl_snapdir_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
zfsvfs_t *zfsvfs = dvp->v_vfsp->vfs_data;
int err;
+ /*
+ * No extended attributes allowed under .zfs
+ */
+ if (flags & LOOKUP_XATTR)
+ return (EINVAL);
+
ASSERT(dvp->v_type == VDIR);
if (gfs_lookup_dot(vpp, dvp, zfsvfs->z_ctldir, nm) == 0)
@@ -814,7 +833,8 @@ zfsctl_mknode_snapdir(vnode_t *pvp)
/* ARGSUSED */
static int
-zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
zfsvfs_t *zfsvfs = vp->v_vfsp->vfs_data;
zfsctl_snapdir_t *sdp = vp->v_data;
@@ -830,7 +850,7 @@ zfsctl_snapdir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
/* ARGSUSED */
static void
-zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr)
+zfsctl_snapdir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
zfsctl_snapdir_t *sdp = vp->v_data;
void *private;
@@ -883,13 +903,13 @@ zfsctl_snapshot_mknode(vnode_t *pvp, uint64_t objset)
}
static void
-zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr)
+zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
zfsctl_snapdir_t *sdp;
zfs_snapentry_t *sep, *next;
vnode_t *dvp;
- VERIFY(gfs_dir_lookup(vp, "..", &dvp) == 0);
+ VERIFY(gfs_dir_lookup(vp, "..", &dvp, cr) == 0);
sdp = dvp->v_data;
mutex_enter(&sdp->sd_lock);
@@ -924,7 +944,7 @@ zfsctl_snapshot_inactive(vnode_t *vp, cred_t *cr)
* "active". If we lookup the same name again we will end up
* creating a new vnode.
*/
- gfs_vop_inactive(vp, cr);
+ gfs_vop_inactive(vp, cr, ct);
}
@@ -949,7 +969,7 @@ zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp)
ASSERT(zfsvfs->z_ctldir != NULL);
error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
- NULL, 0, NULL, kcred);
+ NULL, 0, NULL, kcred, NULL, NULL, NULL);
if (error != 0)
return (error);
sdp = dvp->v_data;
@@ -1008,7 +1028,7 @@ zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
ASSERT(zfsvfs->z_ctldir != NULL);
error = zfsctl_root_lookup(zfsvfs->z_ctldir, "snapshot", &dvp,
- NULL, 0, NULL, cr);
+ NULL, 0, NULL, cr, NULL, NULL, NULL);
if (error != 0)
return (error);
sdp = dvp->v_data;
@@ -1046,7 +1066,7 @@ zfsctl_umount_snapshots(vfs_t *vfsp, int fflags, cred_t *cr)
* would lead to an attempt to re-grab the sd_lock.
*/
ASSERT3U(svp->v_count, ==, 1);
- gfs_vop_inactive(svp, cr);
+ gfs_vop_inactive(svp, cr, NULL);
}
sep = next;
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_dir.c b/usr/src/uts/common/fs/zfs/zfs_dir.c
index bcaa6fd4b5..8ae6a95e41 100644
--- a/usr/src/uts/common/fs/zfs/zfs_dir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_dir.c
@@ -52,7 +52,51 @@
#include <sys/dmu.h>
#include <sys/atomic.h>
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
#include <sys/dnlc.h>
+#include <sys/extdirent.h>
+#include <sys/zfs_i18n.h>
+
+/*
+ * zfs_match_find() is used by zfs_dirent_lock() to peform zap lookups
+ * of names after deciding which is the appropriate lookup interface.
+ */
+static int
+zfs_match_find(zfsvfs_t *zfsvfs, znode_t *dzp, char *name, boolean_t exact,
+ boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
+{
+ int error;
+
+ if (zfsvfs->z_norm) {
+ matchtype_t mt = MT_FIRST;
+ boolean_t conflict = B_FALSE;
+ size_t bufsz = 0;
+ char *buf = NULL;
+
+ if (rpnp) {
+ buf = rpnp->pn_path;
+ bufsz = rpnp->pn_bufsize;
+ }
+ if (exact)
+ mt = MT_EXACT;
+ /*
+ * In the non-mixed case we only expect there would ever
+ * be one match, but we need to use the normalizing lookup.
+ */
+ error = zap_lookup_norm(zfsvfs->z_os, dzp->z_id, name, 8, 1,
+ zoid, mt, buf, bufsz, &conflict);
+ if (deflags)
+ *deflags = conflict ? ED_CASE_CONFLICT : 0;
+ } else {
+ error = zap_lookup(zfsvfs->z_os, dzp->z_id, name, 8, 1, zoid);
+ }
+ *zoid = ZFS_DIRENT_OBJ(*zoid);
+
+ if (error == ENOENT && update)
+ dnlc_update(ZTOV(dzp), name, DNLC_NO_VNODE);
+
+ return (error);
+}
/*
* Lock a directory entry. A dirlock on <dzp, name> protects that name
@@ -67,24 +111,38 @@
* ZEXISTS: if the entry does not exist, fail with ENOENT.
* ZSHARED: allow concurrent access with other ZSHARED callers.
* ZXATTR: we want dzp's xattr directory
+ * ZCILOOK: On a mixed sensitivity file system,
+ * this lookup should be case-insensitive.
+ * ZCIEXACT: On a purely case-insensitive file system,
+ * this lookup should be case-sensitive.
+ * ZRENAMING: we are locking for renaming, force narrow locks
*
* Output arguments:
* zpp - pointer to the znode for the entry (NULL if there isn't one)
* dlpp - pointer to the dirlock for this entry (NULL on error)
+ * direntflags - (case-insensitive lookup only)
+ * flags if multiple case-sensitive matches exist in directory
+ * realpnp - (case-insensitive lookup only)
+ * actual name matched within the directory
*
* Return value: 0 on success or errno on failure.
*
* NOTE: Always checks for, and rejects, '.' and '..'.
+ * NOTE: For case-insensitive file systems we take wide locks (see below),
+ * but return znode pointers to a single match.
*/
int
zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
- int flag)
+ int flag, int *direntflags, pathname_t *realpnp)
{
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
zfs_dirlock_t *dl;
+ boolean_t update;
+ boolean_t exact;
uint64_t zoid;
- int error;
- vnode_t *vp;
+ vnode_t *vp = NULL;
+ int error = 0;
+ int cmpflags;
*zpp = NULL;
*dlpp = NULL;
@@ -98,6 +156,58 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
return (EEXIST);
/*
+ * Case sensitivity and normalization preferences are set when
+ * the file system is created. These are stored in the
+ * zfsvfs->z_case and zfsvfs->z_norm fields. These choices
+ * affect what vnodes can be cached in the DNLC, how we
+ * perform zap lookups, and the "width" of our dirlocks.
+ *
+ * A normal dirlock locks a single name. Note that with
+ * normalization a name can be composed multiple ways, but
+ * when normalized, these names all compare equal. A wide
+ * dirlock locks multiple names. We need these when the file
+ * system is supporting mixed-mode access. It is sometimes
+ * necessary to lock all case permutations of file name at
+ * once so that simultaneous case-insensitive/case-sensitive
+ * behaves as rationally as possible.
+ */
+
+ /*
+ * Decide if exact matches should be requested when performing
+ * a zap lookup on file systems supporting case-insensitive
+ * access.
+ */
+ exact = ((zfsvfs->z_case & ZFS_CI_ONLY) && (flag & ZCIEXACT)) ||
+ ((zfsvfs->z_case & ZFS_CI_MIXD) && !(flag & ZCILOOK));
+
+ /*
+ * Only look in or update the DNLC if we are looking for the
+ * name on a file system that does not require normalization
+ * or case folding. We can also look there if we happen to be
+ * on a non-normalizing, mixed sensitivity file system IF we
+ * are looking for the exact name.
+ *
+ * Maybe can add TO-UPPERed version of name to dnlc in ci-only
+ * case for performance improvement?
+ */
+ update = !zfsvfs->z_norm ||
+ ((zfsvfs->z_case & ZFS_CI_MIXD) &&
+ !(zfsvfs->z_norm & ~U8_TEXTPREP_TOUPPER) && !(flag & ZCILOOK));
+
+ /*
+ * ZRENAMING indicates we are in a situation where we should
+ * take narrow locks regardless of the file system's
+ * preferences for normalizing and case folding. This will
+ * prevent us deadlocking trying to grab the same wide lock
+ * twice if the two names happen to be case-insensitive
+ * matches.
+ */
+ if (flag & ZRENAMING)
+ cmpflags = 0;
+ else
+ cmpflags = zfsvfs->z_norm;
+
+ /*
* Wait until there are no locks on this name.
*/
rw_enter(&dzp->z_name_lock, RW_READER);
@@ -108,9 +218,16 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
rw_exit(&dzp->z_name_lock);
return (ENOENT);
}
- for (dl = dzp->z_dirlocks; dl != NULL; dl = dl->dl_next)
- if (strcmp(name, dl->dl_name) == 0)
+ for (dl = dzp->z_dirlocks; dl != NULL; dl = dl->dl_next) {
+ if ((u8_strcmp(name, dl->dl_name, 0, cmpflags,
+ U8_UNICODE_LATEST, &error) == 0) || error != 0)
break;
+ }
+ if (error != 0) {
+ mutex_exit(&dzp->z_lock);
+ rw_exit(&dzp->z_name_lock);
+ return (ENOENT);
+ }
if (dl == NULL) {
/*
* Allocate a new dirlock and add it to the list.
@@ -156,7 +273,8 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
zoid = dzp->z_phys->zp_xattr;
error = (zoid == 0 ? ENOENT : 0);
} else {
- vp = dnlc_lookup(ZTOV(dzp), name);
+ if (update)
+ vp = dnlc_lookup(ZTOV(dzp), name);
if (vp == DNLC_NO_VNODE) {
VN_RELE(vp);
error = ENOENT;
@@ -170,11 +288,8 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
*zpp = VTOZ(vp);
return (0);
} else {
- error = zap_lookup(zfsvfs->z_os, dzp->z_id, name,
- 8, 1, &zoid);
- zoid = ZFS_DIRENT_OBJ(zoid);
- if (error == ENOENT)
- dnlc_update(ZTOV(dzp), name, DNLC_NO_VNODE);
+ error = zfs_match_find(zfsvfs, dzp, name, exact,
+ update, direntflags, realpnp, &zoid);
}
}
if (error) {
@@ -192,7 +307,7 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
zfs_dirent_unlock(dl);
return (error);
}
- if (!(flag & ZXATTR))
+ if (!(flag & ZXATTR) && update)
dnlc_update(ZTOV(dzp), name, ZTOV(*zpp));
}
@@ -239,7 +354,8 @@ zfs_dirent_unlock(zfs_dirlock_t *dl)
* special pseudo-directory.
*/
int
-zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp)
+zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp, int flags,
+ int *deflg, pathname_t *rpnp)
{
zfs_dirlock_t *dl;
znode_t *zp;
@@ -257,7 +373,8 @@ zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp)
if (dzp->z_phys->zp_parent == dzp->z_id &&
zfsvfs->z_parent != zfsvfs) {
error = zfsctl_root_lookup(zfsvfs->z_parent->z_ctldir,
- "snapshot", vpp, NULL, 0, NULL, kcred);
+ "snapshot", vpp, NULL, 0, NULL, kcred,
+ NULL, NULL, NULL);
return (error);
}
rw_enter(&dzp->z_parent_lock, RW_READER);
@@ -268,14 +385,24 @@ zfs_dirlook(znode_t *dzp, char *name, vnode_t **vpp)
} else if (zfs_has_ctldir(dzp) && strcmp(name, ZFS_CTLDIR_NAME) == 0) {
*vpp = zfsctl_root(dzp);
} else {
- error = zfs_dirent_lock(&dl, dzp, name, &zp, ZEXISTS | ZSHARED);
+ int zf;
+
+ zf = ZEXISTS | ZSHARED;
+ if (flags & FIGNORECASE)
+ zf |= ZCILOOK;
+
+ error = zfs_dirent_lock(&dl, dzp, name, &zp, zf, deflg, rpnp);
if (error == 0) {
*vpp = ZTOV(zp);
zfs_dirent_unlock(dl);
dzp->z_zn_prefetch = B_TRUE; /* enable prefetching */
}
+ rpnp = NULL;
}
+ if ((flags & FIGNORECASE) && rpnp)
+ (void) strlcpy(rpnp->pn_path, name, rpnp->pn_bufsize);
+
return (error);
}
@@ -633,7 +760,20 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
zfs_time_stamper_locked(dzp, CONTENT_MODIFIED, tx);
mutex_exit(&dzp->z_lock);
- error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, tx);
+ if (zp->z_zfsvfs->z_norm) {
+ if (((zp->z_zfsvfs->z_case & ZFS_CI_ONLY) &&
+ (flag & ZCIEXACT)) ||
+ ((zp->z_zfsvfs->z_case & ZFS_CI_MIXD) &&
+ !(flag & ZCILOOK)))
+ error = zap_remove_norm(zp->z_zfsvfs->z_os,
+ dzp->z_id, dl->dl_name, MT_EXACT, tx);
+ else
+ error = zap_remove_norm(zp->z_zfsvfs->z_os,
+ dzp->z_id, dl->dl_name, MT_FIRST, tx);
+ } else {
+ error = zap_remove(zp->z_zfsvfs->z_os,
+ dzp->z_id, dl->dl_name, tx);
+ }
ASSERT(error == 0);
if (unlinkedp != NULL)
@@ -663,15 +803,24 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr)
dmu_tx_t *tx;
uint64_t xoid;
int error;
+ zfs_fuid_info_t *fuidp = NULL;
*xvpp = NULL;
- if (error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, cr))
+ if (error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr))
return (error);
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_bonus(tx, zp->z_id);
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0, SPA_MAXBLOCKSIZE);
+ }
error = dmu_tx_assign(tx, zfsvfs->z_assign);
if (error) {
if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT)
@@ -679,13 +828,16 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr)
dmu_tx_abort(tx);
return (error);
}
- zfs_mknode(zp, vap, &xoid, tx, cr, IS_XATTR, &xzp, 0);
+ zfs_mknode(zp, vap, &xoid, tx, cr, IS_XATTR, &xzp, 0, NULL, &fuidp);
ASSERT(xzp->z_id == xoid);
ASSERT(xzp->z_phys->zp_parent == zp->z_id);
dmu_buf_will_dirty(zp->z_dbuf, tx);
zp->z_phys->zp_xattr = xoid;
- (void) zfs_log_create(zfsvfs->z_log, tx, TX_MKXATTR, zp, xzp, "");
+ (void) zfs_log_create(zfsvfs->z_log, tx, TX_MKXATTR, zp,
+ xzp, "", NULL, fuidp, vap);
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
*xvpp = ZTOV(xzp);
@@ -715,7 +867,7 @@ zfs_get_xattrdir(znode_t *zp, vnode_t **xvpp, cred_t *cr, int flags)
vattr_t va;
int error;
top:
- error = zfs_dirent_lock(&dl, zp, "", &xzp, ZXATTR);
+ error = zfs_dirent_lock(&dl, zp, "", &xzp, ZXATTR, NULL, NULL);
if (error)
return (error);
@@ -750,8 +902,7 @@ top:
va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
va.va_type = VDIR;
va.va_mode = S_IFDIR | S_ISVTX | 0777;
- va.va_uid = (uid_t)zp->z_phys->zp_uid;
- va.va_gid = (gid_t)zp->z_phys->zp_gid;
+ zfs_fuid_map_ids(zp, &va.va_uid, &va.va_gid);
error = zfs_make_xattrdir(zp, &va, xvpp, cr);
zfs_dirent_unlock(dl);
@@ -781,15 +932,22 @@ int
zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
{
uid_t uid;
+ uid_t downer;
+ uid_t fowner;
+ zfsvfs_t *zfsvfs = zdp->z_zfsvfs;
if (zdp->z_zfsvfs->z_assign >= TXG_INITIAL) /* ZIL replay */
return (0);
- if ((zdp->z_phys->zp_mode & S_ISVTX) == 0 ||
- (uid = crgetuid(cr)) == zdp->z_phys->zp_uid ||
- uid == zp->z_phys->zp_uid ||
+ if ((zdp->z_phys->zp_mode & S_ISVTX) == 0)
+ return (0);
+
+ zfs_fuid_map_id(zfsvfs, zdp->z_phys->zp_uid, ZFS_OWNER, &downer);
+ zfs_fuid_map_id(zfsvfs, zp->z_phys->zp_uid, ZFS_OWNER, &fowner);
+
+ if ((uid = crgetuid(cr)) == downer || uid == fowner ||
(ZTOV(zp)->v_type == VREG &&
- zfs_zaccess(zp, ACE_WRITE_DATA, cr) == 0))
+ zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0))
return (0);
else
return (secpolicy_vnode_remove(cr));
diff --git a/usr/src/uts/common/fs/zfs/zfs_fuid.c b/usr/src/uts/common/fs/zfs/zfs_fuid.c
new file mode 100644
index 0000000000..3eb7d56611
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/zfs_fuid.c
@@ -0,0 +1,724 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/unistd.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_fuid.h>
+#include <sys/dmu.h>
+#include <sys/refcount.h>
+#include <sys/avl.h>
+#include <sys/zap.h>
+#include <sys/nvpair.h>
+#include <sys/kidmap.h>
+#include <sys/sid.h>
+
+/*
+ * FUID Domain table(s).
+ *
+ * The FUID table is stored as a packed nvlist of an array
+ * of nvlists which contain an index, domain string and offset
+ *
+ * During file system initialization the nvlist(s) are read and
+ * two AVL trees are created. One tree is keyed by the index number
+ * and the other by the domain string. Nodes are never removed from
+ * trees, but new entries may be added. If a new entry is added then the
+ * on-disk packed nvlist will also be updated.
+ */
+
+#define FUID_IDX "fuid_idx"
+#define FUID_DOMAIN "fuid_domain"
+#define FUID_OFFSET "fuid_offset"
+#define FUID_NVP_ARRAY "fuid_nvlist"
+
+typedef struct fuid_domain {
+ avl_node_t f_node;
+ ksiddomain_t *f_ksid;
+ int f_idx;
+ uint32_t f_offset;
+} fuid_domain_t;
+
+typedef struct fuid_idx {
+ avl_node_t f_node;
+ int f_idx;
+ fuid_domain_t *f_domain;
+} fuid_idx_t;
+
+/*
+ * Compare two indexes.
+ */
+static int
+idx_compare(const void *arg1, const void *arg2)
+{
+ const fuid_idx_t *node1 = arg1;
+ const fuid_idx_t *node2 = arg2;
+
+ if (node1->f_idx < node2->f_idx)
+ return (-1);
+ else if (node1->f_idx > node2->f_idx)
+ return (1);
+ return (0);
+}
+
+/*
+ * Compare two domain strings.
+ */
+static int
+domain_compare(const void *arg1, const void *arg2)
+{
+ const fuid_domain_t *node1 = arg1;
+ const fuid_domain_t *node2 = arg2;
+ int val;
+
+ val = strcmp(node1->f_ksid->kd_name, node2->f_ksid->kd_name);
+ if (val == 0)
+ return (0);
+ return (val > 0 ? 1 : -1);
+}
+
+/*
+ * Load the fuid table(s) into memory.
+ */
+static void
+zfs_fuid_init(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
+{
+ dmu_buf_t *db;
+ char *packed;
+ size_t nvsize = 0;
+ int error = 0;
+ int i;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
+
+ if (zfsvfs->z_fuid_loaded) {
+ rw_exit(&zfsvfs->z_fuid_lock);
+ return;
+ }
+
+ if (zfsvfs->z_fuid_obj == 0) {
+
+ /* first make sure we need to allocate object */
+
+ error = zap_lookup(zfsvfs->z_os, MASTER_NODE_OBJ,
+ ZFS_FUID_TABLES, 8, 1, &zfsvfs->z_fuid_obj);
+ if (error == ENOENT && tx != NULL) {
+ zfsvfs->z_fuid_obj = dmu_object_alloc(zfsvfs->z_os,
+ DMU_OT_FUID, 1 << 14, DMU_OT_FUID_SIZE,
+ sizeof (uint64_t), tx);
+ VERIFY(zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
+ ZFS_FUID_TABLES, sizeof (uint64_t), 1,
+ &zfsvfs->z_fuid_obj, tx) == 0);
+ }
+ }
+
+ avl_create(&zfsvfs->z_fuid_idx, idx_compare,
+ sizeof (fuid_idx_t), offsetof(fuid_idx_t, f_node));
+ avl_create(&zfsvfs->z_fuid_domain, domain_compare,
+ sizeof (fuid_domain_t), offsetof(fuid_domain_t, f_node));
+
+ if (zfsvfs->z_fuid_obj) {
+ VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj,
+ FTAG, &db));
+ nvsize = *(uint64_t *)db->db_data;
+ dmu_buf_rele(db, FTAG);
+ }
+
+ if (nvsize == 0)
+ goto initialized;
+
+ packed = kmem_alloc(nvsize, KM_SLEEP);
+ error = dmu_read(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0, nvsize, packed);
+ if (error == 0) {
+ nvlist_t **fuidnvp;
+ nvlist_t *nvp = NULL;
+ uint_t count;
+
+ VERIFY(nvlist_unpack(packed, nvsize, &nvp, 0) == 0);
+ VERIFY((error = nvlist_lookup_nvlist_array(nvp, FUID_NVP_ARRAY,
+ &fuidnvp, &count)) == 0);
+
+ for (i = 0; i != count; i++) {
+ fuid_idx_t *idxnode;
+ fuid_domain_t *domnode;
+ char *domain;
+ avl_index_t loc;
+ uint64_t idx, offset;
+
+ VERIFY(nvlist_lookup_string(fuidnvp[i], FUID_DOMAIN,
+ &domain) == 0);
+ VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_IDX,
+ &idx) == 0);
+ VERIFY(nvlist_lookup_uint64(fuidnvp[i], FUID_OFFSET,
+ &offset) == 0);
+
+ idxnode = kmem_alloc(sizeof (fuid_idx_t), KM_SLEEP);
+ domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+
+ domnode->f_idx = idxnode->f_idx = idx;
+ domnode->f_ksid = ksid_lookupdomain(domain);
+ idxnode->f_domain = domnode;
+ domnode->f_offset = offset;
+ if (avl_find(&zfsvfs->z_fuid_idx,
+ idxnode, &loc) == NULL) {
+ avl_insert(&zfsvfs->z_fuid_idx, idxnode, loc);
+ }
+ if (avl_find(&zfsvfs->z_fuid_domain,
+ domnode, &loc) == NULL) {
+ avl_insert(&zfsvfs->z_fuid_domain,
+ domnode, loc);
+ }
+ }
+ nvlist_free(nvp);
+ }
+ kmem_free(packed, nvsize);
+
+initialized:
+ zfsvfs->z_fuid_loaded = B_TRUE;
+ rw_exit(&zfsvfs->z_fuid_lock);
+}
+
+/*
+ * Query domain table for a given domain.
+ *
+ * If domain isn't found it is added to AVL trees and
+ * the results are pushed out to disk.
+ */
+int
+zfs_fuid_find_by_domain(zfsvfs_t *zfsvfs, const char *domain, char **retdomain,
+ dmu_tx_t *tx)
+{
+ fuid_domain_t searchnode, *findnode;
+ avl_index_t loc;
+
+ searchnode.f_ksid = ksid_lookupdomain(domain);
+ if (retdomain) {
+ *retdomain = searchnode.f_ksid->kd_name;
+ }
+ if (zfsvfs->z_fuid_loaded == B_FALSE)
+ zfs_fuid_init(zfsvfs, tx);
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
+ findnode = avl_find(&zfsvfs->z_fuid_domain, &searchnode, &loc);
+ rw_exit(&zfsvfs->z_fuid_lock);
+
+ if (findnode) {
+ ksiddomain_rele(searchnode.f_ksid);
+ return (findnode->f_idx);
+ } else {
+ fuid_domain_t *domnode;
+ fuid_idx_t *newidxnode;
+ nvlist_t *nvp;
+ nvlist_t **fuids;
+ uint64_t retidx;
+ size_t nvsize = 0;
+ char *packed;
+ dmu_buf_t *db;
+ int i = 0;
+
+ domnode = kmem_alloc(sizeof (fuid_domain_t), KM_SLEEP);
+ domnode->f_ksid = searchnode.f_ksid;
+ domnode->f_offset = 0;
+
+ newidxnode = kmem_alloc(sizeof (fuid_idx_t), KM_SLEEP);
+ newidxnode->f_domain = domnode;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
+ retidx = domnode->f_idx = newidxnode->f_idx =
+ avl_numnodes(&zfsvfs->z_fuid_idx) + 1;
+
+ avl_add(&zfsvfs->z_fuid_domain, domnode);
+ avl_add(&zfsvfs->z_fuid_idx, newidxnode);
+ /*
+ * Now resync the on-disk nvlist.
+ */
+ VERIFY(nvlist_alloc(&nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ domnode = avl_first(&zfsvfs->z_fuid_domain);
+ fuids = kmem_alloc(retidx * sizeof (void *), KM_SLEEP);
+ while (domnode) {
+ VERIFY(nvlist_alloc(&fuids[i],
+ NV_UNIQUE_NAME, KM_SLEEP) == 0);
+ VERIFY(nvlist_add_uint64(fuids[i], FUID_IDX,
+ domnode->f_idx) == 0);
+ VERIFY(nvlist_add_uint64(fuids[i], FUID_OFFSET,
+ domnode->f_offset) == 0);
+ VERIFY(nvlist_add_string(fuids[i++], FUID_DOMAIN,
+ domnode->f_ksid->kd_name) == 0);
+ domnode = AVL_NEXT(&zfsvfs->z_fuid_domain, domnode);
+ }
+ VERIFY(nvlist_add_nvlist_array(nvp, FUID_NVP_ARRAY,
+ fuids, retidx) == 0);
+ for (i = 0; i != retidx; i++)
+ nvlist_free(fuids[i]);
+ kmem_free(fuids, retidx * sizeof (void *));
+ VERIFY(nvlist_size(nvp, &nvsize, NV_ENCODE_XDR) == 0);
+ packed = kmem_alloc(nvsize, KM_SLEEP);
+ VERIFY(nvlist_pack(nvp, &packed, &nvsize,
+ NV_ENCODE_XDR, KM_SLEEP) == 0);
+ nvlist_free(nvp);
+ dmu_write(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0, nvsize,
+ packed, tx);
+ kmem_free(packed, nvsize);
+ VERIFY(0 == dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj,
+ FTAG, &db));
+ dmu_buf_will_dirty(db, tx);
+ *(uint64_t *)db->db_data = nvsize;
+ dmu_buf_rele(db, FTAG);
+
+ rw_exit(&zfsvfs->z_fuid_lock);
+ return (retidx);
+ }
+}
+
+/*
+ * Query domain table by index, returning domain string
+ *
+ * Returns a pointer from an avl node of the domain string.
+ *
+ */
+char *
+zfs_fuid_find_by_idx(zfsvfs_t *zfsvfs, uint64_t idx)
+{
+ fuid_idx_t searchnode, *findnode;
+ avl_index_t loc;
+
+ if (idx == 0 || zfsvfs->z_use_fuids == B_FALSE)
+ return (NULL);
+
+ if (zfsvfs->z_fuid_loaded == B_FALSE)
+ zfs_fuid_init(zfsvfs, NULL);
+
+ searchnode.f_idx = idx;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_READER);
+ findnode = avl_find(&zfsvfs->z_fuid_idx, &searchnode, &loc);
+ rw_exit(&zfsvfs->z_fuid_lock);
+
+ ASSERT(findnode);
+ return (findnode->f_domain->f_ksid->kd_name);
+}
+
+void
+zfs_fuid_get_mappings(zfs_fuid_hdl_t *hdl)
+{
+ VERIFY(hdl != NULL);
+ if (hdl->z_map_needed == B_FALSE)
+ return;
+
+ (void) kidmap_get_mappings(hdl->z_hdl);
+
+ kidmap_get_destroy(hdl->z_hdl);
+ hdl->z_hdl = NULL;
+ hdl->z_map_needed = B_FALSE;
+}
+
+void
+zfs_fuid_queue_map_id(zfsvfs_t *zfsvfs, zfs_fuid_hdl_t *hdl,
+ uint64_t fuid, zfs_fuid_type_t type, uid_t *id)
+{
+ uint32_t index = FUID_INDEX(fuid);
+ char *domain;
+ int status;
+
+ VERIFY(hdl);
+
+ if (index == 0 || zfsvfs->z_use_fuids == B_FALSE) {
+ *id = (uid_t)fuid;
+ return;
+ }
+
+ if (hdl->z_hdl == NULL) {
+ hdl->z_hdl = kidmap_get_create();
+ hdl->z_map_needed = B_TRUE;
+ }
+
+ domain = zfs_fuid_find_by_idx(zfsvfs, index);
+ ASSERT(domain != NULL);
+
+ if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+ status = kidmap_batch_getuidbysid(hdl->z_hdl, domain,
+ FUID_RID(fuid), id, &hdl->z_status);
+ else
+ status = kidmap_batch_getgidbysid(hdl->z_hdl, domain,
+ FUID_RID(fuid), id, &hdl->z_status);
+ ASSERT(status == 0);
+}
+
+void
+zfs_fuid_map_ids(znode_t *zp, uid_t *uid, uid_t *gid)
+{
+ uint32_t uid_index = FUID_INDEX(zp->z_phys->zp_uid);
+ uint32_t gid_index = FUID_INDEX(zp->z_phys->zp_gid);
+
+ /* Favor the common case, neither will be ephemeral */
+ if (uid_index == 0 && gid_index == 0) {
+ *uid = zp->z_phys->zp_uid;
+ *gid = zp->z_phys->zp_gid;
+ return;
+ } else {
+ zfs_fuid_hdl_t hdl = { 0 };
+
+ zfs_fuid_queue_map_id(zp->z_zfsvfs, &hdl,
+ zp->z_phys->zp_uid, ZFS_OWNER, uid);
+
+ zfs_fuid_queue_map_id(zp->z_zfsvfs, &hdl,
+ zp->z_phys->zp_gid, ZFS_GROUP, gid);
+
+ zfs_fuid_get_mappings(&hdl);
+ }
+}
+
+void
+zfs_fuid_map_id(zfsvfs_t *zfsvfs, uint64_t fuid,
+ zfs_fuid_type_t type, uid_t *id)
+{
+ uint32_t index = FUID_INDEX(fuid);
+ char *domain;
+
+ if (index == 0) {
+ *id = (uid_t)fuid;
+ return;
+ }
+
+ domain = zfs_fuid_find_by_idx(zfsvfs, index);
+ ASSERT(domain != NULL);
+
+ if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+ (void) kidmap_getuidbysid(domain, FUID_RID(fuid), id);
+ else
+ (void) kidmap_getgidbysid(domain, FUID_RID(fuid), id);
+}
+
+/*
+ * Add a FUID node to the list of fuid's being created for this
+ * ACL
+ *
+ * If ACL has multiple domains, then keep only one copy of each unique
+ * domain.
+ */
+static void
+zfs_fuid_node_add(zfs_fuid_info_t **fuidpp, const char *domain, uint32_t rid,
+ uint64_t idx, uint64_t id, zfs_fuid_type_t type)
+{
+ zfs_fuid_t *fuid;
+ zfs_fuid_domain_t *fuid_domain;
+ zfs_fuid_info_t *fuidp;
+ uint64_t fuididx;
+ boolean_t found = B_FALSE;
+
+ if (*fuidpp == NULL)
+ *fuidpp = zfs_fuid_info_alloc();
+
+ fuidp = *fuidpp;
+ /*
+ * First find fuid domain index in linked list
+ *
+ * If one isn't found then create an entry.
+ */
+
+ for (fuididx = 1, fuid_domain = list_head(&fuidp->z_domains);
+ fuid_domain; fuid_domain = list_next(&fuidp->z_domains,
+ fuid_domain), fuididx++) {
+ if (idx == fuid_domain->z_domidx) {
+ found = B_TRUE;
+ break;
+ }
+ }
+
+ if (found == B_FALSE) {
+ fuid_domain = kmem_alloc(sizeof (zfs_fuid_domain_t), KM_SLEEP);
+ fuid_domain->z_domain = domain;
+ fuid_domain->z_domidx = idx;
+ list_insert_tail(&fuidp->z_domains, fuid_domain);
+ fuidp->z_domain_str_sz += strlen(domain) + 1;
+ fuidp->z_domain_cnt++;
+ }
+
+ if (type == ZFS_ACE_USER || type == ZFS_ACE_GROUP) {
+ /*
+ * Now allocate fuid entry and add it on the end of the list
+ */
+
+ fuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP);
+ fuid->z_id = id;
+ fuid->z_domidx = idx;
+ fuid->z_logfuid = FUID_ENCODE(fuididx, rid);
+
+ list_insert_tail(&fuidp->z_fuids, fuid);
+ fuidp->z_fuid_cnt++;
+ } else {
+ if (type == ZFS_OWNER)
+ fuidp->z_fuid_owner = FUID_ENCODE(fuididx, rid);
+ else
+ fuidp->z_fuid_group = FUID_ENCODE(fuididx, rid);
+ }
+}
+
+/*
+ * Create a file system FUID
+ *
+ * During a replay operation the id will be incorrect and
+ * will be ignored. In this case replay must be true and the
+ * cred will have a ksid_t attached to it.
+ *
+ * A mapped uid/gid would have a ksid_t attached to the cred.
+ */
+uint64_t
+zfs_fuid_create_cred(zfsvfs_t *zfsvfs, uint64_t id,
+ zfs_fuid_type_t type, dmu_tx_t *tx, cred_t *cr, zfs_fuid_info_t **fuidp)
+{
+ uint64_t idx;
+ ksid_t *ksid;
+ uint32_t rid;
+ char *kdomain;
+ const char *domain;
+
+ VERIFY(type == ZFS_OWNER || type == ZFS_GROUP);
+
+ if (zfsvfs->z_use_fuids == B_FALSE || !IS_EPHEMERAL(id))
+ return ((uint64_t)id);
+
+ ksid = crgetsid(cr, (type == ZFS_OWNER) ? KSID_OWNER : KSID_GROUP);
+
+ VERIFY(ksid != NULL);
+ rid = ksid_getrid(ksid);
+ domain = ksid_getdomain(ksid);
+
+ idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx);
+
+ zfs_fuid_node_add(fuidp, kdomain, rid, idx, id, type);
+
+ return (FUID_ENCODE(idx, rid));
+}
+
+/*
+ * Create a file system FUID for an ACL ace
+ * or a chown/chgrp of the file.
+ * This is similar to zfs_fuid_create_cred, except that
+ * we can't find the domain + rid information in the
+ * cred. Instead we have to query Winchester for the
+ * domain and rid.
+ */
+uint64_t
+zfs_fuid_create(zfsvfs_t *zfsvfs, uint64_t id,
+ zfs_fuid_type_t type, dmu_tx_t *tx, zfs_fuid_info_t **fuidpp)
+{
+ const char *domain;
+ char *kdomain;
+ uint32_t fuid_idx = FUID_INDEX(id);
+ uint32_t rid;
+ idmap_stat status;
+ uint64_t idx;
+ boolean_t is_replay = (zfsvfs->z_assign >= TXG_INITIAL);
+ zfs_fuid_t *zfuid = NULL;
+ zfs_fuid_info_t *fuidp;
+
+ /*
+ * If POSIX ID, or entry is already a FUID then
+ * just return the id
+ */
+ if (!IS_EPHEMERAL(id) || fuid_idx != 0)
+ return (id);
+
+ if (is_replay) {
+ fuidp = zfsvfs->z_fuid_replay;
+
+ /*
+ * If we are passed an ephemeral id, but no
+ * fuid_info was logged then return NOBODY.
+ * This is most likely a result of idmap service
+ * not being available.
+ */
+ if (fuidp == NULL)
+ return (UID_NOBODY);
+
+ switch (type) {
+ case ZFS_ACE_USER:
+ case ZFS_ACE_GROUP:
+ zfuid = list_head(&fuidp->z_fuids);
+ rid = FUID_RID(zfuid->z_logfuid);
+ idx = FUID_INDEX(zfuid->z_logfuid);
+ break;
+ case ZFS_OWNER:
+ rid = FUID_RID(fuidp->z_fuid_owner);
+ idx = FUID_INDEX(fuidp->z_fuid_owner);
+ break;
+ case ZFS_GROUP:
+ rid = FUID_RID(fuidp->z_fuid_group);
+ idx = FUID_INDEX(fuidp->z_fuid_group);
+ break;
+ };
+ domain = fuidp->z_domain_table[idx -1];
+ } else {
+ if (type == ZFS_OWNER || type == ZFS_ACE_USER)
+ status = kidmap_getsidbyuid(id, &domain, &rid);
+ else
+ status = kidmap_getsidbygid(id, &domain, &rid);
+
+ if (status != 0)
+ return (UID_NOBODY);
+
+ }
+
+ idx = zfs_fuid_find_by_domain(zfsvfs, domain, &kdomain, tx);
+
+ if (is_replay == B_FALSE)
+ zfs_fuid_node_add(fuidpp, kdomain, rid, idx, id, type);
+ else if (zfuid != NULL) {
+ list_remove(&fuidp->z_fuids, zfuid);
+ kmem_free(zfuid, sizeof (zfs_fuid_t));
+ }
+ return (FUID_ENCODE(idx, rid));
+}
+
+void
+zfs_fuid_destroy(zfsvfs_t *zfsvfs)
+{
+ fuid_domain_t *domnode;
+ fuid_idx_t *idxnode;
+ void *cookie;
+
+ rw_enter(&zfsvfs->z_fuid_lock, RW_WRITER);
+ if (zfsvfs->z_fuid_loaded == B_FALSE) {
+ rw_exit(&zfsvfs->z_fuid_lock);
+ return;
+ }
+ cookie = NULL;
+ while (domnode = avl_destroy_nodes(&zfsvfs->z_fuid_domain, &cookie)) {
+ ksiddomain_rele(domnode->f_ksid);
+ kmem_free(domnode, sizeof (fuid_domain_t));
+ }
+ avl_destroy(&zfsvfs->z_fuid_domain);
+ cookie = NULL;
+ while (idxnode = avl_destroy_nodes(&zfsvfs->z_fuid_idx, &cookie))
+ kmem_free(idxnode, sizeof (fuid_idx_t));
+ avl_destroy(&zfsvfs->z_fuid_idx);
+ rw_exit(&zfsvfs->z_fuid_lock);
+}
+
+/*
+ * Allocate zfs_fuid_info for tracking FUIDs created during
+ * zfs_mknode, VOP_SETATTR() or VOP_SETSECATTR()
+ */
+zfs_fuid_info_t *
+zfs_fuid_info_alloc(void)
+{
+ zfs_fuid_info_t *fuidp;
+
+ fuidp = kmem_zalloc(sizeof (zfs_fuid_info_t), KM_SLEEP);
+ list_create(&fuidp->z_domains, sizeof (zfs_fuid_domain_t),
+ offsetof(zfs_fuid_domain_t, z_next));
+ list_create(&fuidp->z_fuids, sizeof (zfs_fuid_t),
+ offsetof(zfs_fuid_t, z_next));
+ return (fuidp);
+}
+
+/*
+ * Release all memory associated with zfs_fuid_info_t
+ */
+void
+zfs_fuid_info_free(zfs_fuid_info_t *fuidp)
+{
+ zfs_fuid_t *zfuid;
+ zfs_fuid_domain_t *zdomain;
+
+ while ((zfuid = list_head(&fuidp->z_fuids)) != NULL) {
+ list_remove(&fuidp->z_fuids, zfuid);
+ kmem_free(zfuid, sizeof (zfs_fuid_t));
+ }
+
+ if (fuidp->z_domain_table != NULL)
+ kmem_free(fuidp->z_domain_table,
+ (sizeof (char **)) * fuidp->z_domain_cnt);
+
+ while ((zdomain = list_head(&fuidp->z_domains)) != NULL) {
+ list_remove(&fuidp->z_domains, zdomain);
+ kmem_free(zdomain, sizeof (zfs_fuid_domain_t));
+ }
+
+ kmem_free(fuidp, sizeof (zfs_fuid_info_t));
+}
+
+/*
+ * Check to see if id is a groupmember. If cred
+ * has ksid info then sidlist is checked first
+ * and if still not found then POSIX groups are checked
+ *
+ * Will use a straight FUID compare when possible.
+ */
+boolean_t
+zfs_groupmember(zfsvfs_t *zfsvfs, uint64_t id, cred_t *cr)
+{
+ ksid_t *ksid = crgetsid(cr, KSID_GROUP);
+ uid_t gid;
+
+ if (ksid) {
+ int i;
+ ksid_t *ksid_groups;
+ ksidlist_t *ksidlist = crgetsidlist(cr);
+ uint32_t idx = FUID_INDEX(id);
+ uint32_t rid = FUID_RID(id);
+
+ ASSERT(ksidlist);
+ ksid_groups = ksidlist->ksl_sids;
+
+ for (i = 0; i != ksidlist->ksl_nsid; i++) {
+ if (idx == 0) {
+ if (id != IDMAP_WK_CREATOR_GROUP_GID &&
+ id == ksid_groups[i].ks_id) {
+ return (B_TRUE);
+ }
+ } else {
+ char *domain;
+
+ domain = zfs_fuid_find_by_idx(zfsvfs, idx);
+ ASSERT(domain != NULL);
+
+ if (strcmp(domain,
+ IDMAP_WK_CREATOR_SID_AUTHORITY) == 0) {
+ return (B_FALSE);
+ }
+
+ if ((strcmp(domain,
+ ksid_groups[i].ks_domain->kd_name) == 0) &&
+ rid == ksid_groups[i].ks_rid) {
+ return (B_TRUE);
+ }
+ }
+ }
+ }
+
+ /*
+ * Not found in ksidlist, check posix groups
+ */
+ zfs_fuid_map_id(zfsvfs, id, ZFS_GROUP, &gid);
+
+ return (groupmember(gid, cr));
+}
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 54158d03f2..72e2524646 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -38,6 +38,8 @@
#include <sys/cmn_err.h>
#include <sys/stat.h>
#include <sys/zfs_ioctl.h>
+#include <sys/zfs_i18n.h>
+#include <sys/zfs_znode.h>
#include <sys/zap.h>
#include <sys/spa.h>
#include <sys/spa_impl.h>
@@ -60,6 +62,7 @@
#include <sys/sdt.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_dir.h>
#include <sys/zvol.h>
#include <sharefs/share.h>
#include <sys/zfs_znode.h>
@@ -154,6 +157,22 @@ history_str_get(zfs_cmd_t *zc)
return (buf);
}
+static int
+zfs_check_version(const char *name, int version)
+{
+
+ spa_t *spa;
+
+ if (spa_open(name, &spa, FTAG) == 0) {
+ if (spa_version(spa) < version) {
+ spa_close(spa, FTAG);
+ return (1);
+ }
+ spa_close(spa, FTAG);
+ }
+ return (0);
+}
+
static void
zfs_log_history(zfs_cmd_t *zc)
{
@@ -1280,9 +1299,8 @@ zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
nvpair_type(elem) != DATA_TYPE_STRING)
return (EINVAL);
- error = zfs_secpolicy_write_perms(name,
- ZFS_DELEG_PERM_USERPROP, CRED());
- if (error)
+ if (error = zfs_secpolicy_write_perms(name,
+ ZFS_DELEG_PERM_USERPROP, CRED()))
return (error);
continue;
}
@@ -1304,35 +1322,25 @@ zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
nvpair_value_uint64(elem, &intval) == 0 &&
intval >= ZIO_COMPRESS_GZIP_1 &&
intval <= ZIO_COMPRESS_GZIP_9) {
- spa_t *spa;
-
- if (spa_open(name, &spa, FTAG) == 0) {
- if (spa_version(spa) <
- SPA_VERSION_GZIP_COMPRESSION) {
- spa_close(spa, FTAG);
- return (ENOTSUP);
- }
-
- spa_close(spa, FTAG);
- }
+ if (zfs_check_version(name,
+ SPA_VERSION_GZIP_COMPRESSION))
+ return (ENOTSUP);
}
break;
case ZFS_PROP_COPIES:
- {
- spa_t *spa;
-
- if (spa_open(name, &spa, FTAG) == 0) {
- if (spa_version(spa) <
- SPA_VERSION_DITTO_BLOCKS) {
- spa_close(spa, FTAG);
- return (ENOTSUP);
- }
- spa_close(spa, FTAG);
- }
+ if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS))
+ return (ENOTSUP);
break;
+ case ZFS_PROP_NORMALIZE:
+ case ZFS_PROP_UTF8ONLY:
+ case ZFS_PROP_CASE:
+ if (zfs_check_version(name, SPA_VERSION_NORMALIZATION))
+ return (ENOTSUP);
+
}
- }
+ if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
+ return (error);
}
elem = NULL;
@@ -1642,13 +1650,163 @@ zfs_get_vfs(const char *resource)
static void
zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
{
- nvlist_t *nvprops = arg;
- uint64_t version = ZPL_VERSION;
+ zfs_creat_t *zct = arg;
+ uint64_t version;
+
+ if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
+ version = ZPL_VERSION;
+ else
+ version = ZPL_VERSION_FUID - 1;
- (void) nvlist_lookup_uint64(nvprops,
+ (void) nvlist_lookup_uint64(zct->zct_props,
zfs_prop_to_name(ZFS_PROP_VERSION), &version);
- zfs_create_fs(os, cr, version, tx);
+ zfs_create_fs(os, cr, version, zct->zct_norm, tx);
+}
+
+/*
+ * zfs_prop_lookup()
+ *
+ * Look for the property first in the existing property nvlist. If
+ * it's already present, you're done. If it's not there, attempt to
+ * find the property value from a parent dataset. If that fails, fall
+ * back to the property's default value. In either of these two
+ * cases, if update is TRUE, add a value for the property to the
+ * property nvlist.
+ *
+ * If the rval pointer is non-NULL, copy the discovered value to rval.
+ *
+ * If we get any unexpected errors, bail and return the error number
+ * to the caller.
+ *
+ * If we succeed, return 0.
+ */
+static int
+zfs_prop_lookup(const char *parentname, zfs_prop_t propnum,
+ nvlist_t *proplist, uint64_t *rval, boolean_t update)
+{
+ const char *propname;
+ uint64_t value;
+ int error = ENOENT;
+
+ propname = zfs_prop_to_name(propnum);
+ if (proplist != NULL)
+ error = nvlist_lookup_uint64(proplist, propname, &value);
+ if (error == ENOENT) {
+ error = dsl_prop_get_integer(parentname, propname,
+ &value, NULL);
+ if (error == ENOENT)
+ value = zfs_prop_default_numeric(propnum);
+ else if (error != 0)
+ return (error);
+ if (update) {
+ ASSERT(proplist != NULL);
+ error = nvlist_add_uint64(proplist, propname, value);
+ }
+ }
+ if (error == 0 && rval)
+ *rval = value;
+ return (error);
+}
+
+/*
+ * zfs_normalization_get
+ *
+ * Get the normalization flag value. If the properties have
+ * non-default values, make sure the pool version is recent enough to
+ * support these choices.
+ */
+static int
+zfs_normalization_get(const char *dataset, nvlist_t *proplist, int *norm,
+ boolean_t update)
+{
+ char parentname[MAXNAMELEN];
+ char poolname[MAXNAMELEN];
+ char *cp;
+ uint64_t value;
+ int check = 0;
+ int error;
+
+ ASSERT(norm != NULL);
+ *norm = 0;
+
+ (void) strncpy(parentname, dataset, sizeof (parentname));
+ cp = strrchr(parentname, '@');
+ if (cp != NULL) {
+ cp[0] = '\0';
+ } else {
+ cp = strrchr(parentname, '/');
+ if (cp == NULL)
+ return (ENOENT);
+ cp[0] = '\0';
+ }
+
+ (void) strncpy(poolname, dataset, sizeof (poolname));
+ cp = strchr(poolname, '/');
+ if (cp != NULL)
+ cp[0] = '\0';
+
+ error = zfs_prop_lookup(parentname, ZFS_PROP_UTF8ONLY,
+ proplist, &value, update);
+ if (error != 0)
+ return (error);
+ if (value != zfs_prop_default_numeric(ZFS_PROP_UTF8ONLY))
+ check = 1;
+
+ error = zfs_prop_lookup(parentname, ZFS_PROP_NORMALIZE,
+ proplist, &value, update);
+ if (error != 0)
+ return (error);
+ if (value != zfs_prop_default_numeric(ZFS_PROP_NORMALIZE)) {
+ check = 1;
+ switch ((int)value) {
+ case ZFS_NORMALIZE_NONE:
+ break;
+ case ZFS_NORMALIZE_C:
+ *norm |= U8_TEXTPREP_NFC;
+ break;
+ case ZFS_NORMALIZE_D:
+ *norm |= U8_TEXTPREP_NFD;
+ break;
+ case ZFS_NORMALIZE_KC:
+ *norm |= U8_TEXTPREP_NFKC;
+ break;
+ case ZFS_NORMALIZE_KD:
+ *norm |= U8_TEXTPREP_NFKD;
+ break;
+ default:
+ ASSERT((int)value >= ZFS_NORMALIZE_NONE);
+ ASSERT((int)value <= ZFS_NORMALIZE_KD);
+ break;
+ }
+ }
+
+ error = zfs_prop_lookup(parentname, ZFS_PROP_CASE,
+ proplist, &value, update);
+ if (error != 0)
+ return (error);
+ if (value != zfs_prop_default_numeric(ZFS_PROP_CASE)) {
+ check = 1;
+ switch ((int)value) {
+ case ZFS_CASE_SENSITIVE:
+ break;
+ case ZFS_CASE_INSENSITIVE:
+ *norm |= U8_TEXTPREP_TOUPPER;
+ break;
+ case ZFS_CASE_MIXED:
+ *norm |= U8_TEXTPREP_TOUPPER;
+ break;
+ default:
+ ASSERT((int)value >= ZFS_CASE_SENSITIVE);
+ ASSERT((int)value <= ZFS_CASE_MIXED);
+ break;
+ }
+ }
+
+ if (check == 1)
+ if (zfs_check_version(poolname, SPA_VERSION_NORMALIZATION))
+ return (ENOTSUP);
+ return (0);
}
static int
@@ -1656,6 +1814,7 @@ zfs_ioc_create(zfs_cmd_t *zc)
{
objset_t *clone;
int error = 0;
+ zfs_creat_t zct;
nvlist_t *nvprops = NULL;
void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
dmu_objset_type_t type = zc->zc_objset_type;
@@ -1682,6 +1841,9 @@ zfs_ioc_create(zfs_cmd_t *zc)
&nvprops)) != 0)
return (error);
+ zct.zct_norm = 0;
+ zct.zct_props = nvprops;
+
if (zc->zc_value[0] != '\0') {
/*
* We're creating a clone of an existing snapshot.
@@ -1699,6 +1861,34 @@ zfs_ioc_create(zfs_cmd_t *zc)
return (error);
}
error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
+ if (error) {
+ dmu_objset_close(clone);
+ nvlist_free(nvprops);
+ return (error);
+ }
+ /*
+ * If caller did not provide any properties, allocate
+ * an nvlist for properties, as we will be adding our set-once
+ * properties to it. This carries the choices made on the
+ * original file system into the clone.
+ */
+ if (nvprops == NULL)
+ VERIFY(nvlist_alloc(&nvprops,
+ NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ /*
+ * We have to have normalization and case-folding
+ * flags correct when we do the file system creation,
+ * so go figure them out now. All we really care about
+ * here is getting these values into the property list.
+ */
+ error = zfs_normalization_get(zc->zc_value, nvprops,
+ &zct.zct_norm, B_TRUE);
+ if (error != 0) {
+ dmu_objset_close(clone);
+ nvlist_free(nvprops);
+ return (error);
+ }
dmu_objset_close(clone);
} else {
if (cbfunc == NULL) {
@@ -1737,18 +1927,38 @@ zfs_ioc_create(zfs_cmd_t *zc)
}
} else if (type == DMU_OST_ZFS) {
uint64_t version;
+ int error;
+
+ error = nvlist_lookup_uint64(nvprops,
+ zfs_prop_to_name(ZFS_PROP_VERSION), &version);
- if (0 == nvlist_lookup_uint64(nvprops,
- zfs_prop_to_name(ZFS_PROP_VERSION), &version) &&
- (version < ZPL_VERSION_INITIAL ||
+ if (error == 0 && (version < ZPL_VERSION_INITIAL ||
version > ZPL_VERSION)) {
nvlist_free(nvprops);
- return (EINVAL);
+ return (ENOTSUP);
+ } else if (error == 0 && version >= ZPL_VERSION_FUID &&
+ zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) {
+ nvlist_free(nvprops);
+ return (ENOTSUP);
}
- }
+ /*
+ * We have to have normalization and
+ * case-folding flags correct when we do the
+ * file system creation, so go figure them out
+ * now. The final argument to zfs_normalization_get()
+ * tells that routine not to update the nvprops
+ * list.
+ */
+ error = zfs_normalization_get(zc->zc_name, nvprops,
+ &zct.zct_norm, B_FALSE);
+ if (error != 0) {
+ nvlist_free(nvprops);
+ return (error);
+ }
+ }
error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
- nvprops);
+ &zct);
}
/*
@@ -1952,7 +2162,7 @@ zfs_ioc_recvbackup(zfs_cmd_t *zc)
if (zfsvfs != NULL)
VFS_RELE(zfsvfs->z_vfs);
new_off = fp->f_offset + zc->zc_cookie;
- if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0)
+ if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off, NULL) == 0)
fp->f_offset = new_off;
releasef(fd);
@@ -2123,55 +2333,129 @@ zfs_ioc_promote(zfs_cmd_t *zc)
/*
* We don't want to have a hard dependency
* against some special symbols in sharefs
- * and nfs. Determine them if needed when
+ * nfs, and smbsrv. Determine them if needed when
* the first file system is shared.
- * Neither sharefs or nfs are unloadable modules.
+ * Neither sharefs, nfs or smbsrv are unloadable modules.
*/
-int (*zexport_fs)(void *arg);
+int (*znfsexport_fs)(void *arg);
int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
+int (*zsmbexport_fs)(void *arg, boolean_t add_share);
+
+int zfs_nfsshare_inited;
+int zfs_smbshare_inited;
-int zfs_share_inited;
ddi_modhandle_t nfs_mod;
ddi_modhandle_t sharefs_mod;
+ddi_modhandle_t smbsrv_mod;
kmutex_t zfs_share_lock;
static int
+zfs_init_sharefs()
+{
+ int error;
+
+ ASSERT(MUTEX_HELD(&zfs_share_lock));
+ /* Both NFS and SMB shares also require sharetab support. */
+ if (sharefs_mod == NULL && ((sharefs_mod =
+ ddi_modopen("fs/sharefs",
+ KRTLD_MODE_FIRST, &error)) == NULL)) {
+ return (ENOSYS);
+ }
+ if (zshare_fs == NULL && ((zshare_fs =
+ (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
+ ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
+ return (ENOSYS);
+ }
+ return (0);
+}
+
+static int
zfs_ioc_share(zfs_cmd_t *zc)
{
int error;
int opcode;
- if (zfs_share_inited == 0) {
- mutex_enter(&zfs_share_lock);
- nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error);
- sharefs_mod = ddi_modopen("fs/sharefs",
- KRTLD_MODE_FIRST, &error);
- if (nfs_mod == NULL || sharefs_mod == NULL) {
+ switch (zc->zc_share.z_sharetype) {
+ case ZFS_SHARE_NFS:
+ case ZFS_UNSHARE_NFS:
+ if (zfs_nfsshare_inited == 0) {
+ mutex_enter(&zfs_share_lock);
+ if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs",
+ KRTLD_MODE_FIRST, &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ if (znfsexport_fs == NULL &&
+ ((znfsexport_fs = (int (*)(void *))
+ ddi_modsym(nfs_mod,
+ "nfs_export", &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ error = zfs_init_sharefs();
+ if (error) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ zfs_nfsshare_inited = 1;
mutex_exit(&zfs_share_lock);
- return (ENOSYS);
}
- if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *))
- ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) {
+ break;
+ case ZFS_SHARE_SMB:
+ case ZFS_UNSHARE_SMB:
+ if (zfs_smbshare_inited == 0) {
+ mutex_enter(&zfs_share_lock);
+ if (smbsrv_mod == NULL && ((smbsrv_mod =
+ ddi_modopen("drv/smbsrv",
+ KRTLD_MODE_FIRST, &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ if (zsmbexport_fs == NULL && ((zsmbexport_fs =
+ (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod,
+ "lmshrd_share_upcall", &error)) == NULL)) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ error = zfs_init_sharefs();
+ if (error) {
+ mutex_exit(&zfs_share_lock);
+ return (ENOSYS);
+ }
+ zfs_smbshare_inited = 1;
mutex_exit(&zfs_share_lock);
- return (ENOSYS);
}
+ break;
+ default:
+ return (EINVAL);
+ }
- if (zshare_fs == NULL && ((zshare_fs =
- (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
- ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
- mutex_exit(&zfs_share_lock);
- return (ENOSYS);
+ switch (zc->zc_share.z_sharetype) {
+ case ZFS_SHARE_NFS:
+ case ZFS_UNSHARE_NFS:
+ if (error =
+ znfsexport_fs((void *)
+ (uintptr_t)zc->zc_share.z_exportdata))
+ return (error);
+ break;
+ case ZFS_SHARE_SMB:
+ case ZFS_UNSHARE_SMB:
+ if (error = zsmbexport_fs((void *)
+ (uintptr_t)zc->zc_share.z_exportdata,
+ zc->zc_share.z_sharetype == ZFS_SHARE_SMB ?
+ B_TRUE : B_FALSE)) {
+ return (error);
}
- zfs_share_inited = 1;
- mutex_exit(&zfs_share_lock);
+ break;
}
- if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata))
- return (error);
-
- opcode = (zc->zc_share.z_sharetype == B_TRUE) ?
+ opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS ||
+ zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ?
SHAREFS_ADD : SHAREFS_REMOVE;
+ /*
+ * Add or remove share from sharetab
+ */
error = zshare_fs(opcode,
(void *)(uintptr_t)zc->zc_share.z_sharedata,
zc->zc_share.z_sharemax);
@@ -2447,10 +2731,12 @@ _fini(void)
zvol_fini();
zfs_fini();
spa_fini();
- if (zfs_share_inited) {
+ if (zfs_nfsshare_inited)
(void) ddi_modclose(nfs_mod);
+ if (zfs_smbshare_inited)
+ (void) ddi_modclose(smbsrv_mod);
+ if (zfs_nfsshare_inited || zfs_smbshare_inited)
(void) ddi_modclose(sharefs_mod);
- }
tsd_destroy(&zfs_fsyncer_key);
ldi_ident_release(zfs_li);
diff --git a/usr/src/uts/common/fs/zfs/zfs_log.c b/usr/src/uts/common/fs/zfs/zfs_log.c
index e5e26d3a05..04075f47bf 100644
--- a/usr/src/uts/common/fs/zfs/zfs_log.c
+++ b/usr/src/uts/common/fs/zfs/zfs_log.c
@@ -45,44 +45,277 @@
#include <sys/acl.h>
#include <sys/dmu.h>
#include <sys/spa.h>
+#include <sys/zfs_fuid.h>
#include <sys/ddi.h>
/*
* All the functions in this file are used to construct the log entries
- * to record transactions. They allocate * a intent log transaction
+ * to record transactions. They allocate * an intent log transaction
* structure (itx_t) and save within it all the information necessary to
* possibly replay the transaction. The itx is then assigned a sequence
* number and inserted in the in-memory list anchored in the zilog.
*/
+int
+zfs_log_create_txtype(zil_create_t type, vsecattr_t *vsecp, vattr_t *vap)
+{
+ int isxvattr = (vap->va_mask & AT_XVATTR);
+ switch (type) {
+ case Z_FILE:
+ if (vsecp == NULL && !isxvattr)
+ return (TX_CREATE);
+ if (vsecp && isxvattr)
+ return (TX_CREATE_ACL_ATTR);
+ if (vsecp)
+ return (TX_CREATE_ACL);
+ else
+ return (TX_CREATE_ATTR);
+ /*NOTREACHED*/
+ case Z_DIR:
+ if (vsecp == NULL && !isxvattr)
+ return (TX_MKDIR);
+ if (vsecp && isxvattr)
+ return (TX_MKDIR_ACL_ATTR);
+ if (vsecp)
+ return (TX_MKDIR_ACL);
+ else
+ return (TX_MKDIR_ATTR);
+ case Z_XATTRDIR:
+ return (TX_MKXATTR);
+ }
+ ASSERT(0);
+ return (TX_MAX_TYPE);
+}
+
+/*
+ * build up the log data necessary for logging xvattr_t
+ * First lr_attr_t is initialized. following the lr_attr_t
+ * is the mapsize and attribute bitmap copied from the xvattr_t.
+ * Following the bitmap and bitmapsize two 64 bit words are reserved
+ * for the create time which may be set. Following the create time
+ * records a single 64 bit integer which has the bits to set on
+ * replay for the xvattr.
+ */
+static void
+zfs_log_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
+{
+ uint32_t *bitmap;
+ uint64_t *attrs;
+ uint64_t *crtime;
+ xoptattr_t *xoap;
+ void *scanstamp;
+ int i;
+
+ xoap = xva_getxoptattr(xvap);
+ ASSERT(xoap);
+
+ lrattr->lr_attr_masksize = xvap->xva_mapsize;
+ bitmap = &lrattr->lr_attr_bitmap;
+ for (i = 0; i != xvap->xva_mapsize; i++, bitmap++) {
+ *bitmap = xvap->xva_reqattrmap[i];
+ }
+
+ /* Now pack the attributes up in a single uint64_t */
+ attrs = (uint64_t *)bitmap;
+ crtime = attrs + 1;
+ scanstamp = (caddr_t)(crtime + 2);
+ *attrs = 0;
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY))
+ *attrs |= (xoap->xoa_readonly == 0) ? 0 :
+ XAT0_READONLY;
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN))
+ *attrs |= (xoap->xoa_hidden == 0) ? 0 :
+ XAT0_HIDDEN;
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM))
+ *attrs |= (xoap->xoa_system == 0) ? 0 :
+ XAT0_SYSTEM;
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE))
+ *attrs |= (xoap->xoa_archive == 0) ? 0 :
+ XAT0_ARCHIVE;
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+ *attrs |= (xoap->xoa_immutable == 0) ? 0 :
+ XAT0_IMMUTABLE;
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+ *attrs |= (xoap->xoa_nounlink == 0) ? 0 :
+ XAT0_NOUNLINK;
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+ *attrs |= (xoap->xoa_appendonly == 0) ? 0 :
+ XAT0_APPENDONLY;
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+ *attrs |= (xoap->xoa_opaque == 0) ? 0 :
+ XAT0_APPENDONLY;
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP))
+ *attrs |= (xoap->xoa_nodump == 0) ? 0 :
+ XAT0_NODUMP;
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED))
+ *attrs |= (xoap->xoa_av_quarantined == 0) ? 0 :
+ XAT0_AV_QUARANTINED;
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+ *attrs |= (xoap->xoa_av_modified == 0) ? 0 :
+ XAT0_AV_MODIFIED;
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME))
+ ZFS_TIME_ENCODE(&xoap->xoa_createtime, crtime);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+ bcopy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ);
+}
+
+static void *
+zfs_log_fuid_ids(zfs_fuid_info_t *fuidp, void *start)
+{
+ zfs_fuid_t *zfuid;
+ uint64_t *fuidloc = start;
+
+ /* First copy in the ACE FUIDs */
+ for (zfuid = list_head(&fuidp->z_fuids); zfuid;
+ zfuid = list_next(&fuidp->z_fuids, zfuid)) {
+ *fuidloc++ = zfuid->z_logfuid;
+ }
+ return (fuidloc);
+}
+
+
+static void *
+zfs_log_fuid_domains(zfs_fuid_info_t *fuidp, void *start)
+{
+ zfs_fuid_domain_t *zdomain;
+
+ /* now copy in the domain info, if any */
+ if (fuidp->z_domain_str_sz != 0) {
+ for (zdomain = list_head(&fuidp->z_domains); zdomain;
+ zdomain = list_next(&fuidp->z_domains, zdomain)) {
+ bcopy((void *)zdomain->z_domain, start,
+ strlen(zdomain->z_domain) + 1);
+ start = (caddr_t)start +
+ strlen(zdomain->z_domain) + 1;
+ }
+ }
+ return (start);
+}
+
/*
- * zfs_log_create() is used to handle TX_CREATE, TX_MKDIR and TX_MKXATTR
+ * zfs_log_create() is used to handle TX_CREATE, TX_CREATE_ATTR, TX_MKDIR,
+ * TX_MKDIR_ATTR and TX_MKXATTR
* transactions.
+ *
+ * TX_CREATE and TX_MKDIR are standard creates, but they may have FUID
+ * domain information appended prior to the name. In this case the
+ * uid/gid in the log record will be a log centric FUID.
+ *
+ * TX_CREATE_ACL_ATTR and TX_MKDIR_ACL_ATTR handle special creates that
+ * may contain attributes, ACL and optional fuid information.
+ *
+ * TX_CREATE_ACL and TX_MKDIR_ACL handle special creates that specify
+ * and ACL and normal users/groups in the ACEs.
+ *
+ * There may be an optional xvattr attribute information similar
+ * to zfs_log_setattr.
+ *
+ * Also, after the file name "domain" strings may be appended.
*/
void
-zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *dzp, znode_t *zp, char *name)
+zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+ znode_t *dzp, znode_t *zp, char *name, vsecattr_t *vsecp,
+ zfs_fuid_info_t *fuidp, vattr_t *vap)
{
itx_t *itx;
uint64_t seq;
lr_create_t *lr;
+ lr_acl_create_t *lracl;
+ size_t aclsize;
+ size_t xvatsize = 0;
+ size_t txsize;
+ xvattr_t *xvap = (xvattr_t *)vap;
+ void *end;
+ size_t lrsize;
+
size_t namesize = strlen(name) + 1;
+ size_t fuidsz = 0;
if (zilog == NULL)
return;
- itx = zil_itx_create(txtype, sizeof (*lr) + namesize);
+ /*
+ * If we have FUIDs present then add in space for
+ * domains and ACE fuid's if any.
+ */
+ if (fuidp) {
+ fuidsz += fuidp->z_domain_str_sz;
+ fuidsz += fuidp->z_fuid_cnt * sizeof (uint64_t);
+ }
+
+ if (vap->va_mask & AT_XVATTR)
+ xvatsize = ZIL_XVAT_SIZE(xvap->xva_mapsize);
+
+ if ((int)txtype == TX_CREATE_ATTR || (int)txtype == TX_MKDIR_ATTR ||
+ (int)txtype == TX_CREATE || (int)txtype == TX_MKDIR ||
+ (int)txtype == TX_MKXATTR) {
+ txsize = sizeof (*lr) + namesize + fuidsz + xvatsize;
+ lrsize = sizeof (*lr);
+ } else {
+ aclsize = (vsecp) ? vsecp->vsa_aclentsz : 0;
+ txsize =
+ sizeof (lr_acl_create_t) + namesize + fuidsz +
+ aclsize + xvatsize;
+ lrsize = sizeof (lr_acl_create_t);
+ }
+
+ itx = zil_itx_create(txtype, txsize);
+
lr = (lr_create_t *)&itx->itx_lr;
lr->lr_doid = dzp->z_id;
lr->lr_foid = zp->z_id;
lr->lr_mode = zp->z_phys->zp_mode;
- lr->lr_uid = zp->z_phys->zp_uid;
- lr->lr_gid = zp->z_phys->zp_gid;
+ if (!IS_EPHEMERAL(zp->z_phys->zp_uid)) {
+ lr->lr_uid = (uint64_t)zp->z_phys->zp_uid;
+ } else {
+ lr->lr_uid = fuidp->z_fuid_owner;
+ }
+ if (!IS_EPHEMERAL(zp->z_phys->zp_gid)) {
+ lr->lr_gid = (uint64_t)zp->z_phys->zp_gid;
+ } else {
+ lr->lr_gid = fuidp->z_fuid_group;
+ }
lr->lr_gen = zp->z_phys->zp_gen;
lr->lr_crtime[0] = zp->z_phys->zp_crtime[0];
lr->lr_crtime[1] = zp->z_phys->zp_crtime[1];
lr->lr_rdev = zp->z_phys->zp_rdev;
- bcopy(name, (char *)(lr + 1), namesize);
+
+ /*
+ * Fill in xvattr info if any
+ */
+ if (vap->va_mask & AT_XVATTR) {
+ zfs_log_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), xvap);
+ end = (caddr_t)lr + lrsize + xvatsize;
+ } else {
+ end = (caddr_t)lr + lrsize;
+ }
+
+ /* Now fill in any ACL info */
+
+ if (vsecp) {
+ lracl = (lr_acl_create_t *)&itx->itx_lr;
+ lracl->lr_aclcnt = vsecp->vsa_aclcnt;
+ lracl->lr_acl_bytes = aclsize;
+ lracl->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
+ lracl->lr_fuidcnt = fuidp ? fuidp->z_fuid_cnt : 0;
+ if (vsecp->vsa_aclflags & VSA_ACE_ACLFLAGS)
+ lracl->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
+ else
+ lracl->lr_acl_flags = 0;
+
+ bcopy(vsecp->vsa_aclentp, end, aclsize);
+ end = (caddr_t)end + aclsize;
+ }
+
+ /* drop in FUID info */
+ if (fuidp) {
+ end = zfs_log_fuid_ids(fuidp, end);
+ end = zfs_log_fuid_domains(fuidp, end);
+ }
+ /*
+ * Now place file name in log record
+ */
+ bcopy(name, end, namesize);
seq = zil_itx_assign(zilog, itx, tx);
dzp->z_last_itx = seq;
@@ -93,7 +326,7 @@ zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_remove() handles both TX_REMOVE and TX_RMDIR transactions.
*/
void
-zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, char *name)
{
itx_t *itx;
@@ -117,7 +350,7 @@ zfs_log_remove(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_link() handles TX_LINK transactions.
*/
void
-zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name)
{
itx_t *itx;
@@ -143,8 +376,8 @@ zfs_log_link(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_symlink() handles TX_SYMLINK transactions.
*/
void
-zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *dzp, znode_t *zp, char *name, char *link)
+zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
+ znode_t *dzp, znode_t *zp, char *name, char *link)
{
itx_t *itx;
uint64_t seq;
@@ -177,7 +410,7 @@ zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_rename() handles TX_RENAME transactions.
*/
void
-zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, int txtype,
+zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *sdzp, char *sname, znode_t *tdzp, char *dname, znode_t *szp)
{
itx_t *itx;
@@ -328,25 +561,60 @@ zfs_log_truncate(zilog_t *zilog, dmu_tx_t *tx, int txtype,
*/
void
zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, vattr_t *vap, uint_t mask_applied)
+ znode_t *zp, vattr_t *vap, uint_t mask_applied, zfs_fuid_info_t *fuidp)
{
- itx_t *itx;
- uint64_t seq;
- lr_setattr_t *lr;
+ itx_t *itx;
+ uint64_t seq;
+ lr_setattr_t *lr;
+ xvattr_t *xvap = (xvattr_t *)vap;
+ size_t recsize = sizeof (lr_setattr_t);
+ void *start;
+
if (zilog == NULL || zp->z_unlinked)
return;
- itx = zil_itx_create(txtype, sizeof (*lr));
+ /*
+ * If XVATTR set, then log record size needs to allow
+ * for lr_attr_t + xvattr mask, mapsize and create time
+ * plus actual attribute values
+ */
+ if (vap->va_mask & AT_XVATTR)
+ recsize = sizeof (*lr) + ZIL_XVAT_SIZE(xvap->xva_mapsize);
+
+ if (fuidp)
+ recsize += fuidp->z_domain_str_sz;
+
+ itx = zil_itx_create(txtype, recsize);
lr = (lr_setattr_t *)&itx->itx_lr;
lr->lr_foid = zp->z_id;
lr->lr_mask = (uint64_t)mask_applied;
lr->lr_mode = (uint64_t)vap->va_mode;
- lr->lr_uid = (uint64_t)vap->va_uid;
- lr->lr_gid = (uint64_t)vap->va_gid;
+ if ((mask_applied & AT_UID) && IS_EPHEMERAL(vap->va_uid))
+ lr->lr_uid = fuidp->z_fuid_owner;
+ else
+ lr->lr_uid = (uint64_t)vap->va_uid;
+
+ if ((mask_applied & AT_GID) && IS_EPHEMERAL(vap->va_gid))
+ lr->lr_gid = fuidp->z_fuid_group;
+ else
+ lr->lr_gid = (uint64_t)vap->va_gid;
+
lr->lr_size = (uint64_t)vap->va_size;
ZFS_TIME_ENCODE(&vap->va_atime, lr->lr_atime);
ZFS_TIME_ENCODE(&vap->va_mtime, lr->lr_mtime);
+ start = (lr_setattr_t *)(lr + 1);
+ if (vap->va_mask & AT_XVATTR) {
+ zfs_log_xvattr((lr_attr_t *)start, xvap);
+ start = (caddr_t)start + ZIL_XVAT_SIZE(xvap->xva_mapsize);
+ }
+
+ /*
+ * Now stick on domain information if any on end
+ */
+
+ if (fuidp)
+ (void) zfs_log_fuid_domains(fuidp, start);
itx->itx_sync = (zp->z_sync_cnt != 0);
seq = zil_itx_assign(zilog, itx, tx);
@@ -357,21 +625,62 @@ zfs_log_setattr(zilog_t *zilog, dmu_tx_t *tx, int txtype,
* zfs_log_acl() handles TX_ACL transactions.
*/
void
-zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, int txtype,
- znode_t *zp, int aclcnt, ace_t *z_ace)
+zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp,
+ vsecattr_t *vsecp, zfs_fuid_info_t *fuidp)
{
itx_t *itx;
uint64_t seq;
+ lr_acl_v0_t *lrv0;
lr_acl_t *lr;
+ int txtype;
+ int lrsize;
+ size_t txsize;
+ size_t aclbytes = vsecp->vsa_aclentsz;
+
+ txtype = (zp->z_zfsvfs->z_version == ZPL_VERSION_INITIAL) ?
+ TX_ACL_V0 : TX_ACL;
+
+ if (txtype == TX_ACL)
+ lrsize = sizeof (*lr);
+ else
+ lrsize = sizeof (*lrv0);
if (zilog == NULL || zp->z_unlinked)
return;
- itx = zil_itx_create(txtype, sizeof (*lr) + aclcnt * sizeof (ace_t));
+ txsize = lrsize + aclbytes + (fuidp ? fuidp->z_domain_str_sz : 0) +
+ sizeof (uint64) * (fuidp ? fuidp->z_fuid_cnt : 0);
+
+ itx = zil_itx_create(txtype, txsize);
+
lr = (lr_acl_t *)&itx->itx_lr;
lr->lr_foid = zp->z_id;
- lr->lr_aclcnt = (uint64_t)aclcnt;
- bcopy(z_ace, (ace_t *)(lr + 1), aclcnt * sizeof (ace_t));
+ if (txtype == TX_ACL) {
+ lr->lr_acl_bytes = aclbytes;
+ lr->lr_domcnt = fuidp ? fuidp->z_domain_cnt : 0;
+ lr->lr_fuidcnt = fuidp ? fuidp->z_fuid_cnt : 0;
+ if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS)
+ lr->lr_acl_flags = (uint64_t)vsecp->vsa_aclflags;
+ else
+ lr->lr_acl_flags = 0;
+ }
+ lr->lr_aclcnt = (uint64_t)vsecp->vsa_aclcnt;
+
+ if (txtype == TX_ACL_V0) {
+ lrv0 = (lr_acl_v0_t *)lr;
+ bcopy(vsecp->vsa_aclentp, (ace_t *)(lrv0 + 1), aclbytes);
+ } else {
+ void *start = (ace_t *)(lr + 1);
+
+ bcopy(vsecp->vsa_aclentp, start, aclbytes);
+
+ start = (caddr_t)start + aclbytes;
+
+ if (fuidp) {
+ start = zfs_log_fuid_ids(fuidp, start);
+ (void) zfs_log_fuid_domains(fuidp, start);
+ }
+ }
itx->itx_sync = (zp->z_sync_cnt != 0);
seq = zil_itx_assign(zilog, itx, tx);
diff --git a/usr/src/uts/common/fs/zfs/zfs_replay.c b/usr/src/uts/common/fs/zfs/zfs_replay.c
index 4b028510b5..6b2937490f 100644
--- a/usr/src/uts/common/fs/zfs/zfs_replay.c
+++ b/usr/src/uts/common/fs/zfs/zfs_replay.c
@@ -39,6 +39,7 @@
#include <sys/zfs_znode.h>
#include <sys/zfs_dir.h>
#include <sys/zfs_acl.h>
+#include <sys/zfs_fuid.h>
#include <sys/spa.h>
#include <sys/zil.h>
#include <sys/byteorder.h>
@@ -62,8 +63,8 @@ zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
vap->va_mask = (uint_t)mask;
vap->va_type = IFTOVT(mode);
vap->va_mode = mode & MODEMASK;
- vap->va_uid = (uid_t)uid;
- vap->va_gid = (gid_t)gid;
+ vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid;
+ vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid;
vap->va_rdev = zfs_cmpldev(rdev);
vap->va_nodeid = nodeid;
}
@@ -75,23 +76,345 @@ zfs_replay_error(zfsvfs_t *zfsvfs, lr_t *lr, boolean_t byteswap)
return (ENOTSUP);
}
+static void
+zfs_replay_xvattr(lr_attr_t *lrattr, xvattr_t *xvap)
+{
+ xoptattr_t *xoap = NULL;
+ uint64_t *attrs;
+ uint64_t *crtime;
+ void *scanstamp;
+
+ xvap->xva_vattr.va_mask |= AT_XVATTR;
+ if ((xoap = xva_getxoptattr(xvap)) == NULL) {
+ xvap->xva_vattr.va_mask &= ~AT_XVATTR; /* shouldn't happen */
+ return;
+ }
+
+ ASSERT(lrattr->lr_attr_masksize == xvap->xva_mapsize);
+ bcopy(&lrattr->lr_attr_bitmap, xvap->xva_reqattrmap,
+ xvap->xva_mapsize);
+ attrs = (uint64_t *)(lrattr + lrattr->lr_attr_masksize - 1);
+ crtime = attrs + 1;
+ scanstamp = (caddr_t)(crtime + 2);
+
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN))
+ xoap->xoa_hidden = ((*attrs & XAT0_HIDDEN) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM))
+ xoap->xoa_system = ((*attrs & XAT0_SYSTEM) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE))
+ xoap->xoa_archive = ((*attrs & XAT0_ARCHIVE) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY))
+ xoap->xoa_readonly = ((*attrs & XAT0_READONLY) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+ xoap->xoa_immutable = ((*attrs & XAT0_IMMUTABLE) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+ xoap->xoa_nounlink = ((*attrs & XAT0_NOUNLINK) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+ xoap->xoa_appendonly = ((*attrs & XAT0_APPENDONLY) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP))
+ xoap->xoa_nodump = ((*attrs & XAT0_NODUMP) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+ xoap->xoa_opaque = ((*attrs & XAT0_OPAQUE) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+ xoap->xoa_av_modified = ((*attrs & XAT0_AV_MODIFIED) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED))
+ xoap->xoa_av_quarantined =
+ ((*attrs & XAT0_AV_QUARANTINED) != 0);
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME))
+ ZFS_TIME_DECODE(&xoap->xoa_createtime, crtime);
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP))
+ bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
+}
+
+static int
+zfs_replay_domain_cnt(uint64_t uid, uint64_t gid)
+{
+ uint64_t uid_idx;
+ uint64_t gid_idx;
+ int domcnt = 0;
+
+ uid_idx = FUID_INDEX(uid);
+ gid_idx = FUID_INDEX(gid);
+ if (uid_idx)
+ domcnt++;
+ if (gid_idx > 0 && gid_idx != uid_idx)
+ domcnt++;
+
+ return (domcnt);
+}
+
+static void *
+zfs_replay_fuid_domain_common(zfs_fuid_info_t *fuid_infop, void *start,
+ int domcnt)
+{
+ int i;
+
+ for (i = 0; i != domcnt; i++) {
+ fuid_infop->z_domain_table[i] = start;
+ start = (caddr_t)start + strlen(start) + 1;
+ }
+
+ return (start);
+}
+
+/*
+ * Set the uid/gid in the fuid_info structure.
+ */
+static void
+zfs_replay_fuid_ugid(zfs_fuid_info_t *fuid_infop, uint64_t uid, uint64_t gid)
+{
+ /*
+ * If owner or group are log specific FUIDs then slurp up
+ * domain information and build zfs_fuid_info_t
+ */
+ if (IS_EPHEMERAL(uid))
+ fuid_infop->z_fuid_owner = uid;
+
+ if (IS_EPHEMERAL(gid))
+ fuid_infop->z_fuid_group = gid;
+}
+
+/*
+ * Load fuid domains into fuid_info_t
+ */
+static zfs_fuid_info_t *
+zfs_replay_fuid_domain(void *buf, void **end, uint64_t uid, uint64_t gid)
+{
+ int domcnt;
+
+ zfs_fuid_info_t *fuid_infop;
+
+ fuid_infop = zfs_fuid_info_alloc();
+
+ domcnt = zfs_replay_domain_cnt(uid, gid);
+
+ if (domcnt == 0)
+ return (fuid_infop);
+
+ fuid_infop->z_domain_table =
+ kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+
+ zfs_replay_fuid_ugid(fuid_infop, uid, gid);
+
+ fuid_infop->z_domain_cnt = domcnt;
+ *end = zfs_replay_fuid_domain_common(fuid_infop, buf, domcnt);
+ return (fuid_infop);
+}
+
+/*
+ * load zfs_fuid_t's and fuid_domains into fuid_info_t
+ */
+static zfs_fuid_info_t *
+zfs_replay_fuids(void *start, void **end, int idcnt, int domcnt, uint64_t uid,
+ uint64_t gid)
+{
+ uint64_t *log_fuid = (uint64_t *)start;
+ zfs_fuid_info_t *fuid_infop;
+ int i;
+
+ fuid_infop = zfs_fuid_info_alloc();
+ fuid_infop->z_domain_cnt = domcnt;
+
+ fuid_infop->z_domain_table =
+ kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+
+ for (i = 0; i != idcnt; i++) {
+ zfs_fuid_t *zfuid;
+
+ zfuid = kmem_alloc(sizeof (zfs_fuid_t), KM_SLEEP);
+ zfuid->z_logfuid = *log_fuid;
+ zfuid->z_id = -1;
+ zfuid->z_domidx = 0;
+ list_insert_tail(&fuid_infop->z_fuids, zfuid);
+ log_fuid++;
+ }
+
+ zfs_replay_fuid_ugid(fuid_infop, uid, gid);
+
+ *end = zfs_replay_fuid_domain_common(fuid_infop, log_fuid, domcnt);
+ return (fuid_infop);
+}
+
+static void
+zfs_replay_swap_attrs(lr_attr_t *lrattr)
+{
+ /* swap the lr_attr structure */
+ byteswap_uint32_array(lrattr, sizeof (*lrattr));
+ /* swap the bitmap */
+ byteswap_uint32_array(lrattr + 1, lrattr->lr_attr_masksize - 1);
+ /* swap the attributes, create time + 64 bit word for attributes */
+ byteswap_uint64_array(lrattr + (sizeof (uint32_t) *
+ (lrattr->lr_attr_masksize - 1)), 3 * sizeof (uint64_t));
+}
+
+/*
+ * Replay file create with optional ACL, xvattr information as well
+ * as option FUID information.
+ */
+static int
+zfs_replay_create_acl(zfsvfs_t *zfsvfs,
+ lr_acl_create_t *lracl, boolean_t byteswap)
+{
+ char *name = NULL; /* location determined later */
+ lr_create_t *lr = (lr_create_t *)lracl;
+ znode_t *dzp;
+ vnode_t *vp = NULL;
+ xvattr_t xva;
+ int vflg = 0;
+ vsecattr_t vsec = { 0 };
+ lr_attr_t *lrattr;
+ void *aclstart;
+ void *fuidstart;
+ size_t xvatlen = 0;
+ uint64_t txtype;
+ int error;
+
+ if (byteswap) {
+ byteswap_uint64_array(lracl, sizeof (*lracl));
+ txtype = (int)lr->lr_common.lrc_txtype;
+ if (txtype == TX_CREATE_ACL_ATTR ||
+ txtype == TX_MKDIR_ACL_ATTR) {
+ lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+ zfs_replay_swap_attrs(lrattr);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ }
+
+ aclstart = (caddr_t)(lracl + 1) + xvatlen;
+ zfs_ace_byteswap(aclstart, lracl->lr_acl_bytes, B_FALSE);
+ /* swap fuids */
+ if (lracl->lr_fuidcnt) {
+ byteswap_uint64_array((caddr_t)aclstart +
+ lracl->lr_acl_bytes, sizeof (uint64_t));
+ }
+ }
+
+ if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
+ return (error);
+
+ xva_init(&xva);
+ zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID,
+ lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
+
+ /*
+ * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
+ * eventually end up in zfs_mknode(), which assigns the object's
+ * creation time and generation number. The generic VOP_CREATE()
+ * doesn't have either concept, so we smuggle the values inside
+ * the vattr's otherwise unused va_ctime and va_nblocks fields.
+ */
+ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
+ xva.xva_vattr.va_nblocks = lr->lr_gen;
+
+ error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
+ if (error != ENOENT)
+ goto bail;
+
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+ switch ((int)lr->lr_common.lrc_txtype) {
+ case TX_CREATE_ACL:
+ aclstart = (caddr_t)(lracl + 1);
+ fuidstart = (caddr_t)aclstart + lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+ /*FALLTHROUGH*/
+ case TX_CREATE_ACL_ATTR:
+ if (name == NULL) {
+ lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ xva.xva_vattr.va_mask |= AT_XVATTR;
+ zfs_replay_xvattr(lrattr, &xva);
+ }
+ vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
+ vsec.vsa_aclcnt = lracl->lr_aclcnt;
+ vsec.vsa_aclentsz = lracl->lr_acl_bytes;
+ vsec.vsa_aclflags = lracl->lr_acl_flags;
+ if (zfsvfs->z_fuid_replay == NULL)
+ fuidstart = (caddr_t)(lracl + 1) + xvatlen +
+ lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+
+ error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr,
+ 0, 0, &vp, kcred, vflg, NULL, &vsec);
+ break;
+ case TX_MKDIR_ACL:
+ aclstart = (caddr_t)(lracl + 1);
+ fuidstart = (caddr_t)aclstart + lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+ /*FALLTHROUGH*/
+ case TX_MKDIR_ACL_ATTR:
+ if (name == NULL) {
+ lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ zfs_replay_xvattr(lrattr, &xva);
+ }
+ vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
+ vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
+ vsec.vsa_aclcnt = lracl->lr_aclcnt;
+ vsec.vsa_aclentsz = lracl->lr_acl_bytes;
+ vsec.vsa_aclflags = lracl->lr_acl_flags;
+ if (zfsvfs->z_fuid_replay == NULL)
+ fuidstart = (caddr_t)(lracl + 1) + xvatlen +
+ lracl->lr_acl_bytes;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuids(fuidstart,
+ (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
+ lr->lr_uid, lr->lr_gid);
+ error = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr,
+ &vp, kcred, NULL, vflg, &vsec);
+ break;
+ default:
+ error = ENOTSUP;
+ }
+
+bail:
+ if (error == 0 && vp != NULL)
+ VN_RELE(vp);
+
+ VN_RELE(ZTOV(dzp));
+
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
+
+ return (error);
+}
+
static int
zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
{
- char *name = (char *)(lr + 1); /* name follows lr_create_t */
+ char *name = NULL; /* location determined later */
char *link; /* symlink content follows name */
znode_t *dzp;
vnode_t *vp = NULL;
- vattr_t va;
+ xvattr_t xva;
+ int vflg = 0;
+ size_t lrsize = sizeof (lr_create_t);
+ lr_attr_t *lrattr;
+ void *start;
+ size_t xvatlen;
+ uint64_t txtype;
int error;
- if (byteswap)
+ if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
+ txtype = (int)lr->lr_common.lrc_txtype;
+ if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR)
+ zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
+ }
+
if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
return (error);
- zfs_init_vattr(&va, AT_TYPE | AT_MODE | AT_UID | AT_GID,
+ xva_init(&xva);
+ zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID,
lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
/*
@@ -101,26 +424,77 @@ zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
* doesn't have either concept, so we smuggle the values inside
* the vattr's otherwise unused va_ctime and va_nblocks fields.
*/
- ZFS_TIME_DECODE(&va.va_ctime, lr->lr_crtime);
- va.va_nblocks = lr->lr_gen;
+ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
+ xva.xva_vattr.va_nblocks = lr->lr_gen;
error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
if (error != ENOENT)
goto out;
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
+ /*
+ * Symlinks don't have fuid info, and CIFS never creates
+ * symlinks.
+ *
+ * The _ATTR versions will grab the fuid info in their subcases.
+ */
+ if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK &&
+ (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR &&
+ (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) {
+ start = (lr + 1);
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
+ }
+
switch ((int)lr->lr_common.lrc_txtype) {
+ case TX_CREATE_ATTR:
+ lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
+ start = (caddr_t)(lr + 1) + xvatlen;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
+ name = (char *)start;
+
+ /*FALLTHROUGH*/
case TX_CREATE:
- error = VOP_CREATE(ZTOV(dzp), name, &va, 0, 0, &vp, kcred, 0);
+ if (name == NULL)
+ name = (char *)start;
+
+ error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr,
+ 0, 0, &vp, kcred, vflg, NULL, NULL);
break;
+ case TX_MKDIR_ATTR:
+ lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
+ xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+ zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
+ start = (caddr_t)(lr + 1) + xvatlen;
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
+ name = (char *)start;
+
+ /*FALLTHROUGH*/
case TX_MKDIR:
- error = VOP_MKDIR(ZTOV(dzp), name, &va, &vp, kcred);
+ if (name == NULL)
+ name = (char *)(lr + 1);
+
+ error = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr,
+ &vp, kcred, NULL, vflg, NULL);
break;
case TX_MKXATTR:
- error = zfs_make_xattrdir(dzp, &va, &vp, kcred);
+ name = (char *)(lr + 1);
+ error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &vp, kcred);
break;
case TX_SYMLINK:
+ name = (char *)(lr + 1);
link = name + strlen(name) + 1;
- error = VOP_SYMLINK(ZTOV(dzp), name, &va, link, kcred);
+ error = VOP_SYMLINK(ZTOV(dzp), name, &xva.xva_vattr,
+ link, kcred, NULL, vflg);
break;
default:
error = ENOTSUP;
@@ -132,6 +506,9 @@ out:
VN_RELE(ZTOV(dzp));
+ if (zfsvfs->z_fuid_replay)
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
return (error);
}
@@ -141,6 +518,7 @@ zfs_replay_remove(zfsvfs_t *zfsvfs, lr_remove_t *lr, boolean_t byteswap)
char *name = (char *)(lr + 1); /* name follows lr_remove_t */
znode_t *dzp;
int error;
+ int vflg = 0;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
@@ -148,12 +526,15 @@ zfs_replay_remove(zfsvfs_t *zfsvfs, lr_remove_t *lr, boolean_t byteswap)
if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
return (error);
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
switch ((int)lr->lr_common.lrc_txtype) {
case TX_REMOVE:
- error = VOP_REMOVE(ZTOV(dzp), name, kcred);
+ error = VOP_REMOVE(ZTOV(dzp), name, kcred, NULL, vflg);
break;
case TX_RMDIR:
- error = VOP_RMDIR(ZTOV(dzp), name, NULL, kcred);
+ error = VOP_RMDIR(ZTOV(dzp), name, NULL, kcred, NULL, vflg);
break;
default:
error = ENOTSUP;
@@ -170,6 +551,7 @@ zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
char *name = (char *)(lr + 1); /* name follows lr_link_t */
znode_t *dzp, *zp;
int error;
+ int vflg = 0;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
@@ -182,7 +564,10 @@ zfs_replay_link(zfsvfs_t *zfsvfs, lr_link_t *lr, boolean_t byteswap)
return (error);
}
- error = VOP_LINK(ZTOV(dzp), ZTOV(zp), name, kcred);
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
+ error = VOP_LINK(ZTOV(dzp), ZTOV(zp), name, kcred, NULL, vflg);
VN_RELE(ZTOV(zp));
VN_RELE(ZTOV(dzp));
@@ -197,6 +582,7 @@ zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, boolean_t byteswap)
char *tname = sname + strlen(sname) + 1;
znode_t *sdzp, *tdzp;
int error;
+ int vflg = 0;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
@@ -209,7 +595,11 @@ zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, boolean_t byteswap)
return (error);
}
- error = VOP_RENAME(ZTOV(sdzp), sname, ZTOV(tdzp), tname, kcred);
+ if (lr->lr_common.lrc_txtype & TX_CI)
+ vflg |= FIGNORECASE;
+
+ error = VOP_RENAME(ZTOV(sdzp), sname, ZTOV(tdzp), tname, kcred,
+ NULL, vflg);
VN_RELE(ZTOV(tdzp));
VN_RELE(ZTOV(sdzp));
@@ -286,12 +676,20 @@ static int
zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap)
{
znode_t *zp;
- vattr_t va;
+ xvattr_t xva;
+ vattr_t *vap = &xva.xva_vattr;
int error;
+ void *start;
- if (byteswap)
+ xva_init(&xva);
+ if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
+ if ((lr->lr_mask & AT_XVATTR) &&
+ zfsvfs->z_version >= ZPL_VERSION_INITIAL)
+ zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
+ }
+
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
/*
* As we can log setattrs out of order, it's possible the
@@ -303,33 +701,95 @@ zfs_replay_setattr(zfsvfs_t *zfsvfs, lr_setattr_t *lr, boolean_t byteswap)
return (error);
}
- zfs_init_vattr(&va, lr->lr_mask, lr->lr_mode,
+ zfs_init_vattr(vap, lr->lr_mask, lr->lr_mode,
lr->lr_uid, lr->lr_gid, 0, lr->lr_foid);
- va.va_size = lr->lr_size;
- ZFS_TIME_DECODE(&va.va_atime, lr->lr_atime);
- ZFS_TIME_DECODE(&va.va_mtime, lr->lr_mtime);
+ vap->va_size = lr->lr_size;
+ ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime);
+ ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime);
+
+ /*
+ * Fill in xvattr_t portions if necessary.
+ */
+
+ start = (lr_setattr_t *)(lr + 1);
+ if (vap->va_mask & AT_XVATTR) {
+ zfs_replay_xvattr((lr_attr_t *)start, &xva);
+ start = (caddr_t)start +
+ ZIL_XVAT_SIZE(((lr_attr_t *)start)->lr_attr_masksize);
+ } else
+ xva.xva_vattr.va_mask &= ~AT_XVATTR;
+
+ zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start,
+ lr->lr_uid, lr->lr_gid);
- error = VOP_SETATTR(ZTOV(zp), &va, 0, kcred, NULL);
+ error = VOP_SETATTR(ZTOV(zp), vap, 0, kcred, NULL);
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
VN_RELE(ZTOV(zp));
return (error);
}
static int
-zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
+zfs_replay_acl_v0(zfsvfs_t *zfsvfs, lr_acl_v0_t *lr, boolean_t byteswap)
{
ace_t *ace = (ace_t *)(lr + 1); /* ace array follows lr_acl_t */
vsecattr_t vsa;
znode_t *zp;
int error;
+ if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
+ /*
+ * As we can log acls out of order, it's possible the
+ * file has been removed. In this case just drop the acl
+ * and return success.
+ */
+ if (error == ENOENT)
+ error = 0;
+ return (error);
+ }
+
if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
- zfs_ace_byteswap(ace, lr->lr_aclcnt);
+ zfs_oldace_byteswap(ace, lr->lr_aclcnt);
}
+ bzero(&vsa, sizeof (vsa));
+ vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsa.vsa_aclcnt = lr->lr_aclcnt;
+ vsa.vsa_aclentp = ace;
+
+ error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);
+
+ VN_RELE(ZTOV(zp));
+
+ return (error);
+}
+
+/*
+ * Replaying ACLs is complicated by FUID support.
+ * The log record may contain some optional data
+ * to be used for replaying FUID's. These pieces
+ * are the actual FUIDs that were created initially.
+ * The FUID table index may no longer be valid and
+ * during zfs_create() a new index may be assigned.
+ * Because of this the log will contain the original
+ * doman+rid in order to create a new FUID.
+ *
+ * The individual ACEs may contain an ephemeral uid/gid which is no
+ * longer valid and will need to be replaced with an actual FUID.
+ *
+ */
+static int
+zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
+{
+ ace_t *ace = (ace_t *)(lr + 1);
+ vsecattr_t vsa;
+ znode_t *zp;
+ int error;
+
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
/*
* As we can log acls out of order, it's possible the
@@ -341,13 +801,36 @@ zfs_replay_acl(zfsvfs_t *zfsvfs, lr_acl_t *lr, boolean_t byteswap)
return (error);
}
+ if (byteswap) {
+ byteswap_uint64_array(lr, sizeof (*lr));
+ zfs_ace_byteswap(ace, lr->lr_acl_bytes, B_FALSE);
+ if (lr->lr_fuidcnt) {
+ byteswap_uint64_array((caddr_t)ace + lr->lr_acl_bytes,
+ lr->lr_fuidcnt * sizeof (uint64_t));
+ }
+ }
+
bzero(&vsa, sizeof (vsa));
- vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
+ vsa.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
vsa.vsa_aclcnt = lr->lr_aclcnt;
vsa.vsa_aclentp = ace;
+ vsa.vsa_aclentsz = lr->lr_acl_bytes;
+ vsa.vsa_aclflags = lr->lr_acl_flags;
+
+ if (lr->lr_fuidcnt) {
+ void *fuidstart = (caddr_t)ace + lr->lr_acl_bytes;
+
+ zfsvfs->z_fuid_replay =
+ zfs_replay_fuids(fuidstart, &fuidstart,
+ lr->lr_fuidcnt, lr->lr_domcnt, 0, 0);
+ }
+
+ error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred, NULL);
- error = VOP_SETSECATTR(ZTOV(zp), &vsa, 0, kcred);
+ if (zfsvfs->z_fuid_replay)
+ zfs_fuid_info_free(zfsvfs->z_fuid_replay);
+ zfsvfs->z_fuid_replay = NULL;
VN_RELE(ZTOV(zp));
return (error);
@@ -369,5 +852,12 @@ zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE] = {
zfs_replay_write, /* TX_WRITE */
zfs_replay_truncate, /* TX_TRUNCATE */
zfs_replay_setattr, /* TX_SETATTR */
+ zfs_replay_acl_v0, /* TX_ACL_V0 */
zfs_replay_acl, /* TX_ACL */
+ zfs_replay_create_acl, /* TX_CREATE_ACL */
+ zfs_replay_create, /* TX_CREATE_ATTR */
+ zfs_replay_create_acl, /* TX_CREATE_ACL_ATTR */
+ zfs_replay_create_acl, /* TX_MKDIR_ACL */
+ zfs_replay_create, /* TX_MKDIR_ATTR */
+ zfs_replay_create_acl, /* TX_MKDIR_ACL_ATTR */
};
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 0736cb3224..4106ca8f2f 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -40,6 +40,7 @@
#include "fs/fs_subr.h"
#include <sys/zfs_znode.h>
#include <sys/zfs_dir.h>
+#include <sys/zfs_i18n.h>
#include <sys/zil.h>
#include <sys/fs/zfs.h>
#include <sys/dmu.h>
@@ -56,6 +57,7 @@
#include <sys/refstr.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
#include <sys/bootconf.h>
#include <sys/sunddi.h>
#include <sys/dnlc.h>
@@ -329,6 +331,27 @@ exec_changed_cb(void *arg, uint64_t newval)
}
}
+/*
+ * The nbmand mount option can be changed at mount time.
+ * We can't allow it to be toggled on live file systems or incorrect
+ * behavior may be seen from cifs clients
+ *
+ * This property isn't registered via dsl_prop_register(), but this callback
+ * will be called when a file system is first mounted
+ */
+static void
+nbmand_changed_cb(void *arg, uint64_t newval)
+{
+ zfsvfs_t *zfsvfs = arg;
+ if (newval == FALSE) {
+ vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND);
+ vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND, NULL, 0);
+ } else {
+ vfs_clearmntopt(zfsvfs->z_vfs, MNTOPT_NONBMAND);
+ vfs_setmntopt(zfsvfs->z_vfs, MNTOPT_NBMAND, NULL, 0);
+ }
+}
+
static void
snapdir_changed_cb(void *arg, uint64_t newval)
{
@@ -338,6 +361,14 @@ snapdir_changed_cb(void *arg, uint64_t newval)
}
static void
+vscan_changed_cb(void *arg, uint64_t newval)
+{
+ zfsvfs_t *zfsvfs = arg;
+
+ zfsvfs->z_vscan = newval;
+}
+
+static void
acl_mode_changed_cb(void *arg, uint64_t newval)
{
zfsvfs_t *zfsvfs = arg;
@@ -354,17 +385,85 @@ acl_inherit_changed_cb(void *arg, uint64_t newval)
}
static int
+zfs_normalization_set(char *osname, zfsvfs_t *zfsvfs)
+{
+ uint64_t pval;
+ int error;
+
+ if (zfsvfs->z_version < ZPL_VERSION_FUID)
+ return (0);
+
+ error = dsl_prop_get_integer(osname, "normalization", &pval, NULL);
+ if (error)
+ goto normquit;
+ switch ((int)pval) {
+ case ZFS_NORMALIZE_NONE:
+ break;
+ case ZFS_NORMALIZE_C:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFC;
+ break;
+ case ZFS_NORMALIZE_KC:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFKC;
+ break;
+ case ZFS_NORMALIZE_D:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFD;
+ break;
+ case ZFS_NORMALIZE_KD:
+ zfsvfs->z_norm |= U8_TEXTPREP_NFKD;
+ break;
+ default:
+ ASSERT(pval <= ZFS_NORMALIZE_KD);
+ break;
+ }
+
+ error = dsl_prop_get_integer(osname, "utf8only", &pval, NULL);
+ if (error)
+ goto normquit;
+ if (pval)
+ zfsvfs->z_case |= ZFS_UTF8_ONLY;
+ else
+ zfsvfs->z_case &= ~ZFS_UTF8_ONLY;
+
+ error = dsl_prop_get_integer(osname, "casesensitivity", &pval, NULL);
+ if (error)
+ goto normquit;
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_DIRENTFLAGS);
+ switch ((int)pval) {
+ case ZFS_CASE_SENSITIVE:
+ break;
+ case ZFS_CASE_INSENSITIVE:
+ zfsvfs->z_norm |= U8_TEXTPREP_TOUPPER;
+ zfsvfs->z_case |= ZFS_CI_ONLY;
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_CASEINSENSITIVE);
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_NOCASESENSITIVE);
+ break;
+ case ZFS_CASE_MIXED:
+ zfsvfs->z_norm |= U8_TEXTPREP_TOUPPER;
+ zfsvfs->z_case |= ZFS_CI_MIXD;
+ vfs_set_feature(zfsvfs->z_vfs, VFSFT_CASEINSENSITIVE);
+ break;
+ default:
+ ASSERT(pval <= ZFS_CASE_MIXED);
+ break;
+ }
+
+normquit:
+ return (error);
+}
+
+static int
zfs_register_callbacks(vfs_t *vfsp)
{
struct dsl_dataset *ds = NULL;
objset_t *os = NULL;
zfsvfs_t *zfsvfs = NULL;
- int readonly, do_readonly = FALSE;
- int setuid, do_setuid = FALSE;
- int exec, do_exec = FALSE;
- int devices, do_devices = FALSE;
- int xattr, do_xattr = FALSE;
- int atime, do_atime = FALSE;
+ uint64_t nbmand;
+ int readonly, do_readonly = B_FALSE;
+ int setuid, do_setuid = B_FALSE;
+ int exec, do_exec = B_FALSE;
+ int devices, do_devices = B_FALSE;
+ int xattr, do_xattr = B_FALSE;
+ int atime, do_atime = B_FALSE;
int error = 0;
ASSERT(vfsp);
@@ -430,6 +529,26 @@ zfs_register_callbacks(vfs_t *vfsp)
}
/*
+ * nbmand is a special property. It can only be changed at
+ * mount time.
+ *
+ * This is weird, but it is documented to only be changeable
+ * at mount time.
+ */
+ if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) {
+ nbmand = B_FALSE;
+ } else if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) {
+ nbmand = B_TRUE;
+ } else {
+ char osname[MAXNAMELEN];
+
+ dmu_objset_name(os, osname);
+ if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand,
+ NULL))
+ return (error);
+ }
+
+ /*
* Register property callbacks.
*
* It would probably be fine to just check for i/o error from
@@ -456,6 +575,8 @@ zfs_register_callbacks(vfs_t *vfsp)
"aclmode", acl_mode_changed_cb, zfsvfs);
error = error ? error : dsl_prop_register(ds,
"aclinherit", acl_inherit_changed_cb, zfsvfs);
+ error = error ? error : dsl_prop_register(ds,
+ "vscan", vscan_changed_cb, zfsvfs);
if (error)
goto unregister;
@@ -475,6 +596,8 @@ zfs_register_callbacks(vfs_t *vfsp)
if (do_atime)
atime_changed_cb(zfsvfs, atime);
+ nbmand_changed_cb(zfsvfs, nbmand);
+
return (0);
unregister:
@@ -494,6 +617,7 @@ unregister:
(void) dsl_prop_unregister(ds, "aclmode", acl_mode_changed_cb, zfsvfs);
(void) dsl_prop_unregister(ds, "aclinherit", acl_inherit_changed_cb,
zfsvfs);
+ (void) dsl_prop_unregister(ds, "vscan", vscan_changed_cb, zfsvfs);
return (error);
}
@@ -643,15 +767,34 @@ zfs_domount(vfs_t *vfsp, char *osname, cred_t *cr)
/* The call to zfs_init_fs leaves the vnode held, release it here. */
VN_RELE(ZTOV(zp));
+ /*
+ * Set features for file system.
+ */
+ zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os);
+ if (zfsvfs->z_use_fuids) {
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
+ vfs_set_feature(vfsp, VFSFT_ACEMASKONACCESS);
+ vfs_set_feature(vfsp, VFSFT_ACLONCREATE);
+ }
+
+ /*
+ * Set normalization regardless of whether or not the object
+ * set is a snapshot. Snapshots and clones need to have
+ * identical normalization as did the file system they
+ * originated from.
+ */
+ if ((error = zfs_normalization_set(osname, zfsvfs)) != 0)
+ goto out;
+
if (dmu_objset_is_snapshot(zfsvfs->z_os)) {
- uint64_t xattr;
+ uint64_t pval;
ASSERT(mode & DS_MODE_READONLY);
atime_changed_cb(zfsvfs, B_FALSE);
readonly_changed_cb(zfsvfs, B_TRUE);
- if (error = dsl_prop_get_integer(osname, "xattr", &xattr, NULL))
+ if (error = dsl_prop_get_integer(osname, "xattr", &pval, NULL))
goto out;
- xattr_changed_cb(zfsvfs, xattr);
+ xattr_changed_cb(zfsvfs, pval);
zfsvfs->z_issnap = B_TRUE;
} else {
error = zfsvfs_setup(zfsvfs, B_TRUE);
@@ -715,6 +858,9 @@ zfs_unregister_callbacks(zfsvfs_t *zfsvfs)
VERIFY(dsl_prop_unregister(ds, "aclinherit",
acl_inherit_changed_cb, zfsvfs) == 0);
+
+ VERIFY(dsl_prop_unregister(ds, "vscan",
+ vscan_changed_cb, zfsvfs) == 0);
}
}
@@ -916,7 +1062,7 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
vattr.va_mask = AT_UID;
- if (error = VOP_GETATTR(mvp, &vattr, 0, cr)) {
+ if (error = VOP_GETATTR(mvp, &vattr, 0, cr, NULL)) {
goto out;
}
@@ -924,7 +1070,7 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
goto out;
}
- if (error = VOP_ACCESS(mvp, VWRITE, 0, cr)) {
+ if (error = VOP_ACCESS(mvp, VWRITE, 0, cr, NULL)) {
goto out;
}
@@ -1301,7 +1447,7 @@ zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
ASSERT(*vpp != NULL);
if (object == ZFSCTL_INO_SNAPDIR) {
VERIFY(zfsctl_root_lookup(*vpp, "snapshot", vpp, NULL,
- 0, NULL, NULL) == 0);
+ 0, NULL, NULL, NULL, NULL, NULL) == 0);
} else {
VN_HOLD(*vpp);
}
@@ -1415,6 +1561,7 @@ zfs_freevfs(vfs_t *vfsp)
list_destroy(&zfsvfs->z_all_znodes);
rrw_destroy(&zfsvfs->z_teardown_lock);
rw_destroy(&zfsvfs->z_teardown_inactive_lock);
+ zfs_fuid_destroy(zfsvfs);
kmem_free(zfsvfs, sizeof (zfsvfs_t));
atomic_add_32(&zfs_active_fs_count, -1);
@@ -1553,7 +1700,8 @@ static vfsdef_t vfw = {
VFSDEF_VERSION,
MNTTYPE_ZFS,
zfs_vfsinit,
- VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS,
+ VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS|
+ VSW_XID,
&zfs_mntopts
};
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 2e6405be7a..573f746e72 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -56,6 +56,7 @@
#include <sys/zfs_dir.h>
#include <sys/zfs_acl.h>
#include <sys/zfs_ioctl.h>
+#include <sys/zfs_i18n.h>
#include <sys/fs/zfs.h>
#include <sys/dmu.h>
#include <sys/spa.h>
@@ -68,8 +69,12 @@
#include <sys/filio.h>
#include "fs/fs_subr.h"
#include <sys/zfs_ctldir.h>
+#include <sys/zfs_fuid.h>
#include <sys/dnlc.h>
#include <sys/zfs_rlock.h>
+#include <sys/extdirent.h>
+#include <sys/kidmap.h>
+#include <sys/cred_impl.h>
/*
* Programming rules.
@@ -77,8 +82,8 @@
* Each vnode op performs some logical unit of work. To do this, the ZPL must
* properly lock its in-core state, create a DMU transaction, do the work,
* record this work in the intent log (ZIL), commit the DMU transaction,
- * and wait the the intent log to commit if it's is a synchronous operation.
- * Morover, the vnode ops must work in both normal and log replay context.
+ * and wait for the intent log to commit if it is a synchronous operation.
+ * Moreover, the vnode ops must work in both normal and log replay context.
* The ordering of events is important to avoid deadlocks and references
* to freed memory. The example below illustrates the following Big Rules:
*
@@ -160,19 +165,33 @@
*/
/* ARGSUSED */
static int
-zfs_open(vnode_t **vpp, int flag, cred_t *cr)
+zfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(*vpp);
+ if ((flag & FWRITE) && (zp->z_phys->zp_flags & ZFS_APPENDONLY) &&
+ ((flag & FAPPEND) == 0)) {
+ return (EPERM);
+ }
+
+ if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan &&
+ ZTOV(zp)->v_type == VREG &&
+ !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) &&
+ zp->z_phys->zp_size > 0)
+ if (fs_vscan(*vpp, cr, 0) != 0)
+ return (EACCES);
+
/* Keep a count of the synchronous opens in the znode */
if (flag & (FSYNC | FDSYNC))
atomic_inc_32(&zp->z_sync_cnt);
+
return (0);
}
/* ARGSUSED */
static int
-zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
+zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
@@ -186,6 +205,12 @@ zfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr)
cleanlocks(vp, ddi_get_pid(), 0);
cleanshares(vp, ddi_get_pid());
+ if (!zfs_has_ctldir(zp) && zp->z_zfsvfs->z_vscan &&
+ ZTOV(zp)->v_type == VREG &&
+ !(zp->z_phys->zp_flags & ZFS_AV_QUARANTINED) &&
+ zp->z_phys->zp_size > 0)
+ VERIFY(fs_vscan(vp, cr, 1) == 0);
+
return (0);
}
@@ -235,7 +260,7 @@ zfs_holey(vnode_t *vp, int cmd, offset_t *off)
/* ARGSUSED */
static int
zfs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
- int *rvalp)
+ int *rvalp, caller_context_t *ct)
{
offset_t off;
int error;
@@ -386,6 +411,7 @@ offset_t zfs_read_chunk_size = 1024 * 1024; /* Tunable */
* and return buffer.
* ioflag - SYNC flags; used to provide FRSYNC semantics.
* cr - credentials of caller.
+ * ct - caller context
*
* OUT: uio - updated offset and range, buffer filled.
*
@@ -552,6 +578,7 @@ zfs_prefault_write(ssize_t n, struct uio *uio)
* and data buffer.
* ioflag - FAPPEND flag set if in append mode.
* cr - credentials of caller.
+ * ct - caller context (NFS/CIFS fem monitor only)
*
* OUT: uio - updated offset and range.
*
@@ -577,9 +604,18 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
ssize_t n, nbytes;
rl_t *rl;
int max_blksz = zfsvfs->z_max_blksz;
+ uint64_t pflags = zp->z_phys->zp_flags;
int error;
/*
+ * If immutable or not appending then return EPERM
+ */
+ if ((pflags & (ZFS_IMMUTABLE | ZFS_READONLY)) ||
+ ((pflags & ZFS_APPENDONLY) && !(ioflag & FAPPEND) &&
+ (uio->uio_loffset < zp->z_phys->zp_size)))
+ return (EPERM);
+
+ /*
* Fasttrack empty write
*/
n = start_resid;
@@ -734,6 +770,9 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
* It would be nice to to this after all writes have
* been done, but that would still expose the ISUID/ISGID
* to another app after the partial write is committed.
+ *
+ * Note: we don't call zfs_fuid_map_id() here because
+ * user 0 is not an ephemeral uid.
*/
mutex_enter(&zp->z_acl_lock);
if ((zp->z_phys->zp_mode & (S_IXUSR | (S_IXUSR >> 3) |
@@ -905,14 +944,20 @@ out:
/*ARGSUSED*/
static int
-zfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
+zfs_access(vnode_t *vp, int mode, int flag, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- error = zfs_zaccess_rwx(zp, mode, cr);
+
+ if (flag & V_ACE_MASK)
+ error = zfs_zaccess(zp, mode, flag, B_FALSE, cr);
+ else
+ error = zfs_zaccess_rwx(zp, mode, flag, cr);
+
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -927,6 +972,9 @@ zfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
* flags - LOOKUP_XATTR set if looking for an attribute.
* rdir - root directory vnode [UNUSED].
* cr - credentials of caller.
+ * ct - caller context
+ * direntflags - directory lookup flags
+ * realpnp - returned pathname.
*
* OUT: vpp - vnode of located entry, NULL if not found.
*
@@ -939,9 +987,9 @@ zfs_access(vnode_t *vp, int mode, int flags, cred_t *cr)
/* ARGSUSED */
static int
zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
- int flags, vnode_t *rdir, cred_t *cr)
+ int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp)
{
-
znode_t *zdp = VTOZ(dvp);
zfsvfs_t *zfsvfs = zdp->z_zfsvfs;
int error;
@@ -977,8 +1025,10 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* Do we have permission to get into attribute directory?
*/
- if (error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, cr)) {
+ if (error = zfs_zaccess(VTOZ(*vpp), ACE_EXECUTE, 0,
+ B_FALSE, cr)) {
VN_RELE(*vpp);
+ *vpp = NULL;
}
ZFS_EXIT(zfsvfs);
@@ -994,13 +1044,19 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* Check accessibility of directory.
*/
- if (error = zfs_zaccess(zdp, ACE_EXECUTE, cr)) {
+ if (error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr)) {
ZFS_EXIT(zfsvfs);
return (error);
}
- if ((error = zfs_dirlook(zdp, nm, vpp)) == 0) {
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(nm, strlen(nm),
+ NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ error = zfs_dirlook(zdp, nm, vpp, flags, direntflags, realpnp);
+ if (error == 0) {
/*
* Convert device special files
*/
@@ -1032,6 +1088,8 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* mode - mode to open file with.
* cr - credentials of caller.
* flag - large file flag [UNUSED].
+ * ct - caller context
+ * vsecp - ACL to be set
*
* OUT: vpp - vnode of created or trunc'd entry.
*
@@ -1042,10 +1100,12 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
* dvp - ctime|mtime updated if new entry created
* vp - ctime|mtime always, atime if new
*/
+
/* ARGSUSED */
static int
zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
- int mode, vnode_t **vpp, cred_t *cr, int flag)
+ int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
+ vsecattr_t *vsecp)
{
znode_t *zp, *dzp = VTOZ(dvp);
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
@@ -1055,11 +1115,36 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
dmu_tx_t *tx;
int error;
uint64_t zoid;
+ zfs_acl_t *aclp = NULL;
+ zfs_fuid_info_t *fuidp = NULL;
+
+ /*
+ * If we have an ephemeral id, ACL, or XVATTR then
+ * make sure file system is at proper version
+ */
+
+ if (zfsvfs->z_use_fuids == B_FALSE &&
+ (vsecp || (vap->va_mask & AT_XVATTR) ||
+ IS_EPHEMERAL(crgetuid(cr)) || IS_EPHEMERAL(crgetgid(cr))))
+ return (EINVAL);
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
os = zfsvfs->z_os;
zilog = zfsvfs->z_log;
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(name, strlen(name),
+ NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+
+ if (vap->va_mask & AT_XVATTR) {
+ if ((error = secpolicy_xvattr((xvattr_t *)vap,
+ crgetuid(cr), cr, vap->va_type)) != 0) {
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
+ }
top:
*vpp = NULL;
@@ -1076,22 +1161,41 @@ top:
error = 0;
} else {
/* possible VN_HOLD(zp) */
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, 0)) {
+ int zflg = 0;
+
+ if (flag & FIGNORECASE)
+ zflg |= ZCILOOK;
+
+ error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+ NULL, NULL);
+ if (error) {
if (strcmp(name, "..") == 0)
error = EISDIR;
ZFS_EXIT(zfsvfs);
+ if (aclp)
+ zfs_acl_free(aclp);
+ return (error);
+ }
+ }
+ if (vsecp && aclp == NULL) {
+ error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, &aclp);
+ if (error) {
+ ZFS_EXIT(zfsvfs);
+ if (dl)
+ zfs_dirent_unlock(dl);
return (error);
}
}
-
zoid = zp ? zp->z_id : -1ULL;
if (zp == NULL) {
+ uint64_t txtype;
+
/*
* Create a new file object and update the directory
* to reference it.
*/
- if (error = zfs_zaccess(dzp, ACE_ADD_FILE, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
goto out;
}
@@ -1107,11 +1211,22 @@ top:
tx = dmu_tx_create(os);
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
dmu_tx_hold_bonus(tx, dzp->z_id);
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
- if (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)
+ if ((dzp->z_phys->zp_flags & ZFS_INHERIT_ACE) || aclp) {
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
0, SPA_MAXBLOCKSIZE);
+ }
error = dmu_tx_assign(tx, zfsvfs->z_assign);
if (error) {
zfs_dirent_unlock(dl);
@@ -1123,14 +1238,24 @@ top:
}
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
+ if (aclp)
+ zfs_acl_free(aclp);
return (error);
}
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0);
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0, aclp, &fuidp);
ASSERT(zp->z_id == zoid);
(void) zfs_link_create(dl, zp, tx, ZNEW);
- zfs_log_create(zilog, tx, TX_CREATE, dzp, zp, name);
+ txtype = zfs_log_create_txtype(Z_FILE, vsecp, vap);
+ if (flag & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_create(zilog, tx, txtype, dzp, zp, name,
+ vsecp, fuidp, vap);
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
} else {
+ int aflags = (flag & FAPPEND) ? V_APPEND : 0;
+
/*
* A directory entry already exists for this name.
*/
@@ -1151,7 +1276,7 @@ top:
/*
* Verify requested access to file.
*/
- if (mode && (error = zfs_zaccess_rwx(zp, mode, cr))) {
+ if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) {
goto out;
}
@@ -1174,7 +1299,7 @@ top:
}
if (error == 0) {
- vnevent_create(ZTOV(zp));
+ vnevent_create(ZTOV(zp), ct);
}
}
}
@@ -1202,6 +1327,8 @@ out:
*vpp = svp;
}
}
+ if (aclp)
+ zfs_acl_free(aclp);
ZFS_EXIT(zfsvfs);
return (error);
@@ -1213,6 +1340,8 @@ out:
* IN: dvp - vnode of directory to remove entry from.
* name - name of entry to remove.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -1221,8 +1350,10 @@ out:
* dvp - ctime|mtime
* vp - ctime (if nlink > 0)
*/
+/*ARGSUSED*/
static int
-zfs_remove(vnode_t *dvp, char *name, cred_t *cr)
+zfs_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
+ int flags)
{
znode_t *zp, *dzp = VTOZ(dvp);
znode_t *xzp = NULL;
@@ -1234,16 +1365,29 @@ zfs_remove(vnode_t *dvp, char *name, cred_t *cr)
dmu_tx_t *tx;
boolean_t may_delete_now, delete_now = FALSE;
boolean_t unlinked;
+ uint64_t txtype;
+ pathname_t *realnmp = NULL;
+ pathname_t realnm;
int error;
+ int zflg = ZEXISTS;
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
+ if (flags & FIGNORECASE) {
+ zflg |= ZCILOOK;
+ pn_alloc(&realnm);
+ realnmp = &realnm;
+ }
+
top:
/*
* Attempt to lock directory; fail if entry doesn't exist.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, ZEXISTS)) {
+ if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+ NULL, realnmp)) {
+ if (realnmp)
+ pn_free(realnmp);
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -1262,9 +1406,12 @@ top:
goto out;
}
- vnevent_remove(vp, dvp, name);
+ vnevent_remove(vp, dvp, name, ct);
- dnlc_remove(dvp, name);
+ if (realnmp)
+ dnlc_remove(dvp, realnmp->pn_path);
+ else
+ dnlc_remove(dvp, name);
mutex_enter(&vp->v_lock);
may_delete_now = vp->v_count == 1 && !vn_has_cached_data(vp);
@@ -1305,6 +1452,8 @@ top:
dmu_tx_abort(tx);
goto top;
}
+ if (realnmp)
+ pn_free(realnmp);
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
return (error);
@@ -1313,7 +1462,7 @@ top:
/*
* Remove the directory entry.
*/
- error = zfs_link_destroy(dl, zp, tx, 0, &unlinked);
+ error = zfs_link_destroy(dl, zp, tx, zflg, &unlinked);
if (error) {
dmu_tx_commit(tx);
@@ -1354,10 +1503,16 @@ top:
zfs_unlinked_add(zp, tx);
}
- zfs_log_remove(zilog, tx, TX_REMOVE, dzp, name);
+ txtype = TX_REMOVE;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_remove(zilog, tx, txtype, dzp, name);
dmu_tx_commit(tx);
out:
+ if (realnmp)
+ pn_free(realnmp);
+
zfs_dirent_unlock(dl);
if (!delete_now) {
@@ -1379,6 +1534,8 @@ out:
* dirname - name of new directory.
* vap - attributes of new directory.
* cr - credentials of caller.
+ * ct - caller context
+ * vsecp - ACL to be set
*
* OUT: vpp - vnode of created directory.
*
@@ -1389,19 +1546,35 @@ out:
* dvp - ctime|mtime updated
* vp - ctime|mtime|atime updated
*/
+/*ARGSUSED*/
static int
-zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr)
+zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr,
+ caller_context_t *ct, int flags, vsecattr_t *vsecp)
{
znode_t *zp, *dzp = VTOZ(dvp);
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
zilog_t *zilog;
zfs_dirlock_t *dl;
uint64_t zoid = 0;
+ uint64_t txtype;
dmu_tx_t *tx;
int error;
+ zfs_acl_t *aclp = NULL;
+ zfs_fuid_info_t *fuidp = NULL;
+ int zf = ZNEW;
ASSERT(vap->va_type == VDIR);
+ /*
+ * If we have an ephemeral id, ACL, or XVATTR then
+ * make sure file system is at proper version
+ */
+
+ if (zfsvfs->z_use_fuids == B_FALSE &&
+ (vsecp || (vap->va_mask & AT_XVATTR) || IS_EPHEMERAL(crgetuid(cr))||
+ IS_EPHEMERAL(crgetgid(cr))))
+ return (EINVAL);
+
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
@@ -1409,30 +1582,65 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr)
ZFS_EXIT(zfsvfs);
return (EINVAL);
}
-top:
- *vpp = NULL;
+
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(dirname,
+ strlen(dirname), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ if (flags & FIGNORECASE)
+ zf |= ZCILOOK;
+
+ if (vap->va_mask & AT_XVATTR)
+ if ((error = secpolicy_xvattr((xvattr_t *)vap,
+ crgetuid(cr), cr, vap->va_type)) != 0) {
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
/*
* First make sure the new directory doesn't exist.
*/
- if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, ZNEW)) {
+top:
+ *vpp = NULL;
+
+ if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf,
+ NULL, NULL)) {
ZFS_EXIT(zfsvfs);
return (error);
}
- if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) {
zfs_dirent_unlock(dl);
ZFS_EXIT(zfsvfs);
return (error);
}
+ if (vsecp && aclp == NULL) {
+ error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, &aclp);
+ if (error) {
+ zfs_dirent_unlock(dl);
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
+ }
/*
* Add a new entry to the directory.
*/
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname);
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
- if (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
+ if ((dzp->z_phys->zp_flags & ZFS_INHERIT_ACE) || aclp)
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
0, SPA_MAXBLOCKSIZE);
error = dmu_tx_assign(tx, zfsvfs->z_assign);
@@ -1445,13 +1653,18 @@ top:
}
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
+ if (aclp)
+ zfs_acl_free(aclp);
return (error);
}
/*
* Create new node.
*/
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0);
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0, aclp, &fuidp);
+
+ if (aclp)
+ zfs_acl_free(aclp);
/*
* Now put new name in parent dir.
@@ -1460,7 +1673,13 @@ top:
*vpp = ZTOV(zp);
- zfs_log_create(zilog, tx, TX_MKDIR, dzp, zp, dirname);
+ txtype = zfs_log_create_txtype(Z_DIR, vsecp, vap);
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_create(zilog, tx, txtype, dzp, zp, dirname, vsecp, fuidp, vap);
+
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
zfs_dirent_unlock(dl);
@@ -1478,6 +1697,8 @@ top:
* name - name of directory to be removed.
* cwd - vnode of current working directory.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -1485,8 +1706,10 @@ top:
* Timestamps:
* dvp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
+zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *dzp = VTOZ(dvp);
znode_t *zp;
@@ -1496,17 +1719,21 @@ zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
zfs_dirlock_t *dl;
dmu_tx_t *tx;
int error;
+ int zflg = ZEXISTS;
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
+ if (flags & FIGNORECASE)
+ zflg |= ZCILOOK;
top:
zp = NULL;
/*
* Attempt to lock directory; fail if entry doesn't exist.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, ZEXISTS)) {
+ if (error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
+ NULL, NULL)) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -1527,7 +1754,7 @@ top:
goto out;
}
- vnevent_rmdir(vp, dvp, name);
+ vnevent_rmdir(vp, dvp, name, ct);
/*
* Grab a lock on the directory to make sure that noone is
@@ -1561,10 +1788,14 @@ top:
return (error);
}
- error = zfs_link_destroy(dl, zp, tx, 0, NULL);
+ error = zfs_link_destroy(dl, zp, tx, zflg, NULL);
- if (error == 0)
- zfs_log_remove(zilog, tx, TX_RMDIR, dzp, name);
+ if (error == 0) {
+ uint64_t txtype = TX_RMDIR;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_remove(zilog, tx, txtype, dzp, name);
+ }
dmu_tx_commit(tx);
@@ -1588,6 +1819,8 @@ out:
* uio - structure supplying read location, range info,
* and return buffer.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* OUT: uio - updated offset and range, buffer filled.
* eofp - set to true if end-of-file detected.
@@ -1605,10 +1838,12 @@ out:
*/
/* ARGSUSED */
static int
-zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
+zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags)
{
znode_t *zp = VTOZ(vp);
iovec_t *iovp;
+ edirent_t *eodp;
dirent64_t *odp;
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
objset_t *os;
@@ -1681,6 +1916,7 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
bufsize = bytes_wanted;
odp = (struct dirent64 *)iovp->iov_base;
}
+ eodp = (struct edirent *)odp;
/*
* Transform to file-system independent format
@@ -1696,12 +1932,15 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
*/
if (offset == 0) {
(void) strcpy(zap.za_name, ".");
+ zap.za_normalization_conflict = 0;
objnum = zp->z_id;
} else if (offset == 1) {
(void) strcpy(zap.za_name, "..");
+ zap.za_normalization_conflict = 0;
objnum = zp->z_phys->zp_parent;
} else if (offset == 2 && zfs_show_ctldir(zp)) {
(void) strcpy(zap.za_name, ZFS_CTLDIR_NAME);
+ zap.za_normalization_conflict = 0;
objnum = ZFSCTL_INO_ROOT;
} else {
/*
@@ -1730,7 +1969,11 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
* uint8_t type = ZFS_DIRENT_TYPE(zap.za_first_integer);
*/
}
- reclen = DIRENT64_RECLEN(strlen(zap.za_name));
+
+ if (flags & V_RDDIR_ENTFLAGS)
+ reclen = EDIRENT_RECLEN(strlen(zap.za_name));
+ else
+ reclen = DIRENT64_RECLEN(strlen(zap.za_name));
/*
* Will this entry fit in the buffer?
@@ -1745,17 +1988,32 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp)
}
break;
}
- /*
- * Add this entry:
- */
- odp->d_ino = objnum;
- odp->d_reclen = reclen;
- /* NOTE: d_off is the offset for the *next* entry */
- next = &(odp->d_off);
- (void) strncpy(odp->d_name, zap.za_name,
- DIRENT64_NAMELEN(reclen));
+ if (flags & V_RDDIR_ENTFLAGS) {
+ /*
+ * Add extended flag entry:
+ */
+ eodp->ed_ino = objnum;
+ eodp->ed_reclen = reclen;
+ /* NOTE: ed_off is the offset for the *next* entry */
+ next = &(eodp->ed_off);
+ eodp->ed_eflags = zap.za_normalization_conflict ?
+ ED_CASE_CONFLICT : 0;
+ (void) strncpy(eodp->ed_name, zap.za_name,
+ EDIRENT_NAMELEN(reclen));
+ eodp = (edirent_t *)((intptr_t)eodp + reclen);
+ } else {
+ /*
+ * Add normal entry:
+ */
+ odp->d_ino = objnum;
+ odp->d_reclen = reclen;
+ /* NOTE: d_off is the offset for the *next* entry */
+ next = &(odp->d_off);
+ (void) strncpy(odp->d_name, zap.za_name,
+ DIRENT64_NAMELEN(reclen));
+ odp = (dirent64_t *)((intptr_t)odp + reclen);
+ }
outcount += reclen;
- odp = (dirent64_t *)((intptr_t)odp + reclen);
ASSERT(outcount <= bufsize);
@@ -1805,7 +2063,7 @@ update:
ulong_t zfs_fsync_sync_cnt = 4;
static int
-zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
+zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -1818,7 +2076,7 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
*/
if (vn_has_cached_data(vp) && !(syncflag & FNODSYNC) &&
(vp->v_type == VREG) && !(IS_SWAPVP(vp)))
- (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_ASYNC, cr, ct);
(void) tsd_set(zfs_fsyncer_key, (void *)zfs_fsync_sync_cnt);
@@ -1828,14 +2086,17 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
return (0);
}
+
/*
* Get the requested file attributes and place them in the provided
* vattr structure.
*
* IN: vp - vnode of file.
* vap - va_mask identifies requested attributes.
- * flags - [UNUSED]
+ * If AT_XVATTR set, then optional attrs are requested
+ * flags - ATTR_NOACLCHECK (CIFS server context)
* cr - credentials of caller.
+ * ct - caller context
*
* OUT: vap - attribute values.
*
@@ -1843,27 +2104,46 @@ zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
+zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
znode_phys_t *pzp;
- int error;
+ int error = 0;
uint64_t links;
+ xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */
+ xoptattr_t *xoap = NULL;
+ boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
pzp = zp->z_phys;
+ mutex_enter(&zp->z_lock);
+
+ /*
+ * If ACL is trivial don't bother looking for ACE_READ_ATTRIBUTES.
+ * Also, if we are the owner don't bother, since owner should
+ * always be allowed to read basic attributes of file.
+ */
+ if (!(pzp->zp_flags & ZFS_ACL_TRIVIAL) &&
+ (pzp->zp_uid != crgetuid(cr))) {
+ if (error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0,
+ skipaclchk, cr)) {
+ mutex_exit(&zp->z_lock);
+ ZFS_EXIT(zfsvfs);
+ return (error);
+ }
+ }
+
/*
* Return all attributes. It's cheaper to provide the answer
* than to determine whether we were asked the question.
*/
- mutex_enter(&zp->z_lock);
vap->va_type = vp->v_type;
vap->va_mode = pzp->zp_mode & MODEMASK;
- vap->va_uid = zp->z_phys->zp_uid;
- vap->va_gid = zp->z_phys->zp_gid;
+ zfs_fuid_map_ids(zp, &vap->va_uid, &vap->va_gid);
vap->va_fsid = zp->z_zfsvfs->z_vfs->vfs_dev;
vap->va_nodeid = zp->z_id;
if ((vp->v_flag & VROOT) && zfs_show_ctldir(zp))
@@ -1875,24 +2155,113 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
vap->va_rdev = vp->v_rdev;
vap->va_seq = zp->z_seq;
- ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime);
- ZFS_TIME_DECODE(&vap->va_mtime, pzp->zp_mtime);
- ZFS_TIME_DECODE(&vap->va_ctime, pzp->zp_ctime);
-
/*
- * If ACL is trivial don't bother looking for ACE_READ_ATTRIBUTES.
- * Also, if we are the owner don't bother, since owner should
- * always be allowed to read basic attributes of file.
+ * Add in any requested optional attributes and the create time.
+ * Also set the corresponding bits in the returned attribute bitmap.
*/
- if (!(zp->z_phys->zp_flags & ZFS_ACL_TRIVIAL) &&
- (zp->z_phys->zp_uid != crgetuid(cr))) {
- if (error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, cr)) {
- mutex_exit(&zp->z_lock);
- ZFS_EXIT(zfsvfs);
- return (error);
+ if ((xoap = xva_getxoptattr(xvap)) != NULL && zfsvfs->z_use_fuids) {
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+ xoap->xoa_archive =
+ ((pzp->zp_flags & ZFS_ARCHIVE) != 0);
+ XVA_SET_RTN(xvap, XAT_ARCHIVE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+ xoap->xoa_readonly =
+ ((pzp->zp_flags & ZFS_READONLY) != 0);
+ XVA_SET_RTN(xvap, XAT_READONLY);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+ xoap->xoa_system =
+ ((pzp->zp_flags & ZFS_SYSTEM) != 0);
+ XVA_SET_RTN(xvap, XAT_SYSTEM);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+ xoap->xoa_hidden =
+ ((pzp->zp_flags & ZFS_HIDDEN) != 0);
+ XVA_SET_RTN(xvap, XAT_HIDDEN);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+ xoap->xoa_nounlink =
+ ((pzp->zp_flags & ZFS_NOUNLINK) != 0);
+ XVA_SET_RTN(xvap, XAT_NOUNLINK);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+ xoap->xoa_immutable =
+ ((pzp->zp_flags & ZFS_IMMUTABLE) != 0);
+ XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+ xoap->xoa_appendonly =
+ ((pzp->zp_flags & ZFS_APPENDONLY) != 0);
+ XVA_SET_RTN(xvap, XAT_APPENDONLY);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+ xoap->xoa_nodump =
+ ((pzp->zp_flags & ZFS_NODUMP) != 0);
+ XVA_SET_RTN(xvap, XAT_NODUMP);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+ xoap->xoa_opaque =
+ ((pzp->zp_flags & ZFS_OPAQUE) != 0);
+ XVA_SET_RTN(xvap, XAT_OPAQUE);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ xoap->xoa_av_quarantined =
+ ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0);
+ XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+ xoap->xoa_av_modified =
+ ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0);
+ XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP) &&
+ vp->v_type == VREG &&
+ (pzp->zp_flags & ZFS_BONUS_SCANSTAMP)) {
+ size_t len;
+ dmu_object_info_t doi;
+
+ /*
+ * Only VREG files have anti-virus scanstamps, so we
+ * won't conflict with symlinks in the bonus buffer.
+ */
+ dmu_object_info_from_db(zp->z_dbuf, &doi);
+ len = sizeof (xoap->xoa_av_scanstamp) +
+ sizeof (znode_phys_t);
+ if (len <= doi.doi_bonus_size) {
+ /*
+ * pzp points to the start of the
+ * znode_phys_t. pzp + 1 points to the
+ * first byte after the znode_phys_t.
+ */
+ (void) memcpy(xoap->xoa_av_scanstamp,
+ pzp + 1,
+ sizeof (xoap->xoa_av_scanstamp));
+ XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
+ }
+ }
+
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ ZFS_TIME_DECODE(&xoap->xoa_createtime, pzp->zp_crtime);
+ XVA_SET_RTN(xvap, XAT_CREATETIME);
}
}
+ ZFS_TIME_DECODE(&vap->va_atime, pzp->zp_atime);
+ ZFS_TIME_DECODE(&vap->va_mtime, pzp->zp_mtime);
+ ZFS_TIME_DECODE(&vap->va_ctime, pzp->zp_ctime);
+
mutex_exit(&zp->z_lock);
dmu_object_size_from_db(zp->z_dbuf, &vap->va_blksize, &vap->va_nblocks);
@@ -1914,8 +2283,11 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
*
* IN: vp - vnode of file to be modified.
* vap - new attribute values.
+ * If AT_XVATTR set, then optional attrs are being set
* flags - ATTR_UTIME set if non-default time values provided.
+ * - ATTR_NOACLCHECK (CIFS context only).
* cr - credentials of caller.
+ * ct - caller context
*
* RETURN: 0 if success
* error code if failure
@@ -1941,6 +2313,10 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
znode_t *attrzp;
int need_policy = FALSE;
int err;
+ zfs_fuid_info_t *fuidp = NULL;
+ xvattr_t *xvap = (xvattr_t *)vap; /* vap may be an xvattr_t * */
+ xoptattr_t *xoap;
+ boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
if (mask == 0)
return (0);
@@ -1948,15 +2324,44 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
if (mask & AT_NOSET)
return (EINVAL);
+ ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
+
+ pzp = zp->z_phys;
+ zilog = zfsvfs->z_log;
+
+ /*
+ * Make sure that if we have ephemeral uid/gid or xvattr specified
+ * that file system is at proper version level
+ */
+
+ if (zfsvfs->z_use_fuids == B_FALSE &&
+ (((mask & AT_UID) && IS_EPHEMERAL(vap->va_uid)) ||
+ ((mask & AT_GID) && IS_EPHEMERAL(vap->va_gid)) ||
+ (mask & AT_XVATTR)))
+ return (EINVAL);
+
if (mask & AT_SIZE && vp->v_type == VDIR)
return (EISDIR);
if (mask & AT_SIZE && vp->v_type != VREG && vp->v_type != VFIFO)
return (EINVAL);
- ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- pzp = zp->z_phys;
- zilog = zfsvfs->z_log;
+ /*
+ * If this is an xvattr_t, then get a pointer to the structure of
+ * optional attributes. If this is NULL, then we have a vattr_t.
+ */
+ xoap = xva_getxoptattr(xvap);
+
+ /*
+ * Immutable files can only alter immutable bit and atime
+ */
+ if ((pzp->zp_flags & ZFS_IMMUTABLE) &&
+ ((mask & (AT_SIZE|AT_UID|AT_GID|AT_MTIME|AT_MODE)) ||
+ ((mask & AT_XVATTR) && XVA_ISSET_REQ(xvap, XAT_CREATETIME))))
+ return (EPERM);
+
+ if ((mask & AT_SIZE) && (pzp->zp_flags & ZFS_READONLY))
+ return (EPERM);
top:
attrzp = NULL;
@@ -1971,7 +2376,7 @@ top:
*/
if (mask & AT_SIZE) {
- err = zfs_zaccess(zp, ACE_WRITE_DATA, cr);
+ err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr);
if (err) {
ZFS_EXIT(zfsvfs);
return (err);
@@ -1992,8 +2397,14 @@ top:
}
}
- if (mask & (AT_ATIME|AT_MTIME))
- need_policy = zfs_zaccess_v4_perm(zp, ACE_WRITE_ATTRIBUTES, cr);
+ if (mask & (AT_ATIME|AT_MTIME) ||
+ ((mask & AT_XVATTR) && (XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
+ XVA_ISSET_REQ(xvap, XAT_READONLY) ||
+ XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+ XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
+ XVA_ISSET_REQ(xvap, XAT_SYSTEM))))
+ need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0,
+ skipaclchk, cr);
if (mask & (AT_UID|AT_GID)) {
int idmask = (mask & (AT_UID|AT_GID));
@@ -2013,7 +2424,8 @@ top:
*/
take_owner = (mask & AT_UID) && (vap->va_uid == crgetuid(cr));
- take_group = (mask & AT_GID) && groupmember(vap->va_gid, cr);
+ take_group = (mask & AT_GID) &&
+ zfs_groupmember(zfsvfs, vap->va_gid, cr);
/*
* If both AT_UID and AT_GID are set then take_owner and
@@ -2027,7 +2439,8 @@ top:
if (((idmask == (AT_UID|AT_GID)) && take_owner && take_group) ||
((idmask == AT_UID) && take_owner) ||
((idmask == AT_GID) && take_group)) {
- if (zfs_zaccess_v4_perm(zp, ACE_WRITE_OWNER, cr) == 0) {
+ if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0,
+ skipaclchk, cr) == 0) {
/*
* Remove setuid/setgid for non-privileged users
*/
@@ -2043,12 +2456,37 @@ top:
mutex_enter(&zp->z_lock);
oldva.va_mode = pzp->zp_mode;
- oldva.va_uid = zp->z_phys->zp_uid;
- oldva.va_gid = zp->z_phys->zp_gid;
+ zfs_fuid_map_ids(zp, &oldva.va_uid, &oldva.va_gid);
+ if (mask & AT_XVATTR) {
+ if ((need_policy == FALSE) &&
+ (XVA_ISSET_REQ(xvap, XAT_APPENDONLY) &&
+ xoap->xoa_appendonly !=
+ ((pzp->zp_flags & ZFS_APPENDONLY) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_NOUNLINK) &&
+ xoap->xoa_nounlink !=
+ ((pzp->zp_flags & ZFS_NOUNLINK) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE) &&
+ xoap->xoa_immutable !=
+ ((pzp->zp_flags & ZFS_IMMUTABLE) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_NODUMP) &&
+ xoap->xoa_nodump !=
+ ((pzp->zp_flags & ZFS_NODUMP) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED) &&
+ xoap->xoa_av_modified !=
+ ((pzp->zp_flags & ZFS_AV_MODIFIED) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED) &&
+ xoap->xoa_av_quarantined !=
+ ((pzp->zp_flags & ZFS_AV_QUARANTINED) != 0)) ||
+ (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) ||
+ (XVA_ISSET_REQ(xvap, XAT_OPAQUE))) {
+ need_policy = TRUE;
+ }
+ }
+
mutex_exit(&zp->z_lock);
if (mask & AT_MODE) {
- if (zfs_zaccess_v4_perm(zp, ACE_WRITE_ACL, cr) == 0) {
+ if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) {
err = secpolicy_setid_setsticky_clear(vp, vap,
&oldva, cr);
if (err) {
@@ -2073,10 +2511,9 @@ top:
if (trim_mask) {
saved_mask = vap->va_mask;
vap->va_mask &= ~trim_mask;
-
}
err = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
- (int (*)(void *, int, cred_t *))zfs_zaccess_rwx, zp);
+ (int (*)(void *, int, cred_t *))zfs_zaccess_unix, zp);
if (err) {
ZFS_EXIT(zfsvfs);
return (err);
@@ -2094,22 +2531,45 @@ top:
tx = dmu_tx_create(zfsvfs->z_os);
dmu_tx_hold_bonus(tx, zp->z_id);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
if (mask & AT_MODE) {
uint64_t pmode = pzp->zp_mode;
new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT);
- if (zp->z_phys->zp_acl.z_acl_extern_obj)
- dmu_tx_hold_write(tx,
- pzp->zp_acl.z_acl_extern_obj, 0, SPA_MAXBLOCKSIZE);
- else
+ if (pzp->zp_acl.z_acl_extern_obj) {
+ /* Are we upgrading ACL from old V0 format to new V1 */
+ if (zfsvfs->z_version <= ZPL_VERSION_FUID &&
+ pzp->zp_acl.z_acl_version ==
+ ZFS_ACL_VERSION_INITIAL) {
+ dmu_tx_hold_free(tx,
+ pzp->zp_acl.z_acl_extern_obj, 0,
+ DMU_OBJECT_END);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
+ 0, sizeof (zfs_object_ace_t) * 2048 + 6);
+ } else {
+ dmu_tx_hold_write(tx,
+ pzp->zp_acl.z_acl_extern_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
+ } else {
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
- 0, ZFS_ACL_SIZE(MAX_ACL_SIZE));
+ 0, sizeof (zfs_object_ace_t) * 2048 + 6);
+ }
}
- if ((mask & (AT_UID | AT_GID)) && zp->z_phys->zp_xattr != 0) {
- err = zfs_zget(zp->z_zfsvfs, zp->z_phys->zp_xattr, &attrzp);
+ if ((mask & (AT_UID | AT_GID)) && pzp->zp_xattr != 0) {
+ err = zfs_zget(zp->z_zfsvfs, pzp->zp_xattr, &attrzp);
if (err) {
dmu_tx_abort(tx);
ZFS_EXIT(zfsvfs);
@@ -2153,16 +2613,20 @@ top:
mutex_enter(&attrzp->z_lock);
if (mask & AT_UID) {
- zp->z_phys->zp_uid = (uint64_t)vap->va_uid;
+ pzp->zp_uid = zfs_fuid_create(zfsvfs,
+ vap->va_uid, ZFS_OWNER, tx, &fuidp);
if (attrzp) {
- attrzp->z_phys->zp_uid = (uint64_t)vap->va_uid;
+ attrzp->z_phys->zp_uid = zfs_fuid_create(zfsvfs,
+ vap->va_uid, ZFS_OWNER, tx, &fuidp);
}
}
if (mask & AT_GID) {
- zp->z_phys->zp_gid = (uint64_t)vap->va_gid;
+ pzp->zp_gid = zfs_fuid_create(zfsvfs, vap->va_gid,
+ ZFS_GROUP, tx, &fuidp);
if (attrzp)
- attrzp->z_phys->zp_gid = (uint64_t)vap->va_gid;
+ attrzp->z_phys->zp_gid = zfs_fuid_create(zfsvfs,
+ vap->va_gid, ZFS_GROUP, tx, &fuidp);
}
if (attrzp)
@@ -2178,10 +2642,33 @@ top:
zfs_time_stamper_locked(zp, CONTENT_MODIFIED, tx);
else if (mask != 0)
zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
+ /*
+ * Do this after setting timestamps to prevent timestamp
+ * update from toggling bit
+ */
+
+ if (xoap && (mask & AT_XVATTR)) {
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+ size_t len;
+ dmu_object_info_t doi;
+
+ ASSERT(vp->v_type == VREG);
+
+ /* Grow the bonus buffer if necessary. */
+ dmu_object_info_from_db(zp->z_dbuf, &doi);
+ len = sizeof (xoap->xoa_av_scanstamp) +
+ sizeof (znode_phys_t);
+ if (len > doi.doi_bonus_size)
+ VERIFY(dmu_set_bonus(zp->z_dbuf, len, tx) == 0);
+ }
+ zfs_xvattr_set(zp, xvap);
+ }
if (mask != 0)
- zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask);
+ zfs_log_setattr(zilog, tx, TX_SETATTR, zp, vap, mask, fuidp);
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
mutex_exit(&zp->z_lock);
if (attrzp)
@@ -2298,6 +2785,8 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp)
* tdvp - Target directory to contain the "new entry".
* tnm - New entry name.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -2305,8 +2794,10 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp)
* Timestamps:
* sdvp,tdvp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
+zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *tdzp, *szp, *tzp;
znode_t *sdzp = VTOZ(sdvp);
@@ -2316,7 +2807,9 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
zfs_dirlock_t *sdl, *tdl;
dmu_tx_t *tx;
zfs_zlock_t *zl;
- int cmp, serr, terr, error;
+ int cmp, serr, terr;
+ int error = 0;
+ int zflg = 0;
ZFS_ENTER_VERIFY_ZP(zfsvfs, sdzp);
zilog = zfsvfs->z_log;
@@ -2324,7 +2817,7 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
/*
* Make sure we have the real vp for the target directory.
*/
- if (VOP_REALVP(tdvp, &realvp) == 0)
+ if (VOP_REALVP(tdvp, &realvp, ct) == 0)
tdvp = realvp;
if (tdvp->v_vfsp != sdvp->v_vfsp) {
@@ -2337,6 +2830,15 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr)
ZFS_EXIT(zfsvfs);
return (EIO);
}
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(tnm,
+ strlen(tnm), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+
+ if (flags & FIGNORECASE)
+ zflg |= ZCILOOK;
+
top:
szp = NULL;
tzp = NULL;
@@ -2364,7 +2866,14 @@ top:
} else if (sdzp->z_id > tdzp->z_id) {
cmp = 1;
} else {
- cmp = strcmp(snm, tnm);
+ /*
+ * First compare the two name arguments without
+ * considering any case folding.
+ */
+ int nofold = (zfsvfs->z_norm & ~U8_TEXTPREP_TOUPPER);
+
+ cmp = u8_strcmp(snm, tnm, 0, nofold, U8_UNICODE_LATEST, &error);
+ ASSERT(error == 0 || !(zfsvfs->z_case & ZFS_UTF8_ONLY));
if (cmp == 0) {
/*
* POSIX: "If the old argument and the new argument
@@ -2375,13 +2884,48 @@ top:
ZFS_EXIT(zfsvfs);
return (0);
}
+ /*
+ * If the file system is case-folding, then we may
+ * have some more checking to do. A case-folding file
+ * system is either supporting mixed case sensitivity
+ * access or is completely case-insensitive. Note
+ * that the file system is always case preserving.
+ *
+ * In mixed sensitivity mode case sensitive behavior
+ * is the default. FIGNORECASE must be used to
+ * explicitly request case insensitive behavior.
+ *
+ * If the source and target names provided differ only
+ * by case (e.g., a request to rename 'tim' to 'Tim'),
+ * we will treat this as a special case in the
+ * case-insensitive mode: as long as the source name
+ * is an exact match, we will allow this to proceed as
+ * a name-change request.
+ */
+ if ((zfsvfs->z_case & ZFS_CI_ONLY ||
+ (zfsvfs->z_case & ZFS_CI_MIXD && flags & FIGNORECASE)) &&
+ u8_strcmp(snm, tnm, 0, zfsvfs->z_norm, U8_UNICODE_LATEST,
+ &error) == 0) {
+ /*
+ * case preserving rename request, require exact
+ * name matches
+ */
+ zflg |= ZCIEXACT;
+ zflg &= ~ZCILOOK;
+ }
}
+
if (cmp < 0) {
- serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp, ZEXISTS);
- terr = zfs_dirent_lock(&tdl, tdzp, tnm, &tzp, 0);
+ serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp,
+ ZEXISTS | zflg, NULL, NULL);
+ terr = zfs_dirent_lock(&tdl,
+ tdzp, tnm, &tzp, ZRENAMING | zflg, NULL, NULL);
} else {
- terr = zfs_dirent_lock(&tdl, tdzp, tnm, &tzp, 0);
- serr = zfs_dirent_lock(&sdl, sdzp, snm, &szp, ZEXISTS);
+ terr = zfs_dirent_lock(&tdl,
+ tdzp, tnm, &tzp, zflg, NULL, NULL);
+ serr = zfs_dirent_lock(&sdl,
+ sdzp, snm, &szp, ZEXISTS | ZRENAMING | zflg,
+ NULL, NULL);
}
if (serr) {
@@ -2455,16 +2999,16 @@ top:
}
}
- vnevent_rename_src(ZTOV(szp), sdvp, snm);
+ vnevent_rename_src(ZTOV(szp), sdvp, snm, ct);
if (tzp)
- vnevent_rename_dest(ZTOV(tzp), tdvp, tnm);
+ vnevent_rename_dest(ZTOV(tzp), tdvp, tnm, ct);
/*
* notify the target directory if it is not the same
* as source directory.
*/
if (tdvp != sdvp) {
- vnevent_rename_dest_dir(tdvp);
+ vnevent_rename_dest_dir(tdvp, ct);
}
tx = dmu_tx_create(zfsvfs->z_os);
@@ -2497,15 +3041,19 @@ top:
}
if (tzp) /* Attempt to remove the existing target */
- error = zfs_link_destroy(tdl, tzp, tx, 0, NULL);
+ error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL);
if (error == 0) {
error = zfs_link_create(tdl, szp, tx, ZRENAMING);
if (error == 0) {
+ szp->z_phys->zp_flags |= ZFS_AV_MODIFIED;
+
error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL);
ASSERT(error == 0);
- zfs_log_rename(zilog, tx, TX_RENAME, sdzp,
- sdl->dl_name, tdzp, tdl->dl_name, szp);
+
+ zfs_log_rename(zilog, tx,
+ TX_RENAME | (flags & FIGNORECASE ? TX_CI : 0),
+ sdzp, sdl->dl_name, tdzp, tdl->dl_name, szp);
}
}
@@ -2533,6 +3081,8 @@ out:
* vap - Attributes of new entry.
* target - Target path of new symlink.
* cr - credentials of caller.
+ * ct - caller context
+ * flags - case flags
*
* RETURN: 0 if success
* error code if failure
@@ -2540,8 +3090,10 @@ out:
* Timestamps:
* dvp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr)
+zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *zp, *dzp = VTOZ(dvp);
zfs_dirlock_t *dl;
@@ -2551,13 +3103,23 @@ zfs_symlink(vnode_t *dvp, char *name, vattr_t *vap, char *link, cred_t *cr)
uint64_t zoid;
int len = strlen(link);
int error;
+ int zflg = ZNEW;
+ zfs_fuid_info_t *fuidp = NULL;
ASSERT(vap->va_type == VLNK);
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
+
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(name, strlen(name),
+ NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ if (flags & FIGNORECASE)
+ zflg |= ZCILOOK;
top:
- if (error = zfs_zaccess(dzp, ACE_ADD_FILE, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2570,7 +3132,8 @@ top:
/*
* Attempt to lock directory; fail if entry already exists.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &zp, ZNEW)) {
+ error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL);
+ if (error) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2581,6 +3144,16 @@ top:
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
if (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, SPA_MAXBLOCKSIZE);
+ if (zfsvfs->z_fuid_obj == 0) {
+ dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+ dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
+ SPA_MAXBLOCKSIZE);
+ dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
+ } else {
+ dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
+ dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
+ SPA_MAXBLOCKSIZE);
+ }
error = dmu_tx_assign(tx, zfsvfs->z_assign);
if (error) {
zfs_dirent_unlock(dl);
@@ -2603,14 +3176,13 @@ top:
*/
zoid = 0;
if (sizeof (znode_phys_t) + len <= dmu_bonus_max()) {
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, len);
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, len, NULL, &fuidp);
if (len != 0)
bcopy(link, zp->z_phys + 1, len);
} else {
dmu_buf_t *dbp;
- zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0);
-
+ zfs_mknode(dzp, vap, &zoid, tx, cr, 0, &zp, 0, NULL, &fuidp);
/*
* Nothing can access the znode yet so no locking needed
* for growing the znode's blocksize.
@@ -2631,8 +3203,14 @@ top:
*/
(void) zfs_link_create(dl, zp, tx, ZNEW);
out:
- if (error == 0)
- zfs_log_symlink(zilog, tx, TX_SYMLINK, dzp, zp, name, link);
+ if (error == 0) {
+ uint64_t txtype = TX_SYMLINK;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
+ }
+ if (fuidp)
+ zfs_fuid_info_free(fuidp);
dmu_tx_commit(tx);
@@ -2651,6 +3229,7 @@ out:
* IN: vp - vnode of symbolic link.
* uoip - structure to contain the link path.
* cr - credentials of caller.
+ * ct - caller context
*
* OUT: uio - structure to contain the link path.
*
@@ -2662,7 +3241,7 @@ out:
*/
/* ARGSUSED */
static int
-zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr)
+zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -2699,6 +3278,7 @@ zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr)
* svp - vnode of new entry.
* name - name of new entry.
* cr - credentials of caller.
+ * ct - caller context
*
* RETURN: 0 if success
* error code if failure
@@ -2709,7 +3289,8 @@ zfs_readlink(vnode_t *vp, uio_t *uio, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr)
+zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
+ caller_context_t *ct, int flags)
{
znode_t *dzp = VTOZ(tdvp);
znode_t *tzp, *szp;
@@ -2719,13 +3300,15 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr)
dmu_tx_t *tx;
vnode_t *realvp;
int error;
+ int zf = ZNEW;
+ uid_t owner;
ASSERT(tdvp->v_type == VDIR);
ZFS_ENTER_VERIFY_ZP(zfsvfs, dzp);
zilog = zfsvfs->z_log;
- if (VOP_REALVP(svp, &realvp) == 0)
+ if (VOP_REALVP(svp, &realvp, ct) == 0)
svp = realvp;
if (svp->v_vfsp != tdvp->v_vfsp) {
@@ -2733,6 +3316,14 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr)
return (EXDEV);
}
+ if (zfsvfs->z_case & ZFS_UTF8_ONLY && u8_validate(name,
+ strlen(name), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
+ ZFS_EXIT(zfsvfs);
+ return (EILSEQ);
+ }
+ if (flags & FIGNORECASE)
+ zf |= ZCILOOK;
+
szp = VTOZ(svp);
if (!szp->z_dbuf_held) {
ZFS_EXIT(zfsvfs);
@@ -2760,13 +3351,14 @@ top:
return (EPERM);
}
- if ((uid_t)szp->z_phys->zp_uid != crgetuid(cr) &&
+ zfs_fuid_map_id(zfsvfs, szp->z_phys->zp_uid, ZFS_OWNER, &owner);
+ if (owner != crgetuid(cr) &&
secpolicy_basic_link(cr) != 0) {
ZFS_EXIT(zfsvfs);
return (EPERM);
}
- if (error = zfs_zaccess(dzp, ACE_ADD_FILE, cr)) {
+ if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2774,7 +3366,8 @@ top:
/*
* Attempt to lock directory; fail if entry already exists.
*/
- if (error = zfs_dirent_lock(&dl, dzp, name, &tzp, ZNEW)) {
+ error = zfs_dirent_lock(&dl, dzp, name, &tzp, zf, NULL, NULL);
+ if (error) {
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -2797,15 +3390,19 @@ top:
error = zfs_link_create(dl, szp, tx, 0);
- if (error == 0)
- zfs_log_link(zilog, tx, TX_LINK, dzp, szp, name);
+ if (error == 0) {
+ uint64_t txtype = TX_LINK;
+ if (flags & FIGNORECASE)
+ txtype |= TX_CI;
+ zfs_log_link(zilog, tx, txtype, dzp, szp, name);
+ }
dmu_tx_commit(tx);
zfs_dirent_unlock(dl);
if (error == 0) {
- vnevent_link(svp);
+ vnevent_link(svp, ct);
}
ZFS_EXIT(zfsvfs);
@@ -2953,6 +3550,7 @@ out:
* len - amount of data to write.
* flags - flags to control the operation.
* cr - credentials of caller.
+ * ct - caller context.
*
* RETURN: 0 if success
* error code if failure
@@ -2960,8 +3558,10 @@ out:
* Timestamps:
* vp - ctime|mtime updated
*/
+/*ARGSUSED*/
static int
-zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr)
+zfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3022,8 +3622,9 @@ out:
return (error);
}
+/*ARGSUSED*/
void
-zfs_inactive(vnode_t *vp, cred_t *cr)
+zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3084,13 +3685,15 @@ zfs_inactive(vnode_t *vp, cred_t *cr)
* IN: vp - vnode seeking within
* ooff - old file offset
* noffp - pointer to new file offset
+ * ct - caller context
*
* RETURN: 0 if success
* EINVAL if new offset invalid
*/
/* ARGSUSED */
static int
-zfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
+zfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct)
{
if (vp->v_type == VDIR)
return (0);
@@ -3103,7 +3706,7 @@ zfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp)
*/
static int
zfs_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
- flk_callback_t *flk_cbp, cred_t *cr)
+ flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3121,7 +3724,7 @@ zfs_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
ZFS_EXIT(zfsvfs);
return (EAGAIN);
}
- error = fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr);
+ error = fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct);
ZFS_EXIT(zfsvfs);
return (error);
}
@@ -3239,6 +3842,7 @@ out:
* addr - virtual address of fault.
* rw - mode of created pages.
* cr - credentials of caller.
+ * ct - caller context.
*
* OUT: protp - protection mode of created pages.
* pl - list of pages created.
@@ -3253,7 +3857,7 @@ out:
static int
zfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, cred_t *cr)
+ enum seg_rw rw, cred_t *cr, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3384,15 +3988,22 @@ out:
*
* zfs_addmap() updates z_mapcnt
*/
+/*ARGSUSED*/
static int
zfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
segvn_crargs_t vn_a;
int error;
+ if ((prot & PROT_WRITE) &&
+ (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_READONLY |
+ ZFS_APPENDONLY)))
+ return (EPERM);
+
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
if (vp->v_flag & VNOMAP) {
@@ -3454,7 +4065,8 @@ zfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
/* ARGSUSED */
static int
zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
uint64_t pages = btopr(len);
@@ -3486,7 +4098,8 @@ zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
/* ARGSUSED */
static int
zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
- size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr)
+ size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct)
{
uint64_t pages = btopr(len);
@@ -3495,7 +4108,7 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
if ((flags & MAP_SHARED) && (prot & PROT_WRITE) &&
vn_has_cached_data(vp))
- (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr);
+ (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr, ct);
return (0);
}
@@ -3512,6 +4125,7 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
* flag - current file open mode flags.
* offset - current file offset.
* cr - credentials of caller [UNUSED].
+ * ct - caller context.
*
* RETURN: 0 if success
* error code if failure
@@ -3559,8 +4173,9 @@ top:
return (error);
}
+/*ARGSUSED*/
static int
-zfs_fid(vnode_t *vp, fid_t *fidp)
+zfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -3611,7 +4226,8 @@ zfs_fid(vnode_t *vp, fid_t *fidp)
}
static int
-zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
+zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp, *xzp;
zfsvfs_t *zfsvfs;
@@ -3633,7 +4249,7 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
*valp = 0;
error = zfs_dirent_lock(&dl, zp, "", &xzp,
- ZXATTR | ZEXISTS | ZSHARED);
+ ZXATTR | ZEXISTS | ZSHARED, NULL, NULL);
if (error == 0) {
zfs_dirent_unlock(dl);
if (!zfs_dirempty(xzp))
@@ -3649,6 +4265,13 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
ZFS_EXIT(zfsvfs);
return (error);
+ case _PC_SATTR_ENABLED:
+ case _PC_SATTR_EXISTS:
+ zp = VTOZ(vp);
+ *valp = vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) &&
+ (vp->v_type == VREG || vp->v_type == VDIR);
+ return (0);
+
case _PC_ACL_ENABLED:
*valp = _ACL_ACE_ENABLED;
return (0);
@@ -3658,20 +4281,22 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr)
return (0);
default:
- return (fs_pathconf(vp, cmd, valp, cr));
+ return (fs_pathconf(vp, cmd, valp, cr, ct));
}
}
/*ARGSUSED*/
static int
-zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr)
+zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
+ boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- error = zfs_getacl(zp, vsecp, cr);
+ error = zfs_getacl(zp, vsecp, skipaclchk, cr);
ZFS_EXIT(zfsvfs);
return (error);
@@ -3679,14 +4304,16 @@ zfs_getsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr)
/*ARGSUSED*/
static int
-zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr)
+zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr,
+ caller_context_t *ct)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
+ boolean_t skipaclchk = (flag & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
ZFS_ENTER_VERIFY_ZP(zfsvfs, zp);
- error = zfs_setacl(zp, vsecp, cr);
+ error = zfs_setacl(zp, vsecp, skipaclchk, cr);
ZFS_EXIT(zfsvfs);
return (error);
}
diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c
index 7415a15e74..c9c3e720ba 100644
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c
@@ -51,7 +51,10 @@
#include <sys/zfs_acl.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_rlock.h>
+#include <sys/zfs_fuid.h>
+#include <sys/zfs_i18n.h>
#include <sys/fs/zfs.h>
+#include <sys/kidmap.h>
#endif /* _KERNEL */
#include <sys/dmu.h>
@@ -262,13 +265,18 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr)
*/
if (dmu_object_info(os, MASTER_NODE_OBJ, &doi) == ENOENT) {
dmu_tx_t *tx = dmu_tx_create(os);
+ uint64_t zpl_version;
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, TRUE, NULL); /* master */
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, TRUE, NULL); /* del queue */
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); /* root node */
error = dmu_tx_assign(tx, TXG_WAIT);
ASSERT3U(error, ==, 0);
- zfs_create_fs(os, cr, ZPL_VERSION, tx);
+ if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
+ zpl_version = ZPL_VERSION;
+ else
+ zpl_version = ZPL_VERSION_FUID - 1;
+ zfs_create_fs(os, cr, zpl_version, 0, tx);
dmu_tx_commit(tx);
}
@@ -327,6 +335,11 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr)
return (error);
}
ASSERT3U((*zpp)->z_id, ==, zfsvfs->z_root);
+ error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1,
+ &zfsvfs->z_fuid_obj);
+ if (error == ENOENT)
+ error = 0;
+
return (0);
}
@@ -503,13 +516,18 @@ zfs_znode_dmu_init(znode_t *zp)
* IS_ROOT_NODE - new object will be root
* IS_XATTR - new object is an attribute
* IS_REPLAY - intent log replay
+ * bonuslen - length of bonus buffer
+ * setaclp - File/Dir initial ACL
+ * fuidp - Tracks fuid allocation.
*
* OUT: oid - ID of created object
+ * zpp - allocated znode
*
*/
void
zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
- uint_t flag, znode_t **zpp, int bonuslen)
+ uint_t flag, znode_t **zpp, int bonuslen, zfs_acl_t *setaclp,
+ zfs_fuid_info_t **fuidp)
{
dmu_buf_t *dbp;
znode_phys_t *pzp;
@@ -543,13 +561,13 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
*/
if (vap->va_type == VDIR) {
if (flag & IS_REPLAY) {
- err = zap_create_claim(zfsvfs->z_os, *oid,
- DMU_OT_DIRECTORY_CONTENTS,
+ err = zap_create_claim_norm(zfsvfs->z_os, *oid,
+ zfsvfs->z_norm, DMU_OT_DIRECTORY_CONTENTS,
DMU_OT_ZNODE, sizeof (znode_phys_t) + bonuslen, tx);
ASSERT3U(err, ==, 0);
} else {
- *oid = zap_create(zfsvfs->z_os,
- DMU_OT_DIRECTORY_CONTENTS,
+ *oid = zap_create_norm(zfsvfs->z_os,
+ zfsvfs->z_norm, DMU_OT_DIRECTORY_CONTENTS,
DMU_OT_ZNODE, sizeof (znode_phys_t) + bonuslen, tx);
}
} else {
@@ -593,6 +611,9 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
pzp->zp_rdev = zfs_expldev(vap->va_rdev);
}
+ if (zfsvfs->z_use_fuids)
+ pzp->zp_flags = ZFS_ARCHIVE | ZFS_AV_MODIFIED;
+
if (vap->va_type == VDIR) {
pzp->zp_size = 2; /* contents ("." and "..") */
pzp->zp_links = (flag & (IS_ROOT_NODE | IS_XATTR)) ? 2 : 1;
@@ -622,7 +643,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
pzp->zp_mode = MAKEIMODE(vap->va_type, vap->va_mode);
zp = zfs_znode_alloc(zfsvfs, dbp, *oid, 0);
- zfs_perm_init(zp, dzp, flag, vap, tx, cr);
+ zfs_perm_init(zp, dzp, flag, vap, tx, cr, setaclp, fuidp);
if (zpp) {
kmutex_t *hash_mtx = ZFS_OBJ_MUTEX(zp);
@@ -639,6 +660,71 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, uint64_t *oid, dmu_tx_t *tx, cred_t *cr,
}
}
+void
+zfs_xvattr_set(znode_t *zp, xvattr_t *xvap)
+{
+ xoptattr_t *xoap;
+
+ xoap = xva_getxoptattr(xvap);
+ ASSERT(xoap);
+
+ if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ ZFS_TIME_ENCODE(&xoap->xoa_createtime, zp->z_phys->zp_crtime);
+ XVA_SET_RTN(xvap, XAT_CREATETIME);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
+ ZFS_ATTR_SET(zp, ZFS_READONLY, xoap->xoa_readonly);
+ XVA_SET_RTN(xvap, XAT_READONLY);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
+ ZFS_ATTR_SET(zp, ZFS_HIDDEN, xoap->xoa_hidden);
+ XVA_SET_RTN(xvap, XAT_HIDDEN);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
+ ZFS_ATTR_SET(zp, ZFS_SYSTEM, xoap->xoa_system);
+ XVA_SET_RTN(xvap, XAT_SYSTEM);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
+ ZFS_ATTR_SET(zp, ZFS_ARCHIVE, xoap->xoa_archive);
+ XVA_SET_RTN(xvap, XAT_ARCHIVE);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE)) {
+ ZFS_ATTR_SET(zp, ZFS_IMMUTABLE, xoap->xoa_immutable);
+ XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
+ ZFS_ATTR_SET(zp, ZFS_NOUNLINK, xoap->xoa_nounlink);
+ XVA_SET_RTN(xvap, XAT_NOUNLINK);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_APPENDONLY)) {
+ ZFS_ATTR_SET(zp, ZFS_APPENDONLY, xoap->xoa_appendonly);
+ XVA_SET_RTN(xvap, XAT_APPENDONLY);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
+ ZFS_ATTR_SET(zp, ZFS_NODUMP, xoap->xoa_nodump);
+ XVA_SET_RTN(xvap, XAT_NODUMP);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_OPAQUE)) {
+ ZFS_ATTR_SET(zp, ZFS_OPAQUE, xoap->xoa_opaque);
+ XVA_SET_RTN(xvap, XAT_OPAQUE);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ ZFS_ATTR_SET(zp, ZFS_AV_QUARANTINED,
+ xoap->xoa_av_quarantined);
+ XVA_SET_RTN(xvap, XAT_AV_QUARANTINED);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED)) {
+ ZFS_ATTR_SET(zp, ZFS_AV_MODIFIED, xoap->xoa_av_modified);
+ XVA_SET_RTN(xvap, XAT_AV_MODIFIED);
+ }
+ if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+ (void) memcpy(zp->z_phys + 1, xoap->xoa_av_scanstamp,
+ sizeof (xoap->xoa_av_scanstamp));
+ zp->z_phys->zp_flags |= ZFS_BONUS_SCANSTAMP;
+ XVA_SET_RTN(xvap, XAT_AV_SCANSTAMP);
+ }
+}
+
int
zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
{
@@ -861,11 +947,17 @@ zfs_time_stamper_locked(znode_t *zp, uint_t flag, dmu_tx_t *tx)
if (flag & AT_ATIME)
ZFS_TIME_ENCODE(&now, zp->z_phys->zp_atime);
- if (flag & AT_MTIME)
+ if (flag & AT_MTIME) {
ZFS_TIME_ENCODE(&now, zp->z_phys->zp_mtime);
+ if (zp->z_zfsvfs->z_use_fuids)
+ zp->z_phys->zp_flags |= (ZFS_ARCHIVE | ZFS_AV_MODIFIED);
+ }
- if (flag & AT_CTIME)
+ if (flag & AT_CTIME) {
ZFS_TIME_ENCODE(&now, zp->z_phys->zp_ctime);
+ if (zp->z_zfsvfs->z_use_fuids)
+ zp->z_phys->zp_flags |= ZFS_ARCHIVE;
+ }
}
/*
@@ -958,8 +1050,13 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
rl_t *rl;
uint64_t end = off + len;
uint64_t size, new_blksz;
+ uint64_t pflags = zp->z_phys->zp_flags;
int error;
+ if ((pflags & (ZFS_IMMUTABLE|ZFS_READONLY)) ||
+ off < zp->z_phys->zp_size && (pflags & ZFS_APPENDONLY))
+ return (EPERM);
+
if (ZTOV(zp)->v_type == VFIFO)
return (0);
@@ -1094,7 +1191,8 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
}
void
-zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx)
+zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version,
+ int norm, dmu_tx_t *tx)
{
zfsvfs_t zfsvfs;
uint64_t moid, doid, roid = 0;
@@ -1155,12 +1253,16 @@ zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx)
zfsvfs.z_os = os;
zfsvfs.z_assign = TXG_NOWAIT;
zfsvfs.z_parent = &zfsvfs;
+ zfsvfs.z_version = version;
+ zfsvfs.z_use_fuids = USE_FUIDS(version, os);
+ zfsvfs.z_norm = norm;
mutex_init(&zfsvfs.z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
list_create(&zfsvfs.z_all_znodes, sizeof (znode_t),
offsetof(znode_t, z_link_node));
- zfs_mknode(rootzp, &vattr, &roid, tx, cr, IS_ROOT_NODE, NULL, 0);
+ zfs_mknode(rootzp, &vattr, &roid, tx, cr, IS_ROOT_NODE,
+ NULL, 0, NULL, NULL);
ASSERT3U(rootzp->z_id, ==, roid);
error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &roid, tx);
ASSERT(error == 0);
@@ -1168,8 +1270,8 @@ zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx)
ZTOV(rootzp)->v_count = 0;
kmem_cache_free(znode_cache, rootzp);
}
-#endif /* _KERNEL */
+#endif /* _KERNEL */
/*
* Given an object number, return its parent object number and whether
* or not the object is an extended attribute directory.
diff --git a/usr/src/uts/common/fs/zfs/zil.c b/usr/src/uts/common/fs/zfs/zil.c
index fb0393f02a..98e494926d 100644
--- a/usr/src/uts/common/fs/zfs/zil.c
+++ b/usr/src/uts/common/fs/zfs/zil.c
@@ -857,7 +857,7 @@ zil_lwb_commit(zilog_t *zilog, itx_t *itx, lwb_t *lwb)
}
itx_t *
-zil_itx_create(int txtype, size_t lrsize)
+zil_itx_create(uint64_t txtype, size_t lrsize)
{
itx_t *itx;
@@ -1396,6 +1396,9 @@ zil_replay_log_record(zilog_t *zilog, lr_t *lr, void *zra, uint64_t claim_txg)
if (lr->lrc_seq <= zh->zh_replay_seq) /* already replayed */
return;
+ /* Strip case-insensitive bit, still present in log record */
+ txtype &= ~TX_CI;
+
/*
* Make a copy of the data so we can revise and extend it.
*/
@@ -1515,8 +1518,9 @@ zil_replay_log_record(zilog_t *zilog, lr_t *lr, void *zra, uint64_t claim_txg)
name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
dmu_objset_name(zr->zr_os, name);
cmn_err(CE_WARN, "ZFS replay transaction error %d, "
- "dataset %s, seq 0x%llx, txtype %llu\n",
- error, name, (u_longlong_t)lr->lrc_seq, (u_longlong_t)txtype);
+ "dataset %s, seq 0x%llx, txtype %llu %s\n",
+ error, name, (u_longlong_t)lr->lrc_seq, (u_longlong_t)txtype,
+ (lr->lrc_txtype & TX_CI) ? "CI" : "");
zilog->zl_stop_replay = 1;
kmem_free(name, MAXNAMELEN);
}
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 7f7c401831..dd83cb7b01 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -223,7 +223,8 @@ zvol_minor_lookup(const char *name)
void
zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
{
- nvlist_t *nvprops = arg;
+ zfs_creat_t *zct = arg;
+ nvlist_t *nvprops = zct->zct_props;
int error;
uint64_t volblocksize, volsize;
diff --git a/usr/src/uts/common/idmap/idmap_cache.c b/usr/src/uts/common/idmap/idmap_cache.c
index d5c5f4f374..3b4c4963cd 100644
--- a/usr/src/uts/common/idmap/idmap_cache.c
+++ b/usr/src/uts/common/idmap/idmap_cache.c
@@ -368,8 +368,8 @@ kidmap_cache_purge_avl(idmap_avl_cache_t *cache)
if (rw_tryupgrade(&cache->lock) == 0) {
/*
* Could not upgrade lock so release lock
- * and aquire the write lock. It is valid to
- * release abd re-aquire the lock as there
+ * and acquire the write lock. It is valid to
+ * release abd re-acquire the lock as there
* can only be one purge routine running on an
* avl tree and no other routine removes
* entries.
@@ -451,7 +451,7 @@ kidmap_find_sid_prefix(const char *sid_prefix) {
if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
/*
* Could not upgrade lock so release lock
- * and aquire the write lock
+ * and acquire the write lock
*/
rw_exit(&kidmap_sid_prefix_store->lock);
rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
diff --git a/usr/src/uts/common/io/cons.c b/usr/src/uts/common/io/cons.c
index 2baf58af37..ae55f2ab61 100644
--- a/usr/src/uts/common/io/cons.c
+++ b/usr/src/uts/common/io/cons.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -121,7 +121,7 @@ static struct dev_ops cn_ops = {
* Global variables associated with the console device:
*
* XXX: There are too many of these!
- * moved to space.c to becone resident in the kernel so that cons
+ * moved to space.c to become resident in the kernel so that cons
* can be loadable.
*/
@@ -310,7 +310,7 @@ cnopen(dev_t *dev, int flag, int state, struct cred *cred)
LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE);
}
- if ((err = VOP_OPEN(&vp, flag, cred)) != 0)
+ if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0)
return (err);
/*
@@ -323,7 +323,7 @@ cnopen(dev_t *dev, int flag, int state, struct cred *cred)
* whilst we were in the middle of the open.
*/
if (rconsvp == NULL) {
- (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred);
+ (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
return (0);
}
cmn_err(CE_PANIC, "cnopen: cloned open");
@@ -354,7 +354,7 @@ cnclose(dev_t dev, int flag, int state, struct cred *cred)
return (0);
while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
- err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred);
+ err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
if (!err) {
vp->v_stream = NULL;
rconsopen--;
diff --git a/usr/src/uts/common/io/devinfo.c b/usr/src/uts/common/io/devinfo.c
index bc441e93a3..79279b4e31 100644
--- a/usr/src/uts/common/io/devinfo.c
+++ b/usr/src/uts/common/io/devinfo.c
@@ -3630,11 +3630,11 @@ di_cache_write(struct di_cache *cache)
/*
* Now sync the file and close it
*/
- if (error = VOP_FSYNC(vp, FSYNC, kcred)) {
+ if (error = VOP_FSYNC(vp, FSYNC, kcred, NULL)) {
CACHE_DEBUG((DI_ERR, "FSYNC failed: %d", error));
}
- if (error = VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred)) {
+ if (error = VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred, NULL)) {
CACHE_DEBUG((DI_ERR, "close() failed: %d", error));
VN_RELE(vp);
return;
@@ -3655,7 +3655,7 @@ di_cache_write(struct di_cache *cache)
return;
fail:
- (void) VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred, NULL);
VN_RELE(vp);
}
diff --git a/usr/src/uts/common/io/devpoll.c b/usr/src/uts/common/io/devpoll.c
index 965df2a9a1..1e71013d17 100644
--- a/usr/src/uts/common/io/devpoll.c
+++ b/usr/src/uts/common/io/devpoll.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,12 +128,12 @@ static struct modlinkage modlinkage = {
* This assumption is not true for /dev/poll; hence the need for extra
* locking.
*
- * To allow more paralellism, each /dev/poll file descriptor (indexed by
+ * To allow more parallelism, each /dev/poll file descriptor (indexed by
* minor number) has its own lock. Since read (dpioctl) is a much more
* frequent operation than write, we want to allow multiple reads on same
* /dev/poll fd. However, we prevent writes from being starved by giving
* priority to write operation. Theoretically writes can starve reads as
- * well. But in pratical sense this is not important because (1) writes
+ * well. But in practical sense this is not important because (1) writes
* happens less often than reads, and (2) write operation defines the
* content of poll fd a cache set. If writes happens so often that they
* can starve reads, that means the cached set is very unstable. It may
@@ -348,7 +348,7 @@ retry:
*/
curthread->t_pollcache = pcp;
error = VOP_POLL(fp->f_vnode, pdp->pd_events, 0,
- &revent, &php);
+ &revent, &php, NULL);
curthread->t_pollcache = NULL;
releasef(fd);
if (error != 0) {
@@ -623,7 +623,7 @@ dpwrite(dev_t dev, struct uio *uiop, cred_t *credp)
*/
curthread->t_pollcache = pcp;
error = VOP_POLL(fp->f_vnode, pfdp->events, 0,
- &pfdp->revents, &php);
+ &pfdp->revents, &php, NULL);
curthread->t_pollcache = NULL;
/*
* We always set the bit when this fd is cached.
@@ -809,7 +809,7 @@ dpioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
continue;
/*
- * Sleep until we are notified, signalled, or timed out.
+ * Sleep until we are notified, signaled, or timed out.
* Do not check for signals if we have a zero timeout.
*/
if (time_out == 0) /* immediate timeout */
diff --git a/usr/src/uts/common/io/fssnap.c b/usr/src/uts/common/io/fssnap.c
index 4e047f03a2..54d3470fda 100644
--- a/usr/src/uts/common/io/fssnap.c
+++ b/usr/src/uts/common/io/fssnap.c
@@ -347,7 +347,7 @@ _fini(void)
* together the frozen file system. The data may either be on the master
* device (no translation exists), in memory (a translation exists but has
* not been flushed to the backing store), or in the backing store file.
- * The read request may require the snapshot driver to retreive data from
+ * The read request may require the snapshot driver to retrieve data from
* several different places and piece it together to look like a single
* contiguous read.
*
@@ -1032,7 +1032,7 @@ int *rvalp)
releasef(fc.rootfiledesc);
/* pass ioctl request to file system */
- error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp);
+ error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp, NULL);
VN_RELE(vp);
break;
}
@@ -1055,7 +1055,7 @@ int *rvalp)
releasef(fc.rootfiledesc);
/* pass ioctl request to file system */
- error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp);
+ error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp, NULL);
VN_RELE(vp);
break;
}
@@ -1130,7 +1130,7 @@ int *rvalp)
* to use as a locking semaphore across the IOCTL
* for mount in progress cases...
*/
- vfsp = kmem_alloc(sizeof (vfs_t), KM_SLEEP);
+ vfsp = vfs_alloc(KM_SLEEP);
VFS_INIT(vfsp, vfsops, NULL);
VFS_HOLD(vfsp);
vfs_addmip(dev, vfsp);
@@ -1146,7 +1146,7 @@ int *rvalp)
* until IOCTL complete to prohibit a mount sneaking
* in
*/
- error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp);
+ error = VOP_IOCTL(vp, cmd, arg, 0, credp, rvalp, NULL);
vfs_delmip(vfsp);
VFS_RELE(vfsp);
VN_RELE(vp);
diff --git a/usr/src/uts/common/io/gentty.c b/usr/src/uts/common/io/gentty.c
index 431e80245d..086624fc26 100644
--- a/usr/src/uts/common/io/gentty.c
+++ b/usr/src/uts/common/io/gentty.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved.
* Use is subject to license terms.
*/
@@ -217,7 +217,7 @@ syopen(dev_t *devp, int flag, int otyp, struct cred *cr)
* The multi-open, single-clone means that no cloning
* can happen via this open, hence the assertion.
*/
- error = VOP_OPEN(&ttyvp, FNOCTTY | flag, cr);
+ error = VOP_OPEN(&ttyvp, FNOCTTY | flag, cr, NULL);
if (error == 0) {
struct snode *csp;
@@ -326,7 +326,7 @@ syioctl(dev_t dev, int cmd, intptr_t arg, int mode, struct cred *cr,
return (ENXIO);
}
- error = VOP_IOCTL(sp->s_vp, cmd, arg, mode, cr, rvalp);
+ error = VOP_IOCTL(sp->s_vp, cmd, arg, mode, cr, rvalp, NULL);
tty_rele(sp);
return (error);
@@ -350,7 +350,7 @@ sypoll(dev_t dev, short events, int anyyet, short *reventsp,
return (ENXIO);
}
- error = VOP_POLL(sp->s_vp, events, anyyet, reventsp, phpp);
+ error = VOP_POLL(sp->s_vp, events, anyyet, reventsp, phpp, NULL);
tty_rele(sp);
return (error);
diff --git a/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c b/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c
index a69ecc8fea..71a20fa918 100644
--- a/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c
+++ b/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_arp.c
@@ -290,7 +290,7 @@ ibcm_arp_unlink_driver(queue_t **q, vnode_t **dev_vp)
setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_TRUE);
- if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED())) != 0) {
+ if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL)) != 0) {
IBTF_DPRINTF_L2(cmlog, "ibcm_arp_unlink_driver: VOP_CLOSE "
"failed %d\n", rc);
}
diff --git a/usr/src/uts/common/io/iwscons.c b/usr/src/uts/common/io/iwscons.c
index e254a42916..54e4bd7762 100644
--- a/usr/src/uts/common/io/iwscons.c
+++ b/usr/src/uts/common/io/iwscons.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -105,7 +105,7 @@ static iwscn_list_t *iwscn_list;
* the redirection streams module (redirmod) pushed on them.
*
* If both iwscn_redirect_lock and iwscn_list_lock must be held then
- * iwscn_redirect_lock must be aquired first.
+ * iwscn_redirect_lock must be acquired first.
*/
static kcondvar_t iwscn_list_cv;
static kmutex_t iwscn_list_lock;
@@ -320,7 +320,7 @@ iwscnpoll(dev_t dev, short events, int anyyet, short *reventsp,
ASSERT(getminor(dev) == 0);
lp = srhold();
- error = VOP_POLL(lp->wl_vp, events, anyyet, reventsp, phpp);
+ error = VOP_POLL(lp->wl_vp, events, anyyet, reventsp, phpp, NULL);
srrele(lp);
return (error);
@@ -448,7 +448,7 @@ iwscnioctl(dev_t dev, int cmd, intptr_t arg, int flag,
}
/* Process the ioctl normally */
- error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp);
+ error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp, NULL);
srrele(lp);
mutex_exit(&iwscn_redirect_lock);
@@ -457,7 +457,7 @@ iwscnioctl(dev_t dev, int cmd, intptr_t arg, int flag,
/* Process the ioctl normally */
lp = srhold();
- error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp);
+ error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp, NULL);
srrele(lp);
return (error);
}
@@ -498,11 +498,11 @@ iwscnopen(dev_t *devp, int flag, int state, cred_t *cred)
* There is currently no redirection going on.
* pass this open request onto the console driver
*/
- error = VOP_OPEN(&vp, flag, cred);
+ error = VOP_OPEN(&vp, flag, cred, NULL);
if (error != 0)
return (error);
- /* Re-aquire the list lock */
+ /* Re-acquire the list lock */
mutex_enter(&iwscn_list_lock);
if (iwscn_list == NULL) {
@@ -513,7 +513,7 @@ iwscnopen(dev_t *devp, int flag, int state, cred_t *cred)
* In this case there must already be a copy of
* this vnode on the list, so we can free up this one.
*/
- (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred);
+ (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
}
}
@@ -588,7 +588,8 @@ iwscnclose(dev_t dev, int flag, int state, cred_t *cred)
if (lp->wl_is_console == B_TRUE)
/* Close the underlying console device. */
- (void) VOP_CLOSE(lp->wl_vp, 0, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(lp->wl_vp, 0, 1, (offset_t)0, kcred,
+ NULL);
kmem_free(lp, sizeof (*lp));
}
diff --git a/usr/src/uts/common/io/l_strplumb.c b/usr/src/uts/common/io/l_strplumb.c
index 7c6f1b55d3..a8ff99b126 100644
--- a/usr/src/uts/common/io/l_strplumb.c
+++ b/usr/src/uts/common/io/l_strplumb.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -70,7 +70,7 @@ kstr_open(major_t maj, minor_t min, vnode_t **vpp, int *fd)
if (fd != NULL)
error = fassign(&vp, FREAD|FWRITE, fd);
else
- error = VOP_OPEN(&vp, FREAD|FWRITE, CRED());
+ error = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
/*
* Must set vpp after calling fassign()/VOP_OPEN()
@@ -135,7 +135,7 @@ kstr_close(vnode_t *vp, int fd)
return (EINVAL);
}
} else {
- ret = VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ ret = VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (ret);
}
diff --git a/usr/src/uts/common/io/lofi.c b/usr/src/uts/common/io/lofi.c
index 2f1107e189..14e06740c8 100644
--- a/usr/src/uts/common/io/lofi.c
+++ b/usr/src/uts/common/io/lofi.c
@@ -223,7 +223,8 @@ lofi_free_handle(dev_t dev, minor_t minor, struct lofi_state *lsp,
char namebuf[50];
if (lsp->ls_vp) {
- (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0, credp);
+ (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag,
+ 1, 0, credp, NULL);
VN_RELE(lsp->ls_vp);
lsp->ls_vp = NULL;
}
@@ -864,7 +865,7 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
}
}
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, credp);
+ error = VOP_GETATTR(vp, &vattr, 0, credp, NULL);
if (error) {
goto closeout;
}
@@ -936,7 +937,7 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
* Try to handle stacked lofs vnodes.
*/
if (vp->v_type == VREG) {
- if (VOP_REALVP(vp, &lsp->ls_vp) != 0) {
+ if (VOP_REALVP(vp, &lsp->ls_vp, NULL) != 0) {
lsp->ls_vp = vp;
} else {
/*
@@ -971,7 +972,7 @@ propout:
(void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
(void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
closeout:
- (void) VOP_CLOSE(vp, flag, 1, 0, credp);
+ (void) VOP_CLOSE(vp, flag, 1, 0, credp, NULL);
VN_RELE(vp);
out:
if (zalloced)
@@ -1035,7 +1036,7 @@ lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename,
while (lsp->ls_vp_iocount > 0)
cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock);
(void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0,
- credp);
+ credp, NULL);
VN_RELE(lsp->ls_vp);
lsp->ls_vp = NULL;
cv_broadcast(&lsp->ls_vp_cv);
diff --git a/usr/src/uts/common/io/lvm/trans/trans_ioctl.c b/usr/src/uts/common/io/lvm/trans/trans_ioctl.c
index 156ed4548a..4fd02c4ff2 100644
--- a/usr/src/uts/common/io/lvm/trans/trans_ioctl.c
+++ b/usr/src/uts/common/io/lvm/trans/trans_ioctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -296,7 +295,7 @@ trans_test_trypage(void *d, int mode, IOLOCK *lock)
/*
* get rid of the devices pages
*/
- (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED());
+ (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED(), NULL);
/*
* test 1 -- don't find nonexistant page
@@ -335,7 +334,7 @@ errout:
/*
* get rid of the file's pages
*/
- (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED());
+ (void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED(), NULL);
VN_RELE(devvp);
migp->size = test;
@@ -1301,7 +1300,7 @@ trans_detach_ioctl(void *d, int mode, IOLOCK *lock)
mdclrerror(&migp->mde);
- /* aquire both md_unit_array_rw, and unit_reader lock */
+ /* acquire both md_unit_array_rw, and unit_reader lock */
un = trans_getun(migp->id, &migp->mde,
READERS, lock);
if (un == NULL)
@@ -2239,7 +2238,7 @@ trans_renexch_update_kids(
}
/*
- * MDRNM_SELF_UPDATE_FROM (exhange down) [self->child]
+ * MDRNM_SELF_UPDATE_FROM (exchange down) [self->child]
*/
void
trans_exchange_self_update_from_down(
@@ -2366,7 +2365,7 @@ trans_exchange_self_update_from_down(
}
/*
- * MDRNM_PARENT_UPDATE_TO (exhange down) [parent->self]
+ * MDRNM_PARENT_UPDATE_TO (exchange down) [parent->self]
*/
void
trans_exchange_parent_update_to(
diff --git a/usr/src/uts/common/io/physmem.c b/usr/src/uts/common/io/physmem.c
index 8a4cab75d1..8a9ca67db8 100644
--- a/usr/src/uts/common/io/physmem.c
+++ b/usr/src/uts/common/io/physmem.c
@@ -96,17 +96,17 @@ kmutex_t physmem_mutex; /* protects phsymem_vnodecnt */
static int physmem_getpage(struct vnode *vp, offset_t off, size_t len,
uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
- enum seg_rw rw, struct cred *cr);
+ enum seg_rw rw, struct cred *cr, caller_context_t *ct);
static int physmem_addmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- struct cred *cred);
+ struct cred *cred, caller_context_t *ct);
static int physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- struct cred *cred);
+ struct cred *cred, caller_context_t *ct);
-static void physmem_inactive(vnode_t *vp, cred_t *crp);
+static void physmem_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct);
const fs_operation_def_t physmem_vnodeops_template[] = {
VOPNAME_GETPAGE, { .vop_getpage = physmem_getpage },
@@ -334,7 +334,7 @@ physmem_setup_vnops()
* The guts of the PHYSMEM_SETUP ioctl.
* Create a segment in the address space with the specified parameters.
* If pspp->user_va is NULL, as_gap will be used to find an appropriate VA.
- * We do not do bounds checking on the requested phsycial addresses, if they
+ * We do not do bounds checking on the requested physical addresses, if they
* do not exist in the system, they will not be mappable.
* Returns 0 on success with the following error codes on failure:
* ENOMEM - The VA range requested was already mapped if pspp->user_va is
@@ -643,7 +643,7 @@ physmem_destroy_addrs(uint64_t p_cookie)
static int
physmem_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw,
- struct cred *cr)
+ struct cred *cr, caller_context_t *ct)
{
page_t *pp;
@@ -674,7 +674,7 @@ physmem_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
static int
physmem_addmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct)
{
if (curproc->p_as != as) {
return (EINVAL);
@@ -687,7 +687,7 @@ physmem_addmap(struct vnode *vp, offset_t off, struct as *as,
static int
physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
- struct cred *cred)
+ struct cred *cred, caller_context_t *ct)
{
/*
* Release our hold on the vnode so that the final VN_RELE will
@@ -703,7 +703,7 @@ physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
*/
/*ARGSUSED*/
static void
-physmem_inactive(vnode_t *vp, cred_t *crp)
+physmem_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
{
page_t *pp;
diff --git a/usr/src/uts/common/io/rsm/rsmops.c b/usr/src/uts/common/io/rsm/rsmops.c
index e69af1ad80..67319d2027 100644
--- a/usr/src/uts/common/io/rsm/rsmops.c
+++ b/usr/src/uts/common/io/rsm/rsmops.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -322,7 +321,7 @@ rsm_get_controller(const char *name, uint_t number,
mutex_enter(&rsmops_lock);
if (vp != NULL) {
(void) VOP_CLOSE(vp, FREAD|FWRITE, 0, 0,
- CRED());
+ CRED(), NULL);
VN_RELE(vp);
}
p_ctrl = find_rsmpi_controller(name, number);
@@ -534,7 +533,7 @@ rsmops_device_open(const char *major_name, const minor_t minor_num)
vp = makespecvp(makedevice(maj, minor_num), VCHR);
- ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED());
+ ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
if (ret == 0) {
return (vp);
} else {
diff --git a/usr/src/uts/common/io/sysmsg.c b/usr/src/uts/common/io/sysmsg.c
index e91648b722..0e7061c42f 100644
--- a/usr/src/uts/common/io/sysmsg.c
+++ b/usr/src/uts/common/io/sysmsg.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -339,7 +338,7 @@ bind_consadm_conf(char *path)
if (vn_open(path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0) != 0)
return;
vattr.va_mask = AT_SIZE;
- if ((err = VOP_GETATTR(vp, &vattr, 0, kcred)) != 0) {
+ if ((err = VOP_GETATTR(vp, &vattr, 0, kcred, NULL)) != 0) {
cmn_err(CE_WARN, "sysmsg: getattr: '%s': error %d",
path, err);
goto closevp;
@@ -358,7 +357,7 @@ bind_consadm_conf(char *path)
kmem_free(buf, size);
closevp:
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, kcred, NULL);
VN_RELE(vp);
}
@@ -446,7 +445,7 @@ sysmclose(dev_t dev, int flag, int state, cred_t *cred)
return (0);
}
- (void) VOP_CLOSE(dcvp, FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(dcvp, FWRITE, 1, (offset_t)0, kcred, NULL);
VN_RELE(dcvp);
dcvp = NULL;
mutex_exit(&dcvp_mutex);
@@ -459,7 +458,7 @@ sysmclose(dev_t dev, int flag, int state, cred_t *cred)
rw_enter(&sysmcache[i].dca_lock, RW_WRITER);
if (sysmcache[i].dca_vp != NULL) {
(void) VOP_CLOSE(sysmcache[i].dca_vp, flag,
- 1, (offset_t)0, cred);
+ 1, (offset_t)0, cred, NULL);
VN_RELE(sysmcache[i].dca_vp);
sysmcache[i].dca_vp = NULL;
}
@@ -565,7 +564,7 @@ sysmioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred, int *rvalp)
}
default:
/* everything else is sent to the console device */
- return (VOP_IOCTL(dcvp, cmd, arg, flag, cred, rvalp));
+ return (VOP_IOCTL(dcvp, cmd, arg, flag, cred, rvalp, NULL));
}
if ((rval = secpolicy_console(cred)) != 0)
@@ -694,7 +693,7 @@ static int
sysmpoll(dev_t dev, short events, int anyyet, short *reventsp,
struct pollhead **phpp)
{
- return (VOP_POLL(dcvp, events, anyyet, reventsp, phpp));
+ return (VOP_POLL(dcvp, events, anyyet, reventsp, phpp, NULL));
}
/* Sanity check that the device is good */
diff --git a/usr/src/uts/common/ipp/ipgpc/classifier.c b/usr/src/uts/common/ipp/ipgpc/classifier.c
index 4f329c9d1b..bb09a3ca89 100644
--- a/usr/src/uts/common/ipp/ipgpc/classifier.c
+++ b/usr/src/uts/common/ipp/ipgpc/classifier.c
@@ -71,7 +71,7 @@ static void get_port_info(ipgpc_packet_t *, void *, int, mblk_t *);
* common_classify(packet, fid_table, slctrs_srchd)
*
* searches each of the common selectors
- * - will return NORMAL_MATCH on sucess. NO_MATCHES on error
+ * - will return NORMAL_MATCH on success. NO_MATCHES on error
*/
static int
common_classify(ipgpc_packet_t *packet, ht_match_t *fid_table,
diff --git a/usr/src/uts/common/ipp/ipgpc/filters.c b/usr/src/uts/common/ipp/ipgpc/filters.c
index 2add8eba6a..7dd4dce48e 100644
--- a/usr/src/uts/common/ipp/ipgpc/filters.c
+++ b/usr/src/uts/common/ipp/ipgpc/filters.c
@@ -1300,7 +1300,7 @@ ipgpc_addclass(ipgpc_class_t *in_class, ipp_flags_t flags) {
* - number of bytes that matched this class
* - number of packets that matched this class
* - time in hrtime of last match for this class
- * any failures are returned, zero on sucess
+ * any failures are returned, zero on success
*/
static int
class_statinit(ipgpc_class_t *in_class, int in_class_id)
@@ -1742,7 +1742,7 @@ ipgpc_modifyfilter(nvlist_t **nvlpp, ipp_flags_t flags)
if (ret == 0) { /* no error, add filter */
ret = ipgpc_addfilter(filter, name, flags);
if (ret != 0) {
- /* error occured, free filter fields */
+ /* error occurred, free filter fields */
ipgpc0dbg(("ipgpc_modifyfilter: invalid " \
"filter given, unable to modify " \
"existing filter %s",
@@ -1756,7 +1756,7 @@ ipgpc_modifyfilter(nvlist_t **nvlpp, ipp_flags_t flags)
}
ipgpc_filter_destructor(&old_filter);
} else {
- ipgpc0dbg(("ipgpc_modifyfilter: error %d occured " \
+ ipgpc0dbg(("ipgpc_modifyfilter: error %d occurred " \
"when modifying filter", ret));
ipgpc_filter_destructor(&old_filter);
ipgpc_filter_destructor(filter);
@@ -1863,7 +1863,7 @@ ipgpc_modifyclass(nvlist_t **nvlpp, ipp_flags_t flags)
if ((rc = ipp_action_ref(ipgpc_aid,
in_class.next_action, 0)) != 0) {
ipgpc0dbg(("ipgpc_modifyclass: error " \
- "occured while adding a reference to " \
+ "occurred while adding a reference to " \
"the new next_action %d",
in_class.next_action));
mutex_exit(&ipgpc_cid_list_lock);
diff --git a/usr/src/uts/common/krtld/kobj.c b/usr/src/uts/common/krtld/kobj.c
index 7a0427265e..deffd012bd 100644
--- a/usr/src/uts/common/krtld/kobj.c
+++ b/usr/src/uts/common/krtld/kobj.c
@@ -217,7 +217,7 @@ static kmutex_t kobj_lock; /* protects mach memory list */
* The following functions have been implemented by the kernel.
* However, many 3rd party drivers provide their own implementations
* of these functions. When such drivers are loaded, messages
- * indicateing that these symbols have been mulply defined will be
+ * indicating that these symbols have been multiply defined will be
* emitted to the console. To avoid alarming customers for no good
* reason, we simply suppress such warnings for the following set of
* functions.
@@ -804,7 +804,7 @@ load_exec(val_t *bootaux, char *filename)
allocsize += MAXPATHLEN;
}
bcopy(libname, mp->depends_on + osize, lsize);
- *(mp->depends_on + nsize) = ' '; /* seperate */
+ *(mp->depends_on + nsize) = ' '; /* separate */
nsize++;
osize = nsize;
}
@@ -1760,7 +1760,7 @@ process_dynamic(struct module *mp, char *dyndata, char *strdata)
* finish up the depends string (if any)
*/
if (depstr != NULL) {
- *(depstr + nsize - 1) = '\0'; /* overwrite seperator w/term */
+ *(depstr + nsize - 1) = '\0'; /* overwrite separator w/term */
if (path != NULL)
kobj_free(path, MAXPATHLEN);
@@ -3577,7 +3577,7 @@ kobj_open(char *filename)
cred_t *saved_cred = curthread->t_cred;
curthread->t_cred = kcred;
Errno = vn_openat(filename, UIO_SYSSPACE, FREAD, 0, &vp,
- 0, 0, rootdir);
+ 0, 0, rootdir, -1);
curthread->t_cred = saved_cred;
}
kobjopen_free(ltp);
@@ -3704,7 +3704,7 @@ kobj_close(intptr_t descr)
if (_modrootloaded) {
struct vnode *vp = (struct vnode *)descr;
- (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
} else
(void) kobj_boot_close((int)descr);
@@ -3719,7 +3719,7 @@ kobj_fstat(intptr_t descr, struct bootstat *buf)
if (_modrootloaded) {
vattr_t vattr;
struct vnode *vp = (struct vnode *)descr;
- if (VOP_GETATTR(vp, &vattr, 0, kcred) != 0)
+ if (VOP_GETATTR(vp, &vattr, 0, kcred, NULL) != 0)
return (-1);
/*
diff --git a/usr/src/uts/common/ktli/t_kopen.c b/usr/src/uts/common/ktli/t_kopen.c
index c49b03b610..c373d4a7f9 100644
--- a/usr/src/uts/common/ktli/t_kopen.c
+++ b/usr/src/uts/common/ktli/t_kopen.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -124,7 +123,8 @@ t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
* might fail due to temporarely out of memory.
*/
do {
- if ((error = VOP_OPEN(&vp, flags, cr)) == EAGAIN) {
+ if ((error = VOP_OPEN(&vp, flags, cr, NULL))
+ == EAGAIN) {
(void) delay(hz);
}
} while (error == EAGAIN && ++rtries < 5);
diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h
index 03c32254b7..265b02d315 100644
--- a/usr/src/uts/common/nfs/nfs.h
+++ b/usr/src/uts/common/nfs/nfs.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -254,7 +254,7 @@ extern bool_t nfs_allow_preepoch_time;
* If no negative otw values are allowed, may use the full 32-bits of the
* time to represent time later than 2038, by presenting the value as an
* unsigned (but this can only be used by 64-bit apps due to cstat32
- * retrictions). If negative values are allowed, cannot represent times
+ * restrictions). If negative values are allowed, cannot represent times
* after 2038. Either way, all 32 bits have a valid representation.
*/
@@ -496,7 +496,7 @@ struct nfsfattr {
uint32_t na_uid; /* owner user id */
uint32_t na_gid; /* owner group id */
uint32_t na_size; /* file size in bytes */
- uint32_t na_blocksize; /* prefered block size */
+ uint32_t na_blocksize; /* preferred block size */
uint32_t na_rdev; /* special device # */
uint32_t na_blocks; /* Kb of disk used by file */
uint32_t na_fsid; /* device # */
@@ -907,7 +907,7 @@ extern int nfsinit(int, char *);
extern void nfsfini(void);
extern int nfs_vfsinit(void);
extern void nfs_vfsfini(void);
-extern int nfs_dump(vnode_t *, caddr_t, int, int);
+extern int nfs_dump(vnode_t *, caddr_t, int, int, caller_context_t *);
extern void nfs_perror(int error, char *fmt, ...);
extern void nfs_cmn_err(int error, int level, char *fmt, ...);
extern int nfs_addcllock(vnode_t *vp, struct flock64 *bfp);
diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h
index 2000cac44f..b9a76a2d43 100644
--- a/usr/src/uts/common/nfs/nfs4.h
+++ b/usr/src/uts/common/nfs/nfs4.h
@@ -858,7 +858,8 @@ extern nfsstat4 rfs4_get_deleg_state(stateid4 *,
extern nfsstat4 rfs4_get_lo_state(stateid4 *, rfs4_lo_state_t **,
bool_t);
extern nfsstat4 rfs4_check_stateid(int, vnode_t *, stateid4 *,
- bool_t, bool_t *, bool_t);
+ bool_t, bool_t *, bool_t,
+ caller_context_t *);
extern int rfs4_check_stateid_seqid(rfs4_state_t *, stateid4 *);
extern int rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *,
stateid4 *);
@@ -908,8 +909,8 @@ extern void rfs4_clear_dont_grant(rfs4_file_t *);
/*
* nfs4 monitored operations.
*/
-extern int deleg_rdopen(femarg_t *, int, cred_t *);
-extern int deleg_wropen(femarg_t *, int, cred_t *);
+extern int deleg_rdopen(femarg_t *, int, cred_t *, caller_context_t *);
+extern int deleg_wropen(femarg_t *, int, cred_t *, caller_context_t *);
extern int deleg_rd_rwlock(femarg_t *, int, caller_context_t *);
extern int deleg_wr_rwlock(femarg_t *, int, caller_context_t *);
extern int deleg_read(femarg_t *, uio_t *, int, cred_t *, caller_context_t *);
@@ -918,8 +919,10 @@ extern int deleg_setattr(femarg_t *, vattr_t *, int, cred_t *,
caller_context_t *);
extern int deleg_space(femarg_t *, int, flock64_t *, int, offset_t, cred_t *,
caller_context_t *);
-extern int deleg_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *);
-extern int deleg_vnevent(femarg_t *, vnevent_t, vnode_t *, char *);
+extern int deleg_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int deleg_vnevent(femarg_t *, vnevent_t, vnode_t *, char *,
+ caller_context_t *);
extern void rfs4_mon_hold(void *);
extern void rfs4_mon_rele(void *);
diff --git a/usr/src/uts/common/nfs/rnode.h b/usr/src/uts/common/nfs/rnode.h
index e4eb0cee5c..63d38ba6ee 100644
--- a/usr/src/uts/common/nfs/rnode.h
+++ b/usr/src/uts/common/nfs/rnode.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -334,7 +334,7 @@ extern void nfs_async_commit(vnode_t *, page_t *, offset3, count3,
cred_t *, void (*)(vnode_t *, page_t *,
offset3, count3, cred_t *));
extern void nfs_async_inactive(vnode_t *, cred_t *, void (*)(vnode_t *,
- cred_t *));
+ cred_t *, caller_context_t *));
extern int writerp(rnode_t *, caddr_t, int, struct uio *, int);
extern int nfs_putpages(vnode_t *, u_offset_t, size_t, int, cred_t *);
extern void nfs_invalidate_pages(vnode_t *, u_offset_t, cred_t *);
diff --git a/usr/src/uts/common/os/acct.c b/usr/src/uts/common/os/acct.c
index c596ce45f3..a8da2f8fb0 100644
--- a/usr/src/uts/common/os/acct.c
+++ b/usr/src/uts/common/os/acct.c
@@ -130,7 +130,8 @@ acct_shutdown(zoneid_t zoneid, void *arg)
* held vnode may cause filesystems to be busy, and the zone
* shutdown operation to fail.
*/
- (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred,
+ NULL);
VN_RELE(ag->acctvp);
}
ag->acctvp = NULL;
@@ -211,7 +212,7 @@ acct_find(vnode_t *vp, boolean_t compare_vfs)
ASSERT(MUTEX_HELD(&acct_list_lock));
ASSERT(vp != NULL);
- if (VOP_REALVP(vp, &realvp))
+ if (VOP_REALVP(vp, &realvp, NULL))
realvp = vp;
for (ag = list_head(&acct_list); ag != NULL;
ag = list_next(&acct_list, ag)) {
@@ -223,7 +224,7 @@ acct_find(vnode_t *vp, boolean_t compare_vfs)
mutex_exit(&ag->aclock);
continue;
}
- if (VOP_REALVP(ag->acctvp, &racctvp))
+ if (VOP_REALVP(ag->acctvp, &racctvp, NULL))
racctvp = ag->acctvp;
if (compare_vfs) {
if (racctvp->v_vfsp == realvp->v_vfsp)
@@ -281,7 +282,8 @@ sysacct(char *fname)
ag->acctvp = NULL;
mutex_exit(&ag->aclock);
if (vp) {
- error = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ error = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(),
+ NULL);
VN_RELE(vp);
}
return (error == 0 ? 0 : set_errno(error));
@@ -333,7 +335,7 @@ sysacct(char *fname)
}
if (vp) {
- (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
}
return (error == 0 ? 0 : set_errno(error));
@@ -425,7 +427,7 @@ acct(char st)
* currently large file aware.
*/
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, 0, kcred) == 0) {
+ if (VOP_GETATTR(vp, &va, 0, kcred, NULL) == 0) {
error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&ag->acctbuf,
sizeof (ag->acctbuf), 0LL, UIO_SYSSPACE, FAPPEND,
(rlim64_t)MAXOFF32_T, kcred, &resid);
diff --git a/usr/src/uts/common/os/core.c b/usr/src/uts/common/os/core.c
index 4adac80e93..71af0012d4 100644
--- a/usr/src/uts/common/os/core.c
+++ b/usr/src/uts/common/os/core.c
@@ -159,16 +159,16 @@ remove_core_file(char *fp, enum core_types core_type)
else if ((dvfsp = dvp->v_vfsp) != NULL &&
(dvfsp->vfs_flag & VFS_RDONLY))
error = EROFS;
- else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED())) == 0) {
+ else if ((error = VOP_ACCESS(vp, VWRITE, 0, CRED(), NULL)) == 0) {
if (nbl_need_check(vp)) {
nbl_start_crit(vp, RW_READER);
in_crit = 1;
- if (nbl_share_conflict(vp, NBL_REMOVE)) {
+ if (nbl_share_conflict(vp, NBL_REMOVE, NULL)) {
error = EACCES;
}
}
if (!error) {
- error = VOP_REMOVE(dvp, pn.pn_path, CRED());
+ error = VOP_REMOVE(dvp, pn.pn_path, CRED(), NULL, 0);
}
}
@@ -254,8 +254,9 @@ create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
pn_setlast(&pn);
file = pn.pn_path;
}
- error = vn_openat(file, UIO_SYSSPACE, FWRITE | FTRUNC | FEXCL |
- FCREAT | FOFFMAX, perms, &vp, CRCREAT, PTOU(curproc)->u_cmask, dvp);
+ error = vn_openat(file, UIO_SYSSPACE,
+ FWRITE | FTRUNC | FEXCL | FCREAT | FOFFMAX,
+ perms, &vp, CRCREAT, PTOU(curproc)->u_cmask, dvp, -1);
if (core_type != CORE_PROC) {
VN_RELE(dvp);
pn_free(&pn);
@@ -265,10 +266,10 @@ create_core_file(char *fp, enum core_types core_type, vnode_t **vpp)
*/
vattr.va_mask = AT_UID;
if (error == 0 &&
- (VOP_GETATTR(vp, &vattr, 0, credp) != 0 ||
+ (VOP_GETATTR(vp, &vattr, 0, credp, NULL) != 0 ||
vattr.va_uid != crgetuid(credp))) {
(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0,
- credp);
+ credp, NULL);
VN_RELE(vp);
(void) remove_core_file(fp, core_type);
error = EACCES;
@@ -448,7 +449,7 @@ do_core(char *fp, int sig, enum core_types core_type, struct core_globals *cg)
rw_exit(eswp->exec_lock);
}
- closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp);
+ closerr = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, credp, NULL);
VN_RELE(vp);
if (error == 0)
error = closerr;
diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c
index 349c4f3c12..c6a1f1fabb 100644
--- a/usr/src/uts/common/os/cred.c
+++ b/usr/src/uts/common/os/cred.c
@@ -56,11 +56,13 @@
#include <sys/prsystm.h>
#include <sys/modctl.h>
#include <sys/avl.h>
+#include <sys/door.h>
#include <c2/audit.h>
#include <sys/zone.h>
#include <sys/tsol/label.h>
#include <sys/sid.h>
#include <sys/idmap.h>
+#include <sys/varargs.h>
typedef struct ephidmap_data {
uid_t min_uid, last_uid;
@@ -1028,8 +1030,8 @@ eph_gid_alloc(int flags, gid_t *start, int count)
}
/*
- * If the credential contains any ephemeral IDs, map the credential
- * to nobody.
+ * If the credential user SID or group SID is mapped to an ephemeral
+ * ID, map the credential to nobody.
*/
cred_t *
crgetmapped(const cred_t *cr)
@@ -1042,15 +1044,11 @@ crgetmapped(const cred_t *cr)
return (NULL);
if (cr->cr_ksid != NULL) {
- int i;
-
- for (i = 0; i < KSID_COUNT; i++)
- if (cr->cr_ksid->kr_sidx[i].ks_id > MAXUID)
- return (ephemeral_data.nobody);
- if (cr->cr_ksid->kr_sidlist != NULL &&
- cr->cr_ksid->kr_sidlist->ksl_neid > 0) {
- return (ephemeral_data.nobody);
- }
+ if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID)
+ return (ephemeral_data.nobody);
+
+ if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID)
+ return (ephemeral_data.nobody);
}
return ((cred_t *)cr);
@@ -1088,7 +1086,38 @@ crgetsid(const cred_t *cr, int i)
ksidlist_t *
crgetsidlist(const cred_t *cr)
{
- if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidlist != NULL)
+ if (cr->cr_ksid != NULL)
return (cr->cr_ksid->kr_sidlist);
return (NULL);
}
+
+/*
+ * Interface to set the effective and permitted privileges for
+ * a credential; this interface does no security checks and is
+ * intended for kernel (file)servers creating credentials with
+ * specific privileges.
+ */
+int
+crsetpriv(cred_t *cr, ...)
+{
+ va_list ap;
+ const char *privnm;
+
+ ASSERT(cr->cr_ref <= 2);
+
+ priv_set_PA(cr);
+
+ va_start(ap, cr);
+
+ while ((privnm = va_arg(ap, const char *)) != NULL) {
+ int priv = priv_getbyname(privnm, 0);
+ if (priv < 0)
+ return (-1);
+
+ priv_addset(&CR_PPRIV(cr), priv);
+ priv_addset(&CR_EPRIV(cr), priv);
+ }
+ priv_adjust_PA(cr);
+ va_end(ap);
+ return (0);
+}
diff --git a/usr/src/uts/common/os/devcache.c b/usr/src/uts/common/os/devcache.c
index 8e1313d487..75ed982940 100644
--- a/usr/src/uts/common/os/devcache.c
+++ b/usr/src/uts/common/os/devcache.c
@@ -75,7 +75,7 @@
* The data per client is entirely within the control of
* the client. When reading, data unpacked from the backing
* store should be inserted in the list. The pointer to
- * the list can be retreived via nvf_list(). When writing,
+ * the list can be retrieved via nvf_list(). When writing,
* the data on the list is to be packed and returned to the
* nvpdaemon as an nvlist.
*
@@ -618,7 +618,7 @@ kfclose(kfile_t *fp)
KFDEBUG((CE_CONT, "close: %s\n", fp->kf_fname));
if ((fp->kf_vnflags & FWRITE) && fp->kf_state == 0) {
- rval = VOP_FSYNC(fp->kf_vp, FSYNC, kcred);
+ rval = VOP_FSYNC(fp->kf_vp, FSYNC, kcred, NULL);
if (rval != 0) {
nvf_error("%s: sync error %d\n",
fp->kf_fname, rval);
@@ -626,7 +626,8 @@ kfclose(kfile_t *fp)
KFDEBUG((CE_CONT, "%s: sync ok\n", fp->kf_fname));
}
- rval = VOP_CLOSE(fp->kf_vp, fp->kf_vnflags, 1, (offset_t)0, kcred);
+ rval = VOP_CLOSE(fp->kf_vp, fp->kf_vnflags, 1, (offset_t)0, kcred,
+ NULL);
if (rval != 0) {
if (fp->kf_state == 0) {
nvf_error("%s: close error %d\n",
diff --git a/usr/src/uts/common/os/driver.c b/usr/src/uts/common/os/driver.c
index 6526113828..3de2712c4c 100644
--- a/usr/src/uts/common/os/driver.c
+++ b/usr/src/uts/common/os/driver.c
@@ -297,7 +297,7 @@ dev_lopen(dev_t *devp, int flag, int otype, struct cred *cred)
struct vnode *cvp;
vp = makespecvp(*devp, (otype == OTYP_BLK) ? VBLK : VCHR);
- error = VOP_OPEN(&vp, flag | FKLYR, cred);
+ error = VOP_OPEN(&vp, flag | FKLYR, cred, NULL);
if (error == 0) {
/* Pick up the (possibly) new dev_t value. */
*devp = vp->v_rdev;
@@ -332,13 +332,13 @@ dev_lclose(dev_t dev, int flag, int otype, struct cred *cred)
ulong_t offset;
vp = makespecvp(dev, (otype == OTYP_BLK) ? VBLK : VCHR);
- error = VOP_CLOSE(vp, flag | FKLYR, 1, (offset_t)0, cred);
+ error = VOP_CLOSE(vp, flag | FKLYR, 1, (offset_t)0, cred, NULL);
/*
* Release the extra dev_lopen hold on the common vnode. We inline a
* VN_RELE(cvp) call so that we can detect more dev_lclose calls than
* dev_lopen calls without panic. See vn_rele. If our inline of
- * vn_rele called VOP_INACTIVE(cvp, CRED()) we would panic on the
+ * vn_rele called VOP_INACTIVE(cvp, CRED(), ...) we would panic on the
* "release the makespecvp vnode" VN_RELE(vp) that follows - so
* instead we diagnose this situation. Note that the driver has
* still seen a double close(9E), but that would have occurred with
diff --git a/usr/src/uts/common/os/driver_lyr.c b/usr/src/uts/common/os/driver_lyr.c
index 266e3cbb79..66e9f58e35 100644
--- a/usr/src/uts/common/os/driver_lyr.c
+++ b/usr/src/uts/common/os/driver_lyr.c
@@ -757,7 +757,7 @@ ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
return (ENXIO);
/* open the device */
- if ((err = VOP_OPEN(&vp, flag | FKLYR, cr)) != 0)
+ if ((err = VOP_OPEN(&vp, flag | FKLYR, cr, NULL)) != 0)
return (err);
/* possible clone open, make sure that we still have a spec node */
@@ -783,7 +783,7 @@ ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
vnode_t *cvp = common_specvp(nlhp->lh_vp);
dev_t dev = cvp->v_rdev;
- (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
+ (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred, NULL);
bflush(dev);
}
@@ -945,7 +945,7 @@ i_check_string(char *str, int prop_len)
/*
* i_pack_string_array takes a a string array property that is represented
- * as a concatination of strings (with the NULL character included for
+ * as a concatenation of strings (with the NULL character included for
* each string) and converts it into a format that can be returned by
* ldi_prop_lookup_string_array.
*/
@@ -1258,7 +1258,7 @@ ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
}
/*
- * ldi_mlink_fp() is invoked for all successfull streams linkages created
+ * ldi_mlink_fp() is invoked for all successful streams linkages created
* via I_LINK and I_PLINK. ldi_mlink_fp() records the linkage information
* in its internal state so that the devinfo snapshot code has some
* observability into streams device linkage information.
@@ -1693,7 +1693,7 @@ ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
vnode_t *cvp = common_specvp(handlep->lh_vp);
dev_t dev = cvp->v_rdev;
- (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
+ (void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred, NULL);
bflush(dev);
}
@@ -1727,7 +1727,7 @@ ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
#endif
/* do a layered close on the device */
- err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr);
+ err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr, NULL);
LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
@@ -2903,7 +2903,7 @@ ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
*
* NDI events: These are events which are serviced by the NDI event subsystem.
* LDI subsystem just provides a thin wrapper around the NDI event interfaces
- * These events are thereefore *not* native events.
+ * These events are therefore *not* native events.
*/
static int
diff --git a/usr/src/uts/common/os/dumpsubr.c b/usr/src/uts/common/os/dumpsubr.c
index 8dd63a298b..b8dba61893 100644
--- a/usr/src/uts/common/os/dumpsubr.c
+++ b/usr/src/uts/common/os/dumpsubr.c
@@ -206,11 +206,11 @@ dumpinit(vnode_t *vp, char *name, int justchecking)
* (1) a real device that's not mounted and has a cb_dump routine, or
* (2) a swapfile on some filesystem that has a vop_dump routine.
*/
- if ((error = VOP_OPEN(&cvp, FREAD | FWRITE, kcred)) != 0)
+ if ((error = VOP_OPEN(&cvp, FREAD | FWRITE, kcred, NULL)) != 0)
return (error);
vattr.va_mask = AT_SIZE | AT_TYPE | AT_RDEV;
- if ((error = VOP_GETATTR(cvp, &vattr, 0, kcred)) == 0) {
+ if ((error = VOP_GETATTR(cvp, &vattr, 0, kcred, NULL)) == 0) {
if (vattr.va_type == VBLK || vattr.va_type == VCHR) {
if (devopsp[getmajor(vattr.va_rdev)]->
devo_cb_ops->cb_dump == nodev)
@@ -228,7 +228,8 @@ dumpinit(vnode_t *vp, char *name, int justchecking)
error = ENOSPC;
if (error || justchecking) {
- (void) VOP_CLOSE(cvp, FREAD | FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(cvp, FREAD | FWRITE, 1, (offset_t)0,
+ kcred, NULL);
return (error);
}
@@ -251,24 +252,26 @@ dumpinit(vnode_t *vp, char *name, int justchecking)
*/
if (cvp->v_type == VBLK &&
(cdev_vp = makespecvp(VTOS(cvp)->s_dev, VCHR)) != NULL) {
- if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred) == 0) {
+ if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred, NULL) == 0) {
size_t blk_size;
struct dk_cinfo dki;
struct vtoc vtoc;
if (VOP_IOCTL(cdev_vp, DKIOCGVTOC, (intptr_t)&vtoc,
- FKIOCTL, kcred, NULL) == 0 && vtoc.v_sectorsz != 0)
+ FKIOCTL, kcred, NULL, NULL) == 0 &&
+ vtoc.v_sectorsz != 0)
blk_size = vtoc.v_sectorsz;
else
blk_size = DEV_BSIZE;
if (VOP_IOCTL(cdev_vp, DKIOCINFO, (intptr_t)&dki,
- FKIOCTL, kcred, NULL) == 0) {
+ FKIOCTL, kcred, NULL, NULL) == 0) {
dump_iosize = dki.dki_maxtransfer * blk_size;
dumpbuf_resize();
}
- (void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0, kcred);
+ (void) VOP_CLOSE(cdev_vp, FREAD | FWRITE, 1, 0,
+ kcred, NULL);
}
VN_RELE(cdev_vp);
@@ -286,7 +289,7 @@ dumpfini(void)
kmem_free(dumppath, strlen(dumppath) + 1);
- (void) VOP_CLOSE(dumpvp, FREAD | FWRITE, 1, (offset_t)0, kcred);
+ (void) VOP_CLOSE(dumpvp, FREAD | FWRITE, 1, (offset_t)0, kcred, NULL);
VN_RELE(dumpvp);
@@ -334,7 +337,7 @@ dumpvp_flush(void)
} else if (size != 0) {
if (panicstr)
err = VOP_DUMP(dumpvp, dumpbuf_start,
- lbtodb(dumpvp_off), btod(size));
+ lbtodb(dumpvp_off), btod(size), NULL);
else
err = vn_rdwr(UIO_WRITE, dumpvp, dumpbuf_start, size,
dumpvp_off, UIO_SYSSPACE, 0, dumpvp_limit,
@@ -478,7 +481,7 @@ dump_ereports(void)
if (!panicstr) {
(void) VOP_PUTPAGE(dumpvp, dumpvp_start,
(size_t)(dumpvp_off - dumpvp_start),
- B_INVAL | B_FORCE, kcred);
+ B_INVAL | B_FORCE, kcred, NULL);
}
}
@@ -521,7 +524,7 @@ dump_messages(void)
if (!panicstr) {
(void) VOP_PUTPAGE(dumpvp, dumpvp_start,
(size_t)(dumpvp_off - dumpvp_start),
- B_INVAL | B_FORCE, kcred);
+ B_INVAL | B_FORCE, kcred, NULL);
}
}
@@ -600,8 +603,8 @@ dumpsys(void)
if (panicstr) {
dumphdr->dump_flags &= ~DF_LIVE;
- (void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL);
- (void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL);
+ (void) VOP_DUMPCTL(dumpvp, DUMP_FREE, NULL, NULL);
+ (void) VOP_DUMPCTL(dumpvp, DUMP_ALLOC, NULL, NULL);
(void) vsnprintf(dumphdr->dump_panicstring, DUMP_PANICSIZE,
panicstr, panicargs);
}
diff --git a/usr/src/uts/common/os/exacct.c b/usr/src/uts/common/os/exacct.c
index 88e532d691..6e27952402 100644
--- a/usr/src/uts/common/os/exacct.c
+++ b/usr/src/uts/common/os/exacct.c
@@ -181,7 +181,7 @@ exacct_vn_write(ac_info_t *info, void *buf, ssize_t bufsize)
* the present accounting file.
*/
va.va_mask = AT_SIZE;
- error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred);
+ error = VOP_GETATTR(info->ac_vnode, &va, 0, kcred, NULL);
if (error == 0) {
error = vn_rdwr(UIO_WRITE, info->ac_vnode, (caddr_t)buf,
bufsize, 0LL, UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFFSET_T,
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 652a01c34c..8823e44e27 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -538,7 +538,7 @@ gexec(
goto bad;
/* need to open vnode for stateful file systems like rfs */
- if ((error = VOP_OPEN(vpp, FREAD, CRED())) != 0)
+ if ((error = VOP_OPEN(vpp, FREAD, CRED(), NULL)) != 0)
goto bad;
vp = *vpp;
@@ -934,13 +934,13 @@ execpermissions(struct vnode *vp, struct vattr *vattrp, struct uarg *args)
proc_t *p = ttoproc(curthread);
vattrp->va_mask = AT_MODE | AT_UID | AT_GID | AT_SIZE;
- if (error = VOP_GETATTR(vp, vattrp, ATTR_EXEC, p->p_cred))
+ if (error = VOP_GETATTR(vp, vattrp, ATTR_EXEC, p->p_cred, NULL))
return (error);
/*
* Check the access mode.
* If VPROC, ask /proc if the file is an object file.
*/
- if ((error = VOP_ACCESS(vp, VEXEC, 0, p->p_cred)) != 0 ||
+ if ((error = VOP_ACCESS(vp, VEXEC, 0, p->p_cred, NULL)) != 0 ||
!(vp->v_type == VREG || (vp->v_type == VPROC && pr_isobject(vp))) ||
(vp->v_vfsp->vfs_flag & VFS_NOEXEC) != 0 ||
(vattrp->va_mode & (VEXEC|(VEXEC>>3)|(VEXEC>>6))) == 0) {
@@ -950,7 +950,7 @@ execpermissions(struct vnode *vp, struct vattr *vattrp, struct uarg *args)
}
if ((p->p_plist || (p->p_proc_flag & (P_PR_PTRACE|P_PR_TRACE))) &&
- (error = VOP_ACCESS(vp, VREAD, 0, p->p_cred))) {
+ (error = VOP_ACCESS(vp, VREAD, 0, p->p_cred, NULL))) {
/*
* If process is under ptrace(2) compatibility,
* fail the exec(2).
@@ -1011,7 +1011,7 @@ execmap(struct vnode *vp, caddr_t addr, size_t len, size_t zfodlen,
}
if (error = VOP_MAP(vp, (offset_t)offset,
p->p_as, &addr, len, prot, PROT_ALL,
- mflag, CRED()))
+ mflag, CRED(), NULL))
goto bad;
/*
@@ -1188,7 +1188,7 @@ execopen(struct vnode **vpp, int *fdp)
*fdp = -1; /* just in case falloc changed value */
return (error);
}
- if (error = VOP_OPEN(&vp, filemode, CRED())) {
+ if (error = VOP_OPEN(&vp, filemode, CRED(), NULL)) {
VN_RELE(vp);
setf(*fdp, NULL);
unfalloc(fp);
diff --git a/usr/src/uts/common/os/fio.c b/usr/src/uts/common/os/fio.c
index b31c9c7c2e..c5dc56e150 100644
--- a/usr/src/uts/common/os/fio.c
+++ b/usr/src/uts/common/os/fio.c
@@ -23,7 +23,7 @@
/* All Rights Reserved */
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -918,7 +918,7 @@ closef(file_t *fp)
vp = fp->f_vnode;
- error = VOP_CLOSE(vp, flag, count, offset, fp->f_cred);
+ error = VOP_CLOSE(vp, flag, count, offset, fp->f_cred, NULL);
if (count > 1) {
mutex_exit(&fp->f_tlock);
@@ -1348,7 +1348,7 @@ fassign(vnode_t **vpp, int mode, int *fdp)
if (error = falloc((vnode_t *)NULL, mode, &fp, &fd))
return (error);
- if (error = VOP_OPEN(vpp, mode, fp->f_cred)) {
+ if (error = VOP_OPEN(vpp, mode, fp->f_cred, NULL)) {
setf(fd, NULL);
unfalloc(fp);
return (error);
@@ -1506,14 +1506,15 @@ vpsetattr(vnode_t *vp, vattr_t *vap, int flags)
nbl_start_crit(vp, RW_READER);
in_crit = 1;
vattr.va_mask = AT_SIZE;
- if (!(error = VOP_GETATTR(vp, &vattr, 0, CRED()))) {
+ if (!(error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
begin = vap->va_size > vattr.va_size ?
vattr.va_size : vap->va_size;
length = vattr.va_size > vap->va_size ?
vattr.va_size - vap->va_size :
vap->va_size - vattr.va_size;
- if (nbl_conflict(vp, NBL_WRITE, begin, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, begin, length, 0,
+ NULL)) {
error = EACCES;
}
}
diff --git a/usr/src/uts/common/os/flock.c b/usr/src/uts/common/os/flock.c
index a3028b75dc..da81003d1c 100644
--- a/usr/src/uts/common/os/flock.c
+++ b/usr/src/uts/common/os/flock.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
/* ONC_PLUS EXTRACT START */
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -201,7 +200,7 @@ static int level_one_path(lock_descriptor_t *, lock_descriptor_t *);
static int level_two_path(lock_descriptor_t *, lock_descriptor_t *, int);
#endif
-/* proc_graph function definitons */
+/* proc_graph function definitions */
static int flk_check_deadlock(lock_descriptor_t *);
static void flk_proc_graph_uncolor(void);
static proc_vertex_t *flk_get_proc_vertex(lock_descriptor_t *);
@@ -684,7 +683,7 @@ flk_zone_fini(zoneid_t zoneid, void *data)
}
/*
- * Get a lock_descriptor structure with initialisation of edge lists.
+ * Get a lock_descriptor structure with initialization of edge lists.
*/
static lock_descriptor_t *
@@ -727,14 +726,14 @@ flk_set_state(lock_descriptor_t *lock, int new_state)
{
/*
* Locks in the sleeping list may be woken up in a number of ways,
- * and more than once. If a sleeping lock is signalled awake more
+ * and more than once. If a sleeping lock is signaled awake more
* than once, then it may or may not change state depending on its
* current state.
* Also note that NLM locks that are sleeping could be moved to an
* interrupted state more than once if the unlock request is
* retransmitted by the NLM client - the second time around, this is
* just a nop.
- * The ordering of being signalled awake is:
+ * The ordering of being signaled awake is:
* INTERRUPTED_STATE > CANCELLED_STATE > GRANTED_STATE.
* The checks below implement this ordering.
*/
@@ -2671,7 +2670,7 @@ convoff(vp, lckdat, whence, offset)
if ((lckdat->l_whence == 2) || (whence == 2)) {
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
}
@@ -3271,7 +3270,7 @@ flk_set_lockmgr_status(flk_lockmgr_status_t status)
*
* A list containing the vnode pointer and an flock structure
* describing the lock is returned. Each element in the list is
- * dynammically allocated and must be freed by the caller. The
+ * dynamically allocated and must be freed by the caller. The
* last item in the list is denoted by a NULL value in the ll_next
* field.
*
@@ -3721,7 +3720,7 @@ wait_for_lock(lock_descriptor_t *request)
* Create an flock structure from the existing lock information
*
* This routine is used to create flock structures for the lock manager
- * to use in a reclaim request. Since the lock was orginated on this
+ * to use in a reclaim request. Since the lock was originated on this
* host, it must be conforming to UNIX semantics, so no checking is
* done to make sure it falls within the lower half of the 32-bit range.
*/
@@ -3768,7 +3767,7 @@ flk_convert_lock_data(vnode_t *vp, flock64_t *flp,
break;
case 2: /* SEEK_END */
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
*start = (u_offset_t)(flp->l_start + vattr.va_size);
break;
@@ -3914,11 +3913,21 @@ cl_flk_change_nlm_state_to_unknown(int nlmid)
int
nbl_lock_conflict(vnode_t *vp, nbl_op_t op, u_offset_t offset,
- ssize_t length, int svmand)
+ ssize_t length, int svmand, caller_context_t *ct)
{
int conflict = 0;
graph_t *gp;
lock_descriptor_t *lock;
+ pid_t pid;
+ int sysid;
+
+ if (ct == NULL) {
+ pid = curproc->p_pid;
+ sysid = 0;
+ } else {
+ pid = ct->cc_pid;
+ sysid = ct->cc_sysid;
+ }
mutex_enter(&flock_lock);
gp = lock_graph[HASH_INDEX(vp)];
@@ -3931,8 +3940,8 @@ nbl_lock_conflict(vnode_t *vp, nbl_op_t op, u_offset_t offset,
for (; lock && lock->l_vnode == vp; lock = lock->l_next) {
if ((svmand || (lock->l_state & NBMAND_LOCK)) &&
- lock->l_flock.l_sysid == 0 &&
- lock->l_flock.l_pid != curproc->p_pid &&
+ (lock->l_flock.l_sysid != sysid ||
+ lock->l_flock.l_pid != pid) &&
lock_blocks_io(op, offset, length,
lock->l_type, lock->l_start, lock->l_end)) {
conflict = 1;
diff --git a/usr/src/uts/common/os/grow.c b/usr/src/uts/common/os/grow.c
index e463b97004..0033b11ff4 100644
--- a/usr/src/uts/common/os/grow.c
+++ b/usr/src/uts/common/os/grow.c
@@ -51,6 +51,7 @@
#include <sys/vmparam.h>
#include <sys/fcntl.h>
#include <sys/lwpchan_impl.h>
+#include <sys/nbmlock.h>
#include <vm/hat.h>
#include <vm/as.h>
@@ -560,6 +561,7 @@ smmap_common(caddr_t *addrp, size_t len,
struct as *as = curproc->p_as;
uint_t uprot, maxprot, type;
int error;
+ int in_crit = 0;
if ((flags & ~(MAP_SHARED | MAP_PRIVATE | MAP_FIXED | _MAP_NEW |
_MAP_LOW32 | MAP_NORESERVE | MAP_ANON | MAP_ALIGN |
@@ -694,12 +696,36 @@ smmap_common(caddr_t *addrp, size_t len,
}
}
+ if ((prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) &&
+ nbl_need_check(vp)) {
+ int svmand;
+ nbl_op_t nop;
+
+ nbl_start_crit(vp, RW_READER);
+ in_crit = 1;
+ error = nbl_svmand(vp, fp->f_cred, &svmand);
+ if (error != 0)
+ goto done;
+ if ((prot & PROT_WRITE) && (type == MAP_SHARED)) {
+ if (prot & (PROT_READ | PROT_EXEC)) {
+ nop = NBL_READWRITE;
+ } else {
+ nop = NBL_WRITE;
+ }
+ } else {
+ nop = NBL_READ;
+ }
+ if (nbl_conflict(vp, nop, 0, LONG_MAX, svmand, NULL)) {
+ error = EACCES;
+ goto done;
+ }
+ }
/*
* Ok, now let the vnode map routine do its thing to set things up.
*/
error = VOP_MAP(vp, pos, as,
- addrp, len, uprot, maxprot, flags, fp->f_cred);
+ addrp, len, uprot, maxprot, flags, fp->f_cred, NULL);
if (error == 0) {
if (vp->v_type == VREG &&
@@ -713,6 +739,9 @@ smmap_common(caddr_t *addrp, size_t len,
}
}
+done:
+ if (in_crit)
+ nbl_end_crit(vp);
return (error);
}
diff --git a/usr/src/uts/common/os/inst_sync.c b/usr/src/uts/common/os/inst_sync.c
index 1100f1d729..a30f83bee6 100644
--- a/usr/src/uts/common/os/inst_sync.c
+++ b/usr/src/uts/common/os/inst_sync.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -221,7 +220,7 @@ in_fclose(File *fp)
{
int error;
- error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED());
+ error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED(), NULL);
VN_RELE(fp->vp);
kmem_free(fp, sizeof (File));
return (error);
@@ -235,7 +234,7 @@ in_fflush(File *fp)
if (fp->count)
error = in_write(fp->vp, &fp->voffset, fp->buf, fp->count);
if (error == 0)
- error = VOP_FSYNC(fp->vp, FSYNC, CRED());
+ error = VOP_FSYNC(fp->vp, FSYNC, CRED(), NULL);
return (error);
}
diff --git a/usr/src/uts/common/os/mem_config.c b/usr/src/uts/common/os/mem_config.c
index 64bbc4b5ad..49f7709c41 100644
--- a/usr/src/uts/common/os/mem_config.c
+++ b/usr/src/uts/common/os/mem_config.c
@@ -296,7 +296,7 @@ kphysm_add_memory_dynamic(pfn_t base, pgcnt_t npgs)
mem_node_add_slice(base, pnum);
/*
- * Allocate or resize page counters as necessary to accomodate
+ * Allocate or resize page counters as necessary to accommodate
* the increase in memory pages.
*/
mnode = PFN_2_MEM_NODE(pnum);
@@ -508,7 +508,7 @@ kphysm_addmem_error_undospan(pfn_t pt_base, pgcnt_t tpgs)
* Only return an available memseg of exactly the right size.
* When the meta data area has it's own virtual address space
* we will need to manage this more carefully and do best fit
- * allocations, possibly splitting an availble area.
+ * allocations, possibly splitting an available area.
*/
static struct memseg *
memseg_reuse(pgcnt_t metapgs)
@@ -2013,7 +2013,7 @@ delete_memory_thread(caddr_t amhp)
VN_HOLD(vp);
page_unlock(pp);
(void) VOP_PUTPAGE(vp, offset, PAGESIZE,
- B_INVAL|B_FORCE, kcred);
+ B_INVAL|B_FORCE, kcred, NULL);
VN_RELE(vp);
#ifdef MEM_DEL_STATS
ntick_pgrp = (uint64_t)ddi_get_lbolt() -
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index ac38b40775..b4b0751d23 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -3129,7 +3129,7 @@ static char load_msg[] = "load '%s' id %d loaded @ 0x%p/0x%p size %d/%d\n";
/*
* Common code for loading a module (but not installing it).
- * Handoff the task of module loading to a seperate thread
+ * Handoff the task of module loading to a separate thread
* with a large stack if possible, since this code may recurse a few times.
* Return zero if there are no errors or an errno value.
*/
@@ -3513,7 +3513,7 @@ moduninstall(struct modctl *mp)
/*
* Even though we only set mod_installed to zero here, a zero
- * return value means we are commited to a code path were
+ * return value means we are committed to a code path were
* mod_loaded will also end up as zero - we have no other
* way to get the module data and bss back to the pre _init
* state except a reload. To ensure this, after return,
diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c
index e2d466227d..bc6ed66429 100644
--- a/usr/src/uts/common/os/policy.c
+++ b/usr/src/uts/common/os/policy.c
@@ -71,7 +71,7 @@ int priv_debug = 0;
* by privilege, there is quite a bit of duplication of
* functions.
*
- * The secpolicy functions must not make asssumptions about
+ * The secpolicy functions must not make assumptions about
* locks held or not held as any lock can be held while they're
* being called.
*
@@ -485,16 +485,40 @@ secpolicy_setpriority(const cred_t *cr)
int
secpolicy_net_privaddr(const cred_t *cr, in_port_t port)
{
- /*
- * NFS ports, these are extra privileged ports, allow bind
- * only if the SYS_NFS privilege is present.
- */
- if (port == 2049 || port == 4045)
- return (PRIV_POLICY(cr, PRIV_SYS_NFS, B_FALSE, EACCES,
- "NFS port"));
- else
- return (PRIV_POLICY(cr, PRIV_NET_PRIVADDR, B_FALSE, EACCES,
- NULL));
+ char *reason;
+ int priv;
+
+ switch (port) {
+ case 137:
+ case 138:
+ case 139:
+ case 445:
+ /*
+ * NBT and SMB ports, these are extra privileged ports,
+ * allow bind only if the SYS_SMB privilege is present.
+ */
+ priv = PRIV_SYS_SMB;
+ reason = "NBT or SMB port";
+ break;
+
+ case 2049:
+ case 4045:
+ /*
+ * NFS ports, these are extra privileged ports, allow bind
+ * only if the SYS_NFS privilege is present.
+ */
+ priv = PRIV_SYS_NFS;
+ reason = "NFS port";
+ break;
+
+ default:
+ priv = PRIV_NET_PRIVADDR;
+ reason = NULL;
+ break;
+
+ }
+
+ return (PRIV_POLICY(cr, priv, B_FALSE, EACCES, reason));
}
/*
@@ -583,7 +607,7 @@ secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp,
int err;
va.va_mask = AT_UID|AT_MODE;
- err = VOP_GETATTR(mvp, &va, 0, cr);
+ err = VOP_GETATTR(mvp, &va, 0, cr, NULL);
if (err != 0)
return (err);
@@ -965,6 +989,70 @@ secpolicy_setid_setsticky_clear(vnode_t *vp, vattr_t *vap, const vattr_t *ovap,
return (0);
}
+#define ATTR_FLAG_PRIV(attr, value, cr) \
+ PRIV_POLICY(cr, value ? PRIV_FILE_FLAG_SET : PRIV_ALL, \
+ B_FALSE, EPERM, NULL)
+
+/*
+ * Check privileges for setting xvattr attributes
+ */
+int
+secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype)
+{
+ xoptattr_t *xoap;
+ int error = 0;
+
+ if ((xoap = xva_getxoptattr(xvap)) == NULL)
+ return (EINVAL);
+
+ /*
+ * First process the DOS bits
+ */
+ if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+ XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
+ XVA_ISSET_REQ(xvap, XAT_READONLY) ||
+ XVA_ISSET_REQ(xvap, XAT_SYSTEM) ||
+ XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+ if ((error = secpolicy_vnode_owner(cr, owner)) != 0)
+ return (error);
+ }
+
+ /*
+ * Now handle special attributes
+ */
+
+ if (XVA_ISSET_REQ(xvap, XAT_IMMUTABLE))
+ error = ATTR_FLAG_PRIV(XAT_IMMUTABLE,
+ xoap->xoa_immutable, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NOUNLINK))
+ error = ATTR_FLAG_PRIV(XAT_NOUNLINK,
+ xoap->xoa_nounlink, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_APPENDONLY))
+ error = ATTR_FLAG_PRIV(XAT_APPENDONLY,
+ xoap->xoa_appendonly, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_NODUMP))
+ error = ATTR_FLAG_PRIV(XAT_NODUMP,
+ xoap->xoa_nodump, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_OPAQUE))
+ error = EPERM;
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_QUARANTINED)) {
+ error = ATTR_FLAG_PRIV(XAT_AV_QUARANTINED,
+ xoap->xoa_av_quarantined, cr);
+ if (error == 0 && vtype != VREG)
+ error = EINVAL;
+ }
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_MODIFIED))
+ error = ATTR_FLAG_PRIV(XAT_AV_MODIFIED,
+ xoap->xoa_av_modified, cr);
+ if (error == 0 && XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
+ error = ATTR_FLAG_PRIV(XAT_AV_SCANSTAMP,
+ xoap->xoa_av_scanstamp, cr);
+ if (error == 0 && vtype != VREG)
+ error = EINVAL;
+ }
+ return (error);
+}
+
/*
* This function checks the policy decisions surrounding the
* vop setattr call.
@@ -1004,15 +1092,24 @@ secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
{
int mask = vap->va_mask;
int error = 0;
+ boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
if (mask & AT_SIZE) {
if (vp->v_type == VDIR) {
error = EISDIR;
goto out;
}
- error = unlocked_access(node, VWRITE, cr);
- if (error)
- goto out;
+
+ /*
+ * If ATTR_NOACLCHECK is set in the flags, then we don't
+ * perform the secondary unlocked_access() call since the
+ * ACL (if any) is being checked there.
+ */
+ if (skipaclchk == B_FALSE) {
+ error = unlocked_access(node, VWRITE, cr);
+ if (error)
+ goto out;
+ }
}
if (mask & AT_MODE) {
/*
@@ -1092,7 +1189,7 @@ secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
if (cr->cr_uid != ovap->va_uid) {
if (flags & ATTR_UTIME)
error = secpolicy_vnode_utime_modify(cr);
- else {
+ else if (skipaclchk == B_FALSE) {
error = unlocked_access(node, VWRITE, cr);
if (error == EACCES &&
secpolicy_vnode_utime_modify(cr) == 0)
@@ -1102,6 +1199,13 @@ secpolicy_vnode_setattr(cred_t *cr, struct vnode *vp, struct vattr *vap,
goto out;
}
}
+
+ /*
+ * Check for optional attributes here by checking the following:
+ */
+ if (mask & AT_XVATTR)
+ error = secpolicy_xvattr((xvattr_t *)vap, ovap->va_uid, cr,
+ vp->v_type);
out:
return (error);
}
@@ -1957,3 +2061,20 @@ secpolicy_sadopen(const cred_t *credp)
return (secpolicy_require_set(credp, &pset, "devpolicy"));
}
+
+/*
+ * secpolicy_smb
+ *
+ * Determine if the cred_t has PRIV_SYS_SMB privilege, indicating
+ * that it has permission to access the smbsrv kernel driver.
+ * PRIV_POLICY checks the privilege and audits the check.
+ *
+ * Returns:
+ * 0 Driver access is allowed.
+ * EPERM Driver access is NOT permitted.
+ */
+int
+secpolicy_smb(const cred_t *cr)
+{
+ return (PRIV_POLICY(cr, PRIV_SYS_SMB, B_FALSE, EPERM, NULL));
+}
diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs
index a39896e73a..b654450428 100644
--- a/usr/src/uts/common/os/priv_defs
+++ b/usr/src/uts/common/os/priv_defs
@@ -149,6 +149,11 @@ privilege PRIV_FILE_UPGRADE_SL
This privilege is interpreted only if the system is configured
with Trusted Extensions.
+privilege PRIV_FILE_FLAG_SET
+
+ Allows a process to set immutable, nounlink or appendonly
+ file attributes.
+
privilege PRIV_GRAPHICS_ACCESS
Allows a process to make privileged ioctls to graphics devices.
@@ -402,6 +407,13 @@ unsafe privilege PRIV_SYS_RESOURCE
Allows a process to extend or create files on a filesystem that
has less than minfree space in reserve.
+privilege PRIV_SYS_SMB
+
+ Allows a process to access the Sun private SMB kernel module.
+ Allows a process to bind to ports reserved by NetBIOS and SMB:
+ ports 137 (NBNS), 138 (NetBIOS Datagram Service), 139 (NetBIOS
+ Session Service and SMB-over-NBT) and 445 (SMB-over-TCP).
+
privilege PRIV_SYS_SUSER_COMPAT
Allows a process to successfully call a third party loadable module
diff --git a/usr/src/uts/common/os/session.c b/usr/src/uts/common/os/session.c
index 7790a09094..ea93f9f6b3 100644
--- a/usr/src/uts/common/os/session.c
+++ b/usr/src/uts/common/os/session.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -166,7 +166,7 @@ tty_hold(void)
/*
* Now we need to drop our hold on the session structure,
* but we can't hold any locks when we do this because
- * sess_rele() may need to aquire pidlock.
+ * sess_rele() may need to acquire pidlock.
*/
mutex_exit(&sp->s_lock);
sess_rele(sp, B_FALSE);
@@ -306,9 +306,9 @@ strctty(stdata_t *stp)
* We are going to try to make stp the default ctty for the session
* associated with curproc. Not only does this require holding a
* bunch of locks but it also requires waiting for any outstanding
- * holds on the session structure (aquired via tty_hold()) to be
+ * holds on the session structure (acquired via tty_hold()) to be
* released. Hence, we have the following for(;;) loop that will
- * aquire our locks, do some sanity checks, and wait for the hold
+ * acquire our locks, do some sanity checks, and wait for the hold
* count on the session structure to hit zero. If we get a signal
* while waiting for outstanding holds to be released then we abort
* the operation and return.
@@ -370,12 +370,12 @@ strctty(stdata_t *stp)
}
/*
- * freectty_lock() attempts to aquire the army of locks required to free
+ * freectty_lock() attempts to acquire the army of locks required to free
* the ctty associated with a given session leader process. If it returns
* successfully the following locks will be held:
* sd_lock, pidlock, p_splock, s_lock
*
- * as a secondary bit of convience, freectty_lock() will also return
+ * as a secondary bit of convenience, freectty_lock() will also return
* pointers to the session, ctty, and ctty stream associated with the
* specified session leader process.
*/
@@ -543,10 +543,10 @@ freectty(boolean_t at_exit)
/*
* If the current process is a session leader we are going to
* try to release the ctty associated our current session. To
- * do this we need to aquire a bunch of locks, signal any
+ * do this we need to acquire a bunch of locks, signal any
* processes in the forground that are associated with the ctty,
* and make sure no one has any outstanding holds on the current
- * session * structure (aquired via tty_hold()). Hence, we have
+ * session * structure (acquired via tty_hold()). Hence, we have
* the following for(;;) loop that will do all this work for
* us and break out when the hold count on the session structure
* hits zero.
@@ -556,7 +556,7 @@ freectty(boolean_t at_exit)
return (EIO);
if (freectty_signal(p, sp, stp, at_exit)) {
- /* loop around to re-aquire locks */
+ /* loop around to re-acquire locks */
continue;
}
@@ -643,7 +643,7 @@ freectty(boolean_t at_exit)
mutex_exit(&stp->sd_lock);
/* This is the only remaining thread with access to this vnode */
- (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred);
+ (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
VN_RELE(vp);
crfree(cred);
diff --git a/usr/src/uts/common/os/share.c b/usr/src/uts/common/os/share.c
index 9714e4b01f..5d3bbb1418 100644
--- a/usr/src/uts/common/os/share.c
+++ b/usr/src/uts/common/os/share.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1996-1998,2001,2003 Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -74,11 +72,11 @@ add_share(struct vnode *vp, struct shrlock *shr)
* Sanity check to make sure we have valid options.
* There is known overlap but it doesn't hurt to be careful.
*/
- if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC)) {
+ if (shr->s_access & ~(F_RDACC|F_WRACC|F_RWACC|F_RMACC|F_MDACC)) {
return (EINVAL);
}
if (shr->s_deny & ~(F_NODNY|F_RDDNY|F_WRDNY|F_RWDNY|F_COMPAT|
- F_MANDDNY)) {
+ F_MANDDNY|F_RMDNY)) {
return (EINVAL);
}
@@ -115,7 +113,7 @@ add_share(struct vnode *vp, struct shrlock *shr)
if ((shrl->shr->s_deny & F_COMPAT) &&
(shr->s_deny & F_COMPAT) &&
((shrl->next == NULL) ||
- (shrl->shr->s_access & F_WRACC)))
+ (shrl->shr->s_access & F_WRACC)))
break;
}
@@ -280,13 +278,13 @@ is_match_for_del(struct shrlock *shr, struct shrlock *element)
* and pids.
*/
result = (nlmid1 == nlmid2 &&
- shr->s_pid == element->s_pid);
+ shr->s_pid == element->s_pid);
}
} else { /* not in a cluster */
result = ((shr->s_sysid == 0 &&
- shr->s_pid == element->s_pid) ||
- (shr->s_sysid != 0 &&
- shr->s_sysid == element->s_sysid));
+ shr->s_pid == element->s_pid) ||
+ (shr->s_sysid != 0 &&
+ shr->s_sysid == element->s_sysid));
}
return (result);
}
@@ -315,11 +313,11 @@ del_share(struct vnode *vp, struct shrlock *shr)
shrlp = &vp->v_shrlocks;
while (*shrlp) {
if ((shr->s_own_len == (*shrlp)->shr->s_own_len &&
- (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
- shr->s_own_len) == 0)) ||
+ (bcmp(shr->s_owner, (*shrlp)->shr->s_owner,
+ shr->s_own_len) == 0)) ||
- (shr->s_own_len == 0 &&
- is_match_for_del(shr, (*shrlp)->shr))) {
+ (shr->s_own_len == 0 &&
+ is_match_for_del(shr, (*shrlp)->shr))) {
shrl = *shrlp;
*shrlp = shrl->next;
@@ -427,7 +425,7 @@ static int
isreadonly(struct vnode *vp)
{
return (vp->v_type != VCHR && vp->v_type != VBLK &&
- vp->v_type != VFIFO && vn_is_readonly(vp));
+ vp->v_type != VFIFO && vn_is_readonly(vp));
}
#ifdef DEBUG
@@ -489,46 +487,117 @@ print_share(struct shrlock *shr)
/*
* Return non-zero if the given I/O request conflicts with a registered
* share reservation.
+ *
+ * A process is identified by the tuple (sysid, pid). When the caller
+ * context is passed to nbl_share_conflict, the sysid and pid in the
+ * caller context are used. Otherwise the sysid is zero, and the pid is
+ * taken from the current process.
+ *
+ * Conflict Algorithm:
+ * 1. An op request of NBL_READ will fail if a different
+ * process has a mandatory share reservation with deny read.
+ *
+ * 2. An op request of NBL_WRITE will fail if a different
+ * process has a mandatory share reservation with deny write.
+ *
+ * 3. An op request of NBL_READWRITE will fail if a different
+ * process has a mandatory share reservation with deny read
+ * or deny write.
+ *
+ * 4. An op request of NBL_REMOVE will fail if there is
+ * a mandatory share reservation with an access of read,
+ * write, or remove. (Anything other than meta data access).
+ *
+ * 5. An op request of NBL_RENAME will fail if there is
+ * a mandatory share reservation with:
+ * a) access write or access remove
+ * or
+ * b) access read and deny remove
+ *
+ * Otherwise there is no conflict and the op request succeeds.
+ *
+ * This behavior is required for interoperability between
+ * the nfs server, cifs server, and local access.
+ * This behavior can result in non-posix semantics.
+ *
+ * When mandatory share reservations are enabled, a process
+ * should call nbl_share_conflict to determine if the
+ * desired operation would conflict with an existing share
+ * reservation.
+ *
+ * The call to nbl_share_conflict may be skipped if the
+ * process has an existing share reservation and the operation
+ * is being performed in the context of that existing share
+ * reservation.
*/
-
int
-nbl_share_conflict(vnode_t *vp, nbl_op_t op)
+nbl_share_conflict(vnode_t *vp, nbl_op_t op, caller_context_t *ct)
{
struct shrlocklist *shrl;
int conflict = 0;
+ pid_t pid;
+ int sysid;
ASSERT(nbl_in_crit(vp));
+ if (ct == NULL) {
+ pid = curproc->p_pid;
+ sysid = 0;
+ } else {
+ pid = ct->cc_pid;
+ sysid = ct->cc_sysid;
+ }
+
mutex_enter(&vp->v_lock);
for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
- if (shrl->shr->s_sysid == 0 &&
- (shrl->shr->s_deny & F_MANDDNY) &&
- shrl->shr->s_pid != curproc->p_pid) {
- switch (op) {
- case NBL_READ:
- if (shrl->shr->s_deny & F_RDDNY)
- conflict = 1;
- break;
- case NBL_WRITE:
- if (shrl->shr->s_deny & F_WRDNY)
- conflict = 1;
- break;
- case NBL_READWRITE:
- if (shrl->shr->s_deny & F_RWDNY)
- conflict = 1;
- break;
- case NBL_RENAME:
- case NBL_REMOVE:
+ if (!(shrl->shr->s_deny & F_MANDDNY))
+ continue;
+ /*
+ * NBL_READ, NBL_WRITE, and NBL_READWRITE need to
+ * check if the share reservation being examined
+ * belongs to the current process.
+ * NBL_REMOVE and NBL_RENAME do not.
+ * This behavior is required by the conflict
+ * algorithm described above.
+ */
+ switch (op) {
+ case NBL_READ:
+ if ((shrl->shr->s_deny & F_RDDNY) &&
+ (shrl->shr->s_sysid != sysid ||
+ shrl->shr->s_pid != pid))
conflict = 1;
- break;
+ break;
+ case NBL_WRITE:
+ if ((shrl->shr->s_deny & F_WRDNY) &&
+ (shrl->shr->s_sysid != sysid ||
+ shrl->shr->s_pid != pid))
+ conflict = 1;
+ break;
+ case NBL_READWRITE:
+ if ((shrl->shr->s_deny & F_RWDNY) &&
+ (shrl->shr->s_sysid != sysid ||
+ shrl->shr->s_pid != pid))
+ conflict = 1;
+ break;
+ case NBL_REMOVE:
+ if (shrl->shr->s_access & (F_RWACC|F_RMACC))
+ conflict = 1;
+ break;
+ case NBL_RENAME:
+ if (shrl->shr->s_access & (F_WRACC|F_RMACC))
+ conflict = 1;
+
+ else if ((shrl->shr->s_access & F_RDACC) &&
+ (shrl->shr->s_deny & F_RMDNY))
+ conflict = 1;
+ break;
#ifdef DEBUG
- default:
- cmn_err(CE_PANIC,
- "nbl_share_conflict: bogus op (%d)",
- op);
- break;
+ default:
+ cmn_err(CE_PANIC,
+ "nbl_share_conflict: bogus op (%d)",
+ op);
+ break;
#endif
- }
}
if (conflict)
break;
@@ -546,10 +615,16 @@ nbl_share_conflict(vnode_t *vp, nbl_op_t op)
int
share_blocks_lock(vnode_t *vp, flock64_t *flkp)
{
+ caller_context_t ct;
+
ASSERT(nbl_in_crit(vp));
+ ct.cc_pid = flkp->l_pid;
+ ct.cc_sysid = flkp->l_sysid;
+ ct.cc_caller_id = 0;
+
if ((flkp->l_type == F_RDLCK || flkp->l_type == F_WRLCK) &&
- nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type)))
+ nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type), &ct))
return (1);
else
return (0);
@@ -602,35 +677,34 @@ lock_blocks_share(vnode_t *vp, struct shrlock *shr)
{
struct flock64 lck;
int error;
-
- /*
- * We don't currently have a good way to match lock
- * ownership with share ownership for remote requests.
- * Fortunately, we know that only local processes (in particular,
- * local CIFS servers) care about conflicts between locks and
- * share reservations, and we can distinguish local processes from
- * each other and from remote processes.
- */
- ASSERT(shr->s_sysid == 0);
+ v_mode_t mode = 0;
if ((shr->s_deny & (F_RWDNY|F_COMPAT)) == 0) {
/* if no deny mode, then there's no conflict */
return (0);
}
- lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
+ /* check for conflict with mapped region */
+ if ((shr->s_deny & F_RWDNY) == F_WRDNY) {
+ mode = V_WRITE;
+ } else if ((shr->s_deny & F_RWDNY) == F_RDDNY) {
+ mode = V_READ;
+ } else {
+ mode = V_RDORWR;
+ }
+ if (vn_is_mapped(vp, mode))
+ return (1);
+ lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
lck.l_whence = 0;
lck.l_start = 0;
lck.l_len = 0; /* to EOF */
- /* would check here for conflict with mapped region */
-
/* XXX should use non-NULL cred? */
- error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL);
+ error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL, NULL);
if (error != 0) {
cmn_err(CE_WARN, "lock_blocks_share: unexpected error (%d)",
- error);
+ error);
return (1);
}
diff --git a/usr/src/uts/common/os/sid.c b/usr/src/uts/common/os/sid.c
index 0da71f3cdf..2ed5ad2989 100644
--- a/usr/src/uts/common/os/sid.c
+++ b/usr/src/uts/common/os/sid.c
@@ -41,8 +41,6 @@
#include <sys/kidmap.h>
#include <sys/idmap.h>
-#define KSIDLIST_MEM(n) (sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
-
static kmutex_t sid_lock;
static avl_tree_t sid_tree;
static boolean_t sid_inited = B_FALSE;
diff --git a/usr/src/uts/common/os/tlabel.c b/usr/src/uts/common/os/tlabel.c
index 30569bb963..3a46745483 100644
--- a/usr/src/uts/common/os/tlabel.c
+++ b/usr/src/uts/common/os/tlabel.c
@@ -287,7 +287,7 @@ getflabel(vnode_t *vp)
/*
* Traverse lofs mounts and fattach'es to get the real vnode
*/
- if (VOP_REALVP(rvp, &rvp2) == 0)
+ if (VOP_REALVP(rvp, &rvp2, NULL) == 0)
rvp = rvp2;
rvfsp = rvp->v_vfsp;
diff --git a/usr/src/uts/common/os/urw.c b/usr/src/uts/common/os/urw.c
index a0195a6db3..ef70ccac45 100644
--- a/usr/src/uts/common/os/urw.c
+++ b/usr/src/uts/common/os/urw.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -75,7 +74,7 @@ page_valid(struct seg *seg, caddr_t addr)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, addr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, 0, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
u_offset_t size = roundup(vattr.va_size, (u_offset_t)PAGESIZE);
u_offset_t offset = SEGOP_GETOFFSET(seg, addr);
@@ -177,7 +176,7 @@ mapout(struct as *as, caddr_t addr, caddr_t vaddr, int writing)
}
/*
- * Perform I/O to a given process. This will return EIO if we dectect
+ * Perform I/O to a given process. This will return EIO if we detect
* corrupt memory and ENXIO if there is no such mapped address in the
* user process's address space.
*/
diff --git a/usr/src/uts/common/os/vm_pageout.c b/usr/src/uts/common/os/vm_pageout.c
index e5c80e9bfd..afbca60785 100644
--- a/usr/src/uts/common/os/vm_pageout.c
+++ b/usr/src/uts/common/os/vm_pageout.c
@@ -634,7 +634,7 @@ int dopageout = 1; /* must be non-zero to turn page stealing on */
* Some filesystems may require resources for the VOP_PUTPAGE
* operations (like memory) and hence can block the pageout
* thread, but the scanner thread can still operate. There is still
- * no gaurentee that memory deadlocks cannot occur.
+ * no guarantee that memory deadlocks cannot occur.
*
* For now, this thing is in very rough form.
*/
@@ -709,7 +709,7 @@ pageout()
if (VOP_PUTPAGE(arg->a_vp, (offset_t)arg->a_off,
arg->a_len, arg->a_flags,
- arg->a_cred) == 0) {
+ arg->a_cred, NULL) == 0) {
pushes++;
}
diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c
index c89945e756..ff2812b781 100644
--- a/usr/src/uts/common/os/zone.c
+++ b/usr/src/uts/common/os/zone.c
@@ -2417,7 +2417,8 @@ zone_set_root(zone_t *zone, const char *upath)
* filesystem, if 'vp' is an autoFS vnode.
* Get the new 'vp' if so.
*/
- if ((error = VOP_ACCESS(vp, VEXEC, 0, CRED())) == 0 &&
+ if ((error =
+ VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) == 0 &&
(!vn_ismntpt(vp) ||
(error = traverse(&vp)) == 0)) {
pathlen = pn.pn_pathlen + 2;
@@ -4381,7 +4382,7 @@ done:
*
* Also return zero if the process has any shared mappings which reserve
* swap. This is because the counting for zone.max-swap does not allow swap
- * revervation to be shared between zones. zone swap reservation is counted
+ * reservation to be shared between zones. zone swap reservation is counted
* on zone->zone_max_swap.
*/
static int
@@ -5645,7 +5646,7 @@ zone_check_datalink(zoneid_t *zoneidp, char *dlname)
/*
* Get the names of the datalinks assigned to a zone.
* Here *nump is the number of datalinks, and the assumption
- * is that the caller will gurantee that the the supplied buffer is
+ * is that the caller will guarantee that the the supplied buffer is
* big enough to hold at least #*nump datalink names, that is,
* LIFNAMSIZ X *nump
* On return, *nump will be the "new" number of datalinks, if it
diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile
new file mode 100644
index 0000000000..233f5d2141
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/Makefile
@@ -0,0 +1,131 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+include ../../../Makefile.master
+
+HDRS= alloc.h \
+ cifs.h \
+ codepage.h \
+ cp_cyrillic.h \
+ cp_latin1.h \
+ cp_latin2.h \
+ cp_latin3.h \
+ cp_latin4.h \
+ cp_latin5.h \
+ cp_latin6.h \
+ cp_unicode.h \
+ cp_usascii.h \
+ crypt.h \
+ ctype.h \
+ doserror.h \
+ hash_table.h \
+ lm.h \
+ lmdfs.h \
+ lmerr.h \
+ lmshare.h \
+ lmshare_door.h \
+ lsalib.h \
+ mac_cifs.h \
+ mailslot.h \
+ mbuf.h \
+ mlrpc.h \
+ mlsvc.h \
+ mlsvc_util.h \
+ msgbuf.h \
+ ndr.h \
+ netbios.h \
+ netrauth.h \
+ nmpipes.h \
+ ntaccess.h \
+ nterror.h \
+ ntifs.h \
+ ntlocale.h \
+ ntsid.h \
+ ntstatus.h \
+ oem.h \
+ samlib.h \
+ smb.h \
+ smb_common_door.h \
+ smb_door_svc.h \
+ smb_fsd.h \
+ smb_fsops.h \
+ smb_i18n.h \
+ smb_idmap.h \
+ smb_incl.h \
+ smb_ioctl.h \
+ smb_kproto.h \
+ smb_privilege.h \
+ smb_secdesc.h \
+ smb_svc_sm.h \
+ smb_token.h \
+ smb_vops.h \
+ smb_winpipe.h \
+ smb_xdr.h \
+ smbfmt.h \
+ smbinfo.h \
+ smbtrans.h \
+ smbvar.h \
+ string.h \
+ svrapi.h \
+ winioctl.h \
+ winsvc.h \
+ wintypes.h
+
+NDLHDRS= dssetup.ndl \
+ eventlog.ndl \
+ llsrpc.ndl \
+ lsarpc.ndl \
+ ndrtypes.ndl \
+ netdfs.ndl \
+ netlogon.ndl \
+ rpcpdu.ndl \
+ samrpc.ndl \
+ spoolss.ndl \
+ srvsvc.ndl \
+ svcctl.ndl \
+ winreg.ndl \
+
+ROOTDIR= $(ROOT)/usr/include/smbsrv
+NDLDIR= $(ROOTDIR)/ndl
+ROOTHDRS= $(HDRS:%=$(ROOTDIR)/%) $(NDLHDRS:%=$(ROOTDIR)/ndl/%)
+CHECKHDRS= $(HDRS:%.h=%.check)
+
+$(ROOTDIR)/%: %
+ $(INS.file)
+
+$(NDLDIR)/%: ndl/%
+ $(INS.file)
+
+$(ROOTDIR) $(NDLDIR):
+ $(INS.dir)
+
+.KEEP_STATE:
+
+.PARALLEL: $(CHECKHDRS)
+
+install_h: $(ROOTDIR) $(NDLDIR) $(ROOTHDRS)
+
+check: $(CHECKHDRS)
diff --git a/usr/src/uts/common/smbsrv/alloc.h b/usr/src/uts/common/smbsrv/alloc.h
new file mode 100644
index 0000000000..8d49256863
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/alloc.h
@@ -0,0 +1,89 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_ALLOC_H
+#define _SMBSRV_ALLOC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Memory management macros to aid in developing code that can
+ * be compiled for both user and kernel.
+ *
+ * Set the AREA parameter to a short text string that is a hint
+ * about the subsystem calling the function. example: "smbrdr"
+ *
+ * Do not mix usage of these macros with malloc/free functions.
+ * It will not work.
+ *
+ * All library code shared between user and kernel must use
+ * these functions instead of malloc/free/kmem_*.
+ *
+ * Quick Summary
+ * MEM_MALLOC - allocate memory
+ * MEM_ZALLOC - allocate and zero memory
+ * MEM_STRDUP - string copy
+ * MEM_REALLOC - reallocate memory
+ * MEM_FREE - free memory
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+
+#define MEM_MALLOC(AREA, SIZE) malloc(SIZE)
+#define MEM_ZALLOC(AREA, SIZE) calloc((SIZE), 1)
+#define MEM_STRDUP(AREA, PTR) strdup(PTR)
+#define MEM_REALLOC(AREA, PTR, SIZE) realloc((PTR), (SIZE))
+#define MEM_FREE(AREA, PTR) free(PTR)
+
+#else /* _KERNEL */
+
+void *mem_malloc(uint32_t size);
+void *mem_zalloc(uint32_t size);
+char *mem_strdup(const char *ptr);
+void *mem_realloc(void *ptr, uint32_t size);
+void smb_mem_free(void *ptr);
+
+#define MEM_MALLOC(AREA, SIZE) mem_malloc(SIZE)
+#define MEM_ZALLOC(AREA, SIZE) mem_zalloc(SIZE)
+#define MEM_STRDUP(AREA, PTR) mem_strdup(PTR)
+#define MEM_REALLOC(AREA, PTR, SIZE) mem_realloc((PTR), (SIZE))
+#define MEM_FREE(AREA, PTR) smb_mem_free(PTR)
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_ALLOC_H */
diff --git a/usr/src/uts/common/smbsrv/cifs.h b/usr/src/uts/common/smbsrv/cifs.h
new file mode 100644
index 0000000000..4533a21bb6
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cifs.h
@@ -0,0 +1,1161 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CIFS_H
+#define _SMBSRV_CIFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions for the CIFS interface. The Macintosh
+ * Extensions for CIFS are defined in mac_cifs.h.
+ */
+
+/*
+ * Macintosh Extensions for CIFS
+ */
+#include <smbsrv/mac_cifs.h>
+
+/*
+ * NT Installable File System (IFS) interface.
+ */
+#include <smbsrv/ntifs.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/*
+ * SMB-over-TCP (NETBIOS-less SMB) TCP port
+ */
+#define SMB_SRVC_TCP_PORT 445
+
+
+/* Share types */
+#ifndef _SHARE_TYPES_DEFINED_
+#define _SHARE_TYPES_DEFINED_
+#define STYPE_DISKTREE 0x00000000
+#define STYPE_PRINTQ 0x00000001
+#define STYPE_DEVICE 0x00000002
+#define STYPE_IPC 0x00000003
+#define STYPE_MASK 0x0000000F
+#define STYPE_DFS 0x00000064
+#define STYPE_HIDDEN 0x80000000
+#define STYPE_SPECIAL 0x80000000
+#endif /* _SHARE_TYPES_DEFINED_ */
+
+#define STYPE_ISDSK(S) (((S) & STYPE_MASK) == STYPE_DISKTREE)
+#define STYPE_ISPRN(S) (((S) & STYPE_MASK) == STYPE_PRINTQ)
+#define STYPE_ISDEV(S) (((S) & STYPE_MASK) == STYPE_DEVICE)
+#define STYPE_ISIPC(S) (((S) & STYPE_MASK) == STYPE_IPC)
+
+/*
+ * NtCreateAndX and NtTransactCreate creation flags: defined in CIFS
+ * section 4.2.2
+ *
+ * Creation Flag Name Value Description
+ * ========================== ====== ==================================
+ * NT_CREATE_REQUEST_OPLOCK 0x02 Level I oplock requested
+ * NT_CREATE_REQUEST_OPBATCH 0x04 Batch oplock requested
+ * NT_CREATE_OPEN_TARGET_DIR 0x08 Target for open is a directory
+ */
+#define NT_CREATE_FLAG_REQUEST_OPLOCK 0x02
+#define NT_CREATE_FLAG_REQUEST_OPBATCH 0x04
+#define NT_CREATE_FLAG_OPEN_TARGET_DIR 0x08
+
+
+/*
+ * Define the filter flags for NtNotifyChangeDirectoryFile
+ */
+#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
+#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
+#define FILE_NOTIFY_CHANGE_NAME 0x00000003
+#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
+#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
+#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
+#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
+#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
+#define FILE_NOTIFY_CHANGE_EA 0x00000080
+#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
+#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+#define FILE_NOTIFY_VALID_MASK 0x00000fff
+
+
+/*
+ * Define the file action type codes for NtNotifyChangeDirectoryFile
+ */
+#define FILE_ACTION_ADDED 0x00000001
+#define FILE_ACTION_REMOVED 0x00000002
+#define FILE_ACTION_MODIFIED 0x00000003
+#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
+#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
+#define FILE_ACTION_ADDED_STREAM 0x00000006
+#define FILE_ACTION_REMOVED_STREAM 0x00000007
+#define FILE_ACTION_MODIFIED_STREAM 0x00000008
+
+
+/* Lock type flags */
+#define LOCKING_ANDX_NORMAL_LOCK 0x00
+#define LOCKING_ANDX_SHARED_LOCK 0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+#define LOCKING_ANDX_CHANGE_LOCK_TYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK 0x08
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+#define SMB_COM_CREATE_DIRECTORY 0x00
+#define SMB_COM_DELETE_DIRECTORY 0x01
+#define SMB_COM_OPEN 0x02
+#define SMB_COM_CREATE 0x03
+#define SMB_COM_CLOSE 0x04
+#define SMB_COM_FLUSH 0x05
+#define SMB_COM_DELETE 0x06
+#define SMB_COM_RENAME 0x07
+#define SMB_COM_QUERY_INFORMATION 0x08
+#define SMB_COM_SET_INFORMATION 0x09
+#define SMB_COM_READ 0x0A
+#define SMB_COM_WRITE 0x0B
+#define SMB_COM_LOCK_BYTE_RANGE 0x0C
+#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D
+#define SMB_COM_CREATE_TEMPORARY 0x0E
+#define SMB_COM_CREATE_NEW 0x0F
+#define SMB_COM_CHECK_DIRECTORY 0x10
+#define SMB_COM_PROCESS_EXIT 0x11
+#define SMB_COM_SEEK 0x12
+#define SMB_COM_LOCK_AND_READ 0x13
+#define SMB_COM_WRITE_AND_UNLOCK 0x14
+
+#define SMB_COM_READ_RAW 0x1A
+#define SMB_COM_READ_MPX 0x1B
+#define SMB_COM_READ_MPX_SECONDARY 0x1C
+#define SMB_COM_WRITE_RAW 0x1D
+#define SMB_COM_WRITE_MPX 0x1E
+#define SMB_COM_WRITE_MPX_SECONDARY 0x1F
+#define SMB_COM_WRITE_COMPLETE 0x20
+
+#define SMB_COM_SET_INFORMATION2 0x22
+#define SMB_COM_QUERY_INFORMATION2 0x23
+#define SMB_COM_LOCKING_ANDX 0x24
+#define SMB_COM_TRANSACTION 0x25
+#define SMB_COM_TRANSACTION_SECONDARY 0x26
+#define SMB_COM_IOCTL 0x27
+#define SMB_COM_IOCTL_SECONDARY 0x28
+#define SMB_COM_COPY 0x29
+#define SMB_COM_MOVE 0x2A
+#define SMB_COM_ECHO 0x2B
+#define SMB_COM_WRITE_AND_CLOSE 0x2C
+#define SMB_COM_OPEN_ANDX 0x2D
+#define SMB_COM_READ_ANDX 0x2E
+#define SMB_COM_WRITE_ANDX 0x2F
+
+#define SMB_COM_CLOSE_AND_TREE_DISC 0x31
+#define SMB_COM_TRANSACTION2 0x32
+#define SMB_COM_TRANSACTION2_SECONDARY 0x33
+#define SMB_COM_FIND_CLOSE2 0x34
+#define SMB_COM_FIND_NOTIFY_CLOSE 0x35
+
+#define SMB_COM_TREE_CONNECT 0x70
+#define SMB_COM_TREE_DISCONNECT 0x71
+#define SMB_COM_NEGOTIATE 0x72
+#define SMB_COM_SESSION_SETUP_ANDX 0x73
+#define SMB_COM_LOGOFF_ANDX 0x74
+#define SMB_COM_TREE_CONNECT_ANDX 0x75
+
+#define SMB_COM_QUERY_INFORMATION_DISK 0x80
+#define SMB_COM_SEARCH 0x81
+#define SMB_COM_FIND 0x82
+#define SMB_COM_FIND_UNIQUE 0x83
+#define SMB_COM_FIND_CLOSE 0x84
+
+#define SMB_COM_NT_TRANSACT 0xA0
+#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
+#define SMB_COM_NT_CREATE_ANDX 0xA2
+#define SMB_COM_NT_CANCEL 0xA4
+
+#define SMB_COM_OPEN_PRINT_FILE 0xC0
+#define SMB_COM_WRITE_PRINT_FILE 0xC1
+#define SMB_COM_CLOSE_PRINT_FILE 0xC2
+#define SMB_COM_GET_PRINT_QUEUE 0xC3
+
+
+/*
+ * Flags field of the SMB header. The names in parenthesis represent
+ * alternative names for the flags.
+ *
+ * SMB_FLAGS_LOCK_AND_READ_OK If the server supports LockAndRead and
+ * (SMB_FLAGS_LOCKS_SUBDIALECT) WriteAndUnlock, it sets this bit in the
+ * Negotiate response.
+ *
+ * SMB_FLAGS_SEND_NO_ACK When on, the client guarantees that there
+ * (SMB_FLAGS_RCV_BUF_POSTED) is a receive buffer posted such that a
+ * "Send-No-Ack" can be used by the server
+ * to respond to the client's request.
+ *
+ * SMB_FLAGS_CASE_INSENSITIVE This is part of the Flags field of every
+ * SMB header. If this bit is set, then all
+ * pathnames in the SMB should be treated as
+ * case-insensitive. Otherwise pathnames are
+ * case-sensitive.
+ *
+ * SMB_FLAGS_CANONICALIZED_PATHS When on in SessionSetupX, this indicates
+ * that all paths sent to the server are
+ * already in OS/2 canonicalized format.
+ *
+ * OS/2 canonical format means that file/directory names are in upper case,
+ * are valid characters, . and .. have been removed and single backslashes
+ * are used as separators.
+ *
+ * SMB_FLAGS_OPLOCK When set in an open file request SMBs
+ * (Open, Create, OpenX, etc.) this bit
+ * indicates a request for an oplock on the
+ * file. When set in the response, this bit
+ * indicates that the oplock was granted.
+ *
+ * SMB_FLAGS_OPLOCK_NOTIFY_ANY When on, this bit indicates that the server
+ * should notify the client on any request
+ * that could cause the file to be changed.
+ * If not set, the server only notifies the
+ * client on other open requests on the file.
+ * This bit is only relevant when
+ * SMB_FLAGS_OPLOCK is set.
+ *
+ * SMB_FLAGS_SERVER_TO_REDIR This bit indicates that the SMB is being
+ * (SMB_FLAGS_REPLY) sent from server to (client) redirector.
+ */
+#define SMB_FLAGS_LOCK_AND_READ_OK 0x01
+#define SMB_FLAGS_SEND_NO_ACK 0x02
+#define SMB_FLAGS_RESERVED 0x04
+#define SMB_FLAGS_CASE_INSENSITIVE 0x08
+#define SMB_FLAGS_CANONICALIZED_PATHS 0x10
+#define SMB_FLAGS_OPLOCK 0x20
+#define SMB_FLAGS_OPLOCK_NOTIFY_ANY 0x40
+#define SMB_FLAGS_REPLY 0x80
+
+
+/*
+ * Flags2 field of the SMB header.
+ */
+#define SMB_FLAGS2_KNOWS_LONG_NAMES 0x0001
+#define SMB_FLAGS2_KNOWS_EAS 0x0002
+#define SMB_FLAGS2_SMB_SECURITY_SIGNATURE 0x0004
+#define SMB_FLAGS2_IS_LONG_NAME 0x0040
+#define SMB_FLAGS2_EXT_SEC 0x0800
+#define SMB_FLAGS2_DFS 0x1000
+#define SMB_FLAGS2_PAGING_IO 0x2000
+#define SMB_FLAGS2_NT_STATUS 0x4000
+#define SMB_FLAGS2_UNICODE 0x8000
+
+#define DIALECT_UNKNOWN 0
+#define PC_NETWORK_PROGRAM_1_0 1 /* The original MSNET SMB protocol */
+#define PCLAN1_0 2 /* Some versions of the original MSNET */
+#define MICROSOFT_NETWORKS_1_03 3 /* This is used for the MS-NET 1.03 */
+#define MICROSOFT_NETWORKS_3_0 4 /* This is the DOS LANMAN 1.0 specific */
+#define LANMAN1_0 5 /* This is the first version of the full */
+#define LM1_2X002 6 /* This is the first version of the full */
+#define DOS_LM1_2X002 7 /* This is the dos equivalent of the */
+#define DOS_LANMAN2_1 8 /* DOS LANMAN2.1 */
+#define LANMAN2_1 9 /* OS/2 LANMAN2.1 */
+#define Windows_for_Workgroups_3_1a 10 /* Windows for Workgroups Version 1.0 */
+#define NT_LM_0_12 11 /* The SMB protocol designed for NT */
+
+/* SMB_TREE_CONNECT_ANDX flags */
+#define SMB_TREE_SUPPORT_SEARCH_BITS 0x01
+#define SMB_TREE_SHARE_IS_IN_DFS 0x02
+
+#define SMB_FA_READONLY 0x01 /* Read only file */
+#define SMB_FA_HIDDEN 0x02 /* Hidden file */
+#define SMB_FA_SYSTEM 0x04 /* System file */
+#define SMB_FA_VOLUME 0x08 /* Volume */
+#define SMB_FA_DIRECTORY 0x10 /* Directory */
+#define SMB_FA_ARCHIVE 0x20 /* Archive file */
+#define SMB_FA_NORMAL 0x80 /* Normal pipe */
+#define SMB_FA_TEMPORARY 0x100 /* Is a temporary file */
+#define SMB_FA_ATOMIC_WRITE 0x200 /* Do atomic writes */
+#define SMB_FA_XACTION_WRITE 0x400 /* XACTION write */
+
+/*
+ * Mask to match the definitions in section 3.7 File Attribute Encoding.
+ * The other bits are reserved.
+ */
+#define SMB_FA_MASK 0x3F
+
+
+/*
+ * The subcommand codes, placed in SETUP[0], for named pipe operations are:
+ * SubCommand Code Value Description
+ * =================== ===== =========================================
+ */
+
+#define CallNamedPipe 0x54 /* open/write/read/close pipe */
+#define WaitNamedPipe 0x53 /* wait for pipe to be nonbusy */
+#define PeekNmPipe 0x23 /* read but don't remove data */
+#define QNmPHandState 0x21 /* query pipe handle modes */
+#define SetNmPHandState 0x01 /* set pipe handle modes */
+#define QNmPipeInfo 0x22 /* query pipe attributes */
+#define TransactNmPipe 0x26 /* write/read operation on pipe */
+#define RawReadNmPipe 0x11 /* read pipe in "raw" (non message mode) */
+#define RawWriteNmPipe 0x31 /* write pipe "raw" (non message mode) */
+
+
+
+/*
+ * Setup[0] Transaction2 Value Description
+ * Subcommand Code
+ * ========================== ===== =============================
+ */
+
+#define TRANS2_OPEN2 0x00 /* Create file, extended attributes */
+#define TRANS2_FIND_FIRST2 0x01 /* Begin search for files */
+#define TRANS2_FIND_NEXT2 0x02 /* Resume search for files */
+#define TRANS2_QUERY_FS_INFORMATION 0x03 /* Get file system information */
+#define _TRANS2_RESV_0x04 0x04 /* Reserved */
+#define TRANS2_QUERY_PATH_INFORMATION 0x05 /* Get info, named file or dir */
+#define TRANS2_SET_PATH_INFORMATION 0x06 /* Set info, named file or dir */
+#define TRANS2_QUERY_FILE_INFORMATION 0x07 /* Get info, handle */
+#define TRANS2_SET_FILE_INFORMATION 0x08 /* Set info, handle */
+#define TRANS2_FSCTL 0x09 /* Not implemented by NT server */
+#define TRANS2_IOCTL2 0x0A /* Not implemented by NT server */
+#define TRANS2_FIND_NOTIFY_FIRST 0x0B /* Not implemented by NT server */
+#define TRANS2_FIND_NOTIFY_NEXT 0x0C /* Not implemented by NT server */
+#define TRANS2_CREATE_DIRECTORY 0x0D /* Create dir, extended attributes */
+#define TRANS2_SESSION_SETUP 0x0E /* Session setup, extended security */
+#define TRANS2_GET_DFS_REFERRAL 0x10 /* Get a Dfs referral */
+#define TRANS2_REPORT_DFS_INCONSISTENCY 0x11 /* Report a Dfs inconsistency */
+
+/*
+ * Access Mode Encoding (CIFS/1.0 1996 Section 3.8).
+ *
+ * The desired access mode passed in SmbOpen and SmbOpenAndX has the following
+ * mapping:
+ *
+ * 1111 11
+ * 5432 1098 7654 3210
+ * rWrC rLLL rSSS rAAA
+ *
+ * where:
+ *
+ * W - Write through mode. No read ahead or write behind allowed on
+ * this file or device. When protocol is returned, data is expected
+ * to be on the disk or device.
+ *
+ * S - Sharing mode:
+ * 0 - Compatibility mode (as in core open)
+ * 1 - Deny read/write/execute (exclusive)
+ * 2 - Deny write
+ * 3 - Deny read/execute
+ * 4 - Deny none
+ *
+ * A - Access mode
+ * 0 - Open for reading
+ * 1 - Open for writing
+ * 2 - Open for reading and writing
+ * 3 - Open for execute
+ *
+ * rSSSrAAA = 11111111 (hex FF) indicates FCB open (as in core protocol)
+ *
+ * C - Cache mode
+ * 0 - Normal file
+ * 1 - Do not cache this file
+ *
+ * L - Locality of reference
+ * 0 - Locality of reference is unknown
+ * 1 - Mainly sequential access
+ * 2 - Mainly random access
+ * 3 - Random access with some locality
+ * 4 to 7 - Currently undefined
+ */
+
+
+#define SMB_DA_SHARE_MASK 0x70
+#define SMB_DA_ACCESS_MASK 0x07
+#define SMB_DA_FCB_MASK (UCHAR)0xFF
+
+#define SMB_DA_ACCESS_READ 0x00
+#define SMB_DA_ACCESS_WRITE 0x01
+#define SMB_DA_ACCESS_READ_WRITE 0x02
+#define SMB_DA_ACCESS_EXECUTE 0x03
+
+#define SMB_DA_SHARE_COMPATIBILITY 0x00
+#define SMB_DA_SHARE_EXCLUSIVE 0x10
+#define SMB_DA_SHARE_DENY_WRITE 0x20
+#define SMB_DA_SHARE_DENY_READ 0x30
+#define SMB_DA_SHARE_DENY_NONE 0x40
+
+#define SMB_DA_FCB (UCHAR)0xFF
+
+#define SMB_CACHE_NORMAL 0x0000
+#define SMB_DO_NOT_CACHE 0x1000
+
+#define SMB_LR_UNKNOWN 0x0000
+#define SMB_LR_SEQUENTIAL 0x0100
+#define SMB_LR_RANDOM 0x0200
+#define SMB_LR_RANDOM_WITH_LOCALITY 0x0300
+#define SMB_LR_MASK 0x0F00
+
+#define SMB_DA_WRITE_THROUGH 0x4000
+
+/*
+ * The SMB open function determines what action should be taken depending
+ * on the existence or lack thereof of files used in the operation. It
+ * has the following mapping:
+ *
+ * 1111 1
+ * 5432 1098 7654 3210
+ * rrrr rrrr rrrC rrOO
+ *
+ * where:
+ *
+ * O - Open (action to be taken if the target file exists)
+ * 0 - Fail
+ * 1 - Open or Append file
+ * 2 - Truncate file
+ *
+ * C - Create (action to be taken if the target file does not exist)
+ * 0 - Fail
+ * 1 - Create file
+ */
+
+#define SMB_OFUN_OPEN_MASK 0x3
+#define SMB_OFUN_CREATE_MASK 0x10
+
+#define SMB_OFUN_OPEN_FAIL 0
+#define SMB_OFUN_OPEN_APPEND 1
+#define SMB_OFUN_OPEN_OPEN 1
+#define SMB_OFUN_OPEN_TRUNCATE 2
+
+#define SMB_OFUN_CREATE_FAIL 0x00
+#define SMB_OFUN_CREATE_CREATE 0x10
+
+/*
+ * The Action field of OpenAndX has the following format:
+ *
+ * 1111 11
+ * 5432 1098 7654 3210
+ * Lrrr rrrr rrrr rrOO
+ *
+ * where:
+ *
+ * L - Opportunistic lock. 1 if lock granted, else 0.
+ *
+ * O - Open action:
+ * 1 - The file existed and was opened
+ * 2 - The file did not exist but was created
+ * 3 - The file existed and was truncated
+ */
+
+#define SMB_OACT_LOCK 0x8000
+#define SMB_OACT_OPENED 0x01
+#define SMB_OACT_CREATED 0x02
+#define SMB_OACT_TRUNCATED 0x03
+
+#define SMB_OACT_OPLOCK 0x8000
+
+#define SMB_FTYPE_DISK 0
+#define SMB_FTYPE_BYTE_PIPE 1
+#define SMB_FTYPE_MESG_PIPE 2
+#define SMB_FTYPE_PRINTER 3
+#define SMB_FTYPE_UNKNOWN 0xFFFF
+
+#define SMB_DEVST_BLOCKING 0x8000
+#define SMB_DEVST_ENDPOINT 0x4000
+#define SMB_DEVST_TYPE_MASK 0x0C00
+#define SMB_DEVST_TYPE_BYTE_PIPE 0x0000
+#define SMB_DEVST_TYPE_MESG_PIPE 0x0400
+#define SMB_DEVST_RMODE_MASK 0x0300
+#define SMB_DEVST_RMODE_BYTES 0x0000
+#define SMB_DEVST_RMODE_MESGS 0x0100
+#define SMB_DEVST_ICOUNT_MASK 0x00FF /* not used */
+
+#define SMB_FTYPE_IS_DISK(F) ((F) == SMB_FTYPE_DISK)
+#define SMB_FTYPE_IS_PIPE(F) \
+ (((F) == SMB_FTYPE_BYTE_PIPE) || ((F) == SMB_FTYPE_MESG_PIPE))
+#define SMB_FTYPE_IS_PRINTER(F) ((F) == SMB_FTYPE_PRINTER)
+
+/*
+ * TRANS2_FIND
+ */
+#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+#define SMB_FIND_FILE_NAMES_INFO 0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+#define SMB_MAC_FIND_BOTH_HFS_INFO MAC_FIND_BOTH_HFS_INFO
+
+
+/*
+ * Flags for TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
+ * (NTDDK cifs.h and smbtrans.h).
+ *
+ * If SMB_FIND_RETURN_RESUME_KEYS was set in the request parameters,
+ * each entry is preceded by a four-byte resume key.
+ */
+#define SMB_FIND_CLOSE_AFTER_REQUEST 0x01
+#define SMB_FIND_CLOSE_AT_EOS 0x02
+#define SMB_FIND_RETURN_RESUME_KEYS 0x04
+#define SMB_FIND_CONTINUE_FROM_LAST 0x08
+#define SMB_FIND_WITH_BACKUP_INTENT 0x10
+
+
+/*
+ * TRANS2_QUERY_FS_INFORMATION
+ */
+#define SMB_INFO_ALLOCATION 1
+#define SMB_INFO_VOLUME 2
+#define SMB_QUERY_FS_LABEL_INFO 0x101
+#define SMB_QUERY_FS_VOLUME_INFO 0x102
+#define SMB_QUERY_FS_SIZE_INFO 0x103
+#define SMB_QUERY_FS_DEVICE_INFO 0x104
+#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+#define SMB_QUERY_FS_QUOTA_INFO 0x106 /* unused? */
+#define SMB_QUERY_FS_CONTROL_INFO 0x107
+#define SMB_MAC_QUERY_FS_INFO MAC_QUERY_FS_INFO
+
+
+/* TRANS2_QUERY_{PATH,FILE}_INFORMATION */
+
+#define SMB_INFO_STANDARD 1
+#define SMB_INFO_QUERY_EA_SIZE 2
+#define SMB_INFO_SET_EAS 2
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3
+#define SMB_INFO_QUERY_ALL_EAS 4
+#define SMB_INFO_QUERY_FULL_NAME 5
+#define SMB_INFO_IS_NAME_VALID 6
+#define SMB_INFO_PASSTHROUGH 1000
+
+#define SMB_QUERY_FILE_BASIC_INFO 0x101
+#define SMB_QUERY_FILE_STANDARD_INFO 0x102
+#define SMB_QUERY_FILE_EA_INFO 0x103
+#define SMB_QUERY_FILE_NAME_INFO 0x104
+#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
+#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
+#define SMB_QUERY_FILE_ALL_INFO 0x107
+#define SMB_QUERY_FILE_ALT_NAME_INFO 0x108
+#define SMB_QUERY_FILE_STREAM_INFO 0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+#define SMB_MAC_SET_FINDER_INFO MAC_SET_FINDER_INFO
+#define SMB_MAC_DT_ADD_APPL MAC_DT_ADD_APPL
+#define SMB_MAC_DT_REMOVE_APPL MAC_DT_REMOVE_APPL
+#define SMB_MAC_DT_GET_APPL MAC_DT_GET_APPL
+#define SMB_MAC_DT_GET_ICON MAC_DT_GET_ICON
+#define SMB_MAC_DT_GET_ICON_INFO MAC_DT_GET_ICON_INFO
+#define SMB_MAC_DT_ADD_ICON MAC_DT_ADD_ICON
+
+#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_DISPOSITION_INFO 0x102
+#define SMB_SET_FILE_ALLOCATION_INFO 0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+
+
+/*
+ * The following bits may be set in the SecurityMode field of the
+ * SMB_COM_NEGOTIATE response.
+ *
+ * Notes:
+ * NEGOTIATE_SECURITY_SHARE_LEVEL is a montana2 invention.
+ *
+ * The NTDDK cifs.h definitions are:
+ * #define NEGOTIATE_USER_SECURITY 0x01
+ * #define NEGOTIATE_ENCRYPT_PASSWORDS 0x02
+ * #define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+ * #define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+ */
+#define NEGOTIATE_SECURITY_SHARE_LEVEL 0x00
+#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
+#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
+#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+
+
+/*
+ * Negotiated Capabilities (CIFS/1.0 section 4.1.1)
+ *
+ * Capabilities allow the server to tell the client what it supports.
+ * Undefined bits MUST be set to zero by servers, and MUST be ignored
+ * by clients. The bit definitions are:
+ *
+ * Capability Name Encoding Meaning
+ * ==================== ======== ==================================
+ * CAP_RAW_MODE 0x0001 The server supports SMB_COM_READ_RAW and
+ * SMB_COM_WRITE_RAW (obsolescent)
+ * CAP_MPX_MODE 0x0002 The server supports SMB_COM_READ_MPX and
+ * SMB_COM_WRITE_MPX (obsolescent)
+ * CAP_UNICODE 0x0004 The server supports Unicode strings
+ * CAP_LARGE_FILES 0x0008 The server supports large files with 64
+ * bit offsets
+ * CAP_NT_SMBS 0x0010 The server supports the SMBs particular
+ * to the NT LM 0.12 dialect.
+ * Implies CAP_NT_FIND.
+ * CAP_RPC_REMOTE_APIS 0x0020 The server supports remote admin API
+ * requests via DCE RPC
+ * CAP_STATUS32 0x0040 The server can respond with 32 bit
+ * status codes in Status.Status
+ * CAP_LEVEL_II_OPLOCKS 0x0080 The server supports level 2 oplocks
+ * CAP_LOCK_AND_READ 0x0100 The server supports the
+ * SMB_COM_LOCK_AND_READ SMB
+ * CAP_NT_FIND 0x0200
+ * CAP_BULK_TRANSFER 0x0400
+ * CAP_COMPRESSED_BULK 0x0800
+ * CAP_DFS 0x1000 The server is DFS aware
+ * CAP_LARGE_READX 0x4000 The server supports large
+ * SMB_COM_READ_ANDX
+ * CAP_LARGE_WRITEX 0x8000 The server supports large
+ * SMB_COM_WRITE_ANDX
+ * CAP_RESERVED 0x02000000 Reserved for future use.
+ * CAP_EXTENDED_SECURITY 0x80000000 The server supports extended security
+ * exchanges.
+ *
+ * Extended security exchanges provides a means of supporting arbitrary
+ * authentication protocols within CIFS. Security blobs are opaque to the
+ * CIFS protocol; they are messages in some authentication protocol that
+ * has been agreed upon by client and server by some out of band mechanism,
+ * for which CIFS merely functions as a transport. When
+ * CAP_EXTENDED_SECURITY is negotiated, the server includes a first
+ * security blob in its response; subsequent security blobs are exchanged
+ * in SMB_COM_SESSION_SETUP_ANDX requests and responses until the
+ * authentication protocol terminates.
+ */
+#define CAP_RAW_MODE 0x0001
+#define CAP_MPX_MODE 0x0002
+#define CAP_UNICODE 0x0004
+#define CAP_LARGE_FILES 0x0008
+#define CAP_NT_SMBS 0x0010
+#define CAP_RPC_REMOTE_APIS 0x0020
+#define CAP_STATUS32 0x0040
+#define CAP_LEVEL_II_OPLOCKS 0x0080
+#define CAP_LOCK_AND_READ 0x0100
+#define CAP_NT_FIND 0x0200
+#define CAP_BULK_TRANSFER 0x0400
+#define CAP_COMPRESSED_BULK 0x0800
+#define CAP_DFS 0x1000
+#define CAP_LARGE_READX 0x4000
+#define CAP_LARGE_WRITEX 0x8000
+#define CAP_RESERVED 0x02000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+
+/*
+ * Different device types according to NT
+ */
+#define FILE_DEVICE_BEEP 0x00000001
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_CONTROLLER 0x00000004
+#define FILE_DEVICE_DATALINK 0x00000005
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_INPORT_PORT 0x0000000a
+#define FILE_DEVICE_KEYBOARD 0x0000000b
+#define FILE_DEVICE_MAILSLOT 0x0000000c
+#define FILE_DEVICE_MIDI_IN 0x0000000d
+#define FILE_DEVICE_MIDI_OUT 0x0000000e
+#define FILE_DEVICE_MOUSE 0x0000000f
+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SCANNER 0x00000019
+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_SCREEN 0x0000001c
+#define FILE_DEVICE_SOUND 0x0000001d
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_TRANSPORT 0x00000021
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_VIDEO 0x00000023
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_WAVE_IN 0x00000025
+#define FILE_DEVICE_WAVE_OUT 0x00000026
+#define FILE_DEVICE_8042_PORT 0x00000027
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+#define FILE_DEVICE_BATTERY 0x00000029
+#define FILE_DEVICE_BUS_EXTENDER 0x0000002a
+#define FILE_DEVICE_MODEM 0x0000002b
+#define FILE_DEVICE_VDM 0x0000002c
+
+/*
+ * Some of these device types are not currently accessible over the network
+ * and may never be accessible over the network. Some may change to be
+ *
+ * accessible over the network. The values for device types that may never
+ * be accessible over the network may be redefined to be just reserved at
+ * some date in the future.
+ *
+ * Characteristics is the sum of any of the following:
+ */
+
+#define FILE_REMOVABLE_MEDIA 0x00000001
+#define FILE_READ_ONLY_DEVICE 0x00000002
+#define FILE_FLOPPY_DISKETTE 0x00000004
+#define FILE_WRITE_ONE_MEDIA 0x00000008
+#define FILE_REMOTE_DEVICE 0x00000010
+#define FILE_DEVICE_IS_MOUNTED 0x00000020
+#define FILE_VIRTUAL_VOLUME 0x00000040
+
+/*
+ * CREATE_ANDX ShareAccess Flags
+ */
+
+#define FILE_SHARE_NONE 0x00000000
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_ALL 0x00000007
+#define FILE_SHARE_VALID_FLAGS 0x00000007
+
+
+/*
+ * CREATE_ANDX CreateDisposition flags
+ *
+ * FILE_SUPERSEDE If the file already exists it should be superseded
+ * by the specified file. If the file does not already
+ * exist then it should be created.
+ *
+ * FILE_CREATE If the file already exists the operation should fail.
+ * If the file does not already exist then it should be
+ * created. (aka CREATE_NEW)
+ *
+ * FILE_OPEN If the file already exists then it should be opened.
+ * If the file does not already exist then the operation
+ * should fail. (aka OPEN_EXISTING)
+ *
+ * FILE_OPEN_IF If the file already exists then it should be opened.
+ * If the file does not already exist then it should be
+ * created. (aka OPEN_ALWAYS)
+ *
+ * FILE_OVERWRITE If the file already exists, it should be opened and
+ * overwritten. If the file does not already exist then
+ * the operation should fail. (aka TRUNCATE_EXISTING)
+ *
+ * FILE_OVERWRITE_IF If the file already exists, it should be opened and
+ * overwritten. If the file does not already exist then
+ * it should be created. (aka CREATE_ALWAYS)
+ */
+#define FILE_SUPERSEDE 0x00000000
+#define FILE_OPEN 0x00000001
+#define FILE_CREATE 0x00000002
+#define FILE_OPEN_IF 0x00000003
+#define FILE_OVERWRITE 0x00000004
+#define FILE_OVERWRITE_IF 0x00000005
+#define FILE_MAXIMUM_DISPOSITION 0x00000005
+
+/*
+ * CREATE_ANDX Impersonation levels
+ */
+
+#define SECURITY_ANONYMOUS 0x00000001
+#define SECURITY_IDENTIFICATION 0x00000002
+#define SECURITY_IMPERSONATION 0x00000003
+#define SECURITY_DELEGATION 0x00000004
+
+/*
+ * CREATE_ANDX SecurityFlags
+ */
+
+#define SECURITY_CONTEXT_TRACKING 0x00000001
+#define SECURITY_EFFECTIVE_ONLY 0x00000002
+
+/*
+ * Server types
+ */
+#define SV_WORKSTATION 0x00000001 /* All workstations */
+#define SV_SERVER 0x00000002 /* All servers */
+#define SV_SQLSERVER 0x00000004 /* running with SQL server */
+#define SV_DOMAIN_CTRL 0x00000008 /* Primary domain controller */
+#define SV_DOMAIN_BAKCTRL 0x00000010 /* Backup domain controller */
+#define SV_TIME_SOURCE 0x00000020 /* running timesource service */
+#define SV_AFP 0x00000040 /* Apple File Protocol */
+#define SV_NOVELL 0x00000080 /* Novell servers */
+#define SV_DOMAIN_MEMBER 0x00000100 /* Domain Member */
+#define SV_PRINTQ_SERVER 0x00000200 /* Server sharing print queue */
+#define SV_DIALIN_SERVER 0x00000400 /* Server running dialin */
+#define SV_XENIX_SERVER 0x00000800 /* Xenix server */
+#define SV_NT 0x00001000 /* NT server */
+#define SV_WFW 0x00002000 /* Server running Windows for */
+#define SV_SERVER_NT 0x00008000 /* Windows NT non DC server */
+#define SV_POTENTIAL_BROWSER 0x00010000 /* can run browser service */
+#define SV_BACKUP_BROWSER 0x00020000 /* Backup browser server */
+#define SV_MASTER_BROWSER 0x00040000 /* Master browser server */
+#define SV_DOMAIN_MASTER 0x00080000 /* Domain Master Browser */
+#define SV_OSF 0x00100000 /* OSF operating system */
+#define SV_VMS 0x00200000 /* VMS operating system */
+#define SV_WINDOWS_95_PLUS 0x00400000 /* Windows 95 or better */
+
+#define SV_LOCAL_LIST_ONLY 0x40000000 /* Enumerate only "local" */
+#define SV_TYPE_DOMAIN_ENUM 0x80000000 /* Enumerate Domains */
+
+#define MY_SERVER_TYPE (SV_SERVER | SV_NT | SV_SERVER_NT | SV_DOMAIN_MEMBER)
+
+
+#define PRQ_ACTIVE 0 /* Active */
+#define PRQ_PAUSE 1 /* Paused */
+#define PRQ_ERROR 2 /* Error Occurred */
+#define PRQ_PENDING 3 /* Deletion pending */
+
+#define PRJ_QS_QUEUED 0 /* Active */
+#define PRJ_QS_PAUSED 1 /* Paused */
+#define PRJ_QS_SPOOLING 2 /* Paused */
+#define PRJ_QS_PRINTING 3 /* Paused */
+
+
+#define SHARE_ACCESS_READ 0x01 /* read & execute from resource */
+#define SHARE_ACCESS_WRITE 0x02 /* write data to resource */
+#define SHARE_ACCESS_CREATE 0x04 /* create an instance of */
+#define SHARE_ACCESS_EXEC 0x08 /* execute from resource */
+#define SHARE_ACCESS_DELETE 0x10 /* Permission to delete the resource */
+#define SHARE_ACCESS_ATTRIB 0x20 /* Permission to modify the resource */
+#define SHARE_ACCESS_PERM 0x40 /* Permission to change permissions */
+#define SHARE_ACCESS_ALL 0x7F /* All of the above permissions */
+
+
+/*
+ * SMB_COM_NT_TRANSACTION sub-command codes (CIFS/1.0 section 5.3)
+ *
+ * SubCommand Code Value Description
+ * =============================== ===== =================================
+ * NT_TRANSACT_CREATE 1 File open/create
+ * NT_TRANSACT_IOCTL 2 Device IOCTL
+ * NT_TRANSACT_SET_SECURITY_DESC 3 Set security descriptor
+ * NT_TRANSACT_NOTIFY_CHANGE 4 Start directory watch
+ * NT_TRANSACT_RENAME 5 Reserved (handle-based rename)
+ * NT_TRANSACT_QUERY_SECURITY_DESC 6 Retrieve security descriptor
+ * NT_TRANSACT_QUERY_QUOTA 7 Retrieve quota information
+ * NT_TRANSACT_SET_QUOTA 8 Set quota information
+ */
+#define NT_TRANSACT_MIN_FUNCTION 1
+
+#define NT_TRANSACT_CREATE 1
+#define NT_TRANSACT_IOCTL 2
+#define NT_TRANSACT_SET_SECURITY_DESC 3
+#define NT_TRANSACT_NOTIFY_CHANGE 4
+#define NT_TRANSACT_RENAME 5
+#define NT_TRANSACT_QUERY_SECURITY_DESC 6
+#define NT_TRANSACT_QUERY_QUOTA 7
+#define NT_TRANSACT_SET_QUOTA 8
+
+#define NT_TRANSACT_MAX_FUNCTION 8
+
+
+/*
+ * Pipe states
+ */
+#define SMB_PIPE_READMODE_BYTE 0x0000
+#define SMB_PIPE_READMODE_MESSAGE 0x0100
+#define SMB_PIPE_TYPE_BYTE 0x0000
+#define SMB_PIPE_TYPE_MESSAGE 0x0400
+#define SMB_PIPE_END_CLIENT 0x0000
+#define SMB_PIPE_END_SERVER 0x4000
+#define SMB_PIPE_WAIT 0x0000
+#define SMB_PIPE_NOWAIT 0x8000
+#define SMB_PIPE_UNLIMITED_INSTANCES 0x00FF
+
+/*
+ * smb_com_seek request
+ */
+#define SMB_SEEK_SET 0 /* set file offset to specified offset */
+#define SMB_SEEK_CUR 1 /* set file offset to current plus specified offset */
+#define SMB_SEEK_END 2 /* set file offset to EOF plus specified offset */
+
+/*
+ * API Numbers for Transact based RAP (Remote Administration Protocol) calls
+ */
+#define API_WshareEnum 0
+#define API_WshareGetInfo 1
+#define API_WshareSetInfo 2
+#define API_WshareAdd 3
+#define API_WshareDel 4
+#define API_NetShareCheck 5
+#define API_WsessionEnum 6
+#define API_WsessionGetInfo 7
+#define API_WsessionDel 8
+#define API_WconnectionEnum 9
+#define API_WfileEnum 10
+#define API_WfileGetInfo 11
+#define API_WfileClose 12
+#define API_WserverGetInfo 13
+#define API_WserverSetInfo 14
+#define API_WserverDiskEnum 15
+#define API_WserverAdminCommand 16
+#define API_NetAuditOpen 17
+#define API_WauditClear 18
+#define API_NetErrorLogOpen 19
+#define API_WerrorLogClear 20
+#define API_NetCharDevEnum 21
+#define API_NetCharDevGetInfo 22
+#define API_WCharDevControl 23
+#define API_NetCharDevQEnum 24
+#define API_NetCharDevQGetInfo 25
+#define API_WCharDevQSetInfo 26
+#define API_WCharDevQPurge 27
+#define API_WCharDevQPurgeSelf 28
+#define API_WMessageNameEnum 29
+#define API_WMessageNameGetInfo 30
+#define API_WMessageNameAdd 31
+#define API_WMessageNameDel 32
+#define API_WMessageNameFwd 33
+#define API_WMessageNameUnFwd 34
+#define API_WMessageBufferSend 35
+#define API_WMessageFileSend 36
+#define API_WMessageLogFileSet 37
+#define API_WMessageLogFileGet 38
+#define API_WServiceEnum 39
+#define API_WServiceInstall 40
+#define API_WServiceControl 41
+#define API_WAccessEnum 42
+#define API_WAccessGetInfo 43
+#define API_WAccessSetInfo 44
+#define API_WAccessAdd 45
+#define API_WAccessDel 46
+#define API_WGroupEnum 47
+#define API_WGroupAdd 48
+#define API_WGroupDel 49
+#define API_WGroupAddUser 50
+#define API_WGroupDelUser 51
+#define API_WGroupGetUsers 52
+#define API_WUserEnum 53
+#define API_WUserAdd 54
+#define API_WUserDel 55
+#define API_WUserGetInfo 56
+#define API_WUserSetInfo 57
+#define API_WUserPasswordSet 58
+#define API_WUserGetGroups 59
+#define API_DeadTableEntry 60
+#define API_WWkstaSetUID 62
+#define API_WWkstaGetInfo 63
+#define API_WWkstaSetInfo 64
+#define API_WUseEnum 65
+#define API_WUseAdd 66
+#define API_WUseDel 67
+#define API_WUseGetInfo 68
+#define API_WPrintQEnum 69
+#define API_WPrintQGetInfo 70
+#define API_WPrintQSetInfo 71
+#define API_WPrintQAdd 72
+#define API_WPrintQDel 73
+#define API_WPrintQPause 74
+#define API_WPrintQContinue 75
+#define API_WPrintJobEnum 76
+#define API_WPrintJobGetInfo 77
+#define API_WPrintJobSetInfo_OLD 78
+#define API_WPrintJobDel 81
+#define API_WPrintJobPause 82
+#define API_WPrintJobContinue 83
+#define API_WPrintDestEnum 84
+#define API_WPrintDestGetInfo 85
+#define API_WPrintDestControl 86
+#define API_WProfileSave 87
+#define API_WProfileLoad 88
+#define API_WStatisticsGet 89
+#define API_WStatisticsClear 90
+#define API_NetRemoteTOD 91
+#define API_WNetBiosEnum 92
+#define API_WNetBiosGetInfo 93
+#define API_NetServerEnum 94
+#define API_I_NetServerEnum 95
+#define API_WServiceGetInfo 96
+#define API_WPrintQPurge 103
+#define API_NetServerEnum2 104
+#define API_WAccessGetUserPerms 105
+#define API_WGroupGetInfo 106
+#define API_WGroupSetInfo 107
+#define API_WGroupSetUsers 108
+#define API_WUserSetGroups 109
+#define API_WUserModalsGet 110
+#define API_WUserModalsSet 111
+#define API_WFileEnum2 112
+#define API_WUserAdd2 113
+#define API_WUserSetInfo2 114
+#define API_WUserPasswordSet2 115
+#define API_I_NetServerEnum2 116
+#define API_WConfigGet2 117
+#define API_WConfigGetAll2 118
+#define API_WGetDCName 119
+#define API_NetHandleGetInfo 120
+#define API_NetHandleSetInfo 121
+#define API_WStatisticsGet2 122
+#define API_WBuildGetInfo 123
+#define API_WFileGetInfo2 124
+#define API_WFileClose2 125
+#define API_WNetServerReqChallenge 126
+#define API_WNetServerAuthenticate 127
+#define API_WNetServerPasswordSet 128
+#define API_WNetAccountDeltas 129
+#define API_WNetAccountSync 130
+#define API_WUserEnum2 131
+#define API_WWkstaUserLogon 132
+#define API_WWkstaUserLogoff 133
+#define API_WLogonEnum 134
+#define API_WErrorLogRead 135
+#define API_WI_NetPathType 136
+#define API_WI_NetPathCanonicalize 137
+#define API_WI_NetPathCompare 138
+#define API_WI_NetNameValidate 139
+#define API_WI_NetNameCanonicalize 140
+#define API_WI_NetNameCompare 141
+#define API_WAuditRead 142
+#define API_WPrintDestAdd 143
+#define API_WPrintDestSetInfo 144
+#define API_WPrintDestDel 145
+#define API_WUserValidate2 146
+#define API_WPrintJobSetInfo 147
+#define API_TI_NetServerDiskEnum 148
+#define API_TI_NetServerDiskGetInfo 149
+#define API_TI_FTVerifyMirror 150
+#define API_TI_FTAbortVerify 151
+#define API_TI_FTGetInfo 152
+#define API_TI_FTSetInfo 153
+#define API_TI_FTLockDisk 154
+#define API_TI_FTFixError 155
+#define API_TI_FTAbortFix 156
+#define API_TI_FTDiagnoseError 157
+#define API_TI_FTGetDriveStats 158
+#define API_TI_FTErrorGetInfo 160
+#define API_NetAccessCheck 163
+#define API_NetAlertRaise 164
+#define API_NetAlertStart 165
+#define API_NetAlertStop 166
+#define API_NetAuditWrite 167
+#define API_NetIRemoteAPI 168
+#define API_NetServiceStatus 169
+#define API_I_NetServerRegister 170
+#define API_I_NetServerDeregister 171
+#define API_I_NetSessionEntryMake 172
+#define API_I_NetSessionEntryClear 173
+#define API_I_NetSessionEntryGetInfo 174
+#define API_I_NetSessionEntrySetInfo 175
+#define API_I_NetConnectionEntryMake 176
+#define API_I_NetConnectionEntryClear 177
+#define API_I_NetConnectionEntrySetInfo 178
+#define API_I_NetConnectionEntryGetInfo 179
+#define API_I_NetFileEntryMake 180
+#define API_I_NetFileEntryClear 181
+#define API_I_NetFileEntrySetInfo 182
+#define API_I_NetFileEntryGetInfo 183
+#define API_AltSrvMessageBufferSend 184
+#define API_AltSrvMessageFileSend 185
+#define API_wI_NetRplWkstaEnum 186
+#define API_wI_NetRplWkstaGetInfo 187
+#define API_wI_NetRplWkstaSetInfo 188
+#define API_wI_NetRplWkstaAdd 189
+#define API_wI_NetRplWkstaDel 190
+#define API_wI_NetRplProfileEnum 191
+#define API_wI_NetRplProfileGetInfo 192
+#define API_wI_NetRplProfileSetInfo 193
+#define API_wI_NetRplProfileAdd 194
+#define API_wI_NetRplProfileDel 195
+#define API_wI_NetRplProfileClone 196
+#define API_wI_NetRplBaseProfileEnum 197
+#define API_WIServerSetInfo 201
+#define API_WPrintDriverEnum 205
+#define API_WPrintQProcessorEnum 206
+#define API_WPrintPortEnum 207
+#define API_WNetWriteUpdateLog 208
+#define API_WNetAccountUpdate 209
+#define API_WNetAccountConfirmUpdate 210
+#define API_WConfigSet 211
+#define API_WAccountsReplicate 212
+#define API_SamOEMChgPasswordUser2_P 214
+#define API_NetServerEnum3 215
+#define API_WprintDriverGetInfo 250
+#define API_WprintDriverSetInfo 251
+#define API_WaliasAdd 252
+#define API_WaliasDel 253
+#define API_WaliasGetInfo 254
+#define API_WaliasSetInfo 255
+#define API_WaliasEnum 256
+#define API_WuserGetLogonAsn 257
+#define API_WuserSetLogonAsn 258
+#define API_WuserGetAppSel 259
+#define API_WuserSetAppSel 260
+#define API_WappAdd 261
+#define API_WappDel 262
+#define API_WappGetInfo 263
+#define API_WappSetInfo 264
+#define API_WappEnum 265
+#define API_WUserDCDBInit 266
+#define API_WDASDAdd 267
+#define API_WDASDDel 268
+#define API_WDASDGetInfo 269
+#define API_WDASDSetInfo 270
+#define API_WDASDEnum 271
+#define API_WDASDCheck 272
+#define API_WDASDCtl 273
+#define API_WuserRemoteLogonCheck 274
+#define API_WUserPasswordSet3 275
+#define API_WCreateRIPLMachine 276
+#define API_WDeleteRIPLMachine 277
+#define API_WGetRIPLMachineInfo 278
+#define API_WSetRIPLMachineInfo 279
+#define API_WEnumRIPLMachine 280
+#define API_WI_ShareAdd 281
+#define API_WI_AliasEnum 282
+#define API_WaccessApply 283
+#define API_WPrt16Query 284
+#define API_WPrt16Set 285
+#define API_WUserDel100 286
+#define API_WUserRemoteLogonCheck2 287
+#define API_WRemoteTODSet 294
+#define API_WprintJobMoveAll 295
+#define API_W16AppParmAdd 296
+#define API_W16AppParmDel 297
+#define API_W16AppParmGet 298
+#define API_W16AppParmSet 299
+#define API_W16RIPLMachineCreate 300
+#define API_W16RIPLMachineGetInfo 301
+#define API_W16RIPLMachineSetInfo 302
+#define API_W16RIPLMachineEnum 303
+#define API_W16RIPLMachineListParmEnum 304
+#define API_W16RIPLMachClassGetInfo 305
+#define API_W16RIPLMachClassEnum 306
+#define API_W16RIPLMachClassCreate 307
+#define API_W16RIPLMachClassSetInfo 308
+#define API_W16RIPLMachClassDelete 309
+#define API_W16RIPLMachClassLPEnum 310
+#define API_W16RIPLMachineDelete 311
+#define API_W16WSLevelGetInfo 312
+#define API_WserverNameAdd 313
+#define API_WserverNameDel 314
+#define API_WserverNameEnum 315
+#define API_I_WDASDEnum 316
+#define API_I_WDASDEnumTerminate 317
+#define API_I_WDASDSetInfo2 318
+#define MAX_RAP_API 318
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CIFS_H */
diff --git a/usr/src/uts/common/smbsrv/codepage.h b/usr/src/uts/common/smbsrv/codepage.h
new file mode 100644
index 0000000000..baefb9de22
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/codepage.h
@@ -0,0 +1,85 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CODEPAGE_H
+#define _SMBSRV_CODEPAGE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/string.h>
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Labels to define whether a code page table entry is an uppercase
+ * character, a lowercase character or neither. One of these values
+ * should appear in the ctype field of the code page tables.
+ */
+#define CODEPAGE_ISNONE 0x00
+#define CODEPAGE_ISUPPER 0x01
+#define CODEPAGE_ISLOWER 0x02
+
+/*
+ * The structure of a code page entry. Each code page table will
+ * consist of an array of 256 codepage entries.
+ *
+ * ctype indicates case of the value.
+ * upper indicates the uppercase equivalent value.
+ * lower indicates the lowercase equivalent value.
+ */
+typedef struct codepage {
+ unsigned char ctype;
+ mts_wchar_t upper;
+ mts_wchar_t lower;
+} codepage_t;
+
+/*
+ * Global pointer to the current code page. This is
+ * defaulted to a standard ASCII table.
+ */
+extern codepage_t usascii_codepage[];
+
+/*
+ * This buffer is used to store the language string for display.
+ */
+#define CODEPAGE_BUFSIZ 48
+
+extern int oem_language_set(char *language);
+extern unsigned int oem_get_smb_cpid(void);
+extern unsigned int oem_get_telnet_cpid(void);
+
+extern int codepage_isupper(int c);
+extern int codepage_islower(int c);
+extern int codepage_toupper(int c);
+extern int codepage_tolower(int c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CODEPAGE_H */
diff --git a/usr/src/uts/common/smbsrv/cp_cyrillic.h b/usr/src/uts/common/smbsrv/cp_cyrillic.h
new file mode 100644
index 0000000000..d3b2a27596
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_cyrillic.h
@@ -0,0 +1,312 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_CYRILLIC_H
+#define _SMBSRV_CP_CYRILLIC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for Cyrillic Character Set
+ * This codepage defines values for the special
+ * characters needed for the written alphabets of the
+ * following languages: Bulgarian, Byelorussian,
+ * Macedonian, Russian, Serbian, and pre-1990 Ukrainian
+ * The cyrillic character set is also known as iso-8859-5
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t cyrillic_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00f1 }, /* 0x00a1 */
+ { CODEPAGE_ISUPPER, 0x00a2, 0x00f2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00f3 }, /* 0x00a3 */
+ { CODEPAGE_ISUPPER, 0x00a4, 0x00f4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00f5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00f6 }, /* 0x00a6 */
+ { CODEPAGE_ISUPPER, 0x00a7, 0x00f7 }, /* 0x00a7 */
+ { CODEPAGE_ISUPPER, 0x00a8, 0x00f8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00f9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00fa }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00fb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00fc }, /* 0x00ac */
+ { CODEPAGE_ISUPPER, 0x00ad, 0x00fd }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00fe }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00ff }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISNONE, 0x00d1, 0x00d1 }, /* 0x00d1 */
+ { CODEPAGE_ISNONE, 0x00d2, 0x00d2 }, /* 0x00d2 */
+ { CODEPAGE_ISNONE, 0x00d3, 0x00d3 }, /* 0x00d3 */
+ { CODEPAGE_ISNONE, 0x00d4, 0x00d4 }, /* 0x00d4 */
+ { CODEPAGE_ISNONE, 0x00d5, 0x00d5 }, /* 0x00d5 */
+ { CODEPAGE_ISNONE, 0x00d6, 0x00d6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISNONE, 0x00d8, 0x00d8 }, /* 0x00d8 */
+ { CODEPAGE_ISNONE, 0x00d9, 0x00d9 }, /* 0x00d9 */
+ { CODEPAGE_ISNONE, 0x00da, 0x00da }, /* 0x00da */
+ { CODEPAGE_ISNONE, 0x00db, 0x00db }, /* 0x00db */
+ { CODEPAGE_ISNONE, 0x00dc, 0x00dc }, /* 0x00dc */
+ { CODEPAGE_ISNONE, 0x00dd, 0x00dd }, /* 0x00dd */
+ { CODEPAGE_ISNONE, 0x00de, 0x00de }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00a2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00a4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISLOWER, 0x00a7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00a8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00ad, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_CYRILLIC_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin1.h b/usr/src/uts/common/smbsrv/cp_latin1.h
new file mode 100644
index 0000000000..728b28e05b
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin1.h
@@ -0,0 +1,317 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_LATIN1_H
+#define _SMBSRV_CP_LATIN1_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the Latin-1 Character Set
+ * (Western Europe). This codepage defines values for
+ * the special characters needed for the written alphabets
+ * of the following Languages: French, Spanish, Catalan,
+ * Basque, Portuguese, Italian, Albanian, Rhaeto-Romanic,
+ * Dutch, German, Danish, Swedish, Norwegian, Finnish,
+ * Faroese, Icelandic, Irish, Scottish, English, Afrikaans
+ * and Swahili.
+ * This codepage is also used in North & South America,
+ * Canada, Australia, and much of Africa
+ * The Latin-1 character set is also Known as iso-8859-1.
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin1_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISNONE, 0x00a1, 0x00a1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISNONE, 0x00a6, 0x00a6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISNONE, 0x00a9, 0x00a9 }, /* 0x00a9 */
+ { CODEPAGE_ISNONE, 0x00aa, 0x00aa }, /* 0x00aa */
+ { CODEPAGE_ISNONE, 0x00ab, 0x00ab }, /* 0x00ab */
+ { CODEPAGE_ISNONE, 0x00ac, 0x00ac }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN1_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin2.h b/usr/src/uts/common/smbsrv/cp_latin2.h
new file mode 100644
index 0000000000..77f2e5a2a4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin2.h
@@ -0,0 +1,314 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_LATIN2_H
+#define _SMBSRV_CP_LATIN2_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the Latin-2 Character Set
+ * (Central & Eastern Europe). This codepage defines
+ * values for the special characters needed
+ * for the written alphabets of the following languages: Czech,
+ * Hungarian, Polish, Romanian, Croatian, Slovak,
+ * Slovenian, and Sorbian
+ * The Latin-2 character set is also known as iso-8859-2
+ *
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin2_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00b3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00b5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00be }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00bf }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN2_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin3.h b/usr/src/uts/common/smbsrv/cp_latin3.h
new file mode 100644
index 0000000000..afc7ae4355
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin3.h
@@ -0,0 +1,311 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_LATIN3_H
+#define _SMBSRV_CP_LATIN3_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for Latin-3 Character Set
+ * This codepage defines values for the special characters
+ * needed for the written alphabets of the following
+ * languages: Esperanto and Maltese.
+ * The Latin-3 character set is also known as iso-8859-3
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin3_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00bf }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISNONE, 0x00c3, 0x00c3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISNONE, 0x00e3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN3_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin4.h b/usr/src/uts/common/smbsrv/cp_latin4.h
new file mode 100644
index 0000000000..87e8282510
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin4.h
@@ -0,0 +1,312 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_LATIN4_H
+#define _SMBSRV_CP_LATIN4_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for Latin-4 Character Set.
+ * This codepage defines values for the special
+ * characters needed for the written alphabets of the
+ * following languages: Estonian, Baltic [Latvian &
+ * Lithuanian], Greenlandic, and Lappish
+ * The Latin-4 character set is also known as iso-8859-4
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin4_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00b3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00b5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00be }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN4_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin5.h b/usr/src/uts/common/smbsrv/cp_latin5.h
new file mode 100644
index 0000000000..87ad426348
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin5.h
@@ -0,0 +1,311 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_LATIN5_H
+#define _SMBSRV_CP_LATIN5_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the Latin-5 Character Set
+ * This codepage defines values for the special characters
+ * needed for the written alphabet of the following
+ * language: Turkish * The Latin-5 character set is also known as iso-8859-9.
+ *
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin5_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISNONE, 0x00a1, 0x00a1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISNONE, 0x00a6, 0x00a6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISNONE, 0x00a9, 0x00a9 }, /* 0x00a9 */
+ { CODEPAGE_ISNONE, 0x00aa, 0x00aa }, /* 0x00aa */
+ { CODEPAGE_ISNONE, 0x00ab, 0x00ab }, /* 0x00ab */
+ { CODEPAGE_ISNONE, 0x00ac, 0x00ac }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISUPPER, 0x00d0, 0x00f0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISLOWER, 0x00d0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN5_H */
diff --git a/usr/src/uts/common/smbsrv/cp_latin6.h b/usr/src/uts/common/smbsrv/cp_latin6.h
new file mode 100644
index 0000000000..fd86d276c4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_latin6.h
@@ -0,0 +1,309 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_LATIN6_H
+#define _SMBSRV_CP_LATIN6_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is the codepage for the Latin-6 Character Set.
+ * This codepage defines values for the special characters
+ * needed for the written alphabets of the following
+ * Nordic Languages: Greenlandic, Eskimo, Lappish,
+ * and Icelandic
+ * The Latin-6 character set is also known as iso-8859-10
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t Latin6_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISUPPER, 0x00a1, 0x00b1 }, /* 0x00a1 */
+ { CODEPAGE_ISUPPER, 0x00a2, 0x00b2 }, /* 0x00a2 */
+ { CODEPAGE_ISUPPER, 0x00a3, 0x00b3 }, /* 0x00a3 */
+ { CODEPAGE_ISUPPER, 0x00a4, 0x00b4 }, /* 0x00a4 */
+ { CODEPAGE_ISUPPER, 0x00a5, 0x00b5 }, /* 0x00a5 */
+ { CODEPAGE_ISUPPER, 0x00a6, 0x00b6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISUPPER, 0x00a8, 0x00b8 }, /* 0x00a8 */
+ { CODEPAGE_ISUPPER, 0x00a9, 0x00b9 }, /* 0x00a9 */
+ { CODEPAGE_ISUPPER, 0x00aa, 0x00ba }, /* 0x00aa */
+ { CODEPAGE_ISUPPER, 0x00ab, 0x00bb }, /* 0x00ab */
+ { CODEPAGE_ISUPPER, 0x00ac, 0x00bc }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISUPPER, 0x00ae, 0x00be }, /* 0x00ae */
+ { CODEPAGE_ISUPPER, 0x00af, 0x00bf }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISLOWER, 0x00a1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISLOWER, 0x00a2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISLOWER, 0x00a3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISLOWER, 0x00a4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISLOWER, 0x00a5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISLOWER, 0x00a6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISLOWER, 0x00a8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISLOWER, 0x00a9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISLOWER, 0x00aa, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISLOWER, 0x00ab, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISLOWER, 0x00ac, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISLOWER, 0x00ae, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISLOWER, 0x00af, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISUPPER, 0x00c0, 0x00e0 }, /* 0x00c0 */
+ { CODEPAGE_ISUPPER, 0x00c1, 0x00e1 }, /* 0x00c1 */
+ { CODEPAGE_ISUPPER, 0x00c2, 0x00e2 }, /* 0x00c2 */
+ { CODEPAGE_ISUPPER, 0x00c3, 0x00e3 }, /* 0x00c3 */
+ { CODEPAGE_ISUPPER, 0x00c4, 0x00e4 }, /* 0x00c4 */
+ { CODEPAGE_ISUPPER, 0x00c5, 0x00e5 }, /* 0x00c5 */
+ { CODEPAGE_ISUPPER, 0x00c6, 0x00e6 }, /* 0x00c6 */
+ { CODEPAGE_ISUPPER, 0x00c7, 0x00e7 }, /* 0x00c7 */
+ { CODEPAGE_ISUPPER, 0x00c8, 0x00e8 }, /* 0x00c8 */
+ { CODEPAGE_ISUPPER, 0x00c9, 0x00e9 }, /* 0x00c9 */
+ { CODEPAGE_ISUPPER, 0x00ca, 0x00ea }, /* 0x00ca */
+ { CODEPAGE_ISUPPER, 0x00cb, 0x00eb }, /* 0x00cb */
+ { CODEPAGE_ISUPPER, 0x00cc, 0x00ec }, /* 0x00cc */
+ { CODEPAGE_ISUPPER, 0x00cd, 0x00ed }, /* 0x00cd */
+ { CODEPAGE_ISUPPER, 0x00ce, 0x00ee }, /* 0x00ce */
+ { CODEPAGE_ISUPPER, 0x00cf, 0x00ef }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISUPPER, 0x00d1, 0x00f1 }, /* 0x00d1 */
+ { CODEPAGE_ISUPPER, 0x00d2, 0x00f2 }, /* 0x00d2 */
+ { CODEPAGE_ISUPPER, 0x00d3, 0x00f3 }, /* 0x00d3 */
+ { CODEPAGE_ISUPPER, 0x00d4, 0x00f4 }, /* 0x00d4 */
+ { CODEPAGE_ISUPPER, 0x00d5, 0x00f5 }, /* 0x00d5 */
+ { CODEPAGE_ISUPPER, 0x00d6, 0x00f6 }, /* 0x00d6 */
+ { CODEPAGE_ISUPPER, 0x00d7, 0x00f7 }, /* 0x00d7 */
+ { CODEPAGE_ISUPPER, 0x00d8, 0x00f8 }, /* 0x00d8 */
+ { CODEPAGE_ISUPPER, 0x00d9, 0x00f9 }, /* 0x00d9 */
+ { CODEPAGE_ISUPPER, 0x00da, 0x00fa }, /* 0x00da */
+ { CODEPAGE_ISUPPER, 0x00db, 0x00fb }, /* 0x00db */
+ { CODEPAGE_ISUPPER, 0x00dc, 0x00fc }, /* 0x00dc */
+ { CODEPAGE_ISUPPER, 0x00dd, 0x00fd }, /* 0x00dd */
+ { CODEPAGE_ISUPPER, 0x00de, 0x00fe }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISLOWER, 0x00c0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISLOWER, 0x00c1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISLOWER, 0x00c2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISLOWER, 0x00c3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISLOWER, 0x00c4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISLOWER, 0x00c5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISLOWER, 0x00c6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISLOWER, 0x00c7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISLOWER, 0x00c8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISLOWER, 0x00c9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISLOWER, 0x00ca, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISLOWER, 0x00cb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISLOWER, 0x00cc, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISLOWER, 0x00cd, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISLOWER, 0x00ce, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISLOWER, 0x00cf, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISLOWER, 0x00d1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISLOWER, 0x00d2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISLOWER, 0x00d3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISLOWER, 0x00d4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISLOWER, 0x00d5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISLOWER, 0x00d6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISLOWER, 0x00d7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISLOWER, 0x00d8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISLOWER, 0x00d9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISLOWER, 0x00da, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISLOWER, 0x00db, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISLOWER, 0x00dc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISLOWER, 0x00dd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISLOWER, 0x00de, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } /* 0x00ff */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_LATIN6_H */
diff --git a/usr/src/uts/common/smbsrv/cp_unicode.h b/usr/src/uts/common/smbsrv/cp_unicode.h
new file mode 100644
index 0000000000..e2f1eb83f9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_unicode.h
@@ -0,0 +1,6639 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_UNICODE_H
+#define _SMBSRV_CP_UNICODE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct unicode_cp {
+ mts_wchar_t val;
+ mts_wchar_t ctype;
+ mts_wchar_t lower;
+ mts_wchar_t upper;
+};
+
+struct unicode_cp a_unicode[] = {
+ { 0x0000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0001, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0002, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0003, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0004, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0005, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0006, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0007, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0008, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0009, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x000F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0010, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0011, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0012, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0013, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0014, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0015, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0016, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0017, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0018, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0019, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x001F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0020, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0021, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0022, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0023, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0024, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0025, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0026, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0027, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0028, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0029, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x002F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0030, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0031, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0032, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0033, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0034, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0035, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0036, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0037, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0038, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0039, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x003F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0040, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0041, CODEPAGE_ISUPPER, 0x0061, 0xFFFF },
+ { 0x0042, CODEPAGE_ISUPPER, 0x0062, 0xFFFF },
+ { 0x0043, CODEPAGE_ISUPPER, 0x0063, 0xFFFF },
+ { 0x0044, CODEPAGE_ISUPPER, 0x0064, 0xFFFF },
+ { 0x0045, CODEPAGE_ISUPPER, 0x0065, 0xFFFF },
+ { 0x0046, CODEPAGE_ISUPPER, 0x0066, 0xFFFF },
+ { 0x0047, CODEPAGE_ISUPPER, 0x0067, 0xFFFF },
+ { 0x0048, CODEPAGE_ISUPPER, 0x0068, 0xFFFF },
+ { 0x0049, CODEPAGE_ISUPPER, 0x0069, 0xFFFF },
+ { 0x004A, CODEPAGE_ISUPPER, 0x006A, 0xFFFF },
+ { 0x004B, CODEPAGE_ISUPPER, 0x006B, 0xFFFF },
+ { 0x004C, CODEPAGE_ISUPPER, 0x006C, 0xFFFF },
+ { 0x004D, CODEPAGE_ISUPPER, 0x006D, 0xFFFF },
+ { 0x004E, CODEPAGE_ISUPPER, 0x006E, 0xFFFF },
+ { 0x004F, CODEPAGE_ISUPPER, 0x006F, 0xFFFF },
+ { 0x0050, CODEPAGE_ISUPPER, 0x0070, 0xFFFF },
+ { 0x0051, CODEPAGE_ISUPPER, 0x0071, 0xFFFF },
+ { 0x0052, CODEPAGE_ISUPPER, 0x0072, 0xFFFF },
+ { 0x0053, CODEPAGE_ISUPPER, 0x0073, 0xFFFF },
+ { 0x0054, CODEPAGE_ISUPPER, 0x0074, 0xFFFF },
+ { 0x0055, CODEPAGE_ISUPPER, 0x0075, 0xFFFF },
+ { 0x0056, CODEPAGE_ISUPPER, 0x0076, 0xFFFF },
+ { 0x0057, CODEPAGE_ISUPPER, 0x0077, 0xFFFF },
+ { 0x0058, CODEPAGE_ISUPPER, 0x0078, 0xFFFF },
+ { 0x0059, CODEPAGE_ISUPPER, 0x0079, 0xFFFF },
+ { 0x005A, CODEPAGE_ISUPPER, 0x007A, 0xFFFF },
+ { 0x005B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x005F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0060, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0061, CODEPAGE_ISLOWER, 0xFFFF, 0x0041 },
+ { 0x0062, CODEPAGE_ISLOWER, 0xFFFF, 0x0042 },
+ { 0x0063, CODEPAGE_ISLOWER, 0xFFFF, 0x0043 },
+ { 0x0064, CODEPAGE_ISLOWER, 0xFFFF, 0x0044 },
+ { 0x0065, CODEPAGE_ISLOWER, 0xFFFF, 0x0045 },
+ { 0x0066, CODEPAGE_ISLOWER, 0xFFFF, 0x0046 },
+ { 0x0067, CODEPAGE_ISLOWER, 0xFFFF, 0x0047 },
+ { 0x0068, CODEPAGE_ISLOWER, 0xFFFF, 0x0048 },
+ { 0x0069, CODEPAGE_ISLOWER, 0xFFFF, 0x0049 },
+ { 0x006A, CODEPAGE_ISLOWER, 0xFFFF, 0x004A },
+ { 0x006B, CODEPAGE_ISLOWER, 0xFFFF, 0x004B },
+ { 0x006C, CODEPAGE_ISLOWER, 0xFFFF, 0x004C },
+ { 0x006D, CODEPAGE_ISLOWER, 0xFFFF, 0x004D },
+ { 0x006E, CODEPAGE_ISLOWER, 0xFFFF, 0x004E },
+ { 0x006F, CODEPAGE_ISLOWER, 0xFFFF, 0x004F },
+ { 0x0070, CODEPAGE_ISLOWER, 0xFFFF, 0x0050 },
+ { 0x0071, CODEPAGE_ISLOWER, 0xFFFF, 0x0051 },
+ { 0x0072, CODEPAGE_ISLOWER, 0xFFFF, 0x0052 },
+ { 0x0073, CODEPAGE_ISLOWER, 0xFFFF, 0x0053 },
+ { 0x0074, CODEPAGE_ISLOWER, 0xFFFF, 0x0054 },
+ { 0x0075, CODEPAGE_ISLOWER, 0xFFFF, 0x0055 },
+ { 0x0076, CODEPAGE_ISLOWER, 0xFFFF, 0x0056 },
+ { 0x0077, CODEPAGE_ISLOWER, 0xFFFF, 0x0057 },
+ { 0x0078, CODEPAGE_ISLOWER, 0xFFFF, 0x0058 },
+ { 0x0079, CODEPAGE_ISLOWER, 0xFFFF, 0x0059 },
+ { 0x007A, CODEPAGE_ISLOWER, 0xFFFF, 0x005A },
+ { 0x007B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x007F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0080, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0081, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0082, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0083, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0084, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0085, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0086, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0087, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0088, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0089, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x008F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0090, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0091, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0092, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0093, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0094, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0095, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0096, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0097, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0098, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0099, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x009F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00C0, CODEPAGE_ISUPPER, 0x00E0, 0xFFFF },
+ { 0x00C1, CODEPAGE_ISUPPER, 0x00E1, 0xFFFF },
+ { 0x00C2, CODEPAGE_ISUPPER, 0x00E2, 0xFFFF },
+ { 0x00C3, CODEPAGE_ISUPPER, 0x00E3, 0xFFFF },
+ { 0x00C4, CODEPAGE_ISUPPER, 0x00E4, 0xFFFF },
+ { 0x00C5, CODEPAGE_ISUPPER, 0x00E5, 0xFFFF },
+ { 0x00C6, CODEPAGE_ISUPPER, 0x00E6, 0xFFFF },
+ { 0x00C7, CODEPAGE_ISUPPER, 0x00E7, 0xFFFF },
+ { 0x00C8, CODEPAGE_ISUPPER, 0x00E8, 0xFFFF },
+ { 0x00C9, CODEPAGE_ISUPPER, 0x00E9, 0xFFFF },
+ { 0x00CA, CODEPAGE_ISUPPER, 0x00EA, 0xFFFF },
+ { 0x00CB, CODEPAGE_ISUPPER, 0x00EB, 0xFFFF },
+ { 0x00CC, CODEPAGE_ISUPPER, 0x00EC, 0xFFFF },
+ { 0x00CD, CODEPAGE_ISUPPER, 0x00ED, 0xFFFF },
+ { 0x00CE, CODEPAGE_ISUPPER, 0x00EE, 0xFFFF },
+ { 0x00CF, CODEPAGE_ISUPPER, 0x00EF, 0xFFFF },
+ { 0x00D0, CODEPAGE_ISUPPER, 0x00F0, 0xFFFF },
+ { 0x00D1, CODEPAGE_ISUPPER, 0x00F1, 0xFFFF },
+ { 0x00D2, CODEPAGE_ISUPPER, 0x00F2, 0xFFFF },
+ { 0x00D3, CODEPAGE_ISUPPER, 0x00F3, 0xFFFF },
+ { 0x00D4, CODEPAGE_ISUPPER, 0x00F4, 0xFFFF },
+ { 0x00D5, CODEPAGE_ISUPPER, 0x00F5, 0xFFFF },
+ { 0x00D6, CODEPAGE_ISUPPER, 0x00F6, 0xFFFF },
+ { 0x00D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00D8, CODEPAGE_ISUPPER, 0x00F8, 0xFFFF },
+ { 0x00D9, CODEPAGE_ISUPPER, 0x00F9, 0xFFFF },
+ { 0x00DA, CODEPAGE_ISUPPER, 0x00FA, 0xFFFF },
+ { 0x00DB, CODEPAGE_ISUPPER, 0x00FB, 0xFFFF },
+ { 0x00DC, CODEPAGE_ISUPPER, 0x00FC, 0xFFFF },
+ { 0x00DD, CODEPAGE_ISUPPER, 0x00FD, 0xFFFF },
+ { 0x00DE, CODEPAGE_ISUPPER, 0x00FE, 0xFFFF },
+ { 0x00DF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x00E0, CODEPAGE_ISLOWER, 0xFFFF, 0x00C0 },
+ { 0x00E1, CODEPAGE_ISLOWER, 0xFFFF, 0x00C1 },
+ { 0x00E2, CODEPAGE_ISLOWER, 0xFFFF, 0x00C2 },
+ { 0x00E3, CODEPAGE_ISLOWER, 0xFFFF, 0x00C3 },
+ { 0x00E4, CODEPAGE_ISLOWER, 0xFFFF, 0x00C4 },
+ { 0x00E5, CODEPAGE_ISLOWER, 0xFFFF, 0x00C5 },
+ { 0x00E6, CODEPAGE_ISLOWER, 0xFFFF, 0x00C6 },
+ { 0x00E7, CODEPAGE_ISLOWER, 0xFFFF, 0x00C7 },
+ { 0x00E8, CODEPAGE_ISLOWER, 0xFFFF, 0x00C8 },
+ { 0x00E9, CODEPAGE_ISLOWER, 0xFFFF, 0x00C9 },
+ { 0x00EA, CODEPAGE_ISLOWER, 0xFFFF, 0x00CA },
+ { 0x00EB, CODEPAGE_ISLOWER, 0xFFFF, 0x00CB },
+ { 0x00EC, CODEPAGE_ISLOWER, 0xFFFF, 0x00CC },
+ { 0x00ED, CODEPAGE_ISLOWER, 0xFFFF, 0x00CD },
+ { 0x00EE, CODEPAGE_ISLOWER, 0xFFFF, 0x00CE },
+ { 0x00EF, CODEPAGE_ISLOWER, 0xFFFF, 0x00CF },
+ { 0x00F0, CODEPAGE_ISLOWER, 0xFFFF, 0x00D0 },
+ { 0x00F1, CODEPAGE_ISLOWER, 0xFFFF, 0x00D1 },
+ { 0x00F2, CODEPAGE_ISLOWER, 0xFFFF, 0x00D2 },
+ { 0x00F3, CODEPAGE_ISLOWER, 0xFFFF, 0x00D3 },
+ { 0x00F4, CODEPAGE_ISLOWER, 0xFFFF, 0x00D4 },
+ { 0x00F5, CODEPAGE_ISLOWER, 0xFFFF, 0x00D5 },
+ { 0x00F6, CODEPAGE_ISLOWER, 0xFFFF, 0x00D6 },
+ { 0x00F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x00F8, CODEPAGE_ISLOWER, 0xFFFF, 0x00D8 },
+ { 0x00F9, CODEPAGE_ISLOWER, 0xFFFF, 0x00D9 },
+ { 0x00FA, CODEPAGE_ISLOWER, 0xFFFF, 0x00DA },
+ { 0x00FB, CODEPAGE_ISLOWER, 0xFFFF, 0x00DB },
+ { 0x00FC, CODEPAGE_ISLOWER, 0xFFFF, 0x00DC },
+ { 0x00FD, CODEPAGE_ISLOWER, 0xFFFF, 0x00DD },
+ { 0x00FE, CODEPAGE_ISLOWER, 0xFFFF, 0x00DE },
+ { 0x00FF, CODEPAGE_ISLOWER, 0xFFFF, 0x0178 },
+ { 0x0100, CODEPAGE_ISUPPER, 0x0101, 0xFFFF },
+ { 0x0101, CODEPAGE_ISLOWER, 0xFFFF, 0x0100 },
+ { 0x0102, CODEPAGE_ISUPPER, 0x0103, 0xFFFF },
+ { 0x0103, CODEPAGE_ISLOWER, 0xFFFF, 0x0102 },
+ { 0x0104, CODEPAGE_ISUPPER, 0x0105, 0xFFFF },
+ { 0x0105, CODEPAGE_ISLOWER, 0xFFFF, 0x0104 },
+ { 0x0106, CODEPAGE_ISUPPER, 0x0107, 0xFFFF },
+ { 0x0107, CODEPAGE_ISLOWER, 0xFFFF, 0x0106 },
+ { 0x0108, CODEPAGE_ISUPPER, 0x0109, 0xFFFF },
+ { 0x0109, CODEPAGE_ISLOWER, 0xFFFF, 0x0108 },
+ { 0x010A, CODEPAGE_ISUPPER, 0x010B, 0xFFFF },
+ { 0x010B, CODEPAGE_ISLOWER, 0xFFFF, 0x010A },
+ { 0x010C, CODEPAGE_ISUPPER, 0x010D, 0xFFFF },
+ { 0x010D, CODEPAGE_ISLOWER, 0xFFFF, 0x010C },
+ { 0x010E, CODEPAGE_ISUPPER, 0x010F, 0xFFFF },
+ { 0x010F, CODEPAGE_ISLOWER, 0xFFFF, 0x010E },
+ { 0x0110, CODEPAGE_ISUPPER, 0x0111, 0xFFFF },
+ { 0x0111, CODEPAGE_ISLOWER, 0xFFFF, 0x0110 },
+ { 0x0112, CODEPAGE_ISUPPER, 0x0113, 0xFFFF },
+ { 0x0113, CODEPAGE_ISLOWER, 0xFFFF, 0x0112 },
+ { 0x0114, CODEPAGE_ISUPPER, 0x0115, 0xFFFF },
+ { 0x0115, CODEPAGE_ISLOWER, 0xFFFF, 0x0114 },
+ { 0x0116, CODEPAGE_ISUPPER, 0x0117, 0xFFFF },
+ { 0x0117, CODEPAGE_ISLOWER, 0xFFFF, 0x0116 },
+ { 0x0118, CODEPAGE_ISUPPER, 0x0119, 0xFFFF },
+ { 0x0119, CODEPAGE_ISLOWER, 0xFFFF, 0x0118 },
+ { 0x011A, CODEPAGE_ISUPPER, 0x011B, 0xFFFF },
+ { 0x011B, CODEPAGE_ISLOWER, 0xFFFF, 0x011A },
+ { 0x011C, CODEPAGE_ISUPPER, 0x011D, 0xFFFF },
+ { 0x011D, CODEPAGE_ISLOWER, 0xFFFF, 0x011C },
+ { 0x011E, CODEPAGE_ISUPPER, 0x011F, 0xFFFF },
+ { 0x011F, CODEPAGE_ISLOWER, 0xFFFF, 0x011E },
+ { 0x0120, CODEPAGE_ISUPPER, 0x0121, 0xFFFF },
+ { 0x0121, CODEPAGE_ISLOWER, 0xFFFF, 0x0120 },
+ { 0x0122, CODEPAGE_ISUPPER, 0x0123, 0xFFFF },
+ { 0x0123, CODEPAGE_ISLOWER, 0xFFFF, 0x0122 },
+ { 0x0124, CODEPAGE_ISUPPER, 0x0125, 0xFFFF },
+ { 0x0125, CODEPAGE_ISLOWER, 0xFFFF, 0x0124 },
+ { 0x0126, CODEPAGE_ISUPPER, 0x0127, 0xFFFF },
+ { 0x0127, CODEPAGE_ISLOWER, 0xFFFF, 0x0126 },
+ { 0x0128, CODEPAGE_ISUPPER, 0x0129, 0xFFFF },
+ { 0x0129, CODEPAGE_ISLOWER, 0xFFFF, 0x0128 },
+ { 0x012A, CODEPAGE_ISUPPER, 0x012B, 0xFFFF },
+ { 0x012B, CODEPAGE_ISLOWER, 0xFFFF, 0x012A },
+ { 0x012C, CODEPAGE_ISUPPER, 0x012D, 0xFFFF },
+ { 0x012D, CODEPAGE_ISLOWER, 0xFFFF, 0x012C },
+ { 0x012E, CODEPAGE_ISUPPER, 0x012F, 0xFFFF },
+ { 0x012F, CODEPAGE_ISLOWER, 0xFFFF, 0x012E },
+ { 0x0130, CODEPAGE_ISUPPER, 0x0069, 0xFFFF },
+ { 0x0131, CODEPAGE_ISLOWER, 0xFFFF, 0x0049 },
+ { 0x0132, CODEPAGE_ISUPPER, 0x0133, 0xFFFF },
+ { 0x0133, CODEPAGE_ISLOWER, 0xFFFF, 0x0132 },
+ { 0x0134, CODEPAGE_ISUPPER, 0x0135, 0xFFFF },
+ { 0x0135, CODEPAGE_ISLOWER, 0xFFFF, 0x0134 },
+ { 0x0136, CODEPAGE_ISUPPER, 0x0137, 0xFFFF },
+ { 0x0137, CODEPAGE_ISLOWER, 0xFFFF, 0x0136 },
+ { 0x0138, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0139, CODEPAGE_ISUPPER, 0x013A, 0xFFFF },
+ { 0x013A, CODEPAGE_ISLOWER, 0xFFFF, 0x0139 },
+ { 0x013B, CODEPAGE_ISUPPER, 0x013C, 0xFFFF },
+ { 0x013C, CODEPAGE_ISLOWER, 0xFFFF, 0x013B },
+ { 0x013D, CODEPAGE_ISUPPER, 0x013E, 0xFFFF },
+ { 0x013E, CODEPAGE_ISLOWER, 0xFFFF, 0x013D },
+ { 0x013F, CODEPAGE_ISUPPER, 0x0140, 0xFFFF },
+ { 0x0140, CODEPAGE_ISLOWER, 0xFFFF, 0x013F },
+ { 0x0141, CODEPAGE_ISUPPER, 0x0142, 0xFFFF },
+ { 0x0142, CODEPAGE_ISLOWER, 0xFFFF, 0x0141 },
+ { 0x0143, CODEPAGE_ISUPPER, 0x0144, 0xFFFF },
+ { 0x0144, CODEPAGE_ISLOWER, 0xFFFF, 0x0143 },
+ { 0x0145, CODEPAGE_ISUPPER, 0x0146, 0xFFFF },
+ { 0x0146, CODEPAGE_ISLOWER, 0xFFFF, 0x0145 },
+ { 0x0147, CODEPAGE_ISUPPER, 0x0148, 0xFFFF },
+ { 0x0148, CODEPAGE_ISLOWER, 0xFFFF, 0x0147 },
+ { 0x0149, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x014A, CODEPAGE_ISUPPER, 0x014B, 0xFFFF },
+ { 0x014B, CODEPAGE_ISLOWER, 0xFFFF, 0x014A },
+ { 0x014C, CODEPAGE_ISUPPER, 0x014D, 0xFFFF },
+ { 0x014D, CODEPAGE_ISLOWER, 0xFFFF, 0x014C },
+ { 0x014E, CODEPAGE_ISUPPER, 0x014F, 0xFFFF },
+ { 0x014F, CODEPAGE_ISLOWER, 0xFFFF, 0x014E },
+ { 0x0150, CODEPAGE_ISUPPER, 0x0151, 0xFFFF },
+ { 0x0151, CODEPAGE_ISLOWER, 0xFFFF, 0x0150 },
+ { 0x0152, CODEPAGE_ISUPPER, 0x0153, 0xFFFF },
+ { 0x0153, CODEPAGE_ISLOWER, 0xFFFF, 0x0152 },
+ { 0x0154, CODEPAGE_ISUPPER, 0x0155, 0xFFFF },
+ { 0x0155, CODEPAGE_ISLOWER, 0xFFFF, 0x0154 },
+ { 0x0156, CODEPAGE_ISUPPER, 0x0157, 0xFFFF },
+ { 0x0157, CODEPAGE_ISLOWER, 0xFFFF, 0x0156 },
+ { 0x0158, CODEPAGE_ISUPPER, 0x0159, 0xFFFF },
+ { 0x0159, CODEPAGE_ISLOWER, 0xFFFF, 0x0158 },
+ { 0x015A, CODEPAGE_ISUPPER, 0x015B, 0xFFFF },
+ { 0x015B, CODEPAGE_ISLOWER, 0xFFFF, 0x015A },
+ { 0x015C, CODEPAGE_ISUPPER, 0x015D, 0xFFFF },
+ { 0x015D, CODEPAGE_ISLOWER, 0xFFFF, 0x015C },
+ { 0x015E, CODEPAGE_ISUPPER, 0x015F, 0xFFFF },
+ { 0x015F, CODEPAGE_ISLOWER, 0xFFFF, 0x015E },
+ { 0x0160, CODEPAGE_ISUPPER, 0x0161, 0xFFFF },
+ { 0x0161, CODEPAGE_ISLOWER, 0xFFFF, 0x0160 },
+ { 0x0162, CODEPAGE_ISUPPER, 0x0163, 0xFFFF },
+ { 0x0163, CODEPAGE_ISLOWER, 0xFFFF, 0x0162 },
+ { 0x0164, CODEPAGE_ISUPPER, 0x0165, 0xFFFF },
+ { 0x0165, CODEPAGE_ISLOWER, 0xFFFF, 0x0164 },
+ { 0x0166, CODEPAGE_ISUPPER, 0x0167, 0xFFFF },
+ { 0x0167, CODEPAGE_ISLOWER, 0xFFFF, 0x0166 },
+ { 0x0168, CODEPAGE_ISUPPER, 0x0169, 0xFFFF },
+ { 0x0169, CODEPAGE_ISLOWER, 0xFFFF, 0x0168 },
+ { 0x016A, CODEPAGE_ISUPPER, 0x016B, 0xFFFF },
+ { 0x016B, CODEPAGE_ISLOWER, 0xFFFF, 0x016A },
+ { 0x016C, CODEPAGE_ISUPPER, 0x016D, 0xFFFF },
+ { 0x016D, CODEPAGE_ISLOWER, 0xFFFF, 0x016C },
+ { 0x016E, CODEPAGE_ISUPPER, 0x016F, 0xFFFF },
+ { 0x016F, CODEPAGE_ISLOWER, 0xFFFF, 0x016E },
+ { 0x0170, CODEPAGE_ISUPPER, 0x0171, 0xFFFF },
+ { 0x0171, CODEPAGE_ISLOWER, 0xFFFF, 0x0170 },
+ { 0x0172, CODEPAGE_ISUPPER, 0x0173, 0xFFFF },
+ { 0x0173, CODEPAGE_ISLOWER, 0xFFFF, 0x0172 },
+ { 0x0174, CODEPAGE_ISUPPER, 0x0175, 0xFFFF },
+ { 0x0175, CODEPAGE_ISLOWER, 0xFFFF, 0x0174 },
+ { 0x0176, CODEPAGE_ISUPPER, 0x0177, 0xFFFF },
+ { 0x0177, CODEPAGE_ISLOWER, 0xFFFF, 0x0176 },
+ { 0x0178, CODEPAGE_ISUPPER, 0x00FF, 0xFFFF },
+ { 0x0179, CODEPAGE_ISUPPER, 0x017A, 0xFFFF },
+ { 0x017A, CODEPAGE_ISLOWER, 0xFFFF, 0x0179 },
+ { 0x017B, CODEPAGE_ISUPPER, 0x017C, 0xFFFF },
+ { 0x017C, CODEPAGE_ISLOWER, 0xFFFF, 0x017B },
+ { 0x017D, CODEPAGE_ISUPPER, 0x017E, 0xFFFF },
+ { 0x017E, CODEPAGE_ISLOWER, 0xFFFF, 0x017D },
+ { 0x017F, CODEPAGE_ISLOWER, 0xFFFF, 0x0053 },
+ { 0x0180, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0181, CODEPAGE_ISUPPER, 0x0253, 0xFFFF },
+ { 0x0182, CODEPAGE_ISUPPER, 0x0183, 0xFFFF },
+ { 0x0183, CODEPAGE_ISLOWER, 0xFFFF, 0x0182 },
+ { 0x0184, CODEPAGE_ISUPPER, 0x0185, 0xFFFF },
+ { 0x0185, CODEPAGE_ISLOWER, 0xFFFF, 0x0184 },
+ { 0x0186, CODEPAGE_ISUPPER, 0x0254, 0xFFFF },
+ { 0x0187, CODEPAGE_ISUPPER, 0x0188, 0xFFFF },
+ { 0x0188, CODEPAGE_ISLOWER, 0xFFFF, 0x0187 },
+ { 0x0189, CODEPAGE_ISUPPER, 0x0256, 0xFFFF },
+ { 0x018A, CODEPAGE_ISUPPER, 0x0257, 0xFFFF },
+ { 0x018B, CODEPAGE_ISUPPER, 0x018C, 0xFFFF },
+ { 0x018C, CODEPAGE_ISLOWER, 0xFFFF, 0x018B },
+ { 0x018D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x018E, CODEPAGE_ISUPPER, 0x0258, 0xFFFF },
+ { 0x018F, CODEPAGE_ISUPPER, 0x0259, 0xFFFF },
+ { 0x0190, CODEPAGE_ISUPPER, 0x025B, 0xFFFF },
+ { 0x0191, CODEPAGE_ISUPPER, 0x0192, 0xFFFF },
+ { 0x0192, CODEPAGE_ISLOWER, 0xFFFF, 0x0191 },
+ { 0x0193, CODEPAGE_ISUPPER, 0x0260, 0xFFFF },
+ { 0x0194, CODEPAGE_ISUPPER, 0x0263, 0xFFFF },
+ { 0x0195, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0196, CODEPAGE_ISUPPER, 0x0269, 0xFFFF },
+ { 0x0197, CODEPAGE_ISUPPER, 0x0268, 0xFFFF },
+ { 0x0198, CODEPAGE_ISUPPER, 0x0199, 0xFFFF },
+ { 0x0199, CODEPAGE_ISLOWER, 0xFFFF, 0x0198 },
+ { 0x019A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x019B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x019C, CODEPAGE_ISUPPER, 0x026F, 0xFFFF },
+ { 0x019D, CODEPAGE_ISUPPER, 0x0272, 0xFFFF },
+ { 0x019E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x019F, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x01A0, CODEPAGE_ISUPPER, 0x01A1, 0xFFFF },
+ { 0x01A1, CODEPAGE_ISLOWER, 0xFFFF, 0x01A0 },
+ { 0x01A2, CODEPAGE_ISUPPER, 0x01A3, 0xFFFF },
+ { 0x01A3, CODEPAGE_ISLOWER, 0xFFFF, 0x01A2 },
+ { 0x01A4, CODEPAGE_ISUPPER, 0x01A5, 0xFFFF },
+ { 0x01A5, CODEPAGE_ISLOWER, 0xFFFF, 0x01A4 },
+ { 0x01A6, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x01A7, CODEPAGE_ISUPPER, 0x01A8, 0xFFFF },
+ { 0x01A8, CODEPAGE_ISLOWER, 0xFFFF, 0x01A7 },
+ { 0x01A9, CODEPAGE_ISUPPER, 0x0283, 0xFFFF },
+ { 0x01AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01AB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01AC, CODEPAGE_ISUPPER, 0x01AD, 0xFFFF },
+ { 0x01AD, CODEPAGE_ISLOWER, 0xFFFF, 0x01AC },
+ { 0x01AE, CODEPAGE_ISUPPER, 0x0288, 0xFFFF },
+ { 0x01AF, CODEPAGE_ISUPPER, 0x01B0, 0xFFFF },
+ { 0x01B0, CODEPAGE_ISLOWER, 0xFFFF, 0x01AF },
+ { 0x01B1, CODEPAGE_ISUPPER, 0x028A, 0xFFFF },
+ { 0x01B2, CODEPAGE_ISUPPER, 0x028B, 0xFFFF },
+ { 0x01B3, CODEPAGE_ISUPPER, 0x01B4, 0xFFFF },
+ { 0x01B4, CODEPAGE_ISLOWER, 0xFFFF, 0x01B3 },
+ { 0x01B5, CODEPAGE_ISUPPER, 0x01B6, 0xFFFF },
+ { 0x01B6, CODEPAGE_ISLOWER, 0xFFFF, 0x01B5 },
+ { 0x01B7, CODEPAGE_ISUPPER, 0x0292, 0xFFFF },
+ { 0x01B8, CODEPAGE_ISUPPER, 0x01B9, 0xFFFF },
+ { 0x01B9, CODEPAGE_ISLOWER, 0xFFFF, 0x01B8 },
+ { 0x01BA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01BC, CODEPAGE_ISUPPER, 0x01BD, 0xFFFF },
+ { 0x01BD, CODEPAGE_ISLOWER, 0xFFFF, 0x01BC },
+ { 0x01BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x01C4, CODEPAGE_ISUPPER, 0x01C6, 0x01C5 },
+ { 0x01C5, CODEPAGE_ISNONE, 0x01C6, 0xFFFF },
+ { 0x01C6, CODEPAGE_ISLOWER, 0xFFFF, 0x01C5 },
+ { 0x01C7, CODEPAGE_ISUPPER, 0x01C9, 0x01C8 },
+ { 0x01C8, CODEPAGE_ISNONE, 0x01C9, 0xFFFF },
+ { 0x01C9, CODEPAGE_ISLOWER, 0xFFFF, 0x01C8 },
+ { 0x01CA, CODEPAGE_ISUPPER, 0x01CC, 0x01CB },
+ { 0x01CB, CODEPAGE_ISNONE, 0x01CC, 0xFFFF },
+ { 0x01CC, CODEPAGE_ISLOWER, 0xFFFF, 0x01CB },
+ { 0x01CD, CODEPAGE_ISUPPER, 0x01CE, 0xFFFF },
+ { 0x01CE, CODEPAGE_ISLOWER, 0xFFFF, 0x01CD },
+ { 0x01CF, CODEPAGE_ISUPPER, 0x01D0, 0xFFFF },
+ { 0x01D0, CODEPAGE_ISLOWER, 0xFFFF, 0x01CF },
+ { 0x01D1, CODEPAGE_ISUPPER, 0x01D2, 0xFFFF },
+ { 0x01D2, CODEPAGE_ISLOWER, 0xFFFF, 0x01D1 },
+ { 0x01D3, CODEPAGE_ISUPPER, 0x01D4, 0xFFFF },
+ { 0x01D4, CODEPAGE_ISLOWER, 0xFFFF, 0x01D3 },
+ { 0x01D5, CODEPAGE_ISUPPER, 0x01D6, 0xFFFF },
+ { 0x01D6, CODEPAGE_ISLOWER, 0xFFFF, 0x01D5 },
+ { 0x01D7, CODEPAGE_ISUPPER, 0x01D8, 0xFFFF },
+ { 0x01D8, CODEPAGE_ISLOWER, 0xFFFF, 0x01D7 },
+ { 0x01D9, CODEPAGE_ISUPPER, 0x01DA, 0xFFFF },
+ { 0x01DA, CODEPAGE_ISLOWER, 0xFFFF, 0x01D9 },
+ { 0x01DB, CODEPAGE_ISUPPER, 0x01DC, 0xFFFF },
+ { 0x01DC, CODEPAGE_ISLOWER, 0xFFFF, 0x01DB },
+ { 0x01DD, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01DE, CODEPAGE_ISUPPER, 0x01DF, 0xFFFF },
+ { 0x01DF, CODEPAGE_ISLOWER, 0xFFFF, 0x01DE },
+ { 0x01E0, CODEPAGE_ISUPPER, 0x01E1, 0xFFFF },
+ { 0x01E1, CODEPAGE_ISLOWER, 0xFFFF, 0x01E0 },
+ { 0x01E2, CODEPAGE_ISUPPER, 0x01E3, 0xFFFF },
+ { 0x01E3, CODEPAGE_ISLOWER, 0xFFFF, 0x01E2 },
+ { 0x01E4, CODEPAGE_ISUPPER, 0x01E5, 0xFFFF },
+ { 0x01E5, CODEPAGE_ISLOWER, 0xFFFF, 0x01E4 },
+ { 0x01E6, CODEPAGE_ISUPPER, 0x01E7, 0xFFFF },
+ { 0x01E7, CODEPAGE_ISLOWER, 0xFFFF, 0x01E6 },
+ { 0x01E8, CODEPAGE_ISUPPER, 0x01E9, 0xFFFF },
+ { 0x01E9, CODEPAGE_ISLOWER, 0xFFFF, 0x01E8 },
+ { 0x01EA, CODEPAGE_ISUPPER, 0x01EB, 0xFFFF },
+ { 0x01EB, CODEPAGE_ISLOWER, 0xFFFF, 0x01EA },
+ { 0x01EC, CODEPAGE_ISUPPER, 0x01ED, 0xFFFF },
+ { 0x01ED, CODEPAGE_ISLOWER, 0xFFFF, 0x01EC },
+ { 0x01EE, CODEPAGE_ISUPPER, 0x01EF, 0xFFFF },
+ { 0x01EF, CODEPAGE_ISLOWER, 0xFFFF, 0x01EE },
+ { 0x01F0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x01F1, CODEPAGE_ISUPPER, 0x01F3, 0x01F2 },
+ { 0x01F2, CODEPAGE_ISNONE, 0x01F3, 0xFFFF },
+ { 0x01F3, CODEPAGE_ISLOWER, 0xFFFF, 0x01F2 },
+ { 0x01F4, CODEPAGE_ISUPPER, 0x01F5, 0xFFFF },
+ { 0x01F5, CODEPAGE_ISLOWER, 0xFFFF, 0x01F4 },
+ { 0x01FA, CODEPAGE_ISUPPER, 0x01FB, 0xFFFF },
+ { 0x01FB, CODEPAGE_ISLOWER, 0xFFFF, 0x01FA },
+ { 0x01FC, CODEPAGE_ISUPPER, 0x01FD, 0xFFFF },
+ { 0x01FD, CODEPAGE_ISLOWER, 0xFFFF, 0x01FC },
+ { 0x01FE, CODEPAGE_ISUPPER, 0x01FF, 0xFFFF },
+ { 0x01FF, CODEPAGE_ISLOWER, 0xFFFF, 0x01FE },
+ { 0x0200, CODEPAGE_ISUPPER, 0x0201, 0xFFFF },
+ { 0x0201, CODEPAGE_ISLOWER, 0xFFFF, 0x0200 },
+ { 0x0202, CODEPAGE_ISUPPER, 0x0203, 0xFFFF },
+ { 0x0203, CODEPAGE_ISLOWER, 0xFFFF, 0x0202 },
+ { 0x0204, CODEPAGE_ISUPPER, 0x0205, 0xFFFF },
+ { 0x0205, CODEPAGE_ISLOWER, 0xFFFF, 0x0204 },
+ { 0x0206, CODEPAGE_ISUPPER, 0x0207, 0xFFFF },
+ { 0x0207, CODEPAGE_ISLOWER, 0xFFFF, 0x0206 },
+ { 0x0208, CODEPAGE_ISUPPER, 0x0209, 0xFFFF },
+ { 0x0209, CODEPAGE_ISLOWER, 0xFFFF, 0x0208 },
+ { 0x020A, CODEPAGE_ISUPPER, 0x020B, 0xFFFF },
+ { 0x020B, CODEPAGE_ISLOWER, 0xFFFF, 0x020A },
+ { 0x020C, CODEPAGE_ISUPPER, 0x020D, 0xFFFF },
+ { 0x020D, CODEPAGE_ISLOWER, 0xFFFF, 0x020C },
+ { 0x020E, CODEPAGE_ISUPPER, 0x020F, 0xFFFF },
+ { 0x020F, CODEPAGE_ISLOWER, 0xFFFF, 0x020E },
+ { 0x0210, CODEPAGE_ISUPPER, 0x0211, 0xFFFF },
+ { 0x0211, CODEPAGE_ISLOWER, 0xFFFF, 0x0210 },
+ { 0x0212, CODEPAGE_ISUPPER, 0x0213, 0xFFFF },
+ { 0x0213, CODEPAGE_ISLOWER, 0xFFFF, 0x0212 },
+ { 0x0214, CODEPAGE_ISUPPER, 0x0215, 0xFFFF },
+ { 0x0215, CODEPAGE_ISLOWER, 0xFFFF, 0x0214 },
+ { 0x0216, CODEPAGE_ISUPPER, 0x0217, 0xFFFF },
+ { 0x0217, CODEPAGE_ISLOWER, 0xFFFF, 0x0216 },
+ { 0x0250, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0251, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0252, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0253, CODEPAGE_ISLOWER, 0xFFFF, 0x0181 },
+ { 0x0254, CODEPAGE_ISLOWER, 0xFFFF, 0x0186 },
+ { 0x0255, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0256, CODEPAGE_ISLOWER, 0xFFFF, 0x0189 },
+ { 0x0257, CODEPAGE_ISLOWER, 0xFFFF, 0x018A },
+ { 0x0258, CODEPAGE_ISLOWER, 0xFFFF, 0x018E },
+ { 0x0259, CODEPAGE_ISLOWER, 0xFFFF, 0x018F },
+ { 0x025A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025B, CODEPAGE_ISLOWER, 0xFFFF, 0x0190 },
+ { 0x025C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x025F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0260, CODEPAGE_ISLOWER, 0xFFFF, 0x0193 },
+ { 0x0261, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0262, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0263, CODEPAGE_ISLOWER, 0xFFFF, 0x0194 },
+ { 0x0264, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0265, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0266, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0267, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0268, CODEPAGE_ISLOWER, 0xFFFF, 0x0197 },
+ { 0x0269, CODEPAGE_ISLOWER, 0xFFFF, 0x0196 },
+ { 0x026A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x026F, CODEPAGE_ISLOWER, 0xFFFF, 0x019C },
+ { 0x0270, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0271, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0272, CODEPAGE_ISLOWER, 0xFFFF, 0x019D },
+ { 0x0273, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0274, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0275, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0276, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0277, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0278, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0279, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x027F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0280, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0281, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0282, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0283, CODEPAGE_ISLOWER, 0xFFFF, 0x01A9 },
+ { 0x0284, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0285, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0286, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0287, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0288, CODEPAGE_ISLOWER, 0xFFFF, 0x01AE },
+ { 0x0289, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028A, CODEPAGE_ISLOWER, 0xFFFF, 0x01B1 },
+ { 0x028B, CODEPAGE_ISLOWER, 0xFFFF, 0x01B2 },
+ { 0x028C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x028F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0290, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0291, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0292, CODEPAGE_ISLOWER, 0xFFFF, 0x01B7 },
+ { 0x0293, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0294, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0295, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0296, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0297, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0298, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0299, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x029F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02A8, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x02B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x02E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0300, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0301, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0302, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0303, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0304, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0305, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0306, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0307, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0308, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0309, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x030F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0310, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0311, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0312, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0313, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0314, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0315, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0316, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0317, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0318, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0319, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x031F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0320, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0321, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0322, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0323, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0324, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0325, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0326, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0327, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0328, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0329, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x032F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0330, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0331, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0332, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0333, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0334, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0335, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0336, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0337, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0338, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0339, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x033F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0340, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0341, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0342, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0343, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0344, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0345, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0360, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0361, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0374, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0375, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x037A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x037E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0384, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0385, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0386, CODEPAGE_ISUPPER, 0x03AC, 0xFFFF },
+ { 0x0387, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0388, CODEPAGE_ISUPPER, 0x03AD, 0xFFFF },
+ { 0x0389, CODEPAGE_ISUPPER, 0x03AE, 0xFFFF },
+ { 0x038A, CODEPAGE_ISUPPER, 0x03AF, 0xFFFF },
+ { 0x038C, CODEPAGE_ISUPPER, 0x03CC, 0xFFFF },
+ { 0x038E, CODEPAGE_ISUPPER, 0x03CD, 0xFFFF },
+ { 0x038F, CODEPAGE_ISUPPER, 0x03CE, 0xFFFF },
+ { 0x0390, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0391, CODEPAGE_ISUPPER, 0x03B1, 0xFFFF },
+ { 0x0392, CODEPAGE_ISUPPER, 0x03B2, 0xFFFF },
+ { 0x0393, CODEPAGE_ISUPPER, 0x03B3, 0xFFFF },
+ { 0x0394, CODEPAGE_ISUPPER, 0x03B4, 0xFFFF },
+ { 0x0395, CODEPAGE_ISUPPER, 0x03B5, 0xFFFF },
+ { 0x0396, CODEPAGE_ISUPPER, 0x03B6, 0xFFFF },
+ { 0x0397, CODEPAGE_ISUPPER, 0x03B7, 0xFFFF },
+ { 0x0398, CODEPAGE_ISUPPER, 0x03B8, 0xFFFF },
+ { 0x0399, CODEPAGE_ISUPPER, 0x03B9, 0xFFFF },
+ { 0x039A, CODEPAGE_ISUPPER, 0x03BA, 0xFFFF },
+ { 0x039B, CODEPAGE_ISUPPER, 0x03BB, 0xFFFF },
+ { 0x039C, CODEPAGE_ISUPPER, 0x03BC, 0xFFFF },
+ { 0x039D, CODEPAGE_ISUPPER, 0x03BD, 0xFFFF },
+ { 0x039E, CODEPAGE_ISUPPER, 0x03BE, 0xFFFF },
+ { 0x039F, CODEPAGE_ISUPPER, 0x03BF, 0xFFFF },
+ { 0x03A0, CODEPAGE_ISUPPER, 0x03C0, 0xFFFF },
+ { 0x03A1, CODEPAGE_ISUPPER, 0x03C1, 0xFFFF },
+ { 0x03A3, CODEPAGE_ISUPPER, 0x03C3, 0xFFFF },
+ { 0x03A4, CODEPAGE_ISUPPER, 0x03C4, 0xFFFF },
+ { 0x03A5, CODEPAGE_ISUPPER, 0x03C5, 0xFFFF },
+ { 0x03A6, CODEPAGE_ISUPPER, 0x03C6, 0xFFFF },
+ { 0x03A7, CODEPAGE_ISUPPER, 0x03C7, 0xFFFF },
+ { 0x03A8, CODEPAGE_ISUPPER, 0x03C8, 0xFFFF },
+ { 0x03A9, CODEPAGE_ISUPPER, 0x03C9, 0xFFFF },
+ { 0x03AA, CODEPAGE_ISUPPER, 0x03CA, 0xFFFF },
+ { 0x03AB, CODEPAGE_ISUPPER, 0x03CB, 0xFFFF },
+ { 0x03AC, CODEPAGE_ISLOWER, 0xFFFF, 0x0386 },
+ { 0x03AD, CODEPAGE_ISLOWER, 0xFFFF, 0x0388 },
+ { 0x03AE, CODEPAGE_ISLOWER, 0xFFFF, 0x0389 },
+ { 0x03AF, CODEPAGE_ISLOWER, 0xFFFF, 0x038A },
+ { 0x03B0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03B1, CODEPAGE_ISLOWER, 0xFFFF, 0x0391 },
+ { 0x03B2, CODEPAGE_ISLOWER, 0xFFFF, 0x0392 },
+ { 0x03B3, CODEPAGE_ISLOWER, 0xFFFF, 0x0393 },
+ { 0x03B4, CODEPAGE_ISLOWER, 0xFFFF, 0x0394 },
+ { 0x03B5, CODEPAGE_ISLOWER, 0xFFFF, 0x0395 },
+ { 0x03B6, CODEPAGE_ISLOWER, 0xFFFF, 0x0396 },
+ { 0x03B7, CODEPAGE_ISLOWER, 0xFFFF, 0x0397 },
+ { 0x03B8, CODEPAGE_ISLOWER, 0xFFFF, 0x0398 },
+ { 0x03B9, CODEPAGE_ISLOWER, 0xFFFF, 0x0399 },
+ { 0x03BA, CODEPAGE_ISLOWER, 0xFFFF, 0x039A },
+ { 0x03BB, CODEPAGE_ISLOWER, 0xFFFF, 0x039B },
+ { 0x03BC, CODEPAGE_ISLOWER, 0xFFFF, 0x039C },
+ { 0x03BD, CODEPAGE_ISLOWER, 0xFFFF, 0x039D },
+ { 0x03BE, CODEPAGE_ISLOWER, 0xFFFF, 0x039E },
+ { 0x03BF, CODEPAGE_ISLOWER, 0xFFFF, 0x039F },
+ { 0x03C0, CODEPAGE_ISLOWER, 0xFFFF, 0x03A0 },
+ { 0x03C1, CODEPAGE_ISLOWER, 0xFFFF, 0x03A1 },
+ { 0x03C2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03C3, CODEPAGE_ISLOWER, 0xFFFF, 0x03A3 },
+ { 0x03C4, CODEPAGE_ISLOWER, 0xFFFF, 0x03A4 },
+ { 0x03C5, CODEPAGE_ISLOWER, 0xFFFF, 0x03A5 },
+ { 0x03C6, CODEPAGE_ISLOWER, 0xFFFF, 0x03A6 },
+ { 0x03C7, CODEPAGE_ISLOWER, 0xFFFF, 0x03A7 },
+ { 0x03C8, CODEPAGE_ISLOWER, 0xFFFF, 0x03A8 },
+ { 0x03C9, CODEPAGE_ISLOWER, 0xFFFF, 0x03A9 },
+ { 0x03CA, CODEPAGE_ISLOWER, 0xFFFF, 0x03AA },
+ { 0x03CB, CODEPAGE_ISLOWER, 0xFFFF, 0x03AB },
+ { 0x03CC, CODEPAGE_ISLOWER, 0xFFFF, 0x038C },
+ { 0x03CD, CODEPAGE_ISLOWER, 0xFFFF, 0x038E },
+ { 0x03CE, CODEPAGE_ISLOWER, 0xFFFF, 0x038F },
+ { 0x03D0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03D1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03D2, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03D3, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03D4, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03D5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03D6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03DA, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03DC, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03DE, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03E0, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x03E2, CODEPAGE_ISUPPER, 0x03E3, 0xFFFF },
+ { 0x03E3, CODEPAGE_ISLOWER, 0xFFFF, 0x03E2 },
+ { 0x03E4, CODEPAGE_ISUPPER, 0x03E5, 0xFFFF },
+ { 0x03E5, CODEPAGE_ISLOWER, 0xFFFF, 0x03E4 },
+ { 0x03E6, CODEPAGE_ISUPPER, 0x03E7, 0xFFFF },
+ { 0x03E7, CODEPAGE_ISLOWER, 0xFFFF, 0x03E6 },
+ { 0x03E8, CODEPAGE_ISUPPER, 0x03E9, 0xFFFF },
+ { 0x03E9, CODEPAGE_ISLOWER, 0xFFFF, 0x03E8 },
+ { 0x03EA, CODEPAGE_ISUPPER, 0x03EB, 0xFFFF },
+ { 0x03EB, CODEPAGE_ISLOWER, 0xFFFF, 0x03EA },
+ { 0x03EC, CODEPAGE_ISUPPER, 0x03ED, 0xFFFF },
+ { 0x03ED, CODEPAGE_ISLOWER, 0xFFFF, 0x03EC },
+ { 0x03EE, CODEPAGE_ISUPPER, 0x03EF, 0xFFFF },
+ { 0x03EF, CODEPAGE_ISLOWER, 0xFFFF, 0x03EE },
+ { 0x03F0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03F1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03F2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x03F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0401, CODEPAGE_ISUPPER, 0x0451, 0xFFFF },
+ { 0x0402, CODEPAGE_ISUPPER, 0x0452, 0xFFFF },
+ { 0x0403, CODEPAGE_ISUPPER, 0x0453, 0xFFFF },
+ { 0x0404, CODEPAGE_ISUPPER, 0x0454, 0xFFFF },
+ { 0x0405, CODEPAGE_ISUPPER, 0x0455, 0xFFFF },
+ { 0x0406, CODEPAGE_ISUPPER, 0x0456, 0xFFFF },
+ { 0x0407, CODEPAGE_ISUPPER, 0x0457, 0xFFFF },
+ { 0x0408, CODEPAGE_ISUPPER, 0x0458, 0xFFFF },
+ { 0x0409, CODEPAGE_ISUPPER, 0x0459, 0xFFFF },
+ { 0x040A, CODEPAGE_ISUPPER, 0x045A, 0xFFFF },
+ { 0x040B, CODEPAGE_ISUPPER, 0x045B, 0xFFFF },
+ { 0x040C, CODEPAGE_ISUPPER, 0x045C, 0xFFFF },
+ { 0x040E, CODEPAGE_ISUPPER, 0x045E, 0xFFFF },
+ { 0x040F, CODEPAGE_ISUPPER, 0x045F, 0xFFFF },
+ { 0x0410, CODEPAGE_ISUPPER, 0x0430, 0xFFFF },
+ { 0x0411, CODEPAGE_ISUPPER, 0x0431, 0xFFFF },
+ { 0x0412, CODEPAGE_ISUPPER, 0x0432, 0xFFFF },
+ { 0x0413, CODEPAGE_ISUPPER, 0x0433, 0xFFFF },
+ { 0x0414, CODEPAGE_ISUPPER, 0x0434, 0xFFFF },
+ { 0x0415, CODEPAGE_ISUPPER, 0x0435, 0xFFFF },
+ { 0x0416, CODEPAGE_ISUPPER, 0x0436, 0xFFFF },
+ { 0x0417, CODEPAGE_ISUPPER, 0x0437, 0xFFFF },
+ { 0x0418, CODEPAGE_ISUPPER, 0x0438, 0xFFFF },
+ { 0x0419, CODEPAGE_ISUPPER, 0x0439, 0xFFFF },
+ { 0x041A, CODEPAGE_ISUPPER, 0x043A, 0xFFFF },
+ { 0x041B, CODEPAGE_ISUPPER, 0x043B, 0xFFFF },
+ { 0x041C, CODEPAGE_ISUPPER, 0x043C, 0xFFFF },
+ { 0x041D, CODEPAGE_ISUPPER, 0x043D, 0xFFFF },
+ { 0x041E, CODEPAGE_ISUPPER, 0x043E, 0xFFFF },
+ { 0x041F, CODEPAGE_ISUPPER, 0x043F, 0xFFFF },
+ { 0x0420, CODEPAGE_ISUPPER, 0x0440, 0xFFFF },
+ { 0x0421, CODEPAGE_ISUPPER, 0x0441, 0xFFFF },
+ { 0x0422, CODEPAGE_ISUPPER, 0x0442, 0xFFFF },
+ { 0x0423, CODEPAGE_ISUPPER, 0x0443, 0xFFFF },
+ { 0x0424, CODEPAGE_ISUPPER, 0x0444, 0xFFFF },
+ { 0x0425, CODEPAGE_ISUPPER, 0x0445, 0xFFFF },
+ { 0x0426, CODEPAGE_ISUPPER, 0x0446, 0xFFFF },
+ { 0x0427, CODEPAGE_ISUPPER, 0x0447, 0xFFFF },
+ { 0x0428, CODEPAGE_ISUPPER, 0x0448, 0xFFFF },
+ { 0x0429, CODEPAGE_ISUPPER, 0x0449, 0xFFFF },
+ { 0x042A, CODEPAGE_ISUPPER, 0x044A, 0xFFFF },
+ { 0x042B, CODEPAGE_ISUPPER, 0x044B, 0xFFFF },
+ { 0x042C, CODEPAGE_ISUPPER, 0x044C, 0xFFFF },
+ { 0x042D, CODEPAGE_ISUPPER, 0x044D, 0xFFFF },
+ { 0x042E, CODEPAGE_ISUPPER, 0x044E, 0xFFFF },
+ { 0x042F, CODEPAGE_ISUPPER, 0x044F, 0xFFFF },
+ { 0x0430, CODEPAGE_ISLOWER, 0xFFFF, 0x0410 },
+ { 0x0431, CODEPAGE_ISLOWER, 0xFFFF, 0x0411 },
+ { 0x0432, CODEPAGE_ISLOWER, 0xFFFF, 0x0412 },
+ { 0x0433, CODEPAGE_ISLOWER, 0xFFFF, 0x0413 },
+ { 0x0434, CODEPAGE_ISLOWER, 0xFFFF, 0x0414 },
+ { 0x0435, CODEPAGE_ISLOWER, 0xFFFF, 0x0415 },
+ { 0x0436, CODEPAGE_ISLOWER, 0xFFFF, 0x0416 },
+ { 0x0437, CODEPAGE_ISLOWER, 0xFFFF, 0x0417 },
+ { 0x0438, CODEPAGE_ISLOWER, 0xFFFF, 0x0418 },
+ { 0x0439, CODEPAGE_ISLOWER, 0xFFFF, 0x0419 },
+ { 0x043A, CODEPAGE_ISLOWER, 0xFFFF, 0x041A },
+ { 0x043B, CODEPAGE_ISLOWER, 0xFFFF, 0x041B },
+ { 0x043C, CODEPAGE_ISLOWER, 0xFFFF, 0x041C },
+ { 0x043D, CODEPAGE_ISLOWER, 0xFFFF, 0x041D },
+ { 0x043E, CODEPAGE_ISLOWER, 0xFFFF, 0x041E },
+ { 0x043F, CODEPAGE_ISLOWER, 0xFFFF, 0x041F },
+ { 0x0440, CODEPAGE_ISLOWER, 0xFFFF, 0x0420 },
+ { 0x0441, CODEPAGE_ISLOWER, 0xFFFF, 0x0421 },
+ { 0x0442, CODEPAGE_ISLOWER, 0xFFFF, 0x0422 },
+ { 0x0443, CODEPAGE_ISLOWER, 0xFFFF, 0x0423 },
+ { 0x0444, CODEPAGE_ISLOWER, 0xFFFF, 0x0424 },
+ { 0x0445, CODEPAGE_ISLOWER, 0xFFFF, 0x0425 },
+ { 0x0446, CODEPAGE_ISLOWER, 0xFFFF, 0x0426 },
+ { 0x0447, CODEPAGE_ISLOWER, 0xFFFF, 0x0427 },
+ { 0x0448, CODEPAGE_ISLOWER, 0xFFFF, 0x0428 },
+ { 0x0449, CODEPAGE_ISLOWER, 0xFFFF, 0x0429 },
+ { 0x044A, CODEPAGE_ISLOWER, 0xFFFF, 0x042A },
+ { 0x044B, CODEPAGE_ISLOWER, 0xFFFF, 0x042B },
+ { 0x044C, CODEPAGE_ISLOWER, 0xFFFF, 0x042C },
+ { 0x044D, CODEPAGE_ISLOWER, 0xFFFF, 0x042D },
+ { 0x044E, CODEPAGE_ISLOWER, 0xFFFF, 0x042E },
+ { 0x044F, CODEPAGE_ISLOWER, 0xFFFF, 0x042F },
+ { 0x0451, CODEPAGE_ISLOWER, 0xFFFF, 0x0401 },
+ { 0x0452, CODEPAGE_ISLOWER, 0xFFFF, 0x0402 },
+ { 0x0453, CODEPAGE_ISLOWER, 0xFFFF, 0x0403 },
+ { 0x0454, CODEPAGE_ISLOWER, 0xFFFF, 0x0404 },
+ { 0x0455, CODEPAGE_ISLOWER, 0xFFFF, 0x0405 },
+ { 0x0456, CODEPAGE_ISLOWER, 0xFFFF, 0x0406 },
+ { 0x0457, CODEPAGE_ISLOWER, 0xFFFF, 0x0407 },
+ { 0x0458, CODEPAGE_ISLOWER, 0xFFFF, 0x0408 },
+ { 0x0459, CODEPAGE_ISLOWER, 0xFFFF, 0x0409 },
+ { 0x045A, CODEPAGE_ISLOWER, 0xFFFF, 0x040A },
+ { 0x045B, CODEPAGE_ISLOWER, 0xFFFF, 0x040B },
+ { 0x045C, CODEPAGE_ISLOWER, 0xFFFF, 0x040C },
+ { 0x045E, CODEPAGE_ISLOWER, 0xFFFF, 0x040E },
+ { 0x045F, CODEPAGE_ISLOWER, 0xFFFF, 0x040F },
+ { 0x0460, CODEPAGE_ISUPPER, 0x0461, 0xFFFF },
+ { 0x0461, CODEPAGE_ISLOWER, 0xFFFF, 0x0460 },
+ { 0x0462, CODEPAGE_ISUPPER, 0x0463, 0xFFFF },
+ { 0x0463, CODEPAGE_ISLOWER, 0xFFFF, 0x0462 },
+ { 0x0464, CODEPAGE_ISUPPER, 0x0465, 0xFFFF },
+ { 0x0465, CODEPAGE_ISLOWER, 0xFFFF, 0x0464 },
+ { 0x0466, CODEPAGE_ISUPPER, 0x0467, 0xFFFF },
+ { 0x0467, CODEPAGE_ISLOWER, 0xFFFF, 0x0466 },
+ { 0x0468, CODEPAGE_ISUPPER, 0x0469, 0xFFFF },
+ { 0x0469, CODEPAGE_ISLOWER, 0xFFFF, 0x0468 },
+ { 0x046A, CODEPAGE_ISUPPER, 0x046B, 0xFFFF },
+ { 0x046B, CODEPAGE_ISLOWER, 0xFFFF, 0x046A },
+ { 0x046C, CODEPAGE_ISUPPER, 0x046D, 0xFFFF },
+ { 0x046D, CODEPAGE_ISLOWER, 0xFFFF, 0x046C },
+ { 0x046E, CODEPAGE_ISUPPER, 0x046F, 0xFFFF },
+ { 0x046F, CODEPAGE_ISLOWER, 0xFFFF, 0x046E },
+ { 0x0470, CODEPAGE_ISUPPER, 0x0471, 0xFFFF },
+ { 0x0471, CODEPAGE_ISLOWER, 0xFFFF, 0x0470 },
+ { 0x0472, CODEPAGE_ISUPPER, 0x0473, 0xFFFF },
+ { 0x0473, CODEPAGE_ISLOWER, 0xFFFF, 0x0472 },
+ { 0x0474, CODEPAGE_ISUPPER, 0x0475, 0xFFFF },
+ { 0x0475, CODEPAGE_ISLOWER, 0xFFFF, 0x0474 },
+ { 0x0476, CODEPAGE_ISUPPER, 0x0477, 0xFFFF },
+ { 0x0477, CODEPAGE_ISLOWER, 0xFFFF, 0x0476 },
+ { 0x0478, CODEPAGE_ISUPPER, 0x0479, 0xFFFF },
+ { 0x0479, CODEPAGE_ISLOWER, 0xFFFF, 0x0478 },
+ { 0x047A, CODEPAGE_ISUPPER, 0x047B, 0xFFFF },
+ { 0x047B, CODEPAGE_ISLOWER, 0xFFFF, 0x047A },
+ { 0x047C, CODEPAGE_ISUPPER, 0x047D, 0xFFFF },
+ { 0x047D, CODEPAGE_ISLOWER, 0xFFFF, 0x047C },
+ { 0x047E, CODEPAGE_ISUPPER, 0x047F, 0xFFFF },
+ { 0x047F, CODEPAGE_ISLOWER, 0xFFFF, 0x047E },
+ { 0x0480, CODEPAGE_ISUPPER, 0x0481, 0xFFFF },
+ { 0x0481, CODEPAGE_ISLOWER, 0xFFFF, 0x0480 },
+ { 0x0482, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0483, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0484, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0485, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0486, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0490, CODEPAGE_ISUPPER, 0x0491, 0xFFFF },
+ { 0x0491, CODEPAGE_ISLOWER, 0xFFFF, 0x0490 },
+ { 0x0492, CODEPAGE_ISUPPER, 0x0493, 0xFFFF },
+ { 0x0493, CODEPAGE_ISLOWER, 0xFFFF, 0x0492 },
+ { 0x0494, CODEPAGE_ISUPPER, 0x0495, 0xFFFF },
+ { 0x0495, CODEPAGE_ISLOWER, 0xFFFF, 0x0494 },
+ { 0x0496, CODEPAGE_ISUPPER, 0x0497, 0xFFFF },
+ { 0x0497, CODEPAGE_ISLOWER, 0xFFFF, 0x0496 },
+ { 0x0498, CODEPAGE_ISUPPER, 0x0499, 0xFFFF },
+ { 0x0499, CODEPAGE_ISLOWER, 0xFFFF, 0x0498 },
+ { 0x049A, CODEPAGE_ISUPPER, 0x049B, 0xFFFF },
+ { 0x049B, CODEPAGE_ISLOWER, 0xFFFF, 0x049A },
+ { 0x049C, CODEPAGE_ISUPPER, 0x049D, 0xFFFF },
+ { 0x049D, CODEPAGE_ISLOWER, 0xFFFF, 0x049C },
+ { 0x049E, CODEPAGE_ISUPPER, 0x049F, 0xFFFF },
+ { 0x049F, CODEPAGE_ISLOWER, 0xFFFF, 0x049E },
+ { 0x04A0, CODEPAGE_ISUPPER, 0x04A1, 0xFFFF },
+ { 0x04A1, CODEPAGE_ISLOWER, 0xFFFF, 0x04A0 },
+ { 0x04A2, CODEPAGE_ISUPPER, 0x04A3, 0xFFFF },
+ { 0x04A3, CODEPAGE_ISLOWER, 0xFFFF, 0x04A2 },
+ { 0x04A4, CODEPAGE_ISUPPER, 0x04A5, 0xFFFF },
+ { 0x04A5, CODEPAGE_ISLOWER, 0xFFFF, 0x04A4 },
+ { 0x04A6, CODEPAGE_ISUPPER, 0x04A7, 0xFFFF },
+ { 0x04A7, CODEPAGE_ISLOWER, 0xFFFF, 0x04A6 },
+ { 0x04A8, CODEPAGE_ISUPPER, 0x04A9, 0xFFFF },
+ { 0x04A9, CODEPAGE_ISLOWER, 0xFFFF, 0x04A8 },
+ { 0x04AA, CODEPAGE_ISUPPER, 0x04AB, 0xFFFF },
+ { 0x04AB, CODEPAGE_ISLOWER, 0xFFFF, 0x04AA },
+ { 0x04AC, CODEPAGE_ISUPPER, 0x04AD, 0xFFFF },
+ { 0x04AD, CODEPAGE_ISLOWER, 0xFFFF, 0x04AC },
+ { 0x04AE, CODEPAGE_ISUPPER, 0x04AF, 0xFFFF },
+ { 0x04AF, CODEPAGE_ISLOWER, 0xFFFF, 0x04AE },
+ { 0x04B0, CODEPAGE_ISUPPER, 0x04B1, 0xFFFF },
+ { 0x04B1, CODEPAGE_ISLOWER, 0xFFFF, 0x04B0 },
+ { 0x04B2, CODEPAGE_ISUPPER, 0x04B3, 0xFFFF },
+ { 0x04B3, CODEPAGE_ISLOWER, 0xFFFF, 0x04B2 },
+ { 0x04B4, CODEPAGE_ISUPPER, 0x04B5, 0xFFFF },
+ { 0x04B5, CODEPAGE_ISLOWER, 0xFFFF, 0x04B4 },
+ { 0x04B6, CODEPAGE_ISUPPER, 0x04B7, 0xFFFF },
+ { 0x04B7, CODEPAGE_ISLOWER, 0xFFFF, 0x04B6 },
+ { 0x04B8, CODEPAGE_ISUPPER, 0x04B9, 0xFFFF },
+ { 0x04B9, CODEPAGE_ISLOWER, 0xFFFF, 0x04B8 },
+ { 0x04BA, CODEPAGE_ISUPPER, 0x04BB, 0xFFFF },
+ { 0x04BB, CODEPAGE_ISLOWER, 0xFFFF, 0x04BA },
+ { 0x04BC, CODEPAGE_ISUPPER, 0x04BD, 0xFFFF },
+ { 0x04BD, CODEPAGE_ISLOWER, 0xFFFF, 0x04BC },
+ { 0x04BE, CODEPAGE_ISUPPER, 0x04BF, 0xFFFF },
+ { 0x04BF, CODEPAGE_ISLOWER, 0xFFFF, 0x04BE },
+ { 0x04C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x04C1, CODEPAGE_ISUPPER, 0x04C2, 0xFFFF },
+ { 0x04C2, CODEPAGE_ISLOWER, 0xFFFF, 0x04C1 },
+ { 0x04C3, CODEPAGE_ISUPPER, 0x04C4, 0xFFFF },
+ { 0x04C4, CODEPAGE_ISLOWER, 0xFFFF, 0x04C3 },
+ { 0x04C7, CODEPAGE_ISUPPER, 0x04C8, 0xFFFF },
+ { 0x04C8, CODEPAGE_ISLOWER, 0xFFFF, 0x04C7 },
+ { 0x04CB, CODEPAGE_ISUPPER, 0x04CC, 0xFFFF },
+ { 0x04CC, CODEPAGE_ISLOWER, 0xFFFF, 0x04CB },
+ { 0x04D0, CODEPAGE_ISUPPER, 0x04D1, 0xFFFF },
+ { 0x04D1, CODEPAGE_ISLOWER, 0xFFFF, 0x04D0 },
+ { 0x04D2, CODEPAGE_ISUPPER, 0x04D3, 0xFFFF },
+ { 0x04D3, CODEPAGE_ISLOWER, 0xFFFF, 0x04D2 },
+ { 0x04D4, CODEPAGE_ISUPPER, 0x04D5, 0xFFFF },
+ { 0x04D5, CODEPAGE_ISLOWER, 0xFFFF, 0x04D4 },
+ { 0x04D6, CODEPAGE_ISUPPER, 0x04D7, 0xFFFF },
+ { 0x04D7, CODEPAGE_ISLOWER, 0xFFFF, 0x04D6 },
+ { 0x04D8, CODEPAGE_ISUPPER, 0x04D9, 0xFFFF },
+ { 0x04D9, CODEPAGE_ISLOWER, 0xFFFF, 0x04D8 },
+ { 0x04DA, CODEPAGE_ISUPPER, 0x04DB, 0xFFFF },
+ { 0x04DB, CODEPAGE_ISLOWER, 0xFFFF, 0x04DA },
+ { 0x04DC, CODEPAGE_ISUPPER, 0x04DD, 0xFFFF },
+ { 0x04DD, CODEPAGE_ISLOWER, 0xFFFF, 0x04DC },
+ { 0x04DE, CODEPAGE_ISUPPER, 0x04DF, 0xFFFF },
+ { 0x04DF, CODEPAGE_ISLOWER, 0xFFFF, 0x04DE },
+ { 0x04E0, CODEPAGE_ISUPPER, 0x04E1, 0xFFFF },
+ { 0x04E1, CODEPAGE_ISLOWER, 0xFFFF, 0x04E0 },
+ { 0x04E2, CODEPAGE_ISUPPER, 0x04E3, 0xFFFF },
+ { 0x04E3, CODEPAGE_ISLOWER, 0xFFFF, 0x04E2 },
+ { 0x04E4, CODEPAGE_ISUPPER, 0x04E5, 0xFFFF },
+ { 0x04E5, CODEPAGE_ISLOWER, 0xFFFF, 0x04E4 },
+ { 0x04E6, CODEPAGE_ISUPPER, 0x04E7, 0xFFFF },
+ { 0x04E7, CODEPAGE_ISLOWER, 0xFFFF, 0x04E6 },
+ { 0x04E8, CODEPAGE_ISUPPER, 0x04E9, 0xFFFF },
+ { 0x04E9, CODEPAGE_ISLOWER, 0xFFFF, 0x04E8 },
+ { 0x04EA, CODEPAGE_ISUPPER, 0x04EB, 0xFFFF },
+ { 0x04EB, CODEPAGE_ISLOWER, 0xFFFF, 0x04EA },
+ { 0x04EE, CODEPAGE_ISUPPER, 0x04EF, 0xFFFF },
+ { 0x04EF, CODEPAGE_ISLOWER, 0xFFFF, 0x04EE },
+ { 0x04F0, CODEPAGE_ISUPPER, 0x04F1, 0xFFFF },
+ { 0x04F1, CODEPAGE_ISLOWER, 0xFFFF, 0x04F0 },
+ { 0x04F2, CODEPAGE_ISUPPER, 0x04F3, 0xFFFF },
+ { 0x04F3, CODEPAGE_ISLOWER, 0xFFFF, 0x04F2 },
+ { 0x04F4, CODEPAGE_ISUPPER, 0x04F5, 0xFFFF },
+ { 0x04F5, CODEPAGE_ISLOWER, 0xFFFF, 0x04F4 },
+ { 0x04F8, CODEPAGE_ISUPPER, 0x04F9, 0xFFFF },
+ { 0x04F9, CODEPAGE_ISLOWER, 0xFFFF, 0x04F8 },
+ { 0x0531, CODEPAGE_ISUPPER, 0x0561, 0xFFFF },
+ { 0x0532, CODEPAGE_ISUPPER, 0x0562, 0xFFFF },
+ { 0x0533, CODEPAGE_ISUPPER, 0x0563, 0xFFFF },
+ { 0x0534, CODEPAGE_ISUPPER, 0x0564, 0xFFFF },
+ { 0x0535, CODEPAGE_ISUPPER, 0x0565, 0xFFFF },
+ { 0x0536, CODEPAGE_ISUPPER, 0x0566, 0xFFFF },
+ { 0x0537, CODEPAGE_ISUPPER, 0x0567, 0xFFFF },
+ { 0x0538, CODEPAGE_ISUPPER, 0x0568, 0xFFFF },
+ { 0x0539, CODEPAGE_ISUPPER, 0x0569, 0xFFFF },
+ { 0x053A, CODEPAGE_ISUPPER, 0x056A, 0xFFFF },
+ { 0x053B, CODEPAGE_ISUPPER, 0x056B, 0xFFFF },
+ { 0x053C, CODEPAGE_ISUPPER, 0x056C, 0xFFFF },
+ { 0x053D, CODEPAGE_ISUPPER, 0x056D, 0xFFFF },
+ { 0x053E, CODEPAGE_ISUPPER, 0x056E, 0xFFFF },
+ { 0x053F, CODEPAGE_ISUPPER, 0x056F, 0xFFFF },
+ { 0x0540, CODEPAGE_ISUPPER, 0x0570, 0xFFFF },
+ { 0x0541, CODEPAGE_ISUPPER, 0x0571, 0xFFFF },
+ { 0x0542, CODEPAGE_ISUPPER, 0x0572, 0xFFFF },
+ { 0x0543, CODEPAGE_ISUPPER, 0x0573, 0xFFFF },
+ { 0x0544, CODEPAGE_ISUPPER, 0x0574, 0xFFFF },
+ { 0x0545, CODEPAGE_ISUPPER, 0x0575, 0xFFFF },
+ { 0x0546, CODEPAGE_ISUPPER, 0x0576, 0xFFFF },
+ { 0x0547, CODEPAGE_ISUPPER, 0x0577, 0xFFFF },
+ { 0x0548, CODEPAGE_ISUPPER, 0x0578, 0xFFFF },
+ { 0x0549, CODEPAGE_ISUPPER, 0x0579, 0xFFFF },
+ { 0x054A, CODEPAGE_ISUPPER, 0x057A, 0xFFFF },
+ { 0x054B, CODEPAGE_ISUPPER, 0x057B, 0xFFFF },
+ { 0x054C, CODEPAGE_ISUPPER, 0x057C, 0xFFFF },
+ { 0x054D, CODEPAGE_ISUPPER, 0x057D, 0xFFFF },
+ { 0x054E, CODEPAGE_ISUPPER, 0x057E, 0xFFFF },
+ { 0x054F, CODEPAGE_ISUPPER, 0x057F, 0xFFFF },
+ { 0x0550, CODEPAGE_ISUPPER, 0x0580, 0xFFFF },
+ { 0x0551, CODEPAGE_ISUPPER, 0x0581, 0xFFFF },
+ { 0x0552, CODEPAGE_ISUPPER, 0x0582, 0xFFFF },
+ { 0x0553, CODEPAGE_ISUPPER, 0x0583, 0xFFFF },
+ { 0x0554, CODEPAGE_ISUPPER, 0x0584, 0xFFFF },
+ { 0x0555, CODEPAGE_ISUPPER, 0x0585, 0xFFFF },
+ { 0x0556, CODEPAGE_ISUPPER, 0x0586, 0xFFFF },
+ { 0x0559, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x055F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0561, CODEPAGE_ISLOWER, 0xFFFF, 0x0531 },
+ { 0x0562, CODEPAGE_ISLOWER, 0xFFFF, 0x0532 },
+ { 0x0563, CODEPAGE_ISLOWER, 0xFFFF, 0x0533 },
+ { 0x0564, CODEPAGE_ISLOWER, 0xFFFF, 0x0534 },
+ { 0x0565, CODEPAGE_ISLOWER, 0xFFFF, 0x0535 },
+ { 0x0566, CODEPAGE_ISLOWER, 0xFFFF, 0x0536 },
+ { 0x0567, CODEPAGE_ISLOWER, 0xFFFF, 0x0537 },
+ { 0x0568, CODEPAGE_ISLOWER, 0xFFFF, 0x0538 },
+ { 0x0569, CODEPAGE_ISLOWER, 0xFFFF, 0x0539 },
+ { 0x056A, CODEPAGE_ISLOWER, 0xFFFF, 0x053A },
+ { 0x056B, CODEPAGE_ISLOWER, 0xFFFF, 0x053B },
+ { 0x056C, CODEPAGE_ISLOWER, 0xFFFF, 0x053C },
+ { 0x056D, CODEPAGE_ISLOWER, 0xFFFF, 0x053D },
+ { 0x056E, CODEPAGE_ISLOWER, 0xFFFF, 0x053E },
+ { 0x056F, CODEPAGE_ISLOWER, 0xFFFF, 0x053F },
+ { 0x0570, CODEPAGE_ISLOWER, 0xFFFF, 0x0540 },
+ { 0x0571, CODEPAGE_ISLOWER, 0xFFFF, 0x0541 },
+ { 0x0572, CODEPAGE_ISLOWER, 0xFFFF, 0x0542 },
+ { 0x0573, CODEPAGE_ISLOWER, 0xFFFF, 0x0543 },
+ { 0x0574, CODEPAGE_ISLOWER, 0xFFFF, 0x0544 },
+ { 0x0575, CODEPAGE_ISLOWER, 0xFFFF, 0x0545 },
+ { 0x0576, CODEPAGE_ISLOWER, 0xFFFF, 0x0546 },
+ { 0x0577, CODEPAGE_ISLOWER, 0xFFFF, 0x0547 },
+ { 0x0578, CODEPAGE_ISLOWER, 0xFFFF, 0x0548 },
+ { 0x0579, CODEPAGE_ISLOWER, 0xFFFF, 0x0549 },
+ { 0x057A, CODEPAGE_ISLOWER, 0xFFFF, 0x054A },
+ { 0x057B, CODEPAGE_ISLOWER, 0xFFFF, 0x054B },
+ { 0x057C, CODEPAGE_ISLOWER, 0xFFFF, 0x054C },
+ { 0x057D, CODEPAGE_ISLOWER, 0xFFFF, 0x054D },
+ { 0x057E, CODEPAGE_ISLOWER, 0xFFFF, 0x054E },
+ { 0x057F, CODEPAGE_ISLOWER, 0xFFFF, 0x054F },
+ { 0x0580, CODEPAGE_ISLOWER, 0xFFFF, 0x0550 },
+ { 0x0581, CODEPAGE_ISLOWER, 0xFFFF, 0x0551 },
+ { 0x0582, CODEPAGE_ISLOWER, 0xFFFF, 0x0552 },
+ { 0x0583, CODEPAGE_ISLOWER, 0xFFFF, 0x0553 },
+ { 0x0584, CODEPAGE_ISLOWER, 0xFFFF, 0x0554 },
+ { 0x0585, CODEPAGE_ISLOWER, 0xFFFF, 0x0555 },
+ { 0x0586, CODEPAGE_ISLOWER, 0xFFFF, 0x0556 },
+ { 0x0587, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x0589, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0591, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0592, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0593, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0594, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0595, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0596, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0597, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0598, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0599, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x059F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x05F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x060C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x061B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x061F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0621, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0622, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0623, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0624, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0625, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0626, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0627, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0628, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0629, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x062F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0630, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0631, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0632, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0633, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0634, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0635, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0636, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0637, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0638, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0639, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x063A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0640, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0641, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0642, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0643, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0644, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0645, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0646, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0647, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0648, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0649, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x064F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0650, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0651, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0652, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0660, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0661, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0662, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0663, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0664, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0665, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0666, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0667, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0668, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0669, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x066D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0670, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0671, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0672, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0673, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0674, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0675, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0676, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0677, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0678, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0679, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x067F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0680, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0681, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0682, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0683, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0684, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0685, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0686, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0687, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0688, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0689, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x068F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0690, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0691, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0692, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0693, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0694, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0695, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0696, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0697, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0698, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0699, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x069F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x06F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0901, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0902, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0903, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0905, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0906, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0907, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0908, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0909, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x090F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0910, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0911, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0912, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0913, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0914, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0915, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0916, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0917, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0918, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0919, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x091F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0920, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0921, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0922, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0923, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0924, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0925, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0926, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0927, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0928, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0929, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x092F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0930, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0931, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0932, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0933, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0934, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0935, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0936, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0937, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0938, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0939, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x093F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0940, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0941, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0942, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0943, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0944, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0945, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0946, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0947, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0948, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0949, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x094D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0950, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0951, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0952, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0953, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0954, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0958, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0959, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x095F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0960, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0961, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0962, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0963, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0964, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0965, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0966, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0967, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0968, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0969, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x096F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0970, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0981, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0982, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0983, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0985, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0986, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0987, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0988, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0989, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x098F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0990, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0993, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0994, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0995, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0996, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0997, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0998, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0999, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x099F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x09FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0A9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ABF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ACB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ACC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ACD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AD0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0AEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0B9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0BF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0C9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0CEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0D6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E45, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0E9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ECD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0ED9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0EDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F45, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0F9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x0FB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x10A0, CODEPAGE_ISUPPER, 0x10D0, 0xFFFF },
+ { 0x10A1, CODEPAGE_ISUPPER, 0x10D1, 0xFFFF },
+ { 0x10A2, CODEPAGE_ISUPPER, 0x10D2, 0xFFFF },
+ { 0x10A3, CODEPAGE_ISUPPER, 0x10D3, 0xFFFF },
+ { 0x10A4, CODEPAGE_ISUPPER, 0x10D4, 0xFFFF },
+ { 0x10A5, CODEPAGE_ISUPPER, 0x10D5, 0xFFFF },
+ { 0x10A6, CODEPAGE_ISUPPER, 0x10D6, 0xFFFF },
+ { 0x10A7, CODEPAGE_ISUPPER, 0x10D7, 0xFFFF },
+ { 0x10A8, CODEPAGE_ISUPPER, 0x10D8, 0xFFFF },
+ { 0x10A9, CODEPAGE_ISUPPER, 0x10D9, 0xFFFF },
+ { 0x10AA, CODEPAGE_ISUPPER, 0x10DA, 0xFFFF },
+ { 0x10AB, CODEPAGE_ISUPPER, 0x10DB, 0xFFFF },
+ { 0x10AC, CODEPAGE_ISUPPER, 0x10DC, 0xFFFF },
+ { 0x10AD, CODEPAGE_ISUPPER, 0x10DD, 0xFFFF },
+ { 0x10AE, CODEPAGE_ISUPPER, 0x10DE, 0xFFFF },
+ { 0x10AF, CODEPAGE_ISUPPER, 0x10DF, 0xFFFF },
+ { 0x10B0, CODEPAGE_ISUPPER, 0x10E0, 0xFFFF },
+ { 0x10B1, CODEPAGE_ISUPPER, 0x10E1, 0xFFFF },
+ { 0x10B2, CODEPAGE_ISUPPER, 0x10E2, 0xFFFF },
+ { 0x10B3, CODEPAGE_ISUPPER, 0x10E3, 0xFFFF },
+ { 0x10B4, CODEPAGE_ISUPPER, 0x10E4, 0xFFFF },
+ { 0x10B5, CODEPAGE_ISUPPER, 0x10E5, 0xFFFF },
+ { 0x10B6, CODEPAGE_ISUPPER, 0x10E6, 0xFFFF },
+ { 0x10B7, CODEPAGE_ISUPPER, 0x10E7, 0xFFFF },
+ { 0x10B8, CODEPAGE_ISUPPER, 0x10E8, 0xFFFF },
+ { 0x10B9, CODEPAGE_ISUPPER, 0x10E9, 0xFFFF },
+ { 0x10BA, CODEPAGE_ISUPPER, 0x10EA, 0xFFFF },
+ { 0x10BB, CODEPAGE_ISUPPER, 0x10EB, 0xFFFF },
+ { 0x10BC, CODEPAGE_ISUPPER, 0x10EC, 0xFFFF },
+ { 0x10BD, CODEPAGE_ISUPPER, 0x10ED, 0xFFFF },
+ { 0x10BE, CODEPAGE_ISUPPER, 0x10EE, 0xFFFF },
+ { 0x10BF, CODEPAGE_ISUPPER, 0x10EF, 0xFFFF },
+ { 0x10C0, CODEPAGE_ISUPPER, 0x10F0, 0xFFFF },
+ { 0x10C1, CODEPAGE_ISUPPER, 0x10F1, 0xFFFF },
+ { 0x10C2, CODEPAGE_ISUPPER, 0x10F2, 0xFFFF },
+ { 0x10C3, CODEPAGE_ISUPPER, 0x10F3, 0xFFFF },
+ { 0x10C4, CODEPAGE_ISUPPER, 0x10F4, 0xFFFF },
+ { 0x10C5, CODEPAGE_ISUPPER, 0x10F5, 0xFFFF },
+ { 0x10D0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D8, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10D9, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DC, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DD, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DE, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10DF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E8, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10E9, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EC, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10ED, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EE, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10EF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10F6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x10FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1100, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1101, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1102, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1103, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1104, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1105, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1106, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1107, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1108, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1109, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x110F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1110, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1111, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1112, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1113, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1114, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1115, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1116, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1117, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1118, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1119, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x111F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1120, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1121, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1122, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1123, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1124, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1125, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1126, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1127, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1128, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1129, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x112F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1130, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1131, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1132, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1133, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1134, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1135, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1136, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1137, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1138, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1139, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x113F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1140, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1141, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1142, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1143, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1144, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1145, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1146, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1147, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1148, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1149, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x114F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1150, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1151, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1152, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1153, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1154, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1155, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1156, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1157, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1158, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1159, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x115F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1160, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1161, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1162, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1163, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1164, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1165, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1166, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1167, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1168, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1169, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x116F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1170, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1171, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1172, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1173, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1174, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1175, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1176, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1177, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1178, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1179, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x117F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1180, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1181, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1182, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1183, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1184, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1185, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1186, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1187, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1188, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1189, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x118F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1190, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1191, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1192, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1193, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1194, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1195, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1196, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1197, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1198, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1199, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x119F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x11F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1E00, CODEPAGE_ISUPPER, 0x1E01, 0xFFFF },
+ { 0x1E01, CODEPAGE_ISLOWER, 0xFFFF, 0x1E00 },
+ { 0x1E02, CODEPAGE_ISUPPER, 0x1E03, 0xFFFF },
+ { 0x1E03, CODEPAGE_ISLOWER, 0xFFFF, 0x1E02 },
+ { 0x1E04, CODEPAGE_ISUPPER, 0x1E05, 0xFFFF },
+ { 0x1E05, CODEPAGE_ISLOWER, 0xFFFF, 0x1E04 },
+ { 0x1E06, CODEPAGE_ISUPPER, 0x1E07, 0xFFFF },
+ { 0x1E07, CODEPAGE_ISLOWER, 0xFFFF, 0x1E06 },
+ { 0x1E08, CODEPAGE_ISUPPER, 0x1E09, 0xFFFF },
+ { 0x1E09, CODEPAGE_ISLOWER, 0xFFFF, 0x1E08 },
+ { 0x1E0A, CODEPAGE_ISUPPER, 0x1E0B, 0xFFFF },
+ { 0x1E0B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E0A },
+ { 0x1E0C, CODEPAGE_ISUPPER, 0x1E0D, 0xFFFF },
+ { 0x1E0D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E0C },
+ { 0x1E0E, CODEPAGE_ISUPPER, 0x1E0F, 0xFFFF },
+ { 0x1E0F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E0E },
+ { 0x1E10, CODEPAGE_ISUPPER, 0x1E11, 0xFFFF },
+ { 0x1E11, CODEPAGE_ISLOWER, 0xFFFF, 0x1E10 },
+ { 0x1E12, CODEPAGE_ISUPPER, 0x1E13, 0xFFFF },
+ { 0x1E13, CODEPAGE_ISLOWER, 0xFFFF, 0x1E12 },
+ { 0x1E14, CODEPAGE_ISUPPER, 0x1E15, 0xFFFF },
+ { 0x1E15, CODEPAGE_ISLOWER, 0xFFFF, 0x1E14 },
+ { 0x1E16, CODEPAGE_ISUPPER, 0x1E17, 0xFFFF },
+ { 0x1E17, CODEPAGE_ISLOWER, 0xFFFF, 0x1E16 },
+ { 0x1E18, CODEPAGE_ISUPPER, 0x1E19, 0xFFFF },
+ { 0x1E19, CODEPAGE_ISLOWER, 0xFFFF, 0x1E18 },
+ { 0x1E1A, CODEPAGE_ISUPPER, 0x1E1B, 0xFFFF },
+ { 0x1E1B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E1A },
+ { 0x1E1C, CODEPAGE_ISUPPER, 0x1E1D, 0xFFFF },
+ { 0x1E1D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E1C },
+ { 0x1E1E, CODEPAGE_ISUPPER, 0x1E1F, 0xFFFF },
+ { 0x1E1F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E1E },
+ { 0x1E20, CODEPAGE_ISUPPER, 0x1E21, 0xFFFF },
+ { 0x1E21, CODEPAGE_ISLOWER, 0xFFFF, 0x1E20 },
+ { 0x1E22, CODEPAGE_ISUPPER, 0x1E23, 0xFFFF },
+ { 0x1E23, CODEPAGE_ISLOWER, 0xFFFF, 0x1E22 },
+ { 0x1E24, CODEPAGE_ISUPPER, 0x1E25, 0xFFFF },
+ { 0x1E25, CODEPAGE_ISLOWER, 0xFFFF, 0x1E24 },
+ { 0x1E26, CODEPAGE_ISUPPER, 0x1E27, 0xFFFF },
+ { 0x1E27, CODEPAGE_ISLOWER, 0xFFFF, 0x1E26 },
+ { 0x1E28, CODEPAGE_ISUPPER, 0x1E29, 0xFFFF },
+ { 0x1E29, CODEPAGE_ISLOWER, 0xFFFF, 0x1E28 },
+ { 0x1E2A, CODEPAGE_ISUPPER, 0x1E2B, 0xFFFF },
+ { 0x1E2B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E2A },
+ { 0x1E2C, CODEPAGE_ISUPPER, 0x1E2D, 0xFFFF },
+ { 0x1E2D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E2C },
+ { 0x1E2E, CODEPAGE_ISUPPER, 0x1E2F, 0xFFFF },
+ { 0x1E2F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E2E },
+ { 0x1E30, CODEPAGE_ISUPPER, 0x1E31, 0xFFFF },
+ { 0x1E31, CODEPAGE_ISLOWER, 0xFFFF, 0x1E30 },
+ { 0x1E32, CODEPAGE_ISUPPER, 0x1E33, 0xFFFF },
+ { 0x1E33, CODEPAGE_ISLOWER, 0xFFFF, 0x1E32 },
+ { 0x1E34, CODEPAGE_ISUPPER, 0x1E35, 0xFFFF },
+ { 0x1E35, CODEPAGE_ISLOWER, 0xFFFF, 0x1E34 },
+ { 0x1E36, CODEPAGE_ISUPPER, 0x1E37, 0xFFFF },
+ { 0x1E37, CODEPAGE_ISLOWER, 0xFFFF, 0x1E36 },
+ { 0x1E38, CODEPAGE_ISUPPER, 0x1E39, 0xFFFF },
+ { 0x1E39, CODEPAGE_ISLOWER, 0xFFFF, 0x1E38 },
+ { 0x1E3A, CODEPAGE_ISUPPER, 0x1E3B, 0xFFFF },
+ { 0x1E3B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E3A },
+ { 0x1E3C, CODEPAGE_ISUPPER, 0x1E3D, 0xFFFF },
+ { 0x1E3D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E3C },
+ { 0x1E3E, CODEPAGE_ISUPPER, 0x1E3F, 0xFFFF },
+ { 0x1E3F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E3E },
+ { 0x1E40, CODEPAGE_ISUPPER, 0x1E41, 0xFFFF },
+ { 0x1E41, CODEPAGE_ISLOWER, 0xFFFF, 0x1E40 },
+ { 0x1E42, CODEPAGE_ISUPPER, 0x1E43, 0xFFFF },
+ { 0x1E43, CODEPAGE_ISLOWER, 0xFFFF, 0x1E42 },
+ { 0x1E44, CODEPAGE_ISUPPER, 0x1E45, 0xFFFF },
+ { 0x1E45, CODEPAGE_ISLOWER, 0xFFFF, 0x1E44 },
+ { 0x1E46, CODEPAGE_ISUPPER, 0x1E47, 0xFFFF },
+ { 0x1E47, CODEPAGE_ISLOWER, 0xFFFF, 0x1E46 },
+ { 0x1E48, CODEPAGE_ISUPPER, 0x1E49, 0xFFFF },
+ { 0x1E49, CODEPAGE_ISLOWER, 0xFFFF, 0x1E48 },
+ { 0x1E4A, CODEPAGE_ISUPPER, 0x1E4B, 0xFFFF },
+ { 0x1E4B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E4A },
+ { 0x1E4C, CODEPAGE_ISUPPER, 0x1E4D, 0xFFFF },
+ { 0x1E4D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E4C },
+ { 0x1E4E, CODEPAGE_ISUPPER, 0x1E4F, 0xFFFF },
+ { 0x1E4F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E4E },
+ { 0x1E50, CODEPAGE_ISUPPER, 0x1E51, 0xFFFF },
+ { 0x1E51, CODEPAGE_ISLOWER, 0xFFFF, 0x1E50 },
+ { 0x1E52, CODEPAGE_ISUPPER, 0x1E53, 0xFFFF },
+ { 0x1E53, CODEPAGE_ISLOWER, 0xFFFF, 0x1E52 },
+ { 0x1E54, CODEPAGE_ISUPPER, 0x1E55, 0xFFFF },
+ { 0x1E55, CODEPAGE_ISLOWER, 0xFFFF, 0x1E54 },
+ { 0x1E56, CODEPAGE_ISUPPER, 0x1E57, 0xFFFF },
+ { 0x1E57, CODEPAGE_ISLOWER, 0xFFFF, 0x1E56 },
+ { 0x1E58, CODEPAGE_ISUPPER, 0x1E59, 0xFFFF },
+ { 0x1E59, CODEPAGE_ISLOWER, 0xFFFF, 0x1E58 },
+ { 0x1E5A, CODEPAGE_ISUPPER, 0x1E5B, 0xFFFF },
+ { 0x1E5B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E5A },
+ { 0x1E5C, CODEPAGE_ISUPPER, 0x1E5D, 0xFFFF },
+ { 0x1E5D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E5C },
+ { 0x1E5E, CODEPAGE_ISUPPER, 0x1E5F, 0xFFFF },
+ { 0x1E5F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E5E },
+ { 0x1E60, CODEPAGE_ISUPPER, 0x1E61, 0xFFFF },
+ { 0x1E61, CODEPAGE_ISLOWER, 0xFFFF, 0x1E60 },
+ { 0x1E62, CODEPAGE_ISUPPER, 0x1E63, 0xFFFF },
+ { 0x1E63, CODEPAGE_ISLOWER, 0xFFFF, 0x1E62 },
+ { 0x1E64, CODEPAGE_ISUPPER, 0x1E65, 0xFFFF },
+ { 0x1E65, CODEPAGE_ISLOWER, 0xFFFF, 0x1E64 },
+ { 0x1E66, CODEPAGE_ISUPPER, 0x1E67, 0xFFFF },
+ { 0x1E67, CODEPAGE_ISLOWER, 0xFFFF, 0x1E66 },
+ { 0x1E68, CODEPAGE_ISUPPER, 0x1E69, 0xFFFF },
+ { 0x1E69, CODEPAGE_ISLOWER, 0xFFFF, 0x1E68 },
+ { 0x1E6A, CODEPAGE_ISUPPER, 0x1E6B, 0xFFFF },
+ { 0x1E6B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E6A },
+ { 0x1E6C, CODEPAGE_ISUPPER, 0x1E6D, 0xFFFF },
+ { 0x1E6D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E6C },
+ { 0x1E6E, CODEPAGE_ISUPPER, 0x1E6F, 0xFFFF },
+ { 0x1E6F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E6E },
+ { 0x1E70, CODEPAGE_ISUPPER, 0x1E71, 0xFFFF },
+ { 0x1E71, CODEPAGE_ISLOWER, 0xFFFF, 0x1E70 },
+ { 0x1E72, CODEPAGE_ISUPPER, 0x1E73, 0xFFFF },
+ { 0x1E73, CODEPAGE_ISLOWER, 0xFFFF, 0x1E72 },
+ { 0x1E74, CODEPAGE_ISUPPER, 0x1E75, 0xFFFF },
+ { 0x1E75, CODEPAGE_ISLOWER, 0xFFFF, 0x1E74 },
+ { 0x1E76, CODEPAGE_ISUPPER, 0x1E77, 0xFFFF },
+ { 0x1E77, CODEPAGE_ISLOWER, 0xFFFF, 0x1E76 },
+ { 0x1E78, CODEPAGE_ISUPPER, 0x1E79, 0xFFFF },
+ { 0x1E79, CODEPAGE_ISLOWER, 0xFFFF, 0x1E78 },
+ { 0x1E7A, CODEPAGE_ISUPPER, 0x1E7B, 0xFFFF },
+ { 0x1E7B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E7A },
+ { 0x1E7C, CODEPAGE_ISUPPER, 0x1E7D, 0xFFFF },
+ { 0x1E7D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E7C },
+ { 0x1E7E, CODEPAGE_ISUPPER, 0x1E7F, 0xFFFF },
+ { 0x1E7F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E7E },
+ { 0x1E80, CODEPAGE_ISUPPER, 0x1E81, 0xFFFF },
+ { 0x1E81, CODEPAGE_ISLOWER, 0xFFFF, 0x1E80 },
+ { 0x1E82, CODEPAGE_ISUPPER, 0x1E83, 0xFFFF },
+ { 0x1E83, CODEPAGE_ISLOWER, 0xFFFF, 0x1E82 },
+ { 0x1E84, CODEPAGE_ISUPPER, 0x1E85, 0xFFFF },
+ { 0x1E85, CODEPAGE_ISLOWER, 0xFFFF, 0x1E84 },
+ { 0x1E86, CODEPAGE_ISUPPER, 0x1E87, 0xFFFF },
+ { 0x1E87, CODEPAGE_ISLOWER, 0xFFFF, 0x1E86 },
+ { 0x1E88, CODEPAGE_ISUPPER, 0x1E89, 0xFFFF },
+ { 0x1E89, CODEPAGE_ISLOWER, 0xFFFF, 0x1E88 },
+ { 0x1E8A, CODEPAGE_ISUPPER, 0x1E8B, 0xFFFF },
+ { 0x1E8B, CODEPAGE_ISLOWER, 0xFFFF, 0x1E8A },
+ { 0x1E8C, CODEPAGE_ISUPPER, 0x1E8D, 0xFFFF },
+ { 0x1E8D, CODEPAGE_ISLOWER, 0xFFFF, 0x1E8C },
+ { 0x1E8E, CODEPAGE_ISUPPER, 0x1E8F, 0xFFFF },
+ { 0x1E8F, CODEPAGE_ISLOWER, 0xFFFF, 0x1E8E },
+ { 0x1E90, CODEPAGE_ISUPPER, 0x1E91, 0xFFFF },
+ { 0x1E91, CODEPAGE_ISLOWER, 0xFFFF, 0x1E90 },
+ { 0x1E92, CODEPAGE_ISUPPER, 0x1E93, 0xFFFF },
+ { 0x1E93, CODEPAGE_ISLOWER, 0xFFFF, 0x1E92 },
+ { 0x1E94, CODEPAGE_ISUPPER, 0x1E95, 0xFFFF },
+ { 0x1E95, CODEPAGE_ISLOWER, 0xFFFF, 0x1E94 },
+ { 0x1E96, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E97, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E98, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E99, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E9A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1E9B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1EA0, CODEPAGE_ISUPPER, 0x1EA1, 0xFFFF },
+ { 0x1EA1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA0 },
+ { 0x1EA2, CODEPAGE_ISUPPER, 0x1EA3, 0xFFFF },
+ { 0x1EA3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA2 },
+ { 0x1EA4, CODEPAGE_ISUPPER, 0x1EA5, 0xFFFF },
+ { 0x1EA5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA4 },
+ { 0x1EA6, CODEPAGE_ISUPPER, 0x1EA7, 0xFFFF },
+ { 0x1EA7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA6 },
+ { 0x1EA8, CODEPAGE_ISUPPER, 0x1EA9, 0xFFFF },
+ { 0x1EA9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EA8 },
+ { 0x1EAA, CODEPAGE_ISUPPER, 0x1EAB, 0xFFFF },
+ { 0x1EAB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EAA },
+ { 0x1EAC, CODEPAGE_ISUPPER, 0x1EAD, 0xFFFF },
+ { 0x1EAD, CODEPAGE_ISLOWER, 0xFFFF, 0x1EAC },
+ { 0x1EAE, CODEPAGE_ISUPPER, 0x1EAF, 0xFFFF },
+ { 0x1EAF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EAE },
+ { 0x1EB0, CODEPAGE_ISUPPER, 0x1EB1, 0xFFFF },
+ { 0x1EB1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB0 },
+ { 0x1EB2, CODEPAGE_ISUPPER, 0x1EB3, 0xFFFF },
+ { 0x1EB3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB2 },
+ { 0x1EB4, CODEPAGE_ISUPPER, 0x1EB5, 0xFFFF },
+ { 0x1EB5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB4 },
+ { 0x1EB6, CODEPAGE_ISUPPER, 0x1EB7, 0xFFFF },
+ { 0x1EB7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB6 },
+ { 0x1EB8, CODEPAGE_ISUPPER, 0x1EB9, 0xFFFF },
+ { 0x1EB9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EB8 },
+ { 0x1EBA, CODEPAGE_ISUPPER, 0x1EBB, 0xFFFF },
+ { 0x1EBB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EBA },
+ { 0x1EBC, CODEPAGE_ISUPPER, 0x1EBD, 0xFFFF },
+ { 0x1EBD, CODEPAGE_ISLOWER, 0xFFFF, 0x1EBC },
+ { 0x1EBE, CODEPAGE_ISUPPER, 0x1EBF, 0xFFFF },
+ { 0x1EBF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EBE },
+ { 0x1EC0, CODEPAGE_ISUPPER, 0x1EC1, 0xFFFF },
+ { 0x1EC1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC0 },
+ { 0x1EC2, CODEPAGE_ISUPPER, 0x1EC3, 0xFFFF },
+ { 0x1EC3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC2 },
+ { 0x1EC4, CODEPAGE_ISUPPER, 0x1EC5, 0xFFFF },
+ { 0x1EC5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC4 },
+ { 0x1EC6, CODEPAGE_ISUPPER, 0x1EC7, 0xFFFF },
+ { 0x1EC7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC6 },
+ { 0x1EC8, CODEPAGE_ISUPPER, 0x1EC9, 0xFFFF },
+ { 0x1EC9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EC8 },
+ { 0x1ECA, CODEPAGE_ISUPPER, 0x1ECB, 0xFFFF },
+ { 0x1ECB, CODEPAGE_ISLOWER, 0xFFFF, 0x1ECA },
+ { 0x1ECC, CODEPAGE_ISUPPER, 0x1ECD, 0xFFFF },
+ { 0x1ECD, CODEPAGE_ISLOWER, 0xFFFF, 0x1ECC },
+ { 0x1ECE, CODEPAGE_ISUPPER, 0x1ECF, 0xFFFF },
+ { 0x1ECF, CODEPAGE_ISLOWER, 0xFFFF, 0x1ECE },
+ { 0x1ED0, CODEPAGE_ISUPPER, 0x1ED1, 0xFFFF },
+ { 0x1ED1, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED0 },
+ { 0x1ED2, CODEPAGE_ISUPPER, 0x1ED3, 0xFFFF },
+ { 0x1ED3, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED2 },
+ { 0x1ED4, CODEPAGE_ISUPPER, 0x1ED5, 0xFFFF },
+ { 0x1ED5, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED4 },
+ { 0x1ED6, CODEPAGE_ISUPPER, 0x1ED7, 0xFFFF },
+ { 0x1ED7, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED6 },
+ { 0x1ED8, CODEPAGE_ISUPPER, 0x1ED9, 0xFFFF },
+ { 0x1ED9, CODEPAGE_ISLOWER, 0xFFFF, 0x1ED8 },
+ { 0x1EDA, CODEPAGE_ISUPPER, 0x1EDB, 0xFFFF },
+ { 0x1EDB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EDA },
+ { 0x1EDC, CODEPAGE_ISUPPER, 0x1EDD, 0xFFFF },
+ { 0x1EDD, CODEPAGE_ISLOWER, 0xFFFF, 0x1EDC },
+ { 0x1EDE, CODEPAGE_ISUPPER, 0x1EDF, 0xFFFF },
+ { 0x1EDF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EDE },
+ { 0x1EE0, CODEPAGE_ISUPPER, 0x1EE1, 0xFFFF },
+ { 0x1EE1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE0 },
+ { 0x1EE2, CODEPAGE_ISUPPER, 0x1EE3, 0xFFFF },
+ { 0x1EE3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE2 },
+ { 0x1EE4, CODEPAGE_ISUPPER, 0x1EE5, 0xFFFF },
+ { 0x1EE5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE4 },
+ { 0x1EE6, CODEPAGE_ISUPPER, 0x1EE7, 0xFFFF },
+ { 0x1EE7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE6 },
+ { 0x1EE8, CODEPAGE_ISUPPER, 0x1EE9, 0xFFFF },
+ { 0x1EE9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EE8 },
+ { 0x1EEA, CODEPAGE_ISUPPER, 0x1EEB, 0xFFFF },
+ { 0x1EEB, CODEPAGE_ISLOWER, 0xFFFF, 0x1EEA },
+ { 0x1EEC, CODEPAGE_ISUPPER, 0x1EED, 0xFFFF },
+ { 0x1EED, CODEPAGE_ISLOWER, 0xFFFF, 0x1EEC },
+ { 0x1EEE, CODEPAGE_ISUPPER, 0x1EEF, 0xFFFF },
+ { 0x1EEF, CODEPAGE_ISLOWER, 0xFFFF, 0x1EEE },
+ { 0x1EF0, CODEPAGE_ISUPPER, 0x1EF1, 0xFFFF },
+ { 0x1EF1, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF0 },
+ { 0x1EF2, CODEPAGE_ISUPPER, 0x1EF3, 0xFFFF },
+ { 0x1EF3, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF2 },
+ { 0x1EF4, CODEPAGE_ISUPPER, 0x1EF5, 0xFFFF },
+ { 0x1EF5, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF4 },
+ { 0x1EF6, CODEPAGE_ISUPPER, 0x1EF7, 0xFFFF },
+ { 0x1EF7, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF6 },
+ { 0x1EF8, CODEPAGE_ISUPPER, 0x1EF9, 0xFFFF },
+ { 0x1EF9, CODEPAGE_ISLOWER, 0xFFFF, 0x1EF8 },
+ { 0x1F00, CODEPAGE_ISLOWER, 0xFFFF, 0x1F08 },
+ { 0x1F01, CODEPAGE_ISLOWER, 0xFFFF, 0x1F09 },
+ { 0x1F02, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0A },
+ { 0x1F03, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0B },
+ { 0x1F04, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0C },
+ { 0x1F05, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0D },
+ { 0x1F06, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0E },
+ { 0x1F07, CODEPAGE_ISLOWER, 0xFFFF, 0x1F0F },
+ { 0x1F08, CODEPAGE_ISUPPER, 0x1F00, 0xFFFF },
+ { 0x1F09, CODEPAGE_ISUPPER, 0x1F01, 0xFFFF },
+ { 0x1F0A, CODEPAGE_ISUPPER, 0x1F02, 0xFFFF },
+ { 0x1F0B, CODEPAGE_ISUPPER, 0x1F03, 0xFFFF },
+ { 0x1F0C, CODEPAGE_ISUPPER, 0x1F04, 0xFFFF },
+ { 0x1F0D, CODEPAGE_ISUPPER, 0x1F05, 0xFFFF },
+ { 0x1F0E, CODEPAGE_ISUPPER, 0x1F06, 0xFFFF },
+ { 0x1F0F, CODEPAGE_ISUPPER, 0x1F07, 0xFFFF },
+ { 0x1F10, CODEPAGE_ISLOWER, 0xFFFF, 0x1F18 },
+ { 0x1F11, CODEPAGE_ISLOWER, 0xFFFF, 0x1F19 },
+ { 0x1F12, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1A },
+ { 0x1F13, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1B },
+ { 0x1F14, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1C },
+ { 0x1F15, CODEPAGE_ISLOWER, 0xFFFF, 0x1F1D },
+ { 0x1F18, CODEPAGE_ISUPPER, 0x1F10, 0xFFFF },
+ { 0x1F19, CODEPAGE_ISUPPER, 0x1F11, 0xFFFF },
+ { 0x1F1A, CODEPAGE_ISUPPER, 0x1F12, 0xFFFF },
+ { 0x1F1B, CODEPAGE_ISUPPER, 0x1F13, 0xFFFF },
+ { 0x1F1C, CODEPAGE_ISUPPER, 0x1F14, 0xFFFF },
+ { 0x1F1D, CODEPAGE_ISUPPER, 0x1F15, 0xFFFF },
+ { 0x1F20, CODEPAGE_ISLOWER, 0xFFFF, 0x1F28 },
+ { 0x1F21, CODEPAGE_ISLOWER, 0xFFFF, 0x1F29 },
+ { 0x1F22, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2A },
+ { 0x1F23, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2B },
+ { 0x1F24, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2C },
+ { 0x1F25, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2D },
+ { 0x1F26, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2E },
+ { 0x1F27, CODEPAGE_ISLOWER, 0xFFFF, 0x1F2F },
+ { 0x1F28, CODEPAGE_ISUPPER, 0x1F20, 0xFFFF },
+ { 0x1F29, CODEPAGE_ISUPPER, 0x1F21, 0xFFFF },
+ { 0x1F2A, CODEPAGE_ISUPPER, 0x1F22, 0xFFFF },
+ { 0x1F2B, CODEPAGE_ISUPPER, 0x1F23, 0xFFFF },
+ { 0x1F2C, CODEPAGE_ISUPPER, 0x1F24, 0xFFFF },
+ { 0x1F2D, CODEPAGE_ISUPPER, 0x1F25, 0xFFFF },
+ { 0x1F2E, CODEPAGE_ISUPPER, 0x1F26, 0xFFFF },
+ { 0x1F2F, CODEPAGE_ISUPPER, 0x1F27, 0xFFFF },
+ { 0x1F30, CODEPAGE_ISLOWER, 0xFFFF, 0x1F38 },
+ { 0x1F31, CODEPAGE_ISLOWER, 0xFFFF, 0x1F39 },
+ { 0x1F32, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3A },
+ { 0x1F33, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3B },
+ { 0x1F34, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3C },
+ { 0x1F35, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3D },
+ { 0x1F36, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3E },
+ { 0x1F37, CODEPAGE_ISLOWER, 0xFFFF, 0x1F3F },
+ { 0x1F38, CODEPAGE_ISUPPER, 0x1F30, 0xFFFF },
+ { 0x1F39, CODEPAGE_ISUPPER, 0x1F31, 0xFFFF },
+ { 0x1F3A, CODEPAGE_ISUPPER, 0x1F32, 0xFFFF },
+ { 0x1F3B, CODEPAGE_ISUPPER, 0x1F33, 0xFFFF },
+ { 0x1F3C, CODEPAGE_ISUPPER, 0x1F34, 0xFFFF },
+ { 0x1F3D, CODEPAGE_ISUPPER, 0x1F35, 0xFFFF },
+ { 0x1F3E, CODEPAGE_ISUPPER, 0x1F36, 0xFFFF },
+ { 0x1F3F, CODEPAGE_ISUPPER, 0x1F37, 0xFFFF },
+ { 0x1F40, CODEPAGE_ISLOWER, 0xFFFF, 0x1F48 },
+ { 0x1F41, CODEPAGE_ISLOWER, 0xFFFF, 0x1F49 },
+ { 0x1F42, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4A },
+ { 0x1F43, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4B },
+ { 0x1F44, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4C },
+ { 0x1F45, CODEPAGE_ISLOWER, 0xFFFF, 0x1F4D },
+ { 0x1F48, CODEPAGE_ISUPPER, 0x1F40, 0xFFFF },
+ { 0x1F49, CODEPAGE_ISUPPER, 0x1F41, 0xFFFF },
+ { 0x1F4A, CODEPAGE_ISUPPER, 0x1F42, 0xFFFF },
+ { 0x1F4B, CODEPAGE_ISUPPER, 0x1F43, 0xFFFF },
+ { 0x1F4C, CODEPAGE_ISUPPER, 0x1F44, 0xFFFF },
+ { 0x1F4D, CODEPAGE_ISUPPER, 0x1F45, 0xFFFF },
+ { 0x1F50, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F51, CODEPAGE_ISLOWER, 0xFFFF, 0x1F59 },
+ { 0x1F52, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F53, CODEPAGE_ISLOWER, 0xFFFF, 0x1F5B },
+ { 0x1F54, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F55, CODEPAGE_ISLOWER, 0xFFFF, 0x1F5D },
+ { 0x1F56, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1F57, CODEPAGE_ISLOWER, 0xFFFF, 0x1F5F },
+ { 0x1F59, CODEPAGE_ISUPPER, 0x1F51, 0xFFFF },
+ { 0x1F5B, CODEPAGE_ISUPPER, 0x1F53, 0xFFFF },
+ { 0x1F5D, CODEPAGE_ISUPPER, 0x1F55, 0xFFFF },
+ { 0x1F5F, CODEPAGE_ISUPPER, 0x1F57, 0xFFFF },
+ { 0x1F60, CODEPAGE_ISLOWER, 0xFFFF, 0x1F68 },
+ { 0x1F61, CODEPAGE_ISLOWER, 0xFFFF, 0x1F69 },
+ { 0x1F62, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6A },
+ { 0x1F63, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6B },
+ { 0x1F64, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6C },
+ { 0x1F65, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6D },
+ { 0x1F66, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6E },
+ { 0x1F67, CODEPAGE_ISLOWER, 0xFFFF, 0x1F6F },
+ { 0x1F68, CODEPAGE_ISUPPER, 0x1F60, 0xFFFF },
+ { 0x1F69, CODEPAGE_ISUPPER, 0x1F61, 0xFFFF },
+ { 0x1F6A, CODEPAGE_ISUPPER, 0x1F62, 0xFFFF },
+ { 0x1F6B, CODEPAGE_ISUPPER, 0x1F63, 0xFFFF },
+ { 0x1F6C, CODEPAGE_ISUPPER, 0x1F64, 0xFFFF },
+ { 0x1F6D, CODEPAGE_ISUPPER, 0x1F65, 0xFFFF },
+ { 0x1F6E, CODEPAGE_ISUPPER, 0x1F66, 0xFFFF },
+ { 0x1F6F, CODEPAGE_ISUPPER, 0x1F67, 0xFFFF },
+ { 0x1F70, CODEPAGE_ISLOWER, 0xFFFF, 0x1FBA },
+ { 0x1F71, CODEPAGE_ISLOWER, 0xFFFF, 0x1FBB },
+ { 0x1F72, CODEPAGE_ISLOWER, 0xFFFF, 0x1FC8 },
+ { 0x1F73, CODEPAGE_ISLOWER, 0xFFFF, 0x1FC9 },
+ { 0x1F74, CODEPAGE_ISLOWER, 0xFFFF, 0x1FCA },
+ { 0x1F75, CODEPAGE_ISLOWER, 0xFFFF, 0x1FCB },
+ { 0x1F76, CODEPAGE_ISLOWER, 0xFFFF, 0x1FDA },
+ { 0x1F77, CODEPAGE_ISLOWER, 0xFFFF, 0x1FDB },
+ { 0x1F78, CODEPAGE_ISLOWER, 0xFFFF, 0x1FF8 },
+ { 0x1F79, CODEPAGE_ISLOWER, 0xFFFF, 0x1FF9 },
+ { 0x1F7A, CODEPAGE_ISLOWER, 0xFFFF, 0x1FEA },
+ { 0x1F7B, CODEPAGE_ISLOWER, 0xFFFF, 0x1FEB },
+ { 0x1F7C, CODEPAGE_ISLOWER, 0xFFFF, 0x1FFA },
+ { 0x1F7D, CODEPAGE_ISLOWER, 0xFFFF, 0x1FFB },
+ { 0x1F80, CODEPAGE_ISLOWER, 0xFFFF, 0x1F88 },
+ { 0x1F81, CODEPAGE_ISLOWER, 0xFFFF, 0x1F89 },
+ { 0x1F82, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8A },
+ { 0x1F83, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8B },
+ { 0x1F84, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8C },
+ { 0x1F85, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8D },
+ { 0x1F86, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8E },
+ { 0x1F87, CODEPAGE_ISLOWER, 0xFFFF, 0x1F8F },
+ { 0x1F88, CODEPAGE_ISUPPER, 0x1F80, 0xFFFF },
+ { 0x1F89, CODEPAGE_ISUPPER, 0x1F81, 0xFFFF },
+ { 0x1F8A, CODEPAGE_ISUPPER, 0x1F82, 0xFFFF },
+ { 0x1F8B, CODEPAGE_ISUPPER, 0x1F83, 0xFFFF },
+ { 0x1F8C, CODEPAGE_ISUPPER, 0x1F84, 0xFFFF },
+ { 0x1F8D, CODEPAGE_ISUPPER, 0x1F85, 0xFFFF },
+ { 0x1F8E, CODEPAGE_ISUPPER, 0x1F86, 0xFFFF },
+ { 0x1F8F, CODEPAGE_ISUPPER, 0x1F87, 0xFFFF },
+ { 0x1F90, CODEPAGE_ISLOWER, 0xFFFF, 0x1F98 },
+ { 0x1F91, CODEPAGE_ISLOWER, 0xFFFF, 0x1F99 },
+ { 0x1F92, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9A },
+ { 0x1F93, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9B },
+ { 0x1F94, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9C },
+ { 0x1F95, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9D },
+ { 0x1F96, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9E },
+ { 0x1F97, CODEPAGE_ISLOWER, 0xFFFF, 0x1F9F },
+ { 0x1F98, CODEPAGE_ISUPPER, 0x1F90, 0xFFFF },
+ { 0x1F99, CODEPAGE_ISUPPER, 0x1F91, 0xFFFF },
+ { 0x1F9A, CODEPAGE_ISUPPER, 0x1F92, 0xFFFF },
+ { 0x1F9B, CODEPAGE_ISUPPER, 0x1F93, 0xFFFF },
+ { 0x1F9C, CODEPAGE_ISUPPER, 0x1F94, 0xFFFF },
+ { 0x1F9D, CODEPAGE_ISUPPER, 0x1F95, 0xFFFF },
+ { 0x1F9E, CODEPAGE_ISUPPER, 0x1F96, 0xFFFF },
+ { 0x1F9F, CODEPAGE_ISUPPER, 0x1F97, 0xFFFF },
+ { 0x1FA0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FA8 },
+ { 0x1FA1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FA9 },
+ { 0x1FA2, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAA },
+ { 0x1FA3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAB },
+ { 0x1FA4, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAC },
+ { 0x1FA5, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAD },
+ { 0x1FA6, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAE },
+ { 0x1FA7, CODEPAGE_ISLOWER, 0xFFFF, 0x1FAF },
+ { 0x1FA8, CODEPAGE_ISUPPER, 0x1FA0, 0xFFFF },
+ { 0x1FA9, CODEPAGE_ISUPPER, 0x1FA1, 0xFFFF },
+ { 0x1FAA, CODEPAGE_ISUPPER, 0x1FA2, 0xFFFF },
+ { 0x1FAB, CODEPAGE_ISUPPER, 0x1FA3, 0xFFFF },
+ { 0x1FAC, CODEPAGE_ISUPPER, 0x1FA4, 0xFFFF },
+ { 0x1FAD, CODEPAGE_ISUPPER, 0x1FA5, 0xFFFF },
+ { 0x1FAE, CODEPAGE_ISUPPER, 0x1FA6, 0xFFFF },
+ { 0x1FAF, CODEPAGE_ISUPPER, 0x1FA7, 0xFFFF },
+ { 0x1FB0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FB8 },
+ { 0x1FB1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FB9 },
+ { 0x1FB2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FBC },
+ { 0x1FB4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FB8, CODEPAGE_ISUPPER, 0x1FB0, 0xFFFF },
+ { 0x1FB9, CODEPAGE_ISUPPER, 0x1FB1, 0xFFFF },
+ { 0x1FBA, CODEPAGE_ISUPPER, 0x1F70, 0xFFFF },
+ { 0x1FBB, CODEPAGE_ISUPPER, 0x1F71, 0xFFFF },
+ { 0x1FBC, CODEPAGE_ISUPPER, 0x1FB3, 0xFFFF },
+ { 0x1FBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FBE, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x1FBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FC2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FCC },
+ { 0x1FC4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FC8, CODEPAGE_ISUPPER, 0x1F72, 0xFFFF },
+ { 0x1FC9, CODEPAGE_ISUPPER, 0x1F73, 0xFFFF },
+ { 0x1FCA, CODEPAGE_ISUPPER, 0x1F74, 0xFFFF },
+ { 0x1FCB, CODEPAGE_ISUPPER, 0x1F75, 0xFFFF },
+ { 0x1FCC, CODEPAGE_ISUPPER, 0x1FC3, 0xFFFF },
+ { 0x1FCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FCE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FCF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FD0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FD8 },
+ { 0x1FD1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FD9 },
+ { 0x1FD2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FD8, CODEPAGE_ISUPPER, 0x1FD0, 0xFFFF },
+ { 0x1FD9, CODEPAGE_ISUPPER, 0x1FD1, 0xFFFF },
+ { 0x1FDA, CODEPAGE_ISUPPER, 0x1F76, 0xFFFF },
+ { 0x1FDB, CODEPAGE_ISUPPER, 0x1F77, 0xFFFF },
+ { 0x1FDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FE0, CODEPAGE_ISLOWER, 0xFFFF, 0x1FE8 },
+ { 0x1FE1, CODEPAGE_ISLOWER, 0xFFFF, 0x1FE9 },
+ { 0x1FE2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE5, CODEPAGE_ISLOWER, 0xFFFF, 0x1FEC },
+ { 0x1FE6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FE8, CODEPAGE_ISUPPER, 0x1FE0, 0xFFFF },
+ { 0x1FE9, CODEPAGE_ISUPPER, 0x1FE1, 0xFFFF },
+ { 0x1FEA, CODEPAGE_ISUPPER, 0x1F7A, 0xFFFF },
+ { 0x1FEB, CODEPAGE_ISUPPER, 0x1F7B, 0xFFFF },
+ { 0x1FEC, CODEPAGE_ISUPPER, 0x1FE5, 0xFFFF },
+ { 0x1FED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FF2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF3, CODEPAGE_ISLOWER, 0xFFFF, 0x1FFC },
+ { 0x1FF4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF7, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x1FF8, CODEPAGE_ISUPPER, 0x1F78, 0xFFFF },
+ { 0x1FF9, CODEPAGE_ISUPPER, 0x1F79, 0xFFFF },
+ { 0x1FFA, CODEPAGE_ISUPPER, 0x1F7C, 0xFFFF },
+ { 0x1FFB, CODEPAGE_ISUPPER, 0x1F7D, 0xFFFF },
+ { 0x1FFC, CODEPAGE_ISUPPER, 0x1FF3, 0xFFFF },
+ { 0x1FFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x1FFE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2001, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2002, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2003, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2004, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2005, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2006, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2007, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2008, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2009, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x200F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2010, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2011, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2012, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2013, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2014, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2015, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2016, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2017, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2018, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2019, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x201F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2020, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2021, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2022, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2023, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2024, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2025, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2026, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2027, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2028, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2029, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x202E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2030, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2031, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2032, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2033, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2034, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2035, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2036, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2037, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2038, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2039, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x203F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2040, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2041, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2042, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2043, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2044, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2045, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2046, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x206F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2070, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2074, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2075, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2076, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2077, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2078, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2079, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x207F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2080, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2081, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2082, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2083, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2084, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2085, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2086, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2087, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2088, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2089, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x208E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x20E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2100, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2101, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2102, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2103, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2104, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2105, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2106, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2107, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2108, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2109, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x210A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x210B, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x210C, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x210D, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x210E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x210F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2110, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2111, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2112, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2113, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2114, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2115, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2116, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2117, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2118, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2119, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211A, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211B, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211C, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211D, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x211E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x211F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2120, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2121, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2122, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2123, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2124, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2125, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2126, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2127, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2128, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2129, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x212A, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212B, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212C, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212D, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x212E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x212F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2130, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2131, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2132, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2133, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x2134, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x2135, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2136, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2137, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2138, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2153, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2154, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2155, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2156, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2157, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2158, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2159, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x215F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2160, CODEPAGE_ISNONE, 0x2170, 0xFFFF },
+ { 0x2161, CODEPAGE_ISNONE, 0x2171, 0xFFFF },
+ { 0x2162, CODEPAGE_ISNONE, 0x2172, 0xFFFF },
+ { 0x2163, CODEPAGE_ISNONE, 0x2173, 0xFFFF },
+ { 0x2164, CODEPAGE_ISNONE, 0x2174, 0xFFFF },
+ { 0x2165, CODEPAGE_ISNONE, 0x2175, 0xFFFF },
+ { 0x2166, CODEPAGE_ISNONE, 0x2176, 0xFFFF },
+ { 0x2167, CODEPAGE_ISNONE, 0x2177, 0xFFFF },
+ { 0x2168, CODEPAGE_ISNONE, 0x2178, 0xFFFF },
+ { 0x2169, CODEPAGE_ISNONE, 0x2179, 0xFFFF },
+ { 0x216A, CODEPAGE_ISNONE, 0x217A, 0xFFFF },
+ { 0x216B, CODEPAGE_ISNONE, 0x217B, 0xFFFF },
+ { 0x216C, CODEPAGE_ISNONE, 0x217C, 0xFFFF },
+ { 0x216D, CODEPAGE_ISNONE, 0x217D, 0xFFFF },
+ { 0x216E, CODEPAGE_ISNONE, 0x217E, 0xFFFF },
+ { 0x216F, CODEPAGE_ISNONE, 0x217F, 0xFFFF },
+ { 0x2170, CODEPAGE_ISNONE, 0xFFFF, 0x2160 },
+ { 0x2171, CODEPAGE_ISNONE, 0xFFFF, 0x2161 },
+ { 0x2172, CODEPAGE_ISNONE, 0xFFFF, 0x2162 },
+ { 0x2173, CODEPAGE_ISNONE, 0xFFFF, 0x2163 },
+ { 0x2174, CODEPAGE_ISNONE, 0xFFFF, 0x2164 },
+ { 0x2175, CODEPAGE_ISNONE, 0xFFFF, 0x2165 },
+ { 0x2176, CODEPAGE_ISNONE, 0xFFFF, 0x2166 },
+ { 0x2177, CODEPAGE_ISNONE, 0xFFFF, 0x2167 },
+ { 0x2178, CODEPAGE_ISNONE, 0xFFFF, 0x2168 },
+ { 0x2179, CODEPAGE_ISNONE, 0xFFFF, 0x2169 },
+ { 0x217A, CODEPAGE_ISNONE, 0xFFFF, 0x216A },
+ { 0x217B, CODEPAGE_ISNONE, 0xFFFF, 0x216B },
+ { 0x217C, CODEPAGE_ISNONE, 0xFFFF, 0x216C },
+ { 0x217D, CODEPAGE_ISNONE, 0xFFFF, 0x216D },
+ { 0x217E, CODEPAGE_ISNONE, 0xFFFF, 0x216E },
+ { 0x217F, CODEPAGE_ISNONE, 0xFFFF, 0x216F },
+ { 0x2180, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2181, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2182, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2190, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2191, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2192, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2193, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2194, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2195, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2196, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2197, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2198, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2199, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x219F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x21EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2200, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2201, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2202, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2203, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2204, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2205, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2206, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2207, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2208, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2209, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x220F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2210, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2211, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2212, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2213, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2214, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2215, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2216, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2217, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2218, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2219, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x221F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2220, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2221, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2222, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2223, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2224, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2225, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2226, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2227, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2228, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2229, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x222F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2230, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2231, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2232, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2233, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2234, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2235, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2236, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2237, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2238, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2239, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x223F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2240, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2241, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2242, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2243, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2244, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2245, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2246, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2247, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2248, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2249, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x224F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2250, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2251, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2252, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2253, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2254, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2255, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2256, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2257, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2258, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2259, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x225F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2260, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2261, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2262, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2263, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2264, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2265, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2266, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2267, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2268, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2269, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x226F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2270, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2271, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2272, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2273, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2274, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2275, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2276, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2277, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2278, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2279, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x227F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2280, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2281, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2282, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2283, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2284, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2285, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2286, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2287, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2288, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2289, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x228F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2290, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2291, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2292, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2293, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2294, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2295, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2296, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2297, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2298, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2299, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x229F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x22F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2300, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2302, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2303, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2304, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2305, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2306, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2307, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2308, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2309, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x230F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2310, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2311, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2312, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2313, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2314, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2315, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2316, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2317, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2318, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2319, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x231F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2320, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2321, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2322, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2323, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2324, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2325, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2326, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2327, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2328, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2329, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x232F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2330, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2331, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2332, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2333, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2334, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2335, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2336, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2337, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2338, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2339, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x233F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2340, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2341, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2342, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2343, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2344, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2345, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2346, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2347, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2348, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2349, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x234F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2350, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2351, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2352, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2353, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2354, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2355, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2356, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2357, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2358, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2359, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x235F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2360, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2361, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2362, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2363, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2364, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2365, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2366, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2367, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2368, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2369, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x236F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2370, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2371, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2372, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2373, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2374, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2375, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2376, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2377, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2378, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2379, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x237A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2400, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2401, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2402, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2403, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2404, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2405, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2406, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2407, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2408, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2409, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x240F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2410, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2411, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2412, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2413, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2414, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2415, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2416, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2417, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2418, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2419, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x241F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2420, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2421, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2422, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2423, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2424, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2440, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2441, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2442, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2443, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2444, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2445, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2446, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2447, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2448, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2449, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x244A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2460, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2461, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2462, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2463, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2464, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2465, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2466, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2467, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2468, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2469, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x246F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2470, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2471, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2472, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2473, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2474, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2475, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2476, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2477, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2478, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2479, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x247F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2480, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2481, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2482, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2483, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2484, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2485, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2486, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2487, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2488, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2489, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x248F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2490, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2491, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2492, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2493, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2494, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2495, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2496, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2497, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2498, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2499, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x249F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x24B6, CODEPAGE_ISUPPER, 0x24D0, 0xFFFF },
+ { 0x24B7, CODEPAGE_ISUPPER, 0x24D1, 0xFFFF },
+ { 0x24B8, CODEPAGE_ISUPPER, 0x24D2, 0xFFFF },
+ { 0x24B9, CODEPAGE_ISUPPER, 0x24D3, 0xFFFF },
+ { 0x24BA, CODEPAGE_ISUPPER, 0x24D4, 0xFFFF },
+ { 0x24BB, CODEPAGE_ISUPPER, 0x24D5, 0xFFFF },
+ { 0x24BC, CODEPAGE_ISUPPER, 0x24D6, 0xFFFF },
+ { 0x24BD, CODEPAGE_ISUPPER, 0x24D7, 0xFFFF },
+ { 0x24BE, CODEPAGE_ISUPPER, 0x24D8, 0xFFFF },
+ { 0x24BF, CODEPAGE_ISUPPER, 0x24D9, 0xFFFF },
+ { 0x24C0, CODEPAGE_ISUPPER, 0x24DA, 0xFFFF },
+ { 0x24C1, CODEPAGE_ISUPPER, 0x24DB, 0xFFFF },
+ { 0x24C2, CODEPAGE_ISUPPER, 0x24DC, 0xFFFF },
+ { 0x24C3, CODEPAGE_ISUPPER, 0x24DD, 0xFFFF },
+ { 0x24C4, CODEPAGE_ISUPPER, 0x24DE, 0xFFFF },
+ { 0x24C5, CODEPAGE_ISUPPER, 0x24DF, 0xFFFF },
+ { 0x24C6, CODEPAGE_ISUPPER, 0x24E0, 0xFFFF },
+ { 0x24C7, CODEPAGE_ISUPPER, 0x24E1, 0xFFFF },
+ { 0x24C8, CODEPAGE_ISUPPER, 0x24E2, 0xFFFF },
+ { 0x24C9, CODEPAGE_ISUPPER, 0x24E3, 0xFFFF },
+ { 0x24CA, CODEPAGE_ISUPPER, 0x24E4, 0xFFFF },
+ { 0x24CB, CODEPAGE_ISUPPER, 0x24E5, 0xFFFF },
+ { 0x24CC, CODEPAGE_ISUPPER, 0x24E6, 0xFFFF },
+ { 0x24CD, CODEPAGE_ISUPPER, 0x24E7, 0xFFFF },
+ { 0x24CE, CODEPAGE_ISUPPER, 0x24E8, 0xFFFF },
+ { 0x24CF, CODEPAGE_ISUPPER, 0x24E9, 0xFFFF },
+ { 0x24D0, CODEPAGE_ISLOWER, 0xFFFF, 0x24B6 },
+ { 0x24D1, CODEPAGE_ISLOWER, 0xFFFF, 0x24B7 },
+ { 0x24D2, CODEPAGE_ISLOWER, 0xFFFF, 0x24B8 },
+ { 0x24D3, CODEPAGE_ISLOWER, 0xFFFF, 0x24B9 },
+ { 0x24D4, CODEPAGE_ISLOWER, 0xFFFF, 0x24BA },
+ { 0x24D5, CODEPAGE_ISLOWER, 0xFFFF, 0x24BB },
+ { 0x24D6, CODEPAGE_ISLOWER, 0xFFFF, 0x24BC },
+ { 0x24D7, CODEPAGE_ISLOWER, 0xFFFF, 0x24BD },
+ { 0x24D8, CODEPAGE_ISLOWER, 0xFFFF, 0x24BE },
+ { 0x24D9, CODEPAGE_ISLOWER, 0xFFFF, 0x24BF },
+ { 0x24DA, CODEPAGE_ISLOWER, 0xFFFF, 0x24C0 },
+ { 0x24DB, CODEPAGE_ISLOWER, 0xFFFF, 0x24C1 },
+ { 0x24DC, CODEPAGE_ISLOWER, 0xFFFF, 0x24C2 },
+ { 0x24DD, CODEPAGE_ISLOWER, 0xFFFF, 0x24C3 },
+ { 0x24DE, CODEPAGE_ISLOWER, 0xFFFF, 0x24C4 },
+ { 0x24DF, CODEPAGE_ISLOWER, 0xFFFF, 0x24C5 },
+ { 0x24E0, CODEPAGE_ISLOWER, 0xFFFF, 0x24C6 },
+ { 0x24E1, CODEPAGE_ISLOWER, 0xFFFF, 0x24C7 },
+ { 0x24E2, CODEPAGE_ISLOWER, 0xFFFF, 0x24C8 },
+ { 0x24E3, CODEPAGE_ISLOWER, 0xFFFF, 0x24C9 },
+ { 0x24E4, CODEPAGE_ISLOWER, 0xFFFF, 0x24CA },
+ { 0x24E5, CODEPAGE_ISLOWER, 0xFFFF, 0x24CB },
+ { 0x24E6, CODEPAGE_ISLOWER, 0xFFFF, 0x24CC },
+ { 0x24E7, CODEPAGE_ISLOWER, 0xFFFF, 0x24CD },
+ { 0x24E8, CODEPAGE_ISLOWER, 0xFFFF, 0x24CE },
+ { 0x24E9, CODEPAGE_ISLOWER, 0xFFFF, 0x24CF },
+ { 0x24EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2500, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2501, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2502, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2503, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2504, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2505, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2506, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2507, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2508, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2509, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x250F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2510, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2511, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2512, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2513, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2514, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2515, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2516, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2517, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2518, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2519, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x251F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2520, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2521, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2522, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2523, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2524, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2525, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2526, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2527, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2528, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2529, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x252F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2530, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2531, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2532, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2533, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2534, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2535, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2536, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2537, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2538, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2539, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x253F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2540, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2541, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2542, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2543, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2544, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2545, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2546, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2547, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2548, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2549, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x254F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2550, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2551, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2552, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2553, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2554, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2555, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2556, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2557, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2558, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2559, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x255F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2560, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2561, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2562, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2563, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2564, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2565, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2566, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2567, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2568, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2569, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x256F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2570, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2571, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2572, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2573, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2574, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2575, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2576, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2577, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2578, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2579, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x257F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2580, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2581, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2582, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2583, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2584, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2585, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2586, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2587, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2588, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2589, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x258F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2590, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2591, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2592, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2593, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2594, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2595, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x25EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2600, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2601, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2602, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2603, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2604, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2605, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2606, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2607, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2608, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2609, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x260F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2610, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2611, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2612, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2613, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x261F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2620, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2621, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2622, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2623, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2624, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2625, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2626, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2627, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2628, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2629, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x262F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2630, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2631, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2632, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2633, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2634, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2635, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2636, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2637, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2638, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2639, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x263F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2640, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2641, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2642, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2643, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2644, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2645, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2646, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2647, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2648, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2649, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x264F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2650, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2651, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2652, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2653, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2654, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2655, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2656, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2657, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2658, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2659, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x265F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2660, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2661, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2662, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2663, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2664, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2665, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2666, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2667, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2668, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2669, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x266F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2701, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2702, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2703, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2704, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2706, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2707, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2708, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2709, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x270F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2710, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2711, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2712, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2713, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2714, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2715, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2716, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2717, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2718, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2719, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x271F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2720, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2721, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2722, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2723, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2724, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2725, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2726, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2727, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2729, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x272F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2730, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2731, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2732, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2733, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2734, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2735, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2736, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2737, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2738, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2739, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x273F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2740, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2741, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2742, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2743, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2744, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2745, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2746, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2747, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2748, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2749, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x274F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2750, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2751, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2752, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2756, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2758, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2759, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x275E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2761, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2762, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2763, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2764, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2765, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2766, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2767, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2776, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2777, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2778, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2779, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x277F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2780, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2781, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2782, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2783, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2784, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2785, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2786, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2787, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2788, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2789, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x278F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2790, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2791, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2792, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2793, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2794, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2798, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x2799, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x279F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x27BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3001, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3002, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3003, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3004, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3005, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3006, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3007, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3008, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3009, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x300F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3010, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3011, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3012, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3013, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3014, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3015, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3016, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3017, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3018, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3019, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x301F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3020, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3021, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3022, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3023, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3024, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3025, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3026, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3027, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3028, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3029, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x302F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3030, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3031, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3032, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3033, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3034, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3035, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3036, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3037, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x303F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3041, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3042, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3043, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3044, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3045, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3046, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3047, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3048, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3049, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x304F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3050, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3051, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3052, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3053, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3054, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3055, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3056, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3057, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3058, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3059, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x305F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3060, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3061, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3062, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3063, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3064, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3065, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3066, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3067, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3068, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3069, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x306F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3070, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3071, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3072, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3073, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3074, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3075, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3076, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3077, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3078, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3079, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x307F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3080, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3081, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3082, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3083, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3084, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3085, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3086, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3087, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3088, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3089, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x308F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3090, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3091, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3092, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3093, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3094, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3099, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x309E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30B9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30BF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30CF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x30FE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3105, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3106, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3107, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3108, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3109, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x310F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3110, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3111, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3112, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3113, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3114, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3115, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3116, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3117, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3118, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3119, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x311F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3120, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3121, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3122, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3123, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3124, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3125, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3126, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3127, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3128, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3129, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x312A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x312B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x312C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3131, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3132, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3133, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3134, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3135, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3136, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3137, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3138, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3139, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x313F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3140, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3141, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3142, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3143, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3144, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3145, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3146, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3147, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3148, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3149, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x314F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3150, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3151, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3152, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3153, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3154, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3155, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3156, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3157, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3158, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3159, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x315F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3160, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3161, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3162, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3163, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3164, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3165, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3166, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3167, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3168, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3169, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x316F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3170, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3171, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3172, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3173, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3174, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3175, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3176, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3177, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3178, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3179, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x317F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3180, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3181, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3182, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3183, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3184, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3185, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3186, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3187, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3188, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3189, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x318E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3190, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3191, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3192, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3193, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3194, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3195, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3196, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3197, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3198, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3199, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x319F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3200, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3201, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3202, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3203, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3204, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3205, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3206, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3207, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3208, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3209, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x320F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3210, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3211, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3212, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3213, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3214, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3215, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3216, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3217, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3218, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3219, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x321A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x321B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x321C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3220, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3221, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3222, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3223, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3224, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3225, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3226, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3227, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3228, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3229, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x322F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3230, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3231, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3232, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3233, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3234, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3235, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3236, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3237, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3238, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3239, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x323F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3240, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3241, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3242, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3243, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3260, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3261, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3262, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3263, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3264, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3265, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3266, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3267, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3268, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3269, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x326F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3270, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3271, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3272, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3273, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3274, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3275, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3276, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3277, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3278, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3279, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x327A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x327B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x327F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3280, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3281, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3282, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3283, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3284, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3285, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3286, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3287, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3288, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3289, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x328F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3290, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3291, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3292, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3293, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3294, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3295, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3296, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3297, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3298, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3299, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x329F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32B0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32CA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32CB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32D9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32DF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x32FE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3300, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3301, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3302, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3303, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3304, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3305, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3306, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3307, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3308, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3309, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x330F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3310, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3311, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3312, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3313, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3314, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3315, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3316, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3317, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3318, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3319, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x331F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3320, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3321, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3322, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3323, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3324, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3325, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3326, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3327, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3328, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3329, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x332F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3330, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3331, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3332, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3333, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3334, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3335, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3336, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3337, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3338, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3339, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x333F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3340, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3341, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3342, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3343, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3344, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3345, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3346, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3347, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3348, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3349, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x334F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3350, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3351, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3352, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3353, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3354, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3355, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3356, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3357, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3358, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3359, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x335F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3360, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3361, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3362, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3363, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3364, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3365, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3366, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3367, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3368, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3369, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x336F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3370, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3371, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3372, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3373, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3374, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3375, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3376, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x337B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x337F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3380, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3381, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3382, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3383, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3384, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3385, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3386, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3387, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x3388, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3389, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x338A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x338B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x338C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x338D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x338E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x338F, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x3390, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3391, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3392, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3393, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3394, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3395, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3396, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3397, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3398, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x3399, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339A, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339B, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339C, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339D, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339E, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x339F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33A9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AD, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33AE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33AF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33B4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33B9, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33BA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33BF, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33C0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C1, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33C2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33C5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33C6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33C9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33CA, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33CB, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33CC, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33CD, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33CE, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33CF, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D0, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D1, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D2, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D3, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D4, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D5, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D6, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33D7, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33D8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33D9, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33DA, CODEPAGE_ISUPPER, 0xFFFF, 0xFFFF },
+ { 0x33DB, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0x33DC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33DD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33E9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33ED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33EF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33F9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x33FE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x4E00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0x9FA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xAC00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xD7A3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xD800, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDB7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDB80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDBFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDC00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xDFFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xE000, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xF8FF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xF900, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFA2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB00, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB01, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB02, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB03, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB04, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB05, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB06, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB13, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB14, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB15, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB16, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB17, CODEPAGE_ISLOWER, 0xFFFF, 0xFFFF },
+ { 0xFB1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFB9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBD9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFBFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC45, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC46, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC47, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC48, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFC9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCCF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCD9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFCFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD00, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD24, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD25, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD26, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD27, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD28, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD29, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD2F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD53, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFD9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFDFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE21, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE22, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE23, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE30, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE31, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE32, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE33, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE34, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE35, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE36, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE37, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE38, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE39, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE41, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE42, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE43, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE44, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE49, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE4F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE50, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE51, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE52, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE54, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE55, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE56, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE57, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE58, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE59, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE5F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE60, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFE9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEBF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEC9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFECF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFED9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEDF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEEF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEF9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFEFF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF01, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF02, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF03, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF04, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF05, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF06, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF07, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF08, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF09, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF0F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF10, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF11, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF12, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF13, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF14, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF15, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF16, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF17, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF18, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF19, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF1F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF20, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF21, CODEPAGE_ISUPPER, 0xFF41, 0xFFFF },
+ { 0xFF22, CODEPAGE_ISUPPER, 0xFF42, 0xFFFF },
+ { 0xFF23, CODEPAGE_ISUPPER, 0xFF43, 0xFFFF },
+ { 0xFF24, CODEPAGE_ISUPPER, 0xFF44, 0xFFFF },
+ { 0xFF25, CODEPAGE_ISUPPER, 0xFF45, 0xFFFF },
+ { 0xFF26, CODEPAGE_ISUPPER, 0xFF46, 0xFFFF },
+ { 0xFF27, CODEPAGE_ISUPPER, 0xFF47, 0xFFFF },
+ { 0xFF28, CODEPAGE_ISUPPER, 0xFF48, 0xFFFF },
+ { 0xFF29, CODEPAGE_ISUPPER, 0xFF49, 0xFFFF },
+ { 0xFF2A, CODEPAGE_ISUPPER, 0xFF4A, 0xFFFF },
+ { 0xFF2B, CODEPAGE_ISUPPER, 0xFF4B, 0xFFFF },
+ { 0xFF2C, CODEPAGE_ISUPPER, 0xFF4C, 0xFFFF },
+ { 0xFF2D, CODEPAGE_ISUPPER, 0xFF4D, 0xFFFF },
+ { 0xFF2E, CODEPAGE_ISUPPER, 0xFF4E, 0xFFFF },
+ { 0xFF2F, CODEPAGE_ISUPPER, 0xFF4F, 0xFFFF },
+ { 0xFF30, CODEPAGE_ISUPPER, 0xFF50, 0xFFFF },
+ { 0xFF31, CODEPAGE_ISUPPER, 0xFF51, 0xFFFF },
+ { 0xFF32, CODEPAGE_ISUPPER, 0xFF52, 0xFFFF },
+ { 0xFF33, CODEPAGE_ISUPPER, 0xFF53, 0xFFFF },
+ { 0xFF34, CODEPAGE_ISUPPER, 0xFF54, 0xFFFF },
+ { 0xFF35, CODEPAGE_ISUPPER, 0xFF55, 0xFFFF },
+ { 0xFF36, CODEPAGE_ISUPPER, 0xFF56, 0xFFFF },
+ { 0xFF37, CODEPAGE_ISUPPER, 0xFF57, 0xFFFF },
+ { 0xFF38, CODEPAGE_ISUPPER, 0xFF58, 0xFFFF },
+ { 0xFF39, CODEPAGE_ISUPPER, 0xFF59, 0xFFFF },
+ { 0xFF3A, CODEPAGE_ISUPPER, 0xFF5A, 0xFFFF },
+ { 0xFF3B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF3F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF40, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF41, CODEPAGE_ISLOWER, 0xFFFF, 0xFF21 },
+ { 0xFF42, CODEPAGE_ISLOWER, 0xFFFF, 0xFF22 },
+ { 0xFF43, CODEPAGE_ISLOWER, 0xFFFF, 0xFF23 },
+ { 0xFF44, CODEPAGE_ISLOWER, 0xFFFF, 0xFF24 },
+ { 0xFF45, CODEPAGE_ISLOWER, 0xFFFF, 0xFF25 },
+ { 0xFF46, CODEPAGE_ISLOWER, 0xFFFF, 0xFF26 },
+ { 0xFF47, CODEPAGE_ISLOWER, 0xFFFF, 0xFF27 },
+ { 0xFF48, CODEPAGE_ISLOWER, 0xFFFF, 0xFF28 },
+ { 0xFF49, CODEPAGE_ISLOWER, 0xFFFF, 0xFF29 },
+ { 0xFF4A, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2A },
+ { 0xFF4B, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2B },
+ { 0xFF4C, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2C },
+ { 0xFF4D, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2D },
+ { 0xFF4E, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2E },
+ { 0xFF4F, CODEPAGE_ISLOWER, 0xFFFF, 0xFF2F },
+ { 0xFF50, CODEPAGE_ISLOWER, 0xFFFF, 0xFF30 },
+ { 0xFF51, CODEPAGE_ISLOWER, 0xFFFF, 0xFF31 },
+ { 0xFF52, CODEPAGE_ISLOWER, 0xFFFF, 0xFF32 },
+ { 0xFF53, CODEPAGE_ISLOWER, 0xFFFF, 0xFF33 },
+ { 0xFF54, CODEPAGE_ISLOWER, 0xFFFF, 0xFF34 },
+ { 0xFF55, CODEPAGE_ISLOWER, 0xFFFF, 0xFF35 },
+ { 0xFF56, CODEPAGE_ISLOWER, 0xFFFF, 0xFF36 },
+ { 0xFF57, CODEPAGE_ISLOWER, 0xFFFF, 0xFF37 },
+ { 0xFF58, CODEPAGE_ISLOWER, 0xFFFF, 0xFF38 },
+ { 0xFF59, CODEPAGE_ISLOWER, 0xFFFF, 0xFF39 },
+ { 0xFF5A, CODEPAGE_ISLOWER, 0xFFFF, 0xFF3A },
+ { 0xFF5B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF5C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF5D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF5E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF61, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF62, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF63, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF64, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF65, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF66, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF67, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF68, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF69, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF6F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF70, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF71, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF72, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF73, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF74, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF75, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF76, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF77, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF78, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF79, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF7F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF80, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF81, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF82, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF83, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF84, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF85, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF86, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF87, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF88, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF89, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF8F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF90, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF91, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF92, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF93, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF94, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF95, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF96, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF97, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF98, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF99, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9A, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9B, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9C, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9D, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9E, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFF9F, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFA9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFAF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFB9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFBE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFC7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFCF, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFD7, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFDA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFDB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFDC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE0, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE1, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE2, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE3, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE4, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE5, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE6, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE8, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFE9, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEA, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEB, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEC, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFED, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFEE, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF },
+ { 0xFFFD, CODEPAGE_ISNONE, 0xFFFF, 0xFFFF }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_UNICODE_H */
diff --git a/usr/src/uts/common/smbsrv/cp_usascii.h b/usr/src/uts/common/smbsrv/cp_usascii.h
new file mode 100644
index 0000000000..d72c28bb88
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/cp_usascii.h
@@ -0,0 +1,310 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CP_USASCII_H
+#define _SMBSRV_CP_USASCII_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file specifies a codepage mapping for a given character set as
+ * specified below:
+ *
+ * This is the codepage for the US-ASCII Character Set
+ * This codepage defines values for the characters of the
+ * written alphabet of the English language. The US-ASCII
+ * character set is used in the USA. It is a proper
+ * subset of the Latin-1 character set.
+ */
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+codepage_t usascii_codepage[256] = {
+ { CODEPAGE_ISNONE, 0x0000, 0x0000 }, /* 0x0000 */
+ { CODEPAGE_ISNONE, 0x0001, 0x0001 }, /* 0x0001 */
+ { CODEPAGE_ISNONE, 0x0002, 0x0002 }, /* 0x0002 */
+ { CODEPAGE_ISNONE, 0x0003, 0x0003 }, /* 0x0003 */
+ { CODEPAGE_ISNONE, 0x0004, 0x0004 }, /* 0x0004 */
+ { CODEPAGE_ISNONE, 0x0005, 0x0005 }, /* 0x0005 */
+ { CODEPAGE_ISNONE, 0x0006, 0x0006 }, /* 0x0006 */
+ { CODEPAGE_ISNONE, 0x0007, 0x0007 }, /* 0x0007 */
+ { CODEPAGE_ISNONE, 0x0008, 0x0008 }, /* 0x0008 */
+ { CODEPAGE_ISNONE, 0x0009, 0x0009 }, /* 0x0009 */
+ { CODEPAGE_ISNONE, 0x000a, 0x000a }, /* 0x000a */
+ { CODEPAGE_ISNONE, 0x000b, 0x000b }, /* 0x000b */
+ { CODEPAGE_ISNONE, 0x000c, 0x000c }, /* 0x000c */
+ { CODEPAGE_ISNONE, 0x000d, 0x000d }, /* 0x000d */
+ { CODEPAGE_ISNONE, 0x000e, 0x000e }, /* 0x000e */
+ { CODEPAGE_ISNONE, 0x000f, 0x000f }, /* 0x000f */
+ { CODEPAGE_ISNONE, 0x0010, 0x0010 }, /* 0x0010 */
+ { CODEPAGE_ISNONE, 0x0011, 0x0011 }, /* 0x0011 */
+ { CODEPAGE_ISNONE, 0x0012, 0x0012 }, /* 0x0012 */
+ { CODEPAGE_ISNONE, 0x0013, 0x0013 }, /* 0x0013 */
+ { CODEPAGE_ISNONE, 0x0014, 0x0014 }, /* 0x0014 */
+ { CODEPAGE_ISNONE, 0x0015, 0x0015 }, /* 0x0015 */
+ { CODEPAGE_ISNONE, 0x0016, 0x0016 }, /* 0x0016 */
+ { CODEPAGE_ISNONE, 0x0017, 0x0017 }, /* 0x0017 */
+ { CODEPAGE_ISNONE, 0x0018, 0x0018 }, /* 0x0018 */
+ { CODEPAGE_ISNONE, 0x0019, 0x0019 }, /* 0x0019 */
+ { CODEPAGE_ISNONE, 0x001a, 0x001a }, /* 0x001a */
+ { CODEPAGE_ISNONE, 0x001b, 0x001b }, /* 0x001b */
+ { CODEPAGE_ISNONE, 0x001c, 0x001c }, /* 0x001c */
+ { CODEPAGE_ISNONE, 0x001d, 0x001d }, /* 0x001d */
+ { CODEPAGE_ISNONE, 0x001e, 0x001e }, /* 0x001e */
+ { CODEPAGE_ISNONE, 0x001f, 0x001f }, /* 0x001f */
+ { CODEPAGE_ISNONE, 0x0020, 0x0020 }, /* 0x0020 */
+ { CODEPAGE_ISNONE, 0x0021, 0x0021 }, /* 0x0021 */
+ { CODEPAGE_ISNONE, 0x0022, 0x0022 }, /* 0x0022 */
+ { CODEPAGE_ISNONE, 0x0023, 0x0023 }, /* 0x0023 */
+ { CODEPAGE_ISNONE, 0x0024, 0x0024 }, /* 0x0024 */
+ { CODEPAGE_ISNONE, 0x0025, 0x0025 }, /* 0x0025 */
+ { CODEPAGE_ISNONE, 0x0026, 0x0026 }, /* 0x0026 */
+ { CODEPAGE_ISNONE, 0x0027, 0x0027 }, /* 0x0027 */
+ { CODEPAGE_ISNONE, 0x0028, 0x0028 }, /* 0x0028 */
+ { CODEPAGE_ISNONE, 0x0029, 0x0029 }, /* 0x0029 */
+ { CODEPAGE_ISNONE, 0x002a, 0x002a }, /* 0x002a */
+ { CODEPAGE_ISNONE, 0x002b, 0x002b }, /* 0x002b */
+ { CODEPAGE_ISNONE, 0x002c, 0x002c }, /* 0x002c */
+ { CODEPAGE_ISNONE, 0x002d, 0x002d }, /* 0x002d */
+ { CODEPAGE_ISNONE, 0x002e, 0x002e }, /* 0x002e */
+ { CODEPAGE_ISNONE, 0x002f, 0x002f }, /* 0x002f */
+ { CODEPAGE_ISNONE, 0x0030, 0x0030 }, /* 0x0030 */
+ { CODEPAGE_ISNONE, 0x0031, 0x0031 }, /* 0x0031 */
+ { CODEPAGE_ISNONE, 0x0032, 0x0032 }, /* 0x0032 */
+ { CODEPAGE_ISNONE, 0x0033, 0x0033 }, /* 0x0033 */
+ { CODEPAGE_ISNONE, 0x0034, 0x0034 }, /* 0x0034 */
+ { CODEPAGE_ISNONE, 0x0035, 0x0035 }, /* 0x0035 */
+ { CODEPAGE_ISNONE, 0x0036, 0x0036 }, /* 0x0036 */
+ { CODEPAGE_ISNONE, 0x0037, 0x0037 }, /* 0x0037 */
+ { CODEPAGE_ISNONE, 0x0038, 0x0038 }, /* 0x0038 */
+ { CODEPAGE_ISNONE, 0x0039, 0x0039 }, /* 0x0039 */
+ { CODEPAGE_ISNONE, 0x003a, 0x003a }, /* 0x003a */
+ { CODEPAGE_ISNONE, 0x003b, 0x003b }, /* 0x003b */
+ { CODEPAGE_ISNONE, 0x003c, 0x003c }, /* 0x003c */
+ { CODEPAGE_ISNONE, 0x003d, 0x003d }, /* 0x003d */
+ { CODEPAGE_ISNONE, 0x003e, 0x003e }, /* 0x003e */
+ { CODEPAGE_ISNONE, 0x003f, 0x003f }, /* 0x003f */
+ { CODEPAGE_ISNONE, 0x0040, 0x0040 }, /* 0x0040 */
+ { CODEPAGE_ISUPPER, 0x0041, 0x0061 }, /* 0x0041 */
+ { CODEPAGE_ISUPPER, 0x0042, 0x0062 }, /* 0x0042 */
+ { CODEPAGE_ISUPPER, 0x0043, 0x0063 }, /* 0x0043 */
+ { CODEPAGE_ISUPPER, 0x0044, 0x0064 }, /* 0x0044 */
+ { CODEPAGE_ISUPPER, 0x0045, 0x0065 }, /* 0x0045 */
+ { CODEPAGE_ISUPPER, 0x0046, 0x0066 }, /* 0x0046 */
+ { CODEPAGE_ISUPPER, 0x0047, 0x0067 }, /* 0x0047 */
+ { CODEPAGE_ISUPPER, 0x0048, 0x0068 }, /* 0x0048 */
+ { CODEPAGE_ISUPPER, 0x0049, 0x0069 }, /* 0x0049 */
+ { CODEPAGE_ISUPPER, 0x004a, 0x006a }, /* 0x004a */
+ { CODEPAGE_ISUPPER, 0x004b, 0x006b }, /* 0x004b */
+ { CODEPAGE_ISUPPER, 0x004c, 0x006c }, /* 0x004c */
+ { CODEPAGE_ISUPPER, 0x004d, 0x006d }, /* 0x004d */
+ { CODEPAGE_ISUPPER, 0x004e, 0x006e }, /* 0x004e */
+ { CODEPAGE_ISUPPER, 0x004f, 0x006f }, /* 0x004f */
+ { CODEPAGE_ISUPPER, 0x0050, 0x0070 }, /* 0x0050 */
+ { CODEPAGE_ISUPPER, 0x0051, 0x0071 }, /* 0x0051 */
+ { CODEPAGE_ISUPPER, 0x0052, 0x0072 }, /* 0x0052 */
+ { CODEPAGE_ISUPPER, 0x0053, 0x0073 }, /* 0x0053 */
+ { CODEPAGE_ISUPPER, 0x0054, 0x0074 }, /* 0x0054 */
+ { CODEPAGE_ISUPPER, 0x0055, 0x0075 }, /* 0x0055 */
+ { CODEPAGE_ISUPPER, 0x0056, 0x0076 }, /* 0x0056 */
+ { CODEPAGE_ISUPPER, 0x0057, 0x0077 }, /* 0x0057 */
+ { CODEPAGE_ISUPPER, 0x0058, 0x0078 }, /* 0x0058 */
+ { CODEPAGE_ISUPPER, 0x0059, 0x0079 }, /* 0x0059 */
+ { CODEPAGE_ISUPPER, 0x005a, 0x007a }, /* 0x005a */
+ { CODEPAGE_ISNONE, 0x005b, 0x005b }, /* 0x005b */
+ { CODEPAGE_ISNONE, 0x005c, 0x005c }, /* 0x005c */
+ { CODEPAGE_ISNONE, 0x005d, 0x005d }, /* 0x005d */
+ { CODEPAGE_ISNONE, 0x005e, 0x005e }, /* 0x005e */
+ { CODEPAGE_ISNONE, 0x005f, 0x005f }, /* 0x005f */
+ { CODEPAGE_ISNONE, 0x0060, 0x0060 }, /* 0x0060 */
+ { CODEPAGE_ISLOWER, 0x0041, 0x0061 }, /* 0x0061 */
+ { CODEPAGE_ISLOWER, 0x0042, 0x0062 }, /* 0x0062 */
+ { CODEPAGE_ISLOWER, 0x0043, 0x0063 }, /* 0x0063 */
+ { CODEPAGE_ISLOWER, 0x0044, 0x0064 }, /* 0x0064 */
+ { CODEPAGE_ISLOWER, 0x0045, 0x0065 }, /* 0x0065 */
+ { CODEPAGE_ISLOWER, 0x0046, 0x0066 }, /* 0x0066 */
+ { CODEPAGE_ISLOWER, 0x0047, 0x0067 }, /* 0x0067 */
+ { CODEPAGE_ISLOWER, 0x0048, 0x0068 }, /* 0x0068 */
+ { CODEPAGE_ISLOWER, 0x0049, 0x0069 }, /* 0x0069 */
+ { CODEPAGE_ISLOWER, 0x004a, 0x006a }, /* 0x006a */
+ { CODEPAGE_ISLOWER, 0x004b, 0x006b }, /* 0x006b */
+ { CODEPAGE_ISLOWER, 0x004c, 0x006c }, /* 0x006c */
+ { CODEPAGE_ISLOWER, 0x004d, 0x006d }, /* 0x006d */
+ { CODEPAGE_ISLOWER, 0x004e, 0x006e }, /* 0x006e */
+ { CODEPAGE_ISLOWER, 0x004f, 0x006f }, /* 0x006f */
+ { CODEPAGE_ISLOWER, 0x0050, 0x0070 }, /* 0x0070 */
+ { CODEPAGE_ISLOWER, 0x0051, 0x0071 }, /* 0x0071 */
+ { CODEPAGE_ISLOWER, 0x0052, 0x0072 }, /* 0x0072 */
+ { CODEPAGE_ISLOWER, 0x0053, 0x0073 }, /* 0x0073 */
+ { CODEPAGE_ISLOWER, 0x0054, 0x0074 }, /* 0x0074 */
+ { CODEPAGE_ISLOWER, 0x0055, 0x0075 }, /* 0x0075 */
+ { CODEPAGE_ISLOWER, 0x0056, 0x0076 }, /* 0x0076 */
+ { CODEPAGE_ISLOWER, 0x0057, 0x0077 }, /* 0x0077 */
+ { CODEPAGE_ISLOWER, 0x0058, 0x0078 }, /* 0x0078 */
+ { CODEPAGE_ISLOWER, 0x0059, 0x0079 }, /* 0x0079 */
+ { CODEPAGE_ISLOWER, 0x005a, 0x007a }, /* 0x007a */
+ { CODEPAGE_ISNONE, 0x007b, 0x007b }, /* 0x007b */
+ { CODEPAGE_ISNONE, 0x007c, 0x007c }, /* 0x007c */
+ { CODEPAGE_ISNONE, 0x007d, 0x007d }, /* 0x007d */
+ { CODEPAGE_ISNONE, 0x007e, 0x007e }, /* 0x007e */
+ { CODEPAGE_ISNONE, 0x007f, 0x007f }, /* 0x007f */
+ { CODEPAGE_ISNONE, 0x0080, 0x0080 }, /* 0x0080 */
+ { CODEPAGE_ISNONE, 0x0081, 0x0081 }, /* 0x0081 */
+ { CODEPAGE_ISNONE, 0x0082, 0x0082 }, /* 0x0082 */
+ { CODEPAGE_ISNONE, 0x0083, 0x0083 }, /* 0x0083 */
+ { CODEPAGE_ISNONE, 0x0084, 0x0084 }, /* 0x0084 */
+ { CODEPAGE_ISNONE, 0x0085, 0x0085 }, /* 0x0085 */
+ { CODEPAGE_ISNONE, 0x0086, 0x0086 }, /* 0x0086 */
+ { CODEPAGE_ISNONE, 0x0087, 0x0087 }, /* 0x0087 */
+ { CODEPAGE_ISNONE, 0x0088, 0x0088 }, /* 0x0088 */
+ { CODEPAGE_ISNONE, 0x0089, 0x0089 }, /* 0x0089 */
+ { CODEPAGE_ISNONE, 0x008a, 0x008a }, /* 0x008a */
+ { CODEPAGE_ISNONE, 0x008b, 0x008b }, /* 0x008b */
+ { CODEPAGE_ISNONE, 0x008c, 0x008c }, /* 0x008c */
+ { CODEPAGE_ISNONE, 0x008d, 0x008d }, /* 0x008d */
+ { CODEPAGE_ISNONE, 0x008e, 0x008e }, /* 0x008e */
+ { CODEPAGE_ISNONE, 0x008f, 0x008f }, /* 0x008f */
+ { CODEPAGE_ISNONE, 0x0090, 0x0090 }, /* 0x0090 */
+ { CODEPAGE_ISNONE, 0x0091, 0x0091 }, /* 0x0091 */
+ { CODEPAGE_ISNONE, 0x0092, 0x0092 }, /* 0x0092 */
+ { CODEPAGE_ISNONE, 0x0093, 0x0093 }, /* 0x0093 */
+ { CODEPAGE_ISNONE, 0x0094, 0x0094 }, /* 0x0094 */
+ { CODEPAGE_ISNONE, 0x0095, 0x0095 }, /* 0x0095 */
+ { CODEPAGE_ISNONE, 0x0096, 0x0096 }, /* 0x0096 */
+ { CODEPAGE_ISNONE, 0x0097, 0x0097 }, /* 0x0097 */
+ { CODEPAGE_ISNONE, 0x0098, 0x0098 }, /* 0x0098 */
+ { CODEPAGE_ISNONE, 0x0099, 0x0099 }, /* 0x0099 */
+ { CODEPAGE_ISNONE, 0x009a, 0x009a }, /* 0x009a */
+ { CODEPAGE_ISNONE, 0x009b, 0x009b }, /* 0x009b */
+ { CODEPAGE_ISNONE, 0x009c, 0x009c }, /* 0x009c */
+ { CODEPAGE_ISNONE, 0x009d, 0x009d }, /* 0x009d */
+ { CODEPAGE_ISNONE, 0x009e, 0x009e }, /* 0x009e */
+ { CODEPAGE_ISNONE, 0x009f, 0x009f }, /* 0x009f */
+ { CODEPAGE_ISNONE, 0x00a0, 0x00a0 }, /* 0x00a0 */
+ { CODEPAGE_ISNONE, 0x00a1, 0x00a1 }, /* 0x00a1 */
+ { CODEPAGE_ISNONE, 0x00a2, 0x00a2 }, /* 0x00a2 */
+ { CODEPAGE_ISNONE, 0x00a3, 0x00a3 }, /* 0x00a3 */
+ { CODEPAGE_ISNONE, 0x00a4, 0x00a4 }, /* 0x00a4 */
+ { CODEPAGE_ISNONE, 0x00a5, 0x00a5 }, /* 0x00a5 */
+ { CODEPAGE_ISNONE, 0x00a6, 0x00a6 }, /* 0x00a6 */
+ { CODEPAGE_ISNONE, 0x00a7, 0x00a7 }, /* 0x00a7 */
+ { CODEPAGE_ISNONE, 0x00a8, 0x00a8 }, /* 0x00a8 */
+ { CODEPAGE_ISNONE, 0x00a9, 0x00a9 }, /* 0x00a9 */
+ { CODEPAGE_ISNONE, 0x00aa, 0x00aa }, /* 0x00aa */
+ { CODEPAGE_ISNONE, 0x00ab, 0x00ab }, /* 0x00ab */
+ { CODEPAGE_ISNONE, 0x00ac, 0x00ac }, /* 0x00ac */
+ { CODEPAGE_ISNONE, 0x00ad, 0x00ad }, /* 0x00ad */
+ { CODEPAGE_ISNONE, 0x00ae, 0x00ae }, /* 0x00ae */
+ { CODEPAGE_ISNONE, 0x00af, 0x00af }, /* 0x00af */
+ { CODEPAGE_ISNONE, 0x00b0, 0x00b0 }, /* 0x00b0 */
+ { CODEPAGE_ISNONE, 0x00b1, 0x00b1 }, /* 0x00b1 */
+ { CODEPAGE_ISNONE, 0x00b2, 0x00b2 }, /* 0x00b2 */
+ { CODEPAGE_ISNONE, 0x00b3, 0x00b3 }, /* 0x00b3 */
+ { CODEPAGE_ISNONE, 0x00b4, 0x00b4 }, /* 0x00b4 */
+ { CODEPAGE_ISNONE, 0x00b5, 0x00b5 }, /* 0x00b5 */
+ { CODEPAGE_ISNONE, 0x00b6, 0x00b6 }, /* 0x00b6 */
+ { CODEPAGE_ISNONE, 0x00b7, 0x00b7 }, /* 0x00b7 */
+ { CODEPAGE_ISNONE, 0x00b8, 0x00b8 }, /* 0x00b8 */
+ { CODEPAGE_ISNONE, 0x00b9, 0x00b9 }, /* 0x00b9 */
+ { CODEPAGE_ISNONE, 0x00ba, 0x00ba }, /* 0x00ba */
+ { CODEPAGE_ISNONE, 0x00bb, 0x00bb }, /* 0x00bb */
+ { CODEPAGE_ISNONE, 0x00bc, 0x00bc }, /* 0x00bc */
+ { CODEPAGE_ISNONE, 0x00bd, 0x00bd }, /* 0x00bd */
+ { CODEPAGE_ISNONE, 0x00be, 0x00be }, /* 0x00be */
+ { CODEPAGE_ISNONE, 0x00bf, 0x00bf }, /* 0x00bf */
+ { CODEPAGE_ISNONE, 0x00c0, 0x00c0 }, /* 0x00c0 */
+ { CODEPAGE_ISNONE, 0x00c1, 0x00c1 }, /* 0x00c1 */
+ { CODEPAGE_ISNONE, 0x00c2, 0x00c2 }, /* 0x00c2 */
+ { CODEPAGE_ISNONE, 0x00c3, 0x00c3 }, /* 0x00c3 */
+ { CODEPAGE_ISNONE, 0x00c4, 0x00c4 }, /* 0x00c4 */
+ { CODEPAGE_ISNONE, 0x00c5, 0x00c5 }, /* 0x00c5 */
+ { CODEPAGE_ISNONE, 0x00c6, 0x00c6 }, /* 0x00c6 */
+ { CODEPAGE_ISNONE, 0x00c7, 0x00c7 }, /* 0x00c7 */
+ { CODEPAGE_ISNONE, 0x00c8, 0x00c8 }, /* 0x00c8 */
+ { CODEPAGE_ISNONE, 0x00c9, 0x00c9 }, /* 0x00c9 */
+ { CODEPAGE_ISNONE, 0x00ca, 0x00ca }, /* 0x00ca */
+ { CODEPAGE_ISNONE, 0x00cb, 0x00cb }, /* 0x00cb */
+ { CODEPAGE_ISNONE, 0x00cc, 0x00cc }, /* 0x00cc */
+ { CODEPAGE_ISNONE, 0x00cd, 0x00cd }, /* 0x00cd */
+ { CODEPAGE_ISNONE, 0x00ce, 0x00ce }, /* 0x00ce */
+ { CODEPAGE_ISNONE, 0x00cf, 0x00cf }, /* 0x00cf */
+ { CODEPAGE_ISNONE, 0x00d0, 0x00d0 }, /* 0x00d0 */
+ { CODEPAGE_ISNONE, 0x00d1, 0x00d1 }, /* 0x00d1 */
+ { CODEPAGE_ISNONE, 0x00d2, 0x00d2 }, /* 0x00d2 */
+ { CODEPAGE_ISNONE, 0x00d3, 0x00d3 }, /* 0x00d3 */
+ { CODEPAGE_ISNONE, 0x00d4, 0x00d4 }, /* 0x00d4 */
+ { CODEPAGE_ISNONE, 0x00d5, 0x00d5 }, /* 0x00d5 */
+ { CODEPAGE_ISNONE, 0x00d6, 0x00d6 }, /* 0x00d6 */
+ { CODEPAGE_ISNONE, 0x00d7, 0x00d7 }, /* 0x00d7 */
+ { CODEPAGE_ISNONE, 0x00d8, 0x00d8 }, /* 0x00d8 */
+ { CODEPAGE_ISNONE, 0x00d9, 0x00d9 }, /* 0x00d9 */
+ { CODEPAGE_ISNONE, 0x00da, 0x00da }, /* 0x00da */
+ { CODEPAGE_ISNONE, 0x00db, 0x00db }, /* 0x00db */
+ { CODEPAGE_ISNONE, 0x00dc, 0x00dc }, /* 0x00dc */
+ { CODEPAGE_ISNONE, 0x00dd, 0x00dd }, /* 0x00dd */
+ { CODEPAGE_ISNONE, 0x00de, 0x00de }, /* 0x00de */
+ { CODEPAGE_ISNONE, 0x00df, 0x00df }, /* 0x00df */
+ { CODEPAGE_ISNONE, 0x00e0, 0x00e0 }, /* 0x00e0 */
+ { CODEPAGE_ISNONE, 0x00e1, 0x00e1 }, /* 0x00e1 */
+ { CODEPAGE_ISNONE, 0x00e2, 0x00e2 }, /* 0x00e2 */
+ { CODEPAGE_ISNONE, 0x00e3, 0x00e3 }, /* 0x00e3 */
+ { CODEPAGE_ISNONE, 0x00e4, 0x00e4 }, /* 0x00e4 */
+ { CODEPAGE_ISNONE, 0x00e5, 0x00e5 }, /* 0x00e5 */
+ { CODEPAGE_ISNONE, 0x00e6, 0x00e6 }, /* 0x00e6 */
+ { CODEPAGE_ISNONE, 0x00e7, 0x00e7 }, /* 0x00e7 */
+ { CODEPAGE_ISNONE, 0x00e8, 0x00e8 }, /* 0x00e8 */
+ { CODEPAGE_ISNONE, 0x00e9, 0x00e9 }, /* 0x00e9 */
+ { CODEPAGE_ISNONE, 0x00ea, 0x00ea }, /* 0x00ea */
+ { CODEPAGE_ISNONE, 0x00eb, 0x00eb }, /* 0x00eb */
+ { CODEPAGE_ISNONE, 0x00ec, 0x00ec }, /* 0x00ec */
+ { CODEPAGE_ISNONE, 0x00ed, 0x00ed }, /* 0x00ed */
+ { CODEPAGE_ISNONE, 0x00ee, 0x00ee }, /* 0x00ee */
+ { CODEPAGE_ISNONE, 0x00ef, 0x00ef }, /* 0x00ef */
+ { CODEPAGE_ISNONE, 0x00f0, 0x00f0 }, /* 0x00f0 */
+ { CODEPAGE_ISNONE, 0x00f1, 0x00f1 }, /* 0x00f1 */
+ { CODEPAGE_ISNONE, 0x00f2, 0x00f2 }, /* 0x00f2 */
+ { CODEPAGE_ISNONE, 0x00f3, 0x00f3 }, /* 0x00f3 */
+ { CODEPAGE_ISNONE, 0x00f4, 0x00f4 }, /* 0x00f4 */
+ { CODEPAGE_ISNONE, 0x00f5, 0x00f5 }, /* 0x00f5 */
+ { CODEPAGE_ISNONE, 0x00f6, 0x00f6 }, /* 0x00f6 */
+ { CODEPAGE_ISNONE, 0x00f7, 0x00f7 }, /* 0x00f7 */
+ { CODEPAGE_ISNONE, 0x00f8, 0x00f8 }, /* 0x00f8 */
+ { CODEPAGE_ISNONE, 0x00f9, 0x00f9 }, /* 0x00f9 */
+ { CODEPAGE_ISNONE, 0x00fa, 0x00fa }, /* 0x00fa */
+ { CODEPAGE_ISNONE, 0x00fb, 0x00fb }, /* 0x00fb */
+ { CODEPAGE_ISNONE, 0x00fc, 0x00fc }, /* 0x00fc */
+ { CODEPAGE_ISNONE, 0x00fd, 0x00fd }, /* 0x00fd */
+ { CODEPAGE_ISNONE, 0x00fe, 0x00fe }, /* 0x00fe */
+ { CODEPAGE_ISNONE, 0x00ff, 0x00ff } }; /* 0x00ff */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CP_USASCII_H */
diff --git a/usr/src/uts/common/smbsrv/crypt.h b/usr/src/uts/common/smbsrv/crypt.h
new file mode 100644
index 0000000000..b2765a2f8e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/crypt.h
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CRYPT_H
+#define _SMBSRV_CRYPT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PASS_LEN 20
+#define BUF_LEN (2 * PASS_LEN)
+
+extern int smb_des_setkey(const char *);
+extern int smb_des_cipher(const char *, char *, long, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CRYPT_H */
diff --git a/usr/src/uts/common/smbsrv/ctype.h b/usr/src/uts/common/smbsrv/ctype.h
new file mode 100644
index 0000000000..284db64419
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ctype.h
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_CTYPE_H
+#define _SMBSRV_CTYPE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/codepage.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _mts_between(l, c, u) ((l) <= (c) && (c) <= (u))
+
+/*
+ * These macros take non-ascii characters into account.
+ * Their behavior depends on the codepage that is used.
+ */
+#define mts_islower(c) codepage_islower((c))
+#define mts_isupper(c) codepage_isupper((c))
+#define mts_tolower(c) codepage_tolower((c))
+#define mts_toupper(c) codepage_toupper((c))
+
+#define mts_isalpha(c) (mts_islower(c) || mts_isupper(c))
+#define mts_isdigit(c) _mts_between('0', (c), '9')
+#define mts_isalnum(c) (mts_isalpha(c) || mts_isdigit(c))
+#define mts_isxdigit(c) (mts_isdigit(c) || \
+ _mts_between('a', (c), 'f') || \
+ _mts_between('A', (c), 'F'))
+#define mts_isblank(c) ((c) == ' ' || (c) == '\t')
+#define mts_isspace(c) ((c) == ' ' || \
+ (c) == '\t' || \
+ (c) == '\n' || \
+ (c) == '\r' || \
+ (c) == '\f')
+#define mts_isascii(c) (!((c) &~ 0x7F))
+
+/* These macros only apply to ASCII */
+#define mts_isalpha_ascii(c) \
+ (_mts_between('a', (c), 'z') || _mts_between('A', (c), 'Z'))
+#define mts_isalnum_ascii(c) (mts_isalpha_ascii(c) || mts_isdigit(c))
+
+/* should it include non-ascii characters ? */
+#define mts_isprint(c) _mts_between('!', (c), '~')
+#define mts_iscntrl(c) (((c) >= 0) && ((c) <= 0x1f)) || ((c) == 0x7f))
+#define mts_ispunct(c) (mts_isprint(c) && !mts_isxdigit(c) && !mts_isspace(c))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_CTYPE_H */
diff --git a/usr/src/uts/common/smbsrv/doserror.h b/usr/src/uts/common/smbsrv/doserror.h
new file mode 100644
index 0000000000..a5703e1b49
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/doserror.h
@@ -0,0 +1,145 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _SMBSRV_DOSERROR_H
+#define _SMBSRV_DOSERROR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the list of DOS error codes. I think the error
+ * codes are divided into different classes, which is why there are
+ * duplicate values.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Error source or class
+ */
+#define SUCCESS 0x00 /* The request was successful. */
+#define ERRDOS 0x01 /* Core DOS operating system error. */
+#define ERRSRV 0x02 /* Server network file error */
+#define ERRHRD 0x03 /* Hardware error */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+
+/*
+ * ERRDOS error codes
+ */
+#define ERRbadfunc 1 /* Invalid function. The server did not */
+#define ERRbadfile 2 /* File not found. The last component of a */
+#define ERRbadpath 3 /* Directory invalid. A directory component in */
+#define ERRnofids 4 /* Too many open files. The server has no file */
+#define ERRnoaccess 5 /* Access denied, the client's context does not */
+#define ERRbadfid 6 /* Invalid file handle. The file handle */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Insufficient server memory to perform the */
+#define ERRbadmem 9 /* Invalid memory block address. */
+#define ERRbadenv 10 /* Invalid environment. */
+#define ERRbadformat 11 /* Invalid format. */
+#define ERRbadaccess 12 /* Invalid open mode. */
+#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls */
+#define ERRbaddrive 15 /* Invalid drive specified. */
+#define ERRremcd 16 /* A Delete Directory request attempted to */
+#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename */
+#define ERRnofiles 18 /* A File Search command can find no more files */
+#define ERRbadshare 32 /* The sharing mode specified for an Open */
+#define ERRlock 33 /* A Lock request conflicted with an existing */
+#define ERRfilexists 80 /* The file named in a Create Directory, Make */
+#define ERRnotlocked 158 /* No lock matched the unlock range */
+#define ERRnoatomiclocks 174 /* Change lock type not supported */
+#define ERRbadpipe 230 /* Pipe invalid. */
+#define ERRpipebusy 231 /* All instances of the requested pipe are busy. */
+#define ERRpipeclosing 232 /* Pipe close in progress. */
+#define ERRnotconnected 233 /* No process on other end of pipe. */
+#define ERRmoredata 234 /* There is more data to be returned. */
+#define ERRunknownlevel 124
+
+
+/*
+ * ERRSRV error codes
+ */
+#define ERRerror 1 /* Non-specific error code. It is returned */
+#define ERRbadpw 2 /* Bad password - name/password pair in a Tree */
+#define ERRaccess 4 /* The client does not have the necessary access */
+#define ERRinvnid 5 /* The Tid specified in a command was invalid. */
+#define ERRinvnetname 6 /* Invalid network name in tree connect. */
+#define ERRinvdevice 7 /* Invalid device - printer request made to non- */
+#define ERRqfull 49 /* Print queue full (files) -- returned by open */
+#define ERRqtoobig 50 /* Print queue full -- no space. */
+#define ERRqeof 51 /* EOF on print queue dump. */
+#define ERRinvpfid 52 /* Invalid print file FID. */
+#define ERRsmbcmd 64 /* The server did not recognize the command */
+#define ERRsrverror 65 /* The server encountered an internal error, */
+#define ERRfilespecs 67 /* The Fid and pathname parameters contained an */
+#define ERRbadpermits 69 /* The access permissions specified for a file */
+#define ERRsetattrmode 71 /* The attribute mode in the Set File Attribute */
+#define ERRpaused 81 /* Server is paused. (reserved for messaging) */
+#define ERRmsgoff 82 /* Not receiving messages. (reserved for */
+#define ERRnoroom 83 /* No room to buffer message. (reserved for */
+#define ERRrmuns 87 /* Too many remote user names. (reserved for */
+#define ERRtimeout 88 /* Operation timed out. */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* Too many Uids active on this session. */
+#define ERRbaduid 91 /* The Uid is not known as a valid user */
+#define ERRusempx 250 /* Temporarily unable to support Raw, use MPX */
+#define ERRusestd 251 /* Temporarily unable to support Raw, use */
+#define ERRcontmpx 252 /* Continue in MPX mode. */
+#define ERRnosupport 65535 /* Function not supported. */
+
+
+/*
+ * ERRHRD error codes
+ */
+#define ERRnowrite 19 /* Attempt to write on write-protected media */
+#define ERRbadunit 20 /* Unknown unit. */
+#define ERRnotready 21 /* Drive not ready. */
+#define ERRbadcmd 22 /* Unknown command. */
+#define ERRdata 23 /* Data error (CRC). */
+#define ERRbadreq 24 /* Bad request structure length. */
+#define ERRseek 25 /* Seek error. */
+#define ERRbadmedia 26 /* Unknown media type. */
+#define ERRbadsector 27 /* Sector not found. */
+#define ERRnopaper 28 /* Printer out of paper. */
+#define ERRwrite 29 /* Write fault. */
+#define ERRread 30 /* Read fault. */
+#define ERRgeneral 31 /* General failure. */
+#define ERRbadshare 32 /* A open conflicts with an existing open. */
+#define ERRlock 33 /* A Lock request conflicted with an existing */
+#define ERRwrongdisk 34 /* The wrong disk was found in a drive. */
+#define ERRFCBUnavail 35 /* No FCBs are available to process request. */
+#define ERRsharebufexc 36 /* A sharing buffer has been exceeded. */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_DOSERROR_H */
diff --git a/usr/src/uts/common/smbsrv/hash_table.h b/usr/src/uts/common/smbsrv/hash_table.h
new file mode 100755
index 0000000000..0e4586097c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/hash_table.h
@@ -0,0 +1,192 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_HASH_TABLE_H
+#define _SMBSRV_HASH_TABLE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * Interface definition for the hash table library. The hash table is a
+ * user-specified array of pointers to items. Hash collisions are handled
+ * using linked lists from the table entries. A handle is associated with
+ * each table, which is used to maintain the hash table.
+ *
+ * +------+ +-------+ +----+ +----+
+ * |handle|---> |index 0|--->|item|--->|item|--->
+ * | ... | +-------+ +----+ +----+
+ * | ... | |index 1|--->
+ * +------+ +-------+ +----+ +----+ +----+
+ * |index 2|--->|item|--->|item|--->|item|--->
+ * +-------+ +----+ +----+ +----+
+ * | ... |--->
+ * +-------+
+ * | ... |--->
+ * +-------+
+ * |index n|--->
+ * +-------+
+ *
+ */
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This is the hash multiplier value.
+ */
+#define HASH_MESH_VALUE 77
+
+/*
+ * Each entry (item) in the hash table has a linked-list pointer, a key,
+ * a pointer to some user defined data (which may be null) and some flags.
+ * The key is a user provided key and is used to position the item within
+ * the table. The linked-list is used to store items whose hash values
+ * collide. The data pointer is never dereferenced in the hash code so
+ * it may be a null pointer.
+ *
+ * The item bit flags are:
+ *
+ * HTIF_DELETE: Specifies that an item is marked for deletion (see
+ * ht_mark_delete and ht_clean_table).
+ */
+#define HTIF_MARKED_DELETED 0x01
+#define HT_DELETE HTIF_MARKED_DELETED
+
+typedef struct ht_item {
+ struct ht_item *hi_next;
+ char *hi_key;
+ void *hi_data;
+ size_t hi_flags;
+} HT_ITEM;
+
+/*
+ * HT_TABLE_ENTRY is an opaque structure (to the public) used to maintain
+ * a pointer to the hash table and the number of items in the table entry.
+ * This number shows number of both available items and those are marked
+ * as deleted.
+ */
+typedef struct ht_table_entry {
+ HT_ITEM *he_head;
+ size_t he_count;
+} HT_TABLE_ENTRY;
+
+/*
+ * The HT_HANDLE is an opaque handle that associates each request with
+ * a hash table. A handle is generated when a hash table is created and
+ * it is used to maintain all global data associated with the table.
+ *
+ * The handle bit flags are:
+ *
+ * HTHF_FIXED_KEY: Specifies that keys are fixed length and should
+ * not be assumed to be null terminated.
+ */
+#define HTHF_FIXED_KEY 0x01
+
+typedef struct ht_handle {
+ HT_TABLE_ENTRY *ht_table;
+ size_t ht_sequence;
+ size_t ht_table_size;
+ size_t ht_table_mask;
+ size_t ht_key_size;
+ size_t ht_total_items; /* show total number of available items */
+ size_t ht_flags;
+ size_t (*ht_hash)(struct ht_handle *handle, const char *key);
+ void (*ht_callback)(HT_ITEM *item);
+ int (*ht_cmp)(const char *key1, const char *key2, size_t n);
+} HT_HANDLE;
+
+/*
+ * Typedefs for the optional user-installable functions.
+ */
+typedef void (*HT_CALLBACK)(HT_ITEM *item);
+
+/*
+ * Compare function cast to make all compare
+ * functions look like strncmp.
+ */
+typedef int (*HT_CMP)(const char *, const char *, size_t);
+
+/*
+ * Iterator used with ht_findfirst and ht_findnext to walk through
+ * all the items in a hash table. The iterator should be treated as
+ * an opaque handle. The sequence number in the iterator is used
+ * to maintain consistency with the table on which the iteration
+ * is being performed. If the table sequence number changes, the
+ * iterator becomes invalid.
+ */
+typedef struct ht_iterator {
+ HT_HANDLE *hti_handle;
+ HT_ITEM *hti_item;
+ size_t hti_index;
+ size_t hti_sequence;
+} HT_ITERATOR;
+
+/*
+ * Public API to create and destroy hash tables, to change the hash
+ * function and to find out how many items are in a hash table.
+ */
+extern HT_HANDLE *ht_create_table(size_t table_size, size_t key_size,
+ size_t flags);
+extern void ht_destroy_table(HT_HANDLE *handle);
+extern void ht_set_cmpfn(HT_HANDLE *handle, HT_CMP cmpfn);
+extern size_t ht_get_total_items(HT_HANDLE *handle);
+
+/*
+ * Public API to add, remove, replace or find specific items
+ * in a hash table.
+ */
+extern HT_ITEM *ht_add_item(HT_HANDLE *handle, const char *key,
+ const void *data);
+extern HT_ITEM *ht_replace_item(HT_HANDLE *handle, const char *key,
+ const void *data);
+extern void *ht_remove_item(HT_HANDLE *handle, const char *key);
+extern HT_ITEM *ht_find_item(HT_HANDLE *handle, const char *key);
+
+/*
+ * Public API to iterate over a hash table. A mechanism is provided to
+ * mark items for deletion while searching the table so that the table
+ * is not modified during the search. When the search is complete, all
+ * of the marked items can be deleted by calling ht_clean_table. If
+ * the item data has been dynamically allocated, a callback can be
+ * registered to free the memory. The callback will be invoked with a
+ * pointer to each item as it is removed from the hash table.
+ */
+extern HT_ITEM *ht_findfirst(HT_HANDLE *handle, HT_ITERATOR *iterator);
+extern HT_ITEM *ht_findnext(HT_ITERATOR *iterator);
+extern void ht_mark_delete(HT_HANDLE *handle, HT_ITEM *item);
+extern void ht_clear_delete(HT_HANDLE *handle, HT_ITEM *item);
+extern size_t ht_clean_table(HT_HANDLE *handle);
+extern HT_CALLBACK ht_register_callback(HT_HANDLE *handle,
+ HT_CALLBACK callback);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_HASH_TABLE_H */
diff --git a/usr/src/uts/common/smbsrv/lm.h b/usr/src/uts/common/smbsrv/lm.h
new file mode 100644
index 0000000000..e1cc28c220
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lm.h
@@ -0,0 +1,47 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _SMBSRV_LM_H
+#define _SMBSRV_LM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides global Lan Manager definitions.
+ */
+
+#include <smbsrv/wintypes.h>
+#include <syslog.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LM_H */
diff --git a/usr/src/uts/common/smbsrv/lmdfs.h b/usr/src/uts/common/smbsrv/lmdfs.h
new file mode 100644
index 0000000000..418c4a9ad2
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmdfs.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_LMDFS_H
+#define _SMBSRV_LMDFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * LAN Manager DFS interface definition.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DFS Volume state
+ */
+#define DFS_VOLUME_STATE_OK 1
+#define DFS_VOLUME_STATE_INCONSISTENT 2
+#define DFS_VOLUME_STATE_OFFLINE 3
+#define DFS_VOLUME_STATE_ONLINE 4
+
+/*
+ * DFS Storage state
+ */
+#define DFS_STORAGE_STATE_OFFLINE 1
+#define DFS_STORAGE_STATE_ONLINE 2
+
+/*
+ * Flags:
+ * DFS_ADD_VOLUME: Add a new volume to the DFS if not already there.
+ * DFS_RESTORE_VOLUME: Volume/Replica is being restored - do not verify
+ * share etc.
+ */
+#define DFS_ADD_VOLUME 1
+#define DFS_RESTORE_VOLUME 2
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMDFS_H */
diff --git a/usr/src/uts/common/smbsrv/lmerr.h b/usr/src/uts/common/smbsrv/lmerr.h
new file mode 100644
index 0000000000..13e8843bbc
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmerr.h
@@ -0,0 +1,536 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_LMERR_H
+#define _SMBSRV_LMERR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains the LAN Manager network error definitions. All
+ * network error codes are relative to NERR_BASE (2100), assigned by
+ * Microsoft, to avoid conflicts with system and redirector error
+ * codes. It should be safe to mix NERR error codes with the Win32
+ * error codes defined in nterror.h.
+ *
+ * This file defines error codes in the range 2100 - 2999. NERR values
+ * must not exceed MAX_NERR (2999); values above this are used by other
+ * services.
+ *
+ * The range 2750-2799 has been allocated to the IBM LAN Server.
+ * The range 2900-2999 has been reserved for Microsoft OEMs.
+ *
+ * See lmcons.h for information on the full LANMAN error code range.
+ *
+ * See msdn.microsoft.com for additional information on the meaning
+ * of each error code.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NERR_Success 0
+
+#define NERR_BASE 2100
+
+/* UNUSED BASE+0 */
+/* UNUSED BASE+1 */
+#define NERR_NetNotStarted (NERR_BASE+2)
+#define NERR_UnknownServer (NERR_BASE+3)
+#define NERR_ShareMem (NERR_BASE+4)
+
+#define NERR_NoNetworkResource (NERR_BASE+5)
+#define NERR_RemoteOnly (NERR_BASE+6)
+#define NERR_DevNotRedirected (NERR_BASE+7)
+/* NERR_BASE+8 is used for ERROR_CONNECTED_OTHER_PASSWORD */
+/* UNUSED BASE+9 */
+/* UNUSED BASE+10 */
+/* UNUSED BASE+11 */
+/* UNUSED BASE+12 */
+/* UNUSED BASE+13 */
+#define NERR_ServerNotStarted (NERR_BASE+14)
+#define NERR_ItemNotFound (NERR_BASE+15)
+#define NERR_UnknownDevDir (NERR_BASE+16)
+#define NERR_RedirectedPath (NERR_BASE+17)
+#define NERR_DuplicateShare (NERR_BASE+18)
+#define NERR_NoRoom (NERR_BASE+19)
+/* UNUSED BASE+20 */
+#define NERR_TooManyItems (NERR_BASE+21)
+#define NERR_InvalidMaxUsers (NERR_BASE+22)
+#define NERR_BufTooSmall (NERR_BASE+23)
+/* UNUSED BASE+24 */
+/* UNUSED BASE+25 */
+/* UNUSED BASE+26 */
+#define NERR_RemoteErr (NERR_BASE+27)
+/* UNUSED BASE+28 */
+/* UNUSED BASE+29 */
+/* UNUSED BASE+30 */
+#define NERR_LanmanIniError (NERR_BASE+31)
+/* UNUSED BASE+32 */
+/* UNUSED BASE+33 */
+/* UNUSED BASE+34 */
+/* UNUSED BASE+35 */
+#define NERR_NetworkError (NERR_BASE+36)
+#define NERR_WkstaInconsistentState (NERR_BASE+37)
+#define NERR_WkstaNotStarted (NERR_BASE+38)
+#define NERR_BrowserNotStarted (NERR_BASE+39)
+#define NERR_InternalError (NERR_BASE+40)
+#define NERR_BadTransactConfig (NERR_BASE+41)
+#define NERR_InvalidAPI (NERR_BASE+42)
+#define NERR_BadEventName (NERR_BASE+43)
+#define NERR_DupNameReboot (NERR_BASE+44)
+
+/*
+ * Config API related
+ * Error codes from BASE+45 to BASE+49
+ */
+/* UNUSED BASE+45 */
+#define NERR_CfgCompNotFound (NERR_BASE+46)
+#define NERR_CfgParamNotFound (NERR_BASE+47)
+#define NERR_LineTooLong (NERR_BASE+49)
+
+/*
+ * Spooler API related
+ * Error codes from BASE+50 to BASE+79
+ */
+#define NERR_QNotFound (NERR_BASE+50)
+#define NERR_JobNotFound (NERR_BASE+51)
+#define NERR_DestNotFound (NERR_BASE+52)
+#define NERR_DestExists (NERR_BASE+53)
+#define NERR_QExists (NERR_BASE+54)
+#define NERR_QNoRoom (NERR_BASE+55)
+#define NERR_JobNoRoom (NERR_BASE+56)
+#define NERR_DestNoRoom (NERR_BASE+57)
+#define NERR_DestIdle (NERR_BASE+58)
+#define NERR_DestInvalidOp (NERR_BASE+59)
+#define NERR_ProcNoRespond (NERR_BASE+60)
+#define NERR_SpoolerNotLoaded (NERR_BASE+61)
+#define NERR_DestInvalidState (NERR_BASE+62)
+#define NERR_QInvalidState (NERR_BASE+63)
+#define NERR_JobInvalidState (NERR_BASE+64)
+#define NERR_SpoolNoMemory (NERR_BASE+65)
+#define NERR_DriverNotFound (NERR_BASE+66)
+#define NERR_DataTypeInvalid (NERR_BASE+67)
+#define NERR_ProcNotFound (NERR_BASE+68)
+
+/*
+ * Service API related
+ * Error codes from BASE+80 to BASE+99
+ */
+#define NERR_ServiceTableLocked (NERR_BASE+80)
+#define NERR_ServiceTableFull (NERR_BASE+81)
+#define NERR_ServiceInstalled (NERR_BASE+82)
+#define NERR_ServiceEntryLocked (NERR_BASE+83)
+#define NERR_ServiceNotInstalled (NERR_BASE+84)
+#define NERR_BadServiceName (NERR_BASE+85)
+#define NERR_ServiceCtlTimeout (NERR_BASE+86)
+#define NERR_ServiceCtlBusy (NERR_BASE+87)
+#define NERR_BadServiceProgName (NERR_BASE+88)
+#define NERR_ServiceNotCtrl (NERR_BASE+89)
+#define NERR_ServiceKillProc (NERR_BASE+90)
+#define NERR_ServiceCtlNotValid (NERR_BASE+91)
+#define NERR_NotInDispatchTbl (NERR_BASE+92)
+#define NERR_BadControlRecv (NERR_BASE+93)
+#define NERR_ServiceNotStarting (NERR_BASE+94)
+
+/*
+ * Wksta and Logon API related
+ * Error codes from BASE+100 to BASE+118
+ */
+#define NERR_AlreadyLoggedOn (NERR_BASE+100)
+#define NERR_NotLoggedOn (NERR_BASE+101)
+#define NERR_BadUsername (NERR_BASE+102)
+#define NERR_BadPassword (NERR_BASE+103)
+#define NERR_UnableToAddName_W (NERR_BASE+104)
+#define NERR_UnableToAddName_F (NERR_BASE+105)
+#define NERR_UnableToDelName_W (NERR_BASE+106)
+#define NERR_UnableToDelName_F (NERR_BASE+107)
+/* UNUSED BASE+108 */
+#define NERR_LogonsPaused (NERR_BASE+109)
+#define NERR_LogonServerConflict (NERR_BASE+110)
+#define NERR_LogonNoUserPath (NERR_BASE+111)
+#define NERR_LogonScriptError (NERR_BASE+112)
+/* UNUSED BASE+113 */
+#define NERR_StandaloneLogon (NERR_BASE+114)
+#define NERR_LogonServerNotFound (NERR_BASE+115)
+#define NERR_LogonDomainExists (NERR_BASE+116)
+#define NERR_NonValidatedLogon (NERR_BASE+117)
+
+/*
+ * ACF API related (access, user, group)
+ * Error codes from BASE+119 to BASE+149
+ */
+#define NERR_ACFNotFound (NERR_BASE+119)
+#define NERR_GroupNotFound (NERR_BASE+120)
+#define NERR_UserNotFound (NERR_BASE+121)
+#define NERR_ResourceNotFound (NERR_BASE+122)
+#define NERR_GroupExists (NERR_BASE+123)
+#define NERR_UserExists (NERR_BASE+124)
+#define NERR_ResourceExists (NERR_BASE+125)
+#define NERR_NotPrimary (NERR_BASE+126)
+#define NERR_ACFNotLoaded (NERR_BASE+127)
+#define NERR_ACFNoRoom (NERR_BASE+128)
+#define NERR_ACFFileIOFail (NERR_BASE+129)
+#define NERR_ACFTooManyLists (NERR_BASE+130)
+#define NERR_UserLogon (NERR_BASE+131)
+#define NERR_ACFNoParent (NERR_BASE+132)
+#define NERR_CanNotGrowSegment (NERR_BASE+133)
+#define NERR_SpeGroupOp (NERR_BASE+134)
+#define NERR_NotInCache (NERR_BASE+135)
+#define NERR_UserInGroup (NERR_BASE+136)
+#define NERR_UserNotInGroup (NERR_BASE+137)
+#define NERR_AccountUndefined (NERR_BASE+138)
+#define NERR_AccountExpired (NERR_BASE+139)
+#define NERR_InvalidWorkstation (NERR_BASE+140)
+#define NERR_InvalidLogonHours (NERR_BASE+141)
+#define NERR_PasswordExpired (NERR_BASE+142)
+#define NERR_PasswordCantChange (NERR_BASE+143)
+#define NERR_PasswordHistConflict (NERR_BASE+144)
+#define NERR_PasswordTooShort (NERR_BASE+145)
+#define NERR_PasswordTooRecent (NERR_BASE+146)
+#define NERR_InvalidDatabase (NERR_BASE+147)
+#define NERR_DatabaseUpToDate (NERR_BASE+148)
+#define NERR_SyncRequired (NERR_BASE+149)
+
+/*
+ * Use API related
+ * Error codes from BASE+150 to BASE+169
+ */
+#define NERR_UseNotFound (NERR_BASE+150)
+#define NERR_BadAsgType (NERR_BASE+151)
+#define NERR_DeviceIsShared (NERR_BASE+152)
+
+/*
+ * Message Server related
+ * Error codes BASE+170 to BASE+209
+ */
+#define NERR_NoComputerName (NERR_BASE+170)
+#define NERR_MsgAlreadyStarted (NERR_BASE+171)
+#define NERR_MsgInitFailed (NERR_BASE+172)
+#define NERR_NameNotFound (NERR_BASE+173)
+#define NERR_AlreadyForwarded (NERR_BASE+174)
+#define NERR_AddForwarded (NERR_BASE+175)
+#define NERR_AlreadyExists (NERR_BASE+176)
+#define NERR_TooManyNames (NERR_BASE+177)
+#define NERR_DelComputerName (NERR_BASE+178)
+#define NERR_LocalForward (NERR_BASE+179)
+#define NERR_GrpMsgProcessor (NERR_BASE+180)
+#define NERR_PausedRemote (NERR_BASE+181)
+#define NERR_BadReceive (NERR_BASE+182)
+#define NERR_NameInUse (NERR_BASE+183)
+#define NERR_MsgNotStarted (NERR_BASE+184)
+#define NERR_NotLocalName (NERR_BASE+185)
+#define NERR_NoForwardName (NERR_BASE+186)
+#define NERR_RemoteFull (NERR_BASE+187)
+#define NERR_NameNotForwarded (NERR_BASE+188)
+#define NERR_TruncatedBroadcast (NERR_BASE+189)
+#define NERR_InvalidDevice (NERR_BASE+194)
+#define NERR_WriteFault (NERR_BASE+195)
+/* UNUSED BASE+196 */
+#define NERR_DuplicateName (NERR_BASE+197)
+#define NERR_DeleteLater (NERR_BASE+198)
+#define NERR_IncompleteDel (NERR_BASE+199)
+#define NERR_MultipleNets (NERR_BASE+200)
+
+/*
+ * Server API related
+ * Error codes BASE+210 to BASE+229
+ */
+#define NERR_NetNameNotFound (NERR_BASE+210)
+#define NERR_DeviceNotShared (NERR_BASE+211)
+#define NERR_ClientNameNotFound (NERR_BASE+212)
+#define NERR_FileIdNotFound (NERR_BASE+214)
+#define NERR_ExecFailure (NERR_BASE+215)
+#define NERR_TmpFile (NERR_BASE+216)
+#define NERR_TooMuchData (NERR_BASE+217)
+#define NERR_DeviceShareConflict (NERR_BASE+218)
+#define NERR_BrowserTableIncomplete (NERR_BASE+219)
+#define NERR_NotLocalDomain (NERR_BASE+220)
+#define NERR_IsDfsShare (NERR_BASE+221)
+
+/*
+ * CharDev API related
+ * Error codes BASE+230 to BASE+249
+ */
+/* UNUSED BASE+230 */
+#define NERR_DevInvalidOpCode (NERR_BASE+231)
+#define NERR_DevNotFound (NERR_BASE+232)
+#define NERR_DevNotOpen (NERR_BASE+233)
+#define NERR_BadQueueDevString (NERR_BASE+234)
+#define NERR_BadQueuePriority (NERR_BASE+235)
+#define NERR_NoCommDevs (NERR_BASE+237)
+#define NERR_QueueNotFound (NERR_BASE+238)
+#define NERR_BadDevString (NERR_BASE+240)
+#define NERR_BadDev (NERR_BASE+241)
+#define NERR_InUseBySpooler (NERR_BASE+242)
+#define NERR_CommDevInUse (NERR_BASE+243)
+
+/*
+ * NetICanonicalize and NetIType and NetIMakeLMFileName
+ * NetIListCanon and NetINameCheck
+ * Error codes BASE+250 to BASE+269
+ */
+#define NERR_InvalidComputer (NERR_BASE+251)
+/* UNUSED BASE+252 */
+/* UNUSED BASE+253 */
+#define NERR_MaxLenExceeded (NERR_BASE+254)
+/* UNUSED BASE+255 */
+#define NERR_BadComponent (NERR_BASE+256)
+#define NERR_CantType (NERR_BASE+257)
+/* UNUSED BASE+258 */
+/* UNUSED BASE+259 */
+#define NERR_TooManyEntries (NERR_BASE+262)
+
+/*
+ * NetProfile
+ * Error codes BASE+270 to BASE+276
+ */
+#define NERR_ProfileFileTooBig (NERR_BASE+270)
+#define NERR_ProfileOffset (NERR_BASE+271)
+#define NERR_ProfileCleanup (NERR_BASE+272)
+#define NERR_ProfileUnknownCmd (NERR_BASE+273)
+#define NERR_ProfileLoadErr (NERR_BASE+274)
+#define NERR_ProfileSaveErr (NERR_BASE+275)
+
+/*
+ * NetAudit and NetErrorLog
+ * Error codes BASE+277 to BASE+279
+ */
+#define NERR_LogOverflow (NERR_BASE+277)
+#define NERR_LogFileChanged (NERR_BASE+278)
+#define NERR_LogFileCorrupt (NERR_BASE+279)
+
+/*
+ * NetRemote
+ * Error codes BASE+280 to BASE+299
+ */
+#define NERR_SourceIsDir (NERR_BASE+280)
+#define NERR_BadSource (NERR_BASE+281)
+#define NERR_BadDest (NERR_BASE+282)
+#define NERR_DifferentServers (NERR_BASE+283)
+/* UNUSED BASE+284 */
+#define NERR_RunSrvPaused (NERR_BASE+285)
+/* UNUSED BASE+286 */
+/* UNUSED BASE+287 */
+/* UNUSED BASE+288 */
+#define NERR_ErrCommRunSrv (NERR_BASE+289)
+/* UNUSED BASE+290 */
+#define NERR_ErrorExecingGhost (NERR_BASE+291)
+#define NERR_ShareNotFound (NERR_BASE+292)
+/* UNUSED BASE+293 */
+/* UNUSED BASE+294 */
+
+
+/*
+ * NetWksta.sys (redir) returned error codes.
+ * NERR_BASE + (300-329)
+ */
+#define NERR_InvalidLana (NERR_BASE+300)
+#define NERR_OpenFiles (NERR_BASE+301)
+#define NERR_ActiveConns (NERR_BASE+302)
+#define NERR_BadPasswordCore (NERR_BASE+303)
+#define NERR_DevInUse (NERR_BASE+304)
+#define NERR_LocalDrive (NERR_BASE+305)
+
+/*
+ * Alert error codes.
+ * NERR_BASE + (330-339)
+ */
+#define NERR_AlertExists (NERR_BASE+330)
+#define NERR_TooManyAlerts (NERR_BASE+331)
+#define NERR_NoSuchAlert (NERR_BASE+332)
+#define NERR_BadRecipient (NERR_BASE+333)
+#define NERR_AcctLimitExceeded (NERR_BASE+334)
+
+/*
+ * Additional Error and Audit log codes.
+ * NERR_BASE +(340-343)
+ */
+#define NERR_InvalidLogSeek (NERR_BASE+340)
+/* UNUSED BASE+341 */
+/* UNUSED BASE+342 */
+/* UNUSED BASE+343 */
+
+/*
+ * Additional UAS and NETLOGON codes
+ * NERR_BASE +(350-359)
+ */
+#define NERR_BadUasConfig (NERR_BASE+350)
+#define NERR_InvalidUASOp (NERR_BASE+351)
+#define NERR_LastAdmin (NERR_BASE+352)
+#define NERR_DCNotFound (NERR_BASE+353)
+#define NERR_LogonTrackingError (NERR_BASE+354)
+#define NERR_NetlogonNotStarted (NERR_BASE+355)
+#define NERR_CanNotGrowUASFile (NERR_BASE+356)
+#define NERR_TimeDiffAtDC (NERR_BASE+357)
+#define NERR_PasswordMismatch (NERR_BASE+358)
+
+/*
+ * Server Integration error codes.
+ * NERR_BASE +(360-369)
+ */
+#define NERR_NoSuchServer (NERR_BASE+360)
+#define NERR_NoSuchSession (NERR_BASE+361)
+#define NERR_NoSuchConnection (NERR_BASE+362)
+#define NERR_TooManyServers (NERR_BASE+363)
+#define NERR_TooManySessions (NERR_BASE+364)
+#define NERR_TooManyConnections (NERR_BASE+365)
+#define NERR_TooManyFiles (NERR_BASE+366)
+#define NERR_NoAlternateServers (NERR_BASE+367)
+/* UNUSED BASE+368 */
+/* UNUSED BASE+369 */
+#define NERR_TryDownLevel (NERR_BASE+370)
+
+/*
+ * UPS error codes.
+ * NERR_BASE + (380-384)
+ */
+#define NERR_UPSDriverNotStarted (NERR_BASE+380)
+#define NERR_UPSInvalidConfig (NERR_BASE+381)
+#define NERR_UPSInvalidCommPort (NERR_BASE+382)
+#define NERR_UPSSignalAsserted (NERR_BASE+383)
+#define NERR_UPSShutdownFailed (NERR_BASE+384)
+
+/*
+ * Remoteboot error codes.
+ * NERR_BASE + (400-419)
+ * Error codes 400 - 405 are used by RPLBOOT.SYS.
+ * Error codes 403, 407 - 416 are used by RPLLOADR.COM,
+ * Error code 417 is the alerter message of REMOTEBOOT (RPLSERVR.EXE).
+ * Error code 418 is for when REMOTEBOOT can't start
+ * Error code 419 is for a disallowed 2nd rpl connection
+ */
+#define NERR_BadDosRetCode (NERR_BASE+400)
+#define NERR_ProgNeedsExtraMem (NERR_BASE+401)
+#define NERR_BadDosFunction (NERR_BASE+402)
+#define NERR_RemoteBootFailed (NERR_BASE+403)
+#define NERR_BadFileCheckSum (NERR_BASE+404)
+#define NERR_NoRplBootSystem (NERR_BASE+405)
+#define NERR_RplLoadrNetBiosErr (NERR_BASE+406)
+#define NERR_RplLoadrDiskErr (NERR_BASE+407)
+#define NERR_ImageParamErr (NERR_BASE+408)
+#define NERR_TooManyImageParams (NERR_BASE+409)
+#define NERR_NonDosFloppyUsed (NERR_BASE+410)
+#define NERR_RplBootRestart (NERR_BASE+411)
+#define NERR_RplSrvrCallFailed (NERR_BASE+412)
+#define NERR_CantConnectRplSrvr (NERR_BASE+413)
+#define NERR_CantOpenImageFile (NERR_BASE+414)
+#define NERR_CallingRplSrvr (NERR_BASE+415)
+#define NERR_StartingRplBoot (NERR_BASE+416)
+#define NERR_RplBootServiceTerm (NERR_BASE+417)
+#define NERR_RplBootStartFailed (NERR_BASE+418)
+#define NERR_RPL_CONNECTED (NERR_BASE+419)
+
+/*
+ * FTADMIN API error codes
+ * NERR_BASE + (425-434)
+ * (Currently not used in NT)
+ */
+
+/*
+ * Browser service API error codes
+ * NERR_BASE + (450-475)
+ */
+#define NERR_BrowserConfiguredToNotRun (NERR_BASE+450)
+
+/*
+ * Additional Remoteboot error codes.
+ * NERR_BASE + (510-550)
+ */
+#define NERR_RplNoAdaptersStarted (NERR_BASE+510)
+#define NERR_RplBadRegistry (NERR_BASE+511)
+#define NERR_RplBadDatabase (NERR_BASE+512)
+#define NERR_RplRplfilesShare (NERR_BASE+513)
+#define NERR_RplNotRplServer (NERR_BASE+514)
+#define NERR_RplCannotEnum (NERR_BASE+515)
+#define NERR_RplWkstaInfoCorrupted (NERR_BASE+516)
+#define NERR_RplWkstaNotFound (NERR_BASE+517)
+#define NERR_RplWkstaNameUnavailable (NERR_BASE+518)
+#define NERR_RplProfileInfoCorrupted (NERR_BASE+519)
+#define NERR_RplProfileNotFound (NERR_BASE+520)
+#define NERR_RplProfileNameUnavailable (NERR_BASE+521)
+#define NERR_RplProfileNotEmpty (NERR_BASE+522)
+#define NERR_RplConfigInfoCorrupted (NERR_BASE+523)
+#define NERR_RplConfigNotFound (NERR_BASE+524)
+#define NERR_RplAdapterInfoCorrupted (NERR_BASE+525)
+#define NERR_RplInternal (NERR_BASE+526)
+#define NERR_RplVendorInfoCorrupted (NERR_BASE+527)
+#define NERR_RplBootInfoCorrupted (NERR_BASE+528)
+#define NERR_RplWkstaNeedsUserAcct (NERR_BASE+529)
+#define NERR_RplNeedsRPLUSERAcct (NERR_BASE+530)
+#define NERR_RplBootNotFound (NERR_BASE+531)
+#define NERR_RplIncompatibleProfile (NERR_BASE+532)
+#define NERR_RplAdapterNameUnavailable (NERR_BASE+533)
+#define NERR_RplConfigNotEmpty (NERR_BASE+534)
+#define NERR_RplBootInUse (NERR_BASE+535)
+#define NERR_RplBackupDatabase (NERR_BASE+536)
+#define NERR_RplAdapterNotFound (NERR_BASE+537)
+#define NERR_RplVendorNotFound (NERR_BASE+538)
+#define NERR_RplVendorNameUnavailable (NERR_BASE+539)
+#define NERR_RplBootNameUnavailable (NERR_BASE+540)
+#define NERR_RplConfigNameUnavailable (NERR_BASE+541)
+
+/*
+ * Dfs API error codes.
+ * NERR_BASE + (560-590)
+ */
+#define NERR_DfsInternalCorruption (NERR_BASE+560)
+#define NERR_DfsVolumeDataCorrupt (NERR_BASE+561)
+#define NERR_DfsNoSuchVolume (NERR_BASE+562)
+#define NERR_DfsVolumeAlreadyExists (NERR_BASE+563)
+#define NERR_DfsAlreadyShared (NERR_BASE+564)
+#define NERR_DfsNoSuchShare (NERR_BASE+565)
+#define NERR_DfsNotALeafVolume (NERR_BASE+566)
+#define NERR_DfsLeafVolume (NERR_BASE+567)
+#define NERR_DfsVolumeHasMultipleServers (NERR_BASE+568)
+#define NERR_DfsCantCreateJunctionPoint (NERR_BASE+569)
+#define NERR_DfsServerNotDfsAware (NERR_BASE+570)
+#define NERR_DfsBadRenamePath (NERR_BASE+571)
+#define NERR_DfsVolumeIsOffline (NERR_BASE+572)
+#define NERR_DfsNoSuchServer (NERR_BASE+573)
+#define NERR_DfsCyclicalName (NERR_BASE+574)
+#define NERR_DfsNotSupportedInServerDfs (NERR_BASE+575)
+#define NERR_DfsInternalError (NERR_BASE+590)
+
+/*
+ * Net setup error codes.
+ * NERR_BASE + (591-595)
+ */
+#define NERR_SetupAlreadyJoined (NERR_BASE+591)
+#define NERR_SetupNotJoined (NERR_BASE+592)
+#define NERR_SetupDomainController (NERR_BASE+593)
+
+/*
+ * MAX_NERR is the last value in the NERR range.
+ * Do not exceed this value here.
+ */
+#define MAX_NERR (NERR_BASE+899)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMERR_H */
diff --git a/usr/src/uts/common/smbsrv/lmshare.h b/usr/src/uts/common/smbsrv/lmshare.h
new file mode 100644
index 0000000000..db41a5bdee
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmshare.h
@@ -0,0 +1,195 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_LMSHARE_H
+#define _SMBSRV_LMSHARE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the LanMan (CIFS/SMB) resource share interface.
+ */
+
+#include <sys/param.h>
+#include <smbsrv/string.h>
+#include <smbsrv/hash_table.h>
+#include <smbsrv/smb_fsd.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/lmerr.h>
+
+#ifndef _KERNEL
+#include <libshare.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SHOPT_AD_CONTAINER "ad-container"
+#define SHOPT_NAME "name" /* name is a pseudo property */
+
+#define SMB_DEFAULT_SHARE_GROUP "smb"
+#define SMB_PROTOCOL_NAME "smb"
+
+/*
+ * Despite the fact that the MAXNAMELEN is 256, we only
+ * support a maximum share name length of 15 characters.
+ */
+#define LMSHR_VALID_NAME_MAX 15
+#define LMSHR_VALID_NAME_BUFSIZ 16
+#define LMSHR_COMMENT_MAX (64 * MTS_MB_CHAR_MAX)
+
+/*
+ * Mode should be renamed to flags.
+ *
+ * LMSHRM_TRANS Transient share
+ * LMSHRM_PERM Permanent share
+ */
+#define LMSHRM_TRANS 0x0001
+#define LMSHRM_PERM 0x0002
+#define LMSHRM_ALL (LMSHRM_TRANS | LMSHRM_PERM)
+
+#define LMSHR_PUBLISH 0
+#define LMSHR_UNPUBLISH 1
+
+#define LMSHR_ADD 0
+#define LMSHR_DELETE 1
+
+
+/*
+ * refcnt is currently only used for autohome. autohome needs a refcnt
+ * because a user can map his autohome share from more than one client
+ * at the same time and the share should only be removed when the last
+ * one is disconnected
+ */
+typedef struct lmshare_info {
+ char share_name[MAXNAMELEN];
+ char directory[MAXPATHLEN];
+ char comment[LMSHR_COMMENT_MAX];
+ char container[MAXPATHLEN];
+ int mode;
+ int stype;
+ int refcnt;
+} lmshare_info_t;
+
+typedef struct lmshare_iterator {
+ lmshare_info_t si;
+ HT_ITERATOR *iterator;
+ unsigned int iteration;
+ int mode;
+} lmshare_iterator_t;
+
+#define LMSHARES_PER_REQUEST 10
+typedef struct lmshare_list {
+ int no;
+ lmshare_info_t smbshr[LMSHARES_PER_REQUEST];
+} lmshare_list_t;
+
+
+#ifndef _KERNEL
+/*
+ * CIFS share management functions (private to the smb daemon).
+ */
+extern int lmshare_start(void);
+extern void lmshare_stop(void);
+extern lmshare_iterator_t *lmshare_open_iterator(int mode);
+extern void lmshare_close_iterator(lmshare_iterator_t *iterator);
+extern lmshare_info_t *lmshare_iterate(lmshare_iterator_t *iterator);
+
+extern DWORD lmshare_list(int offset, lmshare_list_t *list);
+extern DWORD lmshare_list_transient(int offset, lmshare_list_t *list);
+extern int lmshare_num_transient(void);
+
+extern int lmshare_num_shares(void);
+extern DWORD lmshare_add(lmshare_info_t *si, int);
+extern DWORD lmshare_delete(char *share_name, int);
+extern DWORD lmshare_rename(char *from, char *to, int);
+extern DWORD lmshare_getinfo(char *share_name, lmshare_info_t *si);
+extern DWORD lmshare_setinfo(lmshare_info_t *si, int);
+extern DWORD lmshare_get_realpath(const char *srcbuf, char *dstbuf, int maxlen);
+extern void lmshare_do_publish(lmshare_info_t *, char, int);
+
+extern int lmshare_exists(char *share_name);
+extern int lmshare_is_special(char *share_name);
+extern int lmshare_is_restricted(char *share_name);
+extern int lmshare_is_admin(char *share_name);
+extern int lmshare_is_valid(char *share_name);
+extern int lmshare_is_dir(char *path);
+/* XXX Move these 2 functions in mlsvc_util.h, after the libmlsvc cleanup */
+extern sa_group_t smb_get_smb_share_group(sa_handle_t handle);
+extern void smb_build_lmshare_info(char *share_name, char *path,
+ sa_optionset_t opts, lmshare_info_t *si);
+
+/* The following 3 functions are called by FSD user-space library */
+extern DWORD lmshare_add_adminshare(char *volname, unsigned char drive);
+
+#endif /* _KERNEL */
+
+/*
+ * LanMan share API (for both SMB kernel module and GUI/CLI sub-system)
+ *
+ * NOTE: If any error is encounted by either the door server or client,
+ * NERR_InternalError will be returned by most functions.
+ * lmshrd_num_shares will return -1 while the lmshrd_open_iterator/
+ * lmshrd_close_iterator will return NULL.
+ */
+
+extern uint64_t lmshrd_open_iterator(int mode);
+extern DWORD lmshrd_close_iterator(uint64_t iterator);
+extern DWORD lmshrd_iterate(uint64_t iterator, lmshare_info_t *si);
+#ifndef _KERNEL
+extern DWORD lmshrd_list(int offset, lmshare_list_t *list);
+extern DWORD lmshrd_list_transient(int offset, lmshare_list_t *list);
+extern DWORD lmshrd_num_transient(void);
+extern int lmshrd_dump_hash(char *logfname);
+#endif
+extern int lmshrd_num_shares(void);
+extern DWORD lmshrd_delete(char *share_name);
+extern DWORD lmshrd_rename(char *from, char *to);
+extern DWORD lmshrd_getinfo(char *share_name, lmshare_info_t *si);
+extern DWORD lmshrd_add(lmshare_info_t *si);
+extern DWORD lmshrd_setinfo(lmshare_info_t *si);
+
+extern int lmshrd_exists(char *share_name);
+extern int lmshrd_is_special(char *share_name);
+extern int lmshrd_is_restricted(char *share_name);
+extern int lmshrd_is_admin(char *share_name);
+extern int lmshrd_is_valid(char *share_name);
+extern int lmshrd_is_dir(char *path);
+
+/*
+ * The SMB kernel module must invoke the following functions to start/stop
+ * the LanMan share door client.
+ */
+#ifdef _KERNEL
+extern int lmshrd_kclient_start(void);
+extern void lmshrd_kclient_stop(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMSHARE_H */
diff --git a/usr/src/uts/common/smbsrv/lmshare_door.h b/usr/src/uts/common/smbsrv/lmshare_door.h
new file mode 100644
index 0000000000..c1c6f2ba0c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lmshare_door.h
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_LMSHARE_DOOR_H
+#define _SMBSRV_LMSHARE_DOOR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_common_door.h>
+#include <smbsrv/smbinfo.h>
+
+/*
+ * Door interface for CIFS share management.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LMSHR_DOOR_NAME "/var/run/smb_lmshare_door"
+#define LMSHR_DOOR_VERSION 1
+
+#define LMSHR_DOOR_COOKIE ((void*)(0xdeadbeef^LMSHR_DOOR_VERSION))
+#define LMSHR_DOOR_SIZE (sizeof (lmshare_list_t) + 32)
+
+/*
+ * Door interface
+ *
+ * Define door operations
+ */
+#define LMSHR_DOOR_OPEN_ITERATOR 1
+#define LMSHR_DOOR_CLOSE_ITERATOR 2
+#define LMSHR_DOOR_ITERATE 3
+#define LMSHR_DOOR_NUM_SHARES 4
+#define LMSHR_DOOR_DELETE 5
+#define LMSHR_DOOR_RENAME 6
+#define LMSHR_DOOR_GETINFO 7
+#define LMSHR_DOOR_ADD 8
+#define LMSHR_DOOR_SETINFO 9
+#define LMSHR_DOOR_EXISTS 10
+#define LMSHR_DOOR_IS_SPECIAL 11
+#define LMSHR_DOOR_IS_RESTRICTED 12
+#define LMSHR_DOOR_IS_ADMIN 13
+#define LMSHR_DOOR_IS_VALID 14
+#define LMSHR_DOOR_IS_DIR 15
+#define LMSHR_DOOR_LIST 16
+
+#define SMB_GET_KCONFIG 17
+
+void smb_load_kconfig(smb_kmod_cfg_t *cfg);
+void smb_dr_get_kconfig(smb_dr_ctx_t *ctx, smb_kmod_cfg_t *cfg);
+void smb_dr_put_kconfig(smb_dr_ctx_t *ctx, smb_kmod_cfg_t *cfg);
+
+/*
+ * Door server status
+ *
+ * LMSHR_DOOR_ERROR is returned by the door server if there is problem
+ * with marshalling/unmarshalling. Otherwise, LMSHR_DOOR_SUCCESS is
+ * returned.
+ *
+ */
+#define LMSHR_DOOR_SRV_SUCCESS 0
+#define LMSHR_DOOR_SRV_ERROR -1
+
+/*
+ * struct door_request {
+ * int req_type;
+ * <parameters>
+ * };
+ *
+ * struct door_response {
+ * int door_srv_status;
+ * <response>
+ * };
+ */
+
+void smb_dr_get_lmshare(smb_dr_ctx_t *ctx, lmshare_info_t *si);
+void smb_dr_put_lmshare(smb_dr_ctx_t *ctx, lmshare_info_t *si);
+
+uint64_t smb_dr_get_lmshr_iterator(smb_dr_ctx_t *ctx);
+void smb_dr_put_lmshr_iterator(smb_dr_ctx_t *ctx,
+ uint64_t lmshr_iter);
+void smb_dr_free_lmshr_iterator(smb_dr_ctx_t *ctx);
+void smb_dr_get_lmshr_list(smb_dr_ctx_t *ctx,
+ lmshare_list_t *shrlist);
+void smb_dr_put_lmshr_list(smb_dr_ctx_t *ctx,
+ lmshare_list_t *shrlist);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_LMSHARE_DOOR_H */
diff --git a/usr/src/uts/common/smbsrv/lsalib.h b/usr/src/uts/common/smbsrv/lsalib.h
new file mode 100644
index 0000000000..b8566bf342
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/lsalib.h
@@ -0,0 +1,164 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_LSALIB_H
+#define _SMBSRV_LSALIB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Prototypes for the LSA library and RPC client side library interface.
+ * There are two levels of interface defined here: lsa_xxx and lsar_xxx.
+ * The lsa_xxx functions provide a high level interface which make
+ * multiple RPC calls and do all the work necessary to obtain and return
+ * the requested information. The lsar_xxx functions provide a low level
+ * interface in which each function maps to a single underlying RPC.
+ */
+
+#include <smbsrv/ndl/lsarpc.ndl>
+#include <smbsrv/mlsvc_util.h>
+#include <smbsrv/ntsid.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * lsalib.c
+ */
+int lsa_lookup_builtin_name(char *account_name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_local_sam(char *domain,
+ char *account_name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_local(char *name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_name(char *server,
+ char *domain,
+ char *account_name,
+ smb_userinfo_t *user_info);
+
+DWORD lsa_lookup_name2(char *server,
+ char *domain,
+ char *account_name,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_sid(nt_sid_t *sid,
+ smb_userinfo_t *user_info);
+
+DWORD lsa_lookup_sid2(nt_sid_t *sid,
+ smb_userinfo_t *user_info);
+
+int lsa_lookup_privs(char *server,
+ char *account_name,
+ char *target_name,
+ smb_userinfo_t *user_info);
+
+int lsa_test(char *server, char *account_name);
+
+
+/*
+ * lsar_open.c
+ */
+int lsar_open(int ipc_mode,
+ char *server,
+ char *domain,
+ char *username,
+ char *password,
+ mlsvc_handle_t *domain_handle);
+
+int lsar_open_policy2(char *server,
+ char *domain,
+ char *username,
+ mlsvc_handle_t *lsa_handle);
+
+int lsar_open_account(mlsvc_handle_t *lsa_handle,
+ struct mslsa_sid *sid,
+ mlsvc_handle_t *lsa_account_handle);
+
+int lsar_close(mlsvc_handle_t *lsa_handle);
+
+
+/*
+ * lsar_lookup.c
+ */
+int lsar_query_security_desc(mlsvc_handle_t *lsa_handle);
+
+DWORD lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass);
+
+int lsar_lookup_names(mlsvc_handle_t *lsa_handle,
+ char *name,
+ smb_userinfo_t *user_info);
+
+int lsar_lookup_sids(mlsvc_handle_t *lsa_handle,
+ struct mslsa_sid *sid,
+ smb_userinfo_t *user_info);
+
+DWORD lsar_get_userid(char *server, char *name);
+
+int lsar_enum_accounts(mlsvc_handle_t *lsa_handle,
+ DWORD *enum_context,
+ struct mslsa_EnumAccountBuf *accounts);
+
+DWORD lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle,
+ DWORD *enum_context);
+
+int lsar_enum_privs_account(mlsvc_handle_t *account_handle,
+ smb_userinfo_t *user_info);
+
+int lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle,
+ char *name,
+ struct ms_luid *luid);
+
+int lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle,
+ struct ms_luid *luid,
+ char *name,
+ int namelen);
+
+DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle,
+ char *name,
+ char *display_name,
+ int display_len);
+
+DWORD lsar_lookup_sids2(mlsvc_handle_t *lsa_handle,
+ struct mslsa_sid *sid,
+ smb_userinfo_t *user_info);
+
+DWORD lsar_lookup_names2(mlsvc_handle_t *lsa_handle,
+ char *name,
+ smb_userinfo_t *user_info);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_LSALIB_H */
diff --git a/usr/src/uts/common/smbsrv/mac_cifs.h b/usr/src/uts/common/smbsrv/mac_cifs.h
new file mode 100644
index 0000000000..26f0451958
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mac_cifs.h
@@ -0,0 +1,112 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MAC_CIFS_H
+#define _SMBSRV_MAC_CIFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions for the Macintosh Extensions for CIFS
+ * interface (see http://www.thursby.com/cifs).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Macintosh information level extensions. The entire list is presented
+ * here for convenience but for consistency with the existing CIFS
+ * information levels don't use these values directly. Use the SMB_MAC_
+ * definitions in cifs.h.
+ *
+ * SmbTrans2QueryFsInformation: MAC_QUERY_FS_INFO
+ * SmbTrans2Find{First|Next}2: MAC_FIND_BOTH_HFS_INFO
+ * SmbTrans2SetPathInformation: MAC_SET_FINDER_INFO
+ * SmbTrans2QueryPathInformation: MAC_DT_{ADD|REMOVE|GET}_{APPL|ICON}
+ */
+#define MAC_QUERY_FS_INFO 0x301
+#define MAC_FIND_BOTH_HFS_INFO 0x302
+#define MAC_SET_FINDER_INFO 0x303
+#define MAC_DT_ADD_APPL 0x304
+#define MAC_DT_REMOVE_APPL 0x305
+#define MAC_DT_GET_APPL 0x306
+#define MAC_DT_GET_ICON 0x307
+#define MAC_DT_GET_ICON_INFO 0x308
+#define MAC_DT_ADD_ICON 0x309
+
+
+/*
+ * Macintosh extensions support bits. Returned by the server in response
+ * to a TRANS2_QUERY_FS_INFORMATION request when the information level
+ * is MAC_QUERY_FS_INFO.
+ */
+#define MAC_SUPPORT_ACCESS_CONTROL 0x0010
+#define MAC_SUPPORT_GETSETCOMMENTS 0x0020
+#define MAC_SUPPORT_DESKTOPDB_CALLS 0x0040
+#define MAC_SUPPORT_UNIQUE_IDS 0x0080
+#define MAC_SUPPORT_NO_STREAMS 0x0100
+
+
+/*
+ * The MAC_ACCESS values are returned from the MAC_FIND_BOTH_HFS_INFO
+ * info level of TRANS2_FIND. Set SUPPORT_MAC_ACCESS_CNTRL to enable
+ * support.
+ *
+ * The MAC_OWNER bit indicates that the user is the owner of the file
+ * or directory.
+ */
+#define MAC_ACCESS_OWNER 0x0800
+#define MAC_ACCESS_OWNER_READ 0x0400
+#define MAC_ACCESS_OWNER_WRITE 0x0200
+#define MAC_ACCESS_OWNER_SEARCH 0x0100
+#define MAC_ACCESS_GROUP_READ 0x0040
+#define MAC_ACCESS_GROUP_WRITE 0x0020
+#define MAC_ACCESS_GROUP_SEARCH 0x0010
+#define MAC_ACCESS_OTHER_READ 0x0004
+#define MAC_ACCESS_OTHER_WRITE 0x0002
+#define MAC_ACCESS_OTHER_SEARCH 0x0001
+
+
+/*
+ * The MAC_FINDER values support the SMB_MAC_SET_FINDER_INFO info level
+ * of TRANS2_SET_PATH_INFORMATION.
+ */
+#define MAC_FINDER_SET_CREATE_DATE 0x0001
+#define MAC_FINDER_SET_MODE_DATE 0x0002
+#define MAC_FINDER_SET_FL_ATTRIB 0x0004
+#define MAC_FINDER_SET_INFO1 0x0008
+#define MAC_FINDER_SET_INFO2 0x0010
+#define MAC_FINDER_SET_HIDDEN 0x0020
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_MAC_CIFS_H */
diff --git a/usr/src/uts/common/smbsrv/mailslot.h b/usr/src/uts/common/smbsrv/mailslot.h
new file mode 100644
index 0000000000..35f2e74552
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mailslot.h
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MAILSLOT_H
+#define _SMBSRV_MAILSLOT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Mailslots are a one-way, unreliable IPC mechanism that allows a
+ * client to send or broadcast messages to a server. The names follow
+ * the same universal naming convention (UNC) used with named pipes:
+ * \\server\mailslot\name, \\.\mailslot\name etc. There is a good
+ * overview of mailslots, including limitations of NT and Windows 2000,
+ * in Network Programming for Microsoft Windows Chapter 3.
+ *
+ * Network Programming for Microsoft Windows
+ * Anthony Jones and Jim Ohlund
+ * Microsoft Press, ISBN 0-7356-0560-2
+ *
+ * This file defines pre-defined and system common mailslots.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Well-known or pre-defined mailslots.
+ */
+#define MAILSLOT_LANMAN "\\MAILSLOT\\LANMAN"
+#define MAILSLOT_MSBROWSE "\\MAILSLOT\\MSBROWSE"
+#define MAILSLOT_BROWSE "\\MAILSLOT\\BROWSE"
+#define MAILSLOT_NETLOGON "\\MAILSLOT\\NET\\NETLOGON"
+#define MAILSLOT_NTLOGON "\\MAILSLOT\\NET\\NTLOGON"
+
+
+/*
+ * System common mailslots. These should be dynamically assigned
+ * at runtime but we don't support a full mailslot implementation
+ * so we use a set of predefined values that appear to work.
+ */
+#define MAILSLOT_NETLOGON_RDC "\\MAILSLOT\\NET\\GETDC354"
+#define MAILSLOT_NETLOGON_MDC "\\MAILSLOT\\NET\\GETDC576"
+#define MAILSLOT_NETLOGON_SAMLOGON_RDC "\\MAILSLOT\\NET\\GETDC873"
+#define MAILSLOT_NETLOGON_SAMLOGON_MDC "\\MAILSLOT\\NET\\GETDC875"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_MAILSLOT_H */
diff --git a/usr/src/uts/common/smbsrv/mbuf.h b/usr/src/uts/common/smbsrv/mbuf.h
new file mode 100644
index 0000000000..51a6bea6e8
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mbuf.h
@@ -0,0 +1,269 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SMBSRV_MBUF_H
+#define _SMBSRV_MBUF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * PBSHORTCUT This file should be removed from the PB port but is required
+ * for now to get it to compile. This file has also been modified.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/alloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MSIZE 256
+#define MCLBYTES 2048
+#define MCLSHIFT 11
+#define MCLOFSET (MCLBYTES - 1)
+
+#define NBPG 4096
+#define CLBYTES NBPG
+#define PB_PAGESIZE 4096
+
+/*
+ * Mbufs are of a single size, MSIZE (machine/machparam.h), which
+ * includes overhead. An mbuf may add a single "mbuf cluster" of size
+ * MCLBYTES (also in machine/machparam.h), which has no additional overhead
+ * and is used instead of the internal data area; this is done when
+ * at least MINCLSIZE of data must be stored.
+ */
+
+#define MLEN (MSIZE - sizeof (struct m_hdr)) /* normal data len */
+#define MHLEN (MLEN - sizeof (struct pkthdr)) /* data len w/pkthdr */
+
+#define MINCLSIZE (MHLEN + MLEN) /* smallest amount to put in cluster */
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) - convert mbuf pointer to data pointer of correct type
+ */
+#define mtod(m, t) ((t)((m)->m_data))
+
+
+/* header at beginning of each mbuf: */
+struct m_hdr {
+ struct mbuf *mh_next; /* next buffer in chain */
+ struct mbuf *mh_nextpkt; /* next chain in queue/record */
+ int mh_len; /* amount of data in this mbuf */
+ caddr_t mh_data; /* location of data */
+ short mh_type; /* type of data in this mbuf */
+ short mh_flags; /* flags; see below */
+};
+
+/* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
+struct pkthdr {
+ int len; /* total packet length */
+};
+
+
+/* XXX probably do not need m_ext */
+
+/* description of external storage mapped into mbuf, valid if M_EXT set */
+struct m_ext {
+ caddr_t ext_buf; /* start of buffer */
+ int (*ext_ref)(); /* refcount adjust function */
+ uint_t ext_size; /* size of buffer, for ext_free */
+};
+
+struct mbuf {
+ struct m_hdr m_hdr;
+ union {
+ struct {
+ struct pkthdr MH_pkthdr; /* M_PKTHDR set */
+ union {
+ struct m_ext MH_ext; /* M_EXT set */
+ char MH_databuf[MHLEN];
+ } MH_dat;
+ } MH;
+ char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */
+ } M_dat;
+};
+#define m_next m_hdr.mh_next
+#define m_len m_hdr.mh_len
+#define m_data m_hdr.mh_data
+#define m_type m_hdr.mh_type
+#define m_flags m_hdr.mh_flags
+#define m_nextpkt m_hdr.mh_nextpkt
+#define m_act m_nextpkt
+#define m_pkthdr M_dat.MH.MH_pkthdr
+#define m_ext M_dat.MH.MH_dat.MH_ext
+#define m_pktdat M_dat.MH.MH_dat.MH_databuf
+#define m_dat M_dat.M_databuf
+
+/* mbuf flags */
+#define M_EXT 0x0001 /* has associated external storage */
+#define M_PKTHDR 0x0002 /* start of record */
+#define M_EOR 0x0004 /* end of record */
+
+/* mbuf pkthdr flags, also in m_flags */
+#define M_BCAST 0x0100 /* send/received as link-level broadcast */
+#define M_MCAST 0x0200 /* send/received as link-level multicast */
+
+/* flags copied when copying m_pkthdr */
+#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_BCAST|M_MCAST)
+
+/* XXX probably only need MT_DATA */
+
+/* mbuf types */
+#define MT_FREE 0 /* should be on free list */
+#define MT_DATA 1 /* dynamic (data) allocation */
+#define MT_HEADER 2 /* packet header */
+#define MT_SOCKET 3 /* socket structure */
+#define MT_PCB 4 /* protocol control block */
+#define MT_RTABLE 5 /* routing tables */
+#define MT_HTABLE 6 /* IMP host tables */
+#define MT_ATABLE 7 /* address resolution tables */
+#define MT_SONAME 8 /* socket name */
+#define MT_SOOPTS 10 /* socket options */
+#define MT_FTABLE 11 /* fragment reassembly header */
+#define MT_RIGHTS 12 /* access rights */
+#define MT_IFADDR 13 /* interface address */
+#define MT_CONTROL 14 /* extra-data protocol message */
+#define MT_OOBDATA 15 /* expedited data */
+
+/*
+ * flags to malloc: PBSHORTCUT
+ */
+#define M_WAITOK 0x0000
+#define M_NOWAIT 0x0001
+
+/* flags to m_get/MGET */
+#define M_DONTWAIT M_NOWAIT
+#define M_WAIT M_WAITOK
+
+
+/*
+ * mbuf allocation/deallocation macros:
+ *
+ * MGET(struct mbuf *m, int how, int type)
+ * allocates an mbuf and initializes it to contain internal data.
+ *
+ * MGETHDR(struct mbuf *m, int how, int type)
+ * allocates an mbuf and initializes it to contain a packet header
+ * and internal data.
+ */
+
+#define MGET(m, how, type) { \
+ m = MEM_ZALLOC("mbuf", sizeof (struct mbuf)); \
+ (m)->m_next = (struct mbuf *)NULL; \
+ (m)->m_nextpkt = (struct mbuf *)NULL; \
+ (m)->m_data = (m)->m_dat; \
+ (m)->m_flags = 0; \
+ (m)->m_type = (short)(type); \
+}
+
+#define MGETHDR(m, how, type) { \
+ m = MEM_ZALLOC("mbuf", sizeof (struct mbuf)); \
+ (m)->m_type = (MT_HEADER); \
+ (m)->m_next = (struct mbuf *)NULL; \
+ (m)->m_nextpkt = (struct mbuf *)NULL; \
+ (m)->m_data = (m)->m_pktdat; \
+ (m)->m_flags = M_PKTHDR; \
+}
+
+extern int mclref();
+extern int mclrefnoop();
+#define MCLGET(m, how) \
+ { \
+ (m)->m_ext.ext_buf = MEM_ZALLOC("mbuf", MCLBYTES); \
+ (m)->m_data = (m)->m_ext.ext_buf; \
+ (m)->m_flags |= M_EXT; \
+ (m)->m_ext.ext_size = MCLBYTES; \
+ (m)->m_ext.ext_ref = mclref; \
+ }
+
+/*
+ * MFREE(struct mbuf *m, struct mbuf *nn)
+ * Free a single mbuf and associated external storage.
+ * Place the successor, if any, in nn.
+ */
+#define MFREE(m, nn) \
+ { \
+ if ((m)->m_flags & M_EXT) { \
+ (*((m)->m_ext.ext_ref))((m)->m_ext.ext_buf, \
+ (m)->m_ext.ext_size, -1); \
+ (m)->m_ext.ext_buf = 0; \
+ } \
+ (nn) = (m)->m_next; \
+ (m)->m_next = 0; \
+ MEM_FREE("mbuf", m); \
+ }
+
+
+
+/*
+ * As above, for mbufs allocated with m_gethdr/MGETHDR
+ * or initialized by M_COPY_PKTHDR.
+ */
+#define MH_ALIGN(m, len) \
+ { (m)->m_data += (MHLEN - (len)) &~ (sizeof (int32_t) - 1); }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MBUF_H */
diff --git a/usr/src/uts/common/smbsrv/mlrpc.h b/usr/src/uts/common/smbsrv/mlrpc.h
new file mode 100644
index 0000000000..fe82cf01df
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mlrpc.h
@@ -0,0 +1,414 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MLRPC_H
+#define _SMBSRV_MLRPC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MSRPC Like RPC (MLRPC) is an MSRPC compatible implementation of OSF
+ * DCE RPC. DCE RPC is derived from the Apollo Network Computing
+ * Architecture (NCA) RPC implementation. This implementation is based
+ * on the X/Open DCE: Remote Procedure Call specification. The main
+ * MSRPC compatibility issue is the use of Unicode strings. This work
+ * was originally based on the X/Open DCE Remote Procedure Call CAE
+ * 1994 Specification. The current DCE RPC specification is detailed
+ * below.
+ *
+ * CAE Specification (1997)
+ * DCE 1.1: Remote Procedure Call
+ * Document Number: C706
+ * The Open Group
+ * ogspecs@opengroup.org
+ */
+
+/*
+ * Layering
+ *
+ * This shows the software layers of the DCE RPC system compared against
+ * ONC SUN RPC.
+ *
+ * MLRPC Layers Sun RPC Layers Remark
+ * +---------------+ +---------------+ +---------------+
+ * +---------------+ +---------------+
+ * | Application | | Application | The application
+ * +---------------+ +---------------+
+ * | Hand coded | | RPCGEN gen'd | Where the real
+ * | client/server | | client/server | work happens
+ * | srvsvc.ndl | | *_svc.c *_clnt|
+ * | srvsvc.c | | |
+ * +---------------+ +---------------+
+ * | RPC Library | | RPC Library | Calls/Return
+ * | mlrpc_*.c | | | Binding/PMAP
+ * +---------------+ +---------------+
+ * | RPC Protocol | | RPC Protocol | Headers, Auth,
+ * | mlrpcpdu.ndl | | |
+ * +---------------+ +---------------+
+ * | IDL gen'd | | RPCGEN gen'd | Aggregate
+ * | NDR stubs | | XDR stubs | Composition
+ * | *__ndr.c | | *_xdr.c |
+ * +---------------+ +---------------+
+ * | NDR Represen | | XDR Represen | Byte order, padding
+ * +---------------+ +---------------+
+ * | Packet Heaps | | Network Conn | BIG DIFF: DCERPC does
+ * | mlndo_*.c | | clnt_{tcp,udp}| not talk directly to
+ * +---------------+ +---------------+ network.
+ *
+ * There are two major differences between the DCE RPC and ONC RPC:
+ *
+ * 1. MLRPC only generates or processes packets from buffers. Other
+ * layers must take care of packet transmission and reception.
+ * The packet heaps are managed through a simple interface provided
+ * by the Network Data Representation (NDR) module, called struct
+ * mlndr_stream. mlndo_*.c modules implement the different flavors
+ * (operations) of packet heaps.
+ *
+ * ONC RPC communicates directly with the network. You have to do
+ * something special for the RPC packet to be placed in a buffer
+ * rather than sent to the wire.
+ *
+ * 2. MLRPC uses application provided heaps to support operations.
+ * A heap is a single, monolithic chunk of memory that MLRPC manages
+ * as it allocates. When the operation and its result are done, the
+ * heap is disposed of as a single item. The mlrpc_xaction, which
+ * is the anchor of most operations, contains the necessary book-
+ * keeping for the heap.
+ *
+ * ONC RPC uses malloc() liberally throughout its run-time system.
+ * To free results, ONC RPC supports an XDR_FREE operation that
+ * traverses data structures freeing memory as it goes, whether
+ * it was malloc'd or not.
+ */
+
+#include <smbsrv/ndl/rpcpdu.ndl>
+#include <sys/uio.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/ndr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Dispatch Return Code (DRC)
+ *
+ * 0x8000 15:01 Set to indicate a fault, clear indicates status
+ * 0x7F00 08:07 Status/Fault specific
+ * 0x00FF 00:08 MLRPC_PTYPE_... of PDU, 0xFF for header
+ */
+#define MLRPC_DRC_MASK_FAULT 0x8000
+#define MLRPC_DRC_MASK_SPECIFIER 0xFF00
+#define MLRPC_DRC_MASK_PTYPE 0x00FF
+
+/* Usual stuff */
+#define MLRPC_DRC_OK 0x0000
+
+/* Fake PTYPEs for MLRPC_DRC */
+#define MLRPC_DRC_PTYPE_RPCHDR 0x00FF
+#define MLRPC_DRC_PTYPE_API 0x00AA
+
+/* DRC Recognizers */
+#define MLRPC_DRC_IS_OK(DRC) (((DRC)&MLRPC_DRC_MASK_SPECIFIER) == 0)
+#define MLRPC_DRC_IS_FAULT(DRC) (((DRC)&MLRPC_DRC_MASK_FAULT) != 0)
+
+/*
+ * (Un)Marshalling category specifiers
+ */
+#define MLRPC_DRC_FAULT_MODE_MISMATCH 0x8100
+#define MLRPC_DRC_RECEIVED 0x0200
+#define MLRPC_DRC_FAULT_RECEIVED_RUNT 0x8300
+#define MLRPC_DRC_FAULT_RECEIVED_MALFORMED 0x8400
+#define MLRPC_DRC_DECODED 0x0500
+#define MLRPC_DRC_FAULT_DECODE_FAILED 0x8600
+#define MLRPC_DRC_ENCODED 0x0700
+#define MLRPC_DRC_FAULT_ENCODE_FAILED 0x8800
+#define MLRPC_DRC_FAULT_ENCODE_TOO_BIG 0x8900
+#define MLRPC_DRC_SENT 0x0A00
+#define MLRPC_DRC_FAULT_SEND_FAILED 0x8B00
+
+/*
+ * Resource category specifier
+ */
+#define MLRPC_DRC_FAULT_RESOURCE_1 0x9100
+#define MLRPC_DRC_FAULT_RESOURCE_2 0x9200
+
+/*
+ * Parameters. Usually #define'd with useful alias
+ */
+#define MLRPC_DRC_FAULT_PARAM_0_INVALID 0xC000
+#define MLRPC_DRC_FAULT_PARAM_0_UNIMPLEMENTED 0xD000
+#define MLRPC_DRC_FAULT_PARAM_1_INVALID 0xC100
+#define MLRPC_DRC_FAULT_PARAM_1_UNIMPLEMENTED 0xD100
+#define MLRPC_DRC_FAULT_PARAM_2_INVALID 0xC200
+#define MLRPC_DRC_FAULT_PARAM_2_UNIMPLEMENTED 0xD200
+#define MLRPC_DRC_FAULT_PARAM_3_INVALID 0xC300
+#define MLRPC_DRC_FAULT_PARAM_3_UNIMPLEMENTED 0xD300
+
+#define MLRPC_DRC_FAULT_OUT_OF_MEMORY 0xF000
+
+/* RPCHDR */
+#define MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID 0xC0FF /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_RPCHDR_PTYPE_UNIMPLEMENTED 0xD0FF /* PARAM_0_UNIMP */
+
+/* Request */
+#define MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID 0xC000 /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID 0xC100 /* PARAM_1_INVALID */
+
+/* Bind */
+#define MLRPC_DRC_FAULT_BIND_PCONT_BUSY 0xC00B /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_BIND_UNKNOWN_SERVICE 0xC10B /* PARAM_1_INVALID */
+#define MLRPC_DRC_FAULT_BIND_NO_SLOTS 0x910B /* RESOURCE_1 */
+#define MLRPC_DRC_BINDING_MADE 0x000B /* OK */
+
+/* API */
+#define MLRPC_DRC_FAULT_API_SERVICE_INVALID 0xC0AA /* PARAM_0_INVALID */
+#define MLRPC_DRC_FAULT_API_BIND_NO_SLOTS 0x91AA /* RESOURCE_1 */
+#define MLRPC_DRC_FAULT_API_OPNUM_INVALID 0xC1AA /* PARAM_1_INVALID */
+
+struct mlrpc_xaction;
+
+typedef struct mlrpc_stub_table {
+ int (*func)(void *param, struct mlrpc_xaction *mreq);
+ unsigned short opnum;
+} mlrpc_stub_table_t;
+
+typedef struct mlrpc_service {
+ char *name;
+ char *desc;
+ char *endpoint;
+ char *sec_addr_port;
+ char *abstract_syntax_uuid;
+ int abstract_syntax_version;
+ char *transfer_syntax_uuid;
+ int transfer_syntax_version;
+ unsigned bind_instance_size;
+ int (*bind_req)();
+ int (*unbind_and_close)();
+ int (*call_stub)(struct mlrpc_xaction *mreq);
+ struct ndr_typeinfo *interface_ti;
+ struct mlrpc_stub_table *stub_table;
+} mlrpc_service_t;
+
+/*
+ * The list of bindings is anchored at a connection. Nothing in the
+ * RPC mechanism allocates them. Binding elements which have service==0
+ * indicate free elements. When a connection is instantiated, at least
+ * one free binding entry should also be established. Something like
+ * this should suffice for most (all) situations:
+ *
+ * struct connection {
+ * ....
+ * struct mlrpc_binding *binding_list_head;
+ * struct mlrpc_binding binding_pool[N_BINDING_POOL];
+ * ....
+ * };
+ *
+ * init_connection(struct connection *conn) {
+ * ....
+ * mlrpc_binding_pool_initialize(&conn->binding_list_head,
+ * conn->binding_pool, N_BINDING_POOL);
+ */
+struct mlrpc_binding {
+ struct mlrpc_binding *next;
+ mlrpc_p_context_id_t p_cont_id;
+ unsigned char which_side;
+ void * context;
+ struct mlrpc_service *service;
+ void *instance_specific;
+};
+
+#define MLRPC_BIND_SIDE_CLIENT 1
+#define MLRPC_BIND_SIDE_SERVER 2
+
+#define MLRPC_BINDING_TO_SPECIFIC(BINDING, TYPE) \
+ ((TYPE *) (BINDING)->instance_specific)
+
+/*
+ * mlrpc_heap.c
+ *
+ * A number of heap areas are used during marshalling and unmarshalling.
+ * Under some circumstances these areas can be discarded by the library
+ * code, i.e. on the server side before returning to the client and on
+ * completion of a client side bind. In the case of a client side RPC
+ * call, these areas must be preserved after an RPC returns to give the
+ * caller time to take a copy of the data. In this case the client must
+ * call mlrpc_c_free_heap to free the memory.
+ *
+ * The heap management data definition looks a bit like this:
+ *
+ * heap -> +---------------+ +------------+
+ * | iovec[0].base | --> | data block |
+ * | iovec[0].len | +------------+
+ * +---------------+
+ * ::
+ * ::
+ * iov -> +---------------+ +------------+
+ * | iovec[n].base | --> | data block |
+ * | iovec[n].len | +------------+
+ * +---------------+ ^ ^
+ * | |
+ * next ----------------------+ |
+ * top -----------------------------------+
+ *
+ */
+
+/*
+ * Setting MAXIOV to 384 will use ((8 * 384) + 16) = 3088 bytes
+ * of the first heap block.
+ */
+#define MLRPC_HEAP_MAXIOV 384
+#define MLRPC_HEAP_BLKSZ 4096
+
+typedef struct mlrpc_heap {
+ struct iovec iovec[MLRPC_HEAP_MAXIOV];
+ struct iovec *iov;
+ int iovcnt;
+ char *top;
+ char *next;
+} mlrpc_heap_t;
+
+/*
+ * To support the client-side heap preserve functionality.
+ */
+#define MLRPC_HRST_PRESERVED 1
+
+typedef struct mlrpc_heapref {
+ mlrpc_heap_t *heap;
+ char *recv_pdu_buf;
+ char *send_pdu_buf;
+ unsigned int state;
+} mlrpc_heapref_t;
+
+/*
+ * Alternate varying/conformant string definition
+ * - for non-null-terminated strings.
+ */
+struct mlrpc_vcb {
+ /*
+ * size_is (actually a copy of length_is) will
+ * be inserted here by the marshalling library.
+ */
+ DWORD vc_first_is;
+ DWORD vc_length_is;
+ WORD buffer[ANY_SIZE_ARRAY];
+};
+
+typedef struct mlrpc_vcbuf {
+ WORD wclen;
+ WORD wcsize;
+ struct mlrpc_vcb *vcb;
+} mlrpc_vcbuf_t;
+
+mlrpc_heap_t *mlrpc_heap_create(void);
+void mlrpc_heap_destroy(mlrpc_heap_t *);
+void *mlrpc_heap_malloc(mlrpc_heap_t *, unsigned);
+void *mlrpc_heap_strsave(mlrpc_heap_t *, char *);
+void mlrpc_heap_mkvcs(mlrpc_heap_t *, char *, mlrpc_vcbuf_t *);
+int mlrpc_heap_used(mlrpc_heap_t *);
+int mlrpc_heap_avail(mlrpc_heap_t *);
+
+#define MLRPC_HEAP_MALLOC(MXA, SIZE) \
+ mlrpc_heap_malloc((MXA)->heap, SIZE)
+
+#define MLRPC_HEAP_NEW(MXA, TYPE) \
+ mlrpc_heap_malloc((MXA)->heap, sizeof (TYPE))
+
+#define MLRPC_HEAP_NEWN(MXA, TYPE, N) \
+ mlrpc_heap_malloc((MXA)->heap, sizeof (TYPE)*(N))
+
+#define MLRPC_HEAP_STRSAVE(MXA, STR) \
+ mlrpc_heap_strsave((MXA)->heap, (STR))
+
+struct mlrpc_xaction {
+ unsigned short ptype; /* just handy, hi bits spcl */
+ unsigned short opnum; /* for requests */
+ struct mlndr_stream recv_mlnds;
+ mlrpcconn_hdr_t recv_hdr;
+ struct mlndr_stream send_mlnds;
+ mlrpcconn_hdr_t send_hdr;
+ struct mlrpc_binding *binding; /* what we're using */
+ struct mlrpc_binding *binding_list; /* from connection */
+ mlrpc_heap_t *heap;
+ struct mlsvc_rpc_context *context;
+};
+
+struct mlrpc_client {
+ int (*xa_init)(struct mlrpc_client *, struct mlrpc_xaction *,
+ mlrpc_heap_t *);
+ int (*xa_exchange)(struct mlrpc_client *, struct mlrpc_xaction *);
+ int (*xa_read)(struct mlrpc_client *, struct mlrpc_xaction *);
+ int (*xa_preserve)(struct mlrpc_client *, struct mlrpc_xaction *,
+ mlrpc_heapref_t *);
+ int (*xa_destruct)(struct mlrpc_client *, struct mlrpc_xaction *);
+ void (*xa_release)(struct mlrpc_client *, mlrpc_heapref_t *);
+
+ void *context;
+ struct mlrpc_binding *binding_list;
+ uint32_t next_call_id;
+ unsigned next_p_cont_id;
+};
+
+/* mlndo.c */
+int mlnds_initialize(struct mlndr_stream *, unsigned, int, mlrpc_heap_t *);
+void mlnds_destruct(struct mlndr_stream *);
+
+/* mlrpc_client.c */
+int mlrpc_c_bind(struct mlrpc_client *, char *, struct mlrpc_binding **);
+int mlrpc_c_call(struct mlrpc_binding *, int, void *, mlrpc_heapref_t *);
+int mlrpc_c_free_heap(struct mlrpc_binding *, mlrpc_heapref_t *);
+
+/* mlrpc_encdec.c */
+int mlrpc_encode_decode_common(struct mlrpc_xaction *, int, unsigned,
+ struct ndr_typeinfo *, void *);
+int mlrpc_decode_call(struct mlrpc_xaction *, void *);
+int mlrpc_encode_return(struct mlrpc_xaction *, void *);
+int mlrpc_encode_call(struct mlrpc_xaction *, void *);
+int mlrpc_decode_return(struct mlrpc_xaction *, void *);
+int mlrpc_decode_pdu_hdr(struct mlrpc_xaction *);
+int mlrpc_encode_pdu_hdr(struct mlrpc_xaction *);
+void mlrpc_decode_frag_hdr(struct mlndr_stream *, mlrpcconn_common_header_t *);
+unsigned mlrpc_bind_ack_hdr_size(struct mlrpcconn_bind_ack_hdr *);
+
+/* mlrpc_svc.c */
+struct mlrpc_stub_table *mlrpc_find_stub_in_svc(struct mlrpc_service *, int);
+struct mlrpc_service *mlrpc_find_service_by_name(const char *);
+struct mlrpc_service *mlrpc_find_service_by_uuids(mlrpc_uuid_t *, int,
+ mlrpc_uuid_t *, int);
+int mlrpc_register_service(struct mlrpc_service *);
+void mlrpc_unregister_service(struct mlrpc_service *);
+void mlrpc_uuid_to_str(mlrpc_uuid_t *, char *);
+int mlrpc_str_to_uuid(char *, mlrpc_uuid_t *);
+void mlrpc_binding_pool_initialize(struct mlrpc_binding **,
+ struct mlrpc_binding pool[], unsigned);
+struct mlrpc_binding *mlrpc_find_binding(struct mlrpc_xaction *,
+ mlrpc_p_context_id_t);
+struct mlrpc_binding *mlrpc_new_binding(struct mlrpc_xaction *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MLRPC_H */
diff --git a/usr/src/uts/common/smbsrv/mlsvc.h b/usr/src/uts/common/smbsrv/mlsvc.h
new file mode 100644
index 0000000000..cb13cf5733
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mlsvc.h
@@ -0,0 +1,233 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MLSVC_H
+#define _SMBSRV_MLSVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLSVC RPC layer public interface definitions.
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/ksynch.h>
+
+#include <smbsrv/wintypes.h>
+#include <smbsrv/ntsid.h>
+
+#include <smbsrv/smb_winpipe.h>
+#include <smbsrv/smb_xdr.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * RPC strings
+ *
+ * DCE RPC strings (CAE section 14.3.4) are represented as varying or
+ * varying and conformant one-dimensional arrays. Characters can be
+ * single-byte or multi-byte as long as all characters conform to a
+ * fixed element size, i.e. UCS-2 is okay but UTF-8 is not a valid
+ * DCE RPC string format. The string is terminated by a null character
+ * of the appropriate element size.
+ *
+ * MSRPC strings are always varying and conformant format and not null
+ * terminated. This format uses the size_is, first_is and length_is
+ * attributes (CAE section 4.2.18).
+ *
+ * typedef struct mlrpc_string {
+ * DWORD size_is;
+ * DWORD first_is;
+ * DWORD length_is;
+ * wchar_t string[ANY_SIZE_ARRAY];
+ * } mlrpc_string_t;
+ *
+ * The size_is attribute is used to specify the number of data elements
+ * in each dimension of an array.
+ *
+ * The first_is attribute is used to define the lower bound for
+ * significant elements in each dimension of an array. For strings
+ * this is always 0.
+ *
+ * The length_is attribute is used to define the number of significant
+ * elements in each dimension of an array. For strings this is typically
+ * the same as size_is. Although it might be (size_is - 1) if the string
+ * is null terminated.
+ *
+ * In MSRPC, Unicode strings are not null terminated. This means
+ * that the recipient has to manually null-terminate the string after
+ * it has been unmarshalled. Note that there is often a wide-char pad
+ * following a string. Although the padding sometimes contains zero,
+ * it's not guaranteed.
+ *
+ * 4 bytes 4 bytes 4 bytes 2bytes 2bytes 2bytes 2bytes
+ * +---------+---------+---------+------+------+------+------+
+ * |size_is |first_is |length_is| char | char | char | char |
+ * +---------+---------+---------+------+------+------+------+
+ *
+ * The problem is that some strings are null terminated. This seems
+ * to conflict with the statement above that Unicode strings are not
+ * null terminated, which may be a historical thing from earlier
+ * implementations or it may be that different services do different
+ * things. So there is an additional string wrapper with two more
+ * fields used in some RPC structures as shown below (LPTSTR is
+ * automatically converted to mlrpc_string by the NDR marshalling).
+ *
+ * typedef struct ms_string {
+ * WORD length;
+ * WORD maxlen;
+ * LPTSTR str;
+ * } ms_string_t;
+ *
+ * Here, length is the array length in bytes excluding any terminating
+ * null bytes and maxlen is the array length in bytes including null
+ * terminator bytes.
+ */
+typedef struct mlsvc_string {
+ WORD length;
+ WORD maxlen;
+ LPTSTR str;
+} mlsvc_string_t;
+
+/*
+ * The maximum number of domains (NT limit).
+ */
+#define MLSVC_DOMAIN_MAX 32
+
+/*
+ * Some buffer size limits. I don't know if these are definitive
+ * limits for NT but these numbers appear in various places.
+ */
+#define MLSVC_DOMAIN_NAME_MAX 32
+#define MLSVC_ACCOUNT_NAME_MAX 32
+#define MLSVC_CLIENT_NAME_MAX 48
+
+/* 32-byte machine account password (null-terminated) */
+#define MLSVC_MACHINE_ACCT_PASSWD_MAX 32 + 1
+
+/*
+ * Status code returned from enumeration RPCs to indicate
+ * that the server has no more data. Normally returned at
+ * severity level ERROR_SEVERITY_WARNING.
+ */
+#define MLSVC_NO_MORE_DATA 0x1A
+
+/*
+ * IPC connection types, used to indicate the type of session
+ * required for a subsequent series of requests.
+ */
+#define MLSVC_IPC_ANON 0x00
+#define MLSVC_IPC_USER 0x01
+#define MLSVC_IPC_ADMIN 0x02
+
+#define MLSVC_ANON_USER "IPC$"
+
+char *mlsvc_ipc_name(int ipc_type, char *username);
+
+/*
+ * Passthrough negotiation and authentication interface.
+ *
+ * NT supports two forms of password: a Lanman (case-insensitive)
+ * password and an NT (case-sensitive) password. If either of the
+ * passwords is not available its pointer and length should be set
+ * to zero. The session key and vc number are required to validate
+ * the encrypted passwords.
+ */
+
+int mlsvc_anonymous_logon(char *domain_controller, char *domain_name,
+ char **username);
+int mlsvc_user_logon(char *domain_controller, char *domain_name,
+ char *username, char *password);
+int mlsvc_admin_logon(char *domain_controller, char *domain_name);
+int mlsvc_echo(char *server);
+int mlsvc_open_pipe(char *hostname, char *domain, char *username,
+ char *pipename);
+int mlsvc_close_pipe(int fid);
+void mlsvc_nt_password_hash(char *result, char *password);
+int mlsvc_encrypt_nt_password(char *password, char *key, int keylen, char *out,
+ int outmax);
+DWORD mlsvc_validate_user(char *server, char *domain, char *username,
+ char *password);
+int mlsvc_locate_domain_controller(char *domain);
+
+/*
+ * RPC request processing interface (mlsvc_server.c).
+ */
+#define MLSVC_MAX_IOVEC 512
+
+typedef struct mlrpc_frag {
+ struct mlrpc_frag *next;
+ struct mbuf *mhead;
+ uint32_t length;
+} mlrpc_frag_t;
+
+typedef struct mlsvc_stream {
+ mlrpc_frag_t *head;
+ mlrpc_frag_t *tail;
+ mlrpc_frag_t *pending;
+ unsigned int nfrag;
+ struct uio uio;
+ struct iovec iovec[MLSVC_MAX_IOVEC];
+} mlsvc_stream_t;
+
+typedef struct mlsvc_pipe {
+ kmutex_t mutex;
+ kcondvar_t cv;
+ uint32_t busy;
+ uint32_t fid;
+ char *pipe_name;
+ mlsvc_stream_t input;
+ uchar_t *output;
+ int32_t outlen;
+} mlsvc_pipe_t;
+
+int mlsvc_rpc_process(
+ smb_pipe_t *inpipe,
+ smb_pipe_t **outpipe,
+ smb_dr_user_ctx_t *user_ctx);
+
+struct mlsvc_rpc_context *mlsvc_lookup_context(int fid);
+
+void mlsvc_rpc_release(int fid);
+int mlsvc_session_native_values(int fid, int *remote_os, int *remote_lm,
+ int *pdc_type);
+void mlsvc_rpc_report_status(int opnum, DWORD status);
+
+/*
+ * This is a temporary location for this NETLOGON stuff.
+ */
+typedef int (*mlsvc_locate_pdc_t)(char *domain);
+void mlsvc_install_pdc_cb(mlsvc_locate_pdc_t locate_pdc_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_MLSVC_H */
diff --git a/usr/src/uts/common/smbsrv/mlsvc_util.h b/usr/src/uts/common/smbsrv/mlsvc_util.h
new file mode 100644
index 0000000000..e9ababec15
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/mlsvc_util.h
@@ -0,0 +1,244 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MLSVC_UTIL_H
+#define _SMBSRV_MLSVC_UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * MLSVC RPC interface and utility function definitions.
+ */
+
+#include <smbsrv/ndl/ndrtypes.ndl>
+#include <smbsrv/ndr.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/ntsid.h>
+#include <smbsrv/smb_token.h>
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Predefined global RIDs.
+ */
+#define MLSVC_DOMAIN_GROUP_RID_ADMINS 0x00000200L
+#define MLSVC_DOMAIN_GROUP_RID_USERS 0x00000201L
+#define MLSVC_DOMAIN_GROUP_RID_GUESTS 0x00000202L
+#define MLSVC_DOMAIN_GROUP_RID_COMPUTERS 0x00000203L
+#define MLSVC_DOMAIN_GROUP_RID_CONTROLLERS 0x00000204L
+#define MLSVC_DOMAIN_GROUP_RID_CERT_ADMINS 0x00000205L
+#define MLSVC_DOMAIN_GROUP_RID_SCHEMA_ADMINS 0x00000206L
+
+/*
+ * Predefined local alias RIDs.
+ */
+#define MLSVC_LOCAL_GROUP_RID_ADMINS 0x00000220L
+#define MLSVC_LOCAL_GROUP_RID_USERS 0x00000221L
+#define MLSVC_LOCAL_GROUP_RID_GUESTS 0x00000222L
+#define MLSVC_LOCAL_GROUP_RID_POWER_USERS 0x00000223L
+#define MLSVC_LOCAL_GROUP_RID_ACCOUNT_OPS 0x00000224L
+#define MLSVC_LOCAL_GROUP_RID_SERVER_OPS 0x00000225L
+#define MLSVC_LOCAL_GROUP_RID_PRINT_OPS 0x00000226L
+#define MLSVC_LOCAL_GROUP_RID_BACKUP_OPS 0x00000227L
+#define MLSVC_LOCAL_GROUP_RID_REPLICATOR 0x00000228L
+
+/*
+ * All predefined local group RIDs belong
+ * to a special domain called BUILTIN.
+ */
+#define MLSVC_BUILTIN_DOMAIN_NAME "BUILTIN"
+#define MLSVC_BUILTIN_DOMAIN_SIDSTRLEN 8
+
+/*
+ * Universal and NT well-known SIDs
+ */
+#define MLSVC_NULL_SIDSTR "S-1-0-0"
+#define MSLVC_WORLD_SIDSTR "S-1-1-0"
+#define MSLVC_LOCAL_SIDSTR "S-1-2-0"
+#define MSLVC_CREATOR_OWNER_ID_SIDSTR "S-1-3-0"
+#define MSLVC_CREATOR_GROUP_ID_SIDSTR "S-1-3-1"
+#define MSLVC_CREATOR_OWNER_SERVER_ID_SIDSTR "S-1-3-2"
+#define MSLVC_CREATOR_GROUP_SERVER_ID_SIDSTR "S-1-3-3"
+#define MSLVC_NON_UNIQUE_IDS_SIDSTR "S-1-4"
+#define MLSVC_NT_AUTHORITY_SIDSTR "S-1-5"
+#define MLSVC_DIALUP_SIDSTR "S-1-5-1"
+#define MLSVC_NETWORK_SIDSTR "S-1-5-2"
+#define MLSVC_BATCH_SIDSTR "S-1-5-3"
+#define MLSVC_INTERACTIVE_SIDSTR "S-1-5-4"
+#define MLSVC_SERVICE_SIDSTR "S-1-5-6"
+#define MLSVC_ANONYMOUS_LOGON_SIDSTR "S-1-5-7"
+#define MLSVC_PROXY_SIDSTR "S-1-5-8"
+#define MLSVC_SERVER_LOGON_SIDSTR "S-1-5-9"
+#define MLSVC_SELF_SIDSTR "S-1-5-10"
+#define MLSVC_AUTHENTICATED_USER_SIDSTR "S-1-5-11"
+#define MLSVC_RESTRICTED_CODE_SIDSTR "S-1-5-12"
+#define MLSVC_NT_LOCAL_SYSTEM_SIDSTR "S-1-5-18"
+#define MLSVC_NT_NON_UNIQUE_SIDSTR "S-1-5-21"
+#define MLSVC_BUILTIN_DOMAIN_SIDSTR "S-1-5-32"
+
+int mlsvc_lookup_name(char *domain, char *name, nt_sid_t **sid);
+int mlsvc_lookup_sid(nt_sid_t *sid, char *buf, int bufsize);
+
+smb_userinfo_t *mlsvc_alloc_user_info(void);
+void mlsvc_free_user_info(smb_userinfo_t *user_info);
+void mlsvc_release_user_info(smb_userinfo_t *user_info);
+void mlsvc_setadmin_user_info(smb_userinfo_t *user_info);
+char *mlsvc_sid_name_use(unsigned int snu_id);
+
+/*
+ * The definition of a local unique id (LUID). This is an opaque id
+ * used by servers to identify local resources, such as privileges.
+ * A client will use lookup functions to translate the LUID to a
+ * more general, machine independent form; like a string.
+ */
+struct ms_luid {
+ DWORD low_part;
+ DWORD high_part;
+};
+
+/*
+ * As with SIDs, this is the generic, interface independent string
+ * definition.
+ */
+struct ms_string_desc {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct ms_string_desc ms_string_t;
+
+int mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa);
+nt_sid_t *mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa);
+
+/*
+ * This is the generic, interface independent handle definition.
+ */
+typedef struct ms_handle {
+ DWORD handle[5];
+} ms_handle_t;
+
+/*
+ * List of interface specifications: can be used to identify the
+ * sub-system to which a handle is assigned. The handle management
+ * library doesn't check or care about the ifspec value.
+ */
+typedef enum ms_ifspec {
+ MLSVC_IFSPEC_NULL,
+ MLSVC_IFSPEC_LSAR,
+ MLSVC_IFSPEC_SAMR,
+ MLSVC_IFSPEC_WINREG,
+ MLSVC_IFSPEC_SVCCTL,
+ MLSVC_IFSPEC_SPOOLSS,
+ MLSVC_IFSPEC_LOGR,
+ MLSVC_IFSPEC_LLSR,
+ MLSVC_NUM_IFSPECS
+} ms_ifspec_t;
+
+#define MLSVC_HANDLE_KEY_MAX 32
+
+typedef struct ms_handle_desc {
+ struct ms_handle_desc *next;
+ ms_handle_t handle;
+ ms_ifspec_t ifspec;
+ char key[MLSVC_HANDLE_KEY_MAX];
+ DWORD discrim;
+} ms_handle_desc_t;
+
+ms_handle_t *mlsvc_get_handle(ms_ifspec_t ifspec, char *key, DWORD discrim);
+int mlsvc_put_handle(ms_handle_t *handle);
+int mlsvc_validate_handle(ms_handle_t *handle, char *key);
+ms_handle_desc_t *mlsvc_lookup_handle(ms_handle_t *handle);
+
+/*
+ * The mlsvc_rpc_context structure provides the connection binding context
+ * for client RPC calls. This space must be provided by the client library
+ * for use by the underlying RPC library. Note that we need two binding
+ * pools per connection.
+ */
+#define CTXT_N_BINDING_POOL 2
+
+struct mlsvc_rpc_context {
+ struct mlrpc_client cli;
+ int fid;
+ ms_handle_t *handle;
+ smb_dr_user_ctx_t *user_ctx;
+ smb_pipe_t *inpipe; /* used for winpipe */
+ uint32_t inlen; /* inpipes */
+ smb_pipe_t *outpipe; /* used for winpipe */
+ uint32_t outcookie; /* for rpc_read and transact */
+ uint32_t outlen; /* outpipes */
+ int server_os;
+ int server_pdc;
+ WORD max_xmit_frag;
+ WORD max_recv_frag;
+ struct mlrpc_binding *binding;
+ struct mlrpc_binding binding_pool[CTXT_N_BINDING_POOL];
+};
+
+/*
+ * Each RPC interface requires a context and each RPC call within that
+ * interface requires a handle. Handles are call specific, however, so
+ * a number of different handles may be used during a sequence of calls
+ * to a specific RPC interface. Contexts are interface specific so
+ * there is one per interface per thread of execution. This structure
+ * provides a handle to context relationship so that we know which
+ * context to use with any particular handle.
+ *
+ * The context contains a pointer to the top level handle for the
+ * interface, which is assigned during the bind. It's used when closing
+ * to detect when to free the context.
+ *
+ * I know this is really tacky but the elements in the descriptor are
+ * arranged so that a handle can be overlaid directly onto a descriptor.
+ * I probably won't do this but now you know - just in case you see it
+ * in the code.
+ */
+typedef struct mlsvc_rpc_desc {
+ ms_handle_t handle;
+ struct mlsvc_rpc_context *context;
+} mlsvc_handle_t;
+
+
+int mlsvc_rpc_bind(mlsvc_handle_t *handle, int fid, char *service);
+int mlsvc_rpc_init(mlrpc_heapref_t *heapref);
+int mlsvc_rpc_call(struct mlsvc_rpc_context *context, int opnum, void *params,
+ mlrpc_heapref_t *heapref);
+void mlsvc_rpc_free(struct mlsvc_rpc_context *context,
+ mlrpc_heapref_t *heapref);
+int mlsvc_is_null_handle(mlsvc_handle_t *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MLSVC_UTIL_H */
diff --git a/usr/src/uts/common/smbsrv/msgbuf.h b/usr/src/uts/common/smbsrv/msgbuf.h
new file mode 100644
index 0000000000..465ba476de
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/msgbuf.h
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_MSGBUF_H
+#define _SMBSRV_MSGBUF_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Definition and interface for smb_msgbuf buffer management. The
+ * smb_msgbuf interface is typically used to encode or decode SMB
+ * data using sprintf/scanf style operations. It can also be used
+ * for general purpose encoding and decoding.
+ */
+
+#include <sys/types.h>
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * When unicode strings are decoded, the resultant UTF-8 strings are
+ * stored in dynamically allocated areas, which are held on a linked
+ * list anchored at smb_msgbuf.mlist. The list is deallocated by
+ * smb_msgbuf_term.
+ */
+typedef struct smb_msgbuf_mlist {
+ struct smb_msgbuf_mlist *next;
+ size_t size;
+} smb_msgbuf_mlist_t;
+
+/*
+ * smb_smgbuf flags
+ *
+ * SMB_MSGBUF_UNICODE When there is a choice between unicode or ascii
+ * formatting, select unicode processing.
+ * SMB_MSGBUF_NOTERM Do not null terminate strings.
+ */
+#define SMB_MSGBUF_UNICODE 0x00000001
+#define SMB_MSGBUF_NOTERM 0x00000002
+
+/*
+ * base: points to the beginning of the buffer
+ * end: points to the limit of the buffer.
+ * scan: points to the current offset.
+ * max: holds the number of bytes in the buffer.
+ * count: unused.
+ * mlist: anchors the dynamically allocated memory list.
+ * flags: see SMB_SMGBUF flags.
+ */
+typedef struct smb_msgbuf {
+ uint8_t *base;
+ uint8_t *end;
+ uint8_t *scan;
+ size_t count;
+ size_t max;
+ smb_msgbuf_mlist_t mlist;
+ uint32_t flags;
+} smb_msgbuf_t;
+
+/*
+ * List of smb_msgbuf_decode and smb_msgbuf_encode return values.
+ */
+#define SMB_MSGBUF_SUCCESS 0
+#define SMB_MSGBUF_UNDERFLOW -1
+#define SMB_MSGBUF_OVERFLOW SMB_MSGBUF_UNDERFLOW
+#define SMB_MSGBUF_INVALID_FORMAT -2
+#define SMB_MSGBUF_INVALID_HEADER -3
+#define SMB_MSGBUF_DATA_ERROR -4
+
+/*
+ * smb_msgbuf_init must be called to associate the smb_msgbuf_t with
+ * a buffer before any encode or decode operations may be performed.
+ *
+ * smb_msgbuf_term must be called to free any dynamically allocated memory
+ * that was acquired during encode or decode operations. At this time
+ * the only operation that allocates memory is a unicode string decode.
+ *
+ * If there are no errors, smb_msgbuf_decode and smb_msgbuf_encode return
+ * the number of bytes decoded or encoded. If there is a problem they
+ * return -ve error codes.
+ */
+extern void smb_msgbuf_init(smb_msgbuf_t *, uint8_t *, size_t, uint32_t);
+extern void smb_msgbuf_term(smb_msgbuf_t *);
+extern int smb_msgbuf_decode(smb_msgbuf_t *, char *, ...);
+extern int smb_msgbuf_encode(smb_msgbuf_t *, char *, ...);
+extern size_t smb_msgbuf_used(smb_msgbuf_t *);
+extern size_t smb_msgbuf_size(smb_msgbuf_t *);
+extern uint8_t *smb_msgbuf_base(smb_msgbuf_t *);
+extern void smb_msgbuf_word_align(smb_msgbuf_t *);
+extern void smb_msgbuf_dword_align(smb_msgbuf_t *);
+extern int smb_msgbuf_has_space(smb_msgbuf_t *, size_t);
+extern void smb_msgbuf_fset(smb_msgbuf_t *, uint32_t);
+extern void smb_msgbuf_fclear(smb_msgbuf_t *, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_MSGBUF_H */
diff --git a/usr/src/uts/common/smbsrv/ndl/dssetup.ndl b/usr/src/uts/common/smbsrv/ndl/dssetup.ndl
new file mode 100644
index 0000000000..143d243e5a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/dssetup.ndl
@@ -0,0 +1,168 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DSSETUP_NDL_
+#define _DSSETUP_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Active Directory Service Setup
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo 0x00
+#define DSSETUP_OPNUM_DsRoleDnsNameToFlatName 0x01
+#define DSSETUP_OPNUM_DsRoleDcAsDc 0x02
+#define DSSETUP_OPNUM_DsRoleDcAsReplica 0x03
+#define DSSETUP_OPNUM_DsRoleDemoteDc 0x04
+#define DSSETUP_OPNUM_DsRoleGetDcOperationProgress 0x05
+#define DSSETUP_OPNUM_DsRoleGetDcOperationResults 0x06
+#define DSSETUP_OPNUM_DsRoleCancel 0x07
+#define DSSETUP_OPNUM_DsRoleServerSaveStateForUpgrade 0x08
+#define DSSETUP_OPNUM_DsRoleUpgradeDownlevelServer 0x09
+#define DSSETUP_OPNUM_DsRoleAbortDownlevelServerUpgrade 0x0a
+
+/*
+ * DS roles
+ */
+#define DS_ROLE_STANDALONE_WORKSTATION 0
+#define DS_ROLE_MEMBER_WORKSTATION 1
+#define DS_ROLE_STANDALONE_SERVER 2
+#define DS_ROLE_MEMBER_SERVER 3
+#define DS_ROLE_BACKUP_DC 4
+#define DS_ROLE_PRIMARY_DC 5
+
+/*
+ * DS role flags
+ */
+#define DS_ROLE_PRIMARY_DS_RUNNING 0x00000001
+#define DS_ROLE_PRIMARY_DS_MIXED_MODE 0x00000002
+#define DS_ROLE_UPGRADE_IN_PROGRESS 0x00000004
+#define DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT 0x01000000
+
+/*
+ * DS role upgrade
+ */
+#define DS_ROLE_NOT_UPGRADING 0
+#define DS_ROLE_UPGRADING 1
+
+/*
+ * DS role previous
+ */
+#define DS_ROLE_PREVIOUS_UNKNOWN 0
+#define DS_ROLE_PREVIOUS_PRIMARY 1
+#define DS_ROLE_PREVIOUS_BACKUP 2
+
+/*
+ * DS role state
+ */
+#define DS_ROLE_OP_IDLE 0
+#define DS_ROLE_OP_ACTIVE 1
+#define DS_ROLE_OP_NEEDS_REBOOT 2
+
+/*
+ * DS role information levels
+ */
+#define DS_ROLE_BASIC_INFORMATION 1
+#define DS_ROLE_UPGRADE_STATUS 2
+#define DS_ROLE_OP_STATUS 3
+
+struct dssetup_uuid {
+ DWORD data1;
+ WORD data2;
+ WORD data3;
+ BYTE data4[8];
+};
+typedef struct dssetup_uuid dssetup_uuid_t;
+
+/*
+ * DS_ROLE_BASIC_INFORMATION
+ */
+struct dssetup_DsRolePrimaryDomInfo1 {
+ DWORD role;
+ DWORD flags;
+ LPTSTR nt_domain;
+ LPTSTR dns_domain;
+ LPTSTR forest;
+ dssetup_uuid_t domain_guid;
+};
+
+/*
+ * DS_ROLE_UPGRADE_STATUS
+ */
+struct dssetup_DsRolePrimaryDomInfo2 {
+ DWORD upgrade_state;
+ DWORD previous_role;
+};
+
+/*
+ * DS_ROLE_OP_STATUS
+ */
+struct dssetup_DsRolePrimaryDomInfo3 {
+ DWORD status;
+};
+
+union dssetup_GetPrimaryDomainInfo_ru {
+ UNION_INFO_ENT(1,dssetup_DsRolePrimaryDomInfo);
+ UNION_INFO_ENT(2,dssetup_DsRolePrimaryDomInfo);
+ UNION_INFO_ENT(3,dssetup_DsRolePrimaryDomInfo);
+ DEFAULT char *nullptr;
+};
+
+struct dssetup_GetPrimaryDomainInfoRes {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union dssetup_GetPrimaryDomainInfo_ru ru;
+};
+
+OPERATION(DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo)
+struct dssetup_DsRoleGetPrimaryDomainInfo {
+ IN WORD level;
+ OUT DWORD address;
+ OUT WORD switch_value;
+ SWITCH(level)
+ OUT union dssetup_GetPrimaryDomainInfo_ru ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * DSSETUP interface definiton.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union dssetup_interface {
+ CASE(DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo)
+ struct dssetup_DsRoleGetPrimaryDomainInfo GetPrimaryDomainInfo;
+};
+typedef union dssetup_interface dssetup_interface_t;
+EXTERNTYPEINFO(dssetup_interface)
+
+#endif /* _DSSETUP_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/eventlog.ndl b/usr/src/uts/common/smbsrv/ndl/eventlog.ndl
new file mode 100644
index 0000000000..3e412ceb00
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/eventlog.ndl
@@ -0,0 +1,204 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_LOGR_NDL_
+#define _MLSVC_LOGR_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ ***********************************************************************
+ *
+ * Event log RPC (EVENTLOG) interface definition.
+ *
+ ***********************************************************************
+ */
+
+#include "ndrtypes.ndl"
+
+#define LOGR_OPNUM_EventLogClose 0x02
+#define LOGR_OPNUM_EventLogQueryCount 0x04
+#define LOGR_OPNUM_EventLogGetOldestRec 0x05
+#define LOGR_OPNUM_EventLogOpen 0x07
+#define LOGR_OPNUM_EventLogRead 0x0A
+
+#define LOGR_INFOLEN 200
+#define LOGR_RECBUFLEN 0x4000
+
+struct logr_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+
+typedef struct logr_handle logr_handle_t;
+
+
+struct logr_string {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct logr_string logr_string_t;
+
+
+struct logr_record {
+ DWORD Length1; // Length of full record
+ DWORD Reserved; // Used by the service
+ DWORD RecordNumber; // Absolute record number
+ DWORD TimeGenerated; // Seconds since 1-1-1970
+ DWORD TimeWritten; // Seconds since 1-1-1970
+ DWORD EventID;
+ WORD EventType;
+ WORD NumStrings;
+ WORD EventCategory;
+ WORD ReservedFlags; // For use with paired events (auditing)
+ DWORD ClosingRecordNumber; // For use with paired events (auditing)
+ DWORD StringOffset; // Offset from beginning of record
+ DWORD UserSidLength;
+ DWORD UserSidOffset;
+ DWORD DataLength;
+ DWORD DataOffset;
+ //
+ // Then follow:
+ //
+ // WCHAR SourceName[] null terminated
+ // WCHAR Computername[] null terminated
+ // SID UserSid
+ // WCHAR Strings[]
+ // BYTE Data[]
+ // CHAR Pad[] to DWORD
+ // DWORD Length; must be appear
+ BYTE info[LOGR_INFOLEN];
+ DWORD Length2;
+};
+typedef struct logr_record logr_record_t;
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogClose
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogClose)
+struct logr_EventLogClose {
+ IN logr_handle_t handle;
+ OUT logr_handle_t result_handle;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogQueryCount
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogQueryCount)
+struct logr_EventLogQueryCount {
+ IN logr_handle_t handle;
+ OUT DWORD rec_num;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogGetOldestRec
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogGetOldestRec)
+struct logr_EventLogGetOldestRec {
+ IN logr_handle_t handle;
+ OUT DWORD oldest_rec;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogOpen
+ ***********************************************************************
+ */
+OPERATION(LOGR_OPNUM_EventLogOpen)
+struct logr_EventLogOpen {
+ IN DWORD *whatever;
+ IN logr_string_t log_name;
+ IN DWORD unknown1;
+ IN DWORD unknown2;
+ IN DWORD unknown3;
+ OUT logr_handle_t handle;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * LOGR_OPNUM_EventLogRead
+ ***********************************************************************
+ */
+union logr_read_u {
+ CASE(1024) BYTE rec[1024];
+ DEFAULT BYTE recs[LOGR_RECBUFLEN];
+};
+
+
+struct logr_read_info {
+ DWORD nbytes_to_read;
+ SWITCH(nbytes_to_read)
+ union logr_read_u ru;
+};
+
+OPERATION(LOGR_OPNUM_EventLogRead)
+struct logr_EventLogRead {
+ IN logr_handle_t handle;
+ IN DWORD read_flags;
+ IN DWORD rec_offset;
+ INOUT DWORD nbytes_to_read;
+SWITCH (nbytes_to_read)
+ OUT union logr_read_u ru;
+ OUT DWORD sent_size;
+ OUT DWORD unknown;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * The EVENTLOG interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union logr_interface {
+ CASE(LOGR_OPNUM_EventLogClose)
+ struct logr_EventLogClose EventLogClose;
+ CASE(LOGR_OPNUM_EventLogQueryCount)
+ struct logr_EventLogQueryCount EventLogQueryCount;
+ CASE(LOGR_OPNUM_EventLogGetOldestRec)
+ struct logr_EventLogGetOldestRec EventLogGetOldestRec;
+ CASE(LOGR_OPNUM_EventLogOpen)
+ struct logr_EventLogOpen EventLogOpen;
+ CASE(LOGR_OPNUM_EventLogRead)
+ struct logr_EventLogRead EventLogRead;
+};
+typedef union logr_interface logr_interface_t;
+EXTERNTYPEINFO(logr_interface)
+
+
+#endif /* _MLSVC_LOGR_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/llsrpc.ndl b/usr/src/uts/common/smbsrv/ndl/llsrpc.ndl
new file mode 100644
index 0000000000..33b3cccd77
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/llsrpc.ndl
@@ -0,0 +1,110 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_LLSR_NDL_
+#define _MLSVC_LLSR_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * LLSRPC interface.
+ *
+ * 0x50 takes the 3a handle + DWORD, returns 2 DWORDs
+ * 0x3c
+ * 0x3f list of services?
+ * 0x3d unknown
+ * 0x3e unknown
+ * 0x4f
+ * 0x4d
+ * 0x4e
+ * 0x01 closes the handle obtained via 0x00
+ * 0x3b closes the handle obtained via 0x3a
+ */
+
+#include "ndrtypes.ndl"
+
+#define LLSR_OPNUM_Open 0x00
+#define LLSR_OPNUM_Close 0x01
+#define LLSR_OPNUM_Connect 0x3a
+#define LLSR_OPNUM_Disconnect 0x3b
+#define LLSR_OPNUM_Unknown3c 0x3c
+#define LLSR_OPNUM_Unknown3d 0x3d
+#define LLSR_OPNUM_Unknown3e 0x3e
+#define LLSR_OPNUM_Unknown3f 0x3f
+#define LLSR_OPNUM_Unknown4d 0x4d
+#define LLSR_OPNUM_Unknown4e 0x4e
+#define LLSR_OPNUM_Unknown4f 0x4f
+#define LLSR_OPNUM_Unknown50 0x50
+
+
+struct llsr_handle {
+ DWORD opaque[5];
+};
+typedef struct llsr_handle llsr_handle_t;
+
+
+OPERATION(LLSR_OPNUM_Open)
+struct llsr_Open {
+ IN LPTSTR hostname;
+ OUT llsr_handle_t open_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Close)
+struct llsr_Close {
+ IN llsr_handle_t open_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Connect)
+struct llsr_Connect {
+ IN LPTSTR hostname;
+ OUT llsr_handle_t connect_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Disconnect)
+struct llsr_Disconnect {
+ IN llsr_handle_t connect_handle;
+ OUT llsr_handle_t echoed_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(LLSR_OPNUM_Unknown50)
+struct llsr_Unknown50 {
+ IN llsr_handle_t open_handle;
+ IN DWORD unknown1; /* 0x00000004 */
+ OUT DWORD unknown2; /* 0x00000004 */
+ OUT DWORD unknown3; /* 0x0000003F */
+ OUT DWORD status;
+};
+
+
+#endif /* _MLSVC_LLSR_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl b/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl
new file mode 100644
index 0000000000..102a3cf63d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl
@@ -0,0 +1,801 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_LSA_NDL_
+#define _MLSVC_LSA_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ ***********************************************************************
+ * Local Security Authority RPC (LSARPC) interface definition.
+ ***********************************************************************
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define LSARPC_OPNUM_CloseHandle 0x00
+#define LSARPC_OPNUM_EnumPrivileges 0x02
+#define LSARPC_OPNUM_QuerySecurityObject 0x03
+#define LSARPC_OPNUM_SetSecurityObject 0x04
+#define LSARPC_OPNUM_ChangePassword 0x05
+#define LSARPC_OPNUM_OpenPolicy 0x06
+#define LSARPC_OPNUM_QueryInfoPolicy 0x07
+#define LSARPC_OPNUM_SetInfoPolicy 0x08
+#define LSARPC_OPNUM_Unknown09 0x09 /* Crashed the DC */
+#define LSARPC_OPNUM_CreateAccount 0x0a
+#define LSARPC_OPNUM_EnumerateAccounts 0x0b
+#define LSARPC_OPNUM_CreateTrustedDomain 0x0c
+#define LSARPC_OPNUM_EnumTrustedDomain 0x0d
+#define LSARPC_OPNUM_LookupNames 0x0e
+#define LSARPC_OPNUM_LookupSids 0x0f
+#define LSARPC_OPNUM_CreateSecret 0x10
+#define LSARPC_OPNUM_OpenAccount 0x11
+#define LSARPC_OPNUM_EnumPrivsAccount 0x12
+#define LSARPC_OPNUM_GetSystemAccessAccount 0x17
+#define LSARPC_OPNUM_OpenSecret 0x1c
+#define LSARPC_OPNUM_LookupPrivValue 0x1f
+#define LSARPC_OPNUM_LookupPrivName 0x20
+#define LSARPC_OPNUM_LookupPrivDisplayName 0x21
+#define LSARPC_OPNUM_AddAccountRights 0x25
+#define LSARPC_OPNUM_OpenPolicy2 0x2c
+#define LSARPC_OPNUM_GetConnectedUser 0x2d
+#define LSARPC_OPNUM_Discovery 0x2e
+#define LSARPC_OPNUM_LookupSids2 0x39
+#define LSARPC_OPNUM_LookupNames2 0x3a
+
+
+/*
+ * There are at least two lookup level settings. Level 1 appears to mean
+ * only look on the local host and level 2 means forward the request to
+ * the PDC. On the PDC it probably doesn't matter which level you use but
+ * on a BDC a level 1 lookup will fail if the BDC doesn't have the info
+ * whereas a level 2 lookup will also check with the PDC.
+ */
+#define MSLSA_LOOKUP_LEVEL_1 1
+#define MSLSA_LOOKUP_LEVEL_2 2
+
+
+/*
+ * Definition for a SID. The ndl compiler won't allow a typedef of
+ * a structure containing variable size members.
+ */
+struct mslsa_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[6];
+ SIZE_IS(SubAuthCount)
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+};
+
+struct mslsa_string_desc {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct mslsa_string_desc mslsa_string_t;
+
+
+struct mslsa_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+typedef struct mslsa_handle mslsa_handle_t;
+
+
+struct mslsa_luid {
+ DWORD low_part;
+ DWORD high_part;
+};
+typedef struct mslsa_luid mslsa_luid_t;
+
+
+/*
+ ***********************************************************************
+ * OpenPolicy2 obtains a handle for a remote LSA. This handle is
+ * required for all subsequent LSA requests.
+ *
+ * The server name should be the name of the target PDC or BDC, with
+ * the double backslash prefix.
+ *
+ * As far as I can tell, the mslsa_object_attributes structure can be
+ * all zero except for the length, which should be set to sizeof(struct
+ * mslsa_object_attributes).
+ *
+ * For read access, the desired access mask should contain the
+ * READ_CONTROL standard right and whatever policy rights are required.
+ * I haven't tried any update operations but if you get the access mask
+ * wrong you can crash the domain controller.
+ ***********************************************************************
+ */
+
+
+/*
+ * From netmon:
+ * length = 12
+ * impersonation_level = 2
+ * context_tracking_mode = 1
+ * effective_only = 0
+ */
+struct mslsa_quality_of_service {
+ DWORD length;
+ WORD impersonation_level;
+ BYTE context_tracking_mode;
+ BYTE effective_only;
+};
+
+
+struct mslsa_object_attributes {
+ DWORD length;
+ DWORD rootDirectory;
+ DWORD objectName;
+ DWORD attributes;
+ DWORD securityDescriptor;
+ struct mslsa_quality_of_service *qualityOfService;
+};
+
+
+OPERATION(LSARPC_OPNUM_OpenPolicy)
+struct mslsa_OpenPolicy {
+ IN DWORD *servername;
+ IN struct mslsa_object_attributes attributes;
+ IN DWORD desiredAccess;
+ OUT mslsa_handle_t domain_handle;
+ OUT DWORD status;
+};
+
+OPERATION(LSARPC_OPNUM_OpenPolicy2)
+struct mslsa_OpenPolicy2 {
+ IN LPTSTR servername;
+ IN struct mslsa_object_attributes attributes;
+ IN DWORD desiredAccess;
+ OUT mslsa_handle_t domain_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * CloseHandle closes an association with the LSA. The returned handle
+ * will be all zero.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_CloseHandle)
+struct mslsa_CloseHandle {
+ IN mslsa_handle_t handle;
+ OUT mslsa_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumPrivileges
+ *
+ * Obtain a list of privilege names. This interface is not implemented
+ * yet The definition below has not been tested. This is a guess based
+ * on data available from netmon.
+ ***********************************************************************
+ */
+struct mslsa_PrivDef {
+ mslsa_string_t name;
+ mslsa_luid_t luid;
+};
+
+
+struct mslsa_PrivEnumBuf {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslsa_PrivDef *def;
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumPrivileges)
+struct mslsa_EnumPrivileges {
+ IN mslsa_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT REFERENCE struct mslsa_PrivEnumBuf *enum_buf;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QuerySecurityObject. I'm not entirely sure how to set this up yet.
+ * I used the discovery RPC to scope it out. The structures are set up
+ * according to netmon and the assumption that a security descriptor
+ * on the wire looks like the regular user level security descriptor.
+ ***********************************************************************
+ */
+struct mslsa_SecurityDescriptor {
+ BYTE revision;
+ BYTE sbz1;
+ WORD control;
+ DWORD owner;
+ DWORD group;
+ DWORD sacl;
+ DWORD dacl;
+};
+
+
+struct mslsa_SecurityDescInfo {
+ DWORD length;
+ SIZE_IS(length)
+ BYTE *desc; /* temporary */
+ /* struct mslsa_SecurityDescriptor *desc; */
+};
+
+
+OPERATION(LSARPC_OPNUM_QuerySecurityObject)
+struct mslsa_QuerySecurityObject {
+ IN mslsa_handle_t handle;
+ IN DWORD security_info;
+ OUT struct mslsa_SecurityDescInfo *desc_info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumerateAccounts and EnumerateTrustedDomain.
+ ***********************************************************************
+ */
+struct mslsa_AccountInfo {
+ struct mslsa_sid *sid;
+};
+
+
+struct mslsa_EnumAccountBuf {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslsa_AccountInfo *info;
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumerateAccounts)
+struct mslsa_EnumerateAccounts {
+ IN mslsa_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT REFERENCE struct mslsa_EnumAccountBuf *enum_buf;
+ OUT DWORD status;
+};
+
+
+struct mslsa_TrustedDomainInfo {
+ mslsa_string_t name;
+ struct mslsa_sid *sid;
+};
+
+
+struct mslsa_EnumTrustedDomainBuf {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslsa_TrustedDomainInfo *info;
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumTrustedDomain)
+struct mslsa_EnumTrustedDomain {
+ IN mslsa_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT REFERENCE struct mslsa_EnumTrustedDomainBuf *enum_buf;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Definitions common to both LookupSids and LookupNames. Both return
+ * an mslsa_domain_table[]. Each interface also returns a specific
+ * table with entries which index the mslsa_domain_table[].
+ ***********************************************************************
+ */
+struct mslsa_domain_entry {
+ mslsa_string_t domain_name;
+ struct mslsa_sid *domain_sid;
+};
+typedef struct mslsa_domain_entry mslsa_domain_entry_t;
+
+
+struct mslsa_domain_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ mslsa_domain_entry_t *entries;
+ DWORD max_n_entry;
+};
+
+
+/*
+ ***********************************************************************
+ * Definitions for LookupSids.
+ *
+ * The input parameters are:
+ *
+ * A valid LSA handle obtained from an LsarOpenPolicy.
+ * The table of SIDs to be looked up.
+ * A table of names (probably empty).
+ * The lookup level (local=1 or PDC=2).
+ * An enumeration counter (used for continuation operations).
+ *
+ * The output results are:
+ *
+ * A table of referenced domains.
+ * A table of usernames.
+ * The updated value of the enumeration counter.
+ * The result status.
+ ***********************************************************************
+ */
+
+struct mslsa_lup_sid_entry {
+ struct mslsa_sid *psid;
+};
+
+struct mslsa_lup_sid_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct mslsa_lup_sid_entry *entries;
+};
+
+struct mslsa_name_entry {
+ WORD sid_name_use;
+ WORD unknown_flags;
+ mslsa_string_t name;
+ DWORD domain_ix; /* -1 means none */
+};
+
+struct mslsa_name_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct mslsa_name_entry *entries;
+};
+
+OPERATION(LSARPC_OPNUM_LookupSids)
+struct mslsa_LookupSids {
+ IN mslsa_handle_t handle;
+ IN struct mslsa_lup_sid_table lup_sid_table;
+
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct mslsa_name_table name_table;
+
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Definitions for LookupNames.
+ *
+ * LookupNames requires the following input parameters.
+ *
+ * A valid LSA handle obtained from an LsarOpenPolicy.
+ * The table of names to be looked up.
+ * A table of translated sids (probably empty).
+ * The lookup level (local=1 or PDC=2).
+ * An enumeration counter (used for continuation operations).
+ *
+ * The outputs are as follows.
+ *
+ * A table of referenced domains.
+ * A table of translated sids (actually rids).
+ * The updated value of the enumeration counter.
+ * The result status.
+ ***********************************************************************
+ */
+struct mslsa_lup_name_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ mslsa_string_t names[ANY_SIZE_ARRAY];
+};
+
+
+struct mslsa_rid_entry {
+ WORD sid_name_use;
+ WORD pad; /* alignment - probably not required */
+ DWORD rid;
+ DWORD domain_index;
+};
+
+
+struct mslsa_rid_table {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct mslsa_rid_entry *rids;
+};
+
+
+OPERATION(LSARPC_OPNUM_LookupNames)
+struct mslsa_LookupNames {
+ IN mslsa_handle_t handle;
+ IN REFERENCE struct mslsa_lup_name_table *name_table;
+
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct mslsa_rid_table translated_sids;
+
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryInfoPolicy returns various pieces of policy information. The
+ * desired information is specified using a class value, as defined
+ * below.
+ ***********************************************************************
+ */
+#define MSLSA_POLICY_UNKNOWN_1_INFO 1
+#define MSLSA_POLICY_UNKNOWN_2_INFO 2
+#define MSLSA_POLICY_PRIMARY_DOMAIN_INFO 3
+#define MSLSA_POLICY_UNKNOWN_4_INFO 4
+#define MSLSA_POLICY_ACCOUNT_DOMAIN_INFO 5
+#define MSLSA_POLICY_SERVER_ROLE_INFO 6
+#define MSLSA_POLICY_REPLICA_SOURCE_INFO 7
+#define MSLSA_POLICY_DEFAULT_QUOTA_INFO 8
+
+
+struct mslsa_PrimaryDomainInfo {
+ struct mslsa_string_desc name;
+ struct mslsa_sid *sid;
+};
+
+
+struct mslsa_AccountDomainInfo {
+ struct mslsa_string_desc name;
+ struct mslsa_sid *sid;
+};
+
+/*
+struct mslsa_ServerRoleInfo {
+ WORD unknown_0x0003;
+ WORD unknown_0x000e;
+};
+*/
+
+union mslsa_PolicyInfoResUnion {
+ CASE(3) struct mslsa_PrimaryDomainInfo pd_info;
+ CASE(5) struct mslsa_AccountDomainInfo ad_info;
+ DEFAULT char *nullptr;
+};
+
+
+struct mslsa_PolicyInfo {
+ WORD switch_value;
+ SWITCH(switch_value)
+ union mslsa_PolicyInfoResUnion ru;
+};
+
+
+OPERATION(LSARPC_OPNUM_QueryInfoPolicy)
+struct mslsa_QueryInfoPolicy {
+ IN mslsa_handle_t handle;
+ IN WORD info_class;
+ OUT struct mslsa_PolicyInfo *info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenAccount.
+ *
+ * Returns a handle that can be used to access the account specified
+ * by a SID. This handle can be used to enumerate account privileges.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_OpenAccount)
+struct mslsa_OpenAccount {
+ IN mslsa_handle_t handle;
+ IN REFERENCE struct mslsa_sid *sid;
+ IN DWORD access_mask;
+ OUT mslsa_handle_t account_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumPrivilegesAccount.
+ *
+ * Enumerate the list of privileges held by the specified account. The
+ * handle must be a valid account handle obtained via OpenAccount. The
+ * luid values returned will be probably only be relevant on the domain
+ * controller so we'll need to find a way to convert them to the
+ * actual privilege names.
+ ***********************************************************************
+ */
+struct mslsa_LuidAndAttributes {
+ struct mslsa_luid luid;
+ DWORD attributes;
+};
+
+
+struct mslsa_PrivilegeSet {
+ DWORD privilege_count;
+ DWORD control;
+ SIZE_IS(privilege_count)
+ struct mslsa_LuidAndAttributes privilege[ANY_SIZE_ARRAY];
+};
+
+
+OPERATION(LSARPC_OPNUM_EnumPrivsAccount)
+ struct mslsa_EnumPrivsAccount {
+ IN mslsa_handle_t account_handle;
+ OUT struct mslsa_PrivilegeSet *privileges;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupPrivValue
+ *
+ * Map a privilege name to a local unique id (LUID). Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * The privilege list is provided as a set of LUIDs so the privilege
+ * lookup functions must be used to identify which the privilege to
+ * which each LUID refers. The handle here is a policy handle.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_LookupPrivValue)
+struct mslsa_LookupPrivValue {
+ IN mslsa_handle_t handle;
+ IN mslsa_string_t name;
+ OUT struct mslsa_luid luid;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupPrivName
+ *
+ * Map a privilege value (LUID) to a privilege name. Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * The privilege list is provided as a set of LUIDs so the privilege
+ * lookup functions must be used to identify which the privilege to
+ * which each LUID refers. The handle here is a policy handle.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_LookupPrivName)
+struct mslsa_LookupPrivName {
+ IN mslsa_handle_t handle;
+ IN struct mslsa_luid luid;
+ OUT mslsa_string_t *name;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupPrivDisplayName
+ *
+ * Map a privilege name to a local unique id (LUID). Privilege names
+ * are consistent across the network. LUIDs are machine specific.
+ * The privilege list is provided as a set of LUIDs so the privilege
+ * lookup functions must be used to identify which the privilege to
+ * which each LUID refers. The handle here is a policy handle.
+ ***********************************************************************
+ */
+OPERATION(LSARPC_OPNUM_LookupPrivDisplayName)
+struct mslsa_LookupPrivDisplayName {
+ IN mslsa_handle_t handle;
+ IN mslsa_string_t name;
+ IN WORD client_language;
+ IN WORD default_language;
+ OUT mslsa_string_t *display_name;
+ OUT WORD language_ret;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * GetConnectedUser
+ *
+ * This is still guesswork. Netmon doesn't know about this
+ * call and I'm not really sure what it is intended to achieve.
+ * Another packet capture application, Ethereal, calls this RPC as
+ * GetConnectedUser.
+ * We will receive our own hostname in the request and it appears
+ * we should respond with an account name and the domain name of connected
+ * user from the client that makes this call.
+ ***********************************************************************
+ */
+
+struct mslsa_DomainName {
+ struct mslsa_string_desc *name;
+};
+
+
+OPERATION(LSARPC_OPNUM_GetConnectedUser)
+struct mslsa_GetConnectedUser {
+ IN LPTSTR hostname;
+ IN BYTE *unknown1;
+ IN BYTE *unknown2;
+ OUT struct mslsa_string_desc *owner;
+ OUT struct mslsa_DomainName *domain;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LSARPC_OPNUM_LookupSids2
+ *
+ * SID lookup function that appeared in Windows 2000. It appears to be
+ * very similar to the original SID lookup RPC. There are two extra IN
+ * parameters, which we don't care about. The OUT name structure has
+ * an extra field, in which zero seems to be okay.
+ ***********************************************************************
+ */
+struct lsar_name_entry2 {
+ WORD sid_name_use;
+ WORD unknown_flags; /* maybe alignment */
+ mslsa_string_t name;
+ DWORD domain_ix; /* -1 means none */
+ DWORD unknown; /* added */
+};
+
+
+struct lsar_name_table2 {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct lsar_name_entry2 *entries;
+};
+
+
+OPERATION(LSARPC_OPNUM_LookupSids2)
+struct lsar_lookup_sids2 {
+ IN mslsa_handle_t policy_handle;
+ IN struct mslsa_lup_sid_table lup_sid_table;
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct lsar_name_table2 name_table;
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ IN DWORD zero;
+ IN DWORD requested_count;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LSARPC_OPNUM_LookupNames2
+ *
+ * Name lookup function that appeared in Windows 2000. It appears to be
+ * very similar to the original name lookup RPC. There are two extra IN
+ * parameters, which we don't care about. The lsar_rid_entry2 structure
+ * has an extra field, in which zero seems to be okay.
+ ***********************************************************************
+ */
+struct lsar_rid_entry2 {
+ WORD sid_name_use;
+ WORD pad; /* alignment - probably not required */
+ DWORD rid;
+ DWORD domain_index; /* -1 means none */
+ DWORD unknown; /* new */
+};
+
+
+struct lsar_rid_table2 {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct lsar_rid_entry2 *rids;
+};
+
+
+OPERATION(LSARPC_OPNUM_LookupNames2)
+struct lsar_LookupNames2 {
+ IN mslsa_handle_t policy_handle;
+ IN REFERENCE struct mslsa_lup_name_table *name_table;
+ OUT struct mslsa_domain_table *domain_table;
+ INOUT struct lsar_rid_table2 translated_sids;
+ IN DWORD lookup_level;
+ INOUT DWORD mapped_count;
+ IN DWORD unknown_sbz;
+ IN DWORD unknown_sb2;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * This is a generic discovery entry. As long as the handle is valid
+ * this is useful for scoping the network to discover new worlds. To
+ * seek out new life, new civilizations. To boldly spilt infinitives
+ * where no man has gone before. So basically we send and receive a
+ * big buffer and let netmon tell us to which RPC the opnum refers.
+ ***********************************************************************
+ */
+
+#define LSA_DISCOVERY_SIZE 16
+
+
+OPERATION(LSARPC_OPNUM_Discovery)
+struct mslsa_Discovery {
+ IN mslsa_handle_t handle;
+ IN DWORD in_stuff[LSA_DISCOVERY_SIZE];
+ OUT DWORD out_stuff[LSA_DISCOVERY_SIZE];
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The LSARPC interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union lsarpc_interface {
+ CASE(LSARPC_OPNUM_CloseHandle)
+ struct mslsa_CloseHandle CloseHandle;
+ CASE(LSARPC_OPNUM_QuerySecurityObject)
+ struct mslsa_QuerySecurityObject QuerySecurityObj;
+ CASE(LSARPC_OPNUM_EnumerateAccounts)
+ struct mslsa_EnumerateAccounts EnumAccounts;
+ CASE(LSARPC_OPNUM_EnumTrustedDomain)
+ struct mslsa_EnumTrustedDomain EnumTrustedDomain;
+ CASE(LSARPC_OPNUM_OpenAccount)
+ struct mslsa_OpenAccount OpenAccount;
+ CASE(LSARPC_OPNUM_EnumPrivsAccount)
+ struct mslsa_EnumPrivsAccount EnumPrivsAccount;
+ CASE(LSARPC_OPNUM_LookupPrivValue)
+ struct mslsa_LookupPrivValue LookupPrivValue;
+ CASE(LSARPC_OPNUM_LookupPrivName)
+ struct mslsa_LookupPrivName LookupPrivName;
+ CASE(LSARPC_OPNUM_LookupPrivDisplayName)
+ struct mslsa_LookupPrivDisplayName LookupPrivDisplayName;
+ CASE(LSARPC_OPNUM_Discovery)
+ struct mslsa_Discovery Discovery;
+ CASE(LSARPC_OPNUM_QueryInfoPolicy)
+ struct mslsa_QueryInfoPolicy QueryInfoPolicy;
+ CASE(LSARPC_OPNUM_OpenPolicy)
+ struct mslsa_OpenPolicy OpenPolicy;
+ CASE(LSARPC_OPNUM_OpenPolicy2)
+ struct mslsa_OpenPolicy2 OpenPolicy2;
+ CASE(LSARPC_OPNUM_LookupSids)
+ struct mslsa_LookupSids LookupSids;
+ CASE(LSARPC_OPNUM_LookupNames)
+ struct mslsa_LookupNames LookupNames;
+ CASE(LSARPC_OPNUM_GetConnectedUser)
+ struct mslsa_GetConnectedUser GetConnectedUser;
+ CASE(LSARPC_OPNUM_LookupSids2)
+ struct lsar_lookup_sids2 LookupSids2;
+ CASE(LSARPC_OPNUM_LookupNames2)
+ struct lsar_LookupNames2 LookupNames2;
+};
+typedef union lsarpc_interface lsarpc_interface_t;
+EXTERNTYPEINFO(lsarpc_interface)
+
+#endif /* _MLSVC_LSA_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl b/usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl
new file mode 100644
index 0000000000..ec3b76c978
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/ndrtypes.ndl
@@ -0,0 +1,166 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NDR_TYPES_NDL_
+#define _NDR_TYPES_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define TYPEINFO(TYPE) ndt__##TYPE
+
+#ifdef NDRGEN
+
+#define ALIGN(X) [align(X)]
+#define OPERATION(X) [operation(X)]
+#define IN [in]
+#define OUT [out]
+#define INOUT [in out]
+
+#define STRING [string]
+#define SIZE_IS(X) [size_is(X)]
+
+#define SWITCH(X) [switch_is(X)]
+#define CASE(X) [case(X)]
+#define DEFAULT [default]
+
+#define INTERFACE(X) [interface(X)]
+#define UUID(X) [uuid(X)]
+
+#define ARG_IS(X) [arg_is(X)]
+
+#define REFERENCE [reference]
+
+#define ANY_SIZE_ARRAY *
+
+#define IMPORT_EXTERN [extern]
+
+#define BYTE uchar
+#define WORD ushort
+#define DWORD ulong
+
+#define LPTSTR STRING wchar *
+
+#define LPBYTE uchar *
+#define LPWORD ushort *
+#define LPDWORD ulong *
+
+#define EXTERNTYPEINFO(TYPE)
+
+#else /* NDRGEN */
+
+#define ALIGN(X)
+#define OPERATION(X)
+#define IN
+#define OUT
+#define INOUT
+
+#define STRING
+#define SIZE_IS(X)
+
+#define SWITCH(X)
+#define CASE(X)
+#define DEFAULT
+
+#define INTERFACE(X)
+#define UUID(X)
+
+#define ARG_IS(X)
+
+#define REFERENCE
+
+
+#ifndef ANY_SIZE_ARRAY
+#define ANY_SIZE_ARRAY 1
+#endif /* ANY_SIZE_ARRAY */
+
+
+#define IMPORT_EXTERN
+
+
+#ifndef UNSIGNED_TYPES_DEFINED
+#define UNSIGNED_TYPES_DEFINED
+
+#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned long
+#define LPTSTR unsigned char *
+#define LPBYTE unsigned char *
+#define LPWORD unsigned short *
+#define LPDWORD unsigned long *
+
+#endif /* UNSIGNED_TYPES_DEFINED */
+
+
+#define EXTERNTYPEINFO(TYPE) extern struct ndr_typeinfo TYPEINFO(TYPE);
+
+
+/*
+ ***********************************************************************
+ * There is a bug in the way that midl and the marshalling code handles
+ * unions so we need to fix some of the data offsets at runtime. The
+ * following macros and the fixup function handle the correction.
+ ***********************************************************************
+ */
+
+/*
+ * DECL_FIXUP_STRUCT allows us to declare external references to data
+ * structures generated by ndrgen in the _ndr.c file.
+ */
+#define DECL_FIXUP_STRUCT(NAME) \
+ extern struct ndr_typeinfo ndt__##NAME
+
+/*
+ * CASE_INFO_ENT is intended to simplify the declaration of the case
+ * statement in the fixup function. Assuming you have followed the
+ * convention for naming the individual structures all you have to do
+ * is add a single line to the fixup function for each new case.
+ */
+#define CASE_INFO_ENT(NAME,N) \
+ case N: size1 = sizeof (struct NAME##N); \
+ break
+
+/*
+ * FIXUP_PDU_SIZE is used to patch the appropriate structures (identified
+ * by DECL_FIXUP_STRUCT) at runtime. The values are based on the
+ * switch_index.
+ */
+#define FIXUP_PDU_SIZE(NAME,SIZE) { \
+ ndt__##NAME.pdu_size_fixed_part = SIZE; \
+ ndt__##NAME.c_size_fixed_part = SIZE; \
+}
+
+
+#endif /* NDRGEN */
+
+/*
+ * UNION_INFO_ENT is intended to simplify adding new entries to a union.
+ * If the entry structures are named using the form FunctionNameX,
+ * where X is the sitch_value, you can just add a single line. Note
+ * that you must also update the fixup function in mlsvc_xxx.c.
+ */
+#define UNION_INFO_ENT(N,NAME) CASE(N) struct NAME##N info##N
+#define UNION_INFO_PTR(N,NAME) CASE(N) struct NAME##N *info##N
+
+#endif /* _NDR_TYPES_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/netdfs.ndl b/usr/src/uts/common/smbsrv/ndl/netdfs.ndl
new file mode 100644
index 0000000000..a2f86b452d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/netdfs.ndl
@@ -0,0 +1,493 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETDFS_NDL_
+#define _NETDFS_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Distributed File Service (NETDFS) RPC interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define NETDFS_ABSTRACT_UUID "4fc742e0-4a10-11cf-827300aa004ae673"
+#define NETDFS_ABSTRACT_VERS 3
+
+#define NETDFS_TRANSFER_UUID "8a885d04-1ceb-11c9-9fe808002b104860"
+#define NETDFS_TRANSFER_VERS 2
+
+#define NETDFS_OPNUM_GETVER 0x00
+#define NETDFS_OPNUM_ADD 0x01
+#define NETDFS_OPNUM_REMOVE 0x02
+#define NETDFS_OPNUM_SETINFO 0x03
+#define NETDFS_OPNUM_GETINFO 0x04
+#define NETDFS_OPNUM_ENUM 0x05
+#define NETDFS_OPNUM_RENAME 0x06
+#define NETDFS_OPNUM_MOVE 0x07
+#define NETDFS_OPNUM_ADDSTDROOT 0x0c
+#define NETDFS_OPNUM_REMSTDROOT 0x0d
+#define NETDFS_OPNUM_ENUMEX 0x15
+
+#define DFS_MANAGER_VERSION_NT4 0x01
+#define DFS_MANAGER_VERSION_W2K 0x02
+#define DFS_MANAGER_VERSION_W2K3 0x04
+
+
+#define DFS_PROP_FLAG_INSITE_REFERRALS 0x01
+#define DFS_PROP_FLAG_ROOT_SCALABILITY 0x02
+#define DFS_PROP_FLAG_SITE_COSTING 0x04
+#define DFS_PROP_FLAG_TARGET_FAILBACK 0x08
+#define DFS_PROP_FLAG_CLUSTER_ENABLED 0x10
+
+
+#define DFS_STORAGE_PRI_INVALID -1
+#define DFS_STORAGE_PRI_SITE_COST_NORM 0
+#define DFS_STORAGE_PRI_GLOBAL_HIGH 1
+#define DFS_STORAGE_PRI_SITE_COST_HIGH 2
+#define DFS_STORAGE_PRI_SITE_COST_LOW 3
+#define DFS_STORAGE_PRI_GLOBAL_LOW 4
+
+
+struct netdfs_storage_info {
+ DWORD state;
+ LPTSTR server;
+ LPTSTR share;
+};
+
+
+struct netdfs_storage_info2 {
+ DWORD state;
+ LPTSTR server;
+ LPTSTR share;
+ DWORD priority;
+ DWORD rank;
+};
+
+struct netdfs_info1 {
+ LPTSTR entry_path;
+};
+
+
+struct netdfs_info2 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD n_store;
+};
+
+
+struct netdfs_info3 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD n_store;
+ SIZE_IS(n_store)
+ struct netdfs_storage_info *si;
+};
+
+
+struct netdfs_info4 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD timeout;
+ DWORD guuid[4];
+ DWORD n_store;
+ SIZE_IS(n_store)
+ struct netdfs_storage_info *si;
+};
+
+
+struct netdfs_info6 {
+ LPTSTR entry_path;
+ LPTSTR comment;
+ DWORD state;
+ DWORD timeout;
+ DWORD guuid[4];
+ DWORD flags;
+ DWORD pktsize;
+ DWORD n_store;
+ SIZE_IS(n_store)
+ struct netdfs_storage_info2 *si;
+};
+
+
+struct netdfs_info100 {
+ LPTSTR comment;
+};
+
+
+struct netdfs_info101 {
+ DWORD state;
+};
+
+
+struct netdfs_info102 {
+ DWORD timeout;
+};
+
+
+struct netdfs_info103 {
+ DWORD property_flags;
+};
+
+
+struct netdfs_info104 {
+ DWORD priority_class;
+ DWORD priority_rank;
+};
+
+
+struct netdfs_info105 {
+ LPTSTR comment;
+ DWORD volume_state;
+ DWORD timeout;
+ DWORD property_flag_mask;
+ DWORD property_flags;
+};
+
+
+struct netdfs_info106 {
+ DWORD storage_state;
+ DWORD priority_class;
+ DWORD priority_rank;
+};
+
+
+struct netdfs_info200 {
+ LPTSTR entry_path;
+};
+
+
+struct netdfs_info300 {
+ DWORD flavor;
+ LPTSTR entry_path;
+};
+
+
+union netdfs_info_u {
+ CASE(1) struct netdfs_info1 *info1;
+ CASE(2) struct netdfs_info2 *info2;
+ CASE(3) struct netdfs_info3 *info3;
+ CASE(4) struct netdfs_info4 *info4;
+ CASE(6) struct netdfs_info6 *info6;
+ CASE(100) struct netdfs_info100 *info100;
+ CASE(101) struct netdfs_info101 *info101;
+ CASE(102) struct netdfs_info102 *info102;
+ CASE(103) struct netdfs_info103 *info103;
+ CASE(104) struct netdfs_info104 *info104;
+ CASE(105) struct netdfs_info105 *info105;
+ CASE(106) struct netdfs_info106 *info106;
+ DEFAULT char *nullptr;
+};
+
+
+struct netdfs_info {
+ DWORD level;
+ SWITCH(level)
+ union netdfs_info_u iu;
+};
+
+
+struct netdfs_array1 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info1 *info1;
+};
+
+struct netdfs_array2 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info2 *info2;
+};
+
+struct netdfs_array3 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info3 *info3;
+};
+
+struct netdfs_array4 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info4 *info4;
+};
+
+struct netdfs_array6 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info6 *info6;
+};
+
+struct netdfs_array200 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info200 *info200;
+};
+
+struct netdfs_array300 {
+ DWORD count;
+ SIZE_IS(count)
+ struct netdfs_info300 *info300;
+};
+
+union netdfs_enum_info_u {
+ CASE(1) struct netdfs_array1 *info1;
+ CASE(2) struct netdfs_array2 *info2;
+ CASE(3) struct netdfs_array3 *info3;
+ CASE(4) struct netdfs_array4 *info4;
+ CASE(6) struct netdfs_array6 *info6;
+ CASE(200) struct netdfs_array200 *info200;
+ CASE(300) struct netdfs_array300 *info300;
+ DEFAULT char *nullptr;
+};
+
+
+struct netdfs_enum_info {
+ DWORD address;
+ DWORD level;
+ SWITCH(level)
+ union netdfs_enum_info_u iu;
+};
+
+
+/*
+ ***********************************************************************
+ * Return server version id
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_GETVER)
+struct netdfs_getver {
+ OUT DWORD version;
+};
+
+
+/*
+ ***********************************************************************
+ * Add a new volume or additional storage for an existing volume at
+ * dfs_path.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ADD)
+struct netdfs_add {
+ IN REFERENCE LPTSTR dfs_path;
+ IN REFERENCE LPTSTR server;
+ IN LPTSTR share;
+ IN LPTSTR comment;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Remove a volume or additional storage for volume from the DFS at
+ * dfs_path. When applied to the last storage in a volume, removes
+ * the volume from the DFS.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_REMOVE)
+struct netdfs_remove {
+ IN REFERENCE LPTSTR dfs_path;
+ IN LPTSTR server;
+ IN LPTSTR share;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Set information about the volume or storage. If the server and share
+ * are specified, the information set is specific to that server and
+ * share. Otherwise the information is specific to the volume as a whole.
+ *
+ * Valid levels are 100-102.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_SETINFO)
+struct netdfs_setinfo {
+ IN REFERENCE LPTSTR dfs_path;
+ IN LPTSTR server;
+ IN LPTSTR share;
+ IN DWORD level;
+ IN struct netdfs_info info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Get information about the volume or storage. If the server and share
+ * are specified, the information returned is specific to that server
+ * and share. Otherwise the information is specific to the volume as a
+ * whole.
+ *
+ * Valid levels are 1-4, 100-102.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_GETINFO)
+struct netdfs_getinfo {
+ IN REFERENCE LPTSTR dfs_path;
+ IN LPTSTR server;
+ IN LPTSTR share;
+ IN DWORD level;
+ OUT struct netdfs_info info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Get information about all of the volumes in the DFS. dfs_path is
+ * the "server" part of the UNC name used to refer to this particular
+ * DFS.
+ *
+ * Valid levels are 1-3.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ENUM)
+struct netdfs_enum {
+ IN DWORD level;
+ IN DWORD pref_max_len;
+ INOUT struct netdfs_enum_info *info;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Rename the current Win32 path in a DFS to a new Win32 path in the
+ * same DFS.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_RENAME)
+struct netdfs_rename {
+ IN REFERENCE LPTSTR dfs_path;
+ IN REFERENCE LPTSTR new_path;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Move a DFS volume and all subordinate volumes from one place in the
+ * DFS to another place in the DFS.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_MOVE)
+struct netdfs_move {
+ IN REFERENCE LPTSTR dfs_path;
+ IN REFERENCE LPTSTR new_path;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Add a DFS root share.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ADDSTDROOT)
+struct netdfs_addstdroot {
+ IN REFERENCE LPTSTR server;
+ IN REFERENCE LPTSTR share;
+ IN REFERENCE LPTSTR comment;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * Remove a DFS root share.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_REMSTDROOT)
+struct netdfs_remstdroot {
+ IN REFERENCE LPTSTR server;
+ IN REFERENCE LPTSTR share;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Get information about all of the volumes in the DFS. dfs_path is
+ * the "server" part of the UNC name used to refer to this particular
+ * DFS.
+ *
+ * Valid levels are 1-3.
+ ***********************************************************************
+ */
+OPERATION(NETDFS_OPNUM_ENUMEX)
+struct netdfs_enumex {
+ IN REFERENCE LPTSTR dfs_path;
+ IN DWORD level;
+ IN DWORD pref_max_len;
+ INOUT struct netdfs_enum_info *info;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The NETDFS interface definiton.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union netdfs_interface {
+ CASE(NETDFS_OPNUM_GETVER)
+ struct netdfs_getver netdfs_getver;
+ CASE(NETDFS_OPNUM_ADD)
+ struct netdfs_add netdfs_add;
+ CASE(NETDFS_OPNUM_REMOVE)
+ struct netdfs_remove netdfs_remove;
+ CASE(NETDFS_OPNUM_SETINFO)
+ struct netdfs_setinfo netdfs_setinfo;
+ CASE(NETDFS_OPNUM_GETINFO)
+ struct netdfs_getinfo netdfs_getinfo;
+ CASE(NETDFS_OPNUM_ENUM)
+ struct netdfs_enum netdfs_enum;
+ CASE(NETDFS_OPNUM_MOVE)
+ struct netdfs_move netdfs_move;
+ CASE(NETDFS_OPNUM_RENAME)
+ struct netdfs_rename netdfs_rename;
+ CASE(NETDFS_OPNUM_ADDSTDROOT)
+ struct netdfs_addstdroot netdfs_addstdroot;
+ CASE(NETDFS_OPNUM_REMSTDROOT)
+ struct netdfs_remstdroot netdfs_remstdroot;
+ CASE(NETDFS_OPNUM_ENUMEX)
+ struct netdfs_enumex netdfs_enumex;
+};
+typedef union netdfs_interface netdfs_interface_t;
+EXTERNTYPEINFO(netdfs_interface)
+
+
+#endif /* _NETDFS_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/netlogon.ndl b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
new file mode 100644
index 0000000000..e37ee4ca8c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl
@@ -0,0 +1,395 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_NETR_NDL_
+#define _MLSVC_NETR_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ ***********************************************************************
+ *
+ * NetLogon RPC (NETR) interface definition.
+ *
+ ***********************************************************************
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define NETR_OPNUM_SamLogon 0x02
+#define NETR_OPNUM_SamLogoff 0x03
+#define NETR_OPNUM_ServerReqChallenge 0x04
+#define NETR_OPNUM_ServerPasswordSet 0x06
+#define NETR_OPNUM_LogonControl2 0x0E
+#define NETR_OPNUM_ServerAuthenticate2 0x0F
+#define NETR_OPNUM_TrustDomainList 0x13
+
+
+struct netr_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[6];
+ SIZE_IS(SubAuthCount)
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+};
+
+
+struct netr_string {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct netr_string netr_string_t;
+
+
+/*
+ * Alternative varying/conformant string definition - for
+ * non-null terminated strings. This definition must match
+ * mlrpc_vcbuf_t.
+ */
+struct netr_vcb {
+ /*
+ * size_is (actually a copy of length_is) will
+ * be inserted here by the marshalling library.
+ */
+ DWORD vc_first_is;
+ DWORD vc_length_is;
+ SIZE_IS(vc_length_is)
+ WORD buffer[ANY_SIZE_ARRAY];
+};
+
+struct netr_vcbuf {
+ WORD wclen;
+ WORD wcsize;
+ struct netr_vcb *vcb;
+};
+typedef struct netr_vcbuf netr_vcbuf_t;
+
+
+struct netr_credential {
+ BYTE data[8];
+};
+
+
+struct netr_authenticator {
+ struct netr_credential credential;
+ DWORD timestamp;
+};
+typedef struct netr_authenticator netr_auth_t;
+
+
+struct OLD_LARGE_INTEGER {
+ DWORD LowPart;
+ DWORD HighPart;
+};
+typedef struct OLD_LARGE_INTEGER netr_int64_t;
+
+
+struct OWF_PASSWORD {
+ BYTE data[16];
+};
+typedef struct OWF_PASSWORD netr_owf_password_t;
+
+
+struct CYPHER_BLOCK {
+ BYTE data[8];
+};
+
+
+struct USER_SESSION_KEY {
+ struct CYPHER_BLOCK data[2];
+};
+
+
+
+
+/*
+ ***********************************************************************
+ * ServerReqChallenge
+ ***********************************************************************
+ */
+ALIGN(2)
+OPERATION(NETR_OPNUM_ServerReqChallenge)
+struct netr_ServerReqChallenge {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR hostname;
+ IN struct netr_credential client_challenge;
+ OUT struct netr_credential server_challenge;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * ServerAuthenticate2
+ ***********************************************************************
+ */
+ALIGN(2)
+OPERATION(NETR_OPNUM_ServerAuthenticate2)
+struct netr_ServerAuthenticate2 {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR account_name;
+ IN WORD account_type;
+ IN REFERENCE LPTSTR hostname;
+ IN struct netr_credential client_credential;
+ OUT struct netr_credential server_credential;
+ INOUT DWORD negotiate_flags;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * ServerPasswordSet
+ ***********************************************************************
+ */
+ALIGN(2)
+OPERATION(NETR_OPNUM_ServerPasswordSet)
+struct netr_PasswordSet {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR account_name;
+ IN WORD account_type;
+ IN REFERENCE LPTSTR hostname;
+ INOUT struct netr_authenticator auth;
+ IN netr_owf_password_t uas_new_password;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamLogon
+ ***********************************************************************
+ */
+
+/*
+ * The challenge-response data should always be 24 bytes.
+ */
+#define NETR_CR_PASSWORD_SIZE 24
+
+
+struct lm_challenge {
+ BYTE data[8];
+};
+typedef struct lm_challenge lm_challenge_t;
+
+
+struct netr_response {
+ DWORD length;
+ DWORD start;
+ DWORD max_length;
+ BYTE data[NETR_CR_PASSWORD_SIZE];
+};
+typedef struct netr_response netr_response_t;
+
+
+struct netr_response_desc {
+ WORD length;
+ WORD max_length;
+ netr_response_t *data;
+};
+typedef struct netr_response_desc netr_response_desc_t;
+
+/*
+ * Input data
+ */
+struct netr_logon_identity_info {
+ netr_vcbuf_t domain_name;
+ DWORD parameter_control;
+ struct OLD_LARGE_INTEGER logon_id;
+ netr_vcbuf_t username;
+ netr_vcbuf_t workstation;
+};
+typedef struct netr_logon_identity_info netr_logon_id_t;
+
+
+/*
+ * Level 1: interactive logon
+ */
+struct netr_logon_info1 {
+ netr_logon_id_t identity;
+ netr_owf_password_t lm_owf_password;
+ netr_owf_password_t nt_owf_password;
+};
+
+
+/*
+ * Level 2: network logon.
+ */
+struct netr_logon_info2 {
+ netr_logon_id_t identity;
+ lm_challenge_t lm_challenge;
+ netr_response_desc_t nt_response;
+ netr_response_desc_t lm_response;
+};
+
+
+union netr_logon_info_u {
+ UNION_INFO_PTR(1,netr_logon_info);
+ UNION_INFO_PTR(2,netr_logon_info);
+ DEFAULT DWORD nothing;
+};
+
+
+struct netr_login_info {
+ WORD logon_level;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union netr_logon_info_u ru;
+};
+
+
+/*
+ * Output data
+ */
+struct netr_group_membership {
+ DWORD rid;
+ DWORD attributes;
+};
+
+
+struct netr_sid_and_attributes {
+ struct netr_sid *sid;
+ DWORD attributes;
+};
+
+
+struct netr_validation_info3 {
+ struct OLD_LARGE_INTEGER LogonTime;
+ struct OLD_LARGE_INTEGER LogoffTime;
+ struct OLD_LARGE_INTEGER KickOffTime;
+ struct OLD_LARGE_INTEGER PasswordLastSet;
+ struct OLD_LARGE_INTEGER PasswordCanChange;
+ struct OLD_LARGE_INTEGER PasswordMustChange;
+ netr_string_t EffectiveName;
+ netr_string_t FullName;
+ netr_string_t LogonScript;
+ netr_string_t ProfilePath;
+ netr_string_t HomeDirectory;
+ netr_string_t HomeDirectoryDrive;
+ WORD LogonCount;
+ WORD BadPasswordCount;
+ DWORD UserId;
+ DWORD PrimaryGroupId;
+ DWORD GroupCount;
+ SIZE_IS(GroupCount)
+ struct netr_group_membership *GroupIds;
+ DWORD UserFlags;
+ struct USER_SESSION_KEY UserSessionKey;
+ netr_string_t LogonServer;
+ netr_string_t LogonDomainName;
+ struct netr_sid *LogonDomainId;
+ DWORD ExpansionRoom[10];
+ DWORD SidCount;
+ SIZE_IS(SidCount)
+ struct netr_sid_and_attributes *ExtraSids;
+};
+
+
+union netr_validation_u {
+ CASE(3) struct netr_validation_info3 *info3;
+ DEFAULT DWORD nothing;
+};
+
+
+/*
+ * This structure needs to be declared, even though it can't be used
+ * in netr_SamLogon, in order to get the appropriate size to calculate
+ * the correct fixup offsets. If ndrgen did the right thing,
+ * netr_validation_info would be one of the out parameters. However,
+ * if we do it that way, the switch_value isn't known early enough to
+ * do the fixup calculation. So it all has to go in netr_SamLogon.
+ */
+struct netr_validation_info {
+ WORD validation_level;
+ SWITCH(validation_level)
+ union netr_validation_u ru;
+};
+
+
+/*
+ * WARNING
+ *
+ * Validation_level is really a WORD and authoritative is really a
+ * BYTE. They are declared as DWORD here due to the way things are
+ * unmarshalled. NT does not clear out the unused bytes in the
+ * DWORD so they must be cast to get the correct value.
+ */
+OPERATION(NETR_OPNUM_SamLogon)
+struct netr_SamLogon {
+ IN LPTSTR servername;
+ IN LPTSTR hostname;
+ IN struct netr_authenticator *auth;
+ INOUT struct netr_authenticator *ret_auth;
+ IN struct netr_login_info logon_info;
+ INOUT WORD validation_level;
+ SWITCH(validation_level)
+ OUT union netr_validation_u ru;
+ OUT DWORD authoritative;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamLogoff
+ ***********************************************************************
+ */
+OPERATION(NETR_OPNUM_SamLogoff)
+struct netr_SamLogoff {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR hostname;
+ IN struct netr_authenticator auth;
+ INOUT struct netr_authenticator ret_auth;
+ IN DWORD logon_level;
+ SWITCH(logon_level)
+ IN union netr_logon_info_u ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The NETR interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union netr_interface {
+ CASE(NETR_OPNUM_ServerReqChallenge)
+ struct netr_ServerReqChallenge ServerReqChallenge;
+ CASE(NETR_OPNUM_ServerAuthenticate2)
+ struct netr_ServerAuthenticate2 ServerAuthenticate2;
+ CASE(NETR_OPNUM_SamLogon)
+ struct netr_SamLogon SamLogon;
+ CASE(NETR_OPNUM_SamLogoff)
+ struct netr_SamLogoff SamLogoff;
+ CASE(NETR_OPNUM_ServerPasswordSet)
+ struct netr_PasswordSet PasswordSet;
+};
+typedef union netr_interface netr_interface_t;
+EXTERNTYPEINFO(netr_interface)
+
+#endif /* _MLSVC_NETR_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl b/usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl
new file mode 100644
index 0000000000..fd42fcac1c
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/rpcpdu.ndl
@@ -0,0 +1,552 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLRPCPDU_NDL_
+#define _MLRPCPDU_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "ndrtypes.ndl"
+
+/*
+ * Normally, constructs are (un)marshalled atoms first, then
+ * constructs, then pointers. This can be confusing sometimes
+ * when debugging. We know that everything in here can be
+ * safely (un)marshalled in member order, so we say so.
+ */
+#ifdef NDRGEN
+#define _NO_REORDER_ [_no_reorder]
+#else
+#define _NO_REORDER_
+#endif
+
+/*
+ * UUID (Universal Unique IDentifier)
+ */
+/* (X/Open CAE Spec Appendix A) */
+struct mlrpc_uuid_dce {
+ DWORD time_low;
+ WORD time_mid;
+ WORD time_hi_and_version;
+ BYTE clock_seq_hi_and_reserved;
+ BYTE clock_seq_low;
+ BYTE node[6];
+};
+
+struct mlrpc_uuid {
+ DWORD data1;
+ WORD data2;
+ WORD data3;
+ BYTE data4[8];
+};
+typedef struct mlrpc_uuid mlrpc_uuid_t;
+
+/*
+ * Representation label -- needed for RPC header
+ * (X/Open CAE Spec Chapter 14.1)
+ *
+ * Bits Data Type Description
+ * ---- --------- -----------
+ * 0-3 charset 0=ASCII
+ * 1=EBCDIC
+ * 4-7 byte-order 0=big-endian
+ * 1=little-endian
+ * 8-15 float 0=IEEE
+ * 1=VAX
+ * 2=Cray
+ * 3=IBM
+ * 16-31 reserved
+ */
+#define MLRPC_REPLAB_CHAR_MASK 0x0F /* low nibble of intg_char */
+#define MLRPC_REPLAB_CHAR_ASCII 0x00 /* ASCII */
+#define MLRPC_REPLAB_CHAR_EBCDIC 0x01 /* EBCDIC (never happen) */
+#define MLRPC_REPLAB_INTG_MASK 0xF0 /* hi nibble of intg_char */
+#define MLRPC_REPLAB_INTG_BIG_ENDIAN 0x00 /* big endian */
+#define MLRPC_REPLAB_INTG_LITTLE_ENDIAN 0x10 /* little endian (x86) */
+#define MLRPC_REPLAB_FLOAT_IEEE 0x00
+#define MLRPC_REPLAB_FLOAT_VAX 0x01
+#define MLRPC_REPLAB_FLOAT_CRAY 0x02
+#define MLRPC_REPLAB_FLOAT_IBM 0x03
+
+struct mlrpc_representation_label {
+ BYTE intg_char_rep; /* integer and charset */
+ BYTE float_rep;
+ BYTE _spare[2];
+};
+
+
+
+/*
+ * RPC PDU (Protocol Data Unit) types
+ ****************************************************************
+ * (X/Open CAE Spec 12.1)
+ */
+
+#define MLRPC_PTYPE_REQUEST 0x00 /* CO/CL */
+#define MLRPC_PTYPE_PING 0x01 /* CL */
+#define MLRPC_PTYPE_RESPONSE 0x02 /* CO/CL */
+#define MLRPC_PTYPE_FAULT 0x03 /* CL/CL */
+#define MLRPC_PTYPE_WORKING 0x04 /* CL */
+#define MLRPC_PTYPE_NOCALL 0x05 /* CL */
+#define MLRPC_PTYPE_REJECT 0x06 /* CL */
+#define MLRPC_PTYPE_ACK 0x07 /* CL */
+#define MLRPC_PTYPE_CL_CANCEL 0x08 /* CL */
+#define MLRPC_PTYPE_FACK 0x09 /* CL */
+#define MLRPC_PTYPE_CANCEL_ACK 0x0A /* CL */
+#define MLRPC_PTYPE_BIND 0x0B /* CO */
+#define MLRPC_PTYPE_BIND_ACK 0x0C /* CO */
+#define MLRPC_PTYPE_BIND_NAK 0x0D /* CO */
+#define MLRPC_PTYPE_ALTER_CONTEXT 0x0E /* CO */
+#define MLRPC_PTYPE_ALTER_CONTEXT_RESP 0x0F /* CO */
+ /* 0x10 missing from DCE/RPC */
+#define MLRPC_PTYPE_SHUTDOWN 0x11 /* CO */
+#define MLRPC_PTYPE_CO_CANCEL 0x12 /* CO */
+#define MLRPC_PTYPE_ORPHANED 0x13 /* CO */
+
+/*
+ * Flags in the RPC header for Connection-oriented PDU data types
+ * (X/Open CAE Spec 12.6.3.1)
+ */
+#define MLRPC_PFC_FIRST_FRAG 0x01 /* First fragment */
+#define MLRPC_PFC_LAST_FRAG 0x02 /* Last framgent */
+#define MLRPC_PFC_PENDING_CANCEL 0x04 /* Cancel was pending@sender*/
+#define MLRPC_PFC_RESERVED_1 0x08 /* */
+#define MLRPC_PFC_CONC_MPX 0x10 /* supports concurrent muxing
+ * of single connection */
+#define MLRPC_PFC_DID_NOT_EXECUTE 0x20 /* for PTYPE_FAULT, guarantee
+ * call did not execute */
+#define MLRPC_PFC_MAYBE 0x40 /* "maybe" semantics req'ed*/
+#define MLRPC_PFC_OBJECT_UUID 0x80 /* */
+
+
+/*
+ * Header common to all Connection-oriented RPC PDUs
+ ****************************************************************
+ * (X/Open CAE Spec 12.6.3.1)
+ */
+_NO_REORDER_
+struct mlrpcconn_common_header {
+ BYTE rpc_vers; /* 00:01 5 */
+ BYTE rpc_vers_minor; /* 01:01 0 */
+ BYTE ptype; /* 02:01 MLRPC_PTYPE_... */
+ BYTE pfc_flags; /* 03:01 MLRPC_PFC_... */
+ struct mlrpc_representation_label
+ packed_drep; /* 04:04 NDR representation label */
+ WORD frag_length; /* 08:02 total length of frag */
+ WORD auth_length; /* 10:02 length of auth_value */
+ DWORD call_id; /* 12:04 call identifier */
+ /* 16: */
+};
+typedef struct mlrpcconn_common_header mlrpcconn_common_header_t;
+EXTERNTYPEINFO(mlrpcconn_common_header)
+
+
+/*
+ * A plethora of supporting types, only defined the ones we need
+ * (X/Open CAE Spec 12.6.3.1)
+ */
+typedef WORD mlrpc_p_context_id_t;
+
+_NO_REORDER_
+struct mlrpc_p_syntax_id {
+ mlrpc_uuid_t if_uuid;
+ DWORD if_version;
+};
+typedef struct mlrpc_p_syntax_id mlrpc_p_syntax_id_t;
+
+_NO_REORDER_
+struct mlrpc_p_cont_elem {
+ mlrpc_p_context_id_t p_cont_id;
+ BYTE n_transfer_syn;
+ BYTE _reserved;
+ mlrpc_p_syntax_id_t abstract_syntax;
+ /*SIZE_IS(n_transfer_syn)*/
+ mlrpc_p_syntax_id_t transfer_syntaxes[1];
+};
+typedef struct mlrpc_p_cont_elem mlrpc_p_cont_elem_t;
+EXTERNTYPEINFO(mlrpc_p_cont_elem)
+
+_NO_REORDER_
+struct mlrpc_p_cont_list {
+ BYTE n_context_elem;
+ BYTE _reserved;
+ WORD _reserved2;
+ /*SIZE_IS(n_context_elem)*/
+ mlrpc_p_cont_elem_t p_cont_elem[1];
+};
+typedef struct mlrpc_p_cont_list mlrpc_p_cont_list_t;
+EXTERNTYPEINFO(mlrpc_p_cont_list)
+
+typedef WORD mlrpc_p_cont_def_result_t;
+#define MLRPC_PCDR_ACCEPTANCE 0
+#define MLRPC_PCDR_USER_REJECTION 1
+#define MLRPC_PCDR_PROVIDER_REJECTION 2
+
+typedef WORD mlrpc_p_provider_reason_t;
+#define MLRPC_PPR_REASON_NOT_SPECIFIED 0
+#define MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED 1
+#define MLRPC_PPR_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED 2
+#define MLRPC_PPR_LOCAL_LIMIT_EXCEEDED 3
+
+
+_NO_REORDER_
+struct mlrpc_p_result {
+ mlrpc_p_cont_def_result_t result; /* MLRPC_PCDR_... */
+ mlrpc_p_provider_reason_t reason; /* MLRPC_PPR_... */
+ mlrpc_p_syntax_id_t transfer_syntax; /* 0-fill if
+ * result!=ACCEPT*/
+};
+typedef struct mlrpc_p_result mlrpc_p_result_t;
+EXTERNTYPEINFO(mlrpc_p_result)
+
+_NO_REORDER_
+struct mlrpc_p_result_list {
+ BYTE n_results;
+ BYTE reserved;
+ WORD reserved2;
+ /*SIZE_IS(n_results)*/
+ mlrpc_p_result_t p_results[1];
+};
+typedef struct mlrpc_p_result_list mlrpc_p_result_list_t;
+EXTERNTYPEINFO(mlrpc_p_result_list)
+
+#define MLRPC_PORT_ANY_MAX_PORT_SPEC 30
+_NO_REORDER_
+struct mlrpc_port_any {
+ WORD length; /* always 18 */
+ /*SIZE_IS(length)*/
+ BYTE port_spec[MLRPC_PORT_ANY_MAX_PORT_SPEC];
+ /* \PIPE\ntsvcs */
+ /* We cheat by using 18, and pad on the right with zeroes */
+};
+typedef struct mlrpc_port_any mlrpc_port_any_t;
+EXTERNTYPEINFO(mlrpc_port_any)
+
+
+/*
+ * Alter Context PDU (0x0E)
+ * (X/Open CAE Spec 12.6.4.1)
+ */
+_NO_REORDER_
+struct mlrpcconn_alter_context_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 ignored */
+ WORD max_recv_frag; /* 18:02 ignored */
+ DWORD assoc_group_id; /* 20:04 ignored */
+
+ /*
+ * Presentation context list (see bind hdr comments).
+ */
+ mlrpc_p_cont_list_t p_context_elem; /* 24: */
+
+ /* optional authentication verifier if auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_alter_context_hdr mlrpcconn_alter_context_hdr_t;
+
+
+/*
+ * Alter Context Response PDU (0x0F)
+ * (X/Open CAE Spec 12.6.4.2)
+ */
+_NO_REORDER_
+struct mlrpcconn_alter_context_rsp_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 ignored */
+ WORD max_recv_frag; /* 18:02 ignored */
+ DWORD assoc_group_id; /* 20:04 ignored */
+ mlrpc_port_any_t sec_addr; /* 24:20 ignored */
+
+ /*
+ * Presentation context list (see bind hdr comments).
+ */
+ mlrpc_p_result_list_t p_result_list; /* 44:nn */
+
+ /* optional authentication verifier if auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_alter_context_rsp_hdr mlrpcconn_alter_context_rsp_hdr_t;
+
+
+/*
+ * Bind PDU (0x0B)
+ ****************************************************************
+ * (X/Open CAE Spec 12.6.4.3)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_bind_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 max xmit frag size, bytes */
+ WORD max_recv_frag; /* 18:02 max recv frag size, bytes */
+ DWORD assoc_group_id; /* 20:04 incarnation of client-server
+ * association group (???) */
+ /* 24: */
+
+ /* presentation, a variable**2 list, of presentation contexts */
+ mlrpc_p_cont_list_t p_context_elem;
+ /*
+ * This could be follow by more transfer_syntaxes[] for
+ * the p_cont_elem[0], and subsequently followed by
+ * more p_cont_elem[] each with one ore more
+ * transfer_syntaxes[]. The single p_cont_elem[]
+ * with a single transfer_syntaxes[] is so common,
+ * though, we embed such right in the bind_hdr.
+ * The mlrpc_s_bind() processor must walk through
+ * this tail if there is one.
+ */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_bind_hdr mlrpcconn_bind_hdr_t;
+
+
+
+
+/*
+ * Bind_Ack PDU (0x0C)
+ ****************************************************************
+ * (X/Open CAE Spec 12.6.4.4)
+ */
+
+/*
+ * hand coded in mlrpc_encdec.c because sec_addr is an
+ * interior conformant (variable length) array.
+ */
+
+IMPORT_EXTERN /* don't generate function */
+_NO_REORDER_
+struct mlrpcconn_bind_ack_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ WORD max_xmit_frag; /* 16:02 max xmit frag size, bytes */
+ WORD max_recv_frag; /* 18:02 max recv frag size, bytes */
+ DWORD assoc_group_id; /* 20:04 incarnation of client-server
+ * association group (???) */
+ /* 24: */
+
+ mlrpc_port_any_t sec_addr; /* 24:20 */
+
+ mlrpc_p_result_list_t p_result_list; /* 44:nn */
+ /* This could be followed by more. See bind_hdr above */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_bind_ack_hdr mlrpcconn_bind_ack_hdr_t;
+
+
+
+
+/*
+ * Request PDU (0x00)
+ ****************************************************************
+ * Two flavors, selected based on MLRPC_PFC_OBJECT_UUID in hdr.pfc_flags
+ * one without the "object" (flag clear)
+ * one with the "object" (flag set)
+ * (X/Open CAE Spec 12.6.4.9)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_request_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ /* needed for request, response, or fault */
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ WORD opnum; /* 22:02 op number w/i interface */
+
+ /* optional field if PFC_OBJECT_UUID, not present */
+ /* mlrpc_uuid_t object; */
+
+ /* stub-data, 8-octet aligned */ /* 24:nn */
+ /* nn = frag_len - sizeof(common_header) - auth_len */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_request_hdr mlrpcconn_request_hdr_t;
+
+_NO_REORDER_
+struct mlrpcconn_request_hdr_with_object {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ /* needed for request, response, or fault */
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ WORD opnum; /* 22:02 op number w/i interface */
+
+ /* optional field if PFC_OBJECT_UUID, is present */
+ mlrpc_uuid_t object; /* 24:16 object UUID, unknown purpose*/
+
+ /* stub-data, 8-octet aligned */ /* 28:nn */
+ /* nn = frag_len - sizeof(common_header) - auth_len */
+ /* nn -= sizeof(mlrpc_uuid_t); */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+
+
+
+/*
+ * Hack for response header sizing and multi-fragment responses.
+ * We know the header is going to be 24 bytes.
+ */
+#define MLRPC_RSP_HDR_SIZE 24
+
+
+/*
+ * Response PDU (0x02)
+ * (X/Open CAE Spec 12.6.4.10)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_response_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ /* needed for request, response, or fault */
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ /* needed for response or fault */
+ BYTE cancel_count; /* 22:01 cancel count */
+ BYTE reserved; /* 23:01 mbz */
+
+ /* stub-data, 8-octet aligned */ /* 24:nn */
+ /* nn = frag_len - sizeof(common_header) - auth_len */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_response_hdr mlrpcconn_response_hdr_t;
+
+
+
+/*
+ * Fault PDU (0x03)
+ * (X/Open CAE Spec 12.6.4.7)
+ */
+
+_NO_REORDER_
+struct mlrpcconn_fault_hdr {
+ mlrpcconn_common_header_t common_hdr; /* 00:16 (see above) */
+
+ DWORD alloc_hint; /* 16:04 allocation hint */
+ mlrpc_p_context_id_t
+ p_cont_id; /* 20:02 pres context, i.e. data rep */
+
+ /* needed for response or fault */
+ BYTE cancel_count; /* 22:01 cancel count */
+ BYTE reserved; /* 23:01 mbz */
+
+ /* fault code */
+ DWORD status; /* 24:04 run-time fault code or 0 */
+
+ /* pad to 8-byte alignment */
+ BYTE reserved2[4]; /* 28:04 must-be-zero */
+
+ /* stub-data here if status==0. We do not use this mode. */
+
+ /* optional authentication verifier iff auth_length != 0 */
+ /* auth_verifier_co_t auth_verifier; */
+};
+typedef struct mlrpcconn_fault_hdr mlrpcconn_fault_hdr_t;
+
+
+/* Fault status code (X/Open CAE Spec Appendix E) */
+#define MLRPC_FAULT_NCA_RPC_VERSION_MISMATCH 0x1c000008 /* CO/CL */
+#define MLRPC_FAULT_NCA_UNSPEC_REJECT 0x1c000009 /* CO/CL */
+#define MLRPC_FAULT_NCA_S_BAD_ACTID 0x1c00000A /* CL */
+#define MLRPC_FAULT_NCA_WHO_ARE_YOU_FAILED 0x1c00000B /* CL */
+#define MLRPC_FAULT_NCA_MANAGER_NOT_ENTERED 0x1c00000C /* CO/CL */
+#define MLRPC_FAULT_NCA_OP_RNG_ERROR 0x1c010002 /* CO/CL */
+#define MLRPC_FAULT_NCA_UNK_IF 0x1c010003 /* CO/CL */
+#define MLRPC_FAULT_NCA_WRONG_BOOT_TIME 0x1c010006 /* CL */
+#define MLRPC_FAULT_NCA_S_YOU_CRASHED 0x1c010009 /* CL */
+#define MLRPC_FAULT_NCA_PROTO_ERROR 0x1c01000B /* CO/CL */
+#define MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG 0x1c010013 /* CO/CL */
+#define MLRPC_FAULT_NCA_SERVER_TOO_BUSY 0x1c010014 /* CO/CL */
+#define MLRPC_FAULT_NCA_UNSUPPORTED_TYPE 0x1c010017 /* CO/CL */
+#define MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID 0x1c00001c /* CO */
+#define MLRPC_FAULT_NCA_UNSUPPORTED_AUTHN_LEVEL 0x1c00001d /* CO/CL */
+#define MLRPC_FAULT_NCA_INVALID_CHECKSUM 0x1c00001f /* CO/CL */
+#define MLRPC_FAULT_NCA_INVALID_CRC 0x1c000020 /* CO/CL */
+
+
+
+
+/*
+ * The Header Union/Switch
+ ****************************************************************
+ */
+
+#define MLRPC_PTYPE_COMMON 999
+#define MLRPC_PTYPE_REQUEST_WITH 998
+
+
+INTERFACE(0)
+union mlrpcconn_hdr {
+ CASE(MLRPC_PTYPE_COMMON) /* exceeds BYTE range, obtains common hdr */
+ struct mlrpcconn_common_header common_hdr;
+
+ CASE(MLRPC_PTYPE_BIND)
+ struct mlrpcconn_bind_hdr bind_hdr;
+
+ CASE(MLRPC_PTYPE_BIND_ACK)
+ struct mlrpcconn_bind_ack_hdr bind_ack_hdr;
+
+ CASE(MLRPC_PTYPE_REQUEST)
+ struct mlrpcconn_request_hdr request_hdr;
+
+ CASE(MLRPC_PTYPE_REQUEST_WITH) /* exceeds BYTE range, ... */
+ struct mlrpcconn_request_hdr_with_object request_hdr_with;
+
+ CASE(MLRPC_PTYPE_RESPONSE)
+ struct mlrpcconn_response_hdr response_hdr;
+
+ CASE(MLRPC_PTYPE_ALTER_CONTEXT)
+ struct mlrpcconn_alter_context_hdr alter_context_hdr;
+
+ CASE(MLRPC_PTYPE_ALTER_CONTEXT_RESP)
+ struct mlrpcconn_alter_context_rsp_hdr alter_context_rsp_hdr;
+
+ CASE(MLRPC_PTYPE_FAULT)
+ struct mlrpcconn_fault_hdr fault_hdr;
+};
+typedef union mlrpcconn_hdr mlrpcconn_hdr_t;
+EXTERNTYPEINFO(mlrpcconn_hdr)
+
+#endif /* _MLRPCPDU_NDL_ */
+
diff --git a/usr/src/uts/common/smbsrv/ndl/samrpc.ndl b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl
new file mode 100644
index 0000000000..0dfda51186
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl
@@ -0,0 +1,1314 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_SAM_NDL_
+#define _MLSVC_SAM_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Security Accounts Manager RPC (SAMR) interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+
+#define SAMR_OPNUM_ConnectAnon 0x00
+#define SAMR_OPNUM_CloseHandle 0x01
+#define SAMR_OPNUM_QuerySecObject 0x03
+#define SAMR_OPNUM_LookupDomain 0x05
+#define SAMR_OPNUM_EnumLocalDomains 0x06
+#define SAMR_OPNUM_OpenDomain 0x07
+#define SAMR_OPNUM_QueryDomainInfo 0x08
+#define SAMR_OPNUM_CreateDomainGroup 0x0a
+#define SAMR_OPNUM_QueryDomainGroups 0x0b
+#define SAMR_OPNUM_EnumDomainUsers 0x0d
+#define SAMR_OPNUM_CreateDomainAlias 0x0e
+#define SAMR_OPNUM_EnumDomainAliases 0x0f
+#define SAMR_OPNUM_LookupIds 0x10
+#define SAMR_OPNUM_LookupNames 0x11
+#define SAMR_OPNUM_LookupDomainIds 0x12
+#define SAMR_OPNUM_OpenGroup 0x13
+#define SAMR_OPNUM_QueryGroupInfo 0x14
+#define SAMR_OPNUM_StoreGroupInfo 0x15
+#define SAMR_OPNUM_AddGroupMember 0x16
+#define SAMR_OPNUM_DeleteDomainGroup 0x17
+#define SAMR_OPNUM_DeleteGroupMember 0x18
+#define SAMR_OPNUM_ListGroupMembers 0x19
+#define SAMR_OPNUM_OpenAlias 0x1b
+#define SAMR_OPNUM_QueryAliasInfo 0x1c
+#define SAMR_OPNUM_SetAliasInfo 0x1d
+#define SAMR_OPNUM_DeleteDomainAlias 0x1e
+#define SAMR_OPNUM_AddAliasMember 0x1f
+#define SAMR_OPNUM_DeleteAliasMember 0x20
+#define SAMR_OPNUM_QueryAliasMember 0x21
+#define SAMR_OPNUM_OpenUser 0x22
+#define SAMR_OPNUM_DeleteUser 0x23
+#define SAMR_OPNUM_QueryUserInfo 0x24
+#define SAMR_OPNUM_QueryUserGroups 0x27
+#define SAMR_OPNUM_QueryDispInfo 0x28 /* QueryDispInfo1 */
+#define SAMR_OPNUM_GetUserPwInfo 0x2c
+#define SAMR_OPNUM_EnumDomainGroups 0x30 /* QueryDispInfo3 */
+#define SAMR_OPNUM_CreateUser 0x32
+#define SAMR_OPNUM_QueryDispInfo4 0x33
+#define SAMR_OPNUM_AddMultiAliasMember 0x34
+#define SAMR_OPNUM_ChangeUserPasswd 0x37
+#define SAMR_OPNUM_GetDomainPwInfo 0x38
+#define SAMR_OPNUM_Connect 0x39
+#define SAMR_OPNUM_SetUserInfo 0x3a
+#define SAMR_OPNUM_Connect3 0x3e
+#define SAMR_OPNUM_Connect4 0x40
+
+
+/*
+ * UNION_INFO_ENT is intended to simplify adding new entries to a union.
+ * If the entry structures are named using the form samr_QueryUserInfoX,
+ * where X is the sitch_value, you can just add a single line. Note
+ * that you must also update the fixup function in mlsvc_sam.c.
+ */
+#define UNION_INFO_ENT(N,NAME) CASE(N) struct NAME##N info##N
+
+
+/*
+ * Sam account flags used when creating an account. These flags seem
+ * to be very similar to the USER_INFO_X flags (UF_XXX) in lmaccess.h
+ * but the values are different.
+ */
+#define SAMR_AF_ACCOUNTDISABLE 0x0001
+#define SAMR_AF_HOMEDIR_REQUIRED 0x0002
+#define SAMR_AF_PASSWD_NOTREQD 0x0004
+#define SAMR_AF_TEMP_DUPLICATE_ACCOUNT 0x0008
+#define SAMR_AF_NORMAL_ACCOUNT 0x0010
+#define SAMR_AF_MNS_LOGON_ACCOUNT 0x0020
+#define SAMR_AF_INTERDOMAIN_TRUST_ACCOUNT 0x0040
+#define SAMR_AF_WORKSTATION_TRUST_ACCOUNT 0x0080
+#define SAMR_AF_SERVER_TRUST_ACCOUNT 0x0100
+#define SAMR_AF_DONT_EXPIRE_PASSWD 0x0200
+#define SAMR_AF_ACCOUNT_AUTOLOCK 0x0400
+
+
+#define SAMR_AF_MACHINE_ACCOUNT_MASK ( \
+ SAMR_AF_INTERDOMAIN_TRUST_ACCOUNT \
+ | SAMR_AF_WORKSTATION_TRUST_ACCOUNT \
+ | SAMR_AF_SERVER_TRUST_ACCOUNT)
+
+#define SAMR_AF_ACCOUNT_TYPE_MASK ( \
+ SAMR_AF_TEMP_DUPLICATE_ACCOUNT \
+ | SAMR_AF_NORMAL_ACCOUNT \
+ | SAMR_AF_INTERDOMAIN_TRUST_ACCOUNT \
+ | SAMR_AF_WORKSTATION_TRUST_ACCOUNT \
+ | SAMR_AF_SERVER_TRUST_ACCOUNT)
+
+
+/*
+ * specific access rights which can be used in OpenAlias.
+ * extracted from Ethereal network analyzer
+ */
+#define SAMR_ALIAS_ACCESS_SET_INFO 0x00000010
+#define SAMR_ALIAS_ACCESS_GET_INFO 0x00000008
+#define SAMR_ALIAS_ACCESS_GET_MEMBERS 0x00000004
+#define SAMR_ALIAS_ACCESS_DEL_MEMBER 0x00000002
+#define SAMR_ALIAS_ACCESS_ADD_MEMBER 0x00000001
+
+/*
+ * Definition for a SID. The ndl compiler does not allow a typedef of
+ * a structure containing variable size members.
+ */
+struct samr_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[6];
+ SIZE_IS(SubAuthCount)
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+};
+
+
+/*
+ * SAMR definition of a security_descriptor.
+ */
+struct samr_sec_desc {
+ BYTE Revision;
+ BYTE Sbz1;
+ WORD Control;
+ struct samr_sid *owner;
+ struct samr_sid *group;
+ struct samr_sid *sacl;
+ struct samr_sid *dacl;
+};
+
+
+/*
+ * Definition for a string. The length and allosize should be set to
+ * twice the string length (i.e. strlen(str) * 2). The runtime code
+ * will perform the appropriate string to a wide-char conversions,
+ * so str should point to a regular char * string.
+ */
+struct samr_string {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct samr_string samr_string_t;
+
+
+/*
+ * Alternative varying/conformant string definition - for
+ * non-null terminated strings. This definition must match
+ * mlrpc_vcbuf_t.
+ */
+struct samr_vcb {
+ /*
+ * size_is (actually a copy of length_is) will
+ * be inserted here by the marshalling library.
+ */
+ DWORD vc_first_is;
+ DWORD vc_length_is;
+ SIZE_IS(vc_length_is)
+ WORD buffer[ANY_SIZE_ARRAY];
+};
+
+struct samr_vcbuf {
+ WORD wclen;
+ WORD wcsize;
+ struct samr_vcb *vcb;
+};
+typedef struct samr_vcbuf samr_vcbuf_t;
+
+
+/*
+ * Handles appear to be a 20 byte object with the top 4 bytes all zero.
+ * Handles may have some internal structure but this should work since
+ * we always treat it as an opaque handle. They do appear to contain a
+ * sequence number which is incremented when new handle is issued.
+*/
+
+struct samr_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+typedef struct samr_handle samr_handle_t;
+
+/*
+ * A long long, i.e. 64-bit, value.
+ */
+struct samr_quad {
+ DWORD low;
+ DWORD high;
+};
+typedef struct samr_quad samr_quad_t;
+
+
+/*
+ ***********************************************************************
+ * ConnectAnon. It looks like the SAM handle is identical to an LSA
+ * handle. See Connect.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_ConnectAnon)
+struct samr_ConnectAnon {
+ IN DWORD *servername;
+ IN DWORD access_mask;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Connect. I'm not sure what the difference is between Connect and
+ * ConnectAnon but this call seems to work better than ConnectAnon.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_Connect)
+struct samr_Connect {
+ IN LPTSTR servername;
+ IN DWORD access_mask;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamrConnect3. A new form of connect first seen with Windows 2000.
+ * A new field has been added to the input request. Value: 0x00000002.
+ * I haven't looked at the Win2K response yet to see if it differs
+ * from SAMR_OPNUM_Connect.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_Connect3)
+struct samr_Connect3 {
+ IN LPTSTR servername;
+ IN DWORD unknown_02;
+ IN DWORD access_mask;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SamrConnect4. A new form of connect first seen with Windows XP.
+ * The server name is the fully qualified domain name, i.e.
+ * \\server.procom.com.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_Connect4)
+struct samr_Connect4 {
+ IN LPTSTR servername;
+ IN DWORD access_mask;
+ INOUT DWORD unknown2_00000001;
+ INOUT DWORD unknown3_00000001;
+ INOUT DWORD unknown4_00000003;
+ INOUT DWORD unknown5_00000000;
+ OUT samr_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * CloseHandle closes an association with the SAM. Using the same
+ * structure as the LSA seems to work.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_CloseHandle)
+struct samr_CloseHandle {
+ IN samr_handle_t handle;
+ OUT samr_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupDomain: lookup up the domain SID.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_LookupDomain)
+struct samr_LookupDomain {
+ IN samr_handle_t handle;
+ IN samr_string_t domain_name;
+ OUT struct samr_sid *sid;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * EnumLocalDomain
+ *
+ * This looks like a request to get the local domains supported by a
+ * remote server. NT always seems to return 2 domains: the local
+ * domain (hostname) and the Builtin domain.
+ *
+ * The max_length field is set to 0x2000.
+ * Enum_context is set to 0 in the request and set to entries_read in
+ * the reply. Like most of these enums, total_entries is the same as
+ * entries_read.
+ ***********************************************************************
+ */
+struct samr_LocalDomainEntry {
+ DWORD unknown;
+ samr_string_t name;
+};
+
+struct samr_LocalDomainInfo {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct samr_LocalDomainEntry *entry;
+};
+
+
+OPERATION(SAMR_OPNUM_EnumLocalDomains)
+struct samr_EnumLocalDomain {
+ IN samr_handle_t handle;
+ INOUT DWORD enum_context;
+ IN DWORD max_length;
+ OUT struct samr_LocalDomainInfo *info;
+ OUT DWORD total_entries;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenDomain
+ *
+ * Open a specific domain within the SAM. From this I assume that each
+ * SAM can handle multiple domains so you need to identify the one with
+ * which you want to work. Working with a domain handle does appear to
+ * offer the benefit that you can then use RIDs instead of full SIDs,
+ * which simplifies things a bit. The domain handle can be used to get
+ * user and group handles.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_OpenDomain)
+struct samr_OpenDomain {
+ IN samr_handle_t handle;
+ IN DWORD access_mask;
+ IN REFERENCE struct samr_sid *sid;
+ OUT samr_handle_t domain_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryDomainInfo
+ *
+ * Windows 95 Server Manager sends requests for levels 6 and 7 when
+ * the services menu item is selected.
+ ***********************************************************************
+ */
+#define SAMR_QUERY_DOMAIN_INFO_2 2
+#define SAMR_QUERY_DOMAIN_INFO_6 6
+#define SAMR_QUERY_DOMAIN_INFO_7 7
+
+
+struct samr_QueryDomainInfo2 {
+ DWORD unknown1; /* 00 00 00 00 */
+ DWORD unknown2; /* 00 00 00 80 */
+ samr_string_t s1;
+ samr_string_t domain;
+ samr_string_t s2;
+ DWORD sequence_num; /* 2B 00 00 00 */
+ DWORD unknown3; /* 00 00 00 00 */
+ DWORD unknown4; /* 01 00 00 00 */
+ DWORD unknown5; /* 03 00 00 00 */
+ DWORD unknown6; /* 01 */
+ DWORD num_users;
+ DWORD num_groups;
+ DWORD num_aliases;
+};
+
+
+struct samr_QueryDomainInfo6 {
+ DWORD unknown1; /* 00 00 00 00 */
+ DWORD unknown2; /* B0 7F 14 00 */
+ DWORD unknown3; /* 00 00 00 00 */
+ DWORD unknown4; /* 00 00 00 00 */
+ DWORD unknown5; /* 00 00 00 00 */
+};
+
+
+struct samr_QueryDomainInfo7 {
+ DWORD unknown1; /* 03 00 00 00 */
+};
+
+
+union samr_QueryDomainInfo_ru {
+ UNION_INFO_ENT(2,samr_QueryDomainInfo);
+ UNION_INFO_ENT(6,samr_QueryDomainInfo);
+ UNION_INFO_ENT(7,samr_QueryDomainInfo);
+ DEFAULT char *nullptr;
+};
+
+
+/*
+ * This structure needs to be declared, even though it can't be used in
+ * samr_QueryDomainInfo, in order to calculate the correct fixup offsets.
+ * If ndrgen did the right thing, samr_QueryDomainInfoRes would be one of
+ * the out parameters. However, if we do it that way, the switch_value
+ * isn't known early enough to do the fixup calculation. So it all has
+ * to go in samr_QueryDomainInfo.
+ */
+struct samr_QueryDomainInfoRes {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union samr_QueryDomainInfo_ru ru;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryDomainInfo)
+struct samr_QueryDomainInfo {
+ IN samr_handle_t domain_handle;
+ IN WORD info_level;
+ /*
+ * Can't use the standard "OUT result" form because
+ * we need to include members explicitly.
+ * OUT struct samr_QueryDomainInfoRes result;
+ */
+ OUT DWORD address;
+ OUT WORD switch_value;
+ SWITCH(info_level)
+ OUT union samr_QueryDomainInfo_ru ru;
+ OUT DWORD status;
+};
+
+#define SAMR_QUERY_ALIAS_INFO_1 1
+#define SAMR_QUERY_ALIAS_INFO_3 3
+
+
+struct samr_QueryAliasInfo1 {
+ WORD level;
+ samr_string_t name;
+ DWORD unknown;
+ samr_string_t desc;
+};
+
+struct samr_QueryAliasInfo3 {
+ WORD level;
+ samr_string_t desc;
+};
+
+union samr_QueryAliasInfo_ru {
+ UNION_INFO_ENT(1,samr_QueryAliasInfo);
+ UNION_INFO_ENT(3,samr_QueryAliasInfo);
+ DEFAULT char *nullptr;
+};
+
+struct samr_QueryAliasInfoRes {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union samr_QueryAliasInfo_ru ru;
+};
+
+OPERATION(SAMR_OPNUM_QueryAliasInfo)
+struct samr_QueryAliasInfo {
+ IN samr_handle_t alias_handle;
+ IN WORD level;
+ OUT DWORD address;
+ SWITCH (level)
+ OUT union samr_QueryAliasInfo_ru ru;
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_CreateDomainAlias)
+struct samr_CreateDomainAlias {
+ IN samr_handle_t domain_handle;
+ IN samr_string_t alias_name;
+ IN DWORD access_mask;
+ OUT samr_handle_t alias_handle;
+ OUT DWORD rid;
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_SetAliasInfo)
+struct samr_SetAliasInfo {
+ IN samr_handle_t alias_handle;
+ IN WORD level;
+ /* TBD */
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_DeleteDomainAlias)
+struct samr_DeleteDomainAlias {
+ IN samr_handle_t alias_handle;
+ OUT DWORD status;
+};
+
+OPERATION(SAMR_OPNUM_OpenAlias)
+struct samr_OpenAlias {
+ IN samr_handle_t domain_handle;
+ IN DWORD access_mask;
+ IN DWORD rid;
+ OUT samr_handle_t alias_handle;
+ OUT DWORD status;
+};
+
+struct name_rid {
+ DWORD rid;
+ samr_string_t name;
+};
+
+struct aliases_info {
+ DWORD count;
+ DWORD address;
+ SIZE_IS(count)
+ struct name_rid info[ANY_SIZE_ARRAY];
+};
+
+OPERATION(SAMR_OPNUM_EnumDomainAliases)
+struct samr_EnumDomainAliases {
+ IN samr_handle_t domain_handle;
+ IN DWORD resume_handle;
+ IN DWORD mask;
+ OUT DWORD out_resume;
+ OUT struct aliases_info *aliases;
+ OUT DWORD entries;
+ OUT DWORD status;
+};
+
+struct user_acct_info {
+ DWORD index;
+ DWORD rid;
+ DWORD ctrl;
+ samr_string_t name;
+ samr_string_t fullname;
+ samr_string_t desc;
+};
+
+struct user_disp_info {
+ DWORD count;
+ /* right now we just need two entries */
+ struct user_acct_info acct[2];
+};
+
+OPERATION(SAMR_OPNUM_QueryDispInfo)
+struct samr_QueryDispInfo {
+ IN samr_handle_t domain_handle;
+ IN WORD level;
+ IN DWORD start_idx;
+ IN DWORD max_entries;
+ IN DWORD pref_maxsize;
+ OUT DWORD total_size;
+ OUT DWORD returned_size;
+ OUT WORD switch_value;
+ OUT DWORD count;
+ OUT struct user_disp_info *users;
+ OUT DWORD status;
+};
+
+struct group_acct_info {
+ DWORD index;
+ DWORD rid;
+ DWORD ctrl;
+ samr_string_t name;
+ samr_string_t desc;
+};
+
+struct group_disp_info {
+ DWORD count;
+ /* right now we just need one entry */
+ struct group_acct_info acct[1];
+};
+
+OPERATION(SAMR_OPNUM_EnumDomainGroups)
+struct samr_EnumDomainGroups {
+ IN samr_handle_t domain_handle;
+ IN WORD level;
+ IN DWORD start_idx;
+ IN DWORD max_entries;
+ IN DWORD pref_maxsize;
+ OUT DWORD total_size;
+ OUT DWORD returned_size;
+ OUT WORD switch_value;
+ OUT DWORD count;
+ OUT struct group_disp_info *groups;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * OpenUser
+ *
+ * Input must be a domain handle obtained via SAMR_OPNUM_OpenDomain,
+ * an access mask and the appropriate user rid. The output will be a
+ * handle for use with the specified user.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_OpenUser)
+struct samr_OpenUser {
+ IN samr_handle_t handle;
+ IN DWORD access_mask;
+ IN DWORD rid;
+ OUT samr_handle_t user_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * DeleteUser
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_DeleteUser)
+struct samr_DeleteUser {
+ INOUT samr_handle_t user_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryUserInfo
+ *
+ * Provides various pieces of information on a specific user (see
+ * SAM_Q_QUERY_USERINFO and SAM_R_QUERY_USERINFO). The handle must
+ * be a valid SAM user handle.
+ *
+ * QueryUserInfo (
+ * IN samr_handle_t user_handle,
+ * IN WORD switch_value,
+ * OUT union switch(switch_value) {
+ * case 1: struct QueryUserInfo1 *info1;
+ * } bufptr,
+ * OUT DWORD status
+ * )
+ *
+ * The cases identified so far are:
+ *
+ * 1 = username, fullname, description and some other stuff.
+ * 2 = unknown
+ * 3 = large structure containing user rid, group rid, username
+ * and fullname.
+ * 4 = unknown
+ * 5 = large structure (like 3) containing user rid, group rid,
+ * username, fullname and description.
+ * 6 = username and fullname
+ * 7 = username
+ * 8 = fullname
+ * 9 = group rid
+ * 16 = used after creating a new account
+ *
+ * Due to an ndrgen bug, a function must be provided to to patch the
+ * offsets used by the unmarshalling code at runtime. In order to
+ * simplify things it is useful to use a naming convention that
+ * indicates the switch value for each structure.
+ *
+ ***********************************************************************
+ */
+
+
+#define SAMR_QUERY_USER_INFO_1 1
+#define SAMR_QUERY_USER_UNAME_AND_FNAME 6
+#define SAMR_QUERY_USER_USERNAME 7
+#define SAMR_QUERY_USER_FULLNAME 8
+#define SAMR_QUERY_USER_GROUPRID 9
+#define SAMR_QUERY_USER_UNKNOWN16 16
+
+
+struct samr_QueryUserInfo1 {
+ samr_string_t username;
+ samr_string_t fullname;
+ DWORD group_rid;
+ samr_string_t description;
+ samr_string_t unknown;
+};
+
+
+struct samr_QueryUserInfo6 {
+ samr_string_t username;
+ samr_string_t fullname;
+};
+
+struct samr_QueryUserInfo7 {
+ samr_string_t username;
+};
+
+
+struct samr_QueryUserInfo8 {
+ samr_string_t fullname;
+};
+
+
+struct samr_QueryUserInfo9 {
+ DWORD group_rid;
+};
+
+
+struct samr_QueryUserInfo16 {
+ DWORD unknown;
+};
+
+
+union QueryUserInfo_result_u {
+ UNION_INFO_ENT(1,samr_QueryUserInfo);
+ UNION_INFO_ENT(6,samr_QueryUserInfo);
+ UNION_INFO_ENT(7,samr_QueryUserInfo);
+ UNION_INFO_ENT(8,samr_QueryUserInfo);
+ UNION_INFO_ENT(9,samr_QueryUserInfo);
+ UNION_INFO_ENT(16,samr_QueryUserInfo);
+ DEFAULT char *nullptr;
+};
+
+
+/*
+ * This structure needs to be declared, even though it can't be used in
+ * samr_QueryUserInfo, in order to get the appropriate size to calculate
+ * the correct fixup offsets. If ndrgen did the right thing,
+ * QueryUserInfo_result would be one of the out parameters. However, if
+ * we do it that way, the switch_value isn't known early enough to do
+ * the fixup calculation. So it all has to go in samr_QueryUserInfo.
+ */
+struct QueryUserInfo_result {
+ DWORD address;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union QueryUserInfo_result_u ru;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryUserInfo)
+struct samr_QueryUserInfo {
+ IN samr_handle_t user_handle;
+ IN WORD switch_value;
+ /*
+ * Can't use this form because we need to include members explicitly.
+ * OUT struct QueryUserInfo_result result;
+ */
+ OUT DWORD address;
+ OUT WORD switch_index;
+ SWITCH(switch_value)
+ OUT union QueryUserInfo_result_u ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryUserGroups
+ ***********************************************************************
+ */
+struct samr_UserGroups {
+ DWORD rid;
+ DWORD attr;
+};
+
+
+struct samr_UserGroupInfo {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ struct samr_UserGroups *groups;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryUserGroups)
+struct samr_QueryUserGroups {
+ IN samr_handle_t user_handle;
+ OUT struct samr_UserGroupInfo *info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * LookupName
+ ***********************************************************************
+ */
+struct samr_LookupNameTable {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ samr_string_t names[ANY_SIZE_ARRAY];
+};
+
+
+struct samr_LookupRidTable {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ DWORD *rid;
+};
+
+struct samr_RidType {
+ DWORD n_entry;
+ SIZE_IS(n_entry)
+ DWORD *rid_type;
+};
+
+
+OPERATION(SAMR_OPNUM_LookupNames)
+struct samr_LookupNames {
+ IN samr_handle_t handle;
+ IN DWORD n_entry;
+ IN DWORD max_n_entry;
+ IN DWORD index;
+ IN DWORD total;
+ IN samr_string_t name;
+ OUT struct samr_LookupRidTable rids;
+ OUT struct samr_RidType rid_types;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenGroup
+ *
+ * Input must be a domain handle obtained via SAMR_OPNUM_OpenDomain,
+ * an access mask and the appropriate group rid. The output will be a
+ * handle for use with the specified group.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_OpenGroup)
+struct samr_OpenGroup {
+ IN samr_handle_t handle;
+ IN DWORD access_mask;
+ IN DWORD rid;
+ OUT samr_handle_t group_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryGroupInfo
+ *
+ * Input must be a group handle obtained via SAMR_OPNUM_OpenGroup,
+ * an access mask and the appropriate group rid. The output will
+ * be a handle for use with the specified group.
+ ***********************************************************************
+ */
+struct samr_QueryGroupInfo1 {
+ samr_string_t groupname;
+};
+
+
+union samr_QueryGroupInfo_result_u {
+ UNION_INFO_ENT(1,samr_QueryGroupInfo);
+ DEFAULT char *nullptr;
+};
+
+
+struct samr_QueryGroupInfo_result {
+ DWORD address;
+ WORD switch_index;
+ SWITCH(switch_index)
+ union samr_QueryGroupInfo_result_u ru;
+};
+
+
+OPERATION(SAMR_OPNUM_QueryGroupInfo)
+struct samr_QueryGroupInfo {
+ IN samr_handle_t group_handle;
+ IN DWORD switch_value;
+ OUT DWORD address;
+ OUT WORD switch_index;
+ SWITCH(switch_index)
+ OUT union samr_QueryGroupInfo_result_u ru;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * StoreGroupInfo
+ *
+ * This definition is mostly just a place holder in case this is useful
+ * in the future. Note that it may not be correct. The information is
+ * from a netmon trace captured when I added a group description. I
+ * haven't implemented it because we don't have to update anything on
+ * the PDC. The description should almost certainly be in a separate
+ * structure.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_StoreGroupInfo)
+struct samr_StoreGroupInfo {
+ IN samr_handle_t group_handle;
+ IN DWORD switch_value;
+ IN samr_string_t group_description;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * Request 0x2c is a user request. The only parameter is a user handle.
+ * The response is 12 bytes of the form:
+ * unknown: 00 00 BB 01 (443)
+ * unknown: 00 00 00 00
+ * status: 00 00 00 00
+ * RPC book lists this as GetUsrDomPwInfo.
+ ***********************************************************************
+ */
+struct samr_UserPwInfo {
+ WORD unknown1;
+ WORD unknown2;
+ DWORD unknown3;
+};
+
+
+OPERATION(SAMR_OPNUM_GetUserPwInfo)
+struct samr_GetUserPwInfo {
+ IN samr_handle_t user_handle;
+ OUT struct samr_UserPwInfo pw_info;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * CreateUser
+ *
+ * Create a user in the domain specified by the domain handle. The
+ * domain handle is obtained obtained via SAMR_OPNUM_OpenDomain. There
+ * is an unknown value at the end of the request: 0xe00500b0.
+ * The output will be a handle for use with the specified user and the
+ * user's RID. I think the RID may be a pointer but the value came back
+ * as zero once so I've padded it out so that the marshalling doesn't
+ * get confused.
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_CreateUser)
+struct samr_CreateUser {
+ IN samr_handle_t handle;
+ IN samr_vcbuf_t username;
+ IN DWORD account_flags;
+ IN DWORD unknown_e00500b0;
+ OUT samr_handle_t user_handle;
+ OUT DWORD maybe_ptr;
+ OUT DWORD rid;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * ChangeUserPasswd
+ ***********************************************************************
+ */
+struct samr_newpasswd {
+ BYTE data[516];
+};
+
+
+struct samr_oldpasswd {
+ BYTE data[16];
+};
+
+
+OPERATION(SAMR_OPNUM_ChangeUserPasswd)
+struct samr_ChangeUserPasswd {
+ IN LPTSTR servername;
+ IN LPTSTR username;
+ IN struct samr_newpasswd *nt_newpasswd;
+ IN struct samr_oldpasswd *nt_oldpasswd;
+ IN struct samr_newpasswd *lm_newpasswd;
+ IN struct samr_oldpasswd *lm_oldpasswd;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * GetDomainPwInfo
+ ***********************************************************************
+ */
+OPERATION(SAMR_OPNUM_GetDomainPwInfo)
+struct samr_GetDomainPwInfo {
+ IN LPTSTR servername;
+ OUT WORD unknown0;
+ OUT WORD unknown1;
+ OUT WORD unknown2;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * SetUserInfo
+ *
+ * +++ 20 byte user handle and the union switch_value +++
+ * 00 00 00 00 77 F2 DD D5 66 48 D4 11 AD 5F D1 CD
+ * 18 43 7A DF 17 00 17 00
+ *
+ * +++ 14 dwords (56 bytes) of zeros +++
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00
+ *
+ * +++ 9 sets of something - 72 bytes +++
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ * 00 00 02 00 D0 04 8A 77
+ *
+ * +++ 9 DWORD zeros +++
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00
+ *
+ * +++ miscellaneous +++
+ * 01 02 00 00
+ * 80 00 00 00
+ * FA 27 F8 09
+ * A8 00 00 00 70 F1 14 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * +++ encrypted password buffer - 512 bytes +++
+ * 76 68 E8 AA 23 4F 62 C4 81 4E 30 B8 92 29 66 B9
+ * 12 FF 3A 84 82 3A 55 0F C7 18 EA 56 86 50 D7 C5
+ * 43 BA 9C F8 32 D4 E0 15 74 A1 6F E1 59 C2 F2 95
+ * 53 A9 F2 68 9F 7F 29 B9 88 4C 65 A5 C1 DC 0B 44
+ * B8 3C ED 74 D1 6A F7 09 66 97 94 6B 2C 3A A5 88
+ * 39 34 C6 FE 24 59 30 2D CF 6D 7F D5 EC B1 9A 84
+ * E6 57 96 29 40 32 FB 62 9D 93 E2 BE D8 A3 74 88
+ * 8B 85 BC A0 76 D6 C9 DB 8C AF 81 BD 8A F0 08 8D
+ * 23 B0 52 FD 69 DE EF A1 36 E5 30 19 BD DA 67 A3
+ * 81 BD 3F D0 2A A2 8F 60 62 B0 8D 34 9E A4 4F 20
+ * 4E 79 93 82 58 A8 E5 6F 7A DC 12 13 33 E6 74 02
+ * 4C 32 F9 FC 1A E1 C5 0D E2 CC 36 8D FC 72 87 DD
+ * 6C 44 E3 6F 4B FD 46 10 08 89 E5 64 B8 27 14 83
+ * E7 08 DE CF 69 C7 E1 40 63 DF CB 67 95 73 03 1B
+ * CA 99 E1 1B 53 2A 89 6B 30 39 CD 5C DF A0 8A 1C
+ * 4E 50 74 7C 6D 3D E7 EA E9 B2 97 DD 38 7B DA EC
+ * 1A AD DA CE C4 58 9B 29 F3 6D 30 70 4E 63 6D 84
+ * DB DC 5B CD 9A 4E 57 9C E4 65 5D 4F 76 E3 C7 52
+ * 8B 3B 20 0A 3B 4C 4B B1 2E 5B 4D AB BA 2F 45 6A
+ * CA 17 AD 9F C0 B2 07 FB 56 7F E4 3F 9F D4 C6 8C
+ * A1 05 BF 53 42 1E 67 F4 57 54 E3 2C 38 CF E1 94
+ * 75 69 F7 4E 5C 74 CC B3 FD EF 73 3F D5 28 22 EC
+ * 9B 40 E1 1D 65 44 7C BB 69 88 57 10 05 3A C5 48
+ * 8E 4F 77 DB 1A 5C 49 9C D5 06 00 AC 79 BC 7E 89
+ * B0 01 66 70 88 A2 E5 DF 96 DC 75 98 10 12 45 02
+ * 33 35 6C DF 74 8B 14 2F 26 C6 FD 7A B4 D0 A6 7D
+ * DE 2B 13 44 EF 34 46 4D 9D 3E C3 75 BC 11 B4 41
+ * 27 58 25 1E AF AA F0 BB DA 27 7A 1E AE 81 1A 78
+ * 44 19 DE FC C4 7C 4E 32 44 F7 57 2A 41 A2 85 DC
+ * C0 AD 5D 6B 58 FD 2E 75 25 B9 F2 B6 19 82 E5 0E
+ * B6 69 0D C1 27 A9 B6 40 A6 50 49 E5 CB 17 98 65
+ * 88 18 CA E4 1D 2E 20 F7 DE 8E 7D F2 9D A5 6B CD
+ *
+ * D6 79 45 71
+ *
+ * +++ table of 9 things +++
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ * 01 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * +++ miscellaneous +++
+ * EC 04 00 00 00 00 00 00 15 00 00 00
+ * FF FF FF FF FF FF FF FF FF FF FF FF
+ * FF FF FF FF FF FF FF FF FF
+ *
+ ***********************************************************************
+ */
+
+#define SAMR_SET_USER_INFO_23 23
+#define SAMR_SET_USER_DATA_SZ 516
+
+#define SAMR_MINS_PER_WEEK 10080
+#define SAMR_HOURS_PER_WEEK 168
+
+#define SAMR_HOURS_MAX_SIZE (SAMR_MINS_PER_WEEK / 8)
+#define SAMR_HOURS_SET_LEN(LEN) ((LEN) / 8)
+#define SAMR_SET_USER_HOURS_SZ 21
+
+
+struct samr_sd {
+ DWORD length;
+ SIZE_IS(length)
+ BYTE *data;
+};
+
+
+/*
+ * There is some sort of logon bitmap structure in here, which I
+ * think is a varying and conformant array, i.e.
+ *
+ * struct samr_logon_hours {
+ * DWORD size_is; (0x04ec)
+ * DWORD first_is; (zero)
+ * DWORD length_is; (0xa8)
+ * BYTE bitmap[21];
+ * };
+ *
+ * struct samr_logon_info {
+ * DWORD length;
+ * SIZE_IS(length / 8)
+ * struct samr_logon_hours *hours;
+ * };
+ *
+ * There are 10080 minutes/week => 10080/8 = 1260 (0x04EC).
+ * So size_is is set as some sort of maximum.
+ *
+ * There are 168 hours/week => 168/8 = 21 (0xA8). Since there are 21
+ * bytes (all set to 0xFF), this is is probably the default setting.
+ *
+ * ndrgen has a problem with complex [size_is] statements. For now,
+ * we can try to fake it using two separate components.
+ */
+struct samr_logon_hours {
+ DWORD size;
+ DWORD first;
+ DWORD length;
+ BYTE bitmap[SAMR_SET_USER_HOURS_SZ];
+};
+
+
+struct samr_logon_info {
+ DWORD units;
+ DWORD hours;
+};
+
+
+struct samr_oem_password {
+ BYTE password[512];
+ DWORD length;
+};
+
+
+struct samr_SetUserInfo23 {
+ samr_quad_t logon_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t logoff_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t kickoff_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t passwd_last_set_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t passwd_can_change_time; /* 00 00 00 00 00 00 00 00 */
+ samr_quad_t passwd_must_change_time; /* 00 00 00 00 00 00 00 00 */
+
+ samr_vcbuf_t user_name; /* 00 00 00 00 00 00 00 00 */
+ samr_vcbuf_t full_name; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t home_dir; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t home_drive; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t logon_script; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t profile_path; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t acct_desc; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t workstations; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t unknown1; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t unknown2; /* 00 00 02 00 D0 04 8A 77 */
+ samr_vcbuf_t lm_password; /* 00 00 00 00 00 00 00 00 */
+ samr_vcbuf_t nt_password; /* 00 00 00 00 00 00 00 00 */
+ samr_vcbuf_t unknown3; /* 00 00 00 00 00 00 00 00 */
+
+ struct samr_sd sd; /* 00 00 00 00 00 00 00 00 */
+ DWORD user_rid; /* 00 00 00 00 */
+ DWORD group_rid; /* 01 02 00 00 */
+ DWORD acct_info; /* 80 00 00 00 */
+ DWORD flags; /* FA 27 F8 09 */
+ struct samr_logon_info logon_info; /* A8 00 00 00 70 F1 14 00->0xFF */
+ /*
+ * The following 12 bytes are encoded in Ethereal as:
+ *
+ * WORD bad_pwd_count;
+ * WORD logon_count;
+ *
+ * WORD country; (default 0)
+ * WORD codepage;
+ *
+ * BYTE nt_pwd_set;
+ * BYTE lm_pwd_set;
+ * BYTE expired_flag;
+ * BYTE unknown_char;
+ */
+ DWORD unknown4_zero; /* 00 00 00 00 */
+ DWORD unknown5_zero; /* 00 00 00 00 */
+ DWORD unknown6_zero; /* 00 00 00 00 */
+ BYTE password[SAMR_SET_USER_DATA_SZ];
+};
+
+
+union samr_SetUserInfo_u {
+ UNION_INFO_ENT(23,samr_SetUserInfo);
+ DEFAULT char *nullptr;
+};
+
+
+struct samr_SetUserInfo_s {
+ WORD index;
+ WORD switch_value;
+ SWITCH(switch_value)
+ union samr_SetUserInfo_u ru;
+};
+
+
+/*
+ IN DWORD unknown_04EC;
+ IN DWORD unknown_zero;
+ IN DWORD logon_bitmap_size;
+ IN BYTE logon_bitmap[SAMR_SET_USER_HOURS_SZ];
+*/
+OPERATION(SAMR_OPNUM_SetUserInfo)
+struct samr_SetUserInfo {
+ IN samr_handle_t user_handle;
+ IN struct samr_SetUserInfo_s info;
+ IN struct samr_logon_hours logon_hours;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The SAMR interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union samr_interface {
+ CASE(SAMR_OPNUM_ConnectAnon)
+ struct samr_ConnectAnon ConnectAnon;
+ CASE(SAMR_OPNUM_CloseHandle)
+ struct samr_CloseHandle CloseHandle;
+ CASE(SAMR_OPNUM_LookupDomain)
+ struct samr_LookupDomain LookupDomain;
+ CASE(SAMR_OPNUM_EnumLocalDomains)
+ struct samr_EnumLocalDomain EnumLocalDomain;
+ CASE(SAMR_OPNUM_OpenDomain)
+ struct samr_OpenDomain OpenDomain;
+ CASE(SAMR_OPNUM_QueryDomainInfo)
+ struct samr_QueryDomainInfo QueryDomainInfo;
+ CASE(SAMR_OPNUM_LookupNames)
+ struct samr_LookupNames LookupNames;
+ CASE(SAMR_OPNUM_OpenUser)
+ struct samr_OpenUser OpenUser;
+ CASE(SAMR_OPNUM_DeleteUser)
+ struct samr_DeleteUser DeleteUser;
+ CASE(SAMR_OPNUM_QueryUserInfo)
+ struct samr_QueryUserInfo QueryUserInfo;
+ CASE(SAMR_OPNUM_QueryUserGroups)
+ struct samr_QueryUserGroups QueryUserGroups;
+ CASE(SAMR_OPNUM_OpenGroup)
+ struct samr_OpenGroup OpenGroup;
+ CASE(SAMR_OPNUM_GetUserPwInfo)
+ struct samr_GetUserPwInfo GetUserPwInfo;
+ CASE(SAMR_OPNUM_CreateUser)
+ struct samr_CreateUser CreateUser;
+ CASE(SAMR_OPNUM_ChangeUserPasswd)
+ struct samr_ChangeUserPasswd ChangeUserPasswd;
+ CASE(SAMR_OPNUM_GetDomainPwInfo)
+ struct samr_GetDomainPwInfo GetDomainPwInfo;
+ CASE(SAMR_OPNUM_Connect)
+ struct samr_Connect Connect;
+ CASE(SAMR_OPNUM_SetUserInfo)
+ struct samr_SetUserInfo SetUserInfo;
+ CASE(SAMR_OPNUM_Connect3)
+ struct samr_Connect3 Connect3;
+ CASE(SAMR_OPNUM_Connect4)
+ struct samr_Connect4 Connect4;
+ CASE(SAMR_OPNUM_QueryDispInfo)
+ struct samr_QueryDispInfo QueryDispInfo;
+ CASE(SAMR_OPNUM_OpenAlias)
+ struct samr_OpenAlias OpenAlias;
+ CASE(SAMR_OPNUM_CreateDomainAlias)
+ struct samr_CreateDomainAlias CreateDomainAlias;
+ CASE(SAMR_OPNUM_SetAliasInfo)
+ struct samr_SetAliasInfo SetAliasInfo;
+ CASE(SAMR_OPNUM_QueryAliasInfo)
+ struct samr_QueryAliasInfo QueryAliasInfo;
+ CASE(SAMR_OPNUM_DeleteDomainAlias)
+ struct samr_DeleteDomainAlias DeleteDomainAlias;
+ CASE(SAMR_OPNUM_EnumDomainAliases)
+ struct samr_EnumDomainAliases EnumDomainAliases;
+ CASE(SAMR_OPNUM_EnumDomainGroups)
+ struct samr_EnumDomainGroups EnumDomainGroups;
+};
+typedef union samr_interface samr_interface_t;
+EXTERNTYPEINFO(samr_interface)
+
+#endif /* _MLSVC_SAM_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/spoolss.ndl b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl
new file mode 100644
index 0000000000..1598e09d50
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl
@@ -0,0 +1,489 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_SPOOLSS_NDL_
+#define _MLSVC_SPOOLSS_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Printing and Spooling RPC interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+
+/*
+ * The spoolss opcodes.
+ */
+#define SPOOLSS_OPNUM_OpenPrinter 0x01
+#define SPOOLSS_OPNUM_GetJob 0x03
+#define SPOOLSS_OPNUM_DeletePrinter 0x06
+#define SPOOLSS_OPNUM_GetPrinterDriver 0x0b
+#define SPOOLSS_OPNUM_DeletePrinterDriver 0x0d
+#define SPOOLSS_OPNUM_AddPrintProcessor 0x0e
+#define SPOOLSS_OPNUM_GetPrintProcessorDirectory 0x10
+#define SPOOLSS_OPNUM_AbortPrinter 0x15
+#define SPOOLSS_OPNUM_ReadPrinter 0x16
+#define SPOOLSS_OPNUM_WaitForPrinterChange 0x1c
+#define SPOOLSS_OPNUM_AddForm 0x1e
+#define SPOOLSS_OPNUM_DeleteForm 0x1f
+#define SPOOLSS_OPNUM_GetForm 0x20
+#define SPOOLSS_OPNUM_SetForm 0x21
+#define SPOOLSS_OPNUM_EnumMonitors 0x24
+#define SPOOLSS_OPNUM_AddPort 0x25
+#define SPOOLSS_OPNUM_ConfigurePort 0x26
+#define SPOOLSS_OPNUM_DeletePort 0x27
+#define SPOOLSS_OPNUM_CreatePrinterIc 0x28
+#define SPOOLSS_OPNUM_PlayDescriptionPrinterIc 0x29
+#define SPOOLSS_OPNUM_DeletePrinterIc 0x2a
+#define SPOOLSS_OPNUM_AddPrinterConnection 0x2b
+#define SPOOLSS_OPNUM_DeletePrinterConnection 0x2c
+#define SPOOLSS_OPNUM_PrinterMessageBox 0x2d
+#define SPOOLSS_OPNUM_AddMonitor 0x2e
+#define SPOOLSS_OPNUM_DeleteMonitor 0x2f
+#define SPOOLSS_OPNUM_DeletePrintProcessor 0x30
+#define SPOOLSS_OPNUM_AddPrintProvider 0x31
+#define SPOOLSS_OPNUM_DeletePrintProvider 0x32
+#define SPOOLSS_OPNUM_ResetPrinter 0x34
+#define SPOOLSS_OPNUM_FindFirstChangeNotify 0x36
+#define SPOOLSS_OPNUM_FindNextChangeNotify 0x37
+#define SPOOLSS_OPNUM_RouterFindFirstNotify 0x39
+#define SPOOLSS_OPNUM_ReplyOpenPrinter 0x3a
+#define SPOOLSS_OPNUM_RouterReplyPrinter 0x3b
+#define SPOOLSS_OPNUM_ReplyClosePrinter 0x3c
+#define SPOOLSS_OPNUM_AddPortEx 0x3d
+#define SPOOLSS_OPNUM_RemoteFindFirstChangeNotify 0x3e
+#define SPOOLSS_OPNUM_SpoolerInitialize 0x3f
+#define SPOOLSS_OPNUM_ResetPrinterEx 0x40
+#define SPOOLSS_OPNUM_RouterRefreshChangeNotify 0x42
+#define SPOOLSS_OPNUM_OpenPrinter2 0x45
+
+
+/*
+ * The private handle definition for this interface.
+ */
+struct spoolss_handle {
+ DWORD data[5];
+};
+typedef struct spoolss_handle spoolss_handle_t;
+
+
+OPERATION(SPOOLSS_OPNUM_OpenPrinter)
+struct spoolss_OpenPrinter {
+ IN DWORD dontcare;
+ OUT spoolss_handle_t handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetJob)
+struct spoolss_GetJob {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinter)
+struct spoolss_DeletePrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetPrinterDriver)
+struct spoolss_GetPrinterDriver {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinterDriver)
+struct spoolss_DeletePrinterDriver {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPrintProcessor)
+struct spoolss_AddPrintProcessor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetPrintProcessorDirectory)
+struct spoolss_GetPrintProcessorDirectory {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AbortPrinter)
+struct spoolss_AbortPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ReadPrinter)
+struct spoolss_ReadPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_WaitForPrinterChange)
+struct spoolss_WaitForPrinterChange {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddForm)
+struct spoolss_AddForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeleteForm)
+struct spoolss_DeleteForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_GetForm)
+struct spoolss_GetForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_SetForm)
+struct spoolss_SetForm {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_EnumMonitors)
+struct spoolss_EnumMonitors {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPort)
+struct spoolss_AddPort {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ConfigurePort)
+struct spoolss_ConfigurePort {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePort)
+struct spoolss_DeletePort {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_CreatePrinterIc)
+struct spoolss_CreatePrinterIc {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_PlayDescriptionPrinterIc)
+struct spoolss_PlayDescriptionPrinterIc {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinterIc)
+struct spoolss_DeletePrinterIc {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPrinterConnection)
+struct spoolss_AddPrinterConnection {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrinterConnection)
+struct spoolss_DeletePrinterConnection {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_PrinterMessageBox)
+struct spoolss_PrinterMessageBox {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddMonitor)
+struct spoolss_AddMonitor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeleteMonitor)
+struct spoolss_DeleteMonitor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrintProcessor)
+struct spoolss_DeletePrintProcessor {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPrintProvider)
+struct spoolss_AddPrintProvider {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_DeletePrintProvider)
+struct spoolss_DeletePrintProvider {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ResetPrinter)
+struct spoolss_ResetPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_FindFirstChangeNotify)
+struct spoolss_FindFirstChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_FindNextChangeNotify)
+struct spoolss_FindNextChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RouterFindFirstNotify)
+struct spoolss_RouterFindFirstNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ReplyOpenPrinter)
+struct spoolss_ReplyOpenPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RouterReplyPrinter)
+struct spoolss_RouterReplyPrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ReplyClosePrinter)
+struct spoolss_ReplyClosePrinter {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_AddPortEx)
+struct spoolss_AddPortEx {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify)
+struct spoolss_RemoteFindFirstChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_SpoolerInitialize)
+struct spoolss_SpoolerInitialize {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_ResetPrinterEx)
+struct spoolss_ResetPrinterEx {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_RouterRefreshChangeNotify)
+struct spoolss_RouterRefreshChangeNotify {
+ IN DWORD dontcare;
+ OUT DWORD status;
+};
+
+
+OPERATION(SPOOLSS_OPNUM_OpenPrinter2)
+struct spoolss_OpenPrinter2 {
+ IN DWORD dontcare;
+ OUT spoolss_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * The spoolss interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union spoolss_interface {
+ CASE(SPOOLSS_OPNUM_OpenPrinter)
+ struct spoolss_OpenPrinter OpenPrinter;
+ CASE(SPOOLSS_OPNUM_GetJob)
+ struct spoolss_GetJob GetJob;
+ CASE(SPOOLSS_OPNUM_DeletePrinter)
+ struct spoolss_DeletePrinter DeletePrinter;
+ CASE(SPOOLSS_OPNUM_GetPrinterDriver)
+ struct spoolss_GetPrinterDriver GetPrinterDriver;
+ CASE(SPOOLSS_OPNUM_DeletePrinterDriver)
+ struct spoolss_DeletePrinterDriver DeletePrinterDriver;
+ CASE(SPOOLSS_OPNUM_AddPrintProcessor)
+ struct spoolss_AddPrintProcessor AddPrintProcessor;
+ CASE(SPOOLSS_OPNUM_GetPrintProcessorDirectory)
+ struct spoolss_GetPrintProcessorDirectory
+ GetPrintProcessorDirectory;
+ CASE(SPOOLSS_OPNUM_AbortPrinter)
+ struct spoolss_AbortPrinter AbortPrinter;
+ CASE(SPOOLSS_OPNUM_ReadPrinter)
+ struct spoolss_ReadPrinter ReadPrinter;
+ CASE(SPOOLSS_OPNUM_WaitForPrinterChange)
+ struct spoolss_WaitForPrinterChange WaitForPrinterChange;
+ CASE(SPOOLSS_OPNUM_AddForm)
+ struct spoolss_AddForm AddForm;
+ CASE(SPOOLSS_OPNUM_DeleteForm)
+ struct spoolss_DeleteForm DeleteForm;
+ CASE(SPOOLSS_OPNUM_GetForm)
+ struct spoolss_GetForm GetForm;
+ CASE(SPOOLSS_OPNUM_SetForm)
+ struct spoolss_SetForm SetForm;
+ CASE(SPOOLSS_OPNUM_EnumMonitors)
+ struct spoolss_EnumMonitors EnumMonitors;
+ CASE(SPOOLSS_OPNUM_AddPort)
+ struct spoolss_AddPort AddPort;
+ CASE(SPOOLSS_OPNUM_ConfigurePort)
+ struct spoolss_ConfigurePort ConfigurePort;
+ CASE(SPOOLSS_OPNUM_DeletePort)
+ struct spoolss_DeletePort DeletePort;
+ CASE(SPOOLSS_OPNUM_CreatePrinterIc)
+ struct spoolss_CreatePrinterIc CreatePrinterIc;
+ CASE(SPOOLSS_OPNUM_PlayDescriptionPrinterIc)
+ struct spoolss_PlayDescriptionPrinterIc
+ PlayDescriptionPrinterIc;
+ CASE(SPOOLSS_OPNUM_DeletePrinterIc)
+ struct spoolss_DeletePrinterIc DeletePrinterIc;
+ CASE(SPOOLSS_OPNUM_AddPrinterConnection)
+ struct spoolss_AddPrinterConnection AddPrinterConnection;
+ CASE(SPOOLSS_OPNUM_DeletePrinterConnection)
+ struct spoolss_DeletePrinterConnection DeletePrinterConnection;
+ CASE(SPOOLSS_OPNUM_PrinterMessageBox)
+ struct spoolss_PrinterMessageBox PrinterMessageBox;
+ CASE(SPOOLSS_OPNUM_AddMonitor)
+ struct spoolss_AddMonitor AddMonitor;
+ CASE(SPOOLSS_OPNUM_DeleteMonitor)
+ struct spoolss_DeleteMonitor DeleteMonitor;
+ CASE(SPOOLSS_OPNUM_DeletePrintProcessor)
+ struct spoolss_DeletePrintProcessor DeletePrintProcessor;
+ CASE(SPOOLSS_OPNUM_AddPrintProvider)
+ struct spoolss_AddPrintProvider AddPrintProvider;
+ CASE(SPOOLSS_OPNUM_DeletePrintProvider)
+ struct spoolss_DeletePrintProvider DeletePrintProvider;
+ CASE(SPOOLSS_OPNUM_ResetPrinter)
+ struct spoolss_ResetPrinter ResetPrinter;
+ CASE(SPOOLSS_OPNUM_FindFirstChangeNotify)
+ struct spoolss_FindFirstChangeNotify FindFirstChangeNotify;
+ CASE(SPOOLSS_OPNUM_FindNextChangeNotify)
+ struct spoolss_FindNextChangeNotify FindNextChangeNotify;
+ CASE(SPOOLSS_OPNUM_RouterFindFirstNotify)
+ struct spoolss_RouterFindFirstNotify RouterFindFirstNotify;
+ CASE(SPOOLSS_OPNUM_ReplyOpenPrinter)
+ struct spoolss_ReplyOpenPrinter ReplyOpenPrinter;
+ CASE(SPOOLSS_OPNUM_RouterReplyPrinter)
+ struct spoolss_RouterReplyPrinter RouterReplyPrinter;
+ CASE(SPOOLSS_OPNUM_ReplyClosePrinter)
+ struct spoolss_ReplyClosePrinter ReplyClosePrinter;
+ CASE(SPOOLSS_OPNUM_AddPortEx)
+ struct spoolss_AddPortEx AddPortEx;
+ CASE(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify)
+ struct spoolss_RemoteFindFirstChangeNotify
+ RemoteFindFirstChangeNotify;
+ CASE(SPOOLSS_OPNUM_SpoolerInitialize)
+ struct spoolss_SpoolerInitialize SpoolerInitialize;
+ CASE(SPOOLSS_OPNUM_ResetPrinterEx)
+ struct spoolss_ResetPrinterEx ResetPrinterEx;
+ CASE(SPOOLSS_OPNUM_RouterRefreshChangeNotify)
+ struct spoolss_RouterRefreshChangeNotify
+ RouterRefreshChangeNotify;
+ CASE(SPOOLSS_OPNUM_OpenPrinter2)
+ struct spoolss_OpenPrinter2 OpenPrinter2;
+};
+typedef union spoolss_interface spoolss_interface_t;
+EXTERNTYPEINFO(spoolss_interface)
+
+#endif /* _MLSVC_SPOOLSS_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
new file mode 100644
index 0000000000..b952feacb7
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
@@ -0,0 +1,1331 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_LANMAN_NDL_
+#define _MLSVC_LANMAN_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * LanMan RPC (WKSSVC and SRVSVC) interface definitions.
+ */
+
+#include "ndrtypes.ndl"
+
+/*
+ * WARNING: The cpp(1) macros in this file are not understood by
+ * /usr/bin/cpp. Use /usr/libexec/cpp instead.
+ */
+
+/*
+ * TYPE CONSTRUCTOR MACROS FOR INFORMATION RESULTS
+ ****************************************************************
+ *
+ * This is an explanation of the macros that follow this comment.
+ *
+ * The LANMAN API's look something like this:
+ *
+ * NetXXXGetInfo (
+ * IN char * servername,
+ * IN char * XXX_name,
+ * IN int level,
+ * OUT char ** bufptr);
+ *
+ * The bufptr is a pointer-to-pointer (**). The NetXXXGetInfo() function
+ * malloc()s memory, and sets *bufptr to the memory. The API's
+ * are undiscriminated about what bufptr really points to.
+ *
+ * However, for RPI (Remote Procedure Interface), this just won't fly.
+ * We have to know what the result data looks like in order to
+ * properly (un)marshall it.
+ *
+ * As best we can determine, the MSC developers use an RPI that looks
+ * like this (approximately in IDL):
+ *
+ * RemoteNetXXXGetInfo (
+ * IN char * servername,
+ * IN char * XXX_name,
+ * IN int level,
+ * OUT union switch(level) {
+ * case(1): XXX_INFO_1 * info1;
+ * case(2): XXX_INFO_2 * info2;
+ * } bufptr);
+ *
+ * The level guides the (un)marshalling as it follows the pointer.
+ * DCE(MS) IDL will automatically form a structure for the union
+ * which looks about like this (much as Sun/RPC does):
+ *
+ * struct {
+ * int _keyvalue_;
+ * union {
+ * XXX_INFO_1 *info1;
+ * XXX_INFO_2 *info2;
+ * } _u_;
+ * } bufptr;
+ *
+ * This struct is not made visible to the application. It is purely
+ * an internal (automagic) thing. However, ndrgen does not do this.
+ * The ndrgen input MUST remain a valid C header file, and all
+ * struct and union declarations must be exact, and we (would) have
+ * to tediously code sequences like this (approximately NDL)):
+ *
+ * union XXXGetInfo_result_u {
+ * [case(1)]
+ * XXX_INFO_1 * info1;
+ * [case(2)]
+ * XXX_INFO_2 * info2;
+ * };
+ *
+ * struct XXXGetInfo_result {
+ * int level;
+ *
+ * union XXXGetInfo_result_u bufptr;
+ * };
+ *
+ * struct XXXGetInfo_param { // still have to code this one
+ * [in] char * servername;
+ * [in] ushort level;
+ * [out] struct XXXGetInfo_result result;
+ * };
+ *
+ * This is error prone and difficult to write, and more difficult
+ * and distracting to read. It is hard to pick through the
+ * necessary evils and see what's really going on. To mitigate
+ * the situation, we have a series of macros which generate
+ * the tedious code, and are easily recognized as supporting
+ * fluff rather than important structures:
+ *
+ * INFO1RES_DEFINITION(XXXGetInfo,
+ * INFO1RES_UNION_ENTRY(XXXGetInfo, 1)
+ * INFO1RES_UNION_ENTRY(XXXGetInfo, 2))
+ *
+ * structt XXXGetInfo_param { // still have to code this one
+ * [in] char * servername;
+ * [in] ushort level;
+ * [out] struct XXXGetInfo_result result;
+ * };
+ *
+ * The INFO1RES_DEFINITION macro defines two types:
+ *
+ * union ...__ru {...}
+ * struct ..._result { DWORD level; union ..._ru bufptr; }
+ *
+ * There is a similar macro, INFO1RESBUF_DEFINITION, which defines
+ * actual space rather than just pointers. It defines:
+ *
+ * union ...._rb {...}
+ * typedef union ..._rb ..._rb;
+ *
+ * Which is handy in functions because the initial coding sequence
+ * looks something like:
+ *
+ * XXXGetInfoParam (struct XXXGetInfo_param *param) {
+ * XXXGetInfo_rb rb;
+ *
+ * param->result.level = param->level; // for marshalling
+ * param->result.bufptr.nullptr = &rb; // anything fits
+ *
+ * There are two flavors of Info results. The first is the
+ * single XXX_INFO_x result, which the foregoing example
+ * uses. The second flavor is when there are multiple entries
+ * possible. Again, for the sake of guiding the marshalling,
+ * the RPIs use something accommodating:
+ *
+ * struct XXX_INFO_1_result {
+ * unsigned entriesread;
+ * [size_is(entriesread)]
+ * XXX_INFO_1 * table;
+ * };
+ *
+ * union { XXX_INFO_1_result *info1; ...}
+ *
+ * Notice this is using XXX_INFO_1_result rather than just XXX_INFO_1.
+ * The requirements from this point are much like before. Because of
+ * the variable-length value, there is no realistic way to do something
+ * like INFO1RESBUF_DEFINITION.
+ *
+ * There are two sets of macros here. INFO1RES_xxx are for the
+ * single result case, and INFONRES_xxx for the multiple entry case.
+ */
+
+/*
+ * INFO1RES_...
+ * Type constructors for single-result case
+ */
+
+#define INFO1RES_DEFINITION(INFOPREF, ENTRIES) \
+ INFO1RES_UNION(INFOPREF, ENTRIES) \
+ INFO1RES_STRUCT(INFOPREF)
+
+#define INFO1RES_UNION(INFOPREF, ENTRIES) \
+ union INFOPREF##__ru { \
+ INFO1RES_UNION_NULLPTR \
+ ENTRIES \
+ };
+
+#define INFO1RES_UNION_NULLPTR \
+ DEFAULT char * nullptr;
+
+#define INFO1RES_UNION_ENTRY(INFOPREF,NUM) \
+ CASE(NUM) struct INFOPREF##_##NUM * bufptr##NUM;
+
+#define INFO1RES_STRUCT(INFOPREF) \
+ struct INFOPREF##_result { \
+ DWORD level; \
+ SWITCH(level) \
+ union INFOPREF##__ru bufptr; \
+ };
+
+/*
+ * INFO1RESBUF_...
+ * Type constructors for single-result buffering.
+ */
+
+
+#ifndef NDRGEN
+#define INFO1RESBUF_DEFINITION(INFOPREF, ENTRIES) \
+ typedef union INFOPREF##_rb { \
+ ENTRIES \
+ } INFOPREF##_rb;
+#define INFO1RESBUF_UNION_ENTRY(INFOPREF,NUM) \
+ CASE(NUM) struct INFOPREF##_##NUM buf##NUM;
+#else
+#define INFO1RESBUF_DEFINITION(INFOPREF, ENTRIES)
+#define INFO1RESBUF_UNION_ENTRY(INFOPREF,NUM)
+#endif
+
+
+
+
+/*
+ * INFONRES_...
+ * Type constructors for multiple-result case
+ */
+
+#define INFONRES_RESULT(INFOPREF,NUM) \
+ struct INFOPREF##_##NUM##_result { \
+ DWORD entriesread; \
+ SIZE_IS(entriesread) \
+ struct INFOPREF##_##NUM *entries; \
+ };
+
+#define INFONRES_DEFINITION(INFOPREF, ENTRIES) \
+ INFONRES_UNION(INFOPREF, ENTRIES) \
+ INFONRES_STRUCT(INFOPREF)
+
+#define INFONRES_UNION(INFOPREF, ENTRIES) \
+ union INFOPREF##__ru { \
+ INFONRES_UNION_NULLPTR \
+ INFONRES_UNION_INFONRES \
+ ENTRIES \
+ };
+
+#define INFONRES_UNION_NULLPTR \
+ DEFAULT char * nullptr;
+
+#ifndef NDRGEN
+#define INFONRES_UNION_INFONRES \
+ struct mslm_infonres * p;
+#else
+#define INFONRES_UNION_INFONRES
+#endif
+
+#define INFONRES_UNION_ENTRY(INFOPREF,NUM) \
+ CASE(NUM) struct INFOPREF##_##NUM##_result * bufptr##NUM;
+
+#define INFONRES_STRUCT(INFOPREF) \
+ struct INFOPREF##_result { \
+ DWORD level; \
+ SWITCH(level) \
+ union INFOPREF##__ru bufptr; \
+ };
+
+#ifndef NDRGEN
+/*
+ * This just makes things a little easier on the stub modules:
+ *
+ * XXXGetInfoParam (struct XXXGetInfo_param *param) {
+ * struct mslm_infonres infonres;
+ *
+ * infonres.entriesread = 0;
+ * infonres.entries = 0;
+ * param->result.level = param->level; // for marshalling
+ * param->result.bufptr.p = &infonres;
+ */
+struct mslm_infonres {
+ DWORD entriesread;
+ void * entries;
+};
+#endif
+
+
+/*
+ * SERVER SERVICE (SRVSVC)
+ ****************************************************************
+ */
+
+
+#define SRVSVC_OPNUM_NetConnectEnum 0x08
+#define SRVSVC_OPNUM_NetFileEnum 0x09
+#define SRVSVC_OPNUM_NetFileClose 0x0b
+#define SRVSVC_OPNUM_NetSessionEnum 0x0c
+#define SRVSVC_OPNUM_NetSessionDel 0x0d
+#define SRVSVC_OPNUM_NetShareAdd 0x0e
+#define SRVSVC_OPNUM_NetShareEnum 0x0f
+#define SRVSVC_OPNUM_NetShareGetInfo 0x10
+#define SRVSVC_OPNUM_NetShareSetInfo 0x11
+#define SRVSVC_OPNUM_NetShareDel 0x12
+#define SRVSVC_OPNUM_NetServerGetInfo 0x15
+#define SRVSVC_OPNUM_NetServerSetInfo 0x16
+#define SRVSVC_OPNUM_NetRemoteTOD 0x1c
+#define SRVSVC_OPNUM_NetNameValidate 0x21
+#define SRVSVC_OPNUM_NetShareEnumSticky 0x24
+#define SRVSVC_OPNUM_NetGetFileSecurity 0x27
+#define SRVSVC_OPNUM_NetSetFileSecurity 0x28
+
+/*
+ ***********************************************************************
+ * NetConnectEnum:
+ *
+ * Description:
+ *
+ * Request for mslm_NetConnectEnum returns
+ * info of resources in MLRPC server connected
+ * to network. Correctly level 0 and level 1 information
+ * are supported.
+ *
+ ***********************************************************************
+ */
+
+/*
+ * Level 0 connect information.
+ */
+struct mslm_NetConnectInfoBuf0 {
+ DWORD coni0_id;
+};
+
+struct mslm_NetConnectInfo0 {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslm_NetConnectInfoBuf0 *ci0;
+};
+
+/*
+ * Level 1 connect information.
+ */
+struct mslm_NetConnectInfoBuf1 {
+ DWORD coni1_id;
+ DWORD coni1_type;
+ DWORD coni1_num_opens;
+ DWORD coni1_num_users;
+ DWORD coni1_time;
+ LPTSTR coni1_username;
+ LPTSTR coni1_netname; /* share name */
+};
+
+struct mslm_NetConnectInfo1 {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslm_NetConnectInfoBuf1 *ci1;
+};
+
+union mslm_NetConnectInfoResUnion {
+ CASE(0) struct mslm_NetConnectInfo0 *info0;
+ CASE(1) struct mslm_NetConnectInfo1 *info1;
+ DEFAULT char *nullptr;
+};
+
+struct mslm_NetConnectInfo {
+ DWORD level;
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mslm_NetConnectInfoResUnion ru;
+};
+
+OPERATION(SRVSVC_OPNUM_NetConnectEnum)
+struct mslm_NetConnectEnum {
+ IN LPTSTR servername;
+ IN LPTSTR qualifier; /* share name */
+ INOUT struct mslm_NetConnectInfo info;
+ IN DWORD pref_max_len;
+ OUT DWORD total_entries;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetFileEnum: under construction.
+ ***********************************************************************
+ */
+struct mslm_NetFileInfoBuf3 {
+ DWORD fi3_id;
+ DWORD fi3_permissions;
+ DWORD fi3_num_locks;
+ LPTSTR fi3_pathname;
+ LPTSTR fi3_username;
+};
+
+
+struct mslm_NetFileInfo3 {
+ DWORD entries_read;
+ SIZE_IS(entries_read)
+ struct mslm_NetFileInfoBuf3 *fi3;
+};
+
+
+union mslm_NetFileInfoResUnion {
+ CASE(3) struct mslm_NetFileInfo3 *info3;
+ DEFAULT char *nullptr;
+};
+
+
+struct mslm_NetFileInfo {
+ DWORD level;
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mslm_NetFileInfoResUnion ru;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetFileEnum)
+struct mslm_NetFileEnum {
+ IN LPTSTR servername;
+ IN DWORD unknown1;
+ IN DWORD unknown2;
+ INOUT struct mslm_NetFileInfo info;
+ IN DWORD pref_max_len;
+ OUT DWORD total_entries;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetFileClose
+ *
+ * I think this definition is complete but as it doesn't do anything
+ * it probably isn't a big issue. It is used to close files reported
+ * via NetFileEnum (i.e. the file id).
+ ***********************************************************************
+ */
+OPERATION(SRVSVC_OPNUM_NetFileClose)
+struct mslm_NetFileClose {
+ IN LPTSTR servername;
+ IN DWORD file_id;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetShareGetInfo: netname is the name of a share.
+ ***********************************************************************
+ */
+struct mslm_NetShareGetInfo0 {
+ LPTSTR shi0_netname;
+};
+
+
+struct mslm_NetShareGetInfo1 {
+ LPTSTR shi1_netname;
+ DWORD shi1_type; /* type of resource such as IPC$ */
+ LPTSTR shi1_comment;
+};
+
+
+struct mslm_NetShareGetInfo2 {
+ LPTSTR shi2_netname;
+ DWORD shi2_type;
+ LPTSTR shi2_comment;
+ DWORD shi2_permissions;
+ DWORD shi2_max_uses;
+ DWORD shi2_current_uses;
+ LPTSTR shi2_path;
+ LPTSTR shi2_passwd;
+};
+
+struct mslm_NetShareGetInfo502 {
+ LPTSTR shi502_netname;
+ DWORD shi502_type;
+ LPTSTR shi502_comment;
+ DWORD shi502_permissions;
+ DWORD shi502_max_uses;
+ DWORD shi502_current_uses;
+ LPTSTR shi502_path;
+ LPTSTR shi502_passwd;
+ DWORD shi502_reserved;
+ DWORD shi502_security_descriptor;
+};
+
+struct mslm_NetShareGetInfo1005 {
+ DWORD shi1005_flags;
+};
+
+union mlsm_NetShareGetInfoResUnion {
+ CASE(0) struct mslm_NetShareGetInfo0 *info0;
+ CASE(1) struct mslm_NetShareGetInfo1 *info1;
+ CASE(2) struct mslm_NetShareGetInfo2 *info2;
+ CASE(502) struct mslm_NetShareGetInfo502 *info502;
+ CASE(1005) struct mslm_NetShareGetInfo1005 *info1005;
+ DEFAULT char *nullptr;
+};
+
+
+struct mlsm_NetShareGetInfoRes {
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mlsm_NetShareGetInfoResUnion ru;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetShareGetInfo)
+struct mlsm_NetShareGetInfo {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR netname;
+ IN DWORD level;
+ OUT struct mlsm_NetShareGetInfoRes result;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetShareSetInfo: netname is the name of a share.
+ ***********************************************************************
+ */
+OPERATION(SRVSVC_OPNUM_NetShareSetInfo)
+struct mlsm_NetShareSetInfo {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR netname;
+ IN DWORD level;
+/*
+ * This should accept all the same levels as NetShareGetInfo
+ * but we always return ACCESS_DENIED for now. So there's no
+ * point in unmarshalling the share information.
+ *
+ * IN struct mlsm_NetShareGetInfoRes result;
+ */
+ OUT DWORD parm_err_ptr;
+ OUT DWORD parm_err;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetSessionEnum
+ *
+ * The NetSessionEnum function provides information about sessions
+ * established on a server.
+ *
+ * Only members of the Administrators or Account Operators local groups
+ * can successfully execute the NetSessionEnum function at level 1 or
+ * level 2. No special group membership is required for level 0 or level
+ * 10 calls.
+ *
+ * Windows NT/2000/XP: The parameter order is as follows.
+ *
+ * NET_API_STATUS NetSessionEnum(LPWSTR servername,
+ * LPWSTR UncClientName,
+ * LPWSTR username,
+ * DWORD level,
+ * LPBYTE *bufptr,
+ * DWORD prefmaxlen,
+ * LPDWORD entriesread,
+ * LPDWORD totalentries,
+ * LPDWORD resume_handle);
+ *
+ * Windows 95/98/Me: The calling application must use the cbBuffer parameter
+ * to specify the size, in bytes, of the information buffer pointed to by the
+ * pbBuffer parameter. (The cbBuffer parameter replaces the prefmaxlen
+ * parameter.) Neither a user name parameter nor a resume handle parameter is
+ * available on this platform. Therefore, the parameter list is as follows.
+ *
+ * API_FUNCTION NetSessionEnum(const char FAR *pszServer,
+ * short sLevel,
+ * char FAR *pbBuffer,
+ * unsigned short cbBuffer,
+ * unsigned short FAR *pcEntriesRead,
+ * unsigned short FAR *pcTotalAvail);
+ *
+ * Parameters
+ *
+ * servername
+ * [in] Pointer to a string that specifies the DNS or NetBIOS name of the
+ * remote server on which the function is to execute. If this parameter is
+ * NULL, the local computer is used.
+ * Windows NT 4.0 and earlier: This string must begin with \\.
+ *
+ * UncClientName
+ * [in] Pointer to a string that specifies the name of the computer session
+ * for which information is to be returned. If this parameter is NULL,
+ * NetSessionEnum returns information for all computer sessions on the server.
+ *
+ * username
+ * [in] Pointer to a string that specifies the name of the user for which
+ * information is to be returned. If this parameter is NULL, NetSessionEnum
+ * returns information for all users.
+ *
+ * level
+ * [in] Specifies the information level of the data. This parameter can be
+ * one of the following values.
+ * Windows NT/2000/XP: The following levels are valid.
+ * Value Meaning
+ * 0 Return the name of the computer that established the session.
+ * The bufptr parameter points to an array of SESSION_INFO_0
+ * structures.
+ * 1 Return the name of the computer, name of the user, and open files,
+ * pipes, and devices on the computer. The bufptr parameter points to
+ * an array of SESSION_INFO_1 structures.
+ * 2 In addition to the information indicated for level 1, return the
+ * type of client and how the user established the session. The bufptr
+ * parameter points to an array of SESSION_INFO_2 structures.
+ * 10 Return the name of the computer, name of the user, and active and
+ * idle times for the session. The bufptr parameter points to an array
+ * of SESSION_INFO_10 structures.
+ * 502 Return the name of the computer; name of the user; open files,
+ * pipes, and devices on the computer; and the name of the transport
+ * the client is using. The bufptr parameter points to an array of
+ * SESSION_INFO_502 structures.
+ *
+ * Windows 95/98/Me: The following level is valid.
+ * Value Meaning
+ * 50 Return the name of the computer, name of the user, open files on
+ * the computer, and the name of the transport protocol the client is
+ * using. The pbBuffer parameter points to an array of session_info_50
+ * structures.
+ *
+ * bufptr
+ * [out] Pointer to the buffer that receives the data. The format of this
+ * data depends on the value of the level parameter.
+ * Windows NT/2000/XP: This buffer is allocated by the system and must be
+ * freed using the NetApiBufferFree function. Note that you must free the
+ * buffer even if the function fails with ERROR_MORE_DATA.
+ * Windows 95/98/Me: The caller must allocate and deallocate this buffer.
+ *
+ * prefmaxlen
+ * [in] Specifies the preferred maximum length of returned data, in bytes.
+ * If you specify MAX_PREFERRED_LENGTH, the function allocates the amount
+ * of memory required for the data. If you specify another value in this
+ * parameter, it can restrict the number of bytes that the function returns.
+ * If the buffer size is insufficient to hold all entries, the function
+ * returns ERROR_MORE_DATA. For more information, see Network Management
+ * Function Buffers and Network Management Function Buffer Lengths.
+ *
+ * entriesread
+ * [out] Pointer to a value that receives the count of elements actually
+ * enumerated.
+ *
+ * totalentries
+ * [out] Pointer to a value that receives the total number of entries that
+ * could have been enumerated from the current resume position.
+ *
+ * resume_handle
+ * [in/out] Pointer to a value that contains a resume handle which is used
+ * to continue an existing session search. The handle should be zero on the
+ * first call and left unchanged for subsequent calls. If resume_handle is
+ * NULL, no resume handle is stored.
+ *
+ *
+ * SESSION_INFO_1
+ * ==============
+ * The SESSION_INFO_1 structure contains information about the session,
+ * including name of the computer; name of the user; and open files, pipes,
+ * and devices on the computer.
+ *
+ * Members
+ *
+ * sesi1_cname
+ * Pointer to a Unicode string specifying the name of the computer that
+ * established the session.
+ *
+ * sesi1_username
+ * Pointer to a Unicode string specifying the name of the user who established
+ * the session.
+ *
+ * sesi1_num_opens
+ * Specifies a DWORD value that contains the number of files, devices,
+ * and pipes opened during the session.
+ *
+ * sesi1_time
+ * Specifies a DWORD value that contains the number of seconds the session
+ * has been active.
+ *
+ * sesi1_idle_time
+ * Specifies a DWORD value that contains the number of seconds the session
+ * has been idle.
+ *
+ * sesi1_user_flags
+ * Specifies a DWORD value that describes how the user established the
+ * session. This member can be one of the following values:
+ * SESS_GUEST The user specified by the sesi1_username member
+ * established the session using a guest account.
+ * SESS_NOENCRYPTION The user specified by the sesi1_username member
+ * established the session without using password
+ * encryption.
+ ***********************************************************************
+ */
+
+#define SESS_GUEST 0x00000001
+#define SESS_NOENCRYPTION 0x00000002
+
+struct mslm_SESSION_INFO_0 {
+ LPTSTR sesi0_cname;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 0)
+
+struct mslm_SESSION_INFO_1 {
+ LPTSTR sesi1_cname;
+ LPTSTR sesi1_uname;
+ DWORD sesi1_nopens;
+ DWORD sesi1_time;
+ DWORD sesi1_itime;
+ DWORD sesi1_uflags;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 1)
+
+INFONRES_DEFINITION(mslm_NetSessionEnum,
+ INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 0)
+ INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 1))
+
+OPERATION(SRVSVC_OPNUM_NetSessionEnum)
+struct mslm_NetSessionEnum {
+ IN LPTSTR servername;
+ IN DWORD unc_clientname;
+ IN DWORD username;
+ INOUT DWORD level;
+ INOUT struct mslm_NetSessionEnum_result result;
+ IN DWORD pref_max_len;
+ OUT DWORD total_entries;
+ INOUT DWORD *resume_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * NetSessionDel (Platform SDK: Network Management)
+ *
+ * The NetSessionDel function ends a network session between a server
+ * and a workstation.
+ *
+ * Security Requirements
+ * Only members of the Administrators or Account Operators local group
+ * can successfully execute the NetSessionDel function.
+ *
+ * Windows NT/2000/XP: The parameter order is as follows.
+ *
+ * NET_API_STATUS NetSessionDel(LPWSTR servername,
+ * LPWSTR UncClientName,
+ * LPWSTR username);
+ *
+ * Windows 95/98/Me: The sReserved parameter replaces the username
+ * parameter. For more information, see the following Remarks section.
+ * The parameter list is as follows.
+ *
+ * API_FUNCTION NetSessionDel(const char FAR *pszServer,
+ * const char FAR *pszClientName,
+ * short sReserved);
+ *
+ * Parameters
+ *
+ * servername
+ * [in] Pointer to a string that specifies the DNS or NetBIOS name
+ * of the remote server on which the function is to execute. If this
+ * parameter is NULL, the local computer is used.
+ * Windows NT 4.0 and earlier: This string must begin with \\.
+ *
+ * UncClientName
+ * [in] Pointer to a string that specifies the computer name of the
+ * client to disconnect. If UncClientName is NULL, then all the sessions
+ * of the user identified by the username parameter will be deleted on
+ * the server specified by servername. For more information, see
+ * NetSessionEnum.
+ *
+ * username
+ * [in] Pointer to a string that specifies the name of the user whose
+ * session is to be terminated. If this parameter is NULL, all users'
+ * sessions from the client specified by the UncClientName parameter
+ * are to be terminated.
+ *
+ * Remarks
+ * Windows 95/98/Me: You must specify the session key in the sReserved
+ * parameter when you call NetSessionDel. The session key is returned by
+ * the NetSessionEnum function or the NetSessionGetInfo function in the
+ * sesi50_key member of the session_info_50 structure.
+ ***********************************************************************
+ */
+
+OPERATION(SRVSVC_OPNUM_NetSessionDel)
+struct mslm_NetSessionDel {
+ IN LPTSTR servername;
+ IN LPTSTR unc_clientname;
+ IN LPTSTR username;
+ OUT DWORD status;
+};
+
+
+/*
+ * SRVSVC NetServerGetInfo (
+ * IN LPTSTR servername,
+ * IN DWORD level,
+ * OUT union switch(level) {
+ * case 100: _SERVER_INFO_100 * p100;
+ * case 101: _SERVER_INFO_101 * p101;
+ * case 102: _SERVER_INFO_102 * p102;
+ * } bufptr,
+ * OUT DWORD status
+ * )
+ */
+
+/* for svX_platform */
+#define SV_PLATFORM_ID_OS2 400
+#define SV_PLATFORM_ID_NT 500
+
+/* Bit-mapped values for svX_type fields */
+#define SV_TYPE_WORKSTATION 0x00000001
+#define SV_TYPE_SERVER 0x00000002
+#define SV_TYPE_SQLSERVER 0x00000004
+#define SV_TYPE_DOMAIN_CTRL 0x00000008
+#define SV_TYPE_DOMAIN_BAKCTRL 0x00000010
+#define SV_TYPE_TIME_SOURCE 0x00000020
+#define SV_TYPE_AFP 0x00000040
+#define SV_TYPE_NOVELL 0x00000080
+#define SV_TYPE_DOMAIN_MEMBER 0x00000100
+#define SV_TYPE_PRINTQ_SERVER 0x00000200
+#define SV_TYPE_DIALIN_SERVER 0x00000400
+#define SV_TYPE_XENIX_SERVER 0x00000800
+#define SV_TYPE_SERVER_UNIX SV_TYPE_XENIX_SERVER
+#define SV_TYPE_NT 0x00001000
+#define SV_TYPE_WFW 0x00002000
+
+#define SV_TYPE_SERVER_MFPN 0x00004000
+#define SV_TYPE_SERVER_NT 0x00008000
+#define SV_TYPE_POTENTIAL_BROWSER 0x00010000
+#define SV_TYPE_BACKUP_BROWSER 0x00020000
+#define SV_TYPE_MASTER_BROWSER 0x00040000
+#define SV_TYPE_DOMAIN_MASTER 0x00080000
+#define SV_TYPE_SERVER_OSF 0x00100000
+#define SV_TYPE_SERVER_VMS 0x00200000
+#define SV_TYPE_WINDOWS 0x00400000 /* Windows95 and above */
+#define SV_TYPE_ALTERNATE_XPORT 0x20000000 /* return list for
+ * alternate transport */
+#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000 /* Return local list only */
+#define SV_TYPE_DOMAIN_ENUM 0x80000000
+#define SV_TYPE_ALL 0xFFFFFFFF /* handy for NetServerEnum2 */
+
+/* NT-Server 4.0 sends 0x0006_120B */
+#define SV_TYPE_SENT_BY_NT_4_0_SERVER \
+ ( SV_TYPE_WORKSTATION \
+ | SV_TYPE_SERVER \
+ | SV_TYPE_DOMAIN_CTRL \
+ | SV_TYPE_NT \
+ | SV_TYPE_BACKUP_BROWSER \
+ | SV_TYPE_MASTER_BROWSER)
+/* NT-workstation 4.0 send 0x0004_1013 */
+#define SV_TYPE_SENT_BY_NT_4_0_WORKSTATION \
+ ( SV_TYPE_WORKSTATION \
+ | SV_TYPE_SERVER \
+ | SV_TYPE_DOMAIN_BAKCTRL \
+ | SV_TYPE_NT \
+ | SV_TYPE_MASTER_BROWSER)
+
+/* Special value for sv102_disc that specifies infinite disconnect time */
+#define SV_NODISC (-1L) /* No autodisconnect timeout enforced */
+
+/* Values of svX_security field */
+#define SV_USERSECURITY 1
+#define SV_SHARESECURITY 0
+
+/* Values of svX_hidden field */
+#define SV_HIDDEN 1
+#define SV_VISIBLE 0
+
+
+/* Let's get some info already */
+struct mslm_SERVER_INFO_100 {
+ DWORD sv100_platform_id;
+ LPTSTR sv100_name;
+};
+
+struct mslm_SERVER_INFO_101 {
+ DWORD sv101_platform_id;
+ LPTSTR sv101_name;
+ DWORD sv101_version_major;
+ DWORD sv101_version_minor;
+ DWORD sv101_type;
+ LPTSTR sv101_comment;
+};
+
+struct mslm_SERVER_INFO_102 {
+ DWORD sv102_platform_id;
+ LPTSTR sv102_name;
+ DWORD sv102_version_major;
+ DWORD sv102_version_minor;
+ DWORD sv102_type;
+ LPTSTR sv102_comment;
+ DWORD sv102_users;
+ DWORD sv102_disc;
+ DWORD sv102_hidden; /* BOOL */
+ DWORD sv102_announce;
+ DWORD sv102_anndelta;
+ DWORD sv102_licenses;
+ LPTSTR sv102_userpath;
+};
+
+union mslm_NetServerGetInfo_ru {
+ CASE(100) struct mslm_SERVER_INFO_100 *bufptr100;
+ CASE(101) struct mslm_SERVER_INFO_101 *bufptr101;
+ CASE(102) struct mslm_SERVER_INFO_102 *bufptr102;
+ DEFAULT char *nullptr;
+};
+
+struct mslm_NetServerGetInfo_result {
+ DWORD level;
+ SWITCH(level)
+ union mslm_NetServerGetInfo_ru bufptr;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetServerGetInfo)
+struct mslm_NetServerGetInfo {
+ IN LPTSTR servername;
+ IN DWORD level;
+ OUT struct mslm_NetServerGetInfo_result result;
+ OUT DWORD status;
+};
+
+/*
+ * SRVSVC NetRemoteTOD (
+ * IN LPTSTR servername,
+ * OUT _TIME_OF_DAY_INFO *bufptr,
+ * OUT long status
+ * )
+ */
+
+struct mslm_TIME_OF_DAY_INFO {
+ DWORD tod_elapsedt;
+ DWORD tod_msecs;
+ DWORD tod_hours;
+ DWORD tod_mins;
+ DWORD tod_secs;
+ DWORD tod_hunds;
+ DWORD tod_timezone;
+ DWORD tod_tinterval;
+ DWORD tod_day;
+ DWORD tod_month;
+ DWORD tod_year;
+ DWORD tod_weekday;
+};
+
+OPERATION(SRVSVC_OPNUM_NetRemoteTOD)
+struct mslm_NetRemoteTOD {
+ IN LPTSTR servername;
+ OUT struct mslm_TIME_OF_DAY_INFO *bufptr;
+ OUT DWORD status;
+};
+
+/*
+ * SRVSVC_NetNameValidate (
+ * IN LPTSTR servername;
+ * IN REFERENCE LPTSTR pathname;
+ * IN DWORD type;
+ * IN DWORD flags;
+ * OUT DWORD status;
+ * )
+ */
+OPERATION(SRVSVC_OPNUM_NetNameValidate)
+struct mslm_NetNameValidate {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR pathname;
+ IN DWORD type;
+ IN DWORD flags;
+ OUT DWORD status;
+};
+
+/*
+ * SRVSVC NetShareEnum (
+ * IN LPTSTR servername,
+ * IN DWORD level;
+ * OUT union switch(level) {
+ * case 0: struct {
+ * DWORD entriesread;
+ * [size_is(entriesread)]
+ * _SHARE_INFO_0 *entries;
+ * } *bufptr0;
+ * case 1: struct {
+ * DWORD entriesread;
+ * [size_is(entriesread)]
+ * _SHARE_INFO_1 *entries;
+ * } *bufptr1;
+ * ...
+ * } bufptr,
+ * IN DWORD prefmaxlen,
+ * OUT DWORD totalentries,
+ * IN OUT DWORD ?* resume_handle,
+ * OUT DWORD status
+ * )
+ */
+
+/*
+ * Share types for shiX_type fields - duplicated from cifs.h
+ */
+#ifndef _SHARE_TYPES_DEFINED_
+#define _SHARE_TYPES_DEFINED_
+#define STYPE_DISKTREE 0x00000000
+#define STYPE_PRINTQ 0x00000001
+#define STYPE_DEVICE 0x00000002
+#define STYPE_IPC 0x00000003
+#define STYPE_MASK 0x0000000F
+#define STYPE_DFS 0x00000064
+#define STYPE_HIDDEN 0x80000000
+#define STYPE_SPECIAL 0x80000000
+#endif /* _SHARE_TYPES_DEFINED_ */
+
+/* Maximum uses for shiX_max_uses fields */
+#define SHI_USES_UNLIMITED (DWORD)-1
+
+
+
+struct mslm_SHARE_INFO_0 {
+ LPTSTR shi0_netname;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,0)
+
+struct mslm_SHARE_INFO_1 {
+ LPTSTR shi1_netname;
+ DWORD shi1_type;
+ LPTSTR shi1_remark;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,1)
+
+struct mslm_SHARE_INFO_2 {
+ LPTSTR shi2_netname;
+ DWORD shi2_type;
+ LPTSTR shi2_remark;
+ DWORD shi2_permissions;
+ DWORD shi2_max_uses;
+ DWORD shi2_current_uses;
+ LPTSTR shi2_path;
+ LPTSTR shi2_passwd;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,2)
+
+/*
+ * Note: shi502_security_descriptor should be a pointer to a
+ * security descriptor (W32SEC_SECURITY_DESCRIPTOR):
+ * PSECURITY_DESCRIPTOR shi502_security_descriptor;
+ *
+ * For now we can just use a DWORD and set it to zero.
+ */
+struct mslm_SHARE_INFO_502 {
+ LPTSTR shi502_netname;
+ DWORD shi502_type;
+ LPTSTR shi502_remark;
+ DWORD shi502_permissions;
+ DWORD shi502_max_uses;
+ DWORD shi502_current_uses;
+ LPTSTR shi502_path;
+ LPTSTR shi502_passwd;
+ DWORD shi502_reserved;
+ DWORD shi502_security_descriptor;
+};
+INFONRES_RESULT(mslm_SHARE_INFO,502)
+
+union mslm_NetShareAddInfo_u {
+ CASE(2) struct mslm_SHARE_INFO_2 *info2;
+ CASE(502) struct mslm_SHARE_INFO_502 *info502;
+};
+
+struct mslm_NetShareAddInfo {
+ DWORD switch_value;
+ SWITCH(switch_value)
+ union mslm_NetShareAddInfo_u un;
+};
+
+
+OPERATION(SRVSVC_OPNUM_NetShareAdd)
+struct mslm_NetShareAdd {
+ IN LPTSTR servername;
+ IN DWORD level;
+ IN struct mslm_NetShareAddInfo info;
+ INOUT DWORD *parm_err;
+ OUT DWORD status;
+};
+
+
+INFONRES_DEFINITION(mslm_NetShareEnum,
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,0)
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,1)
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,2)
+ INFONRES_UNION_ENTRY(mslm_SHARE_INFO,502))
+
+
+OPERATION(SRVSVC_OPNUM_NetShareEnum)
+struct mslm_NetShareEnum {
+ IN LPTSTR servername;
+ INOUT DWORD level;
+ OUT struct mslm_NetShareEnum_result result;
+ IN DWORD prefmaxlen;
+ OUT DWORD totalentries;
+ INOUT DWORD * resume_handle; /* not sure about ptr */
+ OUT DWORD status;
+};
+
+
+/*
+ * Delete a share. The reserved field appears in netmon
+ * but I've left it out in case it's not always present.
+ * This won't affect RPC processing.
+ */
+OPERATION(SRVSVC_OPNUM_NetShareDel)
+struct mslm_NetShareDel {
+ IN LPTSTR servername;
+ IN REFERENCE LPTSTR netname;
+ /* IN DWORD reserved; */
+ OUT DWORD status;
+};
+
+
+/*
+ * NetShareEnumSticky is the same as NetShareEnum except that hidden
+ * shares are not returned. This call was apparently added due to a
+ * bug in the NT implementation of NetShareEnum - it didn't process
+ * the resume handle correctly so that attempts to enumerate large
+ * share lists resulted in an infinite loop.
+ */
+OPERATION(SRVSVC_OPNUM_NetShareEnumSticky)
+struct mslm_NetShareEnumSticky {
+ IN LPTSTR servername;
+ INOUT DWORD level;
+ OUT struct mslm_NetShareEnum_result result;
+ IN DWORD prefmaxlen;
+ OUT DWORD totalentries;
+ INOUT DWORD * resume_handle; /* not sure about ptr */
+ OUT DWORD status;
+};
+
+/*
+ * When you install Windows NT Server Tools on a Win95 client,
+ * a security tab will be added to properties dialog box of files/folders.
+ * Within this security tab, when you try to get/set permissions on a
+ * file/folder the next two RPC calls are used.
+ */
+OPERATION(SRVSVC_OPNUM_NetGetFileSecurity)
+struct mslm_NetGetFileSecurity {
+ IN LPTSTR servername;
+ IN LPTSTR sharename;
+ IN REFERENCE LPTSTR filename;
+ IN DWORD securityinfo;
+
+ /*
+ * Right now, we can't send back SD of the requested object
+ * in MLRPC code, so we just reply with access denied error
+ * code. Thus, this output declaration is only valid in this
+ * case i.e., it's not complete.
+ * It looks like:
+ *
+ * A Pointer
+ * A Length
+ *
+ * A Pointer
+ * A Length (equal to the prev length)
+ * A buffer
+ *
+ * return value
+ */
+ OUT DWORD length;
+ OUT DWORD status;
+};
+
+/*
+ * This is the request:
+ *
+ * R_SRVSVC: RPC Client call srvsvc:NetrpSetFileSecurity(..)
+ * R_SRVSVC: SRVSVC_HANDLE ServerName = \\WK76-177
+ * R_SRVSVC: LPWSTR ShareName = AFSHIN
+ * R_SRVSVC: LPWSTR lpFileName = \salek.txt
+ * R_SRVSVC: SECURITY_INFORMATION SecurityInformation = 4 (0x4)
+ * -R_SRVSVC: PADT_SECURITY_DESCRIPTOR SecurityDescriptor {..}
+ * R_SRVSVC: DWORD Length = 64 (0x40)
+ * R_SRVSVC: LPBYTE Buffer = 4496048 (0x449AB0)
+ * R_SRVSVC: LPBYTE Buffer [..] = 01 00 04 80 00 00 00 00 00 00 00 00 00 00 00
+ * ...
+ *
+ * 000000A0 00 83 46 00 0B 00 00 00 00 00 00 00 0B 00 ..F...........
+ * 000000B0 00 00 5C 00 5C 00 57 00 4B 00 37 00 36 00 2D 00 ..\.\.W.K.7.6.-.
+ * 000000C0 31 00 37 00 37 00 00 00 08 00 16 83 46 00 07 00 1.7.7.......F...
+ * 000000D0 00 00 00 00 00 00 07 00 00 00 41 00 46 00 53 00 ..........A.F.S.
+ * 000000E0 48 00 49 00 4E 00 00 00 00 00 0B 00 00 00 00 00 H.I.N...........
+ * 000000F0 00 00 0B 00 00 00 5C 00 73 00 61 00 6C 00 65 00 ......\.s.a.l.e.
+ * 00000100 6B 00 2E 00 74 00 78 00 74 00 00 00 00 00 04 00 k...t.x.t.......
+ * 00000110 00 00 40 00 00 00 B0 9A 44 00 40 00 00 00 01 00 ..@.....D.@.....
+ * 00000120 04 80 00 00 00 00 00 00 00 00 00 00 00 00 14 00 ................
+ * 00000130 00 00 02 00 2C 00 01 00 00 00 00 00 24 00 00 00 ....,.......$...
+ * 00000140 00 A0 01 05 00 00 00 00 00 05 15 00 00 00 1A 24 ...............$
+ * 00000150 44 38 90 00 0F 02 65 3A BE 4C FF 03 00 00 00 00 D8....e:.L......
+ * 00000160 00 00 00 00 00 00 00 00 00 00 ..........
+ */
+OPERATION(SRVSVC_OPNUM_NetSetFileSecurity)
+struct mslm_NetSetFileSecurity {
+ IN LPTSTR servername;
+ IN LPTSTR sharename;
+ IN REFERENCE LPTSTR filename;
+ IN DWORD securityinfo;
+ /*
+ * IN Security Descriptor (looks like):
+ * Length1
+ * Pointer
+ * Length2 (== Length1)
+ * buffer itself
+ */
+
+ OUT DWORD status;
+};
+
+/*
+ * The SRVSVC already
+ */
+INTERFACE(0)
+union srvsvc_interface {
+ CASE(SRVSVC_OPNUM_NetConnectEnum)
+ struct mslm_NetConnectEnum NetConnectEnum;
+ CASE(SRVSVC_OPNUM_NetFileEnum)
+ struct mslm_NetFileEnum NetFileEnum;
+ CASE(SRVSVC_OPNUM_NetFileClose)
+ struct mslm_NetFileClose NetFileClose;
+ CASE(SRVSVC_OPNUM_NetShareGetInfo)
+ struct mlsm_NetShareGetInfo NetShareGetInfo;
+ CASE(SRVSVC_OPNUM_NetShareSetInfo)
+ struct mlsm_NetShareGetInfo NetShareSetInfo;
+ CASE(SRVSVC_OPNUM_NetSessionDel)
+ struct mslm_NetSessionDel NetSessionDel;
+ CASE(SRVSVC_OPNUM_NetSessionEnum)
+ struct mslm_NetSessionEnum NetSessionEnum;
+ CASE(SRVSVC_OPNUM_NetServerGetInfo)
+ struct mslm_NetServerGetInfo NetServerGetInfo;
+ CASE(SRVSVC_OPNUM_NetRemoteTOD)
+ struct mslm_NetRemoteTOD NetRemoteTOD;
+ CASE(SRVSVC_OPNUM_NetNameValidate)
+ struct mslm_NetNameValidate NetNameValidate;
+ CASE(SRVSVC_OPNUM_NetShareAdd)
+ struct mslm_NetShareAdd NetShareAdd;
+ CASE(SRVSVC_OPNUM_NetShareDel)
+ struct mslm_NetShareDel NetShareDel;
+ CASE(SRVSVC_OPNUM_NetShareEnum)
+ struct mslm_NetShareEnum NetShareEnum;
+ CASE(SRVSVC_OPNUM_NetShareEnumSticky)
+ struct mslm_NetShareEnumSticky NetShareEnumSticky;
+ CASE(SRVSVC_OPNUM_NetGetFileSecurity)
+ struct mslm_NetGetFileSecurity NetGetFileSecurity;
+ CASE(SRVSVC_OPNUM_NetSetFileSecurity)
+ struct mslm_NetSetFileSecurity NetSetFileSecurity;
+};
+typedef union srvsvc_interface srvsvc_interface_t;
+EXTERNTYPEINFO(srvsvc_interface)
+
+
+
+/*
+ * WKSSVC -- Workstation Service
+ ****************************************************************
+ */
+
+#define WKSSVC_OPNUM_NetWkstaGetInfo 0x00
+
+
+/*
+ * NET_API_STATUS NET_API_FUNCTION
+ * NetWkstaGetInfo (
+ * IN LPTSTR servername OPTIONAL,
+ * IN DWORD level,
+ * OUT LPBYTE *bufptr
+ * );
+ */
+
+struct mslm_WKSTA_INFO_100 {
+ DWORD wki100_platform_id;
+ LPTSTR wki100_computername;
+ LPTSTR wki100_langroup;
+ DWORD wki100_ver_major;
+ DWORD wki100_ver_minor;
+};
+
+/* NetWkstaGetInfo only. System information - user access */
+struct mslm_WKSTA_INFO_101 {
+ DWORD wki101_platform_id;
+ LPTSTR wki101_computername;
+ LPTSTR wki101_langroup;
+ DWORD wki101_ver_major;
+ DWORD wki101_ver_minor;
+ LPTSTR wki101_lanroot;
+};
+
+/* NetWkstaGetInfo only. System information - admin or operator access */
+struct mslm_WKSTA_INFO_102 {
+ DWORD wki102_platform_id;
+ LPTSTR wki102_computername;
+ LPTSTR wki102_langroup;
+ DWORD wki102_ver_major;
+ DWORD wki102_ver_minor;
+ LPTSTR wki102_lanroot;
+ DWORD wki102_logged_on_users;
+};
+
+INFO1RES_DEFINITION(mslm_NetWkstaGetInfo,
+ INFO1RES_UNION_ENTRY(mslm_WKSTA_INFO,100)
+ INFO1RES_UNION_ENTRY(mslm_WKSTA_INFO,101)
+ INFO1RES_UNION_ENTRY(mslm_WKSTA_INFO,102))
+
+INFO1RESBUF_DEFINITION(mslm_NetWkstaGetInfo,
+ INFO1RESBUF_UNION_ENTRY(mslm_WKSTA_INFO,100)
+ INFO1RESBUF_UNION_ENTRY(mslm_WKSTA_INFO,101)
+ INFO1RESBUF_UNION_ENTRY(mslm_WKSTA_INFO,102))
+
+
+OPERATION(WKSSVC_OPNUM_NetWkstaGetInfo)
+struct mslm_NetWkstaGetInfo {
+ IN LPTSTR servername;
+ IN DWORD level;
+ OUT struct mslm_NetWkstaGetInfo_result result;
+ OUT DWORD status;
+};
+
+/*
+ * The WKSSVC already
+ */
+INTERFACE(0)
+union wkssvc_interface {
+ CASE(WKSSVC_OPNUM_NetWkstaGetInfo)
+ struct mslm_NetWkstaGetInfo NetWkstaGetInfo;
+};
+typedef union wkssvc_interface wkssvc_interface_t;
+EXTERNTYPEINFO(wkssvc_interface)
+
+
+#endif /* _MLSVC_LANMAN_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/svcctl.ndl b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
new file mode 100644
index 0000000000..a2fb7f6705
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
@@ -0,0 +1,287 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_SVCCTL_NDL_
+#define _MLSVC_SVCCTL_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Service Control Services (SVCCTL) RPC interface definition.
+ * This interface provides remote access to add, remove, start and
+ * stop services.
+ */
+
+#include "ndrtypes.ndl"
+
+#define SVCCTL_OPNUM_Close 0x00
+#define SVCCTL_OPNUM_QueryServiceStatus 0x06
+#define SVCCTL_OPNUM_EnumServicesStatus 0x0E
+#define SVCCTL_OPNUM_OpenManager 0x0F
+#define SVCCTL_OPNUM_OpenService 0x10
+#define SVCCTL_OPNUM_QueryServiceConfig 0x11
+
+/*
+ * Standard opaque 20 byte RPC handle.
+ */
+
+
+struct svcctl_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+
+typedef struct svcctl_handle svcctl_handle_t;
+
+/*
+ * The svc_status (SERVICE_STATUS) structure contains information about a
+ * service. The ControlService, EnumDependentServices, EnumServicesStatus,
+ * and QueryServiceStatus functions use this structure to return information
+ * about a service. A service uses this structure in the SetServiceStatus
+ * function to report its current status to the service control manager.
+ *
+ * service_type
+ * The type of service. This member can be one of the following values.
+ *
+ * SERVICE_FILE_SYSTEM_DRIVER
+ * SERVICE_KERNEL_DRIVER
+ * SERVICE_WIN32_OWN_PROCESS
+ * SERVICE_WIN32_SHARE_PROCESS
+ *
+ * If the service type is either SERVICE_WIN32_OWN_PROCESS or
+ * SERVICE_WIN32_SHARE_PROCESS, and the service is running in
+ * the context of the LocalSystem account, the following type
+ * may also be specified to indicate that the service can
+ * interact with the desktop.
+ *
+ * SERVICE_INTERACTIVE_PROCESS
+ *
+ * cur_state
+ * The current state of the service. This member can be one of the
+ * following values.
+ *
+ * SERVICE_CONTINUE_PENDING
+ * SERVICE_PAUSE_PENDING
+ * SERVICE_PAUSED
+ * SERVICE_RUNNING
+ * SERVICE_START_PENDING
+ * SERVICE_STOP_PENDING
+ * SERVICE_STOPPED
+ *
+ * ctrl_accepted
+ * The control codes that the service will accept and process in its
+ * handler function (see Handler and HandlerEx). A user interface
+ * process can control a service by specifying a control command in
+ * the ControlService function. By default, all services accept the
+ * SERVICE_CONTROL_INTERROGATE value. The following are the control
+ * codes.
+ *
+ * SERVICE_ACCEPT_STOP
+ * SERVICE_ACCEPT_PAUSE_CONTINUE
+ * SERVICE_ACCEPT_SHUTDOWN
+ * SERVICE_ACCEPT_PARAMCHANGE
+ * SERVICE_ACCEPT_NETBINDCHANGE
+ *
+ * w32_exitcode
+ * An error code that the service uses to report an error that occurs when
+ * it is starting or stopping. To return an error code specific to the
+ * service, the service must set this value to ERROR_SERVICE_SPECIFIC_ERROR
+ * to indicate that the dwServiceSpecificExitCode member contains the error
+ * code. The service should set this value to NO_ERROR when it is running
+ * and on normal termination.
+ *
+ * svc_specified_exitcode
+ * A service-specific error code that the service returns when an error
+ * occurs while the service is starting or stopping. This value is ignored
+ * unless the w32_exitcode member is set to ERROR_SERVICE_SPECIFIC_ERROR.
+ *
+ * check_point
+ * A value that the service increments periodically to report its progress
+ * during a lengthy start, stop, pause, or continue operation. For example,
+ * the service should increment this value as it completes each step of its
+ * initialization when it is starting up. The user interface program that
+ * invoked the operation on the service uses this value to track the progress
+ * of the service during a lengthy operation. This value is not valid and
+ * should be zero when the service does not have a start, stop, pause, or
+ * continue operation pending.
+ *
+ * wait_hint
+ * An estimate of the amount of time, in milliseconds, that the service
+ * expects a pending start, stop, pause, or continue operation to take
+ * before the service makes its next call to the SetServiceStatus
+ * function with either an incremented check_point value or a change in
+ * dwCurrentState. If the amount of time specified by wait_hint passes,
+ * and check_point has not been incremented, or cur_state has not changed,
+ * the service control manager or service control program can assume that
+ * an error has occurred and the service should be stopped.
+ */
+struct svc_status {
+ DWORD service_type;
+ DWORD cur_state;
+ DWORD ctrl_accepted;
+ DWORD w32_exitcode;
+ DWORD svc_specified_exitcode;
+ DWORD check_point;
+ DWORD wait_hint;
+};
+typedef struct svc_status svc_status_t;
+
+struct svc_enum_status {
+ DWORD svc_name; /* offset within response buffer */
+ DWORD display_name; /* offset within response buffer */
+ svc_status_t svc_status;
+};
+typedef struct svc_enum_status svc_enum_status_t;
+
+struct svc_config {
+ DWORD service_type;
+ DWORD start_type;
+ DWORD error_control;
+ LPTSTR binary_pathname;
+ LPTSTR loadorder_group;
+ DWORD tag_id;
+ LPTSTR dependencies;
+ LPTSTR service_startname;
+ LPTSTR display_name;
+};
+typedef struct svc_config svc_config_t;
+
+
+/*
+ ***********************************************************************
+ * Close
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_Close)
+struct svcctl_Close {
+ IN svcctl_handle_t handle;
+ OUT svcctl_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenManager
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_OpenManager)
+struct svcctl_OpenManager {
+ IN LPTSTR machine_name;
+ IN LPTSTR database_name;
+ IN DWORD desired_access;
+ OUT svcctl_handle_t handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * OpenService
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_OpenService)
+struct svcctl_OpenService {
+ IN svcctl_handle_t manager_handle;
+ IN REFERENCE LPTSTR service_name;
+ IN DWORD desired_access;
+ OUT svcctl_handle_t service_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ ***********************************************************************
+ * QueryServiceStatus
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_QueryServiceStatus)
+struct svcctl_QueryServiceStatus {
+ IN svcctl_handle_t service_handle;
+ OUT svc_status_t service_status;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * EnumServicesStatus
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_EnumServicesStatus)
+struct svcctl_EnumServicesStatus {
+ IN svcctl_handle_t manager_handle;
+ IN DWORD svc_type;
+ IN DWORD svc_state;
+ INOUT DWORD buf_size;
+ IN DWORD unknown;
+ OUT BYTE services[1024];
+ OUT DWORD bytes_needed;
+ OUT DWORD svc_num;
+ OUT DWORD resume_handle;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * QueryServiceConfig
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_QueryServiceConfig)
+struct svcctl_QueryServiceConfig {
+ IN svcctl_handle_t service_handle;
+ IN DWORD buf_size;
+ OUT svc_config_t service_cfg;
+ OUT DWORD cfg_bytes;
+ OUT DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * The SVCCTL interface definition.
+ ***********************************************************************
+ */
+INTERFACE(0)
+union svcctl_interface {
+ CASE(SVCCTL_OPNUM_Close)
+ struct svcctl_Close SvcClose;
+ CASE(SVCCTL_OPNUM_OpenManager)
+ struct svcctl_OpenManager SvcOpenManager;
+ CASE(SVCCTL_OPNUM_OpenService)
+ struct svcctl_OpenService SvcOpenService;
+ CASE(SVCCTL_OPNUM_QueryServiceStatus)
+ struct svcctl_QueryServiceStatus SvcQueryServiceStatus;
+ CASE(SVCCTL_OPNUM_EnumServicesStatus)
+ struct svcctl_EnumServicesStatus SvcEnumServicesStatus;
+ CASE(SVCCTL_OPNUM_QueryServiceConfig)
+ struct svcctl_QueryServiceConfig SvcQueryServiceConfig;
+};
+
+typedef union svcctl_interface svcctl_interface_t;
+EXTERNTYPEINFO(svcctl_interface)
+
+
+#endif /* _MLSVC_SVCCTL_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndl/winreg.ndl b/usr/src/uts/common/smbsrv/ndl/winreg.ndl
new file mode 100644
index 0000000000..2d3d1de28d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndl/winreg.ndl
@@ -0,0 +1,288 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MLSVC_WINREG_NDL_
+#define _MLSVC_WINREG_NDL_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Windows Registry (WINREG) RPC interface definition.
+ */
+
+#include "ndrtypes.ndl"
+
+#define WINREG_OPNUM_OpenHKLM 0x02
+#define WINREG_OPNUM_OpenHKUsers 0x04
+#define WINREG_OPNUM_Close 0x05
+#define WINREG_OPNUM_CreateKey 0x06
+#define WINREG_OPNUM_DeleteKey 0x07
+#define WINREG_OPNUM_DeleteValue 0x08
+#define WINREG_OPNUM_EnumKey 0x09
+#define WINREG_OPNUM_EnumValue 0x0a
+#define WINREG_OPNUM_FlushKey 0x0b
+#define WINREG_OPNUM_GetKeySec 0x0c
+#define WINREG_OPNUM_OpenKey 0x0f
+#define WINREG_OPNUM_QueryKey 0x10
+#define WINREG_OPNUM_QueryValue 0x11
+#define WINREG_OPNUM_SetKeySec 0x15
+#define WINREG_OPNUM_CreateValue 0x16
+#define WINREG_OPNUM_Shutdown 0x18
+#define WINREG_OPNUM_GetVersion 0x1a
+
+
+struct msreg_handle {
+ DWORD hand1;
+ DWORD hand2;
+ WORD hand3[2];
+ BYTE hand4[8];
+};
+typedef struct msreg_handle msreg_handle_t;
+
+struct msreg_string_desc {
+ WORD length;
+ WORD allosize;
+ LPTSTR str;
+};
+typedef struct msreg_string_desc msreg_string_t;
+
+/*
+ * Fake Varying/Conformant with a funny conformant.
+ */
+struct msreg_value {
+ DWORD vc_first_is; /* 0 */
+ DWORD vc_length_is;
+ SIZE_IS(vc_length_is)
+ BYTE value[ANY_SIZE_ARRAY];
+};
+
+struct file_time {
+ DWORD low;
+ DWORD high;
+};
+typedef struct file_time file_time_t;
+
+
+OPERATION(WINREG_OPNUM_OpenHKLM)
+struct msreg_OpenHKLM {
+ IN BYTE whatever[8];
+ IN DWORD access_mask;
+ OUT msreg_handle_t handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_OpenHKUsers)
+struct msreg_OpenHKUsers {
+ IN BYTE whatever[8];
+ IN DWORD access_mask;
+ OUT msreg_handle_t handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_Close)
+struct msreg_Close {
+ IN msreg_handle_t handle;
+ OUT msreg_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_CreateKey)
+struct msreg_CreateKey {
+ IN msreg_handle_t handle;
+ IN msreg_string_t subkey;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_DeleteKey)
+struct msreg_DeleteKey {
+ IN msreg_handle_t handle;
+ IN msreg_string_t subkey;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_DeleteValue)
+struct msreg_DeleteValue {
+ IN msreg_handle_t handle;
+ IN msreg_string_t name;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+/*
+ * Some of the OUT parameters are also supplied
+ * as IN parameters but we can ignore them.
+ */
+OPERATION(WINREG_OPNUM_EnumValue)
+struct msreg_EnumValue {
+ IN msreg_handle_t handle;
+ IN DWORD index;
+ /* IN ignore the remaining input data */
+
+ OUT msreg_string_t name;
+ OUT DWORD *type;
+ OUT struct msreg_value *value;
+ OUT DWORD *value_size;
+ OUT DWORD *value_size_total;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_OpenKey)
+struct msreg_OpenKey {
+ IN msreg_handle_t handle;
+ IN msreg_string_t name;
+ IN DWORD unknown;
+ IN DWORD access_mask;
+ OUT msreg_handle_t result_handle;
+ OUT DWORD status;
+};
+
+
+/*
+ * 000000A0 00 00 00 00 C1 F9 C0 86 18 B1 ..........
+ * 000000B0 D5 11 99 C8 00 C0 F0 1F 42 26 00 00 10 04 CC ED ........B&......
+ * 000000C0 12 00 08 02 00 00 00 00 00 00 00 00 00 00 ..............
+ DWORD unknown_0x04100000;
+ DWORD unkown_ptr;
+ DWORD unknown_0x00000208;
+ DWORD unknown2;
+ DWORD unknown3;
+ */
+
+OPERATION(WINREG_OPNUM_QueryKey)
+struct msreg_QueryKey {
+ IN msreg_handle_t handle;
+ /*
+ * Ignore the remaining input data
+ * (2 * DWORD, possibly msreg_string_t).
+ */
+
+ OUT msreg_string_t name;
+ OUT DWORD unknown;
+ OUT DWORD sub_keys;
+ OUT DWORD max_subkey_len;
+ OUT DWORD max_class_len;
+ OUT DWORD values;
+ OUT DWORD max_value_namelen;
+ OUT DWORD max_value_len;
+ OUT DWORD security_desc;
+ OUT file_time_t last_write_time;
+ OUT DWORD status;
+};
+
+
+/*
+ * Some of the OUT parameters are also supplied
+ * as IN parameters but we can ignore them.
+ */
+OPERATION(WINREG_OPNUM_QueryValue)
+struct msreg_QueryValue {
+ IN msreg_handle_t handle;
+ IN msreg_string_t value_name;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD *type;
+ OUT struct msreg_value *value;
+ OUT DWORD *value_size;
+ OUT DWORD *value_size_total;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_CreateValue)
+struct msreg_CreateValue {
+ IN msreg_handle_t handle;
+ IN msreg_string_t name;
+ /* IN ignore the remaining input data */
+
+ OUT DWORD status;
+};
+
+
+/*
+ * The real structure of shutdown passes some strings, a timeout
+ * and reboot/shutdown flags but this allows us to accept the call,
+ * without anything appearing in the log, and return access denied.
+ */
+OPERATION(WINREG_OPNUM_Shutdown)
+struct msreg_Shutdown {
+ IN DWORD ignored;
+ OUT DWORD status;
+};
+
+
+OPERATION(WINREG_OPNUM_GetVersion)
+struct msreg_GetVersion {
+ IN msreg_handle_t handle;
+ OUT DWORD version;
+ OUT DWORD status;
+};
+
+
+/*
+ * The WINREG interface.
+ */
+INTERFACE(0)
+union winreg_interface {
+ CASE(WINREG_OPNUM_OpenHKLM)
+ struct msreg_OpenHKLM OpenHKLM;
+ CASE(WINREG_OPNUM_OpenHKUsers)
+ struct msreg_OpenHKUsers OpenHKUsers;
+ CASE(WINREG_OPNUM_Close)
+ struct msreg_Close Close;
+ CASE(WINREG_OPNUM_CreateKey)
+ struct msreg_CreateKey CreateKey;
+ CASE(WINREG_OPNUM_DeleteKey)
+ struct msreg_DeleteKey DeleteKey;
+ CASE(WINREG_OPNUM_DeleteValue)
+ struct msreg_DeleteValue DeleteValue;
+ CASE(WINREG_OPNUM_OpenKey)
+ struct msreg_OpenKey OpenKey;
+ CASE(WINREG_OPNUM_QueryKey)
+ struct msreg_QueryKey QueryKey;
+ CASE(WINREG_OPNUM_QueryValue)
+ struct msreg_QueryValue QueryValue;
+ CASE(WINREG_OPNUM_CreateValue)
+ struct msreg_CreateValue CreateValue;
+ CASE(WINREG_OPNUM_Shutdown)
+ struct msreg_Shutdown Shutdown;
+ CASE(WINREG_OPNUM_GetVersion)
+ struct msreg_GetVersion GetVersion;
+};
+typedef union winreg_interface winreg_interface_t;
+EXTERNTYPEINFO(winreg_interface)
+
+#endif /* _MLSVC_WINREG_NDL_ */
diff --git a/usr/src/uts/common/smbsrv/ndr.h b/usr/src/uts/common/smbsrv/ndr.h
new file mode 100644
index 0000000000..36c502d1b9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ndr.h
@@ -0,0 +1,468 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NDR_H
+#define _SMBSRV_NDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Network Data Representation (NDR) is a compatible subset of DCE RPC
+ * and MSRPC NDR. NDR is used to move parameters consisting of
+ * complicated trees of data constructs between an RPC client and server.
+ *
+ * CAE Specification (1997)
+ * DCE 1.1: Remote Procedure Call
+ * Document Number: C706
+ * The Open Group
+ * ogspecs@opengroup.org
+ */
+
+#ifndef _KERNEL
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Normal sequence:
+ * - Application calls client-side stub w/ TOP-MOST arg structure
+ * - client stub performs NDR_M_OP_MARSHALL+NDR_DIR_IN
+ * - PDU conveyed (request, aka call, aka query)
+ * - server stub performs NDR_M_OP_UNMARSHALL+NDR_DIR_IN
+ * - server function called w/ TOP-MOST arg structure
+ * - server function returns w/ TOP-MOST arg structure modified
+ * - server stub performs NDR_M_OP_MARSHALL+NDR_DIR_OUT
+ * - PDU conveyed (reply, aka result, aka response)
+ * - client stub performs NDR_M_OP_UNMARSHALL+NDR_DIR_OUT
+ * - return to Application w/ TOP-MOST arg structure modified
+ *
+ * An interface is a sequence of top-most constructs. Each top-most
+ * construct corresponds to one parameter, either argument or return
+ * value.
+ *
+ * A top-most construct is a sequence of outer constructs. The first
+ * outer construct is the referent of the argument, and the subsequent
+ * outer constructs are descendents referenced by pointers from prior
+ * constructs.
+ *
+ * An outer construct is a sequence of variable-sized info, fixed-sized
+ * data, and variable-sized data.
+ */
+
+/*
+ * Terminology
+ *
+ * The ALL UPPER CASE terms recur in the DCE/RPC documentation.
+ * The mixed-case names have been introduced as a reading aid.
+ *
+ * Size The size of an array in elements. Think of this
+ * as the amount to malloc().
+ *
+ * Length The number of elements of an array which are significant
+ * Think of this as the amount to bcopy().
+ *
+ * Known Size/length is known at build time.
+ *
+ * Determined Size/length is determined at run time.
+ *
+ * FIXED The Size and Length are Known.
+ * Think of this as a string constant or a DOS 8.3 file name.
+ * char array[] = "A Constant Size/Length";
+ *
+ * CONFORMANT The Size is Determined. Length is the same as Size.
+ * Think of this as strdup().
+ * char *array = strdup("Something");
+ *
+ * VARYING The Size is Known. The Length is determined.
+ * Think of this as a strcpy() of a variable length string
+ * into a fixed length buffer:
+ * char array[100];
+ * strcpy(array, "very short string");
+ *
+ * VARYING/CONFORMANT
+ * The Size is Determined. The Length is separately Determined.
+ * Think of this like:
+ * char *array = malloc(size);
+ * strcpy(array, "short string");
+ *
+ * STRING Strings can be CONFORMANT, VARYING, or CONFORMANT/VARYING.
+ * A string is fundamentally an array with the last
+ * significant element some sort of NULL.
+ */
+
+#define NDR_F_NONE 0x0000 /* no flags */
+#define NDR_F_PARAMS_MASK 0x00FF
+#define NDR_F_SIZE_IS 0x0001 /* [size_is(X)] required/given */
+#define NDR_F_LENGTH_IS 0x0002 /* not implemented */
+#define NDR_F_SWITCH_IS 0x0004 /* [switch_is(X)] req./given */
+#define NDR_F_IS_STRING 0x0008 /* [string] req./given */
+#define NDR_F_IS_POINTER 0x0010 /* TYPE * ... req./given */
+#define NDR_F_IS_REFERENCE 0x0020 /* TYPE & ... req./given */
+#define NDR_F_DIMENSION_IS 0x0040 /* TYPE [N] req./given */
+
+#define NDR_F_WHENCE_MASK 0x00F0
+#define NDR_F_BACKPTR 0x0010 /* ref cause by pointer */
+#define NDR_F_OUTER 0x0020 /* ref caused by outer */
+#define NDR_F_TOPMOST 0x0040 /* ref caused by topmost */
+
+#define NDR_F_TYPEOP_MASK 0x0F00
+#define NDR_F_ARRAY 0x0100 /* type is array of somethings */
+#define NDR_F_POINTER 0x0200 /* type is pointer to something(s) */
+#define NDR_F_STRING 0x0300 /* type is string of somethings */
+#define NDR_F_UNION 0x0400 /* type is a union */
+#define NDR_F_STRUCT 0x0500 /* type is a structure */
+#define NDR_F_OPERATION 0x0600 /* type is a structure, special */
+#define NDR_F_INTERFACE 0x0700 /* type is a union, special */
+#define NDR_F_CONFORMANT 0x1000 /* struct conforming (var-size tail) */
+#define NDR_F_VARYING 0x2000 /* not implemented */
+
+struct mlrpc_heap;
+struct mlndr_stream;
+struct ndr_reference;
+struct ndr_typeinfo;
+
+struct ndr_typeinfo {
+ unsigned char version; /* sanity check */
+ unsigned char alignment; /* mask */
+ unsigned short type_flags; /* NDR_F_... */
+ int (*ndr_func)(struct ndr_reference *encl_ref);
+ unsigned short pdu_size_fixed_part;
+ unsigned short pdu_size_variable_part;
+ unsigned short c_size_fixed_part;
+ unsigned short c_size_variable_part;
+};
+
+struct ndr_reference {
+ struct ndr_reference *next; /* queue list (outer only) */
+ struct ndr_reference *enclosing; /* e.g. struct for this memb */
+ struct mlndr_stream *stream; /* root of NDR */
+ struct ndr_typeinfo *ti; /* type of data referenced */
+ char *name; /* name of this member */
+ unsigned long pdu_offset; /* referent in stub data */
+ char *datum; /* referent in local memory */
+ char **backptr; /* referer to set */
+ unsigned short outer_flags; /* XXX_is() from top level */
+ unsigned short inner_flags; /* XXX_is() in encapsulated */
+ unsigned short type_flags; /* "requires" */
+ unsigned short packed_alignment;
+ unsigned long size_is; /* conforming constructs */
+ unsigned long strlen_is; /* strings */
+ unsigned long switch_is; /* union arg selector */
+ unsigned long dimension_is; /* fixed-len array size */
+ unsigned long pdu_end_offset; /* offset for limit of PDU */
+};
+
+/*
+ * For all operations, the mlndr_stream, which is the root of NDR processing,
+ * is the primary object. When available, the appropriate ndr_reference
+ * is passed, NULL otherwise. Functions that return 'int' should return
+ * TRUE (!0) or FALSE (0). When functions return FALSE, including
+ * mlndo_malloc() returning NULL, they should set the stream->error to an
+ * appropriate indicator of what went wrong.
+ *
+ * Functions mlndo_get_pdu(), mlndo_put_pdu(), and mlndo_pad_pdu() must
+ * never grow the PDU data. A request for out-of-bounds data is an error.
+ * The swap_bytes flag is 1 if NDR knows that the byte-order in the PDU
+ * is different from the local system. mlndo_pad_pdu() advised that the
+ * affected bytes should be zero filled.
+ */
+struct mlndr_stream_ops {
+ char *(*mlndo_malloc)(struct mlndr_stream *, unsigned,
+ struct ndr_reference *);
+
+ int (*mlndo_free)(struct mlndr_stream *, char *,
+ struct ndr_reference *);
+
+ int (*mlndo_grow_pdu)(struct mlndr_stream *, unsigned long,
+ struct ndr_reference *);
+
+ int (*mlndo_pad_pdu)(struct mlndr_stream *, unsigned long,
+ unsigned long, struct ndr_reference *);
+
+ int (*mlndo_get_pdu)(struct mlndr_stream *, unsigned long,
+ unsigned long, char *, int, struct ndr_reference *);
+
+ int (*mlndo_put_pdu)(struct mlndr_stream *, unsigned long,
+ unsigned long, char *, int, struct ndr_reference *);
+
+ void (*mlndo_tattle)(struct mlndr_stream *, char *,
+ struct ndr_reference *);
+
+ void (*mlndo_tattle_error)(struct mlndr_stream *,
+ struct ndr_reference *);
+
+ int (*mlndo_reset)(struct mlndr_stream *);
+ void (*mlndo_destruct)(struct mlndr_stream *);
+};
+
+#define MLNDS_MALLOC(MLNDS, LEN, REF) \
+ (*(MLNDS)->mlndo->mlndo_malloc)(MLNDS, LEN, REF)
+
+#define MLNDS_GROW_PDU(MLNDS, WANT_END_OFF, REF) \
+ (*(MLNDS)->mlndo->mlndo_grow_pdu)(MLNDS, WANT_END_OFF, REF)
+#define MLNDS_PAD_PDU(MLNDS, PDU_OFFSET, N_BYTES, REF) \
+ (*(MLNDS)->mlndo->mlndo_pad_pdu)(MLNDS, PDU_OFFSET, N_BYTES, REF)
+#define MLNDS_GET_PDU(MLNDS, PDU_OFFSET, N_BYTES, BUF, SWAP, REF) \
+ (*(MLNDS)->mlndo->mlndo_get_pdu)(MLNDS, PDU_OFFSET, N_BYTES, BUF, \
+ SWAP, REF)
+#define MLNDS_PUT_PDU(MLNDS, PDU_OFFSET, N_BYTES, BUF, SWAP, REF) \
+ (*(MLNDS)->mlndo->mlndo_put_pdu)(MLNDS, PDU_OFFSET, N_BYTES, BUF, \
+ SWAP, REF)
+
+#define MLNDS_TATTLE(MLNDS, WHAT, REF) \
+ (*(MLNDS)->mlndo->mlndo_tattle)(MLNDS, WHAT, REF)
+#define MLNDS_TATTLE_ERROR(MLNDS, WHAT, REF) \
+ (*(MLNDS)->mlndo->mlndo_tattle_error)(MLNDS, REF)
+#define MLNDS_RESET(MLNDS) \
+ (*(MLNDS)->mlndo->mlndo_reset)(MLNDS)
+#define MLNDS_DESTRUCT(MLNDS) \
+ (*(MLNDS)->mlndo->mlndo_destruct)(MLNDS)
+
+struct mlndr_stream {
+ unsigned long pdu_size;
+ unsigned long pdu_size_with_rpc_hdrs;
+ unsigned long pdu_max_size;
+ unsigned long pdu_base_offset;
+ unsigned long pdu_scan_offset;
+ unsigned char *pdu_base_addr;
+ unsigned char *pdu_base_addr_with_rpc_hdrs;
+
+ struct mlndr_stream_ops *mlndo;
+
+ unsigned char m_op;
+ unsigned char dir;
+ unsigned char swap; /* native/net endian swap */
+ short error;
+ short error_ref;
+
+ struct ndr_reference *outer_queue_head;
+ struct ndr_reference **outer_queue_tailp;
+ struct ndr_reference *outer_current;
+ struct mlrpc_heap *heap;
+};
+
+
+#define NDR_M_OP_NONE 0x00
+#define NDR_M_OP_MARSHALL 0x01 /* data moving from datum to PDU */
+#define NDR_M_OP_UNMARSHALL 0x02 /* data moving from PDU to datum */
+
+#define NDR_DIR_NONE 0x00
+#define NDR_DIR_IN 0x10 /* data moving from caller to callee */
+#define NDR_DIR_OUT 0x20 /* data moving from callee to caller */
+
+#define NDR_MODE_CALL_SEND (NDR_M_OP_MARSHALL + NDR_DIR_IN)
+#define NDR_MODE_CALL_RECV (NDR_M_OP_UNMARSHALL + NDR_DIR_IN)
+#define NDR_MODE_RETURN_SEND (NDR_M_OP_MARSHALL + NDR_DIR_OUT)
+#define NDR_MODE_RETURN_RECV (NDR_M_OP_UNMARSHALL + NDR_DIR_OUT)
+
+#define NDR_MODE_TO_M_OP(MODE) ((MODE)&0x0F)
+#define NDR_MODE_TO_DIR(MODE) ((MODE)&0xF0)
+#define NDR_M_OP_AND_DIR_TO_MODE(M_OP, DIR) ((M_OP)|(DIR))
+
+#define NDR_MODE_MATCH(MLNDS, MODE) \
+ (NDR_M_OP_AND_DIR_TO_MODE((MLNDS)->m_op, (MLNDS)->dir) == (MODE))
+
+
+#define NDR_ERR_MALLOC_FAILED -1
+#define NDR_ERR_M_OP_INVALID -2
+#define NDR_ERR_UNDERFLOW -3
+#define NDR_ERR_GROW_FAILED -4 /* overflow */
+#define NDR_ERR_PAD_FAILED -5 /* couldn't possibly happen */
+#define NDR_ERR_OUTER_HEADER_BAD -6
+#define NDR_ERR_SWITCH_VALUE_ILLEGAL -7
+#define NDR_ERR_SWITCH_VALUE_INVALID -8
+#define NDR_ERR_SWITCH_VALUE_MISSING -9
+#define NDR_ERR_SIZE_IS_MISMATCH_PDU -10
+#define NDR_ERR_SIZE_IS_MISMATCH_AFTER -11
+#define NDR_ERR_SIZE_IS_UNEXPECTED -12
+#define NDR_ERR_SIZE_IS_DUPLICATED -13
+#define NDR_ERR_OUTER_PARAMS_MISMATCH -14
+#define NDR_ERR_ARRAY_VARLEN_ILLEGAL -15
+#define NDR_ERR_ARRAY_UNION_ILLEGAL -16
+#define NDR_ERR_OUTER_PARAMS_BAD -17
+#define NDR_ERR_OUTER_UNION_ILLEGAL -18
+#define NDR_ERR_TOPMOST_UNION_ILLEGAL -19
+#define NDR_ERR_TOPMOST_VARLEN_ILLEGAL -20
+#define NDR_ERR_INNER_PARAMS_BAD -21
+#define NDR_ERR_UNIMPLEMENTED -22
+#define NDR_ERR_NOT_AN_INTERFACE -23
+#define NDR_ERR_STRLEN -24
+#define NDR_ERR_STRING_SIZING -25
+#define NDR_ERR_BOUNDS_CHECK -26
+
+#define NDR_SET_ERROR(REF, ERROR) \
+ ((REF)->stream->error = (ERROR), \
+ (REF)->stream->error_ref = __LINE__, \
+ MLNDS_TATTLE_ERROR((REF)->stream, 0, REF))
+
+#define NDR_TATTLE(REF, WHAT) \
+ (*(REF)->stream->mlndo->mlndo_tattle)((REF)->stream, WHAT, REF)
+
+#define MEMBER_STR(MEMBER) #MEMBER
+
+#define NDR_DIR_IS_IN (encl_ref->stream->dir == NDR_DIR_IN)
+#define NDR_DIR_IS_OUT (encl_ref->stream->dir == NDR_DIR_OUT)
+
+#define NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ ARGFLAGS, ARGMEM, ARGVAL) { \
+ myref.pdu_offset = encl_ref->pdu_offset + (OFFSET); \
+ myref.name = MEMBER_STR(MEMBER); \
+ myref.datum = (char *)&val->MEMBER; \
+ myref.inner_flags = ARGFLAGS; \
+ myref.ti = &ndt_##TYPE; \
+ myref.ARGMEM = ARGVAL; \
+ if (!mlndr_inner(&myref)) \
+ return (0); \
+ }
+
+#define NDR_MEMBER(TYPE, MEMBER, OFFSET) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_NONE, size_is, 0)
+
+#define NDR_MEMBER_ARR_WITH_SIZE_IS(TYPE, MEMBER, OFFSET, SIZE_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_SIZE_IS, size_is, SIZE_IS)
+
+#define NDR_MEMBER_ARR_WITH_DIMENSION(TYPE, MEMBER, OFFSET, SIZE_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_DIMENSION_IS, dimension_is, SIZE_IS)
+
+#define NDR_MEMBER_PTR_WITH_SIZE_IS(TYPE, MEMBER, OFFSET, SIZE_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_SIZE_IS+NDR_F_IS_POINTER, size_is, SIZE_IS)
+
+#define NDR_MEMBER_PTR(TYPE, MEMBER, OFFSET) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_IS_POINTER, size_is, 0)
+
+#define NDR_MEMBER_WITH_SWITCH_IS(TYPE, MEMBER, OFFSET, SWITCH_IS) \
+ NDR_MEMBER_WITH_ARG(TYPE, MEMBER, OFFSET, \
+ NDR_F_SWITCH_IS, switch_is, SWITCH_IS)
+
+
+#define NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ ARGFLAGS, ARGMEM, ARGVAL) { \
+ myref.pdu_offset = -1; \
+ myref.name = MEMBER_STR(MEMBER); \
+ myref.datum = (char *)&val->MEMBER; \
+ myref.inner_flags = ARGFLAGS; \
+ myref.ti = &ndt_##TYPE; \
+ myref.ARGMEM = ARGVAL; \
+ if (!mlndr_topmost(&myref)) \
+ return (0); \
+ }
+
+#define NDR_TOPMOST_MEMBER(TYPE, MEMBER) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_NONE, size_is, 0)
+
+#define NDR_TOPMOST_MEMBER_ARR_WITH_SIZE_IS(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SIZE_IS, size_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_ARR_WITH_DIMENSION(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_DIMENSION_IS, dimension_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_PTR_WITH_SIZE_IS(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SIZE_IS+NDR_F_IS_POINTER, size_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_PTR(TYPE, MEMBER) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_IS_POINTER, size_is, 0)
+
+#define NDR_TOPMOST_MEMBER_REF(TYPE, MEMBER) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_IS_REFERENCE, size_is, 0)
+
+#define NDR_TOPMOST_MEMBER_REF_WITH_SIZE_IS(TYPE, MEMBER, SIZE_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SIZE_IS+NDR_F_IS_REFERENCE, size_is, SIZE_IS)
+
+#define NDR_TOPMOST_MEMBER_WITH_SWITCH_IS(TYPE, MEMBER, SWITCH_IS) \
+ NDR_TOPMOST_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_SWITCH_IS, switch_is, SWITCH_IS)
+
+/* this is assuming offset+0 */
+#define NDR_PARAMS_MEMBER_WITH_ARG(TYPE, MEMBER, ARGFLAGS, \
+ ARGMEM, ARGVAL) { \
+ myref.pdu_offset = encl_ref->pdu_offset; \
+ myref.name = MEMBER_STR(MEMBER); \
+ myref.datum = (char *)&val->MEMBER; \
+ myref.inner_flags = ARGFLAGS; \
+ myref.ti = &ndt_##TYPE; \
+ myref.ARGMEM = ARGVAL; \
+ if (!mlndr_params(&myref)) \
+ return (0); \
+ }
+
+#define NDR_PARAMS_MEMBER(TYPE, MEMBER) \
+ NDR_PARAMS_MEMBER_WITH_ARG(TYPE, MEMBER, \
+ NDR_F_NONE, size_is, 0)
+
+#define NDR_STRING_DIM 1
+#define NDR_ANYSIZE_DIM 1
+
+int mlndo_process(struct mlndr_stream *, struct ndr_typeinfo *, char *);
+int mlndo_operation(struct mlndr_stream *, struct ndr_typeinfo *,
+ int opnum, char *);
+void mlndo_printf(struct mlndr_stream *, struct ndr_reference *,
+ const char *, ...);
+void mlndo_trace(const char *);
+void mlndo_fmt(struct mlndr_stream *, struct ndr_reference *, char *);
+
+int mlndr_params(struct ndr_reference *);
+int mlndr_topmost(struct ndr_reference *);
+int mlndr_run_outer_queue(struct mlndr_stream *);
+int mlndr_outer(struct ndr_reference *);
+int mlndr_outer_fixed(struct ndr_reference *);
+int mlndr_outer_fixed_array(struct ndr_reference *);
+int mlndr_outer_conformant_array(struct ndr_reference *);
+int mlndr_outer_conformant_construct(struct ndr_reference *);
+int mlndr_size_is(struct ndr_reference *);
+int mlndr_outer_string(struct ndr_reference *);
+int mlndr_outer_peek_sizing(struct ndr_reference *, unsigned,
+ unsigned long *);
+int mlndr_outer_poke_sizing(struct ndr_reference *, unsigned,
+ unsigned long *);
+int mlndr_outer_align(struct ndr_reference *);
+int mlndr_outer_grow(struct ndr_reference *, unsigned);
+int mlndr_inner(struct ndr_reference *);
+int mlndr_inner_pointer(struct ndr_reference *);
+int mlndr_inner_reference(struct ndr_reference *);
+int mlndr_inner_array(struct ndr_reference *);
+void mlnds_bswap(void *src, void *dst, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NDR_H */
diff --git a/usr/src/uts/common/smbsrv/netbios.h b/usr/src/uts/common/smbsrv/netbios.h
new file mode 100644
index 0000000000..3c3d616f4b
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/netbios.h
@@ -0,0 +1,147 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NETBIOS_H
+#define _SMBSRV_NETBIOS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NetBIOS over TCP/IP interface definitions. NetBIOS over TCP/IP is
+ * documented in the following RFC documents:
+ *
+ * RFC 1001: Protocol Standard for a NetBIOS Service on a TCP/UDP
+ * Transport: Concepts and Methods
+ *
+ * RFC 1002: Protocol Standard for a NetBIOS Service on a TCP/UDP
+ * Transport: Detailed Specifications
+ *
+ * These documents reference RCF883.
+ * RFC 883: Domain Names - Implementation and Specification
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * NetBIOS names in NetBIOS packets are valid domain names as defined in
+ * RFC 883. Each label is limited to 63 bytes with an overall length of
+ * 255 bytes as described in RFC 1002 section 4.1. This is known as
+ * second-level encoding. In first-level encoding the label lengths are
+ * represented as dots (.).
+ *
+ * RFC 1001 section 14.1 describes first-level encoding of the NetBIOS
+ * name (hostname) and scope. The ASCII name is padded to 15 bytes using
+ * spaces and a one byte type or suffix is written to the 16th byte.
+ * This is then encoded as a 32 byte string.
+ *
+ * NetBIOS Name: NetBIOS
+ * NetBIOS Scope: PROCOM.COM
+ * First Level: EOGFHEECEJEPFDCACACACACACACACACA.PROCOM.COM
+ * Second Level: <32>EOGFHEECEJEPFDCACACACACACACACACA<6>PROCOM<3>COM<0>
+ */
+#define NETBIOS_NAME_SZ 16
+#define NETBIOS_ENCODED_NAME_SZ 32
+#define NETBIOS_LABEL_MAX 63
+#define NETBIOS_DOMAIN_NAME_MAX 255
+#define NETBIOS_DOMAIN_NAME_BUFLEN (NETBIOS_DOMAIN_NAME_MAX + 1)
+#define NETBIOS_SESSION_REQUEST_DATA_LENGTH \
+ ((NETBIOS_ENCODED_NAME_SZ + 2) * 2)
+
+#define NETBIOS_HDR_SZ 4 /* bytes */
+/*
+ * Session Packet Types (RFC 1002 4.3.1).
+ */
+#define SESSION_MESSAGE 0x00
+#define SESSION_REQUEST 0x81
+#define POSITIVE_SESSION_RESPONSE 0x82
+#define NEGATIVE_SESSION_RESPONSE 0x83
+#define RETARGET_SESSION_RESPONSE 0x84
+#define SESSION_KEEP_ALIVE 0x85
+
+/*
+ * NEGATIVE SESSION RESPONSE packet error code values (RFC 1002 4.3.4).
+ */
+#define SESSION_NOT_LISTENING_ON_CALLED_NAME 0x80
+#define SESSION_NOT_LISTENING_FOR_CALLING_NAME 0x81
+#define SESSION_CALLED_NAME_NOT_PRESENT 0x82
+#define SESSION_INSUFFICIENT_RESOURCES 0x83
+#define SESSION_UNSPECIFIED_ERROR 0x8F
+
+/*
+ * Time conversions
+ */
+#define MILLISECONDS 1
+#define SECONDS (1000 * MILLISECONDS)
+#define MINUTES (60 * SECONDS)
+#define HOURS (60 * MINUTES)
+#define TO_SECONDS(x) ((x) / 1000)
+#define TO_MILLISECONDS(x) ((x) * 1000)
+
+/*
+ * DATAGRAM service definitions
+ */
+#define DATAGRAM_DESTINATION_NAME_NOT_PRESENT 0x82
+#define DATAGRAM_INVALID_SOURCE_NAME_FORMAT 0x83
+#define DATAGRAM_INVALID_DESTINATION_NAME_FORMAT 0x84
+
+#define NAME_SERVICE_TCP_PORT 137
+#define NAME_SERVICE_UDP_PORT 137
+#define DGM_SRVC_UDP_PORT 138
+#define SSN_SRVC_TCP_PORT 139
+#define MAX_DATAGRAM_LENGTH 576
+#define DATAGRAM_HEADER_LENGTH 14
+#define MAX_NAME_LENGTH 256
+#define BCAST_REQ_RETRY_COUNT 2
+#define UCAST_REQ_RETRY_COUNT 2
+#define BCAST_REQ_RETRY_TIMEOUT (500 * MILLISECONDS)
+#define UCAST_REQ_RETRY_TIMEOUT (500 * MILLISECONDS)
+#define CONFLICT_TIMER (1 * SECONDS)
+#define INFINITE_TTL 0
+#define DEFAULT_TTL (600 * SECONDS)
+#define SSN_RETRY_COUNT 4
+#define SSN_CLOSE_TIMEOUT (30 * SECONDS)
+/*
+ * K.L. The keep alive time out use to be default to
+ * 900 seconds. It is not long enough for some applications
+ * i.e. MS Access. Therefore, the timeout is increased to
+ * 5400 seconds.
+ */
+#define SSN_KEEP_ALIVE_TIMEOUT (90 * 60) /* seconds */
+#define FRAGMENT_TIMEOUT (2 * SECONDS)
+
+/* smb_netbios_util.c */
+extern int netbios_first_level_name_decode(char *in, char *name, char *scope);
+extern int netbios_first_level_name_encode(unsigned char *name,
+ unsigned char *scope, unsigned char *out, int max_out);
+extern int netbios_name_isvalid(char *in, char *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NETBIOS_H */
diff --git a/usr/src/uts/common/smbsrv/netrauth.h b/usr/src/uts/common/smbsrv/netrauth.h
new file mode 100644
index 0000000000..075bbba2d2
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/netrauth.h
@@ -0,0 +1,162 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NETRAUTH_H
+#define _SMBSRV_NETRAUTH_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * Interface definitions for the NETR remote authentication and logon
+ * services.
+ */
+
+#include <sys/types.h>
+#include <smbsrv/wintypes.h>
+#include <smbsrv/mlsvc.h>
+
+#ifndef _KERNEL
+#include <syslog.h>
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * See also netlogon.ndl.
+ */
+#define NETR_WKSTA_TRUST_ACCOUNT_TYPE 0x02
+#define NETR_DOMAIN_TRUST_ACCOUNT_TYPE 0x04
+
+/*
+ * Negotiation flags for challenge/response authentication.
+ * The extra flag (0x40000000) was added in SP4.
+ */
+#define NETR_NEGOTIATE_FLAGS 0x000001FF
+#define NETR_NEGOTIATE_SP4_FLAG 0x40000000
+
+#define NETR_SESSION_KEY_SZ 8
+#define NETR_CRED_DATA_SZ 8
+#define NETR_OWF_PASSWORD_SZ 16
+
+
+/*
+ * SAM logon levels: interactive and network.
+ */
+#define NETR_INTERACTIVE_LOGON 0x01
+#define NETR_NETWORK_LOGON 0x02
+
+
+/*
+ * SAM logon validation levels.
+ */
+#define NETR_VALIDATION_LEVEL3 0x03
+
+
+/*
+ * This is a duplicate of the netr_credential
+ * from netlogon.ndl.
+ */
+typedef struct netr_cred {
+ BYTE data[NETR_CRED_DATA_SZ];
+} netr_cred_t;
+
+
+
+#define NETR_FLG_NULL 0x00000001
+#define NETR_FLG_VALID 0x00000001
+#define NETR_FLG_INIT 0x00000002
+
+
+typedef struct netr_info {
+ DWORD flags;
+ char server[MLSVC_DOMAIN_NAME_MAX * 2];
+ char hostname[MLSVC_DOMAIN_NAME_MAX * 2];
+ netr_cred_t client_challenge;
+ netr_cred_t server_challenge;
+ netr_cred_t client_credential;
+ netr_cred_t server_credential;
+ BYTE session_key[NETR_SESSION_KEY_SZ];
+ BYTE password[MLSVC_MACHINE_ACCT_PASSWD_MAX];
+ time_t timestamp;
+} netr_info_t;
+
+/*
+ * netr_client_t flags
+ *
+ * NETR_CFLG_ANON Anonymous connection
+ * NETR_CFLG_LOCAL Local user
+ * NETR_CFLG_DOMAIN Domain user
+ */
+#define NETR_CFLG_ANON 0x01
+#define NETR_CFLG_LOCAL 0x02
+#define NETR_CFLG_DOMAIN 0x04
+
+
+typedef struct netr_client {
+ uint16_t logon_level;
+ char *username;
+ char *domain;
+ char *workstation;
+ uint32_t ipaddr;
+ struct {
+ uint32_t challenge_key_len;
+ uint8_t *challenge_key_val;
+ } challenge_key;
+ struct {
+ uint32_t nt_password_len;
+ uint8_t *nt_password_val;
+ } nt_password;
+ struct {
+ uint32_t lm_password_len;
+ uint8_t *lm_password_val;
+ } lm_password;
+ uint32_t logon_id;
+ int native_os;
+ int native_lm;
+ uint32_t local_ipaddr;
+ uint16_t local_port;
+ uint32_t flags;
+} netr_client_t;
+
+
+/*
+ * NETLOGON private interface.
+ */
+int netr_gen_session_key(netr_info_t *netr_info);
+
+int netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
+ DWORD timestamp, netr_cred_t *out_cred);
+
+
+#define NETR_A2H(c) (isdigit(c)) ? ((c) - '0') : ((c) - 'A' + 10)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NETRAUTH_H */
diff --git a/usr/src/uts/common/smbsrv/nmpipes.h b/usr/src/uts/common/smbsrv/nmpipes.h
new file mode 100644
index 0000000000..f0cd81cc3a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/nmpipes.h
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NMPIPES_H
+#define _SMBSRV_NMPIPES_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines pre-defined and system common named pipes.
+ *
+ * Named pipes are a simple IPC mechanism supported by Windows 9x, NT
+ * and 2000. The Windows named pipe implementation supports reliable
+ * one-way and two-way transport independent network messaging. The
+ * names follow the universal naming convention (UNC) defined for the
+ * Windows redirector: \\[server]\[share]\[path]name. There is a good
+ * overview of named pipes in Network Programming for Microsoft Windows
+ * Chapter 4. The redirector is described in Chapter 2. UNC names are
+ * case-insensitive.
+ *
+ * Network Programming for Microsoft Windows
+ * Anthony Jones and Jim Ohlund
+ * Microsoft Press, ISBN 0-7356-0560-2
+ *
+ * Microsoft RPC, which is derived from DCE RPC, uses SMB named pipes
+ * as its transport mechanism. In addition to the pipe used to open
+ * each connection, a named pipe also appears in the bind response as
+ * a secondary address port. Sometimes the secondary address port is
+ * the same and sometimes it is different. The following associations
+ * have been observed.
+ *
+ * LSARPC lsass
+ * NETLOGON lsass
+ * SAMR lsass
+ * SPOOLSS spoolss
+ * SRVSVC ntsvcs
+ * SVCCTL ntsvcs
+ * WINREG winreg
+ * WKSSVC ntsvcs
+ * EVENTLOG ntsvcs
+ * LLSRPC llsrpc
+ *
+ * Further information on RPC named pipes is available in the following
+ * references.
+ *
+ * RPC for NT
+ * Guy R. Eddon
+ * R&D PUblications, ISBN 0-87930-450-2
+ *
+ * Network Programming in Windows NT
+ * Alok K. Sinha
+ * Addison-Wesley, ISBN 0-201-59056-5
+ *
+ * DCE/RPC over SMB Samba and Windows NT Domain Internals
+ * Luke Kenneth Casson Leighton
+ * Macmillan Technical Publishing, ISBN 1-57870-150-3
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Well-known or pre-defined Windows named pipes. Typically used
+ * with SmbNtCreateAndX and/or SmbTransactNmPipe. When passed to
+ * SmbNtCreateAndX the \PIPE prefix is often missing. These names
+ * are presented as observed on the wire but should be treated in
+ * a case-insensitive manner.
+ */
+#define PIPE_LANMAN "\\PIPE\\LANMAN"
+#define PIPE_NETLOGON "\\PIPE\\NETLOGON"
+#define PIPE_LSARPC "\\PIPE\\lsarpc"
+#define PIPE_SAMR "\\PIPE\\samr"
+#define PIPE_SPOOLSS "\\PIPE\\spoolss"
+#define PIPE_SRVSVC "\\PIPE\\srvsvc"
+#define PIPE_SVCCTL "\\PIPE\\svcctl"
+#define PIPE_WINREG "\\PIPE\\winreg"
+#define PIPE_WKSSVC "\\PIPE\\wkssvc"
+#define PIPE_EVENTLOG "\\PIPE\\EVENTLOG"
+#define PIPE_LSASS "\\PIPE\\lsass"
+#define PIPE_NTSVCS "\\PIPE\\ntsvcs"
+#define PIPE_ATSVC "\\PIPE\\atsvc"
+#define PIPE_BROWSESS "\\PIPE\\browsess"
+#define PIPE_WINSSVC "\\PIPE\\winssvc"
+#define PIPE_WINSMGR "\\PIPE\\winsmgr"
+#define PIPE_LLSRPC "\\PIPE\\llsrpc"
+#define PIPE_REPL "\\PIPE\\repl"
+
+/*
+ * Named pipe function codes (NTDDK cifs.h).
+ */
+#define TRANS_SET_NMPIPE_STATE 0x01
+#define TRANS_RAW_READ_NMPIPE 0x11
+#define TRANS_QUERY_NMPIPE_STATE 0x21
+#define TRANS_QUERY_NMPIPE_INFO 0x22
+#define TRANS_PEEK_NMPIPE 0x23
+#define TRANS_TRANSACT_NMPIPE 0x26
+#define TRANS_RAW_WRITE_NMPIPE 0x31
+#define TRANS_READ_NMPIPE 0x36
+#define TRANS_WRITE_NMPIPE 0x37
+#define TRANS_WAIT_NMPIPE 0x53
+#define TRANS_CALL_NMPIPE 0x54
+
+/*
+ * SMB pipe handle state bits used by Query/SetNamedPipeHandleState.
+ * These numbers are the bit locations of the fields in the handle state.
+ */
+#define PIPE_COMPLETION_MODE_BITS 15
+#define PIPE_PIPE_END_BITS 14
+#define PIPE_PIPE_TYPE_BITS 10
+#define PIPE_READ_MODE_BITS 8
+#define PIPE_MAXIMUM_INSTANCES_BITS 0
+
+/*
+ * DosPeekNmPipe pipe states.
+ */
+#define PIPE_STATE_DISCONNECTED 0x0001
+#define PIPE_STATE_LISTENING 0x0002
+#define PIPE_STATE_CONNECTED 0x0003
+#define PIPE_STATE_CLOSING 0x0004
+
+/*
+ * DosCreateNPipe and DosQueryNPHState state.
+ */
+#define SMB_PIPE_READMODE_BYTE 0x0000
+#define SMB_PIPE_READMODE_MESSAGE 0x0100
+#define SMB_PIPE_TYPE_BYTE 0x0000
+#define SMB_PIPE_TYPE_MESSAGE 0x0400
+#define SMB_PIPE_END_CLIENT 0x0000
+#define SMB_PIPE_END_SERVER 0x4000
+#define SMB_PIPE_WAIT 0x0000
+#define SMB_PIPE_NOWAIT 0x8000
+#define SMB_PIPE_UNLIMITED_INSTANCES 0x00FF
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NMPIPES_H */
diff --git a/usr/src/uts/common/smbsrv/ntaccess.h b/usr/src/uts/common/smbsrv/ntaccess.h
new file mode 100644
index 0000000000..114150baa9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntaccess.h
@@ -0,0 +1,237 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NTACCESS_H
+#define _SMBSRV_NTACCESS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the NT compatible access control masks and values.
+ * An access mask as a 32-bit value arranged as shown below.
+ *
+ * 31-28 Generic bits, interpreted per object type
+ * 27-26 Reserved, must-be-zero
+ * 25 Maximum allowed
+ * 24 System Security rights (SACL is SD)
+ * 23-16 Standard access rights, generic to all object types
+ * 15-0 Specific access rights, object specific
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------+---------------+-------------------------------+
+ * |G|G|G|G|Res'd|A| StandardRights| SpecificRights |
+ * |R|W|E|A| |S| | |
+ * +-+-------------+---------------+-------------------------------+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Specific rights for files, pipes and directories.
+ */
+#define FILE_READ_DATA (0x0001) /* file & pipe */
+#define FILE_LIST_DIRECTORY (0x0001) /* directory */
+#define FILE_WRITE_DATA (0x0002) /* file & pipe */
+#define FILE_ADD_FILE (0x0002) /* directory */
+#define FILE_APPEND_DATA (0x0004) /* file */
+#define FILE_ADD_SUBDIRECTORY (0x0004) /* directory */
+#define FILE_CREATE_PIPE_INSTANCE (0x0004) /* named pipe */
+#define FILE_READ_EA (0x0008) /* file & directory */
+#define FILE_READ_PROPERTIES (0x0008) /* pipe */
+#define FILE_WRITE_EA (0x0010) /* file & directory */
+#define FILE_WRITE_PROPERTIES (0x0010) /* pipe */
+#define FILE_EXECUTE (0x0020) /* file */
+#define FILE_TRAVERSE (0x0020) /* directory */
+#define FILE_DELETE_CHILD (0x0040) /* directory */
+#define FILE_READ_ATTRIBUTES (0x0080) /* all */
+#define FILE_WRITE_ATTRIBUTES (0x0100) /* all */
+#define FILE_SPECIFIC_ALL (0x000001FFL)
+#define SPECIFIC_RIGHTS_ALL (0x0000FFFFL)
+
+
+/*
+ * Standard rights:
+ *
+ * DELETE The right to delete the object.
+ *
+ * READ_CONTROL The right to read the information in the object's security
+ * descriptor, not including the information in the SACL.
+ *
+ * WRITE_DAC The right to modify the DACL in the object's security
+ * descriptor.
+ *
+ * WRITE_OWNER The right to change the owner in the object's security
+ * descriptor.
+ *
+ * SYNCHRONIZE The right to use the object for synchronization. This enables
+ * a thread to wait until the object is in the signaled state.
+ */
+#define DELETE (0x00010000L)
+#define READ_CONTROL (0x00020000L)
+#define WRITE_DAC (0x00040000L)
+#define WRITE_OWNER (0x00080000L) /* take ownership */
+#define SYNCHRONIZE (0x00100000L)
+#define STANDARD_RIGHTS_REQUIRED (0x000F0000L)
+#define STANDARD_RIGHTS_ALL (0x001F0000L)
+
+
+#define STANDARD_RIGHTS_READ (READ_CONTROL)
+#define STANDARD_RIGHTS_WRITE (READ_CONTROL)
+#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL)
+
+#define FILE_METADATA_ALL (FILE_READ_EA |\
+ FILE_READ_ATTRIBUTES |\
+ READ_CONTROL |\
+ FILE_WRITE_EA |\
+ FILE_WRITE_ATTRIBUTES |\
+ WRITE_DAC |\
+ WRITE_OWNER |\
+ SYNCHRONIZE)
+
+#define FILE_DATA_ALL (FILE_READ_DATA |\
+ FILE_WRITE_DATA |\
+ FILE_APPEND_DATA |\
+ FILE_EXECUTE |\
+ DELETE)
+
+#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
+
+
+/*
+ * Miscellaneous bits: SACL access and maximum allowed access.
+ */
+#define ACCESS_SYSTEM_SECURITY (0x01000000L)
+#define MAXIMUM_ALLOWED (0x02000000L)
+
+
+/*
+ * Generic rights. These are shorthands that are interpreted as
+ * appropriate for the type of secured object being accessed.
+ */
+#define GENERIC_ALL (0x10000000UL)
+#define GENERIC_EXECUTE (0x20000000UL)
+#define GENERIC_WRITE (0x40000000UL)
+#define GENERIC_READ (0x80000000UL)
+
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | \
+ FILE_READ_DATA | \
+ FILE_READ_ATTRIBUTES | \
+ FILE_READ_EA | \
+ SYNCHRONIZE)
+
+#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | \
+ FILE_WRITE_DATA | \
+ FILE_WRITE_ATTRIBUTES | \
+ FILE_WRITE_EA | \
+ FILE_APPEND_DATA | \
+ SYNCHRONIZE)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | \
+ FILE_READ_ATTRIBUTES | \
+ FILE_EXECUTE | \
+ SYNCHRONIZE)
+
+#define FILE_GENERIC_ALL (FILE_GENERIC_READ | \
+ FILE_GENERIC_WRITE | \
+ FILE_GENERIC_EXECUTE)
+
+
+/*
+ * LSA policy desired access masks.
+ */
+#define POLICY_VIEW_LOCAL_INFORMATION 0x00000001L
+#define POLICY_VIEW_AUDIT_INFORMATION 0x00000002L
+#define POLICY_GET_PRIVATE_INFORMATION 0x00000004L
+#define POLICY_TRUST_ADMIN 0x00000008L
+#define POLICY_CREATE_ACCOUNT 0x00000010L
+#define POLICY_CREATE_SECRET 0x00000020L
+#define POLICY_CREATE_PRIVILEGE 0x00000040L
+#define POLICY_SET_DEFAULT_QUOTA_LIMITS 0x00000080L
+#define POLICY_SET_AUDIT_REQUIREMENTS 0x00000100L
+#define POLICY_AUDIT_LOG_ADMIN 0x00000200L
+#define POLICY_SERVER_ADMIN 0x00000400L
+#define POLICY_LOOKUP_NAMES 0x00000800L
+
+
+/*
+ * SAM specific rights desired access masks. These definitions are listed
+ * mostly as a convenience; they don't seem to be documented. Setting the
+ * desired access mask to GENERIC_EXECUTE and STANDARD_RIGHTS_EXECUTE
+ * seems to work when just looking up information.
+ */
+#define SAM_LOOKUP_INFORMATION (GENERIC_EXECUTE \
+ | STANDARD_RIGHTS_EXECUTE)
+
+#define SAM_ACCESS_USER_READ 0x0000031BL
+#define SAM_ACCESS_USER_UPDATE 0x0000031FL
+#define SAM_ACCESS_USER_SETPWD 0x0000037FL
+#define SAM_CONNECT_CREATE_ACCOUNT 0x00000020L
+#define SAM_ENUM_LOCAL_DOMAIN 0x00000030L
+#define SAM_DOMAIN_CREATE_ACCOUNT 0x00000211L
+
+
+/*
+ * File attributes
+ *
+ * Note: 0x00000008 is reserved for use for the old DOS VOLID (volume ID)
+ * and is therefore not considered valid in NT.
+ *
+ * Note: 0x00000010 is reserved for use for the old DOS SUBDIRECTORY flag
+ * and is therefore not considered valid in NT. This flag has
+ * been disassociated with file attributes since the other flags are
+ * protected with READ_ and WRITE_ATTRIBUTES access to the file.
+ *
+ * Note: Note also that the order of these flags is set to allow both the
+ * FAT and the Pinball File Systems to directly set the attributes
+ * flags in attributes words without having to pick each flag out
+ * individually. The order of these flags should not be changed!
+ *
+ * The file attributes are defined in smbsrv/smb_vops.h
+ */
+
+/* Filesystem Attributes */
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+#define FILE_PERSISTENT_ACLS 0x00000008
+#define FILE_FILE_COMPRESSION 0x00000010
+#define FILE_VOLUME_QUOTAS 0x00000020
+#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
+#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
+#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
+#define FILE_SUPPORTS_ENCRYPTION 0x00020000
+#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NTACCESS_H */
diff --git a/usr/src/uts/common/smbsrv/nterror.h b/usr/src/uts/common/smbsrv/nterror.h
new file mode 100644
index 0000000000..4695d4f15d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/nterror.h
@@ -0,0 +1,941 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _SMBSRV_NTERROR_H
+#define _SMBSRV_NTERROR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the list of Win32 error codes. If you need an
+ * error code that is defined in the Win32 Error Codes document but
+ * is not listed here, please add it to the file. There is a list
+ * of Win32 error codes on:
+ *
+ * http://msdn.microsoft.com/library/psdk/psdkref/errlist_9usz.htm
+ *
+ * Be careful not to confuse status codes with error codes. The status
+ * codes are listed in ntstatus.h. Some mappings between NT status
+ * codes and Win32 error codes is provided in the Microsoft knowledge
+ * base article Q113996.
+ *
+ * Win32 error codes are 32-bit values with the following format
+ * (winerror.h):
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-+-----------------------+-------------------------------+
+ * |Sev|C|R| Facility | Code |
+ * +---+-+-+-----------------------+-------------------------------+
+ *
+ * Sev severity code
+ * 00 - Success
+ * 01 - Informational
+ * 10 - Warning
+ * 11 - Error
+ *
+ * C customer/client flag (set to 1 for user defined codes).
+ * R reserved (set to zero)
+ * Facility facility code
+ * Code facility's status code
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Facility codes
+ */
+#define FACILITY_NULL 0
+#define FACILITY_RPC 1
+#define FACILITY_DISPATCH 2
+#define FACILITY_STORAGE 3
+#define FACILITY_ITF 4
+/* 5 */
+/* 6 */
+#define FACILITY_WIN32 7
+#define FACILITY_WINDOWS 8
+#define FACILITY_SSPI 9
+#define FACILITY_CONTROL 10
+#define FACILITY_CERT 11
+#define FACILITY_INTERNET 12
+#define FACILITY_MEDIASERVER 13
+#define FACILITY_MSMQ 14
+#define FACILITY_SETUPAPI 15
+
+
+/*
+ * Complete list of Win32 error codes. For error description
+ * you can look at MS-KB articles 155011 and 155012
+ */
+
+#define ERROR_SUCCESS 0
+#define NO_ERROR 0
+#define ERROR_INVALID_FUNCTION 1
+#define ERROR_FILE_NOT_FOUND 2
+#define ERROR_PATH_NOT_FOUND 3
+#define ERROR_TOO_MANY_OPEN_FILES 4
+#define ERROR_ACCESS_DENIED 5
+#define ERROR_INVALID_HANDLE 6
+#define ERROR_ARENA_TRASHED 7
+#define ERROR_NOT_ENOUGH_MEMORY 8
+#define ERROR_INVALID_BLOCK 9
+#define ERROR_BAD_ENVIRONMENT 10
+#define ERROR_BAD_FORMAT 11
+#define ERROR_INVALID_ACCESS 12
+#define ERROR_INVALID_DATA 13
+#define ERROR_OUTOFMEMORY 14
+#define ERROR_INVALID_DRIVE 15
+#define ERROR_CURRENT_DIRECTORY 16
+#define ERROR_NOT_SAME_DEVICE 17
+#define ERROR_NO_MORE_FILES 18
+#define ERROR_WRITE_PROTECT 19
+#define ERROR_BAD_UNIT 20
+#define ERROR_NOT_READY 21
+#define ERROR_BAD_COMMAND 22
+#define ERROR_CRC 23
+#define ERROR_BAD_LENGTH 24
+#define ERROR_SEEK 25
+#define ERROR_NOT_DOS_DISK 26
+#define ERROR_SECTOR_NOT_FOUND 27
+#define ERROR_OUT_OF_PAPER 28
+#define ERROR_WRITE_FAULT 29
+#define ERROR_READ_FAULT 30
+#define ERROR_GEN_FAILURE 31
+#define ERROR_SHARING_VIOLATION 32
+#define ERROR_LOCK_VIOLATION 33
+#define ERROR_WRONG_DISK 34
+#define ERROR_SHARING_BUFFER_EXCEEDED 36
+#define ERROR_HANDLE_EOF 38
+#define ERROR_HANDLE_DISK_FULL 39
+#define ERROR_NOT_SUPPORTED 50
+#define ERROR_REM_NOT_LIST 51
+#define ERROR_DUP_NAME 52
+#define ERROR_BAD_NETPATH 53
+#define ERROR_NETWORK_BUSY 54
+#define ERROR_DEV_NOT_EXIST 55
+#define ERROR_TOO_MANY_CMDS 56
+#define ERROR_ADAP_HDW_ERR 57
+#define ERROR_BAD_NET_RESP 58
+#define ERROR_UNEXP_NET_ERR 59
+#define ERROR_BAD_REM_ADAP 60
+#define ERROR_PRINTQ_FULL 61
+#define ERROR_NO_SPOOL_SPACE 62
+#define ERROR_PRINT_CANCELLED 63
+#define ERROR_NETNAME_DELETED 64
+#define ERROR_NETWORK_ACCESS_DENIED 65
+#define ERROR_BAD_DEV_TYPE 66
+#define ERROR_BAD_NET_NAME 67
+#define ERROR_TOO_MANY_NAMES 68
+#define ERROR_TOO_MANY_SESS 69
+#define ERROR_SHARING_PAUSED 70
+#define ERROR_REQ_NOT_ACCEP 71
+#define ERROR_REDIR_PAUSED 72
+#define ERROR_FILE_EXISTS 80
+#define ERROR_CANNOT_MAKE 82
+#define ERROR_FAIL_I24 83
+#define ERROR_OUT_OF_STRUCTURES 84
+#define ERROR_ALREADY_ASSIGNED 85
+#define ERROR_INVALID_PASSWORD 86
+#define ERROR_INVALID_PARAMETER 87
+#define ERROR_NET_WRITE_FAULT 88
+#define ERROR_NO_PROC_SLOTS 89
+#define ERROR_TOO_MANY_SEMAPHORES 100
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101
+#define ERROR_SEM_IS_SET 102
+#define ERROR_TOO_MANY_SEM_REQUESTS 103
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104
+#define ERROR_SEM_OWNER_DIED 105
+#define ERROR_SEM_USER_LIMIT 106
+#define ERROR_DISK_CHANGE 107
+#define ERROR_DRIVE_LOCKED 108
+#define ERROR_BROKEN_PIPE 109
+#define ERROR_OPEN_FAILED 110
+#define ERROR_BUFFER_OVERFLOW 111
+#define ERROR_DISK_FULL 112
+#define ERROR_NO_MORE_SEARCH_HANDLES 113
+#define ERROR_INVALID_TARGET_HANDLE 114
+#define ERROR_INVALID_CATEGORY 117
+#define ERROR_INVALID_VERIFY_SWITCH 118
+#define ERROR_BAD_DRIVER_LEVEL 119
+#define ERROR_CALL_NOT_IMPLEMENTED 120
+#define ERROR_SEM_TIMEOUT 121
+#define ERROR_INSUFFICIENT_BUFFER 122
+#define ERROR_INVALID_NAME 123
+#define ERROR_INVALID_LEVEL 124
+#define ERROR_NO_VOLUME_LABEL 125
+#define ERROR_MOD_NOT_FOUND 126
+#define ERROR_PROC_NOT_FOUND 127
+#define ERROR_WAIT_NO_CHILDREN 128
+#define ERROR_CHILD_NOT_COMPLETE 129
+#define ERROR_DIRECT_ACCESS_HANDLE 130
+#define ERROR_NEGATIVE_SEEK 131
+#define ERROR_SEEK_ON_DEVICE 132
+#define ERROR_IS_JOIN_TARGET 133
+#define ERROR_IS_JOINED 134
+#define ERROR_IS_SUBSTED 135
+#define ERROR_NOT_JOINED 136
+#define ERROR_NOT_SUBSTED 137
+#define ERROR_JOIN_TO_JOIN 138
+#define ERROR_SUBST_TO_SUBST 139
+#define ERROR_JOIN_TO_SUBST 140
+#define ERROR_SUBST_TO_JOIN 141
+#define ERROR_BUSY_DRIVE 142
+#define ERROR_SAME_DRIVE 143
+#define ERROR_DIR_NOT_ROOT 144
+#define ERROR_DIR_NOT_EMPTY 145
+#define ERROR_IS_SUBST_PATH 146
+#define ERROR_IS_JOIN_PATH 147
+#define ERROR_PATH_BUSY 148
+#define ERROR_IS_SUBST_TARGET 149
+#define ERROR_SYSTEM_TRACE 150
+#define ERROR_INVALID_EVENT_COUNT 151
+#define ERROR_TOO_MANY_MUXWAITERS 152
+#define ERROR_INVALID_LIST_FORMAT 153
+#define ERROR_LABEL_TOO_LONG 154
+#define ERROR_TOO_MANY_TCBS 155
+#define ERROR_SIGNAL_REFUSED 156
+#define ERROR_DISCARDED 157
+#define ERROR_NOT_LOCKED 158
+#define ERROR_BAD_THREADID_ADDR 159
+#define ERROR_BAD_ARGUMENTS 160
+#define ERROR_BAD_PATHNAME 161
+#define ERROR_SIGNAL_PENDING 162
+#define ERROR_MAX_THRDS_REACHED 164
+#define ERROR_LOCK_FAILED 167
+#define ERROR_BUSY 170
+#define ERROR_CANCEL_VIOLATION 173
+#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174
+#define ERROR_INVALID_SEGMENT_NUMBER 180
+#define ERROR_INVALID_ORDINAL 182
+#define ERROR_ALREADY_EXISTS 183
+#define ERROR_INVALID_FLAG_NUMBER 186
+#define ERROR_SEM_NOT_FOUND 187
+#define ERROR_INVALID_STARTING_CODESEG 188
+#define ERROR_INVALID_STACKSEG 189
+#define ERROR_INVALID_MODULETYPE 190
+#define ERROR_INVALID_EXE_SIGNATURE 191
+#define ERROR_EXE_MARKED_INVALID 192
+#define ERROR_BAD_EXE_FORMAT 193
+#define ERROR_ITERATED_DATA_EXCEEDS_64k 194
+#define ERROR_INVALID_MINALLOCSIZE 195
+#define ERROR_DYNLINK_FROM_INVALID_RING 196
+#define ERROR_IOPL_NOT_ENABLED 197
+#define ERROR_INVALID_SEGDPL 198
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202
+#define ERROR_ENVVAR_NOT_FOUND 203
+#define ERROR_NO_SIGNAL_SENT 205
+#define ERROR_FILENAME_EXCED_RANGE 206
+#define ERROR_RING2_STACK_IN_USE 207
+#define ERROR_META_EXPANSION_TOO_LONG 208
+#define ERROR_INVALID_SIGNAL_NUMBER 209
+#define ERROR_THREAD_1_INACTIVE 210
+#define ERROR_LOCKED 212
+#define ERROR_TOO_MANY_MODULES 214
+#define ERROR_NESTING_NOT_ALLOWED 215
+#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216
+#define ERROR_BAD_PIPE 230
+#define ERROR_PIPE_BUSY 231
+#define ERROR_NO_DATA 232
+#define ERROR_PIPE_NOT_CONNECTED 233
+#define ERROR_MORE_DATA 234
+#define ERROR_VC_DISCONNECTED 240
+#define ERROR_INVALID_EA_NAME 254
+#define ERROR_EA_LIST_INCONSISTENT 255
+#define ERROR_NO_MORE_ITEMS 259
+#define ERROR_CANNOT_COPY 266
+#define ERROR_DIRECTORY 267
+#define ERROR_EAS_DIDNT_FIT 275
+#define ERROR_EA_FILE_CORRUPT 276
+#define ERROR_EA_TABLE_FULL 277
+#define ERROR_INVALID_EA_HANDLE 278
+#define ERROR_EAS_NOT_SUPPORTED 282
+#define ERROR_NOT_OWNER 288
+#define ERROR_TOO_MANY_POSTS 298
+#define ERROR_PARTIAL_COPY 299
+#define ERROR_OPLOCK_NOT_GRANTED 300
+#define ERROR_INVALID_OPLOCK_PROTOCOL 301
+#define ERROR_MR_MID_NOT_FOUND 317
+#define ERROR_INVALID_ADDRESS 487
+#define ERROR_ARITHMETIC_OVERFLOW 534
+#define ERROR_PIPE_CONNECTED 535
+#define ERROR_PIPE_LISTENING 536
+#define ERROR_EA_ACCESS_DENIED 994
+#define ERROR_OPERATION_ABORTED 995
+#define ERROR_IO_INCOMPLETE 996
+#define ERROR_IO_PENDING 997
+#define ERROR_NOACCESS 998
+#define ERROR_SWAPERROR 999
+#define ERROR_STACK_OVERFLOW 1001
+#define ERROR_INVALID_MESSAGE 1002
+#define ERROR_CAN_NOT_COMPLETE 1003
+#define ERROR_INVALID_FLAGS 1004
+#define ERROR_UNRECOGNIZED_VOLUME 1005
+#define ERROR_FILE_INVALID 1006
+#define ERROR_FULLSCREEN_MODE 1007
+#define ERROR_NO_TOKEN 1008
+#define ERROR_BADDB 1009
+#define ERROR_BADKEY 1010
+#define ERROR_CANTOPEN 1011
+#define ERROR_CANTREAD 1012
+#define ERROR_CANTWRITE 1013
+#define ERROR_REGISTRY_RECOVERED 1014
+#define ERROR_REGISTRY_CORRUPT 1015
+#define ERROR_REGISTRY_IO_FAILED 1016
+#define ERROR_NOT_REGISTRY_FILE 1017
+#define ERROR_KEY_DELETED 1018
+#define ERROR_NO_LOG_SPACE 1019
+#define ERROR_KEY_HAS_CHILDREN 1020
+#define ERROR_CHILD_MUST_BE_VOLATILE 1021
+#define ERROR_NOTIFY_ENUM_DIR 1022
+#define ERROR_DEPENDENT_SERVICES_RUNNING 1051
+#define ERROR_INVALID_SERVICE_CONTROL 1052
+#define ERROR_SERVICE_REQUEST_TIMEOUT 1053
+#define ERROR_SERVICE_NO_THREAD 1054
+#define ERROR_SERVICE_DATABASE_LOCKED 1055
+#define ERROR_SERVICE_ALREADY_RUNNING 1056
+#define ERROR_INVALID_SERVICE_ACCOUNT 1057
+#define ERROR_SERVICE_DISABLED 1058
+#define ERROR_CIRCULAR_DEPENDENCY 1059
+#define ERROR_SERVICE_DOES_NOT_EXIST 1060
+#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061
+#define ERROR_SERVICE_NOT_ACTIVE 1062
+#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063
+#define ERROR_EXCEPTION_IN_SERVICE 1064
+#define ERROR_DATABASE_DOES_NOT_EXIST 1065
+#define ERROR_SERVICE_SPECIFIC_ERROR 1066
+#define ERROR_PROCESS_ABORTED 1067
+#define ERROR_SERVICE_DEPENDENCY_FAIL 1068
+#define ERROR_SERVICE_LOGON_FAILED 1069
+#define ERROR_SERVICE_START_HANG 1070
+#define ERROR_INVALID_SERVICE_LOCK 1071
+#define ERROR_SERVICE_MARKED_FOR_DELETE 1072
+#define ERROR_SERVICE_EXISTS 1073
+#define ERROR_ALREADY_RUNNING_LKG 1074
+#define ERROR_SERVICE_DEPENDENCY_DELETED 1075
+#define ERROR_BOOT_ALREADY_ACCEPTED 1076
+#define ERROR_SERVICE_NEVER_STARTED 1077
+#define ERROR_DUPLICATE_SERVICE_NAME 1078
+#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079
+#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080
+#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081
+#define ERROR_NO_RECOVERY_PROGRAM 1082
+#define ERROR_END_OF_MEDIA 1100
+#define ERROR_FILEMARK_DETECTED 1101
+#define ERROR_BEGINNING_OF_MEDIA 1102
+#define ERROR_SETMARK_DETECTED 1103
+#define ERROR_NO_DATA_DETECTED 1104
+#define ERROR_PARTITION_FAILURE 1105
+#define ERROR_INVALID_BLOCK_LENGTH 1106
+#define ERROR_DEVICE_NOT_PARTITIONED 1107
+#define ERROR_UNABLE_TO_LOCK_MEDIA 1108
+#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109
+#define ERROR_MEDIA_CHANGED 1110
+#define ERROR_BUS_RESET 1111
+#define ERROR_NO_MEDIA_IN_DRIVE 1112
+#define ERROR_NO_UNICODE_TRANSLATION 1113
+#define ERROR_DLL_INIT_FAILED 1114
+#define ERROR_SHUTDOWN_IN_PROGRESS 1115
+#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116
+#define ERROR_IO_DEVICE 1117
+#define ERROR_SERIAL_NO_DEVICE 1118
+#define ERROR_IRQ_BUSY 1119
+#define ERROR_MORE_WRITES 1120
+#define ERROR_COUNTER_TIMEOUT 1121
+#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122
+#define ERROR_FLOPPY_WRONG_CYLINDER 1123
+#define ERROR_FLOPPY_UNKNOWN_ERROR 1124
+#define ERROR_FLOPPY_BAD_REGISTERS 1125
+#define ERROR_DISK_RECALIBRATE_FAILED 1126
+#define ERROR_DISK_OPERATION_FAILED 1127
+#define ERROR_DISK_RESET_FAILED 1128
+#define ERROR_EOM_OVERFLOW 1129
+#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130
+#define ERROR_POSSIBLE_DEADLOCK 1131
+#define ERROR_MAPPED_ALIGNMENT 1132
+#define ERROR_SET_POWER_STATE_VETOED 1140
+#define ERROR_SET_POWER_STATE_FAILED 1141
+#define ERROR_TOO_MANY_LINKS 1142
+#define ERROR_OLD_WIN_VERSION 1150
+#define ERROR_APP_WRONG_OS 1151
+#define ERROR_SINGLE_INSTANCE_APP 1152
+#define ERROR_RMODE_APP 1153
+#define ERROR_INVALID_DLL 1154
+#define ERROR_NO_ASSOCIATION 1155
+#define ERROR_DDE_FAIL 1156
+#define ERROR_DLL_NOT_FOUND 1157
+#define ERROR_NO_MORE_USER_HANDLES 1158
+#define ERROR_MESSAGE_SYNC_ONLY 1159
+#define ERROR_SOURCE_ELEMENT_EMPTY 1160
+#define ERROR_DESTINATION_ELEMENT_FULL 1161
+#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162
+#define ERROR_MAGAZINE_NOT_PRESENT 1163
+#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164
+#define ERROR_DEVICE_REQUIRES_CLEANING 1165
+#define ERROR_DEVICE_DOOR_OPEN 1166
+#define ERROR_DEVICE_NOT_CONNECTED 1167
+#define ERROR_NOT_FOUND 1168
+#define ERROR_NO_MATCH 1169
+#define ERROR_SET_NOT_FOUND 1170
+#define ERROR_POINT_NOT_FOUND 1171
+#define ERROR_NO_TRACKING_SERVICE 1172
+#define ERROR_NO_VOLUME_ID 1173
+#define ERROR_CONNECTED_OTHER_PASSWORD 2108
+#define ERROR_BAD_USERNAME 2202
+#define ERROR_NOT_CONNECTED 2250
+#define ERROR_OPEN_FILES 2401
+#define ERROR_ACTIVE_CONNECTIONS 2402
+#define ERROR_DEVICE_IN_USE 2404
+#define ERROR_BAD_DEVICE 1200
+#define ERROR_CONNECTION_UNAVAIL 1201
+#define ERROR_DEVICE_ALREADY_REMEMBERED 1202
+#define ERROR_NO_NET_OR_BAD_PATH 1203
+#define ERROR_BAD_PROVIDER 1204
+#define ERROR_CANNOT_OPEN_PROFILE 1205
+#define ERROR_BAD_PROFILE 1206
+#define ERROR_NOT_CONTAINER 1207
+#define ERROR_EXTENDED_ERROR 1208
+#define ERROR_INVALID_GROUPNAME 1209
+#define ERROR_INVALID_COMPUTERNAME 1210
+#define ERROR_INVALID_EVENTNAME 1211
+#define ERROR_INVALID_DOMAINNAME 1212
+#define ERROR_INVALID_SERVICENAME 1213
+#define ERROR_INVALID_NETNAME 1214
+#define ERROR_INVALID_SHARENAME 1215
+#define ERROR_INVALID_PASSWORDNAME 1216
+#define ERROR_INVALID_MESSAGENAME 1217
+#define ERROR_INVALID_MESSAGEDEST 1218
+#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219
+#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220
+#define ERROR_DUP_DOMAINNAME 1221
+#define ERROR_NO_NETWORK 1222
+#define ERROR_CANCELLED 1223
+#define ERROR_USER_MAPPED_FILE 1224
+#define ERROR_CONNECTION_REFUSED 1225
+#define ERROR_GRACEFUL_DISCONNECT 1226
+#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227
+#define ERROR_ADDRESS_NOT_ASSOCIATED 1228
+#define ERROR_CONNECTION_INVALID 1229
+#define ERROR_CONNECTION_ACTIVE 1230
+#define ERROR_NETWORK_UNREACHABLE 1231
+#define ERROR_HOST_UNREACHABLE 1232
+#define ERROR_PROTOCOL_UNREACHABLE 1233
+#define ERROR_PORT_UNREACHABLE 1234
+#define ERROR_REQUEST_ABORTED 1235
+#define ERROR_CONNECTION_ABORTED 1236
+#define ERROR_RETRY 1237
+#define ERROR_CONNECTION_COUNT_LIMIT 1238
+#define ERROR_LOGIN_TIME_RESTRICTION 1239
+#define ERROR_LOGIN_WKSTA_RESTRICTION 1240
+#define ERROR_INCORRECT_ADDRESS 1241
+#define ERROR_ALREADY_REGISTERED 1242
+#define ERROR_SERVICE_NOT_FOUND 1243
+#define ERROR_NOT_AUTHENTICATED 1244
+#define ERROR_NOT_LOGGED_ON 1245
+#define ERROR_CONTINUE 1246
+#define ERROR_ALREADY_INITIALIZED 1247
+#define ERROR_NO_MORE_DEVICES 1248
+#define ERROR_NO_SUCH_SITE 1249
+#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250
+#define ERROR_DS_NOT_INSTALLED 1251
+#define ERROR_NOT_ALL_ASSIGNED 1300
+#define ERROR_SOME_NOT_MAPPED 1301
+#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302
+#define ERROR_LOCAL_USER_SESSION_KEY 1303
+#define ERROR_NULL_LM_PASSWORD 1304
+#define ERROR_UNKNOWN_REVISION 1305
+#define ERROR_REVISION_MISMATCH 1306
+#define ERROR_INVALID_OWNER 1307
+#define ERROR_INVALID_PRIMARY_GROUP 1308
+#define ERROR_NO_IMPERSONATION_TOKEN 1309
+#define ERROR_CANT_DISABLE_MANDATORY 1310
+#define ERROR_NO_LOGON_SERVERS 1311
+#define ERROR_NO_SUCH_LOGON_SESSION 1312
+#define ERROR_NO_SUCH_PRIVILEGE 1313
+#define ERROR_PRIVILEGE_NOT_HELD 1314
+#define ERROR_INVALID_ACCOUNT_NAME 1315
+#define ERROR_USER_EXISTS 1316
+#define ERROR_NO_SUCH_USER 1317
+#define ERROR_GROUP_EXISTS 1318
+#define ERROR_NO_SUCH_GROUP 1319
+#define ERROR_MEMBER_IN_GROUP 1320
+#define ERROR_MEMBER_NOT_IN_GROUP 1321
+#define ERROR_LAST_ADMIN 1322
+#define ERROR_WRONG_PASSWORD 1323
+#define ERROR_ILL_FORMED_PASSWORD 1324
+#define ERROR_PASSWORD_RESTRICTION 1325
+#define ERROR_LOGON_FAILURE 1326
+#define ERROR_ACCOUNT_RESTRICTION 1327
+#define ERROR_INVALID_LOGON_HOURS 1328
+#define ERROR_INVALID_WORKSTATION 1329
+#define ERROR_PASSWORD_EXPIRED 1330
+#define ERROR_ACCOUNT_DISABLED 1331
+#define ERROR_NONE_MAPPED 1332
+#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333
+#define ERROR_LUIDS_EXHAUSTED 1334
+#define ERROR_INVALID_SUB_AUTHORITY 1335
+#define ERROR_INVALID_ACL 1336
+#define ERROR_INVALID_SID 1337
+#define ERROR_INVALID_SECURITY_DESCR 1338
+#define ERROR_BAD_INHERITANCE_ACL 1340
+#define ERROR_SERVER_DISABLED 1341
+#define ERROR_SERVER_NOT_DISABLED 1342
+#define ERROR_INVALID_ID_AUTHORITY 1343
+#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344
+#define ERROR_INVALID_GROUP_ATTRIBUTES 1345
+#define ERROR_BAD_IMPERSONATION_LEVEL 1346
+#define ERROR_CANT_OPEN_ANONYMOUS 1347
+#define ERROR_BAD_VALIDATION_CLASS 1348
+#define ERROR_BAD_TOKEN_TYPE 1349
+#define ERROR_NO_SECURITY_ON_OBJECT 1350
+#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351
+#define ERROR_INVALID_SERVER_STATE 1352
+#define ERROR_INVALID_DOMAIN_STATE 1353
+#define ERROR_INVALID_DOMAIN_ROLE 1354
+#define ERROR_NO_SUCH_DOMAIN 1355
+#define ERROR_DOMAIN_EXISTS 1356
+#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357
+#define ERROR_INTERNAL_DB_CORRUPTION 1358
+#define ERROR_INTERNAL_ERROR 1359
+#define ERROR_GENERIC_NOT_MAPPED 1360
+#define ERROR_BAD_DESCRIPTOR_FORMAT 1361
+#define ERROR_NOT_LOGON_PROCESS 1362
+#define ERROR_LOGON_SESSION_EXISTS 1363
+#define ERROR_NO_SUCH_PACKAGE 1364
+#define ERROR_BAD_LOGON_SESSION_STATE 1365
+#define ERROR_LOGON_SESSION_COLLISION 1366
+#define ERROR_INVALID_LOGON_TYPE 1367
+#define ERROR_CANNOT_IMPERSONATE 1368
+#define ERROR_RXACT_INVALID_STATE 1369
+#define ERROR_RXACT_COMMIT_FAILURE 1370
+#define ERROR_SPECIAL_ACCOUNT 1371
+#define ERROR_SPECIAL_GROUP 1372
+#define ERROR_SPECIAL_USER 1373
+#define ERROR_MEMBERS_PRIMARY_GROUP 1374
+#define ERROR_TOKEN_ALREADY_IN_USE 1375
+#define ERROR_NO_SUCH_ALIAS 1376
+#define ERROR_MEMBER_NOT_IN_ALIAS 1377
+#define ERROR_MEMBER_IN_ALIAS 1378
+#define ERROR_ALIAS_EXISTS 1379
+#define ERROR_LOGON_NOT_GRANTED 1380
+#define ERROR_TOO_MANY_SECRETS 1381
+#define ERROR_SECRET_TOO_LONG 1382
+#define ERROR_INTERNAL_DB_ERROR 1383
+#define ERROR_TOO_MANY_CONTEXT_IDS 1384
+#define ERROR_LOGON_TYPE_NOT_GRANTED 1385
+#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386
+#define ERROR_NO_SUCH_MEMBER 1387
+#define ERROR_INVALID_MEMBER 1388
+#define ERROR_TOO_MANY_SIDS 1389
+#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390
+#define ERROR_NO_INHERITANCE 1391
+#define ERROR_FILE_CORRUPT 1392
+#define ERROR_DISK_CORRUPT 1393
+#define ERROR_NO_USER_SESSION_KEY 1394
+#define ERROR_LICENSE_QUOTA_EXCEEDED 1395
+#define ERROR_INVALID_WINDOW_HANDLE 1400
+#define ERROR_INVALID_MENU_HANDLE 1401
+#define ERROR_INVALID_CURSOR_HANDLE 1402
+#define ERROR_INVALID_ACCEL_HANDLE 1403
+#define ERROR_INVALID_HOOK_HANDLE 1404
+#define ERROR_INVALID_DWP_HANDLE 1405
+#define ERROR_TLW_WITH_WSCHILD 1406
+#define ERROR_CANNOT_FIND_WND_CLASS 1407
+#define ERROR_WINDOW_OF_OTHER_THREAD 1408
+#define ERROR_HOTKEY_ALREADY_REGISTERED 1409
+#define ERROR_CLASS_ALREADY_EXISTS 1410
+#define ERROR_CLASS_DOES_NOT_EXIST 1411
+#define ERROR_CLASS_HAS_WINDOWS 1412
+#define ERROR_INVALID_INDEX 1413
+#define ERROR_INVALID_ICON_HANDLE 1414
+#define ERROR_PRIVATE_DIALOG_INDEX 1415
+#define ERROR_LISTBOX_ID_NOT_FOUND 1416
+#define ERROR_NO_WILDCARD_CHARACTERS 1417
+#define ERROR_CLIPBOARD_NOT_OPEN 1418
+#define ERROR_HOTKEY_NOT_REGISTERED 1419
+#define ERROR_WINDOW_NOT_DIALOG 1420
+#define ERROR_CONTROL_ID_NOT_FOUND 1421
+#define ERROR_INVALID_COMBOBOX_MESSAGE 1422
+#define ERROR_WINDOW_NOT_COMBOBOX 1423
+#define ERROR_INVALID_EDIT_HEIGHT 1424
+#define ERROR_DC_NOT_FOUND 1425
+#define ERROR_INVALID_HOOK_FILTER 1426
+#define ERROR_INVALID_FILTER_PROC 1427
+#define ERROR_HOOK_NEEDS_HMOD 1428
+#define ERROR_GLOBAL_ONLY_HOOK 1429
+#define ERROR_JOURNAL_HOOK_SET 1430
+#define ERROR_HOOK_NOT_INSTALLED 1431
+#define ERROR_INVALID_LB_MESSAGE 1432
+#define ERROR_SETCOUNT_ON_BAD_LB 1433
+#define ERROR_LB_WITHOUT_TABSTOPS 1434
+#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435
+#define ERROR_CHILD_WINDOW_MENU 1436
+#define ERROR_NO_SYSTEM_MENU 1437
+#define ERROR_INVALID_MSGBOX_STYLE 1438
+#define ERROR_INVALID_SPI_VALUE 1439
+#define ERROR_SCREEN_ALREADY_LOCKED 1440
+#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441
+#define ERROR_NOT_CHILD_WINDOW 1442
+#define ERROR_INVALID_GW_COMMAND 1443
+#define ERROR_INVALID_THREAD_ID 1444
+#define ERROR_NON_MDICHILD_WINDOW 1445
+#define ERROR_POPUP_ALREADY_ACTIVE 1446
+#define ERROR_NO_SCROLLBARS 1447
+#define ERROR_INVALID_SCROLLBAR_RANGE 1448
+#define ERROR_INVALID_SHOWWIN_COMMAND 1449
+#define ERROR_NO_SYSTEM_RESOURCES 1450
+#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451
+#define ERROR_PAGED_SYSTEM_RESOURCES 1452
+#define ERROR_WORKING_SET_QUOTA 1453
+#define ERROR_PAGEFILE_QUOTA 1454
+#define ERROR_COMMITMENT_LIMIT 1455
+#define ERROR_MENU_ITEM_NOT_FOUND 1456
+#define ERROR_INVALID_KEYBOARD_HANDLE 1457
+#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458
+#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459
+#define ERROR_TIMEOUT 1460
+#define ERROR_INVALID_MONITOR_HANDLE 1461
+#define ERROR_EVENTLOG_FILE_CORRUPT 1500
+#define ERROR_EVENTLOG_CANT_START 1501
+#define ERROR_LOG_FILE_FULL 1502
+#define ERROR_EVENTLOG_FILE_CHANGED 1503
+#define ERROR_INSTALL_SERVICE 1601
+#define ERROR_INSTALL_USEREXIT 1602
+#define ERROR_INSTALL_FAILURE 1603
+#define ERROR_INSTALL_SUSPEND 1604
+#define ERROR_UNKNOWN_PRODUCT 1605
+#define ERROR_UNKNOWN_FEATURE 1606
+#define ERROR_UNKNOWN_COMPONENT 1607
+#define ERROR_UNKNOWN_PROPERTY 1608
+#define ERROR_INVALID_HANDLE_STATE 1609
+#define ERROR_BAD_CONFIGURATION 1610
+#define ERROR_INDEX_ABSENT 1611
+#define ERROR_INSTALL_SOURCE_ABSENT 1612
+#define ERROR_BAD_DATABASE_VERSION 1613
+#define ERROR_PRODUCT_UNINSTALLED 1614
+#define ERROR_BAD_QUERY_SYNTAX 1615
+#define ERROR_INVALID_FIELD 1616
+#define RPC_S_INVALID_STRING_BINDING 1700
+#define RPC_S_WRONG_KIND_OF_BINDING 1701
+#define RPC_S_INVALID_BINDING 1702
+#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703
+#define RPC_S_INVALID_RPC_PROTSEQ 1704
+#define RPC_S_INVALID_STRING_UUID 1705
+#define RPC_S_INVALID_ENDPOINT_FORMAT 1706
+#define RPC_S_INVALID_NET_ADDR 1707
+#define RPC_S_NO_ENDPOINT_FOUND 1708
+#define RPC_S_INVALID_TIMEOUT 1709
+#define RPC_S_OBJECT_NOT_FOUND 1710
+#define RPC_S_ALREADY_REGISTERED 1711
+#define RPC_S_TYPE_ALREADY_REGISTERED 1712
+#define RPC_S_ALREADY_LISTENING 1713
+#define RPC_S_NO_PROTSEQS_REGISTERED 1714
+#define RPC_S_NOT_LISTENING 1715
+#define RPC_S_UNKNOWN_MGR_TYPE 1716
+#define RPC_S_UNKNOWN_IF 1717
+#define RPC_S_NO_BINDINGS 1718
+#define RPC_S_NO_PROTSEQS 1719
+#define RPC_S_CANT_CREATE_ENDPOINT 1720
+#define RPC_S_OUT_OF_RESOURCES 1721
+#define RPC_S_SERVER_UNAVAILABLE 1722
+#define RPC_S_SERVER_TOO_BUSY 1723
+#define RPC_S_INVALID_NETWORK_OPTIONS 1724
+#define RPC_S_NO_CALL_ACTIVE 1725
+#define RPC_S_CALL_FAILED 1726
+#define RPC_S_CALL_FAILED_DNE 1727
+#define RPC_S_PROTOCOL_ERROR 1728
+#define RPC_S_UNSUPPORTED_TRANS_SYN 1730
+#define RPC_S_UNSUPPORTED_TYPE 1732
+#define RPC_S_INVALID_TAG 1733
+#define RPC_S_INVALID_BOUND 1734
+#define RPC_S_NO_ENTRY_NAME 1735
+#define RPC_S_INVALID_NAME_SYNTAX 1736
+#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737
+#define RPC_S_UUID_NO_ADDRESS 1739
+#define RPC_S_DUPLICATE_ENDPOINT 1740
+#define RPC_S_UNKNOWN_AUTHN_TYPE 1741
+#define RPC_S_MAX_CALLS_TOO_SMALL 1742
+#define RPC_S_STRING_TOO_LONG 1743
+#define RPC_S_PROTSEQ_NOT_FOUND 1744
+#define RPC_S_PROCNUM_OUT_OF_RANGE 1745
+#define RPC_S_BINDING_HAS_NO_AUTH 1746
+#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747
+#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748
+#define RPC_S_INVALID_AUTH_IDENTITY 1749
+#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750
+#define EPT_S_INVALID_ENTRY 1751
+#define EPT_S_CANT_PERFORM_OP 1752
+#define EPT_S_NOT_REGISTERED 1753
+#define RPC_S_NOTHING_TO_EXPORT 1754
+#define RPC_S_INCOMPLETE_NAME 1755
+#define RPC_S_INVALID_VERS_OPTION 1756
+#define RPC_S_NO_MORE_MEMBERS 1757
+#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758
+#define RPC_S_INTERFACE_NOT_FOUND 1759
+#define RPC_S_ENTRY_ALREADY_EXISTS 1760
+#define RPC_S_ENTRY_NOT_FOUND 1761
+#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762
+#define RPC_S_INVALID_NAF_ID 1763
+#define RPC_S_CANNOT_SUPPORT 1764
+#define RPC_S_NO_CONTEXT_AVAILABLE 1765
+#define RPC_S_INTERNAL_ERROR 1766
+#define RPC_S_ZERO_DIVIDE 1767
+#define RPC_S_ADDRESS_ERROR 1768
+#define RPC_S_FP_DIV_ZERO 1769
+#define RPC_S_FP_UNDERFLOW 1770
+#define RPC_S_FP_OVERFLOW 1771
+#define RPC_X_NO_MORE_ENTRIES 1772
+#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773
+#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774
+#define RPC_X_SS_IN_NULL_CONTEXT 1775
+#define RPC_X_SS_CONTEXT_DAMAGED 1777
+#define RPC_X_SS_HANDLES_MISMATCH 1778
+#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779
+#define RPC_X_NULL_REF_POINTER 1780
+#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781
+#define RPC_X_BYTE_COUNT_TOO_SMALL 1782
+#define RPC_X_BAD_STUB_DATA 1783
+#define ERROR_INVALID_USER_BUFFER 1784
+#define ERROR_UNRECOGNIZED_MEDIA 1785
+#define ERROR_NO_TRUST_LSA_SECRET 1786
+#define ERROR_NO_TRUST_SAM_ACCOUNT 1787
+#define ERROR_TRUSTED_DOMAIN_FAILURE 1788
+#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789
+#define ERROR_TRUST_FAILURE 1790
+#define RPC_S_CALL_IN_PROGRESS 1791
+#define ERROR_NETLOGON_NOT_STARTED 1792
+#define ERROR_ACCOUNT_EXPIRED 1793
+#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794
+#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795
+#define ERROR_UNKNOWN_PORT 1796
+#define ERROR_UNKNOWN_PRINTER_DRIVER 1797
+#define ERROR_UNKNOWN_PRINTPROCESSOR 1798
+#define ERROR_INVALID_SEPARATOR_FILE 1799
+#define ERROR_INVALID_PRIORITY 1800
+#define ERROR_INVALID_PRINTER_NAME 1801
+#define ERROR_PRINTER_ALREADY_EXISTS 1802
+#define ERROR_INVALID_PRINTER_COMMAND 1803
+#define ERROR_INVALID_DATATYPE 1804
+#define ERROR_INVALID_ENVIRONMENT 1805
+#define RPC_S_NO_MORE_BINDINGS 1806
+#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807
+#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808
+#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809
+#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810
+#define ERROR_SERVER_HAS_OPEN_HANDLES 1811
+#define ERROR_RESOURCE_DATA_NOT_FOUND 1812
+#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813
+#define ERROR_RESOURCE_NAME_NOT_FOUND 1814
+#define ERROR_RESOURCE_LANG_NOT_FOUND 1815
+#define ERROR_NOT_ENOUGH_QUOTA 1816
+#define RPC_S_NO_INTERFACES 1817
+#define RPC_S_CALL_CANCELLED 1818
+#define RPC_S_BINDING_INCOMPLETE 1819
+#define RPC_S_COMM_FAILURE 1820
+#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821
+#define RPC_S_NO_PRINC_NAME 1822
+#define RPC_S_NOT_RPC_ERROR 1823
+#define RPC_S_UUID_LOCAL_ONLY 1824
+#define RPC_S_SEC_PKG_ERROR 1825
+#define RPC_S_NOT_CANCELLED 1826
+#define RPC_X_INVALID_ES_ACTION 1827
+#define RPC_X_WRONG_ES_VERSION 1828
+#define RPC_X_WRONG_STUB_VERSION 1829
+#define RPC_X_INVALID_PIPE_OBJECT 1830
+#define RPC_X_WRONG_PIPE_ORDER 1831
+#define RPC_X_WRONG_PIPE_VERSION 1832
+#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898
+#define EPT_S_CANT_CREATE 1899
+#define RPC_S_INVALID_OBJECT 1900
+#define ERROR_INVALID_TIME 1901
+#define ERROR_INVALID_FORM_NAME 1902
+#define ERROR_INVALID_FORM_SIZE 1903
+#define ERROR_ALREADY_WAITING 1904
+#define ERROR_PRINTER_DELETED 1905
+#define ERROR_INVALID_PRINTER_STATE 1906
+#define ERROR_PASSWORD_MUST_CHANGE 1907
+#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908
+#define ERROR_ACCOUNT_LOCKED_OUT 1909
+#define OR_INVALID_OXID 1910
+#define OR_INVALID_OID 1911
+#define OR_INVALID_SET 1912
+#define RPC_S_SEND_INCOMPLETE 1913
+#define RPC_S_INVALID_ASYNC_HANDLE 1914
+#define RPC_S_INVALID_ASYNC_CALL 1915
+#define RPC_X_PIPE_CLOSED 1916
+#define RPC_X_PIPE_DISCIPLINE_ERROR 1917
+#define RPC_X_PIPE_EMPTY 1918
+#define ERROR_NO_SITENAME 1919
+#define ERROR_CANT_ACCESS_FILE 1920
+#define ERROR_CANT_RESOLVE_FILENAME 1921
+#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 1922
+#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 1923
+#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 1924
+#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 1925
+#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 1926
+#define ERROR_DS_BUSY 1927
+#define ERROR_DS_UNAVAILABLE 1928
+#define ERROR_DS_NO_RIDS_ALLOCATED 1929
+#define ERROR_DS_NO_MORE_RIDS 1930
+#define ERROR_DS_INCORRECT_ROLE_OWNER 1931
+#define ERROR_DS_RIDMGR_INIT_ERROR 1932
+#define ERROR_DS_OBJ_CLASS_VIOLATION 1933
+#define ERROR_DS_CANT_ON_NON_LEAF 1934
+#define ERROR_DS_CANT_ON_RDN 1935
+#define ERROR_DS_CANT_MOD_OBJ_CLASS 1936
+#define ERROR_DS_CROSS_DOM_MOVE_ERROR 1937
+#define ERROR_DS_GC_NOT_AVAILABLE 1938
+#define ERROR_NO_BROWSER_SERVERS_FOUND 6118
+#define ERROR_INVALID_PIXEL_FORMAT 2000
+#define ERROR_BAD_DRIVER 2001
+#define ERROR_INVALID_WINDOW_STYLE 2002
+#define ERROR_METAFILE_NOT_SUPPORTED 2003
+#define ERROR_TRANSFORM_NOT_SUPPORTED 2004
+#define ERROR_CLIPPING_NOT_SUPPORTED 2005
+#define ERROR_INVALID_CMM 2300
+#define ERROR_INVALID_PROFILE 2301
+#define ERROR_TAG_NOT_FOUND 2302
+#define ERROR_TAG_NOT_PRESENT 2303
+#define ERROR_DUPLICATE_TAG 2304
+#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2305
+#define ERROR_PROFILE_NOT_FOUND 2306
+#define ERROR_INVALID_COLORSPACE 2307
+#define ERROR_ICM_NOT_ENABLED 2308
+#define ERROR_DELETING_ICM_XFORM 2309
+#define ERROR_INVALID_TRANSFORM 2310
+#define ERROR_UNKNOWN_PRINT_MONITOR 3000
+#define ERROR_PRINTER_DRIVER_IN_USE 3001
+#define ERROR_SPOOL_FILE_NOT_FOUND 3002
+#define ERROR_SPL_NO_STARTDOC 3003
+#define ERROR_SPL_NO_ADDJOB 3004
+#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005
+#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006
+#define ERROR_INVALID_PRINT_MONITOR 3007
+#define ERROR_PRINT_MONITOR_IN_USE 3008
+#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009
+#define ERROR_SUCCESS_REBOOT_REQUIRED 3010
+#define ERROR_SUCCESS_RESTART_REQUIRED 3011
+#define ERROR_WINS_INTERNAL 4000
+#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001
+#define ERROR_STATIC_INIT 4002
+#define ERROR_INC_BACKUP 4003
+#define ERROR_FULL_BACKUP 4004
+#define ERROR_REC_NON_EXISTENT 4005
+#define ERROR_RPL_NOT_ALLOWED 4006
+#define ERROR_DHCP_ADDRESS_CONFLICT 4100
+#define ERROR_WMI_GUID_NOT_FOUND 4200
+#define ERROR_WMI_INSTANCE_NOT_FOUND 4201
+#define ERROR_WMI_ITEMID_NOT_FOUND 4202
+#define ERROR_WMI_TRY_AGAIN 4203
+#define ERROR_WMI_DP_NOT_FOUND 4204
+#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205
+#define ERROR_WMI_ALREADY_ENABLED 4206
+#define ERROR_WMI_GUID_DISCONNECTED 4207
+#define ERROR_WMI_SERVER_UNAVAILABLE 4208
+#define ERROR_WMI_DP_FAILED 4209
+#define ERROR_WMI_INVALID_MOF 4210
+#define ERROR_WMI_INVALID_REGINFO 4211
+#define ERROR_INVALID_MEDIA 4300
+#define ERROR_INVALID_LIBRARY 4301
+#define ERROR_INVALID_MEDIA_POOL 4302
+#define ERROR_DRIVE_MEDIA_MISMATCH 4303
+#define ERROR_MEDIA_OFFLINE 4304
+#define ERROR_LIBRARY_OFFLINE 4305
+#define ERROR_EMPTY 4306
+#define ERROR_NOT_EMPTY 4307
+#define ERROR_MEDIA_UNAVAILABLE 4308
+#define ERROR_RESOURCE_DISABLED 4309
+#define ERROR_INVALID_CLEANER 4310
+#define ERROR_UNABLE_TO_CLEAN 4311
+#define ERROR_OBJECT_NOT_FOUND 4312
+#define ERROR_DATABASE_FAILURE 4313
+#define ERROR_DATABASE_FULL 4314
+#define ERROR_MEDIA_INCOMPATIBLE 4315
+#define ERROR_RESOURCE_NOT_PRESENT 4316
+#define ERROR_INVALID_OPERATION 4317
+#define ERROR_MEDIA_NOT_AVAILABLE 4318
+#define ERROR_DEVICE_NOT_AVAILABLE 4319
+#define ERROR_REQUEST_REFUSED 4320
+#define ERROR_FILE_OFFLINE 4350
+#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351
+#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352
+#define ERROR_NOT_A_REPARSE_POINT 4390
+#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391
+#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001
+#define ERROR_DEPENDENCY_NOT_FOUND 5002
+#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003
+#define ERROR_RESOURCE_NOT_ONLINE 5004
+#define ERROR_HOST_NODE_NOT_AVAILABLE 5005
+#define ERROR_RESOURCE_NOT_AVAILABLE 5006
+#define ERROR_RESOURCE_NOT_FOUND 5007
+#define ERROR_SHUTDOWN_CLUSTER 5008
+#define ERROR_CANT_EVICT_ACTIVE_NODE 5009
+#define ERROR_OBJECT_ALREADY_EXISTS 5010
+#define ERROR_OBJECT_IN_LIST 5011
+#define ERROR_GROUP_NOT_AVAILABLE 5012
+#define ERROR_GROUP_NOT_FOUND 5013
+#define ERROR_GROUP_NOT_ONLINE 5014
+#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015
+#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016
+#define ERROR_RESMON_CREATE_FAILED 5017
+#define ERROR_RESMON_ONLINE_FAILED 5018
+#define ERROR_RESOURCE_ONLINE 5019
+#define ERROR_QUORUM_RESOURCE 5020
+#define ERROR_NOT_QUORUM_CAPABLE 5021
+#define ERROR_CLUSTER_SHUTTING_DOWN 5022
+#define ERROR_INVALID_STATE 5023
+#define ERROR_RESOURCE_PROPERTIES_STORED 5024
+#define ERROR_NOT_QUORUM_CLASS 5025
+#define ERROR_CORE_RESOURCE 5026
+#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027
+#define ERROR_QUORUMLOG_OPEN_FAILED 5028
+#define ERROR_CLUSTERLOG_CORRUPT 5029
+#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030
+#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031
+#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032
+#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033
+#define ERROR_ENCRYPTION_FAILED 6000
+#define ERROR_DECRYPTION_FAILED 6001
+#define ERROR_FILE_ENCRYPTED 6002
+#define ERROR_NO_RECOVERY_POLICY 6003
+#define ERROR_NO_EFS 6004
+#define ERROR_WRONG_EFS 6005
+#define ERROR_NO_USER_KEYS 6006
+#define ERROR_FILE_NOT_ENCRYPTED 6007
+#define ERROR_NOT_EXPORT_FORMAT 6008
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NTERROR_H */
diff --git a/usr/src/uts/common/smbsrv/ntifs.h b/usr/src/uts/common/smbsrv/ntifs.h
new file mode 100644
index 0000000000..c538e4139e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntifs.h
@@ -0,0 +1,216 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NTIFS_H
+#define _SMBSRV_NTIFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions compatible with the NT Installable
+ * File System (IFS) interface.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * File creation flags must start at the high end since they
+ * are combined with the attributes
+ */
+
+#define FILE_FLAG_WRITE_THROUGH 0x80000000
+#define FILE_FLAG_OVERLAPPED 0x40000000
+#define FILE_FLAG_NO_BUFFERING 0x20000000
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
+#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
+#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
+#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
+#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
+
+/*
+ * The create/open option flags: used in NtCreateAndx and NtTransactCreate
+ * SMB requests.
+ *
+ * The CreateOptions specify the options to be applied when creating or
+ * opening the file, as a compatible combination of the following flags:
+ *
+ * FILE_DIRECTORY_FILE
+ * The file being created or opened is a directory file. With this
+ * flag, the Disposition parameter must be set to one of FILE_CREATE,
+ * FILE_OPEN, or FILE_OPEN_IF. With this flag, other compatible
+ * CreateOptions flags include only the following:
+ * FILE_SYNCHRONOUS_IO_ALERT
+ * FILE_SYNCHRONOUS_IO_NONALERT
+ * FILE_WRITE_THROUGH
+ * FILE_OPEN_FOR_BACKUP_INTENT
+ * FILE_OPEN_BY_FILE_ID
+ *
+ * FILE_NON_DIRECTORY_FILE
+ * The file being opened must not be a directory file or this call
+ * will fail. The file object being opened can represent a data file,
+ * a logical, virtual, or physical device, or a volume.
+ *
+ * FILE_WRITE_THROUGH
+ * System services, FSDs, and drivers that write data to the file must
+ * actually transfer the data into the file before any requested write
+ * operation is considered complete. This flag is automatically set if
+ * the CreateOptions flag FILE_NO_INTERMEDIATE _BUFFERING is set.
+ *
+ * FILE_SEQUENTIAL_ONLY
+ * All accesses to the file will be sequential.
+ *
+ * FILE_RANDOM_ACCESS
+ * Accesses to the file can be random, so no sequential read-ahead
+ * operations should be performed on the file by FSDs or the system.
+ * FILE_NO_INTERMEDIATE _BUFFERING The file cannot be cached or
+ * buffered in a driver's internal buffers. This flag is incompatible
+ * with the DesiredAccess FILE_APPEND_DATA flag.
+ *
+ * FILE_SYNCHRONOUS_IO_ALERT
+ * All operations on the file are performed synchronously. Any wait
+ * on behalf of the caller is subject to premature termination from
+ * alerts. This flag also causes the I/O system to maintain the file
+ * position context. If this flag is set, the DesiredAccess
+ * SYNCHRONIZE flag also must be set.
+ *
+ * FILE_SYNCHRONOUS_IO _NONALERT
+ * All operations on the file are performed synchronously. Waits in
+ * the system to synchronize I/O queuing and completion are not subject
+ * to alerts. This flag also causes the I/O system to maintain the file
+ * position context. If this flag is set, the DesiredAccess SYNCHRONIZE
+ * flag also must be set.
+ *
+ * FILE_CREATE_TREE _CONNECTION
+ * Create a tree connection for this file in order to open it over the
+ * network. This flag is irrelevant to device and intermediate drivers.
+ *
+ * FILE_COMPLETE_IF_OPLOCKED
+ * Complete this operation immediately with an alternate success code
+ * if the target file is oplocked, rather than blocking the caller's
+ * thread. If the file is oplocked, another caller already has access
+ * to the file over the network. This flag is irrelevant to device and
+ * intermediate drivers.
+ *
+ * FILE_NO_EA_KNOWLEDGE
+ * If the extended attributes on an existing file being opened indicate
+ * that the caller must understand EAs to properly interpret the file,
+ * fail this request because the caller does not understand how to deal
+ * with EAs. Device and intermediate drivers can ignore this flag.
+ *
+ * FILE_DELETE_ON_CLOSE
+ * Delete the file when the last reference to it is passed to close.
+ *
+ * FILE_OPEN_BY_FILE_ID
+ * The file name contains the name of a device and a 64-bit ID to
+ * be used to open the file. This flag is irrelevant to device and
+ * intermediate drivers.
+ *
+ * FILE_OPEN_FOR_BACKUP _INTENT
+ * The file is being opened for backup intent, hence, the system should
+ * check for certain access rights and grant the caller the appropriate
+ * accesses to the file before checking the input DesiredAccess against
+ * the file's security descriptor. This flag is irrelevant to device
+ * and intermediate drivers.
+ */
+#define FILE_DIRECTORY_FILE 0x00000001
+#define FILE_WRITE_THROUGH 0x00000002
+#define FILE_SEQUENTIAL_ONLY 0x00000004
+#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+#define FILE_NON_DIRECTORY_FILE 0x00000040
+#define FILE_CREATE_TREE_CONNECTION 0x00000080
+
+#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
+#define FILE_NO_EA_KNOWLEDGE 0x00000200
+/* UNUSED 0x00000400 */
+#define FILE_RANDOM_ACCESS 0x00000800
+
+#define FILE_DELETE_ON_CLOSE 0x00001000
+#define FILE_OPEN_BY_FILE_ID 0x00002000
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
+#define FILE_NO_COMPRESSION 0x00008000
+
+#define FILE_RESERVE_OPFILTER 0x00100000
+#define FILE_RESERVED0 0x00200000
+#define FILE_RESERVED1 0x00400000
+#define FILE_RESERVED2 0x00800000
+
+#define FILE_VALID_OPTION_FLAGS 0x007fffff
+#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032
+#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032
+#define FILE_VALID_SET_FLAGS 0x00000036
+
+/*
+ * Define the file information class values used by the NT DDK and HAL.
+ */
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation, /* 2 */
+ FileBothDirectoryInformation, /* 3 */
+ FileBasicInformation, /* 4 */
+ FileStandardInformation, /* 5 */
+ FileInternalInformation, /* 6 */
+ FileEaInformation, /* 7 */
+ FileAccessInformation, /* 8 */
+ FileNameInformation, /* 9 */
+ FileRenameInformation, /* 10 */
+ FileLinkInformation, /* 11 */
+ FileNamesInformation, /* 12 */
+ FileDispositionInformation, /* 13 */
+ FilePositionInformation, /* 14 */
+ FileFullEaInformation, /* 15 */
+ FileModeInformation, /* 16 */
+ FileAlignmentInformation, /* 17 */
+ FileAllInformation, /* 18 */
+ FileAllocationInformation, /* 19 */
+ FileEndOfFileInformation, /* 20 */
+ FileAlternateNameInformation, /* 21 */
+ FileStreamInformation, /* 22 */
+ FilePipeInformation, /* 23 */
+ FilePipeLocalInformation, /* 24 */
+ FilePipeRemoteInformation, /* 25 */
+ FileMailslotQueryInformation, /* 26 */
+ FileMailslotSetInformation, /* 27 */
+ FileCompressionInformation, /* 28 */
+ FileObjectIdInformation, /* 29 */
+ FileCompletionInformation, /* 30 */
+ FileMoveClusterInformation, /* 31 */
+ FileInformationReserved32, /* 32 */
+ FileInformationReserved33, /* 33 */
+ FileNetworkOpenInformation, /* 34 */
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NTIFS_H */
diff --git a/usr/src/uts/common/smbsrv/ntlocale.h b/usr/src/uts/common/smbsrv/ntlocale.h
new file mode 100644
index 0000000000..778d6fe68e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntlocale.h
@@ -0,0 +1,330 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NTLOCALE_H
+#define _SMBSRV_NTLOCALE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT language and locale identifiers.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Language IDs.
+ *
+ * A language ID is a 16 bit value which is the combination of a
+ * primary language ID and a secondary language ID. The bits are
+ * allocated as follows:
+ *
+ * +-----------------------+-------------------------+
+ * | Sublanguage ID | Primary Language ID |
+ * +-----------------------+-------------------------+
+ * 15 10 9 0 bit
+ *
+ * The following two combinations of primary language ID and sub-
+ * language ID have special semantics:
+ *
+ * Primary Language ID Sublanguage ID Result
+ * ------------------- --------------- ------------------------
+ * LANG_NEUTRAL SUBLANG_NEUTRAL Language neutral
+ * LANG_NEUTRAL SUBLANG_DEFAULT User default language
+ * LANG_NEUTRAL SUBLANG_SYS_DEFAULT System default language
+ *
+ * Language ID creation/extraction macros:
+ * MAKELANGID - construct language id from a primary language
+ * id and a sublanguage id.
+ * PRIMARYLANGID - extract primary language id from a language id.
+ * SUBLANGID - extract sublanguage id from a language id.
+ */
+#define MAKELANGID(p, s) ((((WORD)(s)) << 10) | (WORD)(p))
+#define PRIMARYLANGID(lgid) ((WORD)(lgid) & 0x3ff)
+#define SUBLANGID(lgid) ((WORD)(lgid) >> 10)
+
+
+/*
+ * Primary language IDs.
+ */
+#define LANG_NEUTRAL 0x00
+
+#define LANG_AFRIKAANS 0x36
+#define LANG_ALBANIAN 0x1c
+#define LANG_ARABIC 0x01
+#define LANG_ARMENIAN 0x2b
+#define LANG_ASSAMESE 0x4d
+#define LANG_AZERI 0x2c
+#define LANG_BASQUE 0x2d
+#define LANG_BELARUSIAN 0x23
+#define LANG_BENGALI 0x45
+#define LANG_BULGARIAN 0x02
+#define LANG_CATALAN 0x03
+#define LANG_CHINESE 0x04
+#define LANG_CROATIAN 0x1a
+#define LANG_CZECH 0x05
+#define LANG_DANISH 0x06
+#define LANG_DUTCH 0x13
+#define LANG_ENGLISH 0x09
+#define LANG_ESTONIAN 0x25
+#define LANG_FAEROESE 0x38
+#define LANG_FARSI 0x29
+#define LANG_FINNISH 0x0b
+#define LANG_FRENCH 0x0c
+#define LANG_GEORGIAN 0x37
+#define LANG_GERMAN 0x07
+#define LANG_GREEK 0x08
+#define LANG_GUJARATI 0x47
+#define LANG_HEBREW 0x0d
+#define LANG_HINDI 0x39
+#define LANG_HUNGARIAN 0x0e
+#define LANG_ICELANDIC 0x0f
+#define LANG_INDONESIAN 0x21
+#define LANG_ITALIAN 0x10
+#define LANG_JAPANESE 0x11
+#define LANG_KANNADA 0x4b
+#define LANG_KASHMIRI 0x60
+#define LANG_KAZAK 0x3f
+#define LANG_KONKANI 0x57
+#define LANG_KOREAN 0x12
+#define LANG_LATVIAN 0x26
+#define LANG_LITHUANIAN 0x27
+#define LANG_MACEDONIAN 0x2f
+#define LANG_MALAY 0x3e
+#define LANG_MALAYALAM 0x4c
+#define LANG_MANIPURI 0x58
+#define LANG_MARATHI 0x4e
+#define LANG_NEPALI 0x61
+#define LANG_NORWEGIAN 0x14
+#define LANG_ORIYA 0x48
+#define LANG_POLISH 0x15
+#define LANG_PORTUGUESE 0x16
+#define LANG_PUNJABI 0x46
+#define LANG_ROMANIAN 0x18
+#define LANG_RUSSIAN 0x19
+#define LANG_SANSKRIT 0x4f
+#define LANG_SERBIAN 0x1a
+#define LANG_SINDHI 0x59
+#define LANG_SLOVAK 0x1b
+#define LANG_SLOVENIAN 0x24
+#define LANG_SPANISH 0x0a
+#define LANG_SWAHILI 0x41
+#define LANG_SWEDISH 0x1d
+#define LANG_TAMIL 0x49
+#define LANG_TATAR 0x44
+#define LANG_TELUGU 0x4a
+#define LANG_THAI 0x1e
+#define LANG_TURKISH 0x1f
+#define LANG_UKRAINIAN 0x22
+#define LANG_URDU 0x20
+#define LANG_UZBEK 0x43
+#define LANG_VIETNAMESE 0x2a
+
+
+/*
+ * Sublanguage IDs.
+ *
+ * The name immediately following SUBLANG_ dictates which primary
+ * language ID can be combined with the sub-language ID to form a
+ * valid language ID.
+ */
+#define SUBLANG_NEUTRAL 0x00 /* language neutral */
+#define SUBLANG_DEFAULT 0x01 /* user default */
+#define SUBLANG_SYS_DEFAULT 0x02 /* system default */
+
+#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 /* Arabic (Saudi Arabia) */
+#define SUBLANG_ARABIC_IRAQ 0x02 /* Arabic (Iraq) */
+#define SUBLANG_ARABIC_EGYPT 0x03 /* Arabic (Egypt) */
+#define SUBLANG_ARABIC_LIBYA 0x04 /* Arabic (Libya) */
+#define SUBLANG_ARABIC_ALGERIA 0x05 /* Arabic (Algeria) */
+#define SUBLANG_ARABIC_MOROCCO 0x06 /* Arabic (Morocco) */
+#define SUBLANG_ARABIC_TUNISIA 0x07 /* Arabic (Tunisia) */
+#define SUBLANG_ARABIC_OMAN 0x08 /* Arabic (Oman) */
+#define SUBLANG_ARABIC_YEMEN 0x09 /* Arabic (Yemen) */
+#define SUBLANG_ARABIC_SYRIA 0x0a /* Arabic (Syria) */
+#define SUBLANG_ARABIC_JORDAN 0x0b /* Arabic (Jordan) */
+#define SUBLANG_ARABIC_LEBANON 0x0c /* Arabic (Lebanon) */
+#define SUBLANG_ARABIC_KUWAIT 0x0d /* Arabic (Kuwait) */
+#define SUBLANG_ARABIC_UAE 0x0e /* Arabic (U.A.E) */
+#define SUBLANG_ARABIC_BAHRAIN 0x0f /* Arabic (Bahrain) */
+#define SUBLANG_ARABIC_QATAR 0x10 /* Arabic (Qatar) */
+#define SUBLANG_AZERI_LATIN 0x01 /* Azeri (Latin) */
+#define SUBLANG_AZERI_CYRILLIC 0x02 /* Azeri (Cyrillic) */
+#define SUBLANG_CHINESE_TRADITIONAL 0x01 /* Chinese (Taiwan Region) */
+#define SUBLANG_CHINESE_SIMPLIFIED 0x02 /* Chinese (PR China) */
+#define SUBLANG_CHINESE_HONGKONG 0x03 /* Chinese (Hong Kong) */
+#define SUBLANG_CHINESE_SINGAPORE 0x04 /* Chinese (Singapore) */
+#define SUBLANG_CHINESE_MACAU 0x05 /* Chinese (Macau) */
+#define SUBLANG_DUTCH 0x01 /* Dutch */
+#define SUBLANG_DUTCH_BELGIAN 0x02 /* Dutch (Belgian) */
+#define SUBLANG_ENGLISH_US 0x01 /* English (USA) */
+#define SUBLANG_ENGLISH_UK 0x02 /* English (UK) */
+#define SUBLANG_ENGLISH_AUS 0x03 /* English (Australian) */
+#define SUBLANG_ENGLISH_CAN 0x04 /* English (Canadian) */
+#define SUBLANG_ENGLISH_NZ 0x05 /* English (New Zealand) */
+#define SUBLANG_ENGLISH_EIRE 0x06 /* English (Irish) */
+#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 /* English (South Africa) */
+#define SUBLANG_ENGLISH_JAMAICA 0x08 /* English (Jamaica) */
+#define SUBLANG_ENGLISH_CARIBBEAN 0x09 /* English (Caribbean) */
+#define SUBLANG_ENGLISH_BELIZE 0x0a /* English (Belize) */
+#define SUBLANG_ENGLISH_TRINIDAD 0x0b /* English (Trinidad) */
+#define SUBLANG_ENGLISH_ZIMBABWE 0x0c /* English (Zimbabwe) */
+#define SUBLANG_ENGLISH_PHILIPPINES 0x0d /* English (Philippines) */
+#define SUBLANG_FRENCH 0x01 /* French */
+#define SUBLANG_FRENCH_BELGIAN 0x02 /* French (Belgian) */
+#define SUBLANG_FRENCH_CANADIAN 0x03 /* French (Canadian) */
+#define SUBLANG_FRENCH_SWISS 0x04 /* French (Swiss) */
+#define SUBLANG_FRENCH_LUXEMBOURG 0x05 /* French (Luxembourg) */
+#define SUBLANG_FRENCH_MONACO 0x06 /* French (Monaco) */
+#define SUBLANG_GERMAN 0x01 /* German */
+#define SUBLANG_GERMAN_SWISS 0x02 /* German (Swiss) */
+#define SUBLANG_GERMAN_AUSTRIAN 0x03 /* German (Austrian) */
+#define SUBLANG_GERMAN_LUXEMBOURG 0x04 /* German (Luxembourg) */
+#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 /* German (Liechtenstein) */
+#define SUBLANG_ITALIAN 0x01 /* Italian */
+#define SUBLANG_ITALIAN_SWISS 0x02 /* Italian (Swiss) */
+#define SUBLANG_KASHMIRI_INDIA 0x02 /* Kashmiri (India) */
+#define SUBLANG_KOREAN 0x01 /* Korean (Extended Wansung) */
+#define SUBLANG_LITHUANIAN 0x01 /* Lithuanian */
+#define SUBLANG_LITHUANIAN_CLASSIC 0x02 /* Lithuanian (Classic) */
+#define SUBLANG_MALAY_MALAYSIA 0x01 /* Malay (Malaysia) */
+#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 /* Malay (Brunei Darussalam) */
+#define SUBLANG_NEPALI_INDIA 0x02 /* Nepali (India) */
+#define SUBLANG_NORWEGIAN_BOKMAL 0x01 /* Norwegian (Bokmal) */
+#define SUBLANG_NORWEGIAN_NYNORSK 0x02 /* Norwegian (Nynorsk) */
+#define SUBLANG_PORTUGUESE 0x02 /* Portuguese */
+#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01 /* Portuguese (Brazilian) */
+#define SUBLANG_SERBIAN_LATIN 0x02 /* Serbian (Latin) */
+#define SUBLANG_SERBIAN_CYRILLIC 0x03 /* Serbian (Cyrillic) */
+#define SUBLANG_SPANISH 0x01 /* Spanish (Castilian) */
+#define SUBLANG_SPANISH_MEXICAN 0x02 /* Spanish (Mexican) */
+#define SUBLANG_SPANISH_MODERN 0x03 /* Spanish (Modern) */
+#define SUBLANG_SPANISH_GUATEMALA 0x04 /* Spanish (Guatemala) */
+#define SUBLANG_SPANISH_COSTA_RICA 0x05 /* Spanish (Costa Rica) */
+#define SUBLANG_SPANISH_PANAMA 0x06 /* Spanish (Panama) */
+#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 /* Spanish (Dom. Republic) */
+#define SUBLANG_SPANISH_VENEZUELA 0x08 /* Spanish (Venezuela) */
+#define SUBLANG_SPANISH_COLOMBIA 0x09 /* Spanish (Colombia) */
+#define SUBLANG_SPANISH_PERU 0x0a /* Spanish (Peru) */
+#define SUBLANG_SPANISH_ARGENTINA 0x0b /* Spanish (Argentina) */
+#define SUBLANG_SPANISH_ECUADOR 0x0c /* Spanish (Ecuador) */
+#define SUBLANG_SPANISH_CHILE 0x0d /* Spanish (Chile) */
+#define SUBLANG_SPANISH_URUGUAY 0x0e /* Spanish (Uruguay) */
+#define SUBLANG_SPANISH_PARAGUAY 0x0f /* Spanish (Paraguay) */
+#define SUBLANG_SPANISH_BOLIVIA 0x10 /* Spanish (Bolivia) */
+#define SUBLANG_SPANISH_EL_SALVADOR 0x11 /* Spanish (El Salvador) */
+#define SUBLANG_SPANISH_HONDURAS 0x12 /* Spanish (Honduras) */
+#define SUBLANG_SPANISH_NICARAGUA 0x13 /* Spanish (Nicaragua) */
+#define SUBLANG_SPANISH_PUERTO_RICO 0x14 /* Spanish (Puerto Rico) */
+#define SUBLANG_SWEDISH 0x01 /* Swedish */
+#define SUBLANG_SWEDISH_FINLAND 0x02 /* Swedish (Finland) */
+#define SUBLANG_URDU_PAKISTAN 0x01 /* Urdu (Pakistan) */
+#define SUBLANG_URDU_INDIA 0x02 /* Urdu (India) */
+#define SUBLANG_UZBEK_LATIN 0x01 /* Uzbek (Latin) */
+#define SUBLANG_UZBEK_CYRILLIC 0x02 /* Uzbek (Cyrillic) */
+
+/*
+ * Sorting IDs.
+ */
+#define SORT_DEFAULT 0x0 /* sorting default */
+
+#define SORT_JAPANESE_XJIS 0x0 /* Japanese XJIS order */
+#define SORT_JAPANESE_UNICODE 0x1 /* Japanese Unicode order */
+
+#define SORT_CHINESE_BIG5 0x0 /* Chinese BIG5 order */
+#define SORT_CHINESE_PRCP 0x0 /* PRC Chinese Phonetic order */
+#define SORT_CHINESE_UNICODE 0x1 /* Chinese Unicode order */
+#define SORT_CHINESE_PRC 0x2 /* PRC Chinese Stroke Count */
+ /* order */
+#define SORT_CHINESE_BOPOMOFO 0x3 /* Traditional Chinese */
+ /* Bopomofo order */
+
+#define SORT_KOREAN_KSC 0x0 /* Korean KSC order */
+#define SORT_KOREAN_UNICODE 0x1 /* Korean Unicode order */
+
+#define SORT_GERMAN_PHONE_BOOK 0x1 /* German Phone Book order */
+
+#define SORT_HUNGARIAN_DEFAULT 0x0 /* Hungarian Default order */
+#define SORT_HUNGARIAN_TECHNICAL 0x1 /* Hungarian Technical order */
+
+#define SORT_GEORGIAN_TRADITIONAL 0x0 /* Georgian Traditional order */
+#define SORT_GEORGIAN_MODERN 0x1 /* Georgian Modern order */
+
+
+/*
+ * A locale ID is a 32 bit value which is the combination of a
+ * language ID, a sort ID, and a reserved area. The bits are
+ * allocated as follows:
+ *
+ * +-------------+---------+-------------------------+
+ * | Reserved | Sort ID | Language ID |
+ * +-------------+---------+-------------------------+
+ * 31 20 19 16 15 0 bit
+ *
+ * Locale ID creation/extraction macros:
+ *
+ * MAKELCID - construct the locale id from a language id
+ * and a sort id.
+ * MAKESORTLCID - construct the locale id from a language id,
+ * sort id, and sort version.
+ * LANGIDFROMLCID - extract the language id from a locale id.
+ * SORTIDFROMLCID - extract the sort id from a locale id.
+ * SORTVERSIONFROMLCID - extract the sort version from a locale id.
+ */
+
+#define NLS_VALID_LOCALE_MASK 0x000fffff
+
+#define MAKELCID(lgid, srtid) \
+ ((DWORD)((((DWORD)((WORD)(srtid))) << 16) | ((DWORD)((WORD)(lgid)))))
+
+#define MAKESORTLCID(lgid, srtid, ver) \
+ ((DWORD)((MAKELCID(lgid, srtid)) | (((DWORD)((WORD)(ver))) << 20)))
+
+#define LANGIDFROMLCID(lcid) ((WORD)(lcid))
+#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf))
+#define SORTVERSIONFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 20) & 0xf))
+
+
+/*
+ * Default System and User IDs for language and locale.
+ */
+#define LANG_SYSTEM_DEFAULT MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT))
+#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT))
+
+#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT))
+#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT))
+
+#define LOCALE_NEUTRAL \
+ (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_NTLOCALE_H */
diff --git a/usr/src/uts/common/smbsrv/ntsid.h b/usr/src/uts/common/smbsrv/ntsid.h
new file mode 100644
index 0000000000..36974ba8fd
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntsid.h
@@ -0,0 +1,304 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NTSID_H
+#define _SMBSRV_NTSID_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Security Identifier (SID) interface definition.
+ */
+
+/*
+ * some kernel include file /usr/include/... is
+ * overriding DWORD and causing conflicts
+ * will investigate further - to be removed
+ */
+
+#ifdef DWORD
+#undef DWORD
+#define DWORD uint32_t
+#endif
+
+#include <smbsrv/wintypes.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Predefined global user RIDs.
+ */
+#define DOMAIN_USER_RID_ADMIN (0x000001F4L) /* 500 */
+#define DOMAIN_USER_RID_GUEST (0x000001F5L) /* 501 */
+#define DOMAIN_USER_RID_KRBTGT (0x000001F6L) /* 502 */
+
+/*
+ * Predefined global group RIDs.
+ */
+#define DOMAIN_GROUP_RID_ADMINS (0x00000200L) /* 512 */
+#define DOMAIN_GROUP_RID_USERS (0x00000201L)
+#define DOMAIN_GROUP_RID_GUESTS (0x00000202L)
+#define DOMAIN_GROUP_RID_COMPUTERS (0x00000203L)
+#define DOMAIN_GROUP_RID_CONTROLLERS (0x00000204L)
+#define DOMAIN_GROUP_RID_CERT_ADMINS (0x00000205L)
+#define DOMAIN_GROUP_RID_SCHEMA_ADMINS (0x00000206L)
+
+
+/*
+ * Predefined local alias RIDs.
+ */
+#define DOMAIN_ALIAS_RID_ADMINS (0x00000220L) /* 544 */
+#define DOMAIN_ALIAS_RID_USERS (0x00000221L)
+#define DOMAIN_ALIAS_RID_GUESTS (0x00000222L)
+#define DOMAIN_ALIAS_RID_POWER_USERS (0x00000223L)
+#define DOMAIN_ALIAS_RID_ACCOUNT_OPS (0x00000224L)
+#define DOMAIN_ALIAS_RID_SYSTEM_OPS (0x00000225L)
+#define DOMAIN_ALIAS_RID_PRINT_OPS (0x00000226L)
+#define DOMAIN_ALIAS_RID_BACKUP_OPS (0x00000227L)
+#define DOMAIN_ALIAS_RID_REPLICATOR (0x00000228L)
+
+
+/*
+ * Universal and NT well-known SIDs
+ */
+#define NT_NULL_SIDSTR "S-1-0-0"
+#define NT_WORLD_SIDSTR "S-1-1-0"
+#define NT_LOCAL_SIDSTR "S-1-2-0"
+#define NT_CREATOR_OWNER_ID_SIDSTR "S-1-3-0"
+#define NT_CREATOR_GROUP_ID_SIDSTR "S-1-3-1"
+#define NT_CREATOR_OWNER_SERVER_ID_SIDSTR "S-1-3-2"
+#define NT_CREATOR_GROUP_SERVER_ID_SIDSTR "S-1-3-3"
+#define NT_NON_UNIQUE_IDS_SIDSTR "S-1-4"
+#define NT_AUTHORITY_SIDSTR "S-1-5"
+#define NT_DIALUP_SIDSTR "S-1-5-1"
+#define NT_NETWORK_SIDSTR "S-1-5-2"
+#define NT_BATCH_SIDSTR "S-1-5-3"
+#define NT_INTERACTIVE_SIDSTR "S-1-5-4"
+#define NT_SERVICE_SIDSTR "S-1-5-6"
+#define NT_ANONYMOUS_LOGON_SIDSTR "S-1-5-7"
+#define NT_PROXY_SIDSTR "S-1-5-8"
+#define NT_SERVER_LOGON_SIDSTR "S-1-5-9"
+#define NT_SELF_SIDSTR "S-1-5-10"
+#define NT_AUTHENTICATED_USER_SIDSTR "S-1-5-11"
+#define NT_RESTRICTED_CODE_SIDSTR "S-1-5-12"
+#define NT_LOCAL_SYSTEM_SIDSTR "S-1-5-18"
+#define NT_NON_UNIQUE_SIDSTR "S-1-5-21"
+#define NT_BUILTIN_DOMAIN_SIDSTR "S-1-5-32"
+
+
+/*
+ * SID type indicators (SID_NAME_USE).
+ */
+#define SidTypeNull 0
+#define SidTypeUser 1
+#define SidTypeGroup 2
+#define SidTypeDomain 3
+#define SidTypeAlias 4
+#define SidTypeWellKnownGroup 5
+#define SidTypeDeletedAccount 6
+#define SidTypeInvalid 7
+#define SidTypeUnknown 8
+#define SidTypeComputer 9
+
+
+/*
+ * Identifier authorities for various domains.
+ */
+#define NT_SID_NULL_AUTH 0
+#define NT_SID_WORLD_AUTH 1
+#define NT_SID_LOCAL_AUTH 2
+#define NT_SID_CREATOR_AUTH 3
+#define NT_SID_NON_UNIQUE_AUTH 4
+#define NT_SID_NT_AUTH 5
+
+
+#define NT_SECURITY_NULL_AUTH {0, 0, 0, 0, 0, 0}
+#define NT_SECURITY_WORLD_AUTH {0, 0, 0, 0, 0, 1}
+#define NT_SECURITY_LOCAL_AUTH {0, 0, 0, 0, 0, 2}
+#define NT_SECURITY_CREATOR_AUTH {0, 0, 0, 0, 0, 3}
+#define NT_SECURITY_NON_UNIQUE_AUTH {0, 0, 0, 0, 0, 4}
+#define NT_SECURITY_NT_AUTH {0, 0, 0, 0, 0, 5}
+#define NT_SECURITY_UNIX_AUTH {0, 0, 0, 0, 0, 99}
+
+
+#define SECURITY_NULL_RID (0x00000000L)
+#define SECURITY_WORLD_RID (0x00000000L)
+#define SECURITY_LOCAL_RID (0X00000000L)
+
+#define SECURITY_CREATOR_OWNER_RID (0x00000000L)
+#define SECURITY_CREATOR_GROUP_RID (0x00000001L)
+#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L)
+#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L)
+
+#define SECURITY_DIALUP_RID (0x00000001L)
+#define SECURITY_NETWORK_RID (0x00000002L)
+#define SECURITY_BATCH_RID (0x00000003L)
+#define SECURITY_INTERACTIVE_RID (0x00000004L)
+#define SECURITY_LOGON_IDS_RID (0x00000005L)
+#define SECURITY_LOGON_IDS_RID_COUNT (3L)
+#define SECURITY_SERVICE_RID (0x00000006L)
+#define SECURITY_ANONYMOUS_LOGON_RID (0x00000007L)
+#define SECURITY_PROXY_RID (0x00000008L)
+#define SECURITY_ENTERPRISE_CONTROLLERS_RID (0x00000009L)
+#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID
+#define SECURITY_PRINCIPAL_SELF_RID (0x0000000AL)
+#define SECURITY_AUTHENTICATED_USER_RID (0x0000000BL)
+#define SECURITY_RESTRICTED_CODE_RID (0x0000000CL)
+
+#define SECURITY_LOCAL_SYSTEM_RID (0x00000012L)
+#define SECURITY_NT_NON_UNIQUE (0x00000015L)
+#define SECURITY_BUILTIN_DOMAIN_RID (0x00000020L)
+
+
+#define NT_SID_NON_UNIQUE_SUBAUTH 21
+
+
+/*
+ * Common definition for a SID.
+ */
+#define NT_SID_REVISION 1
+#define NT_SID_AUTH_MAX 6
+#define NT_SID_SUBAUTH_MAX 15
+
+
+/*
+ * Security Identifier (SID)
+ *
+ * The security identifier (SID) uniquely identifies a user, group or
+ * a domain. It consists of a revision number, the identifier authority,
+ * and a list of sub-authorities. The revision number is currently 1.
+ * The identifier authority identifies which system issued the SID. The
+ * sub-authorities of a domain SID uniquely identify a domain. A user
+ * or group SID consists of a domain SID with the user or group id
+ * appended. The user or group id (also known as a relative id (RID)
+ * uniquely identifies a user within a domain. A user or group SID
+ * uniquely identifies a user or group across all domains. The SidType
+ * values identify the various types of SID.
+ *
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------------------------------------------------------+
+ * | SubAuthorityCount |Reserved1 (SBZ)| Revision |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[0] |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[1] |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[2] |
+ * +---------------------------------------------------------------+
+ * | |
+ * +- - - - - - - - SubAuthority[] - - - - - - - - -+
+ * | |
+ * +---------------------------------------------------------------+
+ *
+ */
+/*
+ * Note: NT defines the Identifier Authority as a separate
+ * structure (SID_IDENTIFIER_AUTHORITY) containing a literal
+ * definition of a 6 byte vector but the effect is the same
+ * as defining it as a member value.
+ */
+typedef struct nt_sid {
+ BYTE Revision;
+ BYTE SubAuthCount;
+ BYTE Authority[NT_SID_AUTH_MAX];
+ DWORD SubAuthority[ANY_SIZE_ARRAY];
+} nt_sid_t;
+
+/*
+ * The structure for entries in a static table of well known
+ * SIDs. The table definition is in os/libnt/ntbuitin.c
+ * The domain_ix field is an index into a predefined domain
+ * list in os/libnt/ntbuitin.c
+ */
+typedef struct well_known_account {
+ WORD sid_name_use;
+ WORD domain_ix; /* index to a predefine domain list */
+ char *sid;
+ char *name;
+ WORD flags;
+ char *desc;
+ nt_sid_t *binsid;
+} well_known_account_t;
+
+/*
+ * flags for local group table entry
+ *
+ * LGF_HIDDEN this entry won't be represented to users
+ * via builtin group management interface
+ */
+#define LGF_HIDDEN 0x1
+
+
+/*
+ * The maximum size of the SID format buffer.
+ */
+#define NT_SID_FMTBUF_SIZE 256
+
+
+int nt_sid_is_valid(nt_sid_t *sid);
+int nt_sid_length(nt_sid_t *sid);
+nt_sid_t *nt_sid_dup(nt_sid_t *sid);
+nt_sid_t *nt_sid_splice(nt_sid_t *domain_sid, DWORD rid);
+int nt_sid_get_rid(nt_sid_t *sid, DWORD *rid);
+int nt_sid_split(nt_sid_t *sid, DWORD *rid);
+nt_sid_t *nt_sid_gen_null_sid(void);
+int nt_sid_domain_equal(nt_sid_t *domain_sid, nt_sid_t *sid);
+int nt_sid_is_equal(nt_sid_t *sid1, nt_sid_t *sid2);
+int nt_sid_is_local(nt_sid_t *sid);
+int nt_sid_is_builtin(nt_sid_t *sid);
+int nt_sid_is_domain_equal(nt_sid_t *sid1, nt_sid_t *sid2);
+int nt_sid_is_indomain(nt_sid_t *domain_sid, nt_sid_t *sid);
+void nt_sid_logf(nt_sid_t *sid);
+char *nt_sid_format(nt_sid_t *sid);
+void nt_sid_format2(nt_sid_t *sid, char *fmtbuf);
+nt_sid_t *nt_sid_strtosid(char *sidstr);
+char *nt_sid_name_use(unsigned int snu_id);
+int nt_sid_copy(nt_sid_t *dessid, nt_sid_t *srcsid, unsigned buflen);
+
+
+/*
+ * SID/name translation service for NT BUILTIN SIDs.
+ */
+int nt_builtin_init(void);
+void nt_builtin_fini(void);
+well_known_account_t *nt_builtin_lookup(char *name);
+char *nt_builtin_lookup_sid(nt_sid_t *sid, WORD *sid_name_use);
+nt_sid_t *nt_builtin_lookup_name(char *name, WORD *sid_name_use);
+char *nt_builtin_lookup_domain(char *name);
+int nt_builtin_is_wellknown(char *name);
+well_known_account_t *nt_builtin_findfirst(DWORD *iterator);
+well_known_account_t *nt_builtin_findnext(DWORD *iterator);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NTSID_H */
diff --git a/usr/src/uts/common/smbsrv/ntstatus.h b/usr/src/uts/common/smbsrv/ntstatus.h
new file mode 100644
index 0000000000..1388dcfcc2
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/ntstatus.h
@@ -0,0 +1,595 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_NTSTATUS_H
+#define _SMBSRV_NTSTATUS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines the list of NT status codes.
+ *
+ * Be careful not to confuse status codes with error
+ * codes. The error codes are listed in nterror.h.
+ */
+
+#include <smbsrv/wintypes.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Status codes are 32-bit values in which the top 2 bits represent
+ * the severity and the lower 16-bits contain a Win32 status code.
+ * The severity levels are:
+ *
+ * 00 success
+ * 01 information
+ * 10 warning
+ * 11 error
+ *
+ * NT also defines an application mask, which is included here
+ * for completeness.
+ */
+#define APPLICATION_ERROR_MASK 0x20000000
+#define ERROR_SEVERITY_SUCCESS 0x00000000
+#define ERROR_SEVERITY_INFORMATIONAL 0x40000000
+#define ERROR_SEVERITY_WARNING 0x80000000
+#define ERROR_SEVERITY_ERROR 0xC0000000
+
+/*
+ * Severity code helper macros.
+ */
+#define NT_SC_SUCCESS(STATUS) (ERROR_SEVERITY_SUCCESS+(STATUS))
+#define NT_SC_INFO(STATUS) (ERROR_SEVERITY_INFORMATIONAL+(STATUS))
+#define NT_SC_WARNING(STATUS) (ERROR_SEVERITY_WARNING+(STATUS))
+#define NT_SC_ERROR(STATUS) (ERROR_SEVERITY_ERROR+(STATUS))
+
+#define NT_SC_IS_SUCCESS(S) (((S) & 0xC0000000) == ERROR_SEVERITY_SUCCESS)
+#define NT_SC_IS_INFO(S) (((S) & 0xC0000000) == ERROR_SEVERITY_INFORMATIONAL)
+#define NT_SC_IS_WARNING(S) (((S) & 0xC0000000) == ERROR_SEVERITY_WARNING)
+#define NT_SC_IS_ERROR(S) (((S) & 0xC0000000) == ERROR_SEVERITY_ERROR)
+
+#define NT_SC_VALUE(S) ((S) & 0x0FFFFFFF)
+
+/*
+ * Win32 status codes
+ */
+#define NT_STATUS_SUCCESS 0
+#define NT_STATUS_UNSUCCESSFUL 1
+#define NT_STATUS_NOT_IMPLEMENTED 2
+#define NT_STATUS_INVALID_INFO_CLASS 3
+#define NT_STATUS_INFO_LENGTH_MISMATCH 4
+#define NT_STATUS_BUFFER_OVERFLOW 5
+/* NT_STATUS_IN_PAGE_ERROR */
+#define NT_STATUS_NO_MORE_FILES 6
+#define NT_STATUS_PAGEFILE_QUOTA 7
+#define NT_STATUS_INVALID_HANDLE 8
+#define NT_STATUS_BAD_INITIAL_STACK 9
+#define NT_STATUS_BAD_INITIAL_PC 10
+#define NT_STATUS_INVALID_CID 11
+#define NT_STATUS_TIMER_NOT_CANCELED 12
+#define NT_STATUS_INVALID_PARAMETER 13
+#define NT_STATUS_NO_SUCH_DEVICE 14
+#define NT_STATUS_NO_SUCH_FILE 15
+#define NT_STATUS_INVALID_DEVICE_REQUEST 16
+#define NT_STATUS_END_OF_FILE 17
+#define NT_STATUS_WRONG_VOLUME 18
+#define NT_STATUS_NO_MEDIA_IN_DEVICE 19
+#define NT_STATUS_UNRECOGNIZED_MEDIA 20
+#define NT_STATUS_NONEXISTENT_SECTOR 21
+#define NT_STATUS_MORE_PROCESSING_REQUIRED 22
+#define NT_STATUS_NO_MEMORY 23
+#define NT_STATUS_CONFLICTING_ADDRESSES 24
+#define NT_STATUS_NOT_MAPPED_VIEW 25
+#define NT_STATUS_UNABLE_TO_FREE_VM 26
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION 27
+#define NT_STATUS_INVALID_SYSTEM_SERVICE 28
+#define NT_STATUS_ILLEGAL_INSTRUCTION 29
+#define NT_STATUS_INVALID_LOCK_SEQUENCE 30
+#define NT_STATUS_INVALID_VIEW_SIZE 31
+#define NT_STATUS_INVALID_FILE_FOR_SECTION 32
+#define NT_STATUS_ALREADY_COMMITTED 33
+#define NT_STATUS_ACCESS_DENIED 34
+#define NT_STATUS_BUFFER_TOO_SMALL 35
+#define NT_STATUS_OBJECT_TYPE_MISMATCH 36
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION 37
+#define NT_STATUS_INVALID_DISPOSITION 38
+#define NT_STATUS_UNWIND 39
+#define NT_STATUS_BAD_STACK 40
+#define NT_STATUS_INVALID_UNWIND_TARGET 41
+#define NT_STATUS_NOT_LOCKED 42
+#define NT_STATUS_PARITY_ERROR 43
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 44
+#define NT_STATUS_NOT_COMMITTED 45
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES 46
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG 47
+#define NT_STATUS_INVALID_PARAMETER_MIX 48
+#define NT_STATUS_INVALID_QUOTA_LOWER 49
+#define NT_STATUS_DISK_CORRUPT_ERROR 50
+#define NT_STATUS_OBJECT_NAME_INVALID 51
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND 52
+#define NT_STATUS_OBJECT_NAME_COLLISION 53
+#define NT_STATUS_HANDLE_NOT_WAITABLE 54
+#define NT_STATUS_PORT_DISCONNECTED 55
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED 56
+#define NT_STATUS_OBJECT_PATH_INVALID 57
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND 58
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 59
+#define NT_STATUS_DATA_OVERRUN 60
+#define NT_STATUS_DATA_LATE_ERROR 61
+#define NT_STATUS_DATA_ERROR 62
+#define NT_STATUS_CRC_ERROR 63
+#define NT_STATUS_SECTION_TOO_BIG 64
+#define NT_STATUS_PORT_CONNECTION_REFUSED 65
+#define NT_STATUS_INVALID_PORT_HANDLE 66
+#define NT_STATUS_SHARING_VIOLATION 67
+#define NT_STATUS_QUOTA_EXCEEDED 68
+#define NT_STATUS_INVALID_PAGE_PROTECTION 69
+#define NT_STATUS_MUTANT_NOT_OWNED 70
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 71
+#define NT_STATUS_PORT_ALREADY_SET 72
+#define NT_STATUS_SECTION_NOT_IMAGE 73
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 74
+#define NT_STATUS_THREAD_IS_TERMINATING 75
+#define NT_STATUS_BAD_WORKING_SET_LIMIT 76
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP 77
+#define NT_STATUS_SECTION_PROTECTION 78
+#define NT_STATUS_EAS_NOT_SUPPORTED 79
+#define NT_STATUS_EA_TOO_LARGE 80
+#define NT_STATUS_NONEXISTENT_EA_ENTRY 81
+#define NT_STATUS_NO_EAS_ON_FILE 82
+#define NT_STATUS_EA_CORRUPT_ERROR 83
+#define NT_STATUS_FILE_LOCK_CONFLICT 84
+#define NT_STATUS_LOCK_NOT_GRANTED 85
+#define NT_STATUS_DELETE_PENDING 86
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 87
+#define NT_STATUS_UNKNOWN_REVISION 88
+#define NT_STATUS_REVISION_MISMATCH 89
+#define NT_STATUS_INVALID_OWNER 90
+#define NT_STATUS_INVALID_PRIMARY_GROUP 91
+#define NT_STATUS_NO_IMPERSONATION_TOKEN 92
+#define NT_STATUS_CANT_DISABLE_MANDATORY 93
+#define NT_STATUS_NO_LOGON_SERVERS 94
+#define NT_STATUS_NO_SUCH_LOGON_SESSION 95
+#define NT_STATUS_NO_SUCH_PRIVILEGE 96
+#define NT_STATUS_PRIVILEGE_NOT_HELD 97
+#define NT_STATUS_INVALID_ACCOUNT_NAME 98
+#define NT_STATUS_USER_EXISTS 99
+#define NT_STATUS_NO_SUCH_USER 100
+#define NT_STATUS_GROUP_EXISTS 101
+#define NT_STATUS_NO_SUCH_GROUP 102
+#define NT_STATUS_MEMBER_IN_GROUP 103
+#define NT_STATUS_MEMBER_NOT_IN_GROUP 104
+#define NT_STATUS_LAST_ADMIN 105
+#define NT_STATUS_WRONG_PASSWORD 106
+#define NT_STATUS_ILL_FORMED_PASSWORD 107
+#define NT_STATUS_PASSWORD_RESTRICTION 108
+#define NT_STATUS_LOGON_FAILURE 109
+#define NT_STATUS_ACCOUNT_RESTRICTION 110
+#define NT_STATUS_INVALID_LOGON_HOURS 111
+#define NT_STATUS_INVALID_WORKSTATION 112
+#define NT_STATUS_PASSWORD_EXPIRED 113
+#define NT_STATUS_ACCOUNT_DISABLED 114
+#define NT_STATUS_NONE_MAPPED 115
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 116
+#define NT_STATUS_LUIDS_EXHAUSTED 117
+#define NT_STATUS_INVALID_SUB_AUTHORITY 118
+#define NT_STATUS_INVALID_ACL 119
+#define NT_STATUS_INVALID_SID 120
+#define NT_STATUS_INVALID_SECURITY_DESCR 121
+#define NT_STATUS_PROCEDURE_NOT_FOUND 122
+#define NT_STATUS_INVALID_IMAGE_FORMAT 123
+#define NT_STATUS_NO_TOKEN 124
+#define NT_STATUS_BAD_INHERITANCE_ACL 125
+#define NT_STATUS_RANGE_NOT_LOCKED 126
+#define NT_STATUS_DISK_FULL 127
+#define NT_STATUS_SERVER_DISABLED 128
+#define NT_STATUS_SERVER_NOT_DISABLED 129
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 130
+#define NT_STATUS_GUIDS_EXHAUSTED 131
+#define NT_STATUS_INVALID_ID_AUTHORITY 132
+#define NT_STATUS_AGENTS_EXHAUSTED 133
+#define NT_STATUS_INVALID_VOLUME_LABEL 134
+#define NT_STATUS_SECTION_NOT_EXTENDED 135
+#define NT_STATUS_NOT_MAPPED_DATA 136
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 137
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 138
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 139
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 140
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND 141
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 142
+#define NT_STATUS_FLOAT_INEXACT_RESULT 143
+#define NT_STATUS_FLOAT_INVALID_OPERATION 144
+#define NT_STATUS_FLOAT_OVERFLOW 145
+#define NT_STATUS_FLOAT_STACK_CHECK 146
+#define NT_STATUS_FLOAT_UNDERFLOW 147
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 148
+#define NT_STATUS_INTEGER_OVERFLOW 149
+#define NT_STATUS_PRIVILEGED_INSTRUCTION 150
+#define NT_STATUS_TOO_MANY_PAGING_FILES 151
+#define NT_STATUS_FILE_INVALID 152
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 153
+#define NT_STATUS_INSUFFICIENT_RESOURCES 154
+#define NT_STATUS_DFS_EXIT_PATH_FOUND 155
+#define NT_STATUS_DEVICE_DATA_ERROR 156
+#define NT_STATUS_DEVICE_NOT_CONNECTED 157
+#define NT_STATUS_DEVICE_POWER_FAILURE 158
+#define NT_STATUS_FREE_VM_NOT_AT_BASE 159
+#define NT_STATUS_MEMORY_NOT_ALLOCATED 160
+#define NT_STATUS_WORKING_SET_QUOTA 161
+#define NT_STATUS_MEDIA_WRITE_PROTECTED 162
+#define NT_STATUS_DEVICE_NOT_READY 163
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 164
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL 165
+#define NT_STATUS_CANT_OPEN_ANONYMOUS 166
+#define NT_STATUS_BAD_VALIDATION_CLASS 167
+#define NT_STATUS_BAD_TOKEN_TYPE 168
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD 169
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT 170
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE 171
+#define NT_STATUS_PIPE_NOT_AVAILABLE 172
+#define NT_STATUS_INVALID_PIPE_STATE 173
+#define NT_STATUS_PIPE_BUSY 174
+#define NT_STATUS_ILLEGAL_FUNCTION 175
+#define NT_STATUS_PIPE_DISCONNECTED 176
+#define NT_STATUS_PIPE_CLOSING 177
+#define NT_STATUS_PIPE_CONNECTED 178
+#define NT_STATUS_PIPE_LISTENING 179
+#define NT_STATUS_INVALID_READ_MODE 180
+#define NT_STATUS_IO_TIMEOUT 181
+#define NT_STATUS_FILE_FORCED_CLOSED 182
+#define NT_STATUS_PROFILING_NOT_STARTED 183
+#define NT_STATUS_PROFILING_NOT_STOPPED 184
+#define NT_STATUS_COULD_NOT_INTERPRET 185
+#define NT_STATUS_FILE_IS_A_DIRECTORY 186
+#define NT_STATUS_NOT_SUPPORTED 187
+#define NT_STATUS_REMOTE_NOT_LISTENING 188
+#define NT_STATUS_DUPLICATE_NAME 189
+#define NT_STATUS_BAD_NETWORK_PATH 190
+#define NT_STATUS_NETWORK_BUSY 191
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST 192
+#define NT_STATUS_TOO_MANY_COMMANDS 193
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR 194
+#define NT_STATUS_INVALID_NETWORK_RESPONSE 195
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 196
+#define NT_STATUS_BAD_REMOTE_ADAPTER 197
+#define NT_STATUS_PRINT_QUEUE_FULL 198
+#define NT_STATUS_NO_SPOOL_SPACE 199
+#define NT_STATUS_PRINT_CANCELLED 200
+#define NT_STATUS_NETWORK_NAME_DELETED 201
+#define NT_STATUS_NETWORK_ACCESS_DENIED 202
+#define NT_STATUS_BAD_DEVICE_TYPE 203
+#define NT_STATUS_BAD_NETWORK_NAME 204
+#define NT_STATUS_TOO_MANY_NAMES 205
+#define NT_STATUS_TOO_MANY_SESSIONS 206
+#define NT_STATUS_SHARING_PAUSED 207
+#define NT_STATUS_REQUEST_NOT_ACCEPTED 208
+#define NT_STATUS_REDIRECTOR_PAUSED 209
+#define NT_STATUS_NET_WRITE_FAULT 210
+#define NT_STATUS_PROFILING_AT_LIMIT 211
+#define NT_STATUS_NOT_SAME_DEVICE 212
+#define NT_STATUS_FILE_RENAMED 213
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 214
+#define NT_STATUS_NO_SECURITY_ON_OBJECT 215
+#define NT_STATUS_CANT_WAIT 216
+#define NT_STATUS_PIPE_EMPTY 217
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 218
+#define NT_STATUS_CANT_TERMINATE_SELF 219
+#define NT_STATUS_INVALID_SERVER_STATE 220
+#define NT_STATUS_INVALID_DOMAIN_STATE 221
+#define NT_STATUS_INVALID_DOMAIN_ROLE 222
+#define NT_STATUS_NO_SUCH_DOMAIN 223
+#define NT_STATUS_DOMAIN_EXISTS 224
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 225
+#define NT_STATUS_OPLOCK_NOT_GRANTED 226
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 227
+#define NT_STATUS_INTERNAL_DB_CORRUPTION 228
+#define NT_STATUS_INTERNAL_ERROR 229
+#define NT_STATUS_GENERIC_NOT_MAPPED 230
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 231
+#define NT_STATUS_INVALID_USER_BUFFER 232
+#define NT_STATUS_UNEXPECTED_IO_ERROR 233
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 234
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 235
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 236
+#define NT_STATUS_NOT_LOGON_PROCESS 237
+#define NT_STATUS_LOGON_SESSION_EXISTS 238
+#define NT_STATUS_INVALID_PARAMETER_1 239
+#define NT_STATUS_INVALID_PARAMETER_2 240
+#define NT_STATUS_INVALID_PARAMETER_3 241
+#define NT_STATUS_INVALID_PARAMETER_4 242
+#define NT_STATUS_INVALID_PARAMETER_5 243
+#define NT_STATUS_INVALID_PARAMETER_6 244
+#define NT_STATUS_INVALID_PARAMETER_7 245
+#define NT_STATUS_INVALID_PARAMETER_8 246
+#define NT_STATUS_INVALID_PARAMETER_9 247
+#define NT_STATUS_INVALID_PARAMETER_10 248
+#define NT_STATUS_INVALID_PARAMETER_11 249
+#define NT_STATUS_INVALID_PARAMETER_12 250
+#define NT_STATUS_REDIRECTOR_NOT_STARTED 251
+#define NT_STATUS_REDIRECTOR_STARTED 252
+#define NT_STATUS_STACK_OVERFLOW 253
+#define NT_STATUS_NO_SUCH_PACKAGE 254
+#define NT_STATUS_BAD_FUNCTION_TABLE 255
+#define NT_STATUS_DIRECTORY_NOT_EMPTY 257
+#define NT_STATUS_FILE_CORRUPT_ERROR 258
+#define NT_STATUS_NOT_A_DIRECTORY 259
+#define NT_STATUS_BAD_LOGON_SESSION_STATE 260
+#define NT_STATUS_LOGON_SESSION_COLLISION 261
+#define NT_STATUS_NAME_TOO_LONG 262
+#define NT_STATUS_FILES_OPEN 263
+#define NT_STATUS_CONNECTION_IN_USE 264
+#define NT_STATUS_MESSAGE_NOT_FOUND 265
+#define NT_STATUS_PROCESS_IS_TERMINATING 266
+#define NT_STATUS_INVALID_LOGON_TYPE 267
+#define NT_STATUS_NO_GUID_TRANSLATION 268
+#define NT_STATUS_CANNOT_IMPERSONATE 269
+#define NT_STATUS_IMAGE_ALREADY_LOADED 270
+#define NT_STATUS_ABIOS_NOT_PRESENT 271
+#define NT_STATUS_ABIOS_LID_NOT_EXIST 272
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 273
+#define NT_STATUS_ABIOS_NOT_LID_OWNER 274
+#define NT_STATUS_ABIOS_INVALID_COMMAND 275
+#define NT_STATUS_ABIOS_INVALID_LID 276
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 277
+#define NT_STATUS_ABIOS_INVALID_SELECTOR 278
+#define NT_STATUS_NO_LDT 279
+#define NT_STATUS_INVALID_LDT_SIZE 280
+#define NT_STATUS_INVALID_LDT_OFFSET 281
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR 282
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 283
+#define NT_STATUS_RXACT_INVALID_STATE 284
+#define NT_STATUS_RXACT_COMMIT_FAILURE 285
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 286
+#define NT_STATUS_TOO_MANY_OPENED_FILES 287
+#define NT_STATUS_CANCELLED 288
+#define NT_STATUS_CANNOT_DELETE 289
+#define NT_STATUS_INVALID_COMPUTER_NAME 290
+#define NT_STATUS_FILE_DELETED 291
+#define NT_STATUS_SPECIAL_ACCOUNT 292
+#define NT_STATUS_SPECIAL_GROUP 293
+#define NT_STATUS_SPECIAL_USER 294
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP 295
+#define NT_STATUS_FILE_CLOSED 296
+#define NT_STATUS_TOO_MANY_THREADS 297
+#define NT_STATUS_THREAD_NOT_IN_PROCESS 298
+#define NT_STATUS_TOKEN_ALREADY_IN_USE 299
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 300
+#define NT_STATUS_COMMITMENT_LIMIT 301
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 302
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ 303
+#define NT_STATUS_INVALID_IMAGE_PROTECT 304
+#define NT_STATUS_INVALID_IMAGE_WIN_16 305
+#define NT_STATUS_LOGON_SERVER_CONFLICT 306
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC 307
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED 308
+#define NT_STATUS_DLL_NOT_FOUND 309
+#define NT_STATUS_OPEN_FAILED 310
+#define NT_STATUS_IO_PRIVILEGE_FAILED 311
+#define NT_STATUS_ORDINAL_NOT_FOUND 312
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND 313
+#define NT_STATUS_CONTROL_C_EXIT 314
+#define NT_STATUS_LOCAL_DISCONNECT 315
+#define NT_STATUS_REMOTE_DISCONNECT 316
+#define NT_STATUS_REMOTE_RESOURCES 317
+#define NT_STATUS_LINK_FAILED 318
+#define NT_STATUS_LINK_TIMEOUT 319
+#define NT_STATUS_INVALID_CONNECTION 320
+#define NT_STATUS_INVALID_ADDRESS 321
+#define NT_STATUS_DLL_INIT_FAILED 322
+#define NT_STATUS_MISSING_SYSTEMFILE 323
+#define NT_STATUS_UNHANDLED_EXCEPTION 324
+#define NT_STATUS_APP_INIT_FAILURE 325
+#define NT_STATUS_PAGEFILE_CREATE_FAILED 326
+#define NT_STATUS_NO_PAGEFILE 327
+#define NT_STATUS_INVALID_LEVEL 328
+#define NT_STATUS_WRONG_PASSWORD_CORE 329
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 330
+#define NT_STATUS_PIPE_BROKEN 331
+#define NT_STATUS_REGISTRY_CORRUPT 332
+#define NT_STATUS_REGISTRY_IO_FAILED 333
+#define NT_STATUS_NO_EVENT_PAIR 334
+#define NT_STATUS_UNRECOGNIZED_VOLUME 335
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED 336
+#define NT_STATUS_NO_SUCH_ALIAS 337
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS 338
+#define NT_STATUS_MEMBER_IN_ALIAS 339
+#define NT_STATUS_ALIAS_EXISTS 340
+#define NT_STATUS_LOGON_NOT_GRANTED 341
+#define NT_STATUS_TOO_MANY_SECRETS 342
+#define NT_STATUS_SECRET_TOO_LONG 343
+#define NT_STATUS_INTERNAL_DB_ERROR 344
+#define NT_STATUS_FULLSCREEN_MODE 345
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS 346
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 347
+#define NT_STATUS_NOT_REGISTRY_FILE 348
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 349
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 350
+#define NT_STATUS_FT_MISSING_MEMBER 351
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 352
+#define NT_STATUS_ILLEGAL_CHARACTER 353
+#define NT_STATUS_UNMAPPABLE_CHARACTER 354
+#define NT_STATUS_UNDEFINED_CHARACTER 355
+#define NT_STATUS_FLOPPY_VOLUME 356
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 357
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER 358
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 359
+#define NT_STATUS_FLOPPY_BAD_REGISTERS 360
+#define NT_STATUS_DISK_RECALIBRATE_FAILED 361
+#define NT_STATUS_DISK_OPERATION_FAILED 362
+#define NT_STATUS_DISK_RESET_FAILED 363
+#define NT_STATUS_SHARED_IRQ_BUSY 364
+#define NT_STATUS_FT_ORPHANING 365
+#define NT_STATUS_PARTITION_FAILURE 370
+#define NT_STATUS_INVALID_BLOCK_LENGTH 371
+#define NT_STATUS_DEVICE_NOT_PARTITIONED 372
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 373
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 374
+#define NT_STATUS_EOM_OVERFLOW 375
+#define NT_STATUS_NO_MEDIA 376
+#define NT_STATUS_NO_SUCH_MEMBER 378
+#define NT_STATUS_INVALID_MEMBER 379
+#define NT_STATUS_KEY_DELETED 380
+#define NT_STATUS_NO_LOG_SPACE 381
+#define NT_STATUS_TOO_MANY_SIDS 382
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 383
+#define NT_STATUS_KEY_HAS_CHILDREN 384
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE 385
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 386
+#define NT_STATUS_DRIVER_INTERNAL_ERROR 387
+#define NT_STATUS_INVALID_DEVICE_STATE 388
+#define NT_STATUS_IO_DEVICE_ERROR 389
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR 390
+#define NT_STATUS_BACKUP_CONTROLLER 391
+#define NT_STATUS_LOG_FILE_FULL 392
+#define NT_STATUS_TOO_LATE 393
+#define NT_STATUS_NO_TRUST_LSA_SECRET 394
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 395
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 396
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 397
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT 398
+#define NT_STATUS_EVENTLOG_CANT_START 399
+#define NT_STATUS_TRUST_FAILURE 400
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 401
+#define NT_STATUS_NETLOGON_NOT_STARTED 402
+#define NT_STATUS_ACCOUNT_EXPIRED 403
+#define NT_STATUS_POSSIBLE_DEADLOCK 404
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 405
+#define NT_STATUS_REMOTE_SESSION_LIMIT 406
+#define NT_STATUS_EVENTLOG_FILE_CHANGED 407
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 408
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 409
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 410
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 411
+#define NT_STATUS_FS_DRIVER_REQUIRED 412
+#define NT_STATUS_NO_USER_SESSION_KEY 514
+#define NT_STATUS_USER_SESSION_DELETED 515
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 516
+#define NT_STATUS_INSUFF_SERVER_RESOURCES 517
+#define NT_STATUS_INVALID_BUFFER_SIZE 518
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT 519
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD 520
+#define NT_STATUS_TOO_MANY_ADDRESSES 521
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS 522
+#define NT_STATUS_ADDRESS_CLOSED 523
+#define NT_STATUS_CONNECTION_DISCONNECTED 524
+#define NT_STATUS_CONNECTION_RESET 525
+#define NT_STATUS_TOO_MANY_NODES 526
+#define NT_STATUS_TRANSACTION_ABORTED 527
+#define NT_STATUS_TRANSACTION_TIMED_OUT 528
+#define NT_STATUS_TRANSACTION_NO_RELEASE 529
+#define NT_STATUS_TRANSACTION_NO_MATCH 530
+#define NT_STATUS_TRANSACTION_RESPONDED 531
+#define NT_STATUS_TRANSACTION_INVALID_ID 532
+#define NT_STATUS_TRANSACTION_INVALID_TYPE 533
+#define NT_STATUS_NOT_SERVER_SESSION 534
+#define NT_STATUS_NOT_CLIENT_SESSION 535
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 536
+#define NT_STATUS_DEBUG_ATTACH_FAILED 537
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 538
+#define NT_STATUS_DATA_NOT_ACCEPTED 539
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 540
+#define NT_STATUS_VDM_HARD_ERROR 541
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 542
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH 543
+#define NT_STATUS_MAPPED_ALIGNMENT 544
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 545
+#define NT_STATUS_LOST_WRITEBEHIND_DATA 546
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 547
+#define NT_STATUS_PASSWORD_MUST_CHANGE 548
+#define NT_STATUS_NOT_FOUND 549
+#define NT_STATUS_NOT_TINY_STREAM 550
+#define NT_STATUS_RECOVERY_FAILURE 551
+#define NT_STATUS_STACK_OVERFLOW_READ 552
+#define NT_STATUS_FAIL_CHECK 553
+#define NT_STATUS_DUPLICATE_OBJECTID 554
+#define NT_STATUS_OBJECTID_EXISTS 555
+#define NT_STATUS_CONVERT_TO_LARGE 556
+#define NT_STATUS_RETRY 557
+#define NT_STATUS_FOUND_OUT_OF_SCOPE 558
+#define NT_STATUS_ALLOCATE_BUCKET 559
+#define NT_STATUS_PROPSET_NOT_FOUND 560
+#define NT_STATUS_MARSHALL_OVERFLOW 561
+#define NT_STATUS_INVALID_VARIANT 562
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 563
+#define NT_STATUS_ACCOUNT_LOCKED_OUT 564
+#define NT_STATUS_HANDLE_NOT_CLOSABLE 565
+#define NT_STATUS_CONNECTION_REFUSED 566
+#define NT_STATUS_GRACEFUL_DISCONNECT 567
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 568
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 569
+#define NT_STATUS_CONNECTION_INVALID 570
+#define NT_STATUS_CONNECTION_ACTIVE 571
+#define NT_STATUS_NETWORK_UNREACHABLE 572
+#define NT_STATUS_HOST_UNREACHABLE 573
+#define NT_STATUS_PROTOCOL_UNREACHABLE 574
+#define NT_STATUS_PORT_UNREACHABLE 575
+#define NT_STATUS_REQUEST_ABORTED 576
+#define NT_STATUS_CONNECTION_ABORTED 577
+#define NT_STATUS_BAD_COMPRESSION_BUFFER 578
+#define NT_STATUS_USER_MAPPED_FILE 579
+#define NT_STATUS_AUDIT_FAILED 580
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 581
+#define NT_STATUS_CONNECTION_COUNT_LIMIT 582
+#define NT_STATUS_LOGIN_TIME_RESTRICTION 583
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 584
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH 585
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO 592
+#define NT_STATUS_BAD_DLL_ENTRYPOINT 593
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 594
+#define NT_STATUS_LPC_REPLY_LOST 595
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 596
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 597
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT 598
+#define NT_STATUS_PATH_NOT_COVERED 599
+#define NT_STATUS_NO_CALLBACK_ACTIVE 600
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 601
+#define NT_STATUS_PWD_TOO_SHORT 602
+#define NT_STATUS_PWD_TOO_RECENT 603
+#define NT_STATUS_PWD_HISTORY_CONFLICT 604
+#define NT_STATUS_PLUGPLAY_NO_DEVICE 606
+#define NT_STATUS_UNSUPPORTED_COMPRESSION 607
+#define NT_STATUS_INVALID_HW_PROFILE 608
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 609
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 610
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 611
+#define NT_STATUS_RESOURCE_NOT_OWNED 612
+#define NT_STATUS_TOO_MANY_LINKS 613
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT 614
+#define NT_STATUS_FILE_IS_OFFLINE 615
+
+char *xlate_nt_status(DWORD ntstatus);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_NTSTATUS_H */
diff --git a/usr/src/uts/common/smbsrv/oem.h b/usr/src/uts/common/smbsrv/oem.h
new file mode 100644
index 0000000000..af30711dac
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/oem.h
@@ -0,0 +1,106 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Support for oem <-> unicode translations.
+ */
+
+#ifndef _SMBSRV_OEM_H
+#define _SMBSRV_OEM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define oem_default_smb_cpid OEM_CP_IND_850
+#define oem_default_telnet_cpid OEM_CP_IND_1252
+#define oem_default_language "english"
+
+/*
+ * The id should corresponds to oemcp_table in os/library/oem.c.
+ */
+typedef enum codepage_id {
+ OEM_CP_IND_850 = 0,
+ OEM_CP_IND_950,
+ OEM_CP_IND_1252,
+ OEM_CP_IND_949,
+ OEM_CP_IND_936,
+ OEM_CP_IND_932,
+ OEM_CP_IND_852,
+ OEM_CP_IND_1250,
+ OEM_CP_IND_1253,
+ OEM_CP_IND_737,
+ OEM_CP_IND_1254,
+ OEM_CP_IND_857,
+ OEM_CP_IND_1251,
+ OEM_CP_IND_866,
+ OEM_CP_IND_1255,
+ OEM_CP_IND_862,
+ OEM_CP_IND_1256,
+ OEM_CP_IND_720,
+ NO_OF_OEM_CP_INDS
+} codepage_id_t;
+
+
+typedef struct language {
+ char *language;
+ unsigned int smbIndex;
+ unsigned int telnetIndex;
+} language;
+
+
+/*
+ * cpid = the cpid of the oemcp_table that oempage_t belong to.
+ * value = the conversion values
+ */
+typedef struct oempage_t {
+ unsigned int cpid;
+ mts_wchar_t *value;
+} oempage_t;
+
+/*
+ * Private functions for opmlang.c
+ */
+extern int oem_codepage_init(unsigned int);
+extern void oem_codepage_free(unsigned int);
+extern language *oem_get_lang_table(void);
+extern int oem_no_of_languages(void);
+#define NO_OF_LANGUAGES oem_no_of_languages()
+
+/*
+ * Public functions
+ */
+extern size_t unicodestooems(char *, const mts_wchar_t *, size_t, unsigned int);
+extern size_t oemstounicodes(mts_wchar_t *, const char *, size_t, unsigned int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_OEM_H */
diff --git a/usr/src/uts/common/smbsrv/samlib.h b/usr/src/uts/common/smbsrv/samlib.h
new file mode 100644
index 0000000000..19186ad8ba
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/samlib.h
@@ -0,0 +1,159 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SAMLIB_H
+#define _SMBSRV_SAMLIB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Prototypes for the SAM library and RPC client side library interface.
+ * There are two levels of interface defined here: sam_xxx and samr_xxx.
+ * The sam_xxx functions provide a high level interface which make
+ * multiple RPC calls and do all the work necessary to obtain and return
+ * the requested information. The samr_xxx functions provide a low level
+ * interface in which each function maps to a single underlying RPC.
+ */
+
+#include <smbsrv/ndl/samrpc.ndl>
+#include <smbsrv/mlsvc_util.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * samlib.c
+ */
+int sam_lookup_user_info(char *server, char *domain_name, char *username,
+ char *password, smb_userinfo_t *user_info);
+
+DWORD sam_create_trust_account(char *server, char *domain,
+ smb_auth_info_t *auth);
+
+DWORD sam_create_account(char *server, char *domain_name, char *account_name,
+ smb_auth_info_t *auth, DWORD account_flags, smb_userinfo_t *user_info);
+
+DWORD sam_remove_trust_account(char *server, char *domain);
+
+DWORD sam_delete_account(char *server, char *domain_name, char *account_name);
+
+DWORD sam_lookup_name(char *server, char *domain_name, char *account_name,
+ DWORD *rid_ret);
+
+DWORD sam_get_local_domains(char *server, char *domain_name);
+
+/*
+ * samr_open.c
+ */
+int samr_open(int ipc_mode, char *server, char *domain, char *username,
+ char *password, DWORD access_mask, mlsvc_handle_t *samr_handle);
+
+int samr_connect(char *server, char *domain, char *username,
+ DWORD access_mask, mlsvc_handle_t *samr_handle);
+
+int samr_close_handle(mlsvc_handle_t *handle);
+
+DWORD samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
+ struct samr_sid *sid, mlsvc_handle_t *domain_handle);
+
+int samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask,
+ DWORD rid, mlsvc_handle_t *user_handle);
+
+DWORD samr_delete_user(mlsvc_handle_t *user_handle);
+
+int samr_open_group(mlsvc_handle_t *domain_handle, DWORD rid,
+ mlsvc_handle_t *group_handle);
+
+DWORD samr_create_user(mlsvc_handle_t *domain_handle, char *username,
+ DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle);
+
+/*
+ * samr_lookup.c
+ */
+union samr_user_info {
+ struct info1 {
+ char *username;
+ char *fullname;
+ DWORD group_rid;
+ char *description;
+ char *unknown;
+ } info1;
+
+ struct info6 {
+ char *username;
+ char *fullname;
+ } info6;
+
+ struct info7 {
+ char *username;
+ } info7;
+
+ struct info8 {
+ char *fullname;
+ } info8;
+
+ struct info9 {
+ DWORD group_rid;
+ } info9;
+
+ struct info16 {
+ DWORD unknown;
+ } info16;
+};
+
+
+int samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name,
+ smb_userinfo_t *user_info);
+
+DWORD samr_enum_local_domains(mlsvc_handle_t *samr_handle);
+
+DWORD samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
+ smb_userinfo_t *user_info);
+
+int samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
+ union samr_user_info *user_info);
+
+int samr_query_user_groups(mlsvc_handle_t *user_handle,
+ smb_userinfo_t *user_info);
+
+DWORD samr_get_user_pwinfo(mlsvc_handle_t *user_handle);
+
+typedef struct oem_password {
+ BYTE data[512];
+ DWORD length;
+} oem_password_t;
+
+
+int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password,
+ unsigned char *old_password);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_SAMLIB_H */
diff --git a/usr/src/uts/common/smbsrv/smb.h b/usr/src/uts/common/smbsrv/smb.h
new file mode 100644
index 0000000000..1214f041d7
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb.h
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_H
+#define _SMBSRV_SMB_H
+
+/*
+ * SMB definitions and interfaces, mostly defined in the CIFS spec.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB definitions and interfaces, mostly defined in the CIFS spec.
+ */
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#endif
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/msgbuf.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Typedefs from CIFS section 3.2
+ */
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef uint32_t ULONG;
+typedef int32_t LONG;
+
+
+/*
+ * The msgbuf format and length of an SMB header.
+ */
+#define SMB_HEADER_DOS_FMT "Mbbbwbww10.wwww"
+#define SMB_HEADER_NT_FMT "Mblbww#c2.wwww"
+#define SMB_HEADER_LEN 32
+#define SMB_SIG_SIZE 8 /* SMB signature size */
+
+/*
+ * CIFS definition for the SMB header (CIFS Section 3.2). Note that the
+ * pid_high field is not documented in the 1997 CIFS specificaction. This
+ * is a decoded or memory-based definition, which may be padded to align
+ * its elements on word boundaries. See smb_hdrbuf_t for the network
+ * ready structure.
+ */
+typedef struct smb_hdr {
+ UCHAR protocol[4];
+ UCHAR command;
+
+ union {
+ struct {
+ UCHAR error_class;
+ UCHAR reserved;
+ USHORT error;
+ } dos_error;
+ ULONG ntstatus;
+ }status;
+
+ UCHAR flags;
+ USHORT flags2;
+ USHORT pid_high;
+
+ union {
+ USHORT pad[5];
+ struct {
+ USHORT reserved;
+ UCHAR security_sig[SMB_SIG_SIZE];
+ } extra;
+ } extra;
+
+ USHORT tid;
+ USHORT pid;
+ USHORT uid;
+ USHORT mid;
+} smb_hdr_t;
+
+
+/*
+ * Encoded or packed SMB header in network ready format.
+ */
+typedef struct smb_hdrbuf {
+ unsigned char hdr[SMB_HEADER_LEN];
+} smb_hdrbuf_t;
+
+typedef struct smb_nethdr {
+ uint8_t sh_protocol[4];
+ uint8_t sh_command;
+
+ union {
+ struct {
+ uint8_t sh_error_class;
+ uint8_t sh_reserved;
+ uint8_t sh_error[2];
+ } dos_error;
+ uint8_t sh_ntstatus[4];
+ } status;
+
+ uint8_t sh_flags;
+ uint8_t sh_flags2[2];
+ uint8_t sh_pid_high[2];
+
+ union {
+ uint8_t sh_pad[10];
+ struct {
+ uint8_t sh_reserved[2];
+ uint8_t sh_security_sig[SMB_SIG_SIZE];
+ } extra;
+ } extra;
+
+ uint8_t sh_tid[2];
+ uint8_t sh_pid[2];
+ uint8_t sh_uid[2];
+ uint8_t sh_mid[2];
+} smb_nethdr_t;
+
+/*
+ * Protocol magic value as a 32-bit. This will be 0xff 0x53 0x4d 0x42 on
+ * the wire.
+ */
+
+#define SMB_PROTOCOL_MAGIC 0x424d53ff
+
+/*
+ * Time and date encoding (CIFS Section 3.6). The date is encoded such
+ * that the year has a range of 0-119, which represents 1980-2099. The
+ * month range is 1-12, and the day range is 1-31.
+ */
+typedef struct smb_date {
+ USHORT day : 5;
+ USHORT month : 4;
+ USHORT year : 7;
+} smb_date_t;
+
+
+/*
+ * The hours range is 0-23, the minutes range is 0-59 and the two_sec
+ * range is 0-29.
+ */
+typedef struct smb_time {
+ USHORT two_sec : 5;
+ USHORT minutes : 6;
+ USHORT hours : 5;
+} smb_time_t;
+
+
+/*
+ * This is a 64-bit signed absolute time representing 100ns increments.
+ * A positive value represents the absolute time since 1601AD. A
+ * negative value represents a context specific relative time.
+ */
+typedef struct smb_time2 {
+ ULONG low_time;
+ LONG high_time;
+} smb_time2_t;
+
+
+/*
+ * The number of seconds since Jan 1, 1970, 00:00:00.0.
+ */
+typedef uint32_t smb_utime_t;
+
+
+#define SMB_LM_NEGOTIATE_WORDCNT 13
+#define SMB_NT_NEGOTIATE_WORDCNT 17
+
+
+typedef struct smb_nt_negotiate_rsp {
+ UCHAR word_count;
+ USHORT dialect_index;
+ UCHAR security_mode;
+ USHORT max_mpx;
+ USHORT max_vc;
+ ULONG max_buffer_size;
+ ULONG max_raw_size;
+ ULONG session_key;
+ ULONG capabilities;
+ ULONG time_low;
+ ULONG time_high;
+ USHORT server_tz;
+ UCHAR security_len;
+ USHORT byte_count;
+ UCHAR *guid;
+ UCHAR *challenge;
+ UCHAR *oem_domain;
+} smb_nt_negotiate_rsp_t;
+
+/*
+ * SMB_COM_TRANSACTION
+ */
+typedef struct smb_transact_rsp {
+ UCHAR WordCount; /* Count of data bytes */
+ /* value = 10 + SetupCount */
+ USHORT TotalParamCount; /* Total parameter bytes being sent */
+ USHORT TotalDataCount; /* Total data bytes being sent */
+ USHORT Reserved;
+ USHORT ParamCount; /* Parameter bytes sent this buffer */
+ USHORT ParamOffset; /* Offset (from hdr start) to params */
+ USHORT ParamDisplacement; /* Displacement of these param bytes */
+ USHORT DataCount; /* Data bytes sent this buffer */
+ USHORT DataOffset; /* Offset (from hdr start) to data */
+ USHORT DataDisplacement; /* Displacement of these data bytes */
+ UCHAR SetupCount; /* Count of setup words */
+ USHORT BCC;
+#if 0
+ UCHAR Reserved2; /* Reserved (pad above to word) */
+ UCHAR Buffer[1]; /* Buffer containing: */
+ USHORT Setup[]; /* Setup words (# = SetupWordCount) */
+ USHORT ByteCount; /* Count of data bytes */
+ UCHAR Pad[]; /* Pad to SHORT or LONG */
+ UCHAR Params[]; /* Param. bytes (# = ParamCount) */
+ UCHAR Pad1[]; /* Pad to SHORT or LONG */
+ UCHAR Data[]; /* Data bytes (# = DataCount) */
+#endif
+} smb_transact_rsp_t;
+
+/*
+ * SMBreadX
+ */
+typedef struct smb_read_andx_rsp {
+ UCHAR WordCount;
+ UCHAR AndXCmd;
+ UCHAR AndXReserved;
+ USHORT AndXOffset;
+ USHORT Remaining;
+ USHORT DataCompactionMode;
+ USHORT Reserved;
+ USHORT DataLength;
+ USHORT DataOffset;
+ ULONG DataLengthHigh;
+ USHORT Reserved2[3];
+ USHORT ByteCount;
+#if 0
+ UCHAR Pad[];
+ UCHAR Data[];
+#endif
+} smb_read_andx_rsp_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMBSRV_SMB_H */
diff --git a/usr/src/uts/common/smbsrv/smb_common_door.h b/usr/src/uts/common/smbsrv/smb_common_door.h
new file mode 100644
index 0000000000..07ff2f1dd4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_common_door.h
@@ -0,0 +1,130 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_COMMON_DOOR_H
+#define _SMBSRV_SMB_COMMON_DOOR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/wintypes.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_token.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int smb_dr_get_opcode(char *argp, size_t arg_size);
+extern int smb_dr_get_res_stat(char *rbufp, size_t rbuf_size);
+extern char *smb_dr_set_opcode(uint32_t opcode, size_t *len);
+extern char *smb_dr_set_res_stat(uint32_t stat, size_t *len);
+extern char *smb_dr_encode_string(uint32_t reserved, char *buf, size_t *len);
+
+#ifdef _KERNEL
+extern int smb_kdr_decode_common(char *buf, size_t len, xdrproc_t proc,
+ void *data);
+extern char *smb_kdr_encode_common(uint_t reserved, void *data,
+ xdrproc_t proc, size_t *len);
+
+/* kernel encode functions */
+extern char *smb_dr_encode_arg_get_token(netr_client_t *clnt_info,
+ size_t *len);
+/* kernel decode functions */
+extern smb_token_t *smb_dr_decode_res_token(char *buf, size_t len);
+extern smb_dr_kshare_t *smb_dr_decode_kshare(char *buf, size_t len);
+
+/* kernel free functions */
+void smb_dr_kshare_free(smb_dr_kshare_t *kshare);
+#else /* _KERNEL */
+extern int smb_dr_decode_common(char *buf, size_t len, xdrproc_t proc,
+ void *data);
+extern char *smb_dr_encode_common(uint_t reserved, void *data, xdrproc_t proc,
+ size_t *len);
+
+/* user-space encode functions */
+extern char *smb_dr_encode_res_token(smb_token_t *token, size_t *len);
+extern char *smb_dr_encode_kshare(smb_dr_kshare_t *, size_t *);
+
+/* user-space decode functions */
+extern netr_client_t *smb_dr_decode_arg_get_token(char *buf, size_t len);
+extern char *smb_dr_decode_string(char *buf, size_t len);
+
+/* user-space free functions */
+extern void smb_dr_ulist_free(smb_dr_ulist_t *ulist);
+#endif /* _KERNEL */
+
+/*
+ * PBSHORTCUT - should be removed once XDR is used for
+ * serializing/deserializing data across door.
+ */
+
+/*
+ * Common encode/decode functions used by door clients/servers.
+ */
+
+typedef struct smb_dr_ctx {
+ char *ptr;
+ char *start_ptr;
+ char *end_ptr;
+ int status;
+} smb_dr_ctx_t;
+
+
+extern smb_dr_ctx_t *smb_dr_decode_start(char *ptr, int size);
+extern int smb_dr_decode_finish(smb_dr_ctx_t *ctx);
+
+extern smb_dr_ctx_t *smb_dr_encode_start(char *ptr, int size);
+extern int smb_dr_encode_finish(smb_dr_ctx_t *ctx, unsigned int *used);
+
+extern int32_t smb_dr_get_int32(smb_dr_ctx_t *ctx);
+extern DWORD smb_dr_get_dword(smb_dr_ctx_t *ctx);
+extern uint32_t smb_dr_get_uint32(smb_dr_ctx_t *ctx);
+extern int64_t smb_dr_get_int64(smb_dr_ctx_t *ctx);
+extern uint64_t smb_dr_get_uint64(smb_dr_ctx_t *ctx);
+
+extern void smb_dr_put_int32(smb_dr_ctx_t *ctx, int32_t num);
+extern void smb_dr_put_dword(smb_dr_ctx_t *ctx, DWORD num);
+extern void smb_dr_put_uint32(smb_dr_ctx_t *ctx, uint32_t num);
+extern void smb_dr_put_int64(smb_dr_ctx_t *ctx, int64_t num);
+extern void smb_dr_put_uint64(smb_dr_ctx_t *ctx, uint64_t num);
+
+extern char *smb_dr_get_string(smb_dr_ctx_t *ctx);
+extern void smb_dr_put_string(smb_dr_ctx_t *ctx, char *buf);
+extern void smb_dr_free_string(char *buf);
+
+extern void smb_dr_put_word(smb_dr_ctx_t *ctx, WORD num);
+extern WORD smb_dr_get_word(smb_dr_ctx_t *ctx);
+
+extern void smb_dr_put_BYTE(smb_dr_ctx_t *ctx, BYTE byte);
+extern BYTE smb_dr_get_BYTE(smb_dr_ctx_t *ctx);
+
+extern void smb_dr_put_buf(smb_dr_ctx_t *ctx, unsigned char *start, int len);
+extern int smb_dr_get_buf(smb_dr_ctx_t *ctx, unsigned char *buf, int bufsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_COMMON_DOOR_H */
diff --git a/usr/src/uts/common/smbsrv/smb_door_svc.h b/usr/src/uts/common/smbsrv/smb_door_svc.h
new file mode 100644
index 0000000000..be8898f42a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_door_svc.h
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_DOOR_SVC_H
+#define _SMBSRV_SMB_DOOR_SVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_token.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SMB door service (user-space and kernel-space)
+ */
+#define SMB_DR_SVC_NAME "/var/run/smbd_door"
+#define SMB_DR_SVC_VERSION 1
+#define SMB_DR_SVC_COOKIE ((void*)(0xdeadbeef^SMB_DR_SVC_VERSION))
+
+/*
+ * Door argument buffer starts off by the four-byte opcode.
+ * Door result buffer starts off by the four-byte status.
+ * The real data starts at offset 4 of the door buffer.
+ */
+#define SMB_DR_DATA_OFFSET 4
+
+/*
+ * A smb_dr_op_t exists for each user-space door operation.
+ * A smb_kdr_op_t exists for each kernel-space door operation.
+ *
+ * The first argument to smb_dr_op_t/smb_kdr_op_t is a pointer to the
+ * door argument buffer. The second argument indicates the size of
+ * the door argument buffer.
+ *
+ * The user-space door server accepts file descriptors from clients.
+ * Thus, door_desc_t and n_desc can be passed to any smb_dr_op_t operation.
+ *
+ * Returns door result buffer and its size 'rbufsize' upon success.
+ * Otherwise, NULL pointer will be returned and appropriate error code
+ * will be set.
+ */
+typedef char *(*smb_dr_op_t)(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc, size_t *rbufsize, int *err);
+typedef char *(*smb_kdr_op_t)(char *argp, size_t arg_size, size_t *rbufsize,
+ int *errno);
+
+extern smb_dr_op_t smb_doorsrv_optab[];
+
+/*
+ * Door Opcode
+ * -------------
+ * smb_dr_opcode_t - opcodes for user-space door operations.
+ * smb_kdr_opcode_t - opcodes for kernel-space door operations.
+ */
+enum smb_dr_opcode_t {
+ SMB_DR_USER_AUTH_LOGON,
+ SMB_DR_SET_DWNCALL_DESC,
+ SMB_DR_USER_NONAUTH_LOGON,
+ SMB_DR_USER_AUTH_LOGOFF,
+ SMB_DR_USER_LIST,
+ SMB_DR_GROUP_ADD,
+ SMB_DR_GROUP_DELETE,
+ SMB_DR_GROUP_MEMBER_ADD,
+ SMB_DR_GROUP_MEMBER_REMOVE,
+ SMB_DR_GROUP_COUNT,
+ SMB_DR_GROUP_CACHE_SIZE,
+ SMB_DR_GROUP_MODIFY,
+ SMB_DR_GROUP_PRIV_NUM,
+ SMB_DR_GROUP_PRIV_LIST,
+ SMB_DR_GROUP_PRIV_GET,
+ SMB_DR_GROUP_PRIV_SET,
+ SMB_DR_GROUP_LIST,
+ SMB_DR_GROUP_MEMBER_LIST,
+ SMB_DR_GROUP_MEMBER_COUNT
+};
+
+enum smb_kdr_opcode_t {
+ SMB_KDR_USER_NUM,
+ SMB_KDR_USER_LIST,
+ SMB_KDR_SHARE
+};
+
+/*
+ * Door result status
+ * SMB door servers will pass the following result status along with the
+ * requested data back to the clients.
+ */
+#define SMB_DR_OP_SUCCESS 0
+#define SMB_DR_OP_ERR 1
+#define SMB_DR_OP_ERR_DECODE 2
+#define SMB_DR_OP_ERR_ENCODE 3
+#define SMB_DR_OP_ERR_EMPTYBUF 4
+#define SMB_DR_OP_ERR_INVALID_OPCODE 5
+
+#ifdef _KERNEL
+/*
+ * The 2nd argument of the smb_kdoor_srv_callback will be of the
+ * following data structure type.
+ *
+ * rbuf - The pointer to a dynamically allocated door result buffer that
+ * is required to be freed after the kernel completes the copyout
+ * operation.
+ */
+typedef struct smb_kdoor_cb_arg {
+ char *rbuf;
+ size_t rbuf_size;
+} smb_kdoor_cb_arg_t;
+
+/*
+ * SMB kernel door server
+ * ------------------------
+ * NOTE: smb_kdoor_srv_init()/smb_kdoor_srv_fini() are noops.
+ */
+extern int smb_kdoor_srv_start();
+extern void smb_kdoor_srv_stop();
+extern int smb_kdr_is_valid_opcode(int opcode);
+
+extern char *smb_kdr_op_user_num(char *argp, size_t arg_size,
+ size_t *rbufsize, int *errno);
+extern char *smb_kdr_op_users(char *argp, size_t arg_size,
+ size_t *rbufsize, int *errno);
+extern char *smb_kdr_op_share(char *argp, size_t arg_size,
+ size_t *rbufsize, int *errno);
+
+/*
+ * SMB kernel door client
+ * ------------------------
+ * NOTE: smb_kdoor_clnt_init()/smb_kdoor_clnt_fini() are noops.
+ */
+extern int smb_kdoor_clnt_start();
+extern void smb_kdoor_clnt_stop();
+extern void smb_kdoor_clnt_free();
+extern char *smb_kdoor_clnt_upcall(char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t desc_num, size_t *rbufsize);
+
+/*
+ * SMB upcalls
+ */
+extern smb_token_t *smb_upcall_get_token(netr_client_t *clnt_info);
+extern int smb_upcall_set_dwncall_desc(uint32_t opcode, door_desc_t *dp,
+ uint_t n_desc);
+extern void smb_user_nonauth_logon(uint32_t);
+extern void smb_user_auth_logoff(uint32_t);
+#else /* _KERNEL */
+
+/*
+ * SMB user-space door server
+ */
+extern int smb_door_srv_start();
+extern void smb_door_srv_stop(void);
+
+/* downcall descriptor */
+typedef int (*smb_dwncall_get_desc_t)();
+extern int smb_dwncall_install_callback(smb_dwncall_get_desc_t get_desc_cb);
+
+extern int smb_dr_is_valid_opcode(int opcode);
+
+/*
+ * SMB user-space door client
+ */
+extern int smb_dr_clnt_open(int *fd, char *path, char *op_desc);
+extern char *smb_dr_clnt_call(int fd, char *argp, size_t arg_size,
+ size_t *rbufsize, char *op_desc);
+extern void smb_dr_clnt_free(char *argp, size_t arg_size, char *rbufp,
+ size_t rbuf_size);
+/*
+ * SMB downcalls
+ */
+extern int smb_dwncall_get_users(int offset, smb_dr_ulist_t *users);
+extern int smb_dwncall_share(int op, char *path, char *sharename);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_DOOR_SVC_H */
diff --git a/usr/src/uts/common/smbsrv/smb_fsd.h b/usr/src/uts/common/smbsrv/smb_fsd.h
new file mode 100644
index 0000000000..e2fe7787b8
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_fsd.h
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_FSD_H
+#define _SMBSRV_SMB_FSD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/vfs.h>
+#include <sys/refstr_impl.h>
+#include <sys/stat.h>
+
+#ifndef _KERNEL
+#include <stdio.h>
+#include <sys/mnttab.h>
+#endif
+
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * VOL_NAME_MAX is derived from Montana's FSOL_NAME_MAX (32).
+ * This is consistent with MAX_FS_NAME from PB fsadm (QFS).
+ */
+
+#define VOL_NAME_MAX 32
+
+typedef struct fsvol_attr {
+ char name[VOL_NAME_MAX];
+ char fs_typename[_ST_FSTYPSZ];
+ unsigned flags;
+ uint32_t fs_sequence;
+} fsvol_attr_t;
+
+/*
+ * Note: fsid_t consists of two 32-bit values.
+ * The first corresponds to the dev and the second to the file system type.
+ * The fsid_t uniquely (and persistently) denotes a file system in a running
+ * system.
+ *
+ * For the CIFS volume serial number, fsid.val[0] is used (a 32-bit value
+ * is expected by TRANS2_QUERY_FS_INFORMATION).
+ */
+
+#define fs_desc_t fsid_t
+
+extern fs_desc_t null_fsd;
+
+#ifdef _KERNEL
+
+void *fsd_lookup(char *, unsigned, fs_desc_t *);
+int fsd_cmp(fs_desc_t *, fs_desc_t *);
+int fsd_getattr(fs_desc_t *, fsvol_attr_t *);
+int fsd_chkcap(fs_desc_t *, unsigned);
+
+void *fsd_hold(fs_desc_t *fsd);
+void fsd_rele(void *vfsp);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_FSD_H */
diff --git a/usr/src/uts/common/smbsrv/smb_fsops.h b/usr/src/uts/common/smbsrv/smb_fsops.h
new file mode 100644
index 0000000000..56a15aa2d0
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_fsops.h
@@ -0,0 +1,153 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_FSOPS_H
+#define _SMBSRV_SMB_FSOPS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This header file contains all the functions for the interface between
+ * the smb layer and the fs layer.
+ */
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_vops.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int smb_fsop_open(smb_ofile_t *of);
+
+int smb_fsop_close(smb_ofile_t *of);
+
+int smb_fsop_create(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ char *name, smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+int smb_fsop_mkdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ char *name, smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+int smb_fsop_remove(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode,
+ char *name, int od);
+
+int smb_fsop_rmdir(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode,
+ char *name, int od);
+
+int smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ smb_attr_t *attr);
+
+int smb_fsop_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t *cookie, char *name, int *namelen, ino64_t *fileid,
+ struct fs_stream_info *stream_info, smb_node_t **ret_snode,
+ smb_attr_t *ret_attr);
+
+int smb_fsop_getdents(struct smb_request *sr, cred_t *cr,
+ struct smb_node *dir_snode, uint32_t *cookie, uint64_t *verifierp,
+ int32_t *maxcnt, char *args, char *pattern);
+
+int smb_maybe_mangled_name(char *name);
+
+int smb_fsop_rename(struct smb_request *sr, cred_t *cr,
+ smb_node_t *from_snode, char *from_name, smb_node_t *to_snode,
+ char *to_name);
+
+int smb_fsop_setattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ smb_attr_t *set_attr, smb_attr_t *ret_attr);
+
+int smb_fsop_read(struct smb_request *sr, cred_t *cr,
+ smb_node_t *snode, uio_t *uio, smb_attr_t *ret_attr);
+
+int smb_fsop_write(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
+ uio_t *uio, uint32_t *lcount, smb_attr_t *ret_attr,
+ uint32_t *stability);
+
+int smb_fsop_statfs(cred_t *cr, struct smb_node *snode,
+ struct statvfs64 *statp);
+
+int smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode);
+
+int smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t faccess);
+
+void smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ uint32_t *faccess);
+
+int smb_fsop_lookup_name(struct smb_request *sr, cred_t *cr, int flags,
+ smb_node_t *root_node, smb_node_t *dir_snode, char *name,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+int smb_fsop_lookup(struct smb_request *sr, cred_t *cr, int flags,
+ smb_node_t *root_node, smb_node_t *dir_snode, char *name,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr, char *ret_shortname,
+ char *ret_name83);
+
+int smb_fsop_commit(smb_request_t *sr, cred_t *cr, struct smb_node *snode);
+
+int smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode, uint32_t *cookiep, struct fs_stream_info *stream_info,
+ smb_node_t **ret_snode, smb_attr_t *ret_attr);
+
+void smb_fsop_aclfree(acl_t *acl);
+acl_t *smb_fsop_aclalloc(int acenum, int flags);
+int smb_fsop_aclread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fssd);
+int smb_fsop_aclwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd);
+acl_type_t smb_fsop_acltype(smb_node_t *snode);
+
+void smb_fsop_sdinit(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t sd_flags);
+void smb_fsop_sdterm(smb_fssd_t *fssd);
+int smb_fsop_sdread(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fssd);
+int smb_fsop_sdwrite(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
+ smb_fssd_t *fs_sd, int overwrite);
+
+
+void smb_get_caller_context(smb_request_t *sr, caller_context_t *ct);
+
+/*
+ * Lookup-related flags
+ *
+ * SMB_FOLLOW_LINKS Follow symbolic links.
+ * SMB_IGNORE_CASE Perform case-insensitive lookup.
+ *
+ * Misc flags
+ *
+ * SMB_STREAM_RDDIR use eflags=0 for streams readdirs this
+ * is currently a workaround because the
+ * vfs isn't filling in this flag
+ */
+
+#define SMB_FOLLOW_LINKS 0x00000001
+#define SMB_IGNORE_CASE 0x00000002
+#define SMB_STREAM_RDDIR 0x00000004
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_FSOPS_H */
diff --git a/usr/src/uts/common/smbsrv/smb_i18n.h b/usr/src/uts/common/smbsrv/smb_i18n.h
new file mode 100644
index 0000000000..74804d0056
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_i18n.h
@@ -0,0 +1,41 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_I18N_H
+#define _SMB_I18N_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned short mts_wchar_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_I18N_H */
diff --git a/usr/src/uts/common/smbsrv/smb_idmap.h b/usr/src/uts/common/smbsrv/smb_idmap.h
new file mode 100644
index 0000000000..0f6380f1bf
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_idmap.h
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_IDMAP_H
+#define _SMB_IDMAP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef _KERNEL
+#include <sys/kidmap.h>
+#else
+#include <idmap.h>
+#endif
+
+#include <smbsrv/ntsid.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SMB ID mapping
+ *
+ * Solaris ID mapping service (aka Winchester) works with domain SIDs
+ * and RIDs where domain SIDs are in string format. CIFS service works
+ * with binary SIDs understanable by CIFS clients. A layer of SMB ID
+ * mapping functions are implemeted to hide the SID conversion details
+ * and also hide the handling of array of batch mapping requests.
+ */
+
+#define SMB_IDMAP_UNKNOWN -1
+#define SMB_IDMAP_GROUP 0
+#define SMB_IDMAP_USER 1
+#define SMB_IDMAP_EVERYONE 2
+
+#define SMB_IDMAP_SID2ID 0x0001
+#define SMB_IDMAP_ID2SID 0x0002
+
+/*
+ * smb_idmap_t
+ *
+ * sim_idtype: ID type (output in sid->uid mapping)
+ * sim_id: UID/GID (output in sid->uid mapping)
+ */
+typedef struct smb_idmap {
+ int sim_idtype;
+ uid_t *sim_id;
+ char *sim_domsid;
+ uint32_t sim_rid;
+ nt_sid_t *sim_sid;
+ idmap_stat sim_stat;
+} smb_idmap_t;
+
+typedef struct smb_idmap_batch {
+ uint16_t sib_nmap;
+ uint32_t sib_flags;
+ uint32_t sib_size;
+ smb_idmap_t *sib_maps;
+ idmap_get_handle_t *sib_idmaph;
+} smb_idmap_batch_t;
+
+idmap_stat smb_idmap_getsid(uid_t, int, nt_sid_t **);
+idmap_stat smb_idmap_getid(nt_sid_t *, uid_t *, int *);
+
+void smb_idmap_batch_destroy(smb_idmap_batch_t *);
+idmap_stat smb_idmap_batch_create(smb_idmap_batch_t *, uint16_t, int);
+idmap_stat smb_idmap_batch_getmappings(smb_idmap_batch_t *);
+idmap_stat smb_idmap_batch_getid(idmap_get_handle_t *, smb_idmap_t *,
+ nt_sid_t *, int);
+idmap_stat smb_idmap_batch_getsid(idmap_get_handle_t *, smb_idmap_t *,
+ uid_t, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMB_IDMAP_H */
diff --git a/usr/src/uts/common/smbsrv/smb_incl.h b/usr/src/uts/common/smbsrv/smb_incl.h
new file mode 100644
index 0000000000..b9cdaa3f13
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_incl.h
@@ -0,0 +1,121 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_INCL_H
+#define _SMBSRV_SMB_INCL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/cmn_err.h>
+#include <sys/cpuvar.h>
+#include <sys/list.h>
+#include <sys/sunddi.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+
+#include <smbsrv/alloc.h>
+#include <smbsrv/ctype.h>
+#include <smbsrv/string.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/doserror.h>
+#include <smbsrv/cifs.h>
+#include <smbsrv/ntaccess.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb.h>
+
+#include <smbsrv/smbvar.h>
+#include <smbsrv/smbfmt.h>
+#include <smbsrv/smb_kproto.h>
+
+#define QUEUE_INSERT_HEAD(q, e) \
+ { \
+ ((e)->forw) = (void *)((q)->forw); \
+ ((e)->back) = (void *)(q); \
+ ((q)->forw->back) = (void *)(e); \
+ ((q)->forw) = (void *)(e); \
+ }
+
+
+#define QUEUE_INSERT_TAIL(q, e) \
+ { \
+ ((e)->back) = (void *)((q)->back); \
+ ((e)->forw) = (void *)(q); \
+ ((q)->back->forw) = (void *)(e); \
+ ((q)->back) = (void *)(e); \
+ }
+
+#define QUEUE_INSERT_SORT(q, e, k, t) \
+ { \
+ (void *)(t) = (void *)((q)->forw); \
+ while (((t)->k) < ((e)->k)) { \
+ (void *)(t) = (void *)((t)->forw); \
+ } \
+ QUEUE_INSERT_TAIL(t, e); \
+ }
+
+#define QUEUE_CLIP(e) \
+ { \
+ (e)->forw->back = (e)->back; \
+ (e)->back->forw = (e)->forw; \
+ (e)->forw = 0; \
+ (e)->back = 0; \
+ }
+
+/* These should be defined in system header files */
+
+extern int atoi(const char *);
+extern int getchar(void);
+
+/*
+ * PBSHORTCUT - remove this when we replace BYTE/WORD/DWORD to
+ * uint8_t/uint16_t/uint32_t and <inet/ip.h> gets included by
+ * files that invoke the following functions.
+ */
+extern char *inet_ntop(int, const void *, char *, int);
+extern int inet_pton(int, char *, void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_INCL_H */
diff --git a/usr/src/uts/common/smbsrv/smb_ioctl.h b/usr/src/uts/common/smbsrv/smb_ioctl.h
new file mode 100755
index 0000000000..6b6ad051fb
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_IOCTL_H_
+#define _SMB_IOCTL_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define SMB_IOC_BASE (('S' << 16) | ('B' << 8))
+#define SMB_IOC_GMTOFF _IOW(SMB_IOC_BASE, 1, int)
+#define SMB_IOC_CONFIG_REFRESH _IOW(SMB_IOC_BASE, 2, int)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_IOCTL_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
new file mode 100644
index 0000000000..26ac73055e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -0,0 +1,602 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Function prototypes for the SMB module.
+ */
+
+#ifndef _SMB_KPROTO_H_
+#define _SMB_KPROTO_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/cred.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smb_token.h>
+
+/*
+ * Definitions that should be elsewhere...
+ */
+struct mbuf *m_free(struct mbuf *);
+void m_freem(struct mbuf *);
+
+int fd_dealloc(int);
+
+off_t lseek(int fildes, off_t offset, int whence);
+
+int arpioctl(int cmd, void *data);
+/* Why? uint32_t inet_addr(char *str); */
+int microtime(timestruc_t *tvp);
+int clock_get_uptime(void);
+
+/*
+ * SMB Service init/shutdown functions
+ */
+int smb_service_init(void);
+void smb_service_fini(void);
+int smb_service_open(struct smb_info *si);
+void smb_service_close(struct smb_info *si);
+int smb_service_connect(struct smb_info *si);
+void smb_service_disconnect(struct smb_info *si);
+int smb_service_start_threads(struct smb_info *si);
+void smb_service_stop_threads(struct smb_info *si);
+
+/*
+ * Logging functions
+ */
+void smb_log_flush(void);
+void smb_correct_keep_alive_values(uint32_t new_keep_alive);
+void smb_close_all_connections(void);
+int smb_set_file_size(struct smb_request *sr);
+int smb_session_send(smb_session_t *, uint8_t type, struct mbuf_chain *);
+int smb_session_xprt_gethdr(smb_session_t *, smb_xprt_t *);
+
+int smb_net_id(uint32_t);
+uint32_t smb_gmt_to_local_time(uint32_t);
+uint32_t smb_local_time_to_gmt(uint32_t);
+
+void smb_process_file_notify_change_queue(struct smb_ofile *of);
+
+void smb_oplock_init(void);
+
+DWORD smb_acquire_oplock(struct smb_request *sr,
+ struct smb_ofile *file,
+ unsigned int level_requested,
+ unsigned int *level_granted);
+
+DWORD smb_break_oplock(struct smb_request *sr, struct smb_node *node);
+void smb_release_oplock(struct smb_ofile *file, int reason);
+
+uint32_t smb_unlock_range(struct smb_request *, struct smb_node *,
+ uint64_t, uint64_t);
+void smb_unlock_range_raise_error(smb_request_t *sr, uint32_t ntstatus);
+uint32_t smb_lock_range(struct smb_request *, struct smb_ofile *,
+ uint64_t, uint64_t, uint32_t, uint32_t);
+void smb_lock_range_raise_error(smb_request_t *sr, uint32_t ntstatus);
+
+int smb_mangle_name(ino64_t fileid, char *name, char *shortname,
+ char *name83, int force);
+int smb_unmangle_name(struct smb_request *sr, cred_t *cred,
+ smb_node_t *dir_node, char *name, char *real_name, int realname_size,
+ char *shortname, char *name83, int od);
+int smb_maybe_mangled_name(char *name);
+int smb_maybe_mangled_path(const char *path, size_t pathlen);
+int smb_needs_mangle(char *name, char **dot_pos);
+
+void smb_set_stability(int mode);
+void smb_commit_required(int state);
+
+
+void smbsr_cleanup(struct smb_request *sr);
+
+int smbsr_connect_tree(struct smb_request *);
+
+int smb_convert_unicode_wildcards(char *);
+int smb_ascii_or_unicode_strlen(struct smb_request *, char *);
+int smb_ascii_or_unicode_strlen_null(struct smb_request *, char *);
+int smb_ascii_or_unicode_null_len(struct smb_request *);
+
+int smb_search(struct smb_request *);
+void smb_rdir_close(struct smb_request *);
+int smb_rdir_open(struct smb_request *, char *, unsigned short);
+int smb_rdir_next(smb_request_t *sr, smb_node_t **rnode,
+ smb_odir_context_t *pc);
+
+DWORD smb_open_subr(struct smb_request *);
+DWORD smb_validate_object_name(char *path, unsigned int ftype);
+
+uint32_t smb_omode_to_amask(uint32_t desired_access);
+
+void sshow_distribution_info(char *);
+
+int smb_dispatch_request(struct smb_request *);
+void smbsr_disconnect_file(smb_request_t *sr);
+void smbsr_disconnect_dir(smb_request_t *sr);
+void smbsr_check_result(struct smb_request *, int, int);
+void smbsr_decode_error(struct smb_request *);
+void smbsr_encode_error(struct smb_request *);
+void smbsr_encode_empty_result(struct smb_request *sr);
+
+#pragma does_not_return(smbsr_decode_error)
+#pragma does_not_return(smbsr_encode_error)
+
+int smbsr_decode_vwv(struct smb_request *sr, char *fmt, ...);
+int smbsr_decode_data(struct smb_request *sr, char *fmt, ...);
+void smbsr_encode_result(struct smb_request *, int, int, char *, ...);
+smb_xa_t *smbsr_lookup_xa(smb_request_t *sr);
+void smbsr_send_reply(struct smb_request *);
+
+void smbsr_raise_cifs_error(struct smb_request *sr, DWORD status,
+ int error_class, int error_code);
+
+int smbsr_set_errno(struct smb_request *, int);
+void smbsr_raise_errno(struct smb_request *, int);
+void smbsr_raise_error(struct smb_request *, int, int);
+void smbsr_raise_nt_error(struct smb_request *sr, uint32_t);
+
+#pragma does_not_return(smbsr_raise_cifs_error)
+#pragma does_not_return(smbsr_raise_error)
+#pragma does_not_return(smbsr_raise_nt_error)
+#pragma does_not_return(smbsr_raise_errno)
+
+void smbsr_setup_nt_status(struct smb_request *sr,
+ uint32_t severity,
+ uint32_t nt_status);
+
+int smb_mbc_encode(struct mbuf_chain *mbc, char *fmt, va_list ap);
+int smb_mbc_decode(struct mbuf_chain *mbc, char *fmt, va_list ap);
+
+int clock_get_milli_uptime(void);
+int dosfs_dos_to_ux_time(int, int);
+int dosfs_ux_to_dos_time(int, short int *, short int *);
+
+int smb_decode_mbc(struct mbuf_chain *mbc, char *fmt, ...);
+int smb_decode_buf(unsigned char *buf, int n_buf, char *fmt, ...);
+int smb_encode_mbc(struct mbuf_chain *mbc, char *fmt, ...);
+int smb_encode_buf(unsigned char *buf, int n_buf, char *fmt, ...);
+int smb_peek_mbc(struct mbuf_chain *buf, int offset, char *fmt, ...);
+int smb_poke_mbc(struct mbuf_chain *buf, int offset, char *fmt, ...);
+
+void smbsr_encode_header(struct smb_request *sr, int wct,
+ int bcc, char *fmt, ...);
+
+int smb_xlate_dialect_str_to_cd(char *);
+char *smb_xlate_com_cd_to_str(int);
+char *smb_xlate_dialect_cd_to_str(int);
+
+void smb_od_destruct(struct smb_session *, struct smb_odir *);
+int smbd_fs_query(struct smb_request *, struct smb_fqi *, int);
+int smb_component_match(struct smb_request *sr, ino64_t fileid,
+ struct smb_odir *od, smb_odir_context_t *pc);
+
+int smb_lock_range_access(struct smb_request *, struct smb_node *,
+ uint64_t, uint64_t, uint32_t desired_access);
+
+/*
+ * Socket functions
+ */
+struct sonode *smb_socreate(int domain, int type, int protocol);
+void smb_soshutdown(struct sonode *so);
+void smb_sodestroy(struct sonode *so);
+int smb_sosend(struct sonode *so, void *msg, size_t len);
+int smb_sorecv(struct sonode *so, void *msg, size_t len);
+int smb_iov_sosend(struct sonode *so, iovec_t *iop, int iovlen,
+ size_t total_len);
+int smb_iov_sorecv(struct sonode *so, iovec_t *iop, int iovlen,
+ size_t total_len);
+
+/*
+ * SMB RPC interface
+ */
+int smb_rpc_open(struct smb_request *sr);
+void smb_rpc_close(struct smb_ofile *of);
+int smb_rpc_transact(struct smb_request *sr, struct uio *uio);
+int smb_rpc_read(struct smb_request *sr, struct uio *uio);
+int smb_rpc_write(struct smb_request *sr, struct uio *uio);
+
+/*
+ * SMB node functions (file smb_node.c)
+ */
+struct smb_node *smb_node_lookup(struct smb_request *sr, struct open_param *op,
+ cred_t *cr, vnode_t *vp, char *od_name, smb_node_t *dir_snode,
+ smb_node_t *unnamed_node, smb_attr_t *attr);
+struct smb_node *smb_stream_node_lookup(struct smb_request *sr, cred_t *cr,
+ smb_node_t *fnode, vnode_t *xattrdirvp, vnode_t *vp, char *stream_name,
+ smb_attr_t *ret_attr);
+void smb_node_ref(smb_node_t *node);
+void smb_node_release(smb_node_t *node);
+int smb_node_assert(smb_node_t *node, const char *file, int line);
+int smb_node_rename(smb_node_t *from_dir_snode, smb_node_t *ret_snode,
+ smb_node_t *to_dir_snode, char *to_name);
+int smb_node_root_init();
+void smb_node_root_fini();
+void smb_node_add_lock(smb_node_t *node, smb_lock_t *lock);
+void smb_node_destroy_lock(smb_node_t *node, smb_lock_t *lock);
+void smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file);
+uint64_t smb_node_get_size(smb_node_t *node, smb_attr_t *attr);
+void smb_node_set_time(struct smb_node *node, timestruc_t *crtime,
+ timestruc_t *mtime, timestruc_t *atime,
+ timestruc_t *ctime, unsigned int what);
+timestruc_t *smb_node_get_crtime(struct smb_node *node);
+timestruc_t *smb_node_get_atime(struct smb_node *node);
+timestruc_t *smb_node_get_ctime(struct smb_node *node);
+timestruc_t *smb_node_get_mtime(struct smb_node *node);
+void smb_node_set_dosattr(struct smb_node *, uint32_t);
+uint32_t smb_node_get_dosattr(struct smb_node *node);
+int smb_node_set_delete_on_close(smb_node_t *, cred_t *);
+void smb_node_reset_delete_on_close(smb_node_t *);
+
+
+
+/*
+ * Pathname functions
+ */
+
+int smb_pathname_reduce(struct smb_request *, cred_t *,
+ const char *, smb_node_t *, smb_node_t *, smb_node_t **, char *);
+
+int smb_pathname(struct smb_request *, char *, int, smb_node_t *,
+ smb_node_t *, smb_node_t **, smb_node_t **, cred_t *);
+
+/*
+ * Share functions
+ */
+
+int smb_share_export(char *);
+int smb_share_unexport(char *, char *);
+
+/*
+ * smb_vfs functions
+ */
+
+boolean_t smb_vfs_hold(vfs_t *);
+void smb_vfs_rele(vfs_t *);
+void smb_vfs_rele_all(void);
+
+/*
+ * String manipulation function
+ */
+char *smb_kstrdup(const char *s, size_t n);
+
+int smb_sync_fsattr(struct smb_request *sr, cred_t *cr,
+ struct smb_node *node);
+
+int smb_com_create_directory(struct smb_request *sr);
+DWORD smb_validate_dirname(char *path);
+
+int smb_com_trans2_create_directory(struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_find_first2(struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_find_next2(struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_query_fs_information(struct smb_request *sr,
+ struct smb_xa *xa);
+int smb_com_trans2_query_path_information(
+ struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_query_file_information(
+ struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_set_path_information(
+ struct smb_request *sr, struct smb_xa *xa);
+int smb_com_trans2_set_file_information(
+ struct smb_request *sr, struct smb_xa *xa);
+
+void smb_encode_stream_info(struct smb_request *sr, struct smb_xa *xa,
+ smb_node_t *snode, smb_attr_t *attr);
+
+int smb_nt_transact_create(struct smb_request *sr, struct smb_xa *xa);
+int smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa);
+int smb_nt_transact_query_security_info(struct smb_request *sr,
+ struct smb_xa *xa);
+int smb_nt_transact_set_security_info(struct smb_request *sr,
+ struct smb_xa *xa);
+int smb_nt_transact_ioctl(struct smb_request *sr, struct smb_xa *xa);
+
+/* NOTIFY CHANGE */
+int smb_reply_notify_change_request(smb_request_t *sr);
+void smb_process_session_notify_change_queue(struct smb_session *session);
+void smb_process_node_notify_change_queue(struct smb_node *node);
+void smb_reply_specific_cancel_request(struct smb_request *sr);
+
+void smb_fem_fcn_install(smb_node_t *node);
+void smb_fem_fcn_uninstall(smb_node_t *node);
+
+/* FEM */
+
+int smb_fem_init();
+void smb_fem_shutdown();
+
+int smb_try_grow(struct smb_request *sr, int64_t new_size);
+
+/* functions from smb_memory_manager.c */
+
+void *smbsr_malloc(smb_malloc_list *, size_t);
+void *smbsr_realloc(void *, size_t);
+void smbsr_free_malloc_list(smb_malloc_list *);
+
+void smbsr_rq_notify(smb_request_t *sr,
+ smb_session_t *session, smb_tree_t *tree);
+
+unsigned short smb_worker_getnum();
+int smb_common_close(struct smb_request *sr, uint32_t last_wtime);
+void smb_preset_delete_on_close(struct smb_ofile *file);
+void smb_commit_delete_on_close(struct smb_ofile *file);
+
+int smb_stream_parse_name(char *name, char *u_stream_name,
+ char *stream_name);
+
+uint32_t smb_get_gmtoff(void);
+void smb_set_gmtoff(uint32_t);
+
+void smb_errmap_unix2smb(int en, smb_error_t *smberr);
+DWORD smb_trans2_set_information(struct smb_request *sr,
+ smb_trans2_setinfo_t *info,
+ smb_error_t *smberr);
+
+/* SMB signing routines smb_signing.c */
+void smb_sign_init(struct smb_request *req,
+ smb_session_key_t *session_key, char *resp, int resp_len);
+
+int smb_sign_check_request(struct smb_request *req);
+
+int smb_sign_check_secondary(struct smb_request *req, unsigned int seqnum);
+
+void smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply);
+
+uint32_t smb_mode_to_dos_attributes(smb_attr_t *ap);
+int smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr);
+
+smb_request_t *smb_request_alloc(struct smb_session *session,
+ int request_length);
+void smb_request_cancel(smb_request_t *sr);
+void smb_request_free(smb_request_t *sr);
+
+smb_session_t *smb_session_create(struct sonode *new_so, uint16_t port);
+void smb_session_delete(smb_session_t *session);
+void smb_session_cancel(smb_session_t *session);
+void smb_session_cancel_requests(smb_session_t *session);
+void smb_session_config(smb_session_t *session);
+void smb_session_reject(smb_session_t *session, char *reason);
+void smb_session_disconnect_share(char *);
+void smb_session_disconnect_volume(fs_desc_t *);
+
+
+/*
+ * ofile functions (file smb_ofile.c)
+ */
+smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *tree, uint16_t fid);
+smb_ofile_t *smb_ofile_open(smb_tree_t *tree, smb_node_t *node, uint16_t pid,
+ uint32_t access_granted, uint32_t create_options, uint32_t share_access,
+ uint16_t ftype, char *pipe_name, uint32_t rpc_fid, smb_error_t *err);
+int smb_ofile_close(smb_ofile_t *ofile, uint32_t last_wtime);
+uint32_t smb_ofile_access(smb_ofile_t *ofile, cred_t *cr, uint32_t access);
+int smb_ofile_seek(smb_ofile_t *of, ushort_t mode, int32_t off,
+ uint32_t *retoff);
+void smb_ofile_release(smb_ofile_t *ofile);
+void smb_ofile_close_all(smb_tree_t *tree);
+void smb_ofile_close_all_by_pid(smb_tree_t *tree, uint16_t pid);
+void smb_ofile_set_flags(smb_ofile_t *of, uint32_t flags);
+void smb_ofile_close_timestamp_update(smb_ofile_t *of, uint32_t last_wtime);
+boolean_t smb_ofile_is_open(smb_ofile_t *of);
+#define smb_ofile_granted_access(_of_) ((_of_)->f_granted_access)
+
+/*
+ * odir functions (file smb_odir.c)
+ */
+smb_odir_t *smb_odir_open(smb_tree_t *tree, smb_node_t *node, char *pattern,
+ uint16_t pid, unsigned short sattr);
+void smb_odir_close(smb_odir_t *od);
+void smb_odir_close_all(smb_tree_t *tree);
+void smb_odir_close_all_by_pid(smb_tree_t *tree, uint16_t pid);
+void smb_odir_release(smb_odir_t *od);
+smb_odir_t *smb_odir_lookup_by_sid(smb_tree_t *tree, uint16_t sid);
+
+/*
+ * SMB user functions (file smb_user.c)
+ */
+smb_user_t *smb_user_login(smb_session_t *, cred_t *,
+ char *, char *, uint32_t, uint32_t, uint32_t);
+smb_user_t *smb_user_dup(smb_user_t *);
+void smb_user_logoff(smb_user_t *user);
+void smb_user_logoff_all(smb_session_t *session);
+smb_user_t *smb_user_lookup_by_uid(smb_session_t *, cred_t **, uint16_t);
+smb_user_t *smb_user_lookup_by_name(smb_session_t *, char *, char *);
+smb_user_t *smb_user_lookup_by_state(smb_session_t *, smb_user_t *user);
+void smb_user_disconnect_share(smb_user_t *user, char *sharename);
+void smb_user_disconnect_volume(smb_user_t *user, fs_desc_t *fsd);
+void smb_user_release(smb_user_t *user);
+
+/*
+ * SMB tree functions (file smb_tree.c)
+ */
+smb_tree_t *smb_tree_connect(smb_user_t *user, uint16_t access_flags,
+ char *sharename, char *resource, int32_t rt_share,
+ smb_node_t *snode, fsvol_attr_t *vol_attr);
+void smb_tree_disconnect(smb_tree_t *tree);
+void smb_tree_disconnect_all(smb_user_t *user);
+void smb_tree_close_all_by_pid(smb_user_t *user, uint16_t pid);
+smb_tree_t *smb_tree_lookup_by_tid(smb_user_t *user, uint16_t tid);
+smb_tree_t *smb_tree_lookup_by_name(smb_user_t *, char *, smb_tree_t *);
+smb_tree_t *smb_tree_lookup_by_fsd(smb_user_t *, fs_desc_t *, smb_tree_t *);
+void smb_tree_release(smb_tree_t *tree);
+
+uint32_t smb_user_get_num(void);
+void smb_dr_user_free(smb_dr_user_ctx_t *uinfo);
+void smb_dr_ulist_free(smb_dr_ulist_t *ulist);
+int smb_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist);
+
+/*
+ * SMB user's credential functions
+ */
+cred_t *smb_cred_create(smb_token_t *, uint32_t *);
+void smb_cred_rele(cred_t *cr);
+int smb_cred_is_member(cred_t *cr, nt_sid_t *sid);
+
+smb_xa_t *smb_xa_create(smb_session_t *session, smb_request_t *sr,
+ uint32_t total_parameter_count, uint32_t total_data_count,
+ uint32_t max_parameter_count, uint32_t max_data_count,
+ uint32_t max_setup_count, uint32_t setup_word_count);
+void smb_xa_delete(smb_xa_t *xa);
+smb_xa_t *smb_xa_hold(smb_xa_t *xa);
+void smb_xa_rele(smb_session_t *session, smb_xa_t *xa);
+int smb_xa_open(smb_xa_t *xa);
+void smb_xa_close(smb_xa_t *xa);
+int smb_xa_complete(smb_xa_t *xa);
+smb_xa_t *smb_xa_find(smb_session_t *session, uint16_t pid, uint16_t mid);
+
+struct mbuf *smb_mbuf_get(uchar_t *buf, int nbytes);
+struct mbuf *smb_mbuf_allocate(struct uio *uio);
+void smb_mbuf_trim(struct mbuf *mhead, int nbytes);
+
+void smb_check_status(void);
+int smb_handle_write_raw(smb_session_t *session, smb_request_t *sr);
+
+void smb_winpipe_init(void);
+void smb_winpipe_fini(void);
+int smb_winpipe_open(void);
+void smb_winpipe_close(void);
+int smb_winpipe_call(smb_request_t *, mlsvc_pipe_t *, mlsvc_stream_t *,
+ uint16_t, uint32_t *);
+
+void smb_reconnection_check(struct smb_session *session);
+
+uint32_t nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time);
+uint64_t unix_to_nt_time(timestruc_t *);
+
+int netbios_name_isvalid(char *in, char *out);
+
+size_t
+unicodestooems(char *oemstring, const mts_wchar_t *unicodestring,
+ size_t nbytes, unsigned int cpid);
+
+size_t oemstounicodes(mts_wchar_t *unicodestring, const char *oemstring,
+ size_t nwchars, unsigned int cpid);
+
+int uioxfer(struct uio *src_uio, struct uio *dst_uio, int n);
+
+int smb_match_name(ino64_t fileid, char *name, char *shortname,
+ char *name83, char *pattern, int ignore_case);
+int is_dot_or_dotdot(char *name);
+int token2buf(smb_token_t *token, char *buf);
+
+/*
+ * Pool ID function prototypes
+ */
+int smb_idpool_constructor(smb_idpool_t *pool);
+void smb_idpool_destructor(smb_idpool_t *pool);
+int smb_idpool_alloc(smb_idpool_t *pool, uint16_t *id);
+void smb_idpool_free(smb_idpool_t *pool, uint16_t id);
+
+/*
+ * SMB thread function prototypes
+ */
+void smb_session_worker(void *arg);
+
+/*
+ * SMB locked list function prototypes
+ */
+void smb_llist_constructor(smb_llist_t *, size_t, size_t);
+void smb_llist_destructor(smb_llist_t *);
+void smb_llist_insert_head(smb_llist_t *ll, void *obj);
+void smb_llist_insert_tail(smb_llist_t *ll, void *obj);
+void smb_llist_remove(smb_llist_t *ll, void *obj);
+int smb_llist_upgrade(smb_llist_t *ll);
+uint32_t smb_llist_get_count(smb_llist_t *ll);
+#define smb_llist_enter(ll, mode) rw_enter(&(ll)->ll_lock, mode)
+#define smb_llist_exit(ll) rw_exit(&(ll)->ll_lock)
+#define smb_llist_head(ll) list_head(&(ll)->ll_list)
+#define smb_llist_next(ll, obj) list_next(&(ll)->ll_list, obj)
+int smb_account_connected(smb_user_t *user);
+
+/*
+ * SMB Synchronized list function prototypes
+ */
+void smb_slist_constructor(smb_slist_t *, size_t, size_t);
+void smb_slist_destructor(smb_slist_t *);
+void smb_slist_insert_head(smb_slist_t *sl, void *obj);
+void smb_slist_insert_tail(smb_slist_t *sl, void *obj);
+void smb_slist_remove(smb_slist_t *sl, void *obj);
+void smb_slist_wait_for_empty(smb_slist_t *sl);
+void smb_slist_exit(smb_slist_t *sl);
+uint32_t smb_slist_move_tail(list_t *lst, smb_slist_t *sl);
+void smb_slist_obj_move(smb_slist_t *dst, smb_slist_t *src, void *obj);
+#define smb_slist_enter(sl) mutex_enter(&(sl)->sl_mutex)
+#define smb_slist_head(sl) list_head(&(sl)->sl_list)
+#define smb_slist_next(sl, obj) list_next(&(sl)->sl_list, obj)
+
+void smb_rwx_init(smb_rwx_t *rwx);
+void smb_rwx_destroy(smb_rwx_t *rwx);
+#define smb_rwx_rwenter(rwx, mode) rw_enter(&(rwx)->rwx_lock, mode)
+void smb_rwx_rwexit(smb_rwx_t *rwx);
+int smb_rwx_rwwait(smb_rwx_t *rwx, clock_t timeout);
+#define smb_rwx_xenter(rwx) mutex_enter(&(rwx)->rwx_mutex)
+#define smb_rwx_xexit(rwx) mutex_exit(&(rwx)->rwx_mutex)
+krw_t smb_rwx_rwupgrade(smb_rwx_t *rwx);
+void smb_rwx_rwdowngrade(smb_rwx_t *rwx, krw_t mode);
+
+void smb_thread_init(smb_thread_t *, char *, smb_thread_ep_t, void *,
+ smb_thread_aw_t, void *);
+void smb_thread_destroy(smb_thread_t *);
+int smb_thread_start(smb_thread_t *);
+void smb_thread_stop(smb_thread_t *);
+void smb_thread_signal(smb_thread_t *);
+boolean_t smb_thread_continue(smb_thread_t *);
+boolean_t smb_thread_continue_nowait(smb_thread_t *);
+boolean_t smb_thread_continue_timedwait(smb_thread_t *, int /* seconds */);
+void smb_thread_set_awaken(smb_thread_t *, smb_thread_aw_t, void *);
+
+uint32_t smb_denymode_to_sharemode(uint32_t desired_access, char *fname);
+uint32_t smb_ofun_to_crdisposition(uint16_t ofun);
+
+void smb_audit_buf_node_create(smb_node_t *node);
+void smb_audit_buf_node_destroy(smb_node_t *node);
+#define smb_audit_node(_n_) \
+ if ((_n_)->n_audit_buf) { \
+ smb_audit_record_node_t *anr; \
+ \
+ anr = (_n_)->n_audit_buf->anb_records; \
+ anr += (_n_)->n_audit_buf->anb_index; \
+ (_n_)->n_audit_buf->anb_index++; \
+ (_n_)->n_audit_buf->anb_index &= \
+ (_n_)->n_audit_buf->anb_max_index; \
+ anr->anr_refcnt = node->n_refcnt; \
+ anr->anr_depth = getpcstack(anr->anr_stack, \
+ SMB_AUDIT_STACK_DEPTH); \
+ }
+
+/* 100's of ns between 1/1/1970 and 1/1/1601 */
+#define NT_TIME_BIAS (134774LL * 24LL * 60LL * 60LL * 10000000LL)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_KPROTO_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_privilege.h b/usr/src/uts/common/smbsrv/smb_privilege.h
new file mode 100644
index 0000000000..c03455d469
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_privilege.h
@@ -0,0 +1,197 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_PRIVILEGE_H
+#define _SMB_PRIVILEGE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/smb_xdr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Privileges
+ *
+ * Privileges apply to all objects and over-ride the access controls
+ * in an object's security descriptor in a manner specific to each
+ * privilege. Privileges are still not full defined. Privileges are
+ * defined in a set structure (LUID = Locally Unique Identifier).
+ *
+ * The default LUID, name and display names defined on NT 4.0 are:
+ * LUID Privilege Name Display Name
+ * ---- -------------- ------------
+ * 0:2 SeCreateTokenPrivilege Create a token object
+ * 0:3 SeAssignPrimaryTokenPrivilege Replace a process level token
+ * 0:4 SeLockMemoryPrivilege Lock pages in memory
+ * 0:5 SeIncreaseQuotaPrivilege Increase quotas
+ * 0:6 SeMachineAccountPrivilege Add workstations to domain
+ * 0:7 SeTcbPrivilege Act as part of the operating system
+ * 0:8 SeSecurityPrivilege Manage auditing and security log
+ * 0:9 SeTakeOwnershipPrivilege Take ownership of files or other objects
+ * 0:10 SeLoadDriverPrivilege Load and unload device drivers
+ * 0:11 SeSystemProfilePrivilege Profile system performance
+ * 0:12 SeSystemtimePrivilege Change the system time
+ * 0:13 SeProfileSingleProcessPrivilege Profile single process
+ * 0:14 SeIncreaseBasePriorityPrivilege Increase scheduling priority
+ * 0:15 SeCreatePagefilePrivilege Create a pagefile
+ * 0:16 SeCreatePermanentPrivilege Create permanent shared objects
+ * 0:17 SeBackupPrivilege Back up files and directories
+ * 0:18 SeRestorePrivilege Restore files and directories
+ * 0:19 SeShutdownPrivilege Shut down the system
+ * 0:20 SeDebugPrivilege Debug programs
+ * 0:21 SeAuditPrivilege Generate security audits
+ * 0:22 SeSystemEnvironmentPrivilege Modify firmware environment values
+ * 0:23 SeChangeNotifyPrivilege Bypass traverse checking
+ * 0:24 SeRemoteShutdownPrivilege Force shutdown from a remote system
+ */
+
+/*
+ * Privilege names
+ */
+#define SE_CREATE_TOKEN_NAME "SeCreateTokenPrivilege"
+#define SE_ASSIGNPRIMARYTOKEN_NAME "SeAssignPrimaryTokenPrivilege"
+#define SE_LOCK_MEMORY_NAME "SeLockMemoryPrivilege"
+#define SE_INCREASE_QUOTA_NAME "SeIncreaseQuotaPrivilege"
+#define SE_UNSOLICITED_INPUT_NAME "SeUnsolicitedInputPrivilege"
+#define SE_MACHINE_ACCOUNT_NAME "SeMachineAccountPrivilege"
+#define SE_TCB_NAME "SeTcbPrivilege"
+#define SE_SECURITY_NAME "SeSecurityPrivilege"
+#define SE_TAKE_OWNERSHIP_NAME "SeTakeOwnershipPrivilege"
+#define SE_LOAD_DRIVER_NAME "SeLoadDriverPrivilege"
+#define SE_SYSTEM_PROFILE_NAME "SeSystemProfilePrivilege"
+#define SE_SYSTEMTIME_NAME "SeSystemtimePrivilege"
+#define SE_PROF_SINGLE_PROCESS_NAME "SeProfileSingleProcessPrivilege"
+#define SE_INC_BASE_PRIORITY_NAME "SeIncreaseBasePriorityPrivilege"
+#define SE_CREATE_PAGEFILE_NAME "SeCreatePagefilePrivilege"
+#define SE_CREATE_PERMANENT_NAME "SeCreatePermanentPrivilege"
+#define SE_BACKUP_NAME "SeBackupPrivilege"
+#define SE_RESTORE_NAME "SeRestorePrivilege"
+#define SE_SHUTDOWN_NAME "SeShutdownPrivilege"
+#define SE_DEBUG_NAME "SeDebugPrivilege"
+#define SE_AUDIT_NAME "SeAuditPrivilege"
+#define SE_SYSTEM_ENVIRONMENT_NAME "SeSystemEnvironmentPrivilege"
+#define SE_CHANGE_NOTIFY_NAME "SeChangeNotifyPrivilege"
+#define SE_REMOTE_SHUTDOWN_NAME "SeRemoteShutdownPrivilege"
+
+#define SE_CREATE_TOKEN_LUID 2
+#define SE_ASSIGNPRIMARYTOKEN_LUID 3
+#define SE_LOCK_MEMORY_LUID 4
+#define SE_INCREASE_QUOTA_LUID 5
+#define SE_MACHINE_ACCOUNT_LUID 6
+#define SE_TCB_LUID 7
+#define SE_SECURITY_LUID 8
+#define SE_TAKE_OWNERSHIP_LUID 9
+#define SE_LOAD_DRIVER_LUID 10
+#define SE_SYSTEM_PROFILE_LUID 11
+#define SE_SYSTEMTIME_LUID 12
+#define SE_PROF_SINGLE_PROCESS_LUID 13
+#define SE_INC_BASE_PRIORITY_LUID 14
+#define SE_CREATE_PAGEFILE_LUID 15
+#define SE_CREATE_PERMANENT_LUID 16
+#define SE_BACKUP_LUID 17
+#define SE_RESTORE_LUID 18
+#define SE_SHUTDOWN_LUID 19
+#define SE_DEBUG_LUID 20
+#define SE_AUDIT_LUID 21
+#define SE_SYSTEM_ENVIRONMENT_LUID 22
+#define SE_CHANGE_NOTIFY_LUID 23
+#define SE_REMOTE_SHUTDOWN_LUID 24
+
+/*
+ * Privilege attributes
+ */
+#define SE_PRIVILEGE_DISABLED 0x00000000
+#define SE_PRIVILEGE_ENABLED_BY_DEFAULT 0x00000001
+#define SE_PRIVILEGE_ENABLED 0x00000002
+#define SE_PRIVILEGE_USED_FOR_ACCESS 0x80000000
+
+/*
+ * Privilege Set Control flags
+ */
+#define PRIVILEGE_SET_ALL_NECESSARY 1
+
+typedef struct smb_luid {
+ uint32_t lo_part;
+ uint32_t hi_part;
+} smb_luid_t;
+
+
+typedef struct smb_luid_attrs {
+ smb_luid_t luid;
+ uint32_t attrs;
+} smb_luid_attrs_t;
+
+
+typedef struct smb_privset {
+ uint32_t priv_cnt;
+ uint32_t control;
+ smb_luid_attrs_t priv[ANY_SIZE_ARRAY];
+} smb_privset_t;
+
+/*
+ * These are possible value for smb_privinfo_t.flags
+ *
+ * PF_PRESENTABLE Privilege is user visible
+ */
+#define PF_PRESENTABLE 0x1
+
+/*
+ * Structure for passing privilege name and id information around within
+ * the system. Note that we are only storing the low uint32_t of the LUID;
+ * the high part is always zero here.
+ */
+typedef struct smb_privinfo {
+ uint32_t id;
+ char *name;
+ char *display_name;
+ uint16_t flags;
+} smb_privinfo_t;
+
+smb_privinfo_t *smb_priv_getbyvalue(uint32_t id);
+smb_privinfo_t *smb_priv_getbyname(char *name);
+int smb_priv_presentable_num(void);
+int smb_priv_presentable_ids(uint32_t *ids, int num);
+smb_privset_t *smb_privset_new();
+int smb_privset_size();
+void smb_privset_init(smb_privset_t *privset);
+void smb_privset_free(smb_privset_t *privset);
+void smb_privset_copy(smb_privset_t *dst, smb_privset_t *src);
+void smb_privset_enable(smb_privset_t *privset, uint32_t id);
+int smb_privset_query(smb_privset_t *privset, uint32_t id);
+void smb_privset_log(smb_privset_t *privset);
+
+/* XDR routines */
+extern bool_t xdr_smb_luid_t();
+extern bool_t xdr_smb_luid_attrs_t();
+extern bool_t xdr_smb_privset_t();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_PRIVILEGE_H */
diff --git a/usr/src/uts/common/smbsrv/smb_secdesc.h b/usr/src/uts/common/smbsrv/smb_secdesc.h
new file mode 100644
index 0000000000..68b890a8e4
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_secdesc.h
@@ -0,0 +1,397 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_SECDESC_H
+#define _SMB_SECDESC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/acl.h>
+#include <smbsrv/ntsid.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Discretionary Access Control List (DACL)
+ *
+ * A Discretionary Access Control List (DACL), often abbreviated to
+ * ACL, is a list of access controls which either allow or deny access
+ * for users or groups to a resource. There is a list header followed
+ * by a list of access control entries (ACE). Each ACE specifies the
+ * access allowed or denied to a single user or group (identified by
+ * a SID).
+ *
+ * There is another access control list object called a System Access
+ * Control List (SACL), which is used to control auditing, but no
+ * support is provideed for SACLs at this time.
+ *
+ * ACL header format:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-------------------------------+---------------+---------------+
+ * | AclSize | Sbz1 | AclRevision |
+ * +-------------------------------+---------------+---------------+
+ * | Sbz2 | AceCount |
+ * +-------------------------------+-------------------------------+
+ *
+ * AclRevision specifies the revision level of the ACL. This value should
+ * be ACL_REVISION, unless the ACL contains an object-specific ACE, in which
+ * case this value must be ACL_REVISION_DS. All ACEs in an ACL must be at the
+ * same revision level.
+ *
+ * ACE header format:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------+-------+-------+---------------+---------------+
+ * | AceSize | AceFlags | AceType |
+ * +---------------+-------+-------+---------------+---------------+
+ *
+ * Access mask format:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------+---------------+-------------------------------+
+ * |G|G|G|G|Res'd|A| StandardRights| SpecificRights |
+ * |R|W|E|A| |S| | |
+ * +-+-------------+---------------+-------------------------------+
+ *
+ * typedef struct ACCESS_MASK {
+ * WORD SpecificRights;
+ * BYTE StandardRights;
+ * BYTE AccessSystemAcl : 1;
+ * BYTE Reserved : 3;
+ * BYTE GenericAll : 1;
+ * BYTE GenericExecute : 1;
+ * BYTE GenericWrite : 1;
+ * BYTE GenericRead : 1;
+ * } ACCESS_MASK;
+ *
+ */
+
+#define ACL_REVISION1 1
+#define ACL_REVISION2 2
+#define MIN_ACL_REVISION2 ACL_REVISION2
+#define ACL_REVISION3 3
+#define ACL_REVISION4 4
+#define MAX_ACL_REVISION ACL_REVISION4
+
+/*
+ * Current ACE and ACL revision Levels
+ */
+#define ACE_REVISION 1
+#define ACL_REVISION ACL_REVISION2
+#define ACL_REVISION_DS ACL_REVISION4
+
+
+#define ACCESS_ALLOWED_ACE_TYPE 0
+#define ACCESS_DENIED_ACE_TYPE 1
+#define SYSTEM_AUDIT_ACE_TYPE 2
+#define SYSTEM_ALARM_ACE_TYPE 3
+
+/*
+ * se_flags
+ * ----------
+ * Specifies a set of ACE type-specific control flags. This member can be a
+ * combination of the following values.
+ *
+ * CONTAINER_INHERIT_ACE: Child objects that are containers, such as
+ * directories, inherit the ACE as an effective ACE. The inherited
+ * ACE is inheritable unless the NO_PROPAGATE_INHERIT_ACE bit flag
+ * is also set.
+ *
+ * INHERIT_ONLY_ACE: Indicates an inherit-only ACE which does not control
+ * access to the object to which it is attached.
+ * If this flag is not set,
+ * the ACE is an effective ACE which controls access to the object
+ * to which it is attached.
+ * Both effective and inherit-only ACEs can be inherited
+ * depending on the state of the other inheritance flags.
+ *
+ * INHERITED_ACE: Windows 2000/XP: Indicates that the ACE was inherited.
+ * The system sets this bit when it propagates an
+ * inherited ACE to a child object.
+ *
+ * NO_PROPAGATE_INHERIT_ACE: If the ACE is inherited by a child object, the
+ * system clears the OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE
+ * flags in the inherited ACE.
+ * This prevents the ACE from being inherited by
+ * subsequent generations of objects.
+ *
+ * OBJECT_INHERIT_ACE: Noncontainer child objects inherit the ACE as an
+ * effective ACE. For child objects that are containers,
+ * the ACE is inherited as an inherit-only ACE unless the
+ * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+#define OBJECT_INHERIT_ACE 0x01
+#define CONTAINER_INHERIT_ACE 0x02
+#define NO_PROPOGATE_INHERIT_ACE 0x04
+#define INHERIT_ONLY_ACE 0x08
+#define INHERITED_ACE 0x10
+#define INHERIT_MASK_ACE 0x1F
+
+
+/*
+ * These flags are only used in system audit or alarm ACEs to
+ * indicate when an audit message should be generated, i.e.
+ * on successful access or on unsuccessful access.
+ */
+#define SUCCESSFUL_ACCESS_ACE_FLAG 0x40
+#define FAILED_ACCESS_ACE_FLAG 0x80
+
+
+/*
+ * AclSize is the size, in bytes, allocated for the ACL. This
+ * includes the ACL header, ACEs and remaining free space in
+ * the buffer. sl_acecnt is the number of ACES in the ACL.
+ */
+typedef struct smb_acl {
+ uint8_t sl_revision;
+ uint8_t sl_sbz1;
+ uint16_t sl_size;
+ uint16_t sl_acecnt;
+ uint16_t sl_sbz2;
+ /* immediately followed by ACE[]s */
+} smb_acl_t;
+
+
+/*
+ * se_type denotes the type of the ace, there are some predefined
+ * ACE types. se_size is the size, in bytes, of ACE. se_flags are
+ * the ACE flags for auditing and inheritance.
+ */
+typedef struct smb_ace_hdr {
+ uint8_t se_type;
+ uint8_t se_flags;
+ uint16_t se_size;
+} smb_ace_hdr_t;
+
+
+typedef struct smb_ace {
+ smb_ace_hdr_t se_header;
+ uint32_t se_mask;
+ nt_sid_t se_sid; /* variable length */
+} smb_ace_t;
+
+
+/*
+ * Security Descriptor (SD)
+ *
+ * Security descriptors provide protection for objects, for example
+ * files and directories. It identifies the owner and primary group
+ * (SIDs) and contains an access control list. When a user tries to
+ * access an object his SID is compared to the permissions in the
+ * DACL to determine if access should be allowed or denied. Note that
+ * this is a simplification because there are other factors, such as
+ * default behavior and privileges to be taken into account (see also
+ * access tokens).
+ *
+ * The boolean flags have the following meanings when set:
+ *
+ * SE_OWNER_DEFAULTED indicates that the SID pointed to by the Owner
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the SID with respect to inheritance of
+ * an owner.
+ *
+ * SE_GROUP_DEFAULTED indicates that the SID in the Group field was
+ * provided by a defaulting mechanism rather than explicitly provided
+ * by the original provider of the security descriptor. This may
+ * affect the treatment of the SID with respect to inheritance of a
+ * primary group.
+ *
+ * SE_DACL_PRESENT indicates that the security descriptor contains a
+ * discretionary ACL. If this flag is set and the Dacl field of the
+ * SECURITY_DESCRIPTOR is null, then a null ACL is explicitly being
+ * specified.
+ *
+ * SE_DACL_DEFAULTED indicates that the ACL pointed to by the Dacl
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the ACL with respect to inheritance of
+ * an ACL. This flag is ignored if the DaclPresent flag is not set.
+ *
+ * SE_SACL_PRESENT indicates that the security descriptor contains a
+ * system ACL pointed to by the Sacl field. If this flag is set and
+ * the Sacl field of the SECURITY_DESCRIPTOR is null, then an empty
+ * (but present) ACL is being specified.
+ *
+ * SE_SACL_DEFAULTED indicates that the ACL pointed to by the Sacl
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the ACL with respect to inheritance of
+ * an ACL. This flag is ignored if the SaclPresent flag is not set.
+ *
+ * SE_DACL_PROTECTED Prevents ACEs set on the DACL of the parent container
+ * (and any objects above the parent container in the directory hierarchy)
+ * from being applied to the object's DACL.
+ *
+ * SE_SACL_PROTECTED Prevents ACEs set on the SACL of the parent container
+ * (and any objects above the parent container in the directory hierarchy)
+ * from being applied to the object's SACL.
+ *
+ * Note that the SE_DACL_PRESENT flag needs to be present to set
+ * SE_DACL_PROTECTED and SE_SACL_PRESENT needs to be present to set
+ * SE_SACL_PROTECTED.
+ *
+ * SE_SELF_RELATIVE indicates that the security descriptor is in self-
+ * relative form. In this form, all fields of the security descriptor
+ * are contiguous in memory and all pointer fields are expressed as
+ * offsets from the beginning of the security descriptor.
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------------------------------------------------------+
+ * | Control |Reserved1 (SBZ)| Revision |
+ * +---------------------------------------------------------------+
+ * | Owner |
+ * +---------------------------------------------------------------+
+ * | Group |
+ * +---------------------------------------------------------------+
+ * | Sacl |
+ * +---------------------------------------------------------------+
+ * | Dacl |
+ * +---------------------------------------------------------------+
+ *
+ */
+
+#define SMB_OWNER_SECINFO 0x0001
+#define SMB_GROUP_SECINFO 0x0002
+#define SMB_DACL_SECINFO 0x0004
+#define SMB_SACL_SECINFO 0x0008
+#define SMB_ALL_SECINFO 0x000F
+#define SMB_ACL_SECINFO (SMB_DACL_SECINFO | SMB_SACL_SECINFO)
+
+#define SECURITY_DESCRIPTOR_REVISION 1
+
+
+#define SE_OWNER_DEFAULTED 0x0001
+#define SE_GROUP_DEFAULTED 0x0002
+#define SE_DACL_PRESENT 0x0004
+#define SE_DACL_DEFAULTED 0x0008
+#define SE_SACL_PRESENT 0x0010
+#define SE_SACL_DEFAULTED 0x0020
+#define SE_DACL_AUTO_INHERIT_REQ 0x0100
+#define SE_SACL_AUTO_INHERIT_REQ 0x0200
+#define SE_DACL_AUTO_INHERITED 0x0400
+#define SE_SACL_AUTO_INHERITED 0x0800
+#define SE_DACL_PROTECTED 0x1000
+#define SE_SACL_PROTECTED 0x2000
+#define SE_SELF_RELATIVE 0x8000
+
+#define SE_DACL_INHERITANCE_MASK 0x1500
+#define SE_SACL_INHERITANCE_MASK 0x2A00
+
+/*
+ * Security descriptor structures:
+ *
+ * smb_sd_t SD in SMB pointer form
+ * smb_sdbuf_t SD in SMB self-relative form
+ * smb_fssd_t SD in filesystem form
+ *
+ * We have to use two different structures to represent
+ * pointer form and self-relative form of the security
+ * descriptor because in SR form the offsets are 4-byte
+ * but in pointer form, pointers will be 8-byte in 64-bit
+ * kernel binary.
+ *
+ * Filesystems (e.g. ZFS/UFS) don't have something equivalent
+ * to SD. The items comprising a SMB SD are kept separately in
+ * filesystem. smb_fssd_t is introduced as a helper to provide
+ * the required abstraction for CIFS code.
+ */
+typedef struct smb_sd_hdr {
+ uint8_t sd_revision;
+ uint8_t sd_sbz1;
+ uint16_t sd_control;
+} smb_sd_hdr_t;
+
+typedef struct smb_sd {
+ smb_sd_hdr_t sd_hdr;
+ nt_sid_t *sd_owner; /* SID file owner */
+ nt_sid_t *sd_group; /* SID group (for POSIX) */
+ smb_acl_t *sd_sacl; /* ACL System (audits) */
+ smb_acl_t *sd_dacl; /* ACL Discretionary (perm) */
+} smb_sd_t;
+
+typedef struct smb_sdbuf {
+ smb_sd_hdr_t sd_hdr;
+ uint32_t sd_owner_offs; /* SID file owner */
+ uint32_t sd_group_offs; /* SID group (for POSIX) */
+ uint32_t sd_sacl_offs; /* ACL System (audits) */
+ uint32_t sd_dacl_offs; /* ACL Discretionary (perm) */
+} smb_sdbuf_t;
+
+/*
+ * values for smb_fssd.sd_flags
+ */
+#define SMB_FSSD_FLAGS_DIR 0x01
+
+typedef struct smb_fssd {
+ uint32_t sd_secinfo;
+ uint32_t sd_flags;
+ uid_t sd_uid;
+ gid_t sd_gid;
+ acl_t *sd_zdacl;
+ acl_t *sd_zsacl;
+} smb_fssd_t;
+
+void smb_sd_init(smb_sd_t *sd, uint8_t revision);
+void smb_sd_set_owner(smb_sd_t *sd, nt_sid_t *owner, int defaulted);
+void smb_sd_set_group(smb_sd_t *sd, nt_sid_t *group, int defaulted);
+void smb_sd_set_dacl(smb_sd_t *sd, int present, smb_acl_t *acl, int defaulted);
+void smb_sd_set_sacl(smb_sd_t *sd, int present, smb_acl_t *acl, int defaulted);
+
+nt_sid_t *smb_sd_get_owner(void *sd, int *defaulted);
+nt_sid_t *smb_sd_get_group(void *sd, int *defaulted);
+smb_acl_t *smb_sd_get_dacl(void *sd, int *present, int *defaulted);
+smb_acl_t *smb_sd_get_sacl(void *sd, int *present, int *defaulted);
+uint32_t smb_sd_get_secinfo(void *sd);
+uint32_t smb_sd_len(void *sd, uint32_t secinfo);
+void smb_sd_log(void *sd);
+void smb_sd_term(smb_sd_t *sd);
+
+smb_acl_t *smb_acl_from_zfs(acl_t *, uid_t, gid_t);
+uint32_t smb_acl_to_zfs(smb_acl_t *, uint32_t, int, acl_t **);
+int smb_acl_isvalid(smb_acl_t *, int);
+uint16_t smb_acl_len(smb_acl_t *);
+smb_acl_t *smb_acl_sort(smb_acl_t *);
+int smb_acl_copy(uint16_t, smb_acl_t *, smb_acl_t *);
+acl_t *smb_acl_inherit(acl_t *, int, int, uid_t);
+
+smb_ace_t *smb_ace_get(smb_acl_t *acl, uint16_t idx);
+int smb_ace_is_generic(int type);
+int smb_ace_is_access(int type);
+int smb_ace_is_audit(int type);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_SECDESC_H */
diff --git a/usr/src/uts/common/smbsrv/smb_svc_sm.h b/usr/src/uts/common/smbsrv/smb_svc_sm.h
new file mode 100644
index 0000000000..d843585edc
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_svc_sm.h
@@ -0,0 +1,162 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Structures and type definitions for the SMB module.
+ */
+
+#ifndef _SMBSRV_SMB_SVC_SM_H
+#define _SMBSRV_SMB_SVC_SM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * CIFS Service State Machine Definitions
+ */
+
+/*
+ * Events
+ *
+ * SMB_SVCEVT_UNDEFINED Invalid Event
+ * SMB_SVCEVT_OPEN Pseudo-device opened
+ * SMB_SVCEVT_CLOSE Pseudo-device closed
+ * SMB_SVCEVT_OPEN_SUCCESS Open actions completed successfully
+ * SMB_SVCEVT_OPEN_FAILED Open actions failed
+ * SMB_SVCEVT_CLOSE_SUCCESS Close actions completed successfully
+ * SMB_SVCEVT_CONNECT Connected and listening on SMB session port
+ * SMB_SVCEVT_DISCONNECT SMB connection dropped or failed to connect
+ * SMB_SVCEVT_CONFIG New config from smbd
+ * SMB_SVCEVT_CONFIG_SUCCESS Configuration updated successfully
+ * SMB_SVCEVT_CONFIG_FAILED Configuration update failed
+ * SMB_SVCEVT_SESSION_CREATE SMB port listener accepted a connection
+ * SMB_SVCEVT_SESSION_DELETE Session ended
+ * SMB_SVCEVT_MAX_EVENT Invalid Event
+ */
+
+typedef enum {
+ SMB_SVCEVT_UNDEFINED = 0,
+ SMB_SVCEVT_OPEN,
+ SMB_SVCEVT_CLOSE,
+ SMB_SVCEVT_OPEN_SUCCESS,
+ SMB_SVCEVT_OPEN_FAILED,
+ SMB_SVCEVT_CLOSE_SUCCESS,
+ SMB_SVCEVT_CONNECT,
+ SMB_SVCEVT_DISCONNECT,
+ SMB_SVCEVT_CONFIG,
+ SMB_SVCEVT_CONFIG_SUCCESS,
+ SMB_SVCEVT_CONFIG_FAILED,
+ SMB_SVCEVT_SESSION_CREATE,
+ SMB_SVCEVT_SESSION_DELETE,
+ SMB_SVCEVT_MAX_EVENT
+} smb_svcevt_t;
+
+/*
+ * States
+ *
+ * SMB_SVCSTATE_UNDEFINED Invalid state
+ * SMB_SVCSTATE_INIT Pseudo-driver loaded/idle
+ * SMB_SVCSTATE_OPENING Pseudo-driver opened, starting
+ * SMB_SVCSTATE_CONFIG_WAIT Waiting for configuration
+ * SMB_SVCSTATE_CONNECTING Waiting for socket bind to SMB
+ * SMB_SVCSTATE_ONLINE Online, accepting connections
+ * SMB_SVCSTATE_RECONFIGURING Updating config, no new connections
+ * SMB_SVCSTATE_DISCONNECTING Smbd requested shutdown, closing socket
+ * SMB_SVCSTATE_SESSION_CLOSE Shutting down, closing active sessions
+ * SMB_SVCSTATE_CLOSING Shutting down, releasing resources
+ * SMB_SVCSTATE_ERROR_SESSION_CLOSE Unexpected SMB socket error,
+ * closing active sessions
+ * SMB_SVCSTATE_ERROR_CLOSING Error, releasing resources
+ * SMB_SVCSTATE_MAX_STATE Invalid state
+ */
+typedef enum {
+ SMB_SVCSTATE_UNDEFINED = 0,
+ SMB_SVCSTATE_INIT,
+ SMB_SVCSTATE_OPENING,
+ SMB_SVCSTATE_CONFIG_WAIT,
+ SMB_SVCSTATE_CONNECTING,
+ SMB_SVCSTATE_ONLINE,
+ SMB_SVCSTATE_RECONFIGURING,
+ SMB_SVCSTATE_DISCONNECTING,
+ SMB_SVCSTATE_SESSION_CLOSE,
+ SMB_SVCSTATE_ERROR_SESSION_CLOSE,
+ SMB_SVCSTATE_CLOSING,
+ SMB_SVCSTATE_ERROR_CLOSING,
+ SMB_SVCSTATE_ERROR,
+ SMB_SVCSTATE_MAX_STATE
+} smb_svcstate_t;
+
+#ifdef _KERNEL
+/* Event context */
+typedef struct {
+ smb_svcevt_t sec_event;
+ uintptr_t sec_info;
+} smb_event_ctx_t;
+
+/* Service state machine context */
+typedef struct {
+ taskq_t *ssc_taskq;
+ krwlock_t ssc_state_rwlock;
+ kmutex_t ssc_state_cv_mutex;
+ kcondvar_t ssc_state_cv;
+ int ssc_started;
+ int ssc_start_error;
+ int ssc_disconnect_error;
+ smb_svcstate_t ssc_state;
+ smb_svcstate_t ssc_last_state; /* Debug only */
+ int ssc_session_creates_waiting;
+ int ssc_deferred_session_count;
+ list_t ssc_deferred_sessions;
+ int ssc_active_session_count;
+ list_t ssc_active_sessions;
+ uint32_t ssc_error_no_resources;
+} smb_svc_sm_ctx_t;
+
+/*
+ * SMB service state machine API
+ */
+
+extern int smb_svcstate_sm_init(smb_svc_sm_ctx_t *svc_sm);
+extern void smb_svcstate_sm_fini(smb_svc_sm_ctx_t *svc_sm);
+extern int smb_svcstate_sm_start(smb_svc_sm_ctx_t *svc_sm);
+extern void smb_svcstate_sm_stop(smb_svc_sm_ctx_t *svc_sm);
+extern boolean_t smb_svcstate_sm_busy(void);
+extern void smb_svcstate_event(smb_svcevt_t event, uintptr_t event_info);
+extern void smb_svcstate_lock_read(smb_svc_sm_ctx_t *svc_sm);
+extern void smb_svcstate_unlock(smb_svc_sm_ctx_t *svc_sm);
+extern smb_session_t *smb_svcstate_session_getnext(smb_svc_sm_ctx_t *svc_sm,
+ smb_session_t *prev);
+extern int smb_svcstate_session_count(smb_svc_sm_ctx_t *svc_sm);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_SVC_SM_H */
diff --git a/usr/src/uts/common/smbsrv/smb_token.h b/usr/src/uts/common/smbsrv/smb_token.h
new file mode 100644
index 0000000000..c2bea1e9a9
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_token.h
@@ -0,0 +1,224 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_TOKEN_H
+#define _SMB_TOKEN_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <smbsrv/netrauth.h>
+#include <smbsrv/smb_privilege.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * User Session Key
+ *
+ * This is part of the MAC key which is required for signing SMB messages.
+ */
+typedef struct smb_session_key {
+ uint8_t data[16];
+} smb_session_key_t;
+
+/*
+ * Access Token
+ *
+ * An access token identifies a user, the user's privileges and the
+ * list of groups of which the user is a member. This information is
+ * used when access is requested to an object by comparing this
+ * information with the DACL in the object's security descriptor.
+ *
+ * Only group attributes are defined. No user attributes defined.
+ */
+
+#define SE_GROUP_MANDATORY 0x00000001
+#define SE_GROUP_ENABLED_BY_DEFAULT 0x00000002
+#define SE_GROUP_ENABLED 0x00000004
+#define SE_GROUP_OWNER 0x00000008
+#define SE_GROUP_USE_FOR_DENY_ONLY 0x00000010
+#define SE_GROUP_LOGON_ID 0xC0000000
+
+typedef struct smb_sid_attrs {
+ uint32_t attrs;
+ nt_sid_t *sid;
+} smb_sid_attrs_t;
+
+/*
+ * smb_id_t consists of both the Windows security identifier
+ * and its corresponding POSIX/ephemeral ID.
+ */
+typedef struct smb_id {
+ smb_sid_attrs_t i_sidattr;
+ uid_t i_id;
+} smb_id_t;
+
+/*
+ * Windows groups (each group SID is associated with a POSIX/ephemeral
+ * gid.
+ */
+typedef struct smb_win_grps {
+ uint16_t wg_count;
+ smb_id_t wg_groups[ANY_SIZE_ARRAY];
+} smb_win_grps_t;
+
+/*
+ * Access Token Flags
+ *
+ * SMB_ATF_GUEST Token belongs to guest user
+ * SMB_ATF_ANON Token belongs to anonymous user
+ * and it's only good for IPC Connection.
+ * SMB_ATF_POWERUSER Token belongs to a Power User member
+ * SMB_ATF_BACKUPOP Token belongs to a Power User member
+ * SMB_ATF_ADMIN Token belongs to a Domain Admins member
+ */
+#define SMB_ATF_GUEST 0x00000001
+#define SMB_ATF_ANON 0x00000002
+#define SMB_ATF_POWERUSER 0x00000004
+#define SMB_ATF_BACKUPOP 0x00000008
+#define SMB_ATF_ADMIN 0x00000010
+
+#define SMB_POSIX_GRPS_SIZE(n) \
+ (sizeof (smb_posix_grps_t) + (n - 1) * sizeof (gid_t))
+/*
+ * It consists of the primary and supplementary POSIX groups.
+ */
+typedef struct smb_posix_grps {
+ uint32_t pg_ngrps;
+ gid_t pg_grps[ANY_SIZE_ARRAY];
+} smb_posix_grps_t;
+
+/*
+ * Token Structure.
+ *
+ * This structure contains information of a user. There should be one
+ * unique token per user per session per client. The information
+ * provided will either give or deny access to shares, files or folders.
+ */
+typedef struct smb_token {
+ smb_id_t *tkn_user;
+ smb_id_t *tkn_owner;
+ smb_id_t *tkn_primary_grp;
+ smb_win_grps_t *tkn_win_grps;
+ smb_privset_t *tkn_privileges;
+ char *tkn_account_name;
+ char *tkn_domain_name;
+ uint32_t tkn_flags;
+ uint32_t tkn_audit_sid;
+ smb_session_key_t *tkn_session_key;
+ smb_posix_grps_t *tkn_posix_grps;
+} smb_token_t;
+
+/*
+ * This is the max buffer length for holding certain fields of
+ * any access token: domain, account, workstation, and IP with the
+ * format as show below:
+ * [domain name]\[user account] [workstation] (IP)
+ *
+ * This is not meant to be the maximum buffer length for holding
+ * the entire context of a token.
+ */
+#define NTTOKEN_BASIC_INFO_MAXLEN (SMB_PI_MAX_DOMAIN + SMB_PI_MAX_USERNAME \
+ + SMB_PI_MAX_HOST + INET_ADDRSTRLEN + 8)
+
+/*
+ * Information returned by an RPC call is allocated on an internal heap
+ * which is deallocated before returning from the interface call. The
+ * smb_userinfo structure provides a useful common mechanism to get the
+ * information back to the caller. It's like a compact access token but
+ * only parts of it are filled in by each RPC so the content is call
+ * specific.
+ */
+typedef struct smb_rid_attrs {
+ uint32_t rid;
+ uint32_t attributes;
+} smb_rid_attrs_t;
+
+#define SMB_UINFO_FLAG_ANON 0x01
+#define SMB_UINFO_FLAG_LADMIN 0x02 /* Local admin */
+#define SMB_UINFO_FLAG_DADMIN 0x04 /* Domain admin */
+#define SMB_UINFO_FLAG_ADMIN (SMB_UINFO_FLAG_LADMIN | SMB_UINFO_FLAG_DADMIN)
+
+/*
+ * This structure is mainly used where there's some
+ * kind of user related interaction with a domain
+ * controller via different RPC calls.
+ */
+typedef struct smb_userinfo {
+ uint16_t sid_name_use;
+ uint32_t rid;
+ uint32_t primary_group_rid;
+ char *name;
+ char *domain_name;
+ nt_sid_t *domain_sid;
+ uint32_t n_groups;
+ smb_rid_attrs_t *groups;
+ uint32_t n_other_grps;
+ smb_sid_attrs_t *other_grps;
+ smb_session_key_t *session_key;
+
+ nt_sid_t *user_sid;
+ nt_sid_t *pgrp_sid;
+ uint32_t flags;
+} smb_userinfo_t;
+
+/* XDR routines */
+extern bool_t xdr_smb_session_key_t();
+extern bool_t xdr_netr_client_t();
+extern bool_t xdr_nt_sid_t();
+extern bool_t xdr_smb_sid_attrs_t();
+extern bool_t xdr_smb_id_t();
+extern bool_t xdr_smb_win_grps_t();
+extern bool_t xdr_smb_posix_grps_t();
+extern bool_t xdr_smb_token_t();
+
+
+#ifndef _KERNEL
+smb_token_t *smb_logon(netr_client_t *clnt);
+void smb_token_destroy(smb_token_t *token);
+uint8_t *smb_token_mkselfrel(smb_token_t *obj, uint32_t *len);
+netr_client_t *netr_client_mkabsolute(uint8_t *buf, uint32_t len);
+#else /* _KERNEL */
+smb_token_t *smb_token_mkabsolute(uint8_t *buf, uint32_t len);
+void smb_token_free(smb_token_t *token);
+uint8_t *netr_client_mkselfrel(netr_client_t *obj, uint32_t *len);
+#endif /* _KERNEL */
+
+int smb_token_query_privilege(smb_token_t *token, int priv_id);
+/*
+ * Diagnostic routines:
+ * smb_token_print: write the contents of a token to the log.
+ * smb_token_log: log message is prefixed with token basic info.
+ */
+void smb_token_print(smb_token_t *token);
+void smb_token_log(int level, smb_dr_user_ctx_t *user_ctx, char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SMB_TOKEN_H */
diff --git a/usr/src/uts/common/smbsrv/smb_vops.h b/usr/src/uts/common/smbsrv/smb_vops.h
new file mode 100644
index 0000000000..8bc18b73ca
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_vops.h
@@ -0,0 +1,386 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_VOPS_H
+#define _SMBSRV_SMB_VOPS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Common file system interfaces and definitions.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/mntent.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/refstr.h>
+#include <sys/acl.h>
+#include <smbsrv/smb_i18n.h>
+#include <smbsrv/smb_fsd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ROOTVOL ""
+#define CHKPNT ".chkpnt"
+#define XATTR_DIR "xattr_dir"
+
+#define SMB_STREAM_PREFIX "SUNWsmb"
+#define SMB_STREAM_PREFIX_LEN (sizeof (SMB_STREAM_PREFIX) - 1)
+
+#define MANGLE_NAMELEN 14
+#define SMB_EOF 0x7FFFFFFF
+
+/*
+ * SMB_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
+ * VOP_READDIR. Its value is the size of the maximum possible edirent_t
+ * for solaris. The EDIRENT_RECLEN macro returns the size of edirent_t
+ * required for a given name length. MAXNAMELEN is the maximum
+ * filename length allowed in Solaris. The first two EDIRENT_RECLEN()
+ * macros are to allow for . and .. entries -- just a minor tweak to try
+ * and guarantee that buffer we give to VOP_READDIR will be large enough
+ * to hold ., .., and the largest possible solaris edirent_t.
+ *
+ * This bufsize will also be used when reading dirent64_t entries.
+ */
+
+#define SMB_MINLEN_RDDIR_BUF \
+ (EDIRENT_RECLEN(1) + EDIRENT_RECLEN(2) + EDIRENT_RECLEN(MAXNAMELEN))
+
+/*
+ * DP_TO_EDP
+ *
+ * Fill in an edirent_t structure with information from a dirent64_t.
+ * This allows the use of an edirent_t in code where both edirent_t's
+ * and dirent64_t's are manipulated.
+ */
+
+#define DP_TO_EDP(dp, edp) \
+{ \
+ ASSERT((dp)); \
+ ASSERT((edp)); \
+ (edp)->ed_ino = (dp)->d_ino; \
+ (edp)->ed_off = (dp)->d_off; \
+ (edp)->ed_eflags = 0; \
+ (edp)->ed_reclen = (dp)->d_reclen; \
+ (void) strlcpy((edp)->ed_name, (dp)->d_name, MAXNAMELEN); \
+}
+
+/*
+ * DP_ADVANCE
+ *
+ * In readdir operations, advance to read the next entry in a buffer
+ * returned from VOP_READDIR. The entries are of type dirent64_t.
+ */
+
+#define DP_ADVANCE(dp, dirbuf, numbytes) \
+{ \
+ ASSERT((dp)); \
+ if ((dp)->d_reclen == 0) { \
+ (dp) = NULL; \
+ } else { \
+ (dp) = (dirent64_t *)((char *)(dp) + (dp)->d_reclen); \
+ if ((dp) >= (dirent64_t *)((dirbuf) + (numbytes))) \
+ (dp) = NULL; \
+ } \
+}
+
+/*
+ * EDP_ADVANCE
+ *
+ * In readdir operations, advance to read the next entry in a buffer
+ * returned from VOP_READDIR. The entries are of type edirent_t.
+ */
+
+#define EDP_ADVANCE(edp, dirbuf, numbytes) \
+{ \
+ ASSERT((edp)); \
+ if ((edp)->ed_reclen == 0) { \
+ (edp) = NULL; \
+ } else { \
+ (edp) = (edirent_t *)((char *)(edp) + (edp)->ed_reclen);\
+ if ((edp) >= (edirent_t *)((dirbuf) + (numbytes))) \
+ (edp) = NULL; \
+ } \
+}
+
+struct smb_node;
+struct smb_request;
+
+/*
+ * Note: When specifying the mask for an smb_attr_t,
+ * the sa_mask, and not the sa_vattr.va_mask, should be
+ * filled in. The #define's that should be used are those
+ * prefixed with SMB_AT_*. Only FSIL routines should
+ * manipulate the sa_vattr.va_mask field.
+ */
+typedef struct smb_attr {
+ uint_t sa_mask; /* For both vattr and CIFS attr's */
+ vattr_t sa_vattr; /* Legacy vattr */
+ uint32_t sa_dosattr; /* DOS attributes */
+ timestruc_t sa_crtime; /* Creation time */
+} smb_attr_t;
+
+#define SMB_AT_TYPE 0x00001
+#define SMB_AT_MODE 0x00002
+#define SMB_AT_UID 0x00004
+#define SMB_AT_GID 0x00008
+#define SMB_AT_FSID 0x00010
+#define SMB_AT_NODEID 0x00020
+#define SMB_AT_NLINK 0x00040
+#define SMB_AT_SIZE 0x00080
+#define SMB_AT_ATIME 0x00100
+#define SMB_AT_MTIME 0x00200
+#define SMB_AT_CTIME 0x00400
+#define SMB_AT_RDEV 0x00800
+#define SMB_AT_BLKSIZE 0x01000
+#define SMB_AT_NBLOCKS 0x02000
+#define SMB_AT_SEQ 0x08000
+
+#define SMB_AT_DOSATTR 0x00100000
+#define SMB_AT_CRTIME 0x00200000
+#define SMB_AT_SMB 0x00300000
+
+#define SMB_AT_ALL (SMB_AT_TYPE|SMB_AT_MODE|SMB_AT_UID|SMB_AT_GID|\
+ SMB_AT_FSID|SMB_AT_NODEID|SMB_AT_NLINK|SMB_AT_SIZE|\
+ SMB_AT_ATIME|SMB_AT_MTIME|SMB_AT_CTIME|SMB_AT_RDEV|\
+ SMB_AT_BLKSIZE|SMB_AT_NBLOCKS|SMB_AT_SEQ|SMB_AT_SMB)
+
+/*
+ * DOS Attributes
+ * Previously defined in smbsrv/ntaccess.h
+ */
+
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_ENCRYPTED 0x00000040
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
+#define FILE_ATTRIBUTE_COMPRESSED 0x00000800
+#define FILE_ATTRIBUTE_OFFLINE 0x00001000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
+#define FILE_ATTRIBUTE_MODIFIED 0x00004000
+#define FILE_ATTRIBUTE_QUARANTINED 0x00008000
+#define FILE_ATTRIBUTE_VALID_FLAGS 0x0000dfb7
+#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x0000dfa7
+#define FILE_ATTRIBUTE_MASK 0x00003FFF
+
+
+#ifndef PBSHORTCUT
+/* remove from libsmbbase */
+#define FHF_SMB 0x02
+#endif
+
+/* DOS specific attribute bits */
+#define FSA_DOSATTR (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM | \
+ FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN)
+
+/*
+ * File types (FSA_FMT) and permissions (FSA_MODMASK).
+ * Restricted to lower 16-bits due to FS inode definitions.
+ */
+#define FSA_MTIME_SEQ 0x10000000
+/* #define FSA_USTREAM_SKIPSEQ 0x10000000 */
+#define FSA_UNDEF 0007000
+#define FSA_SUID 0004000
+#define FSA_SGID 0002000
+#define FSA_STICKY 0001000
+#define FSA_UPERM 0000700
+#define FSA_UREAD 0000400
+#define FSA_UWRITE 0000200
+#define FSA_UEXEC 0000100
+#define FSA_GPERM 0000070
+#define FSA_GREAD 0000040
+#define FSA_GWRITE 0000020
+#define FSA_GEXEC 0000010
+#define FSA_OPERM 0000007
+#define FSA_OREAD 0000004
+#define FSA_OWRITE 0000002
+#define FSA_OEXEC 0000001
+
+
+#define FSA_PERM_MASK (FSA_UPERM | FSA_GPERM | FSA_OPERM)
+#define FSA_MODMASK 0007777 /* mutable by fs_setaddr() */
+#define FSA_DIR_PERM 0777 /* default permission for new */
+ /* directories */
+#define FSA_FILE_PERM 0666 /* default permission for new files */
+
+#define FCM_CREATEVERFSIZE 8
+
+/* stability for write */
+#define FSSTAB_UNSTABLE 0
+#define FSSTAB_DATA_SYNC 1
+#define FSSTAB_FILE_SYNC 2
+
+/*
+ * fs_online flags (meaning when set):
+ *
+ * FSOLF_NOMON Do not monitor this FS.
+ * FSOLF_UTF8_NAME All names in this FS should be in UTF-8 format.
+ * FSOLF_SYNCNOW Flush all dirty blocks for this FS.
+ * FSOLF_NODRIVE Do not assign a drive letter to this FS.
+ * FSOLF_STREAMS This FS supports streams.
+ * FSOLF_DISABLE_OPLOCKS Oplocks are disabled on this FS.
+ * FSOLF_RM_PENDING The volume is being removed (unmounted, deleted,
+ * zapped etc.).
+ * FSOLF_MDCACHE Enable VFS meta-data caching for this FS.
+ * FSOLF_ERROR Inconsistencies detected in the volume.
+ * FSOLF_SYSTEM This is a system volume, no del, ren, dtq, quotas etc
+ * allowed
+ * FSOLF_COMPLIANT This volume is compliant; supports retention on
+ * immutable and unlinkable (no delete, no rename).
+ * FSOLF_LITE_COMPLIANT This volume has a less-stringent compliant capability
+ * FSOLF_SYSAUDIT This volume supports the storing of system audit logs
+ */
+#define FSOLF_NOEXPORT 0x00000001
+#define FSOLF_READONLY 0x00000002
+#define FSOLF_LOCKED 0x00000004
+#define FSOLF_NOMON 0x00000008
+#define FSOLF_NOSHOWMNT 0x00000010
+#define FSOLF_CASE_INSENSITIVE 0x00000020
+#define FSOLF_SUPPORTS_ACLS 0x00000040
+#define FSOLF_UTF8_NAME 0x00000080
+#define FSOLF_MIRRORING 0x00000100
+#define FSOLF_SYNCNOW 0x00000200
+#define FSOLF_NODRIVE 0x00000400
+#define FSOLF_OFFLINE 0x00000800
+#define FSOLF_STREAMS 0x00001000
+#define FSOLF_DISABLE_OPLOCKS 0x00002000
+#define FSOLF_RM_PENDING 0x00004000
+#define FSOLF_MDCACHE 0x00008000
+#define FSOLF_MNT_IN_PROGRESS 0x00010000
+#define FSOLF_NO_ATIME 0x00020000
+#define FSOLF_ERROR 0x00040000
+#define FSOLF_SYSTEM 0x00080000
+#define FSOLF_COMPLIANT 0x00100000
+#define FSOLF_LITE_COMPLIANT 0x00200000
+#define FSOLF_SYSAUDIT 0x00400000
+#define FSOLF_NO_CASE_SENSITIVE 0x00800000
+#define FSOLF_XVATTR 0x02000000
+#define FSOLF_DIRENTFLAGS 0x04000000
+
+/*
+ * The following flags are shared between live and checkpoint volumes.
+ */
+#define FSOLF_SHARED_FLAGS (FSOLF_CASE_INSENSITIVE | FSOLF_UTF8_NAME | \
+ FSOLF_STREAMS)
+
+/*
+ * the following flags are dynamically set and reset so should not be stored
+ * in volume.
+ */
+#define FSOLF_MASK ~(FSOLF_NOEXPORT | FSOLF_READONLY | \
+ FSOLF_LOCKED | FSOLF_NOMON | \
+ FSOLF_SYNCNOW | FSOLF_NOSHOWMNT | \
+ FSOLF_NODRIVE | FSOLF_RM_PENDING)
+
+/*
+ * case_flag: set FHF_IGNORECASE for case-insensitive compare.
+ */
+
+struct fs_stream_info {
+ char name[MAXPATHLEN];
+ uint64_t size;
+};
+
+int fhopen(const struct smb_node *, int);
+
+extern int smb_vop_open(vnode_t **vpp, int mode, cred_t *cred,
+ caller_context_t *ct);
+extern int smb_vop_close(vnode_t *vp, int flag, cred_t *cred,
+ caller_context_t *ct);
+extern int smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_write(vnode_t *vp, uio_t *uiop, unsigned int *flag,
+ uint32_t *lcount, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp,
+ smb_attr_t *ret_attr, int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp,
+ smb_attr_t *set_attr, int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp,
+ cred_t *cr);
+extern void smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp,
+ cred_t *cr);
+extern int smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp,
+ char *od_name, int flags, vnode_t *rootvp, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr,
+ vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct,
+ vsecattr_t *vsap);
+extern int smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp,
+ char *to_name, int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr,
+ vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct,
+ vsecattr_t *vsap);
+extern int smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name,
+ int *namelen, ino64_t *inop, vnode_t **vpp, char *od_name, int flags,
+ cred_t *cr, caller_context_t *ct);
+extern int smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_getdents(struct smb_node *dir_snode, uint32_t *cookiep,
+ uint64_t *verifierp, int32_t *dircountp, char *arg, char *pattern,
+ uint32_t flags, struct smb_request *sr, cred_t *cr,
+ caller_context_t *ct);
+extern int smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr);
+extern int smb_vop_stream_lookup(vnode_t *fvp, char *stream_name,
+ vnode_t **vpp, char *name, vnode_t **xattrdirvpp, int flags,
+ vnode_t *rootvp, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_stream_create(vnode_t *fvp, char *stream_name,
+ smb_attr_t *attr, vnode_t **vpp, vnode_t **xattrdirvpp, int flags,
+ cred_t *cr, caller_context_t *ct);
+extern int smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags,
+ cred_t *cr, caller_context_t *ct);
+extern int smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep,
+ struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvp,
+ int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp,
+ int flags, cred_t *cr, caller_context_t *ct);
+extern int smb_vop_traverse_check(vnode_t **vpp);
+
+int smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
+ cred_t *cr, caller_context_t *ct);
+int smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr,
+ caller_context_t *ct);
+acl_type_t smb_vop_acl_type(vnode_t *vp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_VOPS_H */
diff --git a/usr/src/uts/common/smbsrv/smb_winpipe.h b/usr/src/uts/common/smbsrv/smb_winpipe.h
new file mode 100755
index 0000000000..93a176c101
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_winpipe.h
@@ -0,0 +1,84 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_WINPIPE_H_
+#define _SMB_WINPIPE_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef _KERNEL
+#include <stddef.h>
+#endif /* _KERNEL */
+
+#include <sys/thread.h>
+#include <sys/door.h>
+#include <sys/disp.h>
+#include <sys/systm.h>
+#include <sys/processor.h>
+#include <sys/socket.h>
+#include <inet/common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB_IO_MAX_SIZE 32
+#define SMB_MAX_PIPENAMELEN 32
+
+#define SMB_WINPIPE_DOOR_DOWN_PATH "/var/run/winpipe_doordown"
+#define SMB_WINPIPE_DOOR_UP_PATH "/var/run/winpipe_doorup"
+
+#define SMB_DOWNCALLINFO_MAGIC 0x19121969
+#define SMB_MLSVC_DOOR_VERSION 1
+
+#define SMB_RPC_FLUSH_MAGIC 0x123456CC
+#define SMB_RPC_TRANSACT 1
+#define SMB_RPC_READ 2
+#define SMB_RPC_WRITE 3
+#define SMB_RPC_FLUSH 4
+
+typedef struct {
+ uint64_t md_tid; /* caller's thread id */
+ uint16_t md_version; /* version number, start with 1 */
+ uint16_t md_call_type; /* transact, read, write, flush */
+ uint32_t md_length; /* max bytes to return */
+ uint64_t md_reserved;
+} mlsvc_door_hdr_t;
+
+typedef struct {
+ uint32_t sp_pipeid;
+ char sp_pipename[SMB_MAX_PIPENAMELEN];
+ int32_t sp_datalen;
+ char sp_data[1]; /* any size buffer */
+} smb_pipe_t;
+
+void smb_downcall_service(void *, door_arg_t *, void (**)(void *, void *),
+ void **, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMB_WINPIPE_H_ */
diff --git a/usr/src/uts/common/smbsrv/smb_xdr.h b/usr/src/uts/common/smbsrv/smb_xdr.h
new file mode 100644
index 0000000000..31a7b3e72e
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMB_XDR_H
+#define _SMBSRV_SMB_XDR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rpc/xdr.h>
+#include <sys/param.h>
+
+typedef struct smb_dr_kshare {
+ int32_t k_op;
+ char *k_path;
+ char *k_sharename;
+} smb_dr_kshare_t;
+
+#ifdef _KERNEL
+#define xdr_int8_t xdr_char
+#define xdr_uint8_t xdr_u_char
+#define xdr_int16_t xdr_short
+#define xdr_uint16_t xdr_u_short
+
+extern bool_t xdr_u_char(XDR *xdrs, uchar_t *cp);
+extern bool_t xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
+ uint_t elemsize, xdrproc_t xdr_elem);
+
+smb_dr_kshare_t *smb_share_mkabsolute(uint8_t *buf, uint32_t len);
+#else
+uint8_t *smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len);
+#endif /* _KERNEL */
+
+/* null-terminated string buffer */
+typedef struct smb_dr_string {
+ char *buf;
+} smb_dr_string_t;
+
+/* byte buffer (non-null terminated) */
+typedef struct smb_dr_bytes {
+ uint32_t bytes_len;
+ uint8_t *bytes_val;
+} smb_dr_bytes_t;
+
+/*
+ * smb_dr_user_ctx/smb_dr_ulist data structures are defined to transfer
+ * the necessary information for all connected users via door to
+ * mlsvc. The smb_dr_user_ctx provides user context that will be part
+ * of the MLSVC rpc context.
+ *
+ * Both SMB session ID and SMB UID of smb_dr_user_ctx_t are used to
+ * uniquely identified the corresponding in-kernel SMB user object.
+ */
+#define SMB_DR_MAX_USERS 50
+typedef struct smb_dr_user_ctx {
+ uint64_t du_session_id;
+ uint16_t du_uid;
+ uint16_t du_domain_len;
+ char *du_domain;
+ uint16_t du_account_len;
+ char *du_account;
+ uint16_t du_workstation_len;
+ char *du_workstation;
+ uint32_t du_ipaddr;
+ int32_t du_native_os;
+ int64_t du_logon_time;
+ uint32_t du_flags;
+} smb_dr_user_ctx_t;
+
+typedef struct smb_dr_ulist {
+ uint32_t dul_cnt;
+ smb_dr_user_ctx_t dul_users[SMB_DR_MAX_USERS];
+} smb_dr_ulist_t;
+
+/* xdr routines for common door arguments/results */
+extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *);
+extern bool_t xdr_smb_dr_bytes_t(XDR *, smb_dr_bytes_t *);
+extern bool_t xdr_smb_dr_user_ctx_t(XDR *, smb_dr_user_ctx_t *);
+extern bool_t xdr_smb_dr_ulist_t(XDR *, smb_dr_ulist_t *);
+extern bool_t xdr_smb_dr_kshare_t(XDR *, smb_dr_kshare_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMB_XDR_H */
diff --git a/usr/src/uts/common/smbsrv/smbfmt.h b/usr/src/uts/common/smbsrv/smbfmt.h
new file mode 100644
index 0000000000..4f7e852e14
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbfmt.h
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMBFMT_H
+#define _SMBSRV_SMBFMT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * SMB message header formats.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMB_RESUME_KEY_FMT ".11ccl4."
+#define SMB_HEADER_ED_FMT "Mbbbwbww8c2.wwww"
+#define SMB_HEADER_ED_LEN (4+1+1+1+2+1+2+12+2+2+2+2)
+#define SMB_TRANSHDR_ED_FMT "wwwwb.wl2.wwwwb."
+#define SMB_TRANSHDR_ED_LEN (2+2+2+2+1+1+2+4+2+2+2+2+2+1+1)
+#define SMB_TRANSSHDR_ED_FMT "wwwwwwwww"
+#define SMB_TRANSSHDR_ED_LEN (2+2+2+2+2+2+2+2)
+#define SMB_TRANS2SHDR_ED_FMT "wwwwwwwww"
+#define SMB_TRANS2SHDR_ED_LEN (2+2+2+2+2+2+2+2+2)
+/* There is something wrong with this. Should be 38 bytes. It is 37 bytes */
+#define SMB_NT_TRANSHDR_ED_FMT "b2.llllllllbw"
+#define SMB_NT_TRANSHDR_ED_LEN (1+2+4+4+4+4+4+4+4+4+1+2)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBFMT_H */
diff --git a/usr/src/uts/common/smbsrv/smbinfo.h b/usr/src/uts/common/smbsrv/smbinfo.h
new file mode 100644
index 0000000000..d6a7a03a9a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbinfo.h
@@ -0,0 +1,181 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMBINFO_H
+#define _SMBSRV_SMBINFO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Native OS types used in SmbSessionSetupX.
+ */
+#ifndef NATIVE_OS_DEFINED
+#define NATIVE_OS_DEFINED
+
+#define NATIVE_OS_UNKNOWN 0x00000000
+#define NATIVE_OS_NT4_0 0x00000001
+#define NATIVE_OS_WIN95 0x00000002
+#define NATIVE_OS_OTHER 0x00000003
+#define NATIVE_OS_NT5_0 0x00000004
+#define NATIVE_OS_NT5_1 0x00000005
+#define NATIVE_OS_MACOS 0x00000006
+
+/*
+ * Backward compatibility aliases.
+ */
+#define NATIVE_OS_WINNT NATIVE_OS_NT4_0
+#define NATIVE_OS_WIN2000 NATIVE_OS_NT5_0
+#define NATIVE_OS_WINXP NATIVE_OS_NT5_1
+
+#endif /* NATIVE_OS_DEFINED */
+
+
+/*
+ * Native lanman types in SmbSessionSetupX. Note that these values
+ * are not directly related to the negotiated protocol dialect.
+ */
+#ifndef NATIVE_LANMAN_DEFINED
+#define NATIVE_LANMAN_DEFINED
+
+#define NATIVE_LM_NONE 0x00000000
+#define NATIVE_LM_NT 0x00000001
+#define NATIVE_LM_WIN2000 0x00000002
+
+#endif /* NATIVE_LANMAN_DEFINED */
+
+
+/* PDC types to be used in user authentication process */
+
+#define PDC_UNKNOWN 0
+#define PDC_WINNT 1
+#define PDC_WIN2000 2
+#define PDC_WINXP 3
+#define PDC_SAMBA 4
+
+/*
+ * Please replace the use of MAX_NETWORKS with SMB_PI_MAX_NETWORKS if
+ * you find it used in conjunction with smbparm_info and maybe one day
+ * there will be just a single definition (here) throughout the code.
+ */
+#ifndef MAX_NETWORKS
+#define MAX_NETWORKS 36
+#endif /* MAX_NETWORKS */
+
+#define SMB_PI_MAX_NETWORKS 36
+#define SMB_PI_MAX_WINS 2
+
+#define SMB_SECMODE_WORKGRP 1
+#define SMB_SECMODE_DOMAIN 2
+
+#define SMB_PI_MAX_HOST 48
+#define SMB_PI_MAX_DOMAIN 48
+#define SMB_PI_MAX_SCOPE 16
+#define SMB_PI_MAX_COMMENT 58
+#define SMB_PI_MAX_USERNAME 40
+#define SMB_PI_MAX_PASSWD 40
+#define SMB_PI_MAX_NATIVE_OS 32
+#define SMB_PI_MAX_LANMAN 32
+
+
+#define SMB_PI_UNKNOWN_DOMAIN 0
+#define SMB_PI_RESOURCE_DOMAIN 1
+
+/*
+ * K.L. The keep alive time out use to default to 900
+ * seconds. It is not long enough for some applications
+ * i.e. MS Access. We currently use 5400 seconds.
+ */
+#define SMB_PI_KEEP_ALIVE_MIN (90 * 60)
+#define SMB_LM_COMPATIBILITY_DEFAULT_LEV 3
+
+/*
+ * This is max networks multiply by canonical address for IPv4
+ * This needs a fix for IPv4
+ */
+#define MAX_EXCLUDE_LIST_LEN (SMB_PI_MAX_NETWORKS * INET_ADDRSTRLEN)
+
+typedef struct smb_kmod_cfg {
+ uint32_t skc_maxbufsize;
+ uint32_t skc_maxworkers;
+ uint32_t skc_maxconnections;
+ uint32_t skc_keepalive;
+ uint32_t skc_restrict_anon;
+ uint32_t skc_signing_enable;
+ uint32_t skc_signing_required;
+ uint32_t skc_signing_check;
+ uint32_t skc_oplock_enable;
+ uint32_t skc_oplock_timeout;
+ uint32_t skc_flush_required;
+ uint32_t skc_sync_enable;
+ uint32_t skc_dirsymlink_enable;
+ uint32_t skc_announce_quota;
+ uint32_t skc_secmode;
+ uint32_t skc_lmlevel;
+
+ char skc_resource_domain[SMB_PI_MAX_DOMAIN];
+ char skc_hostname[SMB_PI_MAX_HOST];
+ char skc_system_comment[SMB_PI_MAX_COMMENT];
+} smb_kmod_cfg_t;
+
+#define SMB_VERSION_MAJOR 4
+#define SMB_VERSION_MINOR 0
+
+int smbnative_os_value(char *native_os);
+int smbnative_lm_value(char *native_lm);
+int smbnative_pdc_value(char *native_lm);
+
+/*
+ * Support for passthrough authentication.
+ */
+#define AUTH_USER_GRANT 0x00000000
+#define AUTH_GUEST_GRANT 0x00000001
+#define AUTH_IPC_ONLY_GRANT 0x00000002
+#define AUTH_CONEXUS_GRANT 0x00000004
+
+#define SMBD_DOOR_NAME "/var/run/smbd_door_old"
+#define SMBD_DOOR_VERSION 1
+
+#define SMBD_DOOR_COOKIE ((void*)(0xdeadbeef^SMBD_DOOR_VERSION))
+#define SMBD_DOOR_SIZE 256
+
+#define SMBD_DOOR_SRV_SUCCESS 0
+#define SMBD_DOOR_SRV_ERROR -1
+
+#define SMBD_DOOR_JOIN 1
+#define SMBD_DOOR_PARAM_GET 2
+#define SMBD_DOOR_PARAM_SET 3
+#define SMBD_DOOR_NETBIOS_RECONFIG 4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBINFO_H */
diff --git a/usr/src/uts/common/smbsrv/smbtrans.h b/usr/src/uts/common/smbsrv/smbtrans.h
new file mode 100644
index 0000000000..9ffd7e3667
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbtrans.h
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SMBTRANS_H
+#define _SMBSRV_SMBTRANS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Note that name can be variable length; therefore, it has to
+ * stay last.
+ */
+typedef struct smb_dent_info {
+ uint32_t cookie;
+ smb_attr_t attr;
+ struct smb_node *snode;
+ char name83[14];
+ char shortname[14];
+ char name[1];
+} smb_dent_info_t;
+
+#define SMB_MAX_DENT_INFO_SIZE (sizeof (smb_dent_info_t) + MAXNAMELEN - 1)
+#define SMB_MAX_DENTS_BUF_SIZE (64 * 1024) /* 64k */
+#define SMB_MAX_DENTS_IOVEC (SMB_MAX_DENTS_BUF_SIZE / SMB_MAX_DENT_INFO_SIZE)
+
+typedef struct smb_dent_info_hdr {
+ struct smb_request *sr;
+ char *pattern;
+ unsigned short sattr;
+ struct uio uio;
+ struct iovec iov[SMB_MAX_DENTS_IOVEC];
+} smb_dent_info_hdr_t;
+
+int smb_get_dents(struct smb_request *sr, uint32_t *cookie,
+ struct smb_node *dir_snode, unsigned int wildcards,
+ smb_dent_info_hdr_t *ihdr, int *more);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBTRANS_H */
diff --git a/usr/src/uts/common/smbsrv/smbvar.h b/usr/src/uts/common/smbsrv/smbvar.h
new file mode 100644
index 0000000000..30e41c714a
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/smbvar.h
@@ -0,0 +1,1402 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Structures and type definitions for the SMB module.
+ */
+
+#ifndef _SMBSRV_SMBVAR_H
+#define _SMBSRV_SMBVAR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/synch.h>
+#include <sys/taskq.h>
+#include <sys/acl.h>
+#include <sys/sdt.h>
+#include <sys/vnode.h>
+#include <sys/cred.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/lmshare.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/mbuf.h>
+#include <smbsrv/smb_secdesc.h>
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_fsd.h>
+#include <smbsrv/mlsvc.h>
+
+typedef struct smb_session smb_session_t;
+typedef struct smb_request smb_request_t;
+
+#include <smbsrv/smb_svc_sm.h>
+
+int smb_noop(void *, size_t, int);
+
+#define SMB_AUDIT_STACK_DEPTH 16
+#define SMB_AUDIT_BUF_MAX_REC 16
+#define SMB_AUDIT_NODE 0x00000001
+
+extern uint32_t smb_audit_flags;
+
+typedef struct {
+ uint32_t anr_refcnt;
+ int anr_depth;
+ pc_t anr_stack[SMB_AUDIT_STACK_DEPTH];
+} smb_audit_record_node_t;
+
+typedef struct {
+ int anb_index;
+ int anb_max_index;
+ smb_audit_record_node_t anb_records[SMB_AUDIT_BUF_MAX_REC];
+} smb_audit_buf_node_t;
+
+#define SMB_WORKER_PRIORITY 99
+/*
+ * Thread State Machine
+ * --------------------
+ *
+ * T5 T0
+ * smb_thread_destroy() <-------+ +------- smb_thread_init()
+ * | |
+ * | v
+ * +-----------------------------+
+ * | SMB_THREAD_STATE_EXITED |<---+
+ * +-----------------------------+ |
+ * | T1 |
+ * v |
+ * +-----------------------------+ |
+ * | SMB_THREAD_STATE_STARTING | |
+ * +-----------------------------+ |
+ * | T2 | T4
+ * v |
+ * +-----------------------------+ |
+ * | SMB_THREAD_STATE_RUNNING | |
+ * +-----------------------------+ |
+ * | T3 |
+ * v |
+ * +-----------------------------+ |
+ * | SMB_THREAD_STATE_EXITING |----+
+ * +-----------------------------+
+ *
+ * Transition T0
+ *
+ * This transition is executed in smb_thread_init().
+ *
+ * Transition T1
+ *
+ * This transition is executed in smb_thread_start().
+ *
+ * Transition T2
+ *
+ * This transition is executed by the thread itself when it starts running.
+ *
+ * Transition T3
+ *
+ * This transition is executed by the thread itself in
+ * smb_thread_entry_point() just before calling thread_exit().
+ *
+ *
+ * Transition T4
+ *
+ * This transition is executed in smb_thread_stop().
+ *
+ * Transition T5
+ *
+ * This transition is executed in smb_thread_destroy().
+ *
+ * Comments
+ * --------
+ *
+ * The field smb_thread_aw_t contains a function pointer that knows how to
+ * awake the thread. It is a temporary solution to work around the fact that
+ * kernel threads (not part of a userspace process) cannot be signaled.
+ */
+typedef enum smb_thread_state {
+ SMB_THREAD_STATE_STARTING = 0,
+ SMB_THREAD_STATE_RUNNING,
+ SMB_THREAD_STATE_EXITING,
+ SMB_THREAD_STATE_EXITED
+} smb_thread_state_t;
+
+struct _smb_thread;
+
+typedef void (*smb_thread_ep_t)(struct _smb_thread *, void *ep_arg);
+typedef void (*smb_thread_aw_t)(struct _smb_thread *, void *aw_arg);
+
+#define SMB_THREAD_MAGIC 0x534D4254 /* SMBT */
+
+typedef struct _smb_thread {
+ uint32_t sth_magic;
+ char sth_name[16];
+ smb_thread_state_t sth_state;
+ kthread_t *sth_th;
+ kt_did_t sth_did;
+ smb_thread_ep_t sth_ep;
+ void *sth_ep_arg;
+ smb_thread_aw_t sth_aw;
+ void *sth_aw_arg;
+ boolean_t sth_kill;
+ kmutex_t sth_mtx;
+ kcondvar_t sth_cv;
+} smb_thread_t;
+
+/*
+ * Pool of IDs
+ * -----------
+ *
+ * A pool of IDs is a pool of 16 bit numbers. It is implemented as a bitmap.
+ * A bit set to '1' indicates that that particular value has been allocated.
+ * The allocation process is done shifting a bit through the whole bitmap.
+ * The current position of that index bit is kept in the smb_idpool_t
+ * structure and represented by a byte index (0 to buffer size minus 1) and
+ * a bit index (0 to 7).
+ *
+ * The pools start with a size of 8 bytes or 64 IDs. Each time the pool runs
+ * out of IDs its current size is doubled until it reaches its maximum size
+ * (8192 bytes or 65536 IDs). The IDs 0 and 65535 are never given out which
+ * means that a pool can have a maximum number of 65534 IDs available.
+ */
+#define SMB_IDPOOL_MAGIC 0x4944504C /* IDPL */
+#define SMB_IDPOOL_MIN_SIZE 64 /* Number of IDs to begin with */
+#define SMB_IDPOOL_MAX_SIZE 64 * 1024
+
+typedef struct smb_idpool {
+ uint32_t id_magic;
+ kmutex_t id_mutex;
+ uint8_t *id_pool;
+ uint32_t id_size;
+ uint8_t id_bit;
+ uint8_t id_bit_idx;
+ uint32_t id_idx;
+ uint32_t id_idx_msk;
+ uint32_t id_free_counter;
+ uint32_t id_max_free_counter;
+} smb_idpool_t;
+
+/*
+ * Maximum size of a Netbios Request.
+ * 0x1FFFF -> Maximum size of the data
+ * 4 -> Size of the Netbios header
+ */
+#define NETBIOS_REQ_MAX_SIZE (0x1FFFF + 0x4)
+
+/*
+ * IR104720 Experiments with Windows 2000 indicate that we achieve better
+ * SmbWriteX performance with a buffer size of 64KB instead of the 37KB
+ * used with Windows NT4.0. Previous experiments with NT4.0 resulted in
+ * directory listing problems so this buffer size is configurable based
+ * on the end-user environment. When in doubt use 37KB.
+ *
+ * smb_maxbufsize (smb_negotiate.c) is setup from SMB_NT_MAXBUF during
+ * initialization.
+ */
+#define NBMAXBUF 8
+#define SMB_NT_MAXBUF(S) (((S) * 1024) - NBMAXBUF)
+extern int smb_maxbufsize;
+
+#define OUTBUFSIZE (65 * 1024)
+#define SMBHEADERSIZE 32
+#define SMBND_HASH_MASK (0xFF)
+#define MAX_IOVEC 512
+#define MAX_READREF (8 * 1024)
+
+#define SMB_WORKER_MIN 4
+#define SMB_WORKER_DEFAULT 64
+#define SMB_WORKER_MAX 1024
+
+/*
+ * Fix align a pointer or offset appropriately so that fields will not
+ * cross word boundaries.
+ */
+#define PTRALIGN(x) \
+ (((uintptr_t)(x) + (uintptr_t)(_POINTER_ALIGNMENT) - 1l) & \
+ ~((uintptr_t)(_POINTER_ALIGNMENT) - 1l))
+
+/*
+ * native os types are defined in win32/smbinfo.h
+ */
+
+/*
+ * All 4 different time / date formats that will bee seen in SMB
+ */
+typedef struct {
+ uint16_t Day : 5;
+ uint16_t Month : 4;
+ uint16_t Year : 7;
+} SMB_DATE;
+
+typedef struct {
+ uint16_t TwoSeconds : 5;
+ uint16_t Minutes : 6;
+ uint16_t Hours : 5;
+} SMB_TIME;
+
+
+typedef uint32_t UTIME; /* seconds since Jan 1 1970 */
+
+typedef struct smb_malloc_list {
+ struct smb_malloc_list *forw;
+ struct smb_malloc_list *back;
+} smb_malloc_list;
+
+typedef struct smb_llist {
+ krwlock_t ll_lock;
+ list_t ll_list;
+ uint32_t ll_count;
+ uint64_t ll_wrop;
+} smb_llist_t;
+
+typedef struct smb_slist {
+ kmutex_t sl_mutex;
+ kcondvar_t sl_cv;
+ list_t sl_list;
+ uint32_t sl_count;
+ boolean_t sl_waiting;
+} smb_slist_t;
+
+typedef struct {
+ kcondvar_t rwx_cv;
+ kmutex_t rwx_mutex;
+ krwlock_t rwx_lock;
+ boolean_t rwx_waiting;
+} smb_rwx_t;
+
+/* NOTIFY CHANGE */
+
+typedef struct smb_notify_change_req {
+ list_node_t nc_lnd;
+ struct smb_node *nc_node;
+ uint32_t nc_reply_type;
+ uint32_t nc_flags;
+} smb_notify_change_req_t;
+
+/*
+ * SMB operates over a NetBIOS-over-TCP transport (NBT) or directly
+ * over TCP, which is also known as direct hosted NetBIOS-less SMB
+ * or SMB-over-TCP.
+ *
+ * NBT messages have a 4-byte header that defines the message type
+ * (8-bits), a 7-bit flags field and a 17-bit length.
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TYPE | FLAGS |E| LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 8-bit type Defined in RFC 1002
+ * 7-bit flags Bits 0-6 reserved (must be 0)
+ * Bit 7: Length extension bit (E)
+ * 17-bit length Includes bit 7 of the flags byte
+ *
+ *
+ * SMB-over-TCP is defined to use a modified version of the NBT header
+ * containing an 8-bit message type and 24-bit message length.
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TYPE | LENGTH |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 8-bit type Must be 0
+ * 24-bit length
+ *
+ * The following structure is used to represent a generic, in-memory
+ * SMB transport header; it is not intended to map directly to either
+ * of the over-the-wire formats.
+ */
+typedef struct {
+ uint8_t xh_type;
+ uint32_t xh_length;
+} smb_xprt_t;
+
+struct mbuf_chain {
+ volatile uint32_t flags; /* Various flags */
+ struct mbuf_chain *shadow_of; /* I'm shadowing someone */
+ struct mbuf *chain; /* Start of chain */
+ int32_t max_bytes; /* max # of bytes for chain */
+ int32_t chain_offset; /* Current offset into chain */
+};
+
+int MBC_LENGTH(struct mbuf_chain *MBC);
+void MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes);
+void MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes);
+void MBC_FLUSH(struct mbuf_chain *MBC);
+void MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF);
+void MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF);
+void MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN);
+int MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
+ int OFF, int LEN);
+
+#define MBC_ROOM_FOR(b, n) (((b)->chain_offset + (n)) <= (b)->max_bytes)
+
+typedef struct smb_oplock {
+ struct smb_ofile *op_ofile;
+ uint32_t op_flags;
+} smb_oplock_t;
+
+#define OPLOCK_FLAG_BREAKING 1
+
+#define OPLOCK_RELEASE_LOCK_RELEASED 0
+#define OPLOCK_RELEASE_FILE_CLOSED 1
+
+#define DOS_ATTR_VALID 0x80000000
+
+#define SMB_VFS_MAGIC 0x534D4256 /* 'SMBV' */
+
+typedef struct smb_vfs {
+ uint32_t sv_magic;
+ list_node_t sv_lnd;
+ uint32_t sv_refcnt;
+ vfs_t *sv_vfsp;
+ vnode_t *sv_rootvp;
+} smb_vfs_t;
+
+#define SMB_NODE_MAGIC 0x4E4F4445 /* 'NODE' */
+
+typedef enum {
+ SMB_NODE_STATE_AVAILABLE = 0,
+ SMB_NODE_STATE_DESTROYING
+} smb_node_state_t;
+
+typedef struct smb_node {
+ uint32_t n_magic;
+ smb_rwx_t n_lock;
+ list_node_t n_lnd;
+ smb_node_state_t n_state;
+ uint32_t n_refcnt;
+ uint32_t n_hashkey;
+ smb_llist_t *n_hash_bucket;
+ uint64_t n_orig_session_id;
+ uint32_t n_orig_uid;
+ smb_llist_t n_ofile_list;
+ smb_llist_t n_lock_list;
+ volatile int flags; /* FILE_NOTIFY_CHANGE_* */
+ volatile int waiting_event; /* # of clients requesting FCN */
+ smb_attr_t attr;
+ unsigned int what;
+ off_t n_size;
+ smb_oplock_t n_oplock;
+ struct smb_node *dir_snode; /* Directory of node */
+ struct smb_node *unnamed_stream_node; /* set in stream nodes */
+ /* Credentials for delayed delete */
+ cred_t *delete_on_close_cred;
+ char od_name[MAXNAMELEN];
+ timestruc_t set_mtime;
+ fs_desc_t tree_fsd;
+ vnode_t *vp;
+ smb_audit_buf_node_t *n_audit_buf;
+
+} smb_node_t;
+
+#define NODE_FLAGS_NOTIFY_CHANGE 0x10000fff
+#define NODE_OPLOCKS_IN_FORCE 0x0000f000
+#define NODE_OPLOCK_NONE 0x00000000
+#define NODE_EXCLUSIVE_OPLOCK 0x00001000
+#define NODE_BATCH_OPLOCK 0x00002000
+#define NODE_LEVEL_II_OPLOCK 0x00003000
+#define NODE_CAP_LEVEL_II 0x00010000
+#define NODE_PROTOCOL_LOCK 0x00020000
+#define NODE_READ_ONLY 0x00040000
+#define NODE_CREATED_READONLY 0x00080000
+#define NODE_FLAGS_WRITE_THROUGH 0x00100000
+#define NODE_FLAGS_SYNCATIME 0x00200000
+#define NODE_FLAGS_LOCKED 0x00400000
+#define NODE_FLAGS_ATTR_VALID 0x00800000
+#define NODE_FLAGS_CREATED 0x04000000
+#define NODE_FLAGS_CHANGED 0x08000000
+#define NODE_FLAGS_WATCH_TREE 0x10000000
+#define NODE_FLAGS_SET_SIZE 0x20000000
+#define NODE_FLAGS_DELETE_ON_CLOSE 0x40000000
+#define NODE_FLAGS_EXECUTABLE 0x80000000
+
+#define NODE_IS_READONLY(node) \
+ ((node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) || \
+ (node->flags & NODE_READ_ONLY) || \
+ (node->flags & NODE_CREATED_READONLY))
+
+#define OPLOCK_TYPE(n) ((n)->flags & NODE_OPLOCKS_IN_FORCE)
+#define OPLOCKS_IN_FORCE(n) (OPLOCK_TYPE(n) != NODE_OPLOCK_NONE)
+#define EXCLUSIVE_OPLOCK_IN_FORCE(n) \
+ (OPLOCK_TYPE(n) == NODE_EXCLUSIVE_OPLOCK)
+#define BATCH_OPLOCK_IN_FORCE(n) (OPLOCK_TYPE(n) == NODE_BATCH_OPLOCK)
+#define LEVEL_II_OPLOCK_IN_FORCE(n) (OPLOCK_TYPE(n) == NODE_LEVEL_II_OPLOCK)
+
+/*
+ * Based on section 2.6.1.2 (Connection Management) of the June 13,
+ * 1996 CIFS spec, a server may terminate the transport connection
+ * due to inactivity. The client software is expected to be able to
+ * automatically reconnect to the server if this happens. Like much
+ * of the useful background information, this section appears to
+ * have been dropped from later revisions of the document.
+ *
+ * Each session has an activity timestamp that's updated whenever a
+ * request is dispatched. If the session is idle, i.e. receives no
+ * requests, for SMB_SESSION_INACTIVITY_TIMEOUT minutes it will be
+ * closed.
+ *
+ * Each session has an I/O semaphore to serialize communication with
+ * the client. For example, after receiving a raw-read request, the
+ * server is not allowed to send an oplock break to the client until
+ * after it has sent the raw-read data.
+ */
+#define SMB_SESSION_INACTIVITY_TIMEOUT (15 * 60)
+
+#define SMB_SESSION_OFILE_MAX (16 * 1024)
+
+/*
+ * When a connection is set up we need to remember both the client
+ * (peer) IP address and the local IP address used to establish the
+ * connection. When a client connects with a vc number of zero, we
+ * are supposed to abort any existing connections with that client
+ * (see notes in smb_negotiate.c and smb_session_setup_andx.c). For
+ * servers with multiple network interfaces or IP aliases, however,
+ * each interface has to be managed independently since the client
+ * is not aware of the server configuration. We have to allow the
+ * client to establish a connection on each interface with a vc
+ * number of zero without aborting the other connections.
+ *
+ * ipaddr: the client (peer) IP address for the session.
+ * local_ipaddr: the local IP address used to connect to the server.
+ */
+
+#define SMB_MAC_KEYSZ 512
+
+struct smb_sign {
+ unsigned int seqnum;
+ unsigned int mackey_len;
+ unsigned int flags;
+ unsigned char mackey[SMB_MAC_KEYSZ];
+};
+
+#define SMB_SIGNING_ENABLED 1
+#define SMB_SIGNING_CHECK 2
+
+/*
+ * Session State Machine
+ * ---------------------
+ *
+ * +-----------------------------+ +------------------------------+
+ * | SMB_SESSION_STATE_CONNECTED | | SMB_SESSION_STATE_TERMINATED |
+ * +-----------------------------+ +------------------------------+
+ * T0| ^
+ * +--------------------+ |T13
+ * v |T14 |
+ * +-------------------------------+ | +--------------------------------+
+ * | SMB_SESSION_STATE_ESTABLISHED |---+--->| SMB_SESSION_STATE_DISCONNECTED |
+ * +-------------------------------+ +--------------------------------+
+ * T1| ^ ^ ^ ^
+ * +----------+ |T9 | | |
+ * v | | | |
+ * +------------------------------+ | | |
+ * | SMB_SESSION_STATE_NEGOTIATED | | | |
+ * +------------------------------+ | | |
+ * ^| ^| | ^ | | |
+ * +----------------+| || | | | | |
+ * |+----------------+ || T7| |T8 | | |
+ * || || | | | | |
+ * || +----------------+| | | | | |
+ * || |+----------------+ | | | | |
+ * || || v | | | |
+ * || || +-----------------------------------+ T10| | |
+ * || || | SMB_SESSION_STATE_OPLOCK_BREAKING |----+ | |
+ * || || +-----------------------------------+ | |
+ * || ||T5 | |
+ * || |+-->+-----------------------------------+ T11| |
+ * || |T6 | SMB_SESSION_STATE_READ_RAW_ACTIVE |------+ |
+ * || +----+-----------------------------------+ |
+ * ||T3 |
+ * |+------->+------------------------------------+ T12|
+ * |T4 | SMB_SESSION_STATE_WRITE_RAW_ACTIVE |-------+
+ * +---------+------------------------------------+
+ *
+ * Transition T0
+ *
+ *
+ *
+ * Transition T1
+ *
+ *
+ *
+ * Transition T2
+ *
+ *
+ *
+ * Transition T3
+ *
+ *
+ *
+ * Transition T4
+ *
+ *
+ *
+ * Transition T5
+ *
+ *
+ *
+ * Transition T6
+ *
+ *
+ *
+ * Transition T7
+ *
+ *
+ *
+ * Transition T8
+ *
+ *
+ *
+ * Transition T9
+ *
+ *
+ *
+ * Transition T10
+ *
+ *
+ *
+ * Transition T11
+ *
+ *
+ *
+ * Transition T12
+ *
+ *
+ *
+ * Transition T13
+ *
+ *
+ *
+ * Transition T14
+ *
+ *
+ *
+ */
+#define SMB_SESSION_MAGIC 0x53455353 /* 'SESS' */
+
+typedef enum {
+ SMB_SESSION_STATE_DISCONNECTED = 0,
+ SMB_SESSION_STATE_CONNECTED,
+ SMB_SESSION_STATE_ESTABLISHED,
+ SMB_SESSION_STATE_NEGOTIATED,
+ SMB_SESSION_STATE_OPLOCK_BREAKING,
+ SMB_SESSION_STATE_WRITE_RAW_ACTIVE,
+ SMB_SESSION_STATE_TERMINATED
+} smb_session_state_t;
+
+struct smb_session {
+ uint32_t s_magic;
+ smb_rwx_t s_lock;
+ list_node_t s_lnd;
+ uint64_t s_kid;
+ smb_session_state_t s_state;
+ uint32_t s_flags;
+ int s_write_raw_status;
+ smb_thread_t s_thread;
+ uint32_t keep_alive;
+ uint64_t opentime;
+ uint16_t vcnumber;
+ uint16_t s_local_port;
+ uint32_t ipaddr;
+ uint32_t local_ipaddr;
+ char workstation[SMB_PI_MAX_HOST];
+ int dialect;
+ int native_os;
+ uint32_t capabilities;
+ struct smb_sign signing;
+
+ struct sonode *sock;
+
+ smb_slist_t s_req_list;
+ smb_llist_t s_xa_list;
+ smb_llist_t s_user_list;
+ smb_idpool_t s_uid_pool;
+
+ volatile uint32_t s_tree_cnt;
+ volatile uint32_t s_file_cnt;
+ volatile uint32_t s_dir_cnt;
+
+ uint16_t secmode;
+ uint32_t sesskey;
+ uint32_t challenge_len;
+ unsigned char challenge_key[8];
+ unsigned char MAC_key[44];
+ int64_t activity_timestamp;
+ /*
+ * Maximum negotiated buffer size between SMB client and server
+ * in SMB_SESSION_SETUP_ANDX
+ */
+ uint16_t smb_msg_size;
+ uchar_t *outpipe_data;
+ int outpipe_datalen;
+ int outpipe_cookie;
+};
+
+#define SMB_USER_MAGIC 0x55534552 /* 'USER' */
+
+#define SMB_USER_FLAG_GUEST SMB_ATF_GUEST
+#define SMB_USER_FLAG_IPC SMB_ATF_ANON
+#define SMB_USER_FLAG_ADMIN SMB_ATF_ADMIN
+#define SMB_USER_FLAG_POWER_USER SMB_ATF_POWERUSER
+#define SMB_USER_FLAG_BACKUP_OPERATOR SMB_ATF_BACKUPOP
+
+#define SMB_USER_PRIV_TAKE_OWNERSHIP 0x00000001
+#define SMB_USER_PRIV_BACKUP 0x00000002
+#define SMB_USER_PRIV_RESTORE 0x00000004
+#define SMB_USER_PRIV_SECURITY 0x00000008
+
+
+typedef enum {
+ SMB_USER_STATE_LOGGED_IN = 0,
+ SMB_USER_STATE_LOGGING_OFF,
+ SMB_USER_STATE_LOGGED_OFF
+} smb_user_state_t;
+
+typedef struct smb_user {
+ uint32_t u_magic;
+ list_node_t u_lnd;
+ kmutex_t u_mutex;
+ smb_user_state_t u_state;
+
+ smb_session_t *u_session;
+ uint16_t u_name_len;
+ char *u_name;
+ uint16_t u_domain_len;
+ char *u_domain;
+ time_t u_logon_time;
+ cred_t *u_cred;
+
+ smb_llist_t u_tree_list;
+ smb_idpool_t u_tid_pool;
+
+ uint32_t u_refcnt;
+ uint32_t u_flags;
+ uint32_t u_privileges;
+ uint16_t u_uid;
+ uint32_t u_audit_sid;
+} smb_user_t;
+
+#define SMB_TREE_MAGIC 0x54524545 /* 'TREE' */
+#define SMB_TREE_TYPENAME_SZ 8
+
+typedef enum {
+ SMB_TREE_STATE_CONNECTED = 0,
+ SMB_TREE_STATE_DISCONNECTING,
+ SMB_TREE_STATE_DISCONNECTED
+} smb_tree_state_t;
+
+typedef struct smb_tree {
+ uint32_t t_magic;
+ kmutex_t t_mutex;
+ list_node_t t_lnd;
+ smb_tree_state_t t_state;
+
+ smb_session_t *t_session;
+ smb_user_t *t_user;
+ smb_node_t *t_snode;
+
+ smb_llist_t t_ofile_list;
+ smb_idpool_t t_fid_pool;
+
+ smb_llist_t t_odir_list;
+ smb_idpool_t t_sid_pool;
+
+ uint32_t t_refcnt;
+ uint32_t t_flags;
+ int32_t t_res_type;
+ uint16_t t_tid;
+ uint16_t t_access;
+ uint16_t t_umask;
+ char t_sharename[MAXNAMELEN];
+ char t_resource[MAXPATHLEN];
+ char t_typename[SMB_TREE_TYPENAME_SZ];
+ fs_desc_t t_fsd;
+ acl_type_t t_acltype;
+} smb_tree_t;
+
+/* Tree access bits */
+#define SMB_TREE_NO_ACCESS 0x0000
+#define SMB_TREE_READ_ONLY 0x0001
+#define SMB_TREE_READ_WRITE 0x0002
+
+/*
+ * Tree flags
+ *
+ * SMB_TREE_FLAG_ACLONCREATE Underlying FS supports ACL on create.
+ *
+ * SMB_TREE_FLAG_ACEMASKONACCESS Underlying FS understands 32-bit access mask
+ */
+#define SMB_TREE_FLAG_OPEN 0x0001
+#define SMB_TREE_FLAG_CLOSE 0x0002
+#define SMB_TREE_FLAG_ACLONCREATE 0x0004
+#define SMB_TREE_FLAG_ACEMASKONACCESS 0x0008
+#define SMB_TREE_FLAG_IGNORE_CASE 0x0010
+#define SMB_TREE_CLOSED(tree) ((tree)->t_flags & SMB_TREE_FLAG_CLOSE)
+
+/*
+ * SMB_TREE_CASE_INSENSITIVE returns whether operations on a given tree
+ * will be case-insensitive or not. SMB_TREE_FLAG_IGNORE_CASE is set at
+ * share set up time based on file system capability and client preference.
+ */
+
+#define SMB_TREE_CASE_INSENSITIVE(sr) \
+ (((sr) && (sr)->tid_tree) ? \
+ ((sr)->tid_tree->t_flags & SMB_TREE_FLAG_IGNORE_CASE) : 0)
+
+/*
+ * SMB_TREE_ROOT_FS is called by certain smb_fsop_* functions to make sure
+ * that a given vnode is in the same file system as the share root.
+ */
+
+#define SMB_TREE_ROOT_FS(sr, node) \
+ (((sr) && (sr)->tid_tree) ? \
+ ((sr)->tid_tree->t_snode->vp->v_vfsp == (node)->vp->v_vfsp) : 1)
+
+#define SMB_TREE_IS_READ_ONLY(sr) \
+ ((sr) && ((sr)->tid_tree->t_access == SMB_TREE_READ_ONLY))
+
+
+#define PIPE_STATE_AUTH_VERIFY 0x00000001
+
+/*
+ * The of_ftype of an open file should contain the SMB_FTYPE value
+ * (cifs.h) returned when the file/pipe was opened. The following
+ * assumptions are currently made:
+ *
+ * File Type Node PipeInfo
+ * --------- -------- --------
+ * SMB_FTYPE_DISK Valid Null
+ * SMB_FTYPE_BYTE_PIPE Undefined Undefined
+ * SMB_FTYPE_MESG_PIPE Null Valid
+ * SMB_FTYPE_PRINTER Undefined Undefined
+ * SMB_FTYPE_UNKNOWN Undefined Undefined
+ */
+
+/*
+ * Some flags for ofile structure
+ *
+ * SMB_OFLAGS_SET_DELETE_ON_CLOSE
+ * Set this flag when the corresponding open operation whose
+ * DELETE_ON_CLOSE bit of the CreateOptions is set. If any
+ * open file instance has this bit set, the NODE_FLAGS_DELETE_ON_CLOSE
+ * will be set for the file node upon close.
+ */
+
+#define SMB_OFLAGS_SET_DELETE_ON_CLOSE 0x0004
+#define SMB_OFLAGS_LLF_POS_VALID 0x0008
+
+#define SMB_OFILE_MAGIC 0x4F464C45 /* 'OFLE' */
+
+typedef enum {
+ SMB_OFILE_STATE_OPEN = 0,
+ SMB_OFILE_STATE_CLOSING,
+ SMB_OFILE_STATE_CLOSED
+} smb_ofile_state_t;
+
+typedef struct smb_ofile {
+ uint32_t f_magic;
+ kmutex_t f_mutex;
+ list_node_t f_lnd;
+ list_node_t f_nnd;
+ smb_ofile_state_t f_state;
+
+ smb_session_t *f_session;
+ smb_user_t *f_user;
+ smb_tree_t *f_tree;
+ smb_node_t *f_node;
+
+ mlsvc_pipe_t *f_pipe_info;
+
+ uint32_t f_refcnt;
+ uint64_t f_seek_pos;
+ uint32_t f_flags;
+ uint32_t f_granted_access;
+ uint32_t f_share_access;
+ uint32_t f_create_options;
+ uint16_t f_fid;
+ uint16_t f_opened_by_pid;
+ uint16_t f_ftype;
+ uint64_t f_llf_pos;
+ cred_t *f_cr;
+} smb_ofile_t;
+
+/* odir flags bits */
+#define SMB_DIR_FLAG_OPEN 0x0001
+#define SMB_DIR_FLAG_CLOSE 0x0002
+#define SMB_DIR_CLOSED(dir) ((dir)->d_flags & SMB_DIR_FLAG_CLOSE)
+
+#define SMB_ODIR_MAGIC 0x4F444952 /* 'ODIR' */
+
+typedef enum {
+ SMB_ODIR_STATE_OPEN = 0,
+ SMB_ODIR_STATE_CLOSING,
+ SMB_ODIR_STATE_CLOSED
+} smb_odir_state_t;
+
+typedef struct smb_odir {
+ uint32_t d_magic;
+ kmutex_t d_mutex;
+ list_node_t d_lnd;
+ smb_odir_state_t d_state;
+
+ smb_session_t *d_session;
+ smb_user_t *d_user;
+ smb_tree_t *d_tree;
+
+ uint32_t d_refcnt;
+ uint32_t d_cookie;
+ uint16_t d_sid;
+ uint16_t d_opened_by_pid;
+ uint16_t d_sattr;
+ char d_pattern[MAXNAMELEN];
+ struct smb_node *d_dir_snode;
+ unsigned int d_wildcards;
+} smb_odir_t;
+
+typedef struct smb_odir_context {
+ uint32_t dc_cookie;
+ uint16_t dc_dattr;
+ char dc_name[MAXNAMELEN]; /* Real 'Xxxx.yyy.xx' */
+ char dc_name83[14]; /* w/ dot 'XXXX .XX ' */
+ char dc_shortname[14]; /* w/ dot 'XXXX.XX' */
+ smb_attr_t dc_attr;
+} smb_odir_context_t;
+
+#define SMB_LOCK_MAGIC 0x4C4F434B /* 'LOCK' */
+
+typedef struct smb_lock {
+ uint32_t l_magic;
+ kmutex_t l_mutex;
+ list_node_t l_lnd;
+ kcondvar_t l_cv;
+
+ list_node_t l_conflict_lnd;
+ smb_slist_t l_conflict_list;
+
+ smb_session_t *l_session;
+ smb_ofile_t *l_file;
+ smb_request_t *l_sr;
+
+ uint32_t l_flags;
+ uint64_t l_session_kid;
+ struct smb_lock *l_blocked_by; /* Debug info only */
+
+ uint16_t l_pid;
+ uint16_t l_uid;
+ uint32_t l_type;
+ uint64_t l_start;
+ uint64_t l_length;
+ clock_t l_end_time;
+} smb_lock_t;
+
+#define SMB_LOCK_FLAG_INDEFINITE 0x0004
+#define SMB_LOCK_INDEFINITE_WAIT(lock) \
+ ((lock)->l_flags & SMB_LOCK_FLAG_INDEFINITE)
+
+#define SMB_LOCK_TYPE_READWRITE 101
+#define SMB_LOCK_TYPE_READONLY 102
+
+
+struct smb_fqi { /* fs_query_info */
+ char *path;
+ uint16_t srch_attr;
+ struct smb_node *dir_snode;
+ smb_attr_t dir_attr;
+ char last_comp[MAXNAMELEN];
+ int last_comp_was_found;
+ char last_comp_od[MAXNAMELEN];
+ struct smb_node *last_snode;
+ smb_attr_t last_attr;
+};
+
+#define SMB_NULL_FQI_NODES(fqi) \
+ (fqi).last_snode = NULL; \
+ (fqi).dir_snode = NULL;
+
+#define FQM_DIR_MUST_EXIST 1
+#define FQM_PATH_MUST_EXIST 2
+#define FQM_PATH_MUST_NOT_EXIST 3
+
+#define MYF_OPLOCK_MASK 0x000000F0
+#define MYF_OPLOCK_NONE 0x00000000
+#define MYF_EXCLUSIVE_OPLOCK 0x00000010
+#define MYF_BATCH_OPLOCK 0x00000020
+#define MYF_LEVEL_II_OPLOCK 0x00000030
+#define MYF_MUST_BE_DIRECTORY 0x00000100
+
+#define MYF_OPLOCK_TYPE(o) ((o) & MYF_OPLOCK_MASK)
+#define MYF_OPLOCKS_REQUEST(o) (MYF_OPLOCK_TYPE(o) != MYF_OPLOCK_NONE)
+#define MYF_IS_EXCLUSIVE_OPLOCK(o) (MYF_OPLOCK_TYPE(o) == MYF_EXCLUSIVE_OPLOCK)
+#define MYF_IS_BATCH_OPLOCK(o) (MYF_OPLOCK_TYPE(o) == MYF_BATCH_OPLOCK)
+#define MYF_IS_LEVEL_II_OPLOCK(o) (MYF_OPLOCK_TYPE(o) == MYF_LEVEL_II_OPLOCK)
+
+#define OPLOCK_MIN_TIMEOUT (5 * 1000)
+#define OPLOCK_STD_TIMEOUT (15 * 1000)
+
+
+/*
+ * SMB Request State Machine
+ * -------------------------
+ *
+ * T4 +------+ T0
+ * +--------------------------->| FREE |---------------------------+
+ * | +------+ |
+ * +-----------+ |
+ * | COMPLETED | |
+ * +-----------+
+ * ^ |
+ * | T15 +----------+ v
+ * +------------+ T6 | | +--------------+
+ * | CLEANED_UP |<-----------------| CANCELED | | INITIALIZING |
+ * +------------+ | | +--------------+
+ * | ^ +----------+ |
+ * | | ^ ^ ^ ^ |
+ * | | +-------------+ | | | |
+ * | | T3 | | | | T13 | T1
+ * | +-------------------------+ | | +----------------------+ |
+ * +----------------------------+ | | | | |
+ * T16 | | | | +-----------+ | |
+ * | \/ | | T5 | | v
+ * +-----------------+ | T12 +--------+ | T2 +-----------+
+ * | EVENT_OCCURRED |------------->| ACTIVE |<--------------------| SUBMITTED |
+ * +-----------------+ | +--------+ | +-----------+
+ * ^ | | ^ | |
+ * | | T8 | | | T7 |
+ * | T10 T9 | +----------+ | +-------+ | T11
+ * | | | +-------+ | |
+ * | | | T14 | | |
+ * | | v | v |
+ * +----------------------+ +--------------+
+ * | WAITING_EVENT | | WAITING_LOCK |
+ * +----------------------+ +--------------+
+ *
+ *
+ *
+ *
+ *
+ * Transition T0
+ *
+ * This transition occurs when the request is allocated and is still under the
+ * control of the session thread.
+ *
+ * Transition T1
+ *
+ * This transition occurs when the session thread dispatches a task to treat the
+ * request.
+ *
+ * Transition T2
+ *
+ *
+ *
+ * Transition T3
+ *
+ * A request completes and smbsr_cleanup is called to release resources
+ * associated with the request (but not the smb_request_t itself). This
+ * includes references on smb_ofile_t, smb_node_t, and other structures.
+ * CLEANED_UP state exists to detect if we attempt to cleanup a request
+ * multiple times and to allow us to detect that we are accessing a
+ * request that has already been cleaned up.
+ *
+ * Transition T4
+ *
+ *
+ *
+ * Transition T5
+ *
+ *
+ *
+ * Transition T6
+ *
+ *
+ *
+ * Transition T7
+ *
+ *
+ *
+ * Transition T8
+ *
+ *
+ *
+ * Transition T9
+ *
+ *
+ *
+ * Transition T10
+ *
+ *
+ *
+ * Transition T11
+ *
+ *
+ *
+ * Transition T12
+ *
+ *
+ *
+ * Transition T13
+ *
+ *
+ *
+ * Transition T14
+ *
+ *
+ *
+ * Transition T15
+ *
+ * Request processing is completed (control returns from smb_dispatch)
+ *
+ * Transition T16
+ *
+ * Multipart (andx) request was cleaned up with smbsr_cleanup but more "andx"
+ * sections remain to be processed.
+ *
+ */
+
+#define SMB_REQ_MAGIC 0x534D4252 /* 'SMBR' */
+
+typedef enum smb_req_state {
+ SMB_REQ_STATE_FREE = 0,
+ SMB_REQ_STATE_INITIALIZING,
+ SMB_REQ_STATE_SUBMITTED,
+ SMB_REQ_STATE_ACTIVE,
+ SMB_REQ_STATE_WAITING_EVENT,
+ SMB_REQ_STATE_EVENT_OCCURRED,
+ SMB_REQ_STATE_WAITING_LOCK,
+ SMB_REQ_STATE_COMPLETED,
+ SMB_REQ_STATE_CANCELED,
+ SMB_REQ_STATE_CLEANED_UP
+} smb_req_state_t;
+
+struct smb_request {
+ uint32_t sr_magic;
+ kmutex_t sr_mutex;
+ list_node_t sr_session_lnd;
+ smb_req_state_t sr_state;
+ boolean_t sr_keep;
+
+ struct smb_session *session;
+
+ smb_notify_change_req_t sr_ncr;
+
+ /* Info from session service header */
+ uint32_t sr_req_length; /* Excluding NBT header */
+
+ /* Request buffer excluding NBT header */
+ void *sr_request_buf;
+
+ /* Fields for raw writes */
+ uint32_t sr_raw_data_length;
+ void *sr_raw_data_buf;
+
+ smb_lock_t *sr_awaiting;
+ struct mbuf_chain command;
+ struct mbuf_chain reply;
+ struct mbuf_chain raw_data;
+ smb_malloc_list request_storage;
+ struct smb_xa *r_xa;
+ int andx_prev_wct;
+ int cur_reply_offset;
+ int orig_request_hdr;
+ unsigned int reply_seqnum; /* reply sequence number */
+ unsigned char first_smb_com; /* command code */
+ unsigned char smb_com; /* command code */
+ unsigned char smb_rcls; /* error code class */
+ unsigned char smb_reh; /* rsvd (AH DOS INT-24 ERR) */
+ uint16_t smb_err; /* error code */
+ uint8_t smb_flg; /* flags */
+ uint16_t smb_flg2; /* flags */
+ uint16_t smb_pid_high; /* high part of pid */
+ unsigned char smb_sig[8]; /* signiture */
+ uint16_t smb_tid; /* tree id # */
+ uint16_t smb_pid; /* caller's process id # */
+ uint16_t smb_uid; /* user id # */
+ uint16_t smb_mid; /* mutiplex id # */
+ unsigned char smb_wct; /* count of parameter words */
+ uint16_t smb_bcc; /* data byte count */
+
+ /* Parameters */
+ struct mbuf_chain smb_vwv; /* variable width value */
+
+ /* Data */
+ struct mbuf_chain smb_data;
+
+ uint16_t smb_fid; /* not in hdr, but common */
+ uint16_t smb_sid; /* not in hdr, but common */
+
+ unsigned char andx_com;
+ uint16_t andx_off;
+
+ struct smb_tree *tid_tree;
+ struct smb_ofile *fid_ofile;
+ struct smb_odir *sid_odir;
+ smb_user_t *uid_user;
+
+ union {
+ struct {
+ char *path;
+ char *service;
+ int pwdlen;
+ char *password;
+ uint16_t flags;
+ } tcon;
+
+ struct open_param {
+ struct smb_fqi fqi;
+ uint16_t omode;
+ uint16_t oflags;
+ uint16_t ofun;
+ uint32_t my_flags;
+ uint32_t timeo;
+ uint32_t dattr;
+ timestruc_t utime;
+ uint64_t dsize;
+ uint32_t desired_access;
+ uint32_t share_access;
+ uint32_t create_options;
+ uint32_t create_disposition;
+ uint32_t ftype, devstate;
+ uint32_t action_taken;
+ uint64_t fileid;
+ /* This is only set by NTTransactCreate */
+ smb_sdbuf_t *sd_buf;
+ } open;
+
+ struct {
+ struct smb_fqi fqi;
+ struct smb_fqi dst_fqi;
+ } dirop;
+
+ } arg;
+
+ label_t exjb;
+ cred_t *user_cr;
+ caller_context_t ct;
+};
+
+caller_context_t local_ct;
+
+#define SMB_READ_PROTOCOL(smb_nh_ptr) \
+ LE_IN32(((smb_nethdr_t *)(smb_nh_ptr))->sh_protocol)
+
+#define SMB_PROTOCOL_MAGIC_INVALID(rd_sr) \
+ (SMB_READ_PROTOCOL((rd_sr)->sr_request_buf) != SMB_PROTOCOL_MAGIC)
+
+#define SMB_READ_COMMAND(smb_nh_ptr) \
+ (((smb_nethdr_t *)(smb_nh_ptr))->sh_command)
+
+#define SMB_IS_WRITERAW(rd_sr) \
+ (SMB_READ_COMMAND((rd_sr)->sr_request_buf) == SMB_COM_WRITE_RAW)
+
+
+#define SR_FLG_OFFSET 9
+
+#define MAX_TRANS_NAME 64
+
+#define SMB_XA_FLAG_OPEN 0x0001
+#define SMB_XA_FLAG_CLOSE 0x0002
+#define SMB_XA_FLAG_COMPLETE 0x0004
+#define SMB_XA_CLOSED(xa) (!((xa)->xa_flags & SMB_XA_FLAG_OPEN))
+
+#define SMB_XA_MAGIC 0x534D4258 /* 'SMBX' */
+
+typedef struct smb_xa {
+ uint32_t xa_magic;
+ kmutex_t xa_mutex;
+ list_node_t xa_lnd;
+
+ uint32_t xa_refcnt;
+ uint32_t xa_flags;
+
+ struct smb_session *xa_session;
+
+ unsigned char smb_com; /* which TRANS type */
+ unsigned char smb_flg; /* flags */
+ uint16_t smb_flg2; /* flags */
+ uint16_t smb_tid; /* tree id number */
+ uint16_t smb_pid; /* caller's process id number */
+ uint16_t smb_uid; /* user id number */
+ uint32_t smb_func; /* NT_TRANS function */
+
+ uint16_t xa_smb_mid; /* mutiplex id number */
+ uint16_t xa_smb_fid; /* TRANS2 secondary */
+
+ unsigned int reply_seqnum; /* reply sequence number */
+
+ uint32_t smb_tpscnt; /* total parameter bytes being sent */
+ uint32_t smb_tdscnt; /* total data bytes being sent */
+ uint32_t smb_mprcnt; /* max parameter bytes to return */
+ uint32_t smb_mdrcnt; /* max data bytes to return */
+ uint32_t smb_msrcnt; /* max setup words to return */
+ uint32_t smb_flags; /* additional information: */
+ /* bit 0 - if set, disconnect TID in smb_tid */
+ /* bit 1 - if set, transaction is one way */
+ /* (no final response) */
+ int32_t smb_timeout; /* number of milliseconds to await completion */
+ uint32_t smb_suwcnt; /* set up word count */
+
+
+ char *xa_smb_trans_name;
+
+ int req_disp_param;
+ int req_disp_data;
+
+ struct mbuf_chain req_setup_mb;
+ struct mbuf_chain req_param_mb;
+ struct mbuf_chain req_data_mb;
+
+ struct mbuf_chain rep_setup_mb;
+ struct mbuf_chain rep_param_mb;
+ struct mbuf_chain rep_data_mb;
+} smb_xa_t;
+
+
+#define SDDF_NO_FLAGS 0
+#define SDDF_SUPPRESS_TID 0x0001
+#define SDDF_SUPPRESS_UID 0x0002
+#define SDDF_SUPPRESS_UNLEASH 0x0004
+#define SDDF_SUPPRESS_SHOW 0x0080
+
+#define SDRC_NORMAL_REPLY 0
+#define SDRC_DROP_VC 1
+#define SDRC_NO_REPLY 2
+#define SDRC_ERROR_REPLY 3
+#define SDRC_UNIMPLEMENTED 4
+#define SDRC_UNSUPPORTED 5
+
+
+struct vardata_block {
+ unsigned char tag;
+ uint16_t len;
+ struct uio uio;
+ struct iovec iovec[MAX_IOVEC];
+};
+
+#define VAR_BCC ((short)-1)
+
+
+
+
+extern struct smb_info smb_info;
+
+#define SMB_SI_NBT_CONNECTED 0x01
+#define SMB_SI_TCP_CONNECTED 0x02
+
+typedef struct smb_info {
+ smb_svc_sm_ctx_t si_svc_sm_ctx;
+
+ uint32_t si_open_progress;
+ uint32_t si_connect_progress;
+
+ volatile uint64_t si_global_kid;
+ volatile uint32_t si_gmtoff;
+
+ smb_thread_t si_nbt_daemon;
+ smb_thread_t si_tcp_daemon;
+ smb_thread_t si_thread_notify_change;
+ smb_thread_t si_thread_timers;
+
+ taskq_t *thread_pool;
+
+ kmem_cache_t *si_cache_vfs;
+ kmem_cache_t *si_cache_request;
+ kmem_cache_t *si_cache_session;
+ kmem_cache_t *si_cache_user;
+ kmem_cache_t *si_cache_tree;
+ kmem_cache_t *si_cache_ofile;
+ kmem_cache_t *si_cache_odir;
+ kmem_cache_t *si_cache_node;
+
+ smb_slist_t si_ncr_list;
+ smb_slist_t si_nce_list;
+
+ smb_kmod_cfg_t si;
+
+ volatile uint32_t open_trees;
+ volatile uint32_t open_files;
+ volatile uint32_t open_users;
+
+ smb_node_t *si_root_smb_node;
+ smb_llist_t node_hash_table[SMBND_HASH_MASK+1];
+ smb_llist_t si_vfs_list;
+} smb_info_t;
+
+#define SMB_INFO_NETBIOS_SESSION_SVC_RUNNING 0x0001
+#define SMB_INFO_NETBIOS_SESSION_SVC_FAILED 0x0002
+#define SMB_INFO_USER_LEVEL_SECURITY 0x40000000
+#define SMB_INFO_ENCRYPT_PASSWORDS 0x80000000
+
+#define SMB_NEW_KID() atomic_inc_64_nv(&smb_info.si_global_kid)
+
+typedef struct {
+ uint16_t errcls;
+ uint16_t errcode;
+ DWORD status;
+} smb_error_t;
+
+/*
+ * This is to be used by Trans2SetFileInfo
+ * and Trans2SetPathInfo
+ */
+typedef struct smb_trans2_setinfo {
+ uint16_t level;
+ struct smb_xa *ts_xa;
+ struct smb_node *node;
+ char *path;
+ char name[MAXNAMELEN];
+} smb_trans2_setinfo_t;
+
+
+#define SMB_IS_STREAM(node) ((node)->unnamed_stream_node)
+
+#ifdef DEBUG
+extern uint_t smb_tsd_key;
+#endif
+
+typedef struct smb_tsd {
+ void (*proc)();
+ void *arg;
+ char name[100];
+} smb_tsd_t;
+
+#define SMB_INVALID_AMASK -1
+#define SMB_INVALID_SHAREMODE -1
+#define SMB_INVALID_CRDISPOSITION -1
+
+typedef struct smb_dispatch_table {
+ int (*sdt_function)(struct smb_request *);
+ char sdt_dialect;
+ unsigned char sdt_flags;
+ krw_t sdt_slock_mode;
+ kstat_named_t sdt_dispatch_stats; /* invocations */
+} smb_dispatch_table_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SMBVAR_H */
diff --git a/usr/src/uts/common/smbsrv/string.h b/usr/src/uts/common/smbsrv/string.h
new file mode 100644
index 0000000000..6696cbc33d
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/string.h
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_STRING_H
+#define _SMBSRV_STRING_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <smbsrv/smb_i18n.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *strsubst(char *, char, char);
+extern char *strsep(char **, const char *);
+extern char *strcanon(char *, const char *);
+
+extern char *utf8_strupr(char *);
+extern char *utf8_strlwr(char *);
+extern int utf8_isstrupr(const char *);
+extern int utf8_isstrlwr(const char *);
+extern int utf8_strcasecmp(const char *, const char *);
+extern int utf8_strncasecmp(const char *, const char *, int);
+extern int utf8_isstrascii(const char *);
+
+extern int smb_match(char *patn, char *str);
+extern int smb_match_ci(char *patn, char *str);
+extern int smb_match83(char *patn, char *str83);
+
+/*
+ * Maximum number of bytes per multi-byte character.
+ */
+#define MTS_MB_CUR_MAX 3
+#define MTS_MB_CHAR_MAX MTS_MB_CUR_MAX
+
+size_t mts_mbstowcs(mts_wchar_t *, const char *, size_t);
+size_t mts_wcstombs(char *, const mts_wchar_t *, size_t);
+int mts_mbtowc(mts_wchar_t *, const char *, size_t);
+int mts_wctomb(char *, mts_wchar_t);
+
+size_t mts_wcequiv_strlen(const char *);
+size_t mts_sbequiv_strlen(const char *);
+
+int mts_stombs(char *, char *, int);
+int mts_mbstos(char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_STRING_H */
diff --git a/usr/src/uts/common/smbsrv/svrapi.h b/usr/src/uts/common/smbsrv/svrapi.h
new file mode 100644
index 0000000000..4199feb8d7
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/svrapi.h
@@ -0,0 +1,263 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_SVRAPI_H
+#define _SMBSRV_SVRAPI_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file provides definitions for the SMB Net interface. On Windows
+ * this would be NetAccess, NetConnection, NetFile, NetServer,
+ * NetSession, NetShare and NetSecurity but here things are a limited.
+ * This stuff should be described in Windows 9x LanMan documentation.
+ *
+ * Notes:
+ * Lengths of ASCIIZ strings are given as the maximum strlen() value.
+ * This does not include space for the terminating 0-byte. When
+ * allocating space for such an item, use the form:
+ *
+ * char username[LM20_UNLEN+1];
+ *
+ * An exception to this is PATHLEN, which does include space for the
+ * terminating 0-byte.
+ *
+ * User names, computer names and share names should be upper-cased
+ * by the caller and drawn from the ANSI character set.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Server Class (NetServerGetInfo, NetServerEnum2)
+ */
+
+struct server_info_0 {
+ char sv0_name[CNLEN + 1]; /* Server name */
+}; /* server_info_0 */
+
+
+struct server_info_1 {
+ char sv1_name[CNLEN + 1]; /* Server name */
+ unsigned char sv1_version_major; /* Major version # of net */
+ unsigned char sv1_version_minor; /* Minor version # of net */
+ uint32_t sv1_type; /* Server type */
+ char *sv1_comment; /* Exported server comment */
+}; /* server_info_1 */
+
+
+/* NOTE struct prefix must equal server_info_1 format */
+
+struct server_info_50 {
+ char sv50_name[CNLEN + 1];
+ unsigned char sv50_version_major; /* Major version # of net */
+ unsigned char sv50_version_minor; /* Minor version # of net */
+ uint32_t sv50_type; /* Server type */
+ char *sv50_comment; /* Exported server comment */
+ unsigned short sv50_security; /* SV_SECURITY_* (see below) */
+ unsigned short sv50_auditing; /* 0 = no auditing; !0 = auditing */
+ char *sv50_container; /* Security server/domain */
+ char *sv50_ab_server; /* Address book server */
+ char *sv50_ab_dll; /* Address book provider DLL */
+}; /* server_info_50 */
+
+
+struct server_info_2 {
+ char sv2_name[CNLEN + 1];
+ unsigned char sv2_version_major;
+ unsigned char sv2_version_minor;
+ uint32_t sv2_type;
+ char *sv2_comment;
+ uint32_t sv2_ulist_mtime; /* User list, last modification time */
+ uint32_t sv2_glist_mtime; /* Group list, last modification time */
+ uint32_t sv2_alist_mtime; /* Access list, last modification time */
+ uint16_t sv2_users; /* max number of users allowed */
+ uint16_t sv2_disc; /* auto-disconnect timeout(in minutes) */
+ char *sv2_alerts; /* alert names (semicolon separated) */
+ uint16_t sv2_security; /* SV_USERSECURITY or SV_SHARESECURITY */
+ uint16_t sv2_auditing; /* 0 = no auditing; nonzero = auditing */
+
+ uint16_t sv2_numadmin; /* max number of administrators allowed */
+ uint16_t sv2_lanmask; /* bit mask representing the srv'd nets */
+ uint16_t sv2_hidden; /* 0 = visible; nonzero = hidden */
+ uint16_t sv2_announce; /* visible server announce rate (sec) */
+ uint16_t sv2_anndelta; /* announce randomize interval (sec) */
+ /* name of guest account */
+ char sv2_guestacct[LM20_UNLEN + 1];
+ unsigned char sv2_pad1; /* Word alignment pad byte */
+ char *sv2_userpath; /* ASCIIZ path to user directories */
+ uint16_t sv2_chdevs; /* max # shared character devices */
+ uint16_t sv2_chdevq; /* max # character device queues */
+ uint16_t sv2_chdevjobs; /* max # character device jobs */
+ uint16_t sv2_connections; /* max # of connections */
+ uint16_t sv2_shares; /* max # of shares */
+ uint16_t sv2_openfiles; /* max # of open files */
+ uint16_t sv2_sessopens; /* max # of open files per session */
+ uint16_t sv2_sessvcs; /* max # of virtual circuits per client */
+ uint16_t sv2_sessreqs; /* max # of simul. reqs. from a client */
+ uint16_t sv2_opensearch; /* max # of open searches */
+ uint16_t sv2_activelocks; /* max # of active file locks */
+ uint16_t sv2_numreqbuf; /* number of server (standard) buffers */
+ uint16_t sv2_sizreqbuf; /* size of svr (standard) bufs (bytes) */
+ uint16_t sv2_numbigbuf; /* number of big (64K) buffers */
+ uint16_t sv2_numfiletasks; /* number of file worker processes */
+ uint16_t sv2_alertsched; /* alert counting interval (minutes) */
+ uint16_t sv2_erroralert; /* error log alerting threshold */
+ uint16_t sv2_logonalert; /* logon violation alerting threshold */
+ uint16_t sv2_accessalert; /* access violation alerting threshold */
+ uint16_t sv2_diskalert; /* low disk space alert threshold (KB) */
+ uint16_t sv2_netioalert; /* net I/O error ratio alert threshold */
+ /* (tenths of a percent) */
+ uint16_t sv2_maxauditsz; /* Maximum audit file size (KB) */
+ char *sv2_srvheuristics; /* performance related server switches */
+}; /* server_info_2 */
+
+
+struct server_info_3 {
+ char sv3_name[CNLEN + 1];
+ unsigned char sv3_version_major;
+ unsigned char sv3_version_minor;
+ uint32_t sv3_type;
+ char *sv3_comment;
+ uint32_t sv3_ulist_mtime; /* User list, last modification time */
+ uint32_t sv3_glist_mtime; /* Group list, last modification time */
+ uint32_t sv3_alist_mtime; /* Access list, last modification time */
+ uint16_t sv3_users; /* max number of users allowed */
+ uint16_t sv3_disc; /* auto-disconnect timeout(in minutes) */
+ char *sv3_alerts; /* alert names (semicolon separated) */
+ uint16_t sv3_security; /* SV_USERSECURITY or SV_SHARESECURITY */
+ uint16_t sv3_auditing; /* 0 = no auditing; nonzero = auditing */
+
+ uint16_t sv3_numadmin; /* max number of administrators allowed */
+ uint16_t sv3_lanmask; /* bit mask representing the srv'd nets */
+ uint16_t sv3_hidden; /* 0 = visible; nonzero = hidden */
+ uint16_t sv3_announce; /* visible server announce rate (sec) */
+ uint16_t sv3_anndelta; /* announce randomize interval (sec) */
+ /* name of guest account */
+ char sv3_guestacct[LM20_UNLEN + 1];
+ unsigned char sv3_pad1; /* Word alignment pad byte */
+ char *sv3_userpath; /* ASCIIZ path to user directories */
+ uint16_t sv3_chdevs; /* max # shared character devices */
+ uint16_t sv3_chdevq; /* max # character device queues */
+ uint16_t sv3_chdevjobs; /* max # character device jobs */
+ uint16_t sv3_connections; /* max # of connections */
+ uint16_t sv3_shares; /* max # of shares */
+ uint16_t sv3_openfiles; /* max # of open files */
+ uint16_t sv3_sessopens; /* max # of open files per session */
+ uint16_t sv3_sessvcs; /* max # of virtual circuits per client */
+ uint16_t sv3_sessreqs; /* max # of simul. reqs. from a client */
+ uint16_t sv3_opensearch; /* max # of open searches */
+ uint16_t sv3_activelocks; /* max # of active file locks */
+ uint16_t sv3_numreqbuf; /* number of server (standard) buffers */
+ uint16_t sv3_sizreqbuf; /* size of svr (standard) bufs (bytes) */
+ uint16_t sv3_numbigbuf; /* number of big (64K) buffers */
+ uint16_t sv3_numfiletasks; /* number of file worker processes */
+ uint16_t sv3_alertsched; /* alert counting interval (minutes) */
+ uint16_t sv3_erroralert; /* error log alerting threshold */
+ uint16_t sv3_logonalert; /* logon violation alerting threshold */
+ uint16_t sv3_accessalert; /* access violation alerting threshold */
+ uint16_t sv3_diskalert; /* low disk space alert threshold (KB) */
+ uint16_t sv3_netioalert; /* net I/O error ratio alert threshold */
+ /* (tenths of a percent) */
+ uint16_t sv3_maxauditsz; /* Maximum audit file size (KB) */
+ char *sv3_srvheuristics; /* performance related server switches */
+ uint32_t sv3_auditedevents; /* Audit event control mask */
+ uint16_t sv3_autoprofile; /* (0,1,2,3) = (NONE,LOAD,SAVE,or BOTH) */
+ char *sv3_autopath; /* file pathname (where to load & save) */
+}; /* server_info_3 */
+
+
+/*
+ * Mask to be applied to svX_version_major in order to obtain
+ * the major version number.
+ */
+#define MAJOR_VERSION_MASK 0x0F
+
+
+/*
+ * Bit-mapped values for svX_type fields. X = 1, 2, 3 etc.
+ *
+ * SV_TYPE_WORKSTATION 0x00000001 All workstations
+ * SV_TYPE_SERVER 0x00000002 All servers
+ * SV_TYPE_SQLSERVER 0x00000004 Any server running with SQL
+ * server
+ * SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
+ * SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
+ * SV_TYPE_TIME_SOURCE 0x00000020 Server running the timesource
+ * service
+ * SV_TYPE_AFP 0x00000040 Apple File Protocol servers
+ * SV_TYPE_NOVELL 0x00000080 Novell servers
+ * SV_TYPE_DOMAIN_MEMBER 0x00000100 Domain Member
+ * SV_TYPE_PRINTQ_SERVER 0x00000200 Server sharing print queue
+ * SV_TYPE_DIALIN_SERVER 0x00000400 Server running dialin service.
+ * SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
+ * SV_TYPE_NT 0x00001000 NT server
+ * SV_TYPE_WFW 0x00002000 Server running Windows for
+ * Workgroups
+ * SV_TYPE_SERVER_NT 0x00008000 Windows NT non DC server
+ * SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the browser
+ * service
+ * SV_TYPE_BACKUP_BROWSER 0x00020000 Backup browser server
+ * SV_TYPE_MASTER_BROWSER 0x00040000 Master browser server
+ * SV_TYPE_DOMAIN_MASTER 0x00080000 Domain Master Browser server
+ * SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Enumerate only entries marked
+ * "local"
+ * SV_TYPE_DOMAIN_ENUM 0x80000000 Enumerate Domains. The pszDomain
+ * parameter must be NULL.
+ */
+#define SV_TYPE_WORKSTATION 0x00000001
+#define SV_TYPE_SERVER 0x00000002
+#define SV_TYPE_SQLSERVER 0x00000004
+#define SV_TYPE_DOMAIN_CTRL 0x00000008
+#define SV_TYPE_DOMAIN_BAKCTRL 0x00000010
+#define SV_TYPE_TIME_SOURCE 0x00000020
+#define SV_TYPE_AFP 0x00000040
+/* Also set by Win95 NWSERVER */
+#define SV_TYPE_NOVELL 0x00000080
+#define SV_TYPE_DOMAIN_MEMBER 0x00000100
+#define SV_TYPE_PRINTQ_SERVER 0x00000200
+#define SV_TYPE_DIALIN_SERVER 0x00000400
+#define SV_TYPE_XENIX_SERVER 0x00000800
+#define SV_TYPE_NT 0x00001000
+#define SV_TYPE_WFW 0x00002000
+#define SV_TYPE_SERVER_NT 0x00008000
+#define SV_TYPE_POTENTIAL_BROWSER 0x00010000
+#define SV_TYPE_BACKUP_BROWSER 0x00020000
+#define SV_TYPE_MASTER_BROWSER 0x00040000
+#define SV_TYPE_DOMAIN_MASTER 0x00080000
+#define SV_TYPE_LOCAL_LIST_ONLY 0x40000000
+#define SV_TYPE_DOMAIN_ENUM 0x80000000
+/* Handy for NetServerEnum2 */
+#define SV_TYPE_ALL 0xFFFFFFFF
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_SVRAPI_H */
diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smbsrv/winioctl.h
new file mode 100644
index 0000000000..8a9badc544
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/winioctl.h
@@ -0,0 +1,475 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _SMBSRV_WINIOCTL_H
+#define _SMBSRV_WINIOCTL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Standard Windows NT IOCTL/FSCTL definitions (derived from the VC++
+ * include file of the same name).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _DEVIOCTL_
+#define _DEVIOCTL_
+
+/*
+ * begin_ntddk begin_wdm begin_nthal begin_ntifs
+ *
+ * Define the various device type values. Note that values used by Microsoft
+ * Corporation are in the range 0-32767, and 32768-65535 are reserved for use
+ * by customers.
+ */
+
+#define DEVICE_TYPE DWORD
+
+#define FILE_DEVICE_BEEP 0x00000001
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_CONTROLLER 0x00000004
+#define FILE_DEVICE_DATALINK 0x00000005
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_INPORT_PORT 0x0000000a
+#define FILE_DEVICE_KEYBOARD 0x0000000b
+#define FILE_DEVICE_MAILSLOT 0x0000000c
+#define FILE_DEVICE_MIDI_IN 0x0000000d
+#define FILE_DEVICE_MIDI_OUT 0x0000000e
+#define FILE_DEVICE_MOUSE 0x0000000f
+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SCANNER 0x00000019
+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_SCREEN 0x0000001c
+#define FILE_DEVICE_SOUND 0x0000001d
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_TRANSPORT 0x00000021
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_VIDEO 0x00000023
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_WAVE_IN 0x00000025
+#define FILE_DEVICE_WAVE_OUT 0x00000026
+#define FILE_DEVICE_8042_PORT 0x00000027
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+#define FILE_DEVICE_BATTERY 0x00000029
+#define FILE_DEVICE_BUS_EXTENDER 0x0000002a
+#define FILE_DEVICE_MODEM 0x0000002b
+#define FILE_DEVICE_VDM 0x0000002c
+#define FILE_DEVICE_MASS_STORAGE 0x0000002d
+#define FILE_DEVICE_SMB 0x0000002e
+#define FILE_DEVICE_KS 0x0000002f
+#define FILE_DEVICE_CHANGER 0x00000030
+#define FILE_DEVICE_SMARTCARD 0x00000031
+#define FILE_DEVICE_ACPI 0x00000032
+#define FILE_DEVICE_DVD 0x00000033
+#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034
+#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035
+#define FILE_DEVICE_DFS_VOLUME 0x00000036
+
+/*
+ * Macro definition for defining IOCTL and FSCTL function control codes. Note
+ * that function codes 0-2047 are reserved for Microsoft Corporation, and
+ * 2048-4095 are reserved for customers.
+ */
+
+#define CTL_CODE(DeviceType, Function, Method, Access) \
+ (((DeviceType) << 16) | ((Access) << 14) | \
+ ((Function) << 2) | (Method))
+
+/*
+ * Define the method codes for how buffers are passed for I/O and FS controls
+ */
+
+#define METHOD_BUFFERED 0
+#define METHOD_IN_DIRECT 1
+#define METHOD_OUT_DIRECT 2
+#define METHOD_NEITHER 3
+
+/*
+ * Define the access check value for any access
+ */
+
+#define FILE_ANY_ACCESS 0
+#define FILE_READ_ACCESS 0x0001 /* file & pipe */
+#define FILE_WRITE_ACCESS 0x0002 /* file & pipe */
+
+/* end_ntddk end_wdm end_nthal end_ntifs */
+
+#endif /* _DEVIOCTL_ */
+
+
+#ifndef _NTDDSTOR_H_
+#define _NTDDSTOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * IoControlCode values for storage devices
+ */
+
+#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
+
+/*
+ * The following device control codes are common for all class drivers. They
+ * should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE
+ * common codes
+ */
+
+#define IOCTL_STORAGE_CHECK_VERIFY \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_MEDIA_REMOVAL \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_EJECT_MEDIA \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_LOAD_MEDIA \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESERVE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RELEASE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_FIND_NEW_DEVICES \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_STORAGE_GET_MEDIA_TYPES \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_STORAGE_RESET_BUS \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESET_DEVICE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_STORAGE_GET_DEVICE_NUMBER \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _NTDDSTOR_H_ */
+
+/*
+ * IoControlCode values for disk devices.
+ */
+
+#define IOCTL_DISK_BASE FILE_DEVICE_DISK
+#define IOCTL_DISK_GET_DRIVE_GEOMETRY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_GET_PARTITION_INFO \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_SET_PARTITION_INFO \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_GET_DRIVE_LAYOUT \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_SET_DRIVE_LAYOUT \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_VERIFY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_FORMAT_TRACKS \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_REASSIGN_BLOCKS \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_PERFORMANCE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_IS_WRITABLE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_LOGGING \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_FORMAT_TRACKS_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_HISTOGRAM_STRUCTURE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_HISTOGRAM_DATA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_HISTOGRAM_RESET \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_REQUEST_STRUCTURE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_REQUEST_DATA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_CONTROLLER_NUMBER \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/*
+ * IOCTL support for SMART drive fault prediction.
+ */
+
+#define SMART_GET_VERSION \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define SMART_SEND_DRIVE_COMMAND \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define SMART_RCV_DRIVE_DATA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+
+/*
+ * The following device control codes are common for all class drivers. The
+ * functions codes defined here must match all of the other class drivers.
+ *
+ * Warning: these codes will be replaced in the future by equivalent
+ * IOCTL_STORAGE codes
+ */
+
+#define IOCTL_DISK_CHECK_VERIFY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_MEDIA_REMOVAL \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_EJECT_MEDIA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_LOAD_MEDIA \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_RESERVE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_RELEASE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_FIND_NEW_DEVICES \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_GET_MEDIA_TYPES \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_CHANGER_BASE FILE_DEVICE_CHANGER
+
+#define IOCTL_CHANGER_GET_PARAMETERS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_GET_STATUS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_GET_PRODUCT_DATA \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_SET_ACCESS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0004, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_CHANGER_GET_ELEMENT_STATUS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0005, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_SET_POSITION \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_EXCHANGE_MEDIUM \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_MOVE_MEDIUM \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x0009, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_REINITIALIZE_TRANSPORT \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CHANGER_QUERY_VOLUME_TAGS \
+ CTL_CODE(IOCTL_CHANGER_BASE, 0x000B, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#ifndef _FILESYSTEMFSCTL_
+#define _FILESYSTEMFSCTL_
+/*
+ * The following is a list of the native file system fsctls followed by
+ * additional network file system fsctls. Some values have been
+ * decommissioned.
+ */
+
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REQUEST_BATCH_OPLOCK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_OPBATCH_ACK_CLOSE_PENDING \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_OPLOCK_BREAK_NOTIFY \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_LOCK_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_UNLOCK_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DISMOUNT_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* decommissioned fsctl value 9 */
+#define FSCTL_IS_VOLUME_MOUNTED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* PATHNAME_BUFFER, */
+#define FSCTL_IS_PATHNAME_VALID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_MARK_VOLUME_DIRTY \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* decommissioned fsctl value 13 */
+#define FSCTL_QUERY_RETRIEVAL_POINTERS \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_GET_COMPRESSION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SET_COMPRESSION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+/* decommissioned fsctl value 17 */
+/* decommissioned fsctl value 18 */
+#define FSCTL_MARK_AS_SYSTEM_HIVE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_OPLOCK_BREAK_ACK_NO_2 \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_INVALIDATE_VOLUMES \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* FSCTL_QUERY_FAT_BPB_BUFFER */
+#define FSCTL_QUERY_FAT_BPB \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_REQUEST_FILTER_OPLOCK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* FILESYSTEM_STATISTICS */
+#define FSCTL_FILESYSTEM_GET_STATISTICS \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* NTFS_VOLUME_DATA_BUFFER */
+#define FSCTL_GET_NTFS_VOLUME_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* NTFS_FILE_RECORD_INPUT_BUFFER, NTFS_FILE_RECORD_OUTPUT_BUFFER */
+#define FSCTL_GET_NTFS_FILE_RECORD \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* STARTING_LCN_INPUT_BUFFER, VOLUME_BITMAP_BUFFER */
+#define FSCTL_GET_VOLUME_BITMAP \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER */
+#define FSCTL_GET_RETRIEVAL_POINTERS \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* MOVE_FILE_DATA, */
+#define FSCTL_MOVE_FILE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_IS_VOLUME_DIRTY \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_GET_HFS_INFORMATION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 31, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_ALLOW_EXTENDED_DASD_IO \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_READ_PROPERTY_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 33, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_WRITE_PROPERTY_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 34, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_FIND_FILES_BY_SID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* decommissioned fsctl value 36 */
+#define FSCTL_DUMP_PROPERTY_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 37, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* FILE_OBJECTID_BUFFER */
+#define FSCTL_SET_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_OBJECTID_BUFFER */
+#define FSCTL_GET_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DELETE_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* REPARSE_DATA_BUFFER, */
+#define FSCTL_SET_REPARSE_POINT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* REPARSE_DATA_BUFFER */
+#define FSCTL_GET_REPARSE_POINT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/* REPARSE_DATA_BUFFER, */
+#define FSCTL_DELETE_REPARSE_POINT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* MFT_ENUM_DATA, */
+#define FSCTL_ENUM_USN_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_READ_ACCESS)
+/* BULK_SECURITY_TEST_DATA, */
+#define FSCTL_SECURITY_ID_CHECK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, FILE_READ_ACCESS)
+/* READ_USN_JOURNAL_DATA, USN */
+#define FSCTL_READ_USN_JOURNAL \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_SET_OBJECT_ID_EXTENDED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 47, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_OBJECTID_BUFFER */
+#define FSCTL_CREATE_OR_GET_OBJECT_ID \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SET_SPARSE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_ZERO_DATA_INFORMATION, */
+#define FSCTL_SET_ZERO_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* FILE_ALLOCATED_RANGE_BUFFER, FILE_ALLOCATED_RANGE_BUFFER */
+#define FSCTL_QUERY_ALLOCATED_RANGES \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_ENABLE_UPGRADE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+/* ENCRYPTION_BUFFER, */
+#define FSCTL_SET_ENCRYPTION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_ENCRYPTION_FSCTL_IO \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 54, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* ENCRYPTED_DATA_INFO, */
+#define FSCTL_WRITE_RAW_ENCRYPTED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 55, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* REQUEST_RAW_ENCRYPTED_DATA, ENCRYPTED_DATA_INFO */
+#define FSCTL_READ_RAW_ENCRYPTED \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 56, METHOD_NEITHER, FILE_ANY_ACCESS)
+/* CREATE_USN_JOUNRAL_DATA, */
+#define FSCTL_CREATE_USN_JOURNAL \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_READ_ACCESS)
+/* Read the Usn Record for a file */
+#define FSCTL_READ_FILE_USN_DATA \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_READ_ACCESS)
+/* Generate Close Usn Record */
+#define FSCTL_WRITE_USN_CLOSE_RECORD \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_EXTEND_VOLUME \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif /* _FILESYSTEMFSCTL_ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_WINIOCTL_H */
diff --git a/usr/src/uts/common/smbsrv/winsvc.h b/usr/src/uts/common/smbsrv/winsvc.h
new file mode 100644
index 0000000000..9da682c1bb
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/winsvc.h
@@ -0,0 +1,217 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_WINSVC_H
+#define _SMBSRV_WINSVC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NT Service Control interface definition for the Service Control
+ * Manager (SCM).
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Service types (Bit Mask).
+ *
+ * SERVICE_WIN32_OWN_PROCESS The service runs in its own process.
+ * SERVICE_WIN32_SHARE_PROCESS The service shares a process with other
+ * services.
+ */
+#define SERVICE_KERNEL_DRIVER 0x00000001
+#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002
+#define SERVICE_ADAPTER 0x00000004
+#define SERVICE_RECOGNIZER_DRIVER 0x00000008
+#define SERVICE_WIN32_OWN_PROCESS 0x00000010
+#define SERVICE_WIN32_SHARE_PROCESS 0x00000020
+#define SERVICE_INTERACTIVE_PROCESS 0x00000100
+
+#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER \
+ | SERVICE_FILE_SYSTEM_DRIVER \
+ | SERVICE_RECOGNIZER_DRIVER)
+
+#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS \
+ | SERVICE_WIN32_SHARE_PROCESS)
+
+#define SERVICE_TYPE_ALL (SERVICE_WIN32 \
+ | SERVICE_ADAPTER \
+ | SERVICE_DRIVER \
+ | SERVICE_INTERACTIVE_PROCESS)
+
+/*
+ * Start type.
+ */
+#define SERVICE_BOOT_START 0x00000000
+#define SERVICE_SYSTEM_START 0x00000001
+#define SERVICE_AUTO_START 0x00000002
+#define SERVICE_DEMAND_START 0x00000003
+#define SERVICE_DISABLED 0x00000004
+
+/*
+ * Error control type.
+ */
+#define SERVICE_ERROR_IGNORE 0x00000000
+#define SERVICE_ERROR_NORMAL 0x00000001
+#define SERVICE_ERROR_SEVERE 0x00000002
+#define SERVICE_ERROR_CRITICAL 0x00000003
+
+/*
+ * Value to indicate no change to an optional parameter.
+ */
+#define SERVICE_NO_CHANGE 0xffffffff
+
+/*
+ * Service State - for Enum Requests (Bit Mask).
+ */
+#define SERVICE_ACTIVE 0x00000001
+#define SERVICE_INACTIVE 0x00000002
+#define SERVICE_STATE_ALL (SERVICE_ACTIVE | SERVICE_INACTIVE)
+
+/*
+ * Controls
+ */
+#define SERVICE_CONTROL_STOP 0x00000001
+#define SERVICE_CONTROL_PAUSE 0x00000002
+#define SERVICE_CONTROL_CONTINUE 0x00000003
+#define SERVICE_CONTROL_INTERROGATE 0x00000004
+#define SERVICE_CONTROL_SHUTDOWN 0x00000005
+#define SERVICE_CONTROL_PARAMCHANGE 0x00000006
+#define SERVICE_CONTROL_NETBINDADD 0x00000007
+#define SERVICE_CONTROL_NETBINDREMOVE 0x00000008
+#define SERVICE_CONTROL_NETBINDENABLE 0x00000009
+#define SERVICE_CONTROL_NETBINDDISABLE 0x0000000A
+
+/*
+ * Service State -- for CurrentState
+ */
+#define SERVICE_STOPPED 0x00000001
+#define SERVICE_START_PENDING 0x00000002
+#define SERVICE_STOP_PENDING 0x00000003
+#define SERVICE_RUNNING 0x00000004
+#define SERVICE_CONTINUE_PENDING 0x00000005
+#define SERVICE_PAUSE_PENDING 0x00000006
+#define SERVICE_PAUSED 0x00000007
+
+/*
+ * Controls Accepted (Bit Mask)
+ *
+ * SERVICE_ACCEPT_NETBINDCHANGE
+ * Windows 2000/XP: The service is a network component that
+ * can accept changes in its binding without being stopped and restarted.
+ * This control code allows the service to receive SERVICE_CONTROL_NETBINDADD,
+ * SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE, and
+ * SERVICE_CONTROL_NETBINDDISABLE notifications.
+ *
+ * SERVICE_ACCEPT_PARAMCHANGE
+ * Windows 2000/XP: The service can reread its startup parameters without
+ * being stopped and restarted. This control code allows the service to
+ * receive SERVICE_CONTROL_PARAMCHANGE notifications.
+ *
+ * SERVICE_ACCEPT_PAUSE_CONTINUE
+ * The service can be paused and continued. This control code allows the
+ * service to receive SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE
+ * notifications.
+ *
+ * SERVICE_ACCEPT_SHUTDOWN
+ * The service is notified when system shutdown occurs. This control code
+ * allows the service to receive SERVICE_CONTROL_SHUTDOWN notifications.
+ * Note that ControlService cannot send this notification; only the system
+ * can send it.
+ *
+ * SERVICE_ACCEPT_STOP
+ * The service can be stopped. This control code allows the service to
+ * receive SERVICE_CONTROL_STOP notifications.
+ */
+#define SERVICE_ACCEPT_STOP 0x00000001
+#define SERVICE_ACCEPT_PAUSE_CONTINUE 0x00000002
+#define SERVICE_ACCEPT_SHUTDOWN 0x00000004
+#define SERVICE_ACCEPT_PARAMCHANGE 0x00000008
+#define SERVICE_ACCEPT_NETBINDCHANGE 0x00000010
+
+/*
+ * Service Control Manager object specific access types.
+ */
+#define SC_MANAGER_CONNECT 0x0001
+#define SC_MANAGER_CREATE_SERVICE 0x0002
+#define SC_MANAGER_ENUMERATE_SERVICE 0x0004
+#define SC_MANAGER_LOCK 0x0008
+#define SC_MANAGER_QUERY_LOCK_STATUS 0x0010
+#define SC_MANAGER_MODIFY_BOOT_CONFIG 0x0020
+
+#define SC_MANAGER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED \
+ | SC_MANAGER_CONNECT \
+ | SC_MANAGER_CREATE_SERVICE \
+ | SC_MANAGER_ENUMERATE_SERVICE \
+ | SC_MANAGER_LOCK \
+ | SC_MANAGER_QUERY_LOCK_STATUS \
+ | SC_MANAGER_MODIFY_BOOT_CONFIG)
+
+/*
+ * Service object specific access type.
+ */
+#define SERVICE_QUERY_CONFIG 0x0001
+#define SERVICE_CHANGE_CONFIG 0x0002
+#define SERVICE_QUERY_STATUS 0x0004
+#define SERVICE_ENUMERATE_DEPENDENTS 0x0008
+#define SERVICE_START 0x0010
+#define SERVICE_STOP 0x0020
+#define SERVICE_PAUSE_CONTINUE 0x0040
+#define SERVICE_INTERROGATE 0x0080
+#define SERVICE_USER_DEFINED_CONTROL 0x0100
+
+#define SERVICE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED \
+ | SERVICE_QUERY_CONFIG \
+ | SERVICE_CHANGE_CONFIG \
+ | SERVICE_QUERY_STATUS \
+ | SERVICE_ENUMERATE_DEPENDENTS \
+ | SERVICE_START \
+ | SERVICE_STOP \
+ | SERVICE_PAUSE_CONTINUE \
+ | SERVICE_INTERROGATE \
+ | SERVICE_USER_DEFINED_CONTROL)
+
+/*
+ * Info levels for ChangeServiceConfig2 and QueryServiceConfig2.
+ */
+#define SERVICE_CONFIG_DESCRIPTION 1
+#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+
+/*
+ * Actions to take on service failure (SC_ACTION_TYPE).
+ */
+#define SC_ACTION_NONE 0
+#define SC_ACTION_RESTART 1
+#define SC_ACTION_REBOOT 2
+#define SC_ACTION_RUN_COMMAND 3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_WINSVC_H */
diff --git a/usr/src/uts/common/smbsrv/wintypes.h b/usr/src/uts/common/smbsrv/wintypes.h
new file mode 100644
index 0000000000..698e5dcdde
--- /dev/null
+++ b/usr/src/uts/common/smbsrv/wintypes.h
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBSRV_WINTYPES_H
+#define _SMBSRV_WINTYPES_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Standard win32 types and definitions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef UNSIGNED_TYPES_DEFINED
+#define UNSIGNED_TYPES_DEFINED
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned int DWORD;
+/* XXX PGD Shouldn't this be "char *"? */
+typedef unsigned char *LPTSTR;
+typedef unsigned char *LPBYTE;
+typedef unsigned short *LPWORD;
+typedef unsigned int *LPDWORD;
+
+#endif /* UNSIGNED_TYPES_DEFINED */
+
+
+#ifndef ANY_SIZE_ARRAY
+#define ANY_SIZE_ARRAY 1
+#endif /* ANY_SIZE_ARRAY */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBSRV_WINTYPES_H */
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 4cd97b5c3a..55b5b18e42 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -76,6 +76,7 @@ CHKHDRS= \
acct.h \
acctctl.h \
acl.h \
+ acl_impl.h \
aggr.h \
aggr_impl.h \
aio.h \
@@ -85,6 +86,7 @@ CHKHDRS= \
ascii.h \
asynch.h \
atomic.h \
+ attr.h \
audio.h \
audiodebug.h \
audioio.h \
@@ -223,6 +225,7 @@ CHKHDRS= \
exacct_impl.h \
exec.h \
exechdr.h \
+ extdirent.h \
fault.h \
fasttrap.h \
fasttrap_impl.h \
@@ -540,6 +543,7 @@ CHKHDRS= \
turnstile.h \
types.h \
types32.h \
+ tzfile.h \
u8_textprep.h \
u8_textprep_data.h \
uadmin.h \
diff --git a/usr/src/uts/common/sys/acl.h b/usr/src/uts/common/sys/acl.h
index b0dc94240d..98f962deba 100644
--- a/usr/src/uts/common/sys/acl.h
+++ b/usr/src/uts/common/sys/acl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,6 +29,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
+#include <sys/acl_impl.h>
#ifdef __cplusplus
extern "C" {
@@ -62,7 +63,7 @@ typedef struct acl_info acl_t;
#define ACL_DEFAULT (0x1000) /* default flag */
/* default object owner */
#define DEF_USER_OBJ (ACL_DEFAULT | USER_OBJ)
-/* defalut additional users */
+/* default additional users */
#define DEF_USER (ACL_DEFAULT | USER)
/* default owning group */
#define DEF_GROUP_OBJ (ACL_DEFAULT | GROUP_OBJ)
@@ -101,6 +102,7 @@ typedef struct acl_info acl_t;
#define ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010
#define ACE_FAILED_ACCESS_ACE_FLAG 0x0020
#define ACE_IDENTIFIER_GROUP 0x0040
+#define ACE_INHERITED_ACE 0x0080
#define ACE_OWNER 0x1000
#define ACE_GROUP 0x2000
#define ACE_EVERYONE 0x4000
@@ -110,6 +112,44 @@ typedef struct acl_info acl_t;
#define ACE_SYSTEM_AUDIT_ACE_TYPE 0x0002
#define ACE_SYSTEM_ALARM_ACE_TYPE 0x0003
+#define ACL_AUTO_INHERIT 0x0001
+#define ACL_PROTECTED 0x0002
+#define ACL_DEFAULTED 0x0004
+#define ACL_FLAGS_ALL (ACL_AUTO_INHERIT|ACL_PROTECTED| \
+ ACL_DEFAULTED)
+
+#ifdef _KERNEL
+
+/*
+ * These are only applicable in a CIFS context.
+ */
+#define ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE 0x04
+#define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05
+#define ACE_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06
+#define ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07
+#define ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08
+#define ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE 0x09
+#define ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE 0x0A
+#define ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE 0x0B
+#define ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE 0x0C
+#define ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE 0x0D
+#define ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE 0x0E
+#define ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE 0x0F
+#define ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 0x10
+
+#define ACE_ALL_TYPES 0x001F
+
+typedef struct ace_object {
+ uid_t a_who; /* uid or gid */
+ uint32_t a_access_mask; /* read,write,... */
+ uint16_t a_flags; /* see below */
+ uint16_t a_type; /* allow or deny */
+ uint8_t a_obj_type[16]; /* obj type */
+ uint8_t a_inherit_obj_type[16]; /* inherit obj */
+} ace_object_t;
+
+#endif
+
#define ACE_ALL_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \
ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \
@@ -125,7 +165,10 @@ typedef struct acl_info acl_t;
ACE_INHERIT_ONLY_ACE | \
ACE_IDENTIFIER_GROUP)
-#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
+#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE| \
+ ACE_IDENTIFIER_GROUP)
+#define ACE_INHERIT_FLAGS (ACE_FILE_INHERIT_ACE| \
+ ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
/* cmd args to acl(2) for aclent_t */
#define GETACL 1
diff --git a/usr/src/uts/common/sys/acl_impl.h b/usr/src/uts/common/sys/acl_impl.h
new file mode 100644
index 0000000000..b82f259143
--- /dev/null
+++ b/usr/src/uts/common/sys/acl_impl.h
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_ACL_IMPL_H
+#define _SYS_ACL_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * acl flags
+ *
+ * ACL_AUTO_INHERIT, ACL_PROTECTED and ACL_DEFAULTED
+ * flags can also be stored in this field.
+ */
+#define ACL_IS_TRIVIAL 0x10000
+#define ACL_IS_DIR 0x20000
+
+typedef enum acl_type {
+ ACLENT_T = 0,
+ ACE_T = 1
+} acl_type_t;
+
+struct acl_info {
+ acl_type_t acl_type; /* style of acl */
+ int acl_cnt; /* number of acl entries */
+ int acl_entry_size; /* sizeof acl entry */
+ int acl_flags; /* special flags about acl */
+ void *acl_aclp; /* the acl */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ACL_IMPL_H */
diff --git a/usr/src/uts/common/sys/attr.h b/usr/src/uts/common/sys/attr.h
new file mode 100644
index 0000000000..34e802eed1
--- /dev/null
+++ b/usr/src/uts/common/sys/attr.h
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_ATTR_H
+#define _SYS_ATTR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <nfs/nfs.h>
+#endif
+#include <sys/nvpair.h>
+
+/* Attribute names for nvlist's */
+#define A_CRTIME "crtime"
+#define A_HIDDEN "hidden"
+#define A_SYSTEM "system"
+#define A_READONLY "readonly"
+#define A_ARCHIVE "archive"
+#define A_NOUNLINK "nounlink"
+#define A_IMMUTABLE "immutable"
+#define A_APPENDONLY "appendonly"
+#define A_NODUMP "nodump"
+#define A_OPAQUE "opaque"
+#define A_AV_QUARANTINED "av_quarantined"
+#define A_AV_MODIFIED "av_modified"
+#define A_FSID "fsid"
+#define A_AV_SCANSTAMP "av_scanstamp"
+#define A_MDEV "mdev"
+#define A_OWNERSID "ownersid"
+#define A_GROUPSID "groupsid"
+
+/* Attribute option for utilities */
+#define O_HIDDEN "H"
+#define O_SYSTEM "S"
+#define O_READONLY "R"
+#define O_ARCHIVE "A"
+#define O_NOUNLINK "u"
+#define O_IMMUTABLE "i"
+#define O_APPENDONLY "a"
+#define O_NODUMP "d"
+#define O_AV_QUARANTINED "q"
+#define O_AV_MODIFIED "m"
+#define O_NONE ""
+
+/* ownersid and groupsid are composed of two nvpairs */
+#define SID_DOMAIN "domain"
+#define SID_RID "rid"
+
+typedef enum {
+ F_ATTR_INVAL = -1,
+ F_ARCHIVE,
+ F_HIDDEN,
+ F_READONLY,
+ F_SYSTEM,
+ F_APPENDONLY,
+ F_NODUMP,
+ F_IMMUTABLE,
+ F_AV_MODIFIED,
+ F_OPAQUE,
+ F_AV_SCANSTAMP,
+ F_AV_QUARANTINED,
+ F_NOUNLINK,
+ F_CRTIME,
+ F_OWNERSID,
+ F_GROUPSID,
+ F_FSID,
+ F_MDEV,
+ F_ATTR_ALL
+} f_attr_t;
+
+#define VIEW_READONLY "SUNWattr_ro"
+#define VIEW_READWRITE "SUNWattr_rw"
+
+/*
+ * These are the supported views into the virtual sysattr directory.
+ * Additional views should be added before XATTR_VIEW_LAST.
+ */
+typedef enum {
+ XATTR_VIEW_INVALID = -1,
+ XATTR_VIEW_READONLY,
+ XATTR_VIEW_READWRITE,
+ XATTR_VIEW_LAST
+} xattr_view_t;
+
+typedef struct {
+ char *x_name;
+ char *x_option;
+ xattr_view_t x_xattr_view;
+ data_type_t x_data_type;
+} xattr_entry_t;
+
+#ifdef _KERNEL
+#define XATTR_MAXFIDSZ NFS_FHMAXDATA
+
+typedef struct {
+ uint16_t len;
+ char parent_fid[XATTR_MAXFIDSZ];
+ uint16_t parent_len;
+ uint16_t dir_offset;
+} xattr_fid_t;
+
+#define XATTR_FIDSZ (sizeof (xattr_fid_t) - sizeof (uint16_t))
+
+int xattr_dir_vget(vfs_t *, vnode_t **, fid_t *);
+#endif
+
+int attr_count(void);
+const char *attr_to_name(f_attr_t);
+const char *attr_to_option(f_attr_t);
+f_attr_t name_to_attr(const char *name);
+f_attr_t option_to_attr(const char *option);
+xattr_view_t attr_to_xattr_view(f_attr_t attr);
+data_type_t attr_to_data_type(f_attr_t attr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ATTR_H */
diff --git a/usr/src/uts/common/sys/byteorder.h b/usr/src/uts/common/sys/byteorder.h
index b80a0f02bd..36a82e2bbf 100644
--- a/usr/src/uts/common/sys/byteorder.h
+++ b/usr/src/uts/common/sys/byteorder.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,6 +128,68 @@ extern in_port_t ntohs(in_port_t);
#define BE_64(x) BSWAP_64(x)
#endif
+/*
+ * Macros to read unaligned values from a specific byte order to
+ * native byte order
+ */
+
+#define BE_IN8(xa) \
+ *((uint8_t *)(xa))
+
+#define BE_IN16(xa) \
+ (((uint16_t)BE_IN8(xa) << 8) | BE_IN8((uint8_t *)(xa)+1))
+
+#define BE_IN32(xa) \
+ (((uint32_t)BE_IN16(xa) << 16) | BE_IN16((uint8_t *)(xa)+2))
+
+#define BE_IN64(xa) \
+ (((uint64_t)BE_IN32(xa) << 32) | BE_IN32((uint8_t *)(xa)+4))
+
+#define LE_IN8(xa) \
+ *((uint8_t *)(xa))
+
+#define LE_IN16(xa) \
+ (((uint16_t)LE_IN8((uint8_t *)(xa) + 1) << 8) | LE_IN8(xa))
+
+#define LE_IN32(xa) \
+ (((uint32_t)LE_IN16((uint8_t *)(xa) + 2) << 16) | LE_IN16(xa))
+
+#define LE_IN64(xa) \
+ (((uint64_t)LE_IN32((uint8_t *)(xa) + 4) << 32) | LE_IN32(xa))
+
+/*
+ * Macros to write unaligned values from native byte order to a specific byte
+ * order.
+ */
+
+#define BE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define BE_OUT16(xa, yv) \
+ BE_OUT8((uint8_t *)(xa) + 1, yv); \
+ BE_OUT8((uint8_t *)(xa), (yv) >> 8);
+
+#define BE_OUT32(xa, yv) \
+ BE_OUT16((uint8_t *)(xa) + 2, yv); \
+ BE_OUT16((uint8_t *)(xa), (yv) >> 16);
+
+#define BE_OUT64(xa, yv) \
+ BE_OUT32((uint8_t *)(xa) + 4, yv); \
+ BE_OUT32((uint8_t *)(xa), (yv) >> 32);
+
+#define LE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define LE_OUT16(xa, yv) \
+ LE_OUT8((uint8_t *)(xa), yv); \
+ LE_OUT8((uint8_t *)(xa) + 1, (yv) >> 8);
+
+#define LE_OUT32(xa, yv) \
+ LE_OUT16((uint8_t *)(xa), yv); \
+ LE_OUT16((uint8_t *)(xa) + 2, (yv) >> 16);
+
+#define LE_OUT64(xa, yv) \
+ LE_OUT32((uint8_t *)(xa), yv); \
+ LE_OUT32((uint8_t *)(xa) + 4, (yv) >> 32);
+
#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/cred.h b/usr/src/uts/common/sys/cred.h
index 29e9a6ddeb..41f2827f78 100644
--- a/usr/src/uts/common/sys/cred.h
+++ b/usr/src/uts/common/sys/cred.h
@@ -170,6 +170,8 @@ extern void crsetsidlist(cred_t *, struct ksidlist *);
extern struct ksid *crgetsid(const cred_t *, int);
extern struct ksidlist *crgetsidlist(const cred_t *);
+extern int crsetpriv(cred_t *, ...);
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/ctfs_impl.h b/usr/src/uts/common/sys/ctfs_impl.h
index 1c835a60f6..77e491a550 100644
--- a/usr/src/uts/common/sys/ctfs_impl.h
+++ b/usr/src/uts/common/sys/ctfs_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -207,11 +206,16 @@ extern vnode_t *ctfs_create_symnode(vnode_t *, contract_t *);
* common ctfs routines
*/
extern void ctfs_common_getattr(vnode_t *, vattr_t *);
-extern int ctfs_close(vnode_t *, int, int, offset_t, cred_t *);
-extern int ctfs_access_dir(vnode_t *, int, int, cred_t *);
-extern int ctfs_access_readonly(vnode_t *, int, int, cred_t *);
-extern int ctfs_access_readwrite(vnode_t *, int, int, cred_t *);
-extern int ctfs_open(vnode_t **, int, cred_t *);
+extern int ctfs_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
+extern int ctfs_access_dir(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int ctfs_access_readonly(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int ctfs_access_readwrite(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int ctfs_open(vnode_t **, int, cred_t *,
+ caller_context_t *);
/*
* vnode ops vector templates
diff --git a/usr/src/uts/common/sys/epm.h b/usr/src/uts/common/sys/epm.h
index 35b656409b..d1c67f383f 100644
--- a/usr/src/uts/common/sys/epm.h
+++ b/usr/src/uts/common/sys/epm.h
@@ -33,6 +33,7 @@
#include <sys/devops.h>
#include <sys/ddi_impldefs.h>
#include <sys/taskq.h>
+#include <sys/tzfile.h>
/*
* XXXX
@@ -166,7 +167,7 @@ typedef struct pm_component {
* kidsupcnt counts (the number of components of new-style children at non-zero
* level (unknown counts as non-zero)) + (the number of old-style children with
* component 0 at non-zero level) for parents that have not asked for
- * notifcation. When kidsupcnt is 0 for a nexus node, then pm scans it,
+ * notification. When kidsupcnt is 0 for a nexus node, then pm scans it,
* otherwise it leaves it alone.
* Parents that ask for notification always get get scanned,
* so we keep their kidsupcnt at zero.
@@ -911,7 +912,7 @@ typedef struct pscc { /* pm_state_change_control */
#define PSCCOUNT 128 /* number of state change entries kept per process */
/*
- * Struct used to track the existance of devices exporting the
+ * Struct used to track the existence of devices exporting the
* no-involuntary-power-cycles property, and remember things from their
* devinfo node for later attach.
*/
@@ -985,14 +986,6 @@ typedef struct pm_desc_pwrchk {
* These defines are used by pm_trans_check() to calculate time.
* Mostly copied from "tzfile.h".
*/
-#define EPOCH_YEAR 1970
-#define SECSPERMIN 60
-#define MINSPERHOUR 60
-#define HOURSPERDAY 24
-#define DAYSPERWEEK 7
-#define DAYSPERNYEAR 365
-#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
-#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
#define DC_SPY (SECSPERDAY * DAYSPERNYEAR)
#define DC_SPW (SECSPERDAY * DAYSPERWEEK)
#define DC_SPD SECSPERDAY
diff --git a/usr/src/uts/common/sys/extdirent.h b/usr/src/uts/common/sys/extdirent.h
new file mode 100644
index 0000000000..3f9a665f00
--- /dev/null
+++ b/usr/src/uts/common/sys/extdirent.h
@@ -0,0 +1,77 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_EXTDIRENT_H
+#define _SYS_EXTDIRENT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#if defined(_KERNEL)
+
+/*
+ * Extended file-system independent directory entry. This style of
+ * dirent provides additional informational flag bits for each
+ * directory entry. This dirent will be returned instead of the
+ * standard dirent if a VOP_READDIR() requests dirent flags via
+ * V_RDDIR_ENTFLAGS, and if the file system supports the flags.
+ */
+typedef struct edirent {
+ ino64_t ed_ino; /* "inode number" of entry */
+ off64_t ed_off; /* offset of disk directory entry */
+ uint32_t ed_eflags; /* per-entry flags */
+ unsigned short ed_reclen; /* length of this record */
+ char ed_name[1]; /* name of file */
+} edirent_t;
+
+#define EDIRENT_RECLEN(namelen) \
+ ((offsetof(edirent_t, ed_name[0]) + 1 + (namelen) + 7) & ~ 7)
+#define EDIRENT_NAMELEN(reclen) \
+ ((reclen) - (offsetof(edirent_t, ed_name[0])))
+
+/*
+ * Extended entry flags
+ * Extended entries include a bitfield of extra information
+ * regarding that entry.
+ */
+#define ED_CASE_CONFLICT 0x10 /* Disconsidering case, entry is not unique */
+
+/*
+ * Extended flags accessor function
+ */
+#define ED_CASE_CONFLICTS(x) ((x)->ed_eflags & ED_CASE_CONFLICT)
+
+#endif /* defined(_KERNEL) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_EXTDIRENT_H */
diff --git a/usr/src/uts/common/sys/fcntl.h b/usr/src/uts/common/sys/fcntl.h
index 70df5244f6..cb55161060 100644
--- a/usr/src/uts/common/sys/fcntl.h
+++ b/usr/src/uts/common/sys/fcntl.h
@@ -329,6 +329,8 @@ typedef struct fshare {
#define F_RDACC 0x1 /* Read-only share access */
#define F_WRACC 0x2 /* Write-only share access */
#define F_RWACC 0x3 /* Read-Write share access */
+#define F_RMACC 0x4 /* private flag: Delete share access */
+#define F_MDACC 0x20 /* private flag: Metadata share access */
/*
* f_deny values
@@ -337,6 +339,7 @@ typedef struct fshare {
#define F_RDDNY 0x1 /* Deny others read share access */
#define F_WRDNY 0x2 /* Deny others write share access */
#define F_RWDNY 0x3 /* Deny others read or write share access */
+#define F_RMDNY 0x4 /* private flag: Deny delete share access */
#define F_COMPAT 0x8 /* Set share to old DOS compatibility mode */
#define F_MANDDNY 0x10 /* private flag: mandatory enforcement */
#endif /* defined(__EXTENSIONS__) || !defined(__XOPEN_OR_POSIX) */
diff --git a/usr/src/uts/common/sys/fem.h b/usr/src/uts/common/sys/fem.h
index 2816734291..e1f051b4ad 100644
--- a/usr/src/uts/common/sys/fem.h
+++ b/usr/src/uts/common/sys/fem.h
@@ -92,6 +92,8 @@ typedef struct fsem fsem_t;
typedef int femop_t();
+typedef void (*fem_func_t)(void *);
+
/*
* The following enumerations specify the conditions
* under which a monitor (operation/argument combination)
@@ -146,95 +148,119 @@ struct fem_head {
* the fem structure (below) and the fs_func_p union (vfs_opreg.h).
*/
#define FEM_OPS \
- int (*femop_open)(femarg_t *vf, int mode, cred_t *cr); \
+ int (*femop_open)(femarg_t *vf, int mode, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_close)(femarg_t *vf, int flag, int count, \
- offset_t offset, cred_t *cr); \
+ offset_t offset, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_read)(femarg_t *vf, uio_t *uiop, int ioflag, \
- cred_t *cr, struct caller_context *ct); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_write)(femarg_t *vf, uio_t *uiop, int ioflag, \
- cred_t *cr, struct caller_context *ct); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_ioctl)(femarg_t *vf, int cmd, intptr_t arg, \
- int flag, cred_t *cr, int *rvalp); \
+ int flag, cred_t *cr, int *rvalp, \
+ caller_context_t *ct); \
int (*femop_setfl)(femarg_t *vf, int oflags, int nflags, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_getattr)(femarg_t *vf, vattr_t *vap, int flags, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_setattr)(femarg_t *vf, vattr_t *vap, int flags, \
cred_t *cr, caller_context_t *ct); \
int (*femop_access)(femarg_t *vf, int mode, int flags, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_lookup)(femarg_t *vf, char *nm, vnode_t **vpp, \
pathname_t *pnp, int flags, vnode_t *rdir, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct, \
+ int *direntflags, pathname_t *realpnp); \
int (*femop_create)(femarg_t *vf, char *name, vattr_t *vap, \
vcexcl_t excl, int mode, vnode_t **vpp, \
- cred_t *cr, int flag); \
- int (*femop_remove)(femarg_t *vf, char *nm, cred_t *cr); \
+ cred_t *cr, int flag, caller_context_t *ct, \
+ vsecattr_t *vsecp); \
+ int (*femop_remove)(femarg_t *vf, char *nm, cred_t *cr, \
+ caller_context_t *ct, int flags); \
int (*femop_link)(femarg_t *vf, vnode_t *svp, char *tnm, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct, int flags); \
int (*femop_rename)(femarg_t *vf, char *snm, vnode_t *tdvp, \
- char *tnm, cred_t *cr); \
+ char *tnm, cred_t *cr, caller_context_t *ct, \
+ int flags); \
int (*femop_mkdir)(femarg_t *vf, char *dirname, vattr_t *vap, \
- vnode_t **vpp, cred_t *cr); \
+ vnode_t **vpp, cred_t *cr, \
+ caller_context_t *ct, int flags, \
+ vsecattr_t *vsecp); \
int (*femop_rmdir)(femarg_t *vf, char *nm, vnode_t *cdir, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct, int flags); \
int (*femop_readdir)(femarg_t *vf, uio_t *uiop, cred_t *cr, \
- int *eofp); \
+ int *eofp, caller_context_t *ct, int flags); \
int (*femop_symlink)(femarg_t *vf, char *linkname, \
- vattr_t *vap, char *target, cred_t *cr); \
- int (*femop_readlink)(femarg_t *vf, uio_t *uiop, cred_t *cr); \
- int (*femop_fsync)(femarg_t *vf, int syncflag, cred_t *cr); \
- void (*femop_inactive)(femarg_t *vf, cred_t *cr); \
- int (*femop_fid)(femarg_t *vf, fid_t *fidp); \
+ vattr_t *vap, char *target, cred_t *cr, \
+ caller_context_t *ct, int flags); \
+ int (*femop_readlink)(femarg_t *vf, uio_t *uiop, cred_t *cr, \
+ caller_context_t *ct); \
+ int (*femop_fsync)(femarg_t *vf, int syncflag, cred_t *cr, \
+ caller_context_t *ct); \
+ void (*femop_inactive)(femarg_t *vf, cred_t *cr, \
+ caller_context_t *ct); \
+ int (*femop_fid)(femarg_t *vf, fid_t *fidp, \
+ caller_context_t *ct); \
int (*femop_rwlock)(femarg_t *vf, int write_lock, \
caller_context_t *ct); \
void (*femop_rwunlock)(femarg_t *vf, int write_lock, \
caller_context_t *ct); \
int (*femop_seek)(femarg_t *vf, offset_t ooff, \
- offset_t *noffp); \
- int (*femop_cmp)(femarg_t *vf, vnode_t *vp2); \
+ offset_t *noffp, caller_context_t *ct); \
+ int (*femop_cmp)(femarg_t *vf, vnode_t *vp2, \
+ caller_context_t *ct); \
int (*femop_frlock)(femarg_t *vf, int cmd, struct flock64 *bfp, \
int flag, offset_t offset, \
- struct flk_callback *flk_cbp, cred_t *cr); \
+ struct flk_callback *flk_cbp, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_space)(femarg_t *vf, int cmd, struct flock64 *bfp, \
int flag, offset_t offset, cred_t *cr, \
caller_context_t *ct); \
- int (*femop_realvp)(femarg_t *vf, vnode_t **vpp); \
+ int (*femop_realvp)(femarg_t *vf, vnode_t **vpp, \
+ caller_context_t *ct); \
int (*femop_getpage)(femarg_t *vf, offset_t off, size_t len, \
uint_t *protp, struct page **plarr, \
size_t plsz, struct seg *seg, caddr_t addr, \
- enum seg_rw rw, cred_t *cr); \
+ enum seg_rw rw, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_putpage)(femarg_t *vf, offset_t off, size_t len, \
- int flags, cred_t *cr); \
+ int flags, cred_t *cr, caller_context_t *ct); \
int (*femop_map)(femarg_t *vf, offset_t off, struct as *as, \
caddr_t *addrp, size_t len, uchar_t prot, \
- uchar_t maxprot, uint_t flags, cred_t *cr); \
+ uchar_t maxprot, uint_t flags, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_addmap)(femarg_t *vf, offset_t off, struct as *as, \
caddr_t addr, size_t len, uchar_t prot, \
- uchar_t maxprot, uint_t flags, cred_t *cr); \
+ uchar_t maxprot, uint_t flags, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_delmap)(femarg_t *vf, offset_t off, struct as *as, \
caddr_t addr, size_t len, uint_t prot, \
- uint_t maxprot, uint_t flags, cred_t *cr); \
+ uint_t maxprot, uint_t flags, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_poll)(femarg_t *vf, short events, int anyyet, \
- short *reventsp, struct pollhead **phpp); \
+ short *reventsp, struct pollhead **phpp, \
+ caller_context_t *ct); \
int (*femop_dump)(femarg_t *vf, caddr_t addr, int lbdn, \
- int dblks); \
+ int dblks, caller_context_t *ct); \
int (*femop_pathconf)(femarg_t *vf, int cmd, ulong_t *valp, \
- cred_t *cr); \
+ cred_t *cr, caller_context_t *ct); \
int (*femop_pageio)(femarg_t *vf, struct page *pp, \
u_offset_t io_off, size_t io_len, int flags, \
- cred_t *cr); \
- int (*femop_dumpctl)(femarg_t *vf, int action, int *blkp); \
+ cred_t *cr, caller_context_t *ct); \
+ int (*femop_dumpctl)(femarg_t *vf, int action, int *blkp, \
+ caller_context_t *ct); \
void (*femop_dispose)(femarg_t *vf, struct page *pp, int flag, \
- int dn, cred_t *cr); \
+ int dn, cred_t *cr, caller_context_t *ct); \
int (*femop_setsecattr)(femarg_t *vf, vsecattr_t *vsap, \
- int flag, cred_t *cr); \
+ int flag, cred_t *cr, caller_context_t *ct); \
int (*femop_getsecattr)(femarg_t *vf, vsecattr_t *vsap, \
- int flag, cred_t *cr); \
+ int flag, cred_t *cr, caller_context_t *ct); \
int (*femop_shrlock)(femarg_t *vf, int cmd, \
- struct shrlock *shr, int flag, cred_t *cr); \
+ struct shrlock *shr, int flag, cred_t *cr, \
+ caller_context_t *ct); \
int (*femop_vnevent)(femarg_t *vf, vnevent_t vnevent, \
- vnode_t *dvp, char *cname)
+ vnode_t *dvp, char *cname, caller_context_t *ct)
/* NB: No ";" */
struct fem {
@@ -267,83 +293,105 @@ struct fsem {
FSEM_OPS; /* Signatures of all FSEM operations (fsemops) */
};
-extern int vnext_open(femarg_t *vf, int mode, cred_t *cr);
+extern int vnext_open(femarg_t *vf, int mode, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_close(femarg_t *vf, int flag, int count, offset_t offset,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct);
+ caller_context_t *ct);
extern int vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
- struct caller_context *ct);
+ caller_context_t *ct);
extern int vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag,
- cred_t *cr, int *rvalp);
-extern int vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr);
-extern int vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr);
+ cred_t *cr, int *rvalp, caller_context_t *ct);
+extern int vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr,
+ caller_context_t *ct);
+extern int vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
caller_context_t *ct);
-extern int vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr);
+extern int vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp,
pathname_t *pnp, int flags, vnode_t *rdir,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct,
+ int *direntflags, pathname_t *realpnp);
extern int vnext_create(femarg_t *vf, char *name, vattr_t *vap,
vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cr,
- int flag);
-extern int vnext_remove(femarg_t *vf, char *nm, cred_t *cr);
-extern int vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr);
+ int flag, caller_context_t *ct, vsecattr_t *vsecp);
+extern int vnext_remove(femarg_t *vf, char *nm, cred_t *cr,
+ caller_context_t *ct, int flags);
+extern int vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
+ caller_context_t *ct, int flags);
extern int vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct, int flags);
extern int vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap,
- vnode_t **vpp, cred_t *cr);
-extern int vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr);
-extern int vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp);
+ vnode_t **vpp, cred_t *cr, caller_context_t *ct,
+ int flags, vsecattr_t *vsecp);
+extern int vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
+ caller_context_t *ct, int flags);
+extern int vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
+ caller_context_t *ct, int flags);
extern int vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap,
- char *target, cred_t *cr);
-extern int vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr);
-extern int vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr);
-extern void vnext_inactive(femarg_t *vf, cred_t *cr);
-extern int vnext_fid(femarg_t *vf, fid_t *fidp);
+ char *target, cred_t *cr, caller_context_t *ct,
+ int flags);
+extern int vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr,
+ caller_context_t *ct);
+extern int vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr,
+ caller_context_t *ct);
+extern void vnext_inactive(femarg_t *vf, cred_t *cr, caller_context_t *ct);
+extern int vnext_fid(femarg_t *vf, fid_t *fidp, caller_context_t *ct);
extern int vnext_rwlock(femarg_t *vf, int write_lock, caller_context_t *ct);
extern void vnext_rwunlock(femarg_t *vf, int write_lock, caller_context_t *ct);
-extern int vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp);
-extern int vnext_cmp(femarg_t *vf, vnode_t *vp2);
+extern int vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp,
+ caller_context_t *ct);
+extern int vnext_cmp(femarg_t *vf, vnode_t *vp2, caller_context_t *ct);
extern int vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp,
int flag, offset_t offset,
- struct flk_callback *flk_cbp, cred_t *cr);
+ struct flk_callback *flk_cbp, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_space(femarg_t *vf, int cmd, struct flock64 *bfp,
int flag, offset_t offset, cred_t *cr,
caller_context_t *ct);
-extern int vnext_realvp(femarg_t *vf, vnode_t **vpp);
+extern int vnext_realvp(femarg_t *vf, vnode_t **vpp, caller_context_t *ct);
extern int vnext_getpage(femarg_t *vf, offset_t off, size_t len,
uint_t *protp, struct page **plarr, size_t plsz,
struct seg *seg, caddr_t addr, enum seg_rw rw,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_map(femarg_t *vf, offset_t off, struct as *as,
caddr_t *addrp, size_t len, uchar_t prot, uchar_t maxprot,
- uint_t flags, cred_t *cr);
+ uint_t flags, cred_t *cr, caller_context_t *ct);
extern int vnext_addmap(femarg_t *vf, offset_t off, struct as *as,
caddr_t addr, size_t len, uchar_t prot,
- uchar_t maxprot, uint_t flags, cred_t *cr);
+ uchar_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_delmap(femarg_t *vf, offset_t off, struct as *as,
caddr_t addr, size_t len, uint_t prot,
- uint_t maxprot, uint_t flags, cred_t *cr);
+ uint_t maxprot, uint_t flags, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_poll(femarg_t *vf, short events, int anyyet,
- short *reventsp, struct pollhead **phpp);
-extern int vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks);
-extern int vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr);
+ short *reventsp, struct pollhead **phpp,
+ caller_context_t *ct);
+extern int vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks,
+ caller_context_t *ct);
+extern int vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr,
+ caller_context_t *ct);
extern int vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
- size_t io_len, int flags, cred_t *cr);
-extern int vnext_dumpctl(femarg_t *vf, int action, int *blkp);
+ size_t io_len, int flags, cred_t *cr,
+ caller_context_t *ct);
+extern int vnext_dumpctl(femarg_t *vf, int action, int *blkp,
+ caller_context_t *ct);
extern void vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag,
- cred_t *cr);
+ cred_t *cr, caller_context_t *ct);
extern int vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr,
- int flag, cred_t *cr);
+ int flag, cred_t *cr, caller_context_t *ct);
extern int vnext_vnevent(femarg_t *vf, vnevent_t vevent, vnode_t *dvp,
- char *cname);
+ char *cname, caller_context_t *ct);
extern int vfsnext_mount(fsemarg_t *vf, vnode_t *mvp, struct mounta *uap,
cred_t *cr);
diff --git a/usr/src/uts/common/sys/file.h b/usr/src/uts/common/sys/file.h
index e893696564..01af00ddb2 100644
--- a/usr/src/uts/common/sys/file.h
+++ b/usr/src/uts/common/sys/file.h
@@ -89,10 +89,6 @@ typedef struct fpollinfo {
#define FREVOKED 0x20 /* C2 Security - Revoke Subsystem */
#endif
#define FDSYNC 0x40 /* file data only integrity while writing */
-#define FRSYNC 0x8000 /* sync read operations at same level of */
- /* integrity as specified for writes by */
- /* FSYNC and FDSYNC flags */
-#define FOFFMAX 0x2000 /* large file */
#define FNONBLOCK 0x80
#define FMASK 0xa0ff /* all flags that can be changed by F_SETFL */
@@ -102,14 +98,20 @@ typedef struct fpollinfo {
#define FCREAT 0x0100
#define FTRUNC 0x0200
#define FEXCL 0x0400
-#define FNOCTTY 0x0800
+#define FASYNC 0x1000 /* asyncio in progress pseudo flag */
+#define FOFFMAX 0x2000 /* large file */
#define FXATTR 0x4000 /* open as extended attribute */
+#define FNOCTTY 0x0800
+#define FRSYNC 0x8000 /* sync read operations at same level of */
+ /* integrity as specified for writes by */
+ /* FSYNC and FDSYNC flags */
-#define FASYNC 0x1000 /* asyncio in progress pseudo flag */
#define FNODSYNC 0x10000 /* fsync pseudo flag */
#define FNOFOLLOW 0x20000 /* don't follow symlinks */
#define FNOLINKS 0x40000 /* don't allow multiple hard links */
+#define FIGNORECASE 0x80000 /* request case-insensitive lookups */
+#define FXATTRDIROPEN 0x100000 /* only opening hidden attribute directory */
#ifdef _KERNEL
diff --git a/usr/src/uts/common/sys/fs/fifonode.h b/usr/src/uts/common/sys/fs/fifonode.h
index ddd64ab0a3..5ef83b4778 100644
--- a/usr/src/uts/common/sys/fs/fifonode.h
+++ b/usr/src/uts/common/sys/fs/fifonode.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -123,8 +123,8 @@ typedef struct fifodata {
#define FIFOPOLLR 0x1000 /* process waiting on poll read */
#define FIFOISOPEN 0x2000 /* pipe is open */
#define FIFOSYNC 0x4000 /* FIFO is waiting for open sync */
-#define FIFOWOCR 0x8000 /* Write open occured */
-#define FIFOROCR 0x10000 /* Read open occured */
+#define FIFOWOCR 0x8000 /* Write open occurred */
+#define FIFOROCR 0x10000 /* Read open occurred */
/*
* process waiting on poll read on band data
* this can only occur if we go to streams
@@ -165,8 +165,9 @@ struct queue;
extern int fifoinit(int, char *);
extern int fifo_stropen(vnode_t **, int, cred_t *, int, int);
-extern int fifo_open(vnode_t **, int, cred_t *);
-extern int fifo_close(vnode_t *, int, int, offset_t, cred_t *);
+extern int fifo_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int fifo_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
extern void fifo_cleanup(vnode_t *, int);
extern void fiforemove(fifonode_t *);
extern ino_t fifogetid(void);
diff --git a/usr/src/uts/common/sys/fs/pc_node.h b/usr/src/uts/common/sys/fs/pc_node.h
index 72e96d579b..1e8921c6c1 100644
--- a/usr/src/uts/common/sys/fs/pc_node.h
+++ b/usr/src/uts/common/sys/fs/pc_node.h
@@ -129,8 +129,10 @@ extern void pc_mark_irrecov(struct pcfs *);
extern int pc_dirlook(struct pcnode *, char *, struct pcnode **);
extern int pc_direnter(struct pcnode *, char *, struct vattr *,
struct pcnode **);
-extern int pc_dirremove(struct pcnode *, char *, struct vnode *, enum vtype);
-extern int pc_rename(struct pcnode *, struct pcnode *, char *, char *);
+extern int pc_dirremove(struct pcnode *, char *, struct vnode *, enum vtype,
+ caller_context_t *);
+extern int pc_rename(struct pcnode *, struct pcnode *, char *, char *,
+ caller_context_t *);
extern int pc_blkatoff(struct pcnode *, offset_t, struct buf **,
struct pcdir **);
extern int pc_truncate(struct pcnode *, uint_t);
diff --git a/usr/src/uts/common/sys/fs/snode.h b/usr/src/uts/common/sys/fs/snode.h
index cd572d545c..d0176af293 100644
--- a/usr/src/uts/common/sys/fs/snode.h
+++ b/usr/src/uts/common/sys/fs/snode.h
@@ -162,7 +162,8 @@ void sdelete(struct snode *);
void smark(struct snode *, int);
int specinit(int, char *);
int device_close(struct vnode *, int, struct cred *);
-int spec_putpage(struct vnode *, offset_t, size_t, int, struct cred *);
+int spec_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
+ caller_context_t *);
int spec_segmap(dev_t, off_t, struct as *, caddr_t *, off_t,
uint_t, uint_t, uint_t, cred_t *);
struct vnode *specvp_devfs(struct vnode *, dev_t, vtype_t,
diff --git a/usr/src/uts/common/sys/fs/tmp.h b/usr/src/uts/common/sys/fs/tmp.h
index 583eaab18c..68dd67c61e 100644
--- a/usr/src/uts/common/sys/fs/tmp.h
+++ b/usr/src/uts/common/sys/fs/tmp.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1989-1991, 1996-1999, 2001-2003 Sun Microsystems, Inc.
+ * Copyright 2007 Sun Microsystems, Inc.
* All rights reserved. Use is subject to license terms.
*/
@@ -111,7 +110,7 @@ extern int tmp_sticky_remove_access(struct tmpnode *, struct tmpnode *,
extern int tmp_convnum(char *, pgcnt_t *);
extern int tdirenter(struct tmount *, struct tmpnode *, char *,
enum de_op, struct tmpnode *, struct tmpnode *, struct vattr *,
- struct tmpnode **, struct cred *);
+ struct tmpnode **, struct cred *, caller_context_t *);
#define TMP_MUSTHAVE 0x01
diff --git a/usr/src/uts/common/sys/fs/udf_inode.h b/usr/src/uts/common/sys/fs/udf_inode.h
index 6a2b3e83e1..dd68124bca 100644
--- a/usr/src/uts/common/sys/fs/udf_inode.h
+++ b/usr/src/uts/common/sys/fs/udf_inode.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -709,10 +708,10 @@ int32_t ud_dirlook(struct ud_inode *,
char *, struct ud_inode **, struct cred *, int32_t);
int32_t ud_direnter(struct ud_inode *, char *, enum de_op,
struct ud_inode *, struct ud_inode *, struct vattr *,
- struct ud_inode **, struct cred *);
+ struct ud_inode **, struct cred *, caller_context_t *);
int32_t ud_dirremove(struct ud_inode *,
char *, struct ud_inode *, struct vnode *,
- enum dr_op, struct cred *);
+ enum dr_op, struct cred *, caller_context_t *);
/*
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index 8babbef0d1..1250b18c4e 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -92,6 +92,12 @@ typedef enum {
ZFS_PROP_NUMCLONES, /* not exposed to the user */
ZFS_PROP_COPIES,
ZFS_PROP_VERSION,
+ ZFS_PROP_UTF8ONLY,
+ ZFS_PROP_NORMALIZE,
+ ZFS_PROP_CASE,
+ ZFS_PROP_VSCAN,
+ ZFS_PROP_NBMAND,
+ ZFS_PROP_SHARESMB,
ZFS_NUM_PROPS
} zfs_prop_t;
@@ -144,11 +150,13 @@ const char *zfs_prop_default_string(zfs_prop_t);
uint64_t zfs_prop_default_numeric(zfs_prop_t);
boolean_t zfs_prop_readonly(zfs_prop_t);
boolean_t zfs_prop_inheritable(zfs_prop_t);
+boolean_t zfs_prop_setonce(zfs_prop_t);
const char *zfs_prop_to_name(zfs_prop_t);
zfs_prop_t zfs_name_to_prop(const char *);
boolean_t zfs_prop_user(const char *);
int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **);
int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *);
+int zfs_prop_valid_for_type(int, zfs_type_t);
/*
* Pool property functions shared between libzfs and kernel.
@@ -190,6 +198,13 @@ typedef enum {
#define ZFS_DELEG_PERM_GID "gid"
#define ZFS_DELEG_PERM_GROUPS "groups"
+typedef enum zfs_share_op {
+ ZFS_SHARE_NFS = 0,
+ ZFS_UNSHARE_NFS = 1,
+ ZFS_SHARE_SMB = 2,
+ ZFS_UNSHARE_SMB = 3
+} zfs_share_op_t;
+
/*
* On-disk version number.
*/
@@ -201,13 +216,15 @@ typedef enum {
#define SPA_VERSION_6 6ULL
#define SPA_VERSION_7 7ULL
#define SPA_VERSION_8 8ULL
+#define SPA_VERSION_9 9ULL
+
/*
* When bumping up SPA_VERSION, make sure GRUB ZFS understand the on-disk
* format change. Go to usr/src/grub/grub-0.95/stage2/{zfs-include/, fsys_zfs*},
* and do the appropriate changes.
*/
-#define SPA_VERSION SPA_VERSION_8
-#define SPA_VERSION_STRING "8"
+#define SPA_VERSION SPA_VERSION_9
+#define SPA_VERSION_STRING "9"
/*
* Symbolic names for the changes that caused a SPA_VERSION switch.
@@ -232,6 +249,8 @@ typedef enum {
#define SPA_VERSION_BOOTFS SPA_VERSION_6
#define SPA_VERSION_SLOGS SPA_VERSION_7
#define SPA_VERSION_DELEGATED_PERMS SPA_VERSION_8
+#define SPA_VERSION_FUID SPA_VERSION_9
+#define SPA_VERSION_NORMALIZATION SPA_VERSION_9
/*
* ZPL version - rev'd whenever an incompatible on-disk format change
@@ -243,11 +262,14 @@ typedef enum {
*/
#define ZPL_VERSION_1 1ULL
#define ZPL_VERSION_2 2ULL
-#define ZPL_VERSION ZPL_VERSION_2
-#define ZPL_VERSION_STRING "2"
+#define ZPL_VERSION_3 3ULL
+#define ZPL_VERSION ZPL_VERSION_3
+#define ZPL_VERSION_STRING "3"
#define ZPL_VERSION_INITIAL ZPL_VERSION_1
#define ZPL_VERSION_DIRENT_TYPE ZPL_VERSION_2
+#define ZPL_VERSION_FUID ZPL_VERSION_3
+#define ZPL_VERSION_SYSATTR ZPL_VERSION_3
/*
* The following are configuration names used in the nvlist describing a pool's
diff --git a/usr/src/uts/common/sys/gfs.h b/usr/src/uts/common/sys/gfs.h
index ce21cbe525..b53031086b 100644
--- a/usr/src/uts/common/sys/gfs.h
+++ b/usr/src/uts/common/sys/gfs.h
@@ -76,7 +76,8 @@ typedef struct gfs_file {
typedef int (*gfs_readdir_cb)(vnode_t *, struct dirent64 *, int *, offset_t *,
offset_t *, void *);
-typedef int (*gfs_lookup_cb)(vnode_t *, const char *, vnode_t **, ino64_t *);
+typedef int (*gfs_lookup_cb)(vnode_t *, const char *, vnode_t **, ino64_t *,
+ cred_t *);
typedef ino64_t (*gfs_inode_cb)(vnode_t *, int);
typedef struct gfs_dir {
@@ -103,8 +104,9 @@ extern vnode_t *gfs_root_create_file(size_t, struct vfs *, vnodeops_t *,
extern void *gfs_file_inactive(vnode_t *);
extern void *gfs_dir_inactive(vnode_t *);
-extern int gfs_dir_lookup(vnode_t *, const char *, vnode_t **);
-extern int gfs_dir_readdir(vnode_t *, uio_t *, int *, void *);
+extern int gfs_dir_lookup(vnode_t *, const char *, vnode_t **, cred_t *);
+extern int gfs_dir_readdir(vnode_t *, uio_t *, int *, void *, cred_t *,
+ caller_context_t *);
#define gfs_dir_lock(gd) mutex_enter(&(gd)->gfsd_lock)
#define gfs_dir_unlock(gd) mutex_exit(&(gd)->gfsd_lock)
@@ -137,14 +139,22 @@ extern int gfs_readdir_emitn(gfs_readdir_state_t *, uio_t *, offset_t, ino64_t,
extern int gfs_readdir_pred(gfs_readdir_state_t *, uio_t *, offset_t *);
extern int gfs_readdir_fini(gfs_readdir_state_t *, int, int *, int);
+/*
+ * Objects with real extended attributes will get their . and ..
+ * readdir entries from the real xattr directory. GFS_STATIC_ENTRY_OFFSET
+ * lets us skip right to the static entries in the GFS directory.
+ */
+#define GFS_STATIC_ENTRY_OFFSET ((offset_t)2)
+
extern int gfs_lookup_dot(vnode_t **, vnode_t *, vnode_t *, const char *);
extern int gfs_vop_lookup(vnode_t *, char *, vnode_t **, pathname_t *,
- int, vnode_t *, cred_t *);
-extern int gfs_vop_readdir(vnode_t *, uio_t *, cred_t *, int *);
+ int, vnode_t *, cred_t *, caller_context_t *, int *, pathname_t *);
+extern int gfs_vop_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
extern int gfs_vop_map(vnode_t *, offset_t, struct as *, caddr_t *,
- size_t, uchar_t, uchar_t, uint_t, cred_t *);
-extern void gfs_vop_inactive(vnode_t *, cred_t *);
+ size_t, uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
+extern void gfs_vop_inactive(vnode_t *, cred_t *, caller_context_t *);
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h
index 3477a11cb6..818572a94d 100644
--- a/usr/src/uts/common/sys/modctl.h
+++ b/usr/src/uts/common/sys/modctl.h
@@ -109,7 +109,7 @@ struct modlsys {
struct modlfs {
struct mod_ops *fs_modops;
char *fs_linkinfo;
- struct vfsdef_v3 *fs_vfsdef; /* version may actually vary */
+ struct vfsdef_v4 *fs_vfsdef; /* version may actually vary */
};
#if defined(__i386) || defined(__amd64)
diff --git a/usr/src/uts/common/sys/nbmlock.h b/usr/src/uts/common/sys/nbmlock.h
index 98211d7b70..e5215cc9ee 100644
--- a/usr/src/uts/common/sys/nbmlock.h
+++ b/usr/src/uts/common/sys/nbmlock.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#ifndef _NBMLOCK_H
@@ -57,9 +56,11 @@ extern int nbl_in_crit(vnode_t *);
/* conflict checking */
extern int nbl_need_check(vnode_t *);
-extern int nbl_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int);
-extern int nbl_share_conflict(vnode_t *, nbl_op_t);
-extern int nbl_lock_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int);
+extern int nbl_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int,
+ caller_context_t *);
+extern int nbl_share_conflict(vnode_t *, nbl_op_t, caller_context_t *);
+extern int nbl_lock_conflict(vnode_t *, nbl_op_t, u_offset_t, ssize_t, int,
+ caller_context_t *);
extern int nbl_svmand(vnode_t *, cred_t *, int *);
extern nbl_op_t nbl_lock_to_op(int);
diff --git a/usr/src/uts/common/sys/objfs_impl.h b/usr/src/uts/common/sys/objfs_impl.h
index df60a8af95..687db9edec 100644
--- a/usr/src/uts/common/sys/objfs_impl.h
+++ b/usr/src/uts/common/sys/objfs_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -49,9 +48,11 @@ typedef struct objfs_vfs {
/*
* Common vop_ entry points
*/
-extern int objfs_dir_open(vnode_t **, int, cred_t *);
-extern int objfs_dir_access(vnode_t *, int, int, cred_t *);
-extern int objfs_common_close(vnode_t *, int, int, offset_t, cred_t *);
+extern int objfs_dir_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int objfs_dir_access(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
+extern int objfs_common_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
/*
* Common vop_ support functions
diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h
index c132402d3b..2949605b9e 100644
--- a/usr/src/uts/common/sys/policy.h
+++ b/usr/src/uts/common/sys/policy.h
@@ -129,6 +129,7 @@ int secpolicy_rpcmod_open(const cred_t *);
int secpolicy_rsm_access(const cred_t *, uid_t, mode_t);
int secpolicy_setpriority(const cred_t *);
int secpolicy_settime(const cred_t *);
+int secpolicy_smb(const cred_t *);
int secpolicy_spec_open(const cred_t *, struct vnode *, int);
int secpolicy_sti(const cred_t *);
int secpolicy_swapctl(const cred_t *);
@@ -154,6 +155,7 @@ void secpolicy_setid_clear(vattr_t *, cred_t *);
void secpolicy_fs_mount_clearopts(cred_t *, struct vfs *);
int secpolicy_setid_setsticky_clear(vnode_t *, vattr_t *,
const vattr_t *, cred_t *);
+int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t);
int secpolicy_basic_exec(const cred_t *);
int secpolicy_basic_fork(const cred_t *);
diff --git a/usr/src/uts/common/sys/sid.h b/usr/src/uts/common/sys/sid.h
index 9d68191eb6..96b9f5a0b8 100644
--- a/usr/src/uts/common/sys/sid.h
+++ b/usr/src/uts/common/sys/sid.h
@@ -52,6 +52,8 @@ extern "C" {
#define SIDSYS_ID2SID 1
#ifdef _KERNEL
+#define KSIDLIST_MEM(n) (sizeof (ksidlist_t) + ((n) - 1) * sizeof (ksid_t))
+
/* Domains are stored in AVL trees so we can share them among SIDs */
typedef struct ksiddomain {
uint_t kd_ref;
diff --git a/usr/src/uts/common/sys/socketvar.h b/usr/src/uts/common/sys/socketvar.h
index 1863d2ea01..0680546ade 100644
--- a/usr/src/uts/common/sys/socketvar.h
+++ b/usr/src/uts/common/sys/socketvar.h
@@ -262,7 +262,7 @@ struct sonode {
* but one of the key reasons for their existence and careful
* tracking in sockfs is to support getsockname and getpeername
* when the transport does not handle the TI_GET*NAME ioctls
- * and caching when it does (signalled by valid bits in so_state).
+ * and caching when it does (signaled by valid bits in so_state).
* When all transports support the new TPI (with T_ADDR_REQ)
* we can revisit this code.
* The other usage of so_faddr is to keep the "connected to"
@@ -704,7 +704,8 @@ extern int sock_putmsg(vnode_t *, struct strbuf *, struct strbuf *,
uchar_t, int, int);
struct sonode *sotpi_create(vnode_t *, int, int, int, int, struct sonode *,
int *);
-extern int socktpi_open(struct vnode **, int, struct cred *);
+extern int socktpi_open(struct vnode **, int, struct cred *,
+ caller_context_t *);
extern int so_sock2stream(struct sonode *);
extern void so_stream2sock(struct sonode *);
extern int sockinit(int, char *);
@@ -783,7 +784,7 @@ extern int sotpi_getsockopt(struct sonode *, int, int, void *,
extern int sotpi_setsockopt(struct sonode *, int, int, const void *,
socklen_t);
extern int socktpi_ioctl(struct vnode *, int, intptr_t, int,
- struct cred *, int *);
+ struct cred *, int *, caller_context_t *);
extern int sodisconnect(struct sonode *, t_scalar_t, int);
extern ssize_t soreadfile(file_t *, uchar_t *, u_offset_t, int *, size_t);
extern int so_set_asyncsigs(vnode_t *, pid_t, int, int, cred_t *);
@@ -795,7 +796,7 @@ extern void sock_kstat_fini(zoneid_t, void *);
extern struct sonode *getsonode(int, int *, file_t **);
/*
- * Function wrappers (mostly arround the sonode switch) for
+ * Function wrappers (mostly around the sonode switch) for
* backward compatibility.
*/
extern int soaccept(struct sonode *, int, struct sonode **);
@@ -820,15 +821,19 @@ extern struct sonode *socreate(vnode_t *, int, int, int, int,
extern int so_copyin(const void *, void *, size_t, int);
extern int so_copyout(const void *, void *, size_t, int);
-extern int socktpi_access(struct vnode *, int, int, struct cred *);
-extern int socktpi_fid(struct vnode *, struct fid *);
-extern int socktpi_fsync(struct vnode *, int, struct cred *);
+extern int socktpi_access(struct vnode *, int, int, struct cred *,
+ caller_context_t *);
+extern int socktpi_fid(struct vnode *, struct fid *, caller_context_t *);
+extern int socktpi_fsync(struct vnode *, int, struct cred *,
+ caller_context_t *);
extern int socktpi_getattr(struct vnode *, struct vattr *, int,
- struct cred *);
-extern int socktpi_seek(struct vnode *, offset_t, offset_t *);
+ struct cred *, caller_context_t *);
+extern int socktpi_seek(struct vnode *, offset_t, offset_t *,
+ caller_context_t *);
extern int socktpi_setattr(struct vnode *, struct vattr *, int,
struct cred *, caller_context_t *);
-extern int socktpi_setfl(vnode_t *, int, int, cred_t *);
+extern int socktpi_setfl(vnode_t *, int, int, cred_t *,
+ caller_context_t *);
/* SCTP sockfs */
extern struct sonode *sosctp_create(vnode_t *, int, int, int, int,
diff --git a/usr/src/uts/common/sys/tzfile.h b/usr/src/uts/common/sys/tzfile.h
new file mode 100644
index 0000000000..8f451f27d9
--- /dev/null
+++ b/usr/src/uts/common/sys/tzfile.h
@@ -0,0 +1,166 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * from Arthur Olson's 6.1
+ */
+
+#ifndef _SYS_TZFILE_H
+#define _SYS_TZFILE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information about time zone files.
+ */
+
+#define TZDIR "/usr/share/lib/zoneinfo" /* Time zone object file directory */
+
+#define TZDEFAULT (getenv("TZ"))
+
+#define TZDEFRULES "posixrules"
+
+/*
+ * Each file begins with. . .
+ */
+
+struct tzhead {
+ char tzh_reserved[24]; /* reserved for future use */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+ * . . .followed by. . .
+ *
+ * tzh_timecnt (char [4])s coded transition times a la time(2)
+ * tzh_timecnt (unsigned char)s types of local time starting at above
+ * tzh_typecnt repetitions of
+ * one (char [4]) coded GMT offset in seconds
+ * one (unsigned char) used to set tm_isdst
+ * one (unsigned char) that's an abbreviation list index
+ * tzh_charcnt (char)s '\0'-terminated zone abbreviations
+ * tzh_leapcnt repetitions of
+ * one (char [4]) coded leap second transition times
+ * one (char [4]) total correction after above
+ * tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+ * time is standard time, if FALSE,
+ * transition time is wall clock time
+ * if absent, transition times are
+ * assumed to be wall clock time
+ */
+
+/*
+ * In the current implementation, "tzset()" refuses to deal with files that
+ * exceed any of the limits below.
+ */
+
+/*
+ * The TZ_MAX_TIMES value below is enough to handle a bit more than a
+ * year's worth of solar time (corrected daily to the nearest second) or
+ * 138 years of Pacific Presidential Election time
+ * (where there are three time zone transitions every fourth year).
+ */
+#define TZ_MAX_TIMES 370
+
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+/*
+ * Accurate only for the past couple of centuries;
+ * that will probably do.
+ */
+
+#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
+
+/*
+ * Use of the underscored variants may cause problems if you move your code to
+ * certain System-V-based systems; for maximum portability, use the
+ * underscore-free variants. The underscored variants are provided for
+ * backward compatibility only; they may disappear from future versions of
+ * this file.
+ */
+
+#define SECS_PER_MIN SECSPERMIN
+#define MINS_PER_HOUR MINSPERHOUR
+#define HOURS_PER_DAY HOURSPERDAY
+#define DAYS_PER_WEEK DAYSPERWEEK
+#define DAYS_PER_NYEAR DAYSPERNYEAR
+#define DAYS_PER_LYEAR DAYSPERLYEAR
+#define SECS_PER_HOUR SECSPERHOUR
+#define SECS_PER_DAY SECSPERDAY
+#define MONS_PER_YEAR MONSPERYEAR
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TZFILE_H */
diff --git a/usr/src/uts/common/sys/unistd.h b/usr/src/uts/common/sys/unistd.h
index 7cfbb9744f..29e0476abd 100644
--- a/usr/src/uts/common/sys/unistd.h
+++ b/usr/src/uts/common/sys/unistd.h
@@ -310,6 +310,10 @@ extern "C" {
#define _PC_2_SYMLINKS 19
#define _PC_ACL_ENABLED 20
#define _PC_MIN_HOLE_SIZE 21
+#define _PC_CASE_BEHAVIOR 22
+#define _PC_SATTR_ENABLED 23
+#define _PC_SATTR_EXISTS 24
+
/*
* Large File Summit names
*
@@ -326,6 +330,12 @@ extern "C" {
#define _PC_XATTR_EXISTS 101
/*
+ * Case sensitivity values (related to _PC_CASE_BEHAVIOR)
+ */
+#define _CASE_SENSITIVE 0x1
+#define _CASE_INSENSITIVE 0x2
+
+/*
* The value of 0 is returned when
* ACL's are not supported
*/
diff --git a/usr/src/uts/common/sys/vfs.h b/usr/src/uts/common/sys/vfs.h
index 114ce97811..2b627cd344 100644
--- a/usr/src/uts/common/sys/vfs.h
+++ b/usr/src/uts/common/sys/vfs.h
@@ -175,6 +175,24 @@ extern avl_tree_t vskstat_tree;
extern kmutex_t vskstat_tree_lock;
/*
+ * Private vfs data, NOT to be used by a file system implementation.
+ */
+
+#define VFS_FEATURE_MAXSZ 4
+
+typedef struct vfs_impl {
+ /* Counted array - Bitmap of vfs features */
+ uint32_t vi_featureset[VFS_FEATURE_MAXSZ];
+ /*
+ * Support for statistics on the vnode operations
+ */
+ vsk_anchor_t *vi_vskap; /* anchor for vopstats' kstat */
+ vopstats_t *vi_fstypevsp; /* ptr to per-fstype vopstats */
+ vopstats_t vi_vopstats; /* per-mount vnode op stats */
+} vfs_impl_t;
+
+
+/*
* Structure per mounted file system. Each mounted file system has
* an array of operations and an instance record.
*
@@ -200,19 +218,6 @@ extern kmutex_t vskstat_tree_lock;
struct zone; /* from zone.h */
struct fem_head; /* from fem.h */
-/*
- * Private vfs data, NOT to be used by a file system implementation.
- */
-typedef struct vfs_impl {
- struct fem_head *vi_femhead; /* fs monitoring */
- /*
- * Support for statistics on the vnode operations
- */
- vsk_anchor_t *vi_vskap; /* anchor for vopstats' kstat */
- vopstats_t *vi_fstypevsp; /* ptr to per-fstype vopstats */
- vopstats_t vi_vopstats; /* per-mount vnode op stats */
-} vfs_impl_t;
-
typedef struct vfs {
struct vfs *vfs_next; /* next VFS in VFS list */
struct vfs *vfs_prev; /* prev VFS in VFS list */
@@ -246,9 +251,10 @@ typedef struct vfs {
struct zone *vfs_zone; /* zone that owns the mount */
struct vfs *vfs_zone_next; /* next VFS visible in zone */
struct vfs *vfs_zone_prev; /* prev VFS visible in zone */
+ struct fem_head *vfs_femhead; /* fs monitoring */
} vfs_t;
-#define vfs_femhead vfs_implp->vi_femhead
+#define vfs_featureset vfs_implp->vi_featureset
#define vfs_vskap vfs_implp->vi_vskap
#define vfs_fstypevsp vfs_implp->vi_fstypevsp
#define vfs_vopstats vfs_implp->vi_vopstats
@@ -275,6 +281,22 @@ typedef struct vfs {
#define VFS_NOMNTPT "unspecified_mountpoint"
/*
+ * VFS features are implemented as bits set in the vfs_t.
+ * The vfs_feature_t typedef is a 64-bit number that will translate
+ * into an element in an array of bitmaps and a bit in that element.
+ * Developers must not depend on the implementation of this and
+ * need to use vfs_has_feature()/vfs_set_feature() routines.
+ */
+typedef uint64_t vfs_feature_t;
+
+#define VFSFT_XVATTR 0x100000001 /* Supports xvattr for attrs */
+#define VFSFT_CASEINSENSITIVE 0x100000002 /* Supports case-insensitive */
+#define VFSFT_NOCASESENSITIVE 0x100000004 /* NOT case-sensitive */
+#define VFSFT_DIRENTFLAGS 0x100000008 /* Supports dirent flags */
+#define VFSFT_ACLONCREATE 0x100000010 /* Supports ACL on create */
+#define VFSFT_ACEMASKONACCESS 0x100000020 /* Can use ACEMASK for access */
+
+/*
* Argument structure for mount(2).
*
* Flags are defined in <sys/mount.h>.
@@ -380,21 +402,22 @@ typedef struct vfssw {
/*
* Filesystem type definition record. All file systems must export a record
- * of this type through their modlfs structure.
+ * of this type through their modlfs structure. N.B., changing the version
+ * number requires a change in sys/modctl.h.
*/
-typedef struct vfsdef_v3 {
+typedef struct vfsdef_v4 {
int def_version; /* structure version, must be first */
char *name; /* filesystem type name */
int (*init) (int, char *); /* init routine */
int flags; /* filesystem flags */
mntopts_t *optproto; /* mount options table prototype */
-} vfsdef_v3;
+} vfsdef_v4;
-typedef struct vfsdef_v3 vfsdef_t;
+typedef struct vfsdef_v4 vfsdef_t;
enum {
- VFSDEF_VERSION = 3
+ VFSDEF_VERSION = 4
};
/*
@@ -424,6 +447,8 @@ void vfs_setops(vfs_t *, vfsops_t *);
vfsops_t *vfs_getops(vfs_t *vfsp);
int vfs_matchops(vfs_t *, vfsops_t *);
int vfs_can_sync(vfs_t *vfsp);
+vfs_t *vfs_alloc(int);
+void vfs_free(vfs_t *);
void vfs_init(vfs_t *vfsp, vfsops_t *, void *);
void vfsimpl_setup(vfs_t *vfsp);
void vfsimpl_teardown(vfs_t *vfsp);
@@ -450,6 +475,10 @@ void vfs_mountroot(void);
void vfs_add(vnode_t *, struct vfs *, int);
void vfs_remove(struct vfs *);
+/* VFS feature routines */
+void vfs_set_feature(vfs_t *, vfs_feature_t);
+int vfs_has_feature(vfs_t *, vfs_feature_t);
+
/* The following functions are not for general use by filesystems */
void vfs_createopttbl(mntopts_t *, const char *);
@@ -545,7 +574,6 @@ extern const mntopts_t vfs_mntopts; /* globally recognized options */
#define VFS_INIT(vfsp, op, data) { \
vfs_init((vfsp), (op), (data)); \
- vfsimpl_setup((vfsp)); \
}
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index 56f4ac42d8..3195fb4ebd 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -194,6 +194,7 @@ struct vsd_node {
* v_shrlocks
* v_path
* v_vsd
+ * v_xattrdir
*
* A special lock (implemented by vn_vfswlock in vnode.c) protects:
* v_vfsmountedhere
@@ -262,6 +263,7 @@ typedef struct vnode {
krwlock_t v_mslock; /* protects v_mset */
void *v_fopdata; /* list of file ops event watches */
struct vsd_node *v_vsd; /* vnode specific data */
+ struct vnode *v_xattrdir; /* unnamed extended attr dir (GFS) */
} vnode_t;
#define IS_DEVVP(vp) \
@@ -334,6 +336,8 @@ typedef struct vn_vfslocks_entry {
#define VISSWAPFS 0x20000 /* vnode is being used for swapfs */
#define IS_SWAPFSVP(vp) (((vp)->v_flag & VISSWAPFS) != 0)
+#define V_SYSATTR 0x40000 /* vnode is a GFS system attribute */
+
/*
* Vnode attributes. A bit-mask is supplied as part of the
* structure to indicate the attributes the caller wants to
@@ -366,6 +370,101 @@ typedef struct vattr {
uint_t va_seq; /* sequence number */
} vattr_t;
+#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
+
+/*
+ * Structure of all optional attributes.
+ */
+typedef struct xoptattr {
+ timestruc_t xoa_createtime; /* Create time of file */
+ uint8_t xoa_archive;
+ uint8_t xoa_system;
+ uint8_t xoa_readonly;
+ uint8_t xoa_hidden;
+ uint8_t xoa_nounlink;
+ uint8_t xoa_immutable;
+ uint8_t xoa_appendonly;
+ uint8_t xoa_nodump;
+ uint8_t xoa_opaque;
+ uint8_t xoa_av_quarantined;
+ uint8_t xoa_av_modified;
+ uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
+} xoptattr_t;
+
+/*
+ * The xvattr structure is really a variable length structure that
+ * is made up of:
+ * - The classic vattr_t (xva_vattr)
+ * - a 32 bit quantity (xva_mapsize) that specifies the size of the
+ * attribute bitmaps in 32 bit words.
+ * - A pointer to the returned attribute bitmap (needed because the
+ * previous element, the requested attribute bitmap) is variable lenth.
+ * - The requested attribute bitmap, which is an array of 32 bit words.
+ * Callers use the XVA_SET_REQ() macro to set the bits corresponding to
+ * the attributes that are being requested.
+ * - The returned attribute bitmap, which is an array of 32 bit words.
+ * File systems that support optional attributes use the XVA_SET_RTN()
+ * macro to set the bits corresponding to the attributes that are being
+ * returned.
+ * - The xoptattr_t structure which contains the attribute values
+ *
+ * xva_mapsize determines how many words in the attribute bitmaps.
+ * Immediately following the attribute bitmaps is the xoptattr_t.
+ * xva_getxoptattr() is used to get the pointer to the xoptattr_t
+ * section.
+ */
+
+#define XVA_MAPSIZE 3 /* Size of attr bitmaps */
+#define XVA_MAGIC 0x78766174 /* Magic # for verification */
+
+/*
+ * The xvattr structure is an extensible structure which permits optional
+ * attributes to be requested/returned. File systems may or may not support
+ * optional attributes. They do so at their own discretion but if they do
+ * support optional attributes, they must register the VFSFT_XVATTR feature
+ * so that the optional attributes can be set/retrived.
+ *
+ * The fields of the xvattr structure are:
+ *
+ * xva_vattr - The first element of an xvattr is a legacy vattr structure
+ * which includes the common attributes. If AT_XVATTR is set in the va_mask
+ * then the entire structure is treated as an xvattr. If AT_XVATTR is not
+ * set, then only the xva_vattr structure can be used.
+ *
+ * xva_magic - 0x78766174 (hex for "xvat"). Magic number for verification.
+ *
+ * xva_mapsize - Size of requested and returned attribute bitmaps.
+ *
+ * xva_rtnattrmapp - Pointer to xva_rtnattrmap[]. We need this since the
+ * size of the array before it, xva_reqattrmap[], could change which means
+ * the location of xva_rtnattrmap[] could change. This will allow unbundled
+ * file systems to find the location of xva_rtnattrmap[] when the sizes change.
+ *
+ * xva_reqattrmap[] - Array of requested attributes. Attributes are
+ * represented by a specific bit in a specific element of the attribute
+ * map array. Callers set the bits corresponding to the attributes
+ * that the caller wants to get/set.
+ *
+ * xva_rtnattrmap[] - Array of attributes that the file system was able to
+ * process. Not all file systems support all optional attributes. This map
+ * informs the caller which attributes the underlying file system was able
+ * to set/get. (Same structure as the requested attributes array in terms
+ * of each attribute corresponding to specific bits and array elements.)
+ *
+ * xva_xoptattrs - Structure containing values of optional attributes.
+ * These values are only valid if the corresponding bits in xva_reqattrmap
+ * are set and the underlying file system supports those attributes.
+ */
+typedef struct xvattr {
+ vattr_t xva_vattr; /* Embedded vattr structure */
+ uint32_t xva_magic; /* Magic Number */
+ uint32_t xva_mapsize; /* Size of attr bitmap (32-bit words) */
+ uint32_t *xva_rtnattrmapp; /* Ptr to xva_rtnattrmap[] */
+ uint32_t xva_reqattrmap[XVA_MAPSIZE]; /* Requested attrs */
+ uint32_t xva_rtnattrmap[XVA_MAPSIZE]; /* Returned attrs */
+ xoptattr_t xva_xoptattrs; /* Optional attributes */
+} xvattr_t;
+
#ifdef _SYSCALL32
/*
* For bigtypes time_t changed to 64 bit on the 64-bit kernel.
@@ -407,22 +506,29 @@ typedef vattr_t vattr32_t;
/*
* Attributes of interest to the caller of setattr or getattr.
*/
-#define AT_TYPE 0x0001
-#define AT_MODE 0x0002
-#define AT_UID 0x0004
-#define AT_GID 0x0008
-#define AT_FSID 0x0010
-#define AT_NODEID 0x0020
-#define AT_NLINK 0x0040
-#define AT_SIZE 0x0080
-#define AT_ATIME 0x0100
-#define AT_MTIME 0x0200
-#define AT_CTIME 0x0400
-#define AT_RDEV 0x0800
-#define AT_BLKSIZE 0x1000
-#define AT_NBLOCKS 0x2000
-/* 0x4000 */ /* unused */
-#define AT_SEQ 0x8000
+#define AT_TYPE 0x00001
+#define AT_MODE 0x00002
+#define AT_UID 0x00004
+#define AT_GID 0x00008
+#define AT_FSID 0x00010
+#define AT_NODEID 0x00020
+#define AT_NLINK 0x00040
+#define AT_SIZE 0x00080
+#define AT_ATIME 0x00100
+#define AT_MTIME 0x00200
+#define AT_CTIME 0x00400
+#define AT_RDEV 0x00800
+#define AT_BLKSIZE 0x01000
+#define AT_NBLOCKS 0x02000
+/* 0x04000 */ /* unused */
+#define AT_SEQ 0x08000
+/*
+ * If AT_XVATTR is set then there are additional bits to process in
+ * the xvattr_t's attribute bitmap. If this is not set then the bitmap
+ * MUST be ignored. Note that this bit must be set/cleared explicitly.
+ * That is, setting AT_ALL will NOT set AT_XVATTR.
+ */
+#define AT_XVATTR 0x10000
#define AT_ALL (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|\
AT_NLINK|AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|\
@@ -437,6 +543,116 @@ typedef vattr_t vattr32_t;
AT_BLKSIZE|AT_NBLOCKS|AT_SEQ)
/*
+ * Attribute bits used in the extensible attribute's (xva's) attribute
+ * bitmaps. Note that the bitmaps are made up of a variable length number
+ * of 32-bit words. The convention is to use XAT{n}_{attrname} where "n"
+ * is the element in the bitmap (starting at 1). This convention is for
+ * the convenience of the maintainer to keep track of which element each
+ * attribute belongs to.
+ *
+ * NOTE THAT CONSUMERS MUST *NOT* USE THE XATn_* DEFINES DIRECTLY. CONSUMERS
+ * MUST USE THE XAT_* DEFINES.
+ */
+#define XAT0_INDEX 0LL /* Index into bitmap for XAT0 attrs */
+#define XAT0_CREATETIME 0x00000001 /* Create time of file */
+#define XAT0_ARCHIVE 0x00000002 /* Archive */
+#define XAT0_SYSTEM 0x00000004 /* System */
+#define XAT0_READONLY 0x00000008 /* Readonly */
+#define XAT0_HIDDEN 0x00000010 /* Hidden */
+#define XAT0_NOUNLINK 0x00000020 /* Nounlink */
+#define XAT0_IMMUTABLE 0x00000040 /* immutable */
+#define XAT0_APPENDONLY 0x00000080 /* appendonly */
+#define XAT0_NODUMP 0x00000100 /* nodump */
+#define XAT0_OPAQUE 0x00000200 /* opaque */
+#define XAT0_AV_QUARANTINED 0x00000400 /* anti-virus quarantine */
+#define XAT0_AV_MODIFIED 0x00000800 /* anti-virus modified */
+#define XAT0_AV_SCANSTAMP 0x00001000 /* anti-virus scanstamp */
+
+#define XAT0_ALL_ATTRS (XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
+ XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
+ XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \
+ XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP)
+
+/* Support for XAT_* optional attributes */
+#define XVA_MASK 0xffffffff /* Used to mask off 32 bits */
+#define XVA_SHFT 32 /* Used to shift index */
+
+/*
+ * Used to pry out the index and attribute bits from the XAT_* attributes
+ * defined below. Note that we're masking things down to 32 bits then
+ * casting to uint32_t.
+ */
+#define XVA_INDEX(attr) ((uint32_t)(((attr) >> XVA_SHFT) & XVA_MASK))
+#define XVA_ATTRBIT(attr) ((uint32_t)((attr) & XVA_MASK))
+
+/*
+ * The following defines present a "flat namespace" so that consumers don't
+ * need to keep track of which element belongs to which bitmap entry.
+ *
+ * NOTE THAT THESE MUST NEVER BE OR-ed TOGETHER
+ */
+#define XAT_CREATETIME ((XAT0_INDEX << XVA_SHFT) | XAT0_CREATETIME)
+#define XAT_ARCHIVE ((XAT0_INDEX << XVA_SHFT) | XAT0_ARCHIVE)
+#define XAT_SYSTEM ((XAT0_INDEX << XVA_SHFT) | XAT0_SYSTEM)
+#define XAT_READONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_READONLY)
+#define XAT_HIDDEN ((XAT0_INDEX << XVA_SHFT) | XAT0_HIDDEN)
+#define XAT_NOUNLINK ((XAT0_INDEX << XVA_SHFT) | XAT0_NOUNLINK)
+#define XAT_IMMUTABLE ((XAT0_INDEX << XVA_SHFT) | XAT0_IMMUTABLE)
+#define XAT_APPENDONLY ((XAT0_INDEX << XVA_SHFT) | XAT0_APPENDONLY)
+#define XAT_NODUMP ((XAT0_INDEX << XVA_SHFT) | XAT0_NODUMP)
+#define XAT_OPAQUE ((XAT0_INDEX << XVA_SHFT) | XAT0_OPAQUE)
+#define XAT_AV_QUARANTINED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_QUARANTINED)
+#define XAT_AV_MODIFIED ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_MODIFIED)
+#define XAT_AV_SCANSTAMP ((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
+
+/*
+ * The returned attribute map array (xva_rtnattrmap[]) is located past the
+ * requested attribute map array (xva_reqattrmap[]). Its location changes
+ * when the array sizes change. We use a separate pointer in a known location
+ * (xva_rtnattrmapp) to hold the location of xva_rtnattrmap[]. This is
+ * set in xva_init()
+ */
+#define XVA_RTNATTRMAP(xvap) ((xvap)->xva_rtnattrmapp)
+
+/*
+ * XVA_SET_REQ() sets an attribute bit in the proper element in the bitmap
+ * of requested attributes (xva_reqattrmap[]).
+ */
+#define XVA_SET_REQ(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (xvap)->xva_reqattrmap[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+
+/*
+ * XVA_SET_RTN() sets an attribute bit in the proper element in the bitmap
+ * of returned attributes (xva_rtnattrmap[]).
+ */
+#define XVA_SET_RTN(xvap, attr) \
+ ASSERT((xvap)->xva_vattr.va_mask | AT_XVATTR); \
+ ASSERT((xvap)->xva_magic == XVA_MAGIC); \
+ (XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] |= XVA_ATTRBIT(attr)
+
+/*
+ * XVA_ISSET_REQ() checks the requested attribute bitmap (xva_reqattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_REQ(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((xvap)->xva_reqattrmap[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
+ * XVA_ISSET_RTN() checks the returned attribute bitmap (xva_rtnattrmap[])
+ * to see of the corresponding attribute bit is set. If so, returns non-zero.
+ */
+#define XVA_ISSET_RTN(xvap, attr) \
+ ((((xvap)->xva_vattr.va_mask | AT_XVATTR) && \
+ ((xvap)->xva_magic == XVA_MAGIC) && \
+ ((xvap)->xva_mapsize > XVA_INDEX(attr))) ? \
+ ((XVA_RTNATTRMAP(xvap))[XVA_INDEX(attr)] & XVA_ATTRBIT(attr)) : 0)
+
+/*
* Modes. Some values same as S_xxx entries from stat.h for convenience.
*/
#define VSUID 04000 /* set user id on execution */
@@ -454,6 +670,12 @@ typedef vattr_t vattr32_t;
#define PERMMASK 00777 /* permission bits */
/*
+ * VOP_ACCESS flags
+ */
+#define V_ACE_MASK 0x1 /* mask represents NFSv4 ACE permissions */
+#define V_APPEND 0x2 /* want to do append only check */
+
+/*
* Check whether mandatory file locking is enabled.
*/
@@ -506,15 +728,19 @@ typedef struct vsecattr {
void *vsa_aclentp; /* pointer to ACL entries */
int vsa_dfaclcnt; /* default ACL entry count */
void *vsa_dfaclentp; /* pointer to default ACL entries */
+ size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
+ uint_t vsa_aclflags; /* ACE ACL flags */
} vsecattr_t;
/* vsa_mask values */
-#define VSA_ACL 0x0001
-#define VSA_ACLCNT 0x0002
-#define VSA_DFACL 0x0004
-#define VSA_DFACLCNT 0x0008
-#define VSA_ACE 0x0010
-#define VSA_ACECNT 0x0020
+#define VSA_ACL 0x0001
+#define VSA_ACLCNT 0x0002
+#define VSA_DFACL 0x0004
+#define VSA_DFACLCNT 0x0008
+#define VSA_ACE 0x0010
+#define VSA_ACECNT 0x0020
+#define VSA_ACE_ALLTYPES 0x0040
+#define VSA_ACE_ACLFLAGS 0x0080 /* get/set ACE ACL flags */
/*
* Structure used by various vnode operations to determine
@@ -552,79 +778,110 @@ struct pollhead;
* the vnodeops structure (below) and the fs_func_p union (vfs_opreg.h).
*/
#define VNODE_OPS \
- int (*vop_open)(vnode_t **, int, cred_t *); \
- int (*vop_close)(vnode_t *, int, int, offset_t, cred_t *); \
+ int (*vop_open)(vnode_t **, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_close)(vnode_t *, int, int, offset_t, cred_t *, \
+ caller_context_t *); \
int (*vop_read)(vnode_t *, uio_t *, int, cred_t *, \
caller_context_t *); \
int (*vop_write)(vnode_t *, uio_t *, int, cred_t *, \
caller_context_t *); \
int (*vop_ioctl)(vnode_t *, int, intptr_t, int, cred_t *, \
- int *); \
- int (*vop_setfl)(vnode_t *, int, int, cred_t *); \
- int (*vop_getattr)(vnode_t *, vattr_t *, int, cred_t *); \
+ int *, caller_context_t *); \
+ int (*vop_setfl)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_getattr)(vnode_t *, vattr_t *, int, cred_t *, \
+ caller_context_t *); \
int (*vop_setattr)(vnode_t *, vattr_t *, int, cred_t *, \
caller_context_t *); \
- int (*vop_access)(vnode_t *, int, int, cred_t *); \
+ int (*vop_access)(vnode_t *, int, int, cred_t *, \
+ caller_context_t *); \
int (*vop_lookup)(vnode_t *, char *, vnode_t **, \
struct pathname *, \
- int, vnode_t *, cred_t *); \
+ int, vnode_t *, cred_t *, \
+ caller_context_t *, int *, \
+ struct pathname *); \
int (*vop_create)(vnode_t *, char *, vattr_t *, vcexcl_t, \
- int, vnode_t **, cred_t *, int); \
- int (*vop_remove)(vnode_t *, char *, cred_t *); \
- int (*vop_link)(vnode_t *, vnode_t *, char *, cred_t *); \
+ int, vnode_t **, cred_t *, int, \
+ caller_context_t *, vsecattr_t *); \
+ int (*vop_remove)(vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_link)(vnode_t *, vnode_t *, char *, cred_t *, \
+ caller_context_t *, int); \
int (*vop_rename)(vnode_t *, char *, vnode_t *, char *, \
- cred_t *); \
+ cred_t *, caller_context_t *, int); \
int (*vop_mkdir)(vnode_t *, char *, vattr_t *, vnode_t **, \
- cred_t *); \
- int (*vop_rmdir)(vnode_t *, char *, vnode_t *, cred_t *); \
- int (*vop_readdir)(vnode_t *, uio_t *, cred_t *, int *); \
+ cred_t *, caller_context_t *, int, \
+ vsecattr_t *); \
+ int (*vop_rmdir)(vnode_t *, char *, vnode_t *, cred_t *, \
+ caller_context_t *, int); \
+ int (*vop_readdir)(vnode_t *, uio_t *, cred_t *, int *, \
+ caller_context_t *, int); \
int (*vop_symlink)(vnode_t *, char *, vattr_t *, char *, \
- cred_t *); \
- int (*vop_readlink)(vnode_t *, uio_t *, cred_t *); \
- int (*vop_fsync)(vnode_t *, int, cred_t *); \
- void (*vop_inactive)(vnode_t *, cred_t *); \
- int (*vop_fid)(vnode_t *, struct fid *); \
+ cred_t *, caller_context_t *, int); \
+ int (*vop_readlink)(vnode_t *, uio_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fsync)(vnode_t *, int, cred_t *, \
+ caller_context_t *); \
+ void (*vop_inactive)(vnode_t *, cred_t *, \
+ caller_context_t *); \
+ int (*vop_fid)(vnode_t *, struct fid *, \
+ caller_context_t *); \
int (*vop_rwlock)(vnode_t *, int, caller_context_t *); \
void (*vop_rwunlock)(vnode_t *, int, caller_context_t *); \
- int (*vop_seek)(vnode_t *, offset_t, offset_t *); \
- int (*vop_cmp)(vnode_t *, vnode_t *); \
+ int (*vop_seek)(vnode_t *, offset_t, offset_t *, \
+ caller_context_t *); \
+ int (*vop_cmp)(vnode_t *, vnode_t *, caller_context_t *); \
int (*vop_frlock)(vnode_t *, int, struct flock64 *, \
int, offset_t, \
- struct flk_callback *, cred_t *); \
+ struct flk_callback *, cred_t *, \
+ caller_context_t *); \
int (*vop_space)(vnode_t *, int, struct flock64 *, \
int, offset_t, \
cred_t *, caller_context_t *); \
- int (*vop_realvp)(vnode_t *, vnode_t **); \
+ int (*vop_realvp)(vnode_t *, vnode_t **, \
+ caller_context_t *); \
int (*vop_getpage)(vnode_t *, offset_t, size_t, uint_t *, \
struct page **, size_t, struct seg *, \
- caddr_t, enum seg_rw, cred_t *); \
+ caddr_t, enum seg_rw, cred_t *, \
+ caller_context_t *); \
int (*vop_putpage)(vnode_t *, offset_t, size_t, \
- int, cred_t *); \
+ int, cred_t *, caller_context_t *); \
int (*vop_map)(vnode_t *, offset_t, struct as *, \
caddr_t *, size_t, \
- uchar_t, uchar_t, uint_t, cred_t *); \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
int (*vop_addmap)(vnode_t *, offset_t, struct as *, \
caddr_t, size_t, \
- uchar_t, uchar_t, uint_t, cred_t *); \
+ uchar_t, uchar_t, uint_t, cred_t *, \
+ caller_context_t *); \
int (*vop_delmap)(vnode_t *, offset_t, struct as *, \
caddr_t, size_t, \
- uint_t, uint_t, uint_t, cred_t *); \
+ uint_t, uint_t, uint_t, cred_t *, \
+ caller_context_t *); \
int (*vop_poll)(vnode_t *, short, int, short *, \
- struct pollhead **); \
- int (*vop_dump)(vnode_t *, caddr_t, int, int); \
- int (*vop_pathconf)(vnode_t *, int, ulong_t *, cred_t *); \
+ struct pollhead **, \
+ caller_context_t *); \
+ int (*vop_dump)(vnode_t *, caddr_t, int, int, \
+ caller_context_t *); \
+ int (*vop_pathconf)(vnode_t *, int, ulong_t *, cred_t *, \
+ caller_context_t *); \
int (*vop_pageio)(vnode_t *, struct page *, \
- u_offset_t, size_t, int, cred_t *); \
- int (*vop_dumpctl)(vnode_t *, int, int *); \
+ u_offset_t, size_t, int, cred_t *, \
+ caller_context_t *); \
+ int (*vop_dumpctl)(vnode_t *, int, int *, \
+ caller_context_t *); \
void (*vop_dispose)(vnode_t *, struct page *, \
- int, int, cred_t *); \
+ int, int, cred_t *, \
+ caller_context_t *); \
int (*vop_setsecattr)(vnode_t *, vsecattr_t *, \
- int, cred_t *); \
+ int, cred_t *, caller_context_t *); \
int (*vop_getsecattr)(vnode_t *, vsecattr_t *, \
- int, cred_t *); \
+ int, cred_t *, caller_context_t *); \
int (*vop_shrlock)(vnode_t *, int, struct shrlock *, \
- int, cred_t *); \
- int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, char *) \
+ int, cred_t *, caller_context_t *); \
+ int (*vop_vnevent)(vnode_t *, vnevent_t, vnode_t *, \
+ char *, caller_context_t *)
/* NB: No ";" */
/*
@@ -639,153 +896,178 @@ typedef struct vnodeops {
typedef int (*fs_generic_func_p) (); /* Generic vop/vfsop/femop/fsemop ptr */
-extern int fop_open(vnode_t **, int, cred_t *);
-extern int fop_close(vnode_t *, int, int, offset_t, cred_t *);
+extern int fop_open(vnode_t **, int, cred_t *, caller_context_t *);
+extern int fop_close(vnode_t *, int, int, offset_t, cred_t *,
+ caller_context_t *);
extern int fop_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *);
extern int fop_write(vnode_t *, uio_t *, int, cred_t *,
caller_context_t *);
-extern int fop_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *);
-extern int fop_setfl(vnode_t *, int, int, cred_t *);
-extern int fop_getattr(vnode_t *, vattr_t *, int, cred_t *);
+extern int fop_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+ caller_context_t *);
+extern int fop_setfl(vnode_t *, int, int, cred_t *, caller_context_t *);
+extern int fop_getattr(vnode_t *, vattr_t *, int, cred_t *,
+ caller_context_t *);
extern int fop_setattr(vnode_t *, vattr_t *, int, cred_t *,
caller_context_t *);
-extern int fop_access(vnode_t *, int, int, cred_t *);
+extern int fop_access(vnode_t *, int, int, cred_t *, caller_context_t *);
extern int fop_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
- int, vnode_t *, cred_t *);
+ int, vnode_t *, cred_t *, caller_context_t *,
+ int *, struct pathname *);
extern int fop_create(vnode_t *, char *, vattr_t *, vcexcl_t, int,
- vnode_t **, cred_t *, int);
-extern int fop_remove(vnode_t *vp, char *, cred_t *);
-extern int fop_link(vnode_t *, vnode_t *, char *, cred_t *);
-extern int fop_rename(vnode_t *, char *, vnode_t *, char *, cred_t *);
-extern int fop_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *);
-extern int fop_rmdir(vnode_t *, char *, vnode_t *, cred_t *);
-extern int fop_readdir(vnode_t *, uio_t *, cred_t *, int *);
-extern int fop_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *);
-extern int fop_readlink(vnode_t *, uio_t *, cred_t *);
-extern int fop_fsync(vnode_t *, int, cred_t *);
-extern void fop_inactive(vnode_t *, cred_t *);
-extern int fop_fid(vnode_t *, struct fid *);
+ vnode_t **, cred_t *, int, caller_context_t *,
+ vsecattr_t *);
+extern int fop_remove(vnode_t *vp, char *, cred_t *, caller_context_t *,
+ int);
+extern int fop_link(vnode_t *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
+ caller_context_t *, int, vsecattr_t *);
+extern int fop_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readdir(vnode_t *, uio_t *, cred_t *, int *,
+ caller_context_t *, int);
+extern int fop_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
+ caller_context_t *, int);
+extern int fop_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *);
+extern int fop_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+extern void fop_inactive(vnode_t *, cred_t *, caller_context_t *);
+extern int fop_fid(vnode_t *, struct fid *, caller_context_t *);
extern int fop_rwlock(vnode_t *, int, caller_context_t *);
extern void fop_rwunlock(vnode_t *, int, caller_context_t *);
-extern int fop_seek(vnode_t *, offset_t, offset_t *);
-extern int fop_cmp(vnode_t *, vnode_t *);
+extern int fop_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+extern int fop_cmp(vnode_t *, vnode_t *, caller_context_t *);
extern int fop_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
- struct flk_callback *, cred_t *);
+ struct flk_callback *, cred_t *,
+ caller_context_t *);
extern int fop_space(vnode_t *, int, struct flock64 *, int, offset_t,
cred_t *, caller_context_t *);
-extern int fop_realvp(vnode_t *, vnode_t **);
+extern int fop_realvp(vnode_t *, vnode_t **, caller_context_t *);
extern int fop_getpage(vnode_t *, offset_t, size_t, uint_t *,
struct page **, size_t, struct seg *,
- caddr_t, enum seg_rw, cred_t *);
-extern int fop_putpage(vnode_t *, offset_t, size_t, int, cred_t *);
+ caddr_t, enum seg_rw, cred_t *,
+ caller_context_t *);
+extern int fop_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
+ caller_context_t *);
extern int fop_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
- uchar_t, uchar_t, uint_t, cred_t *cr);
+ uchar_t, uchar_t, uint_t, cred_t *cr,
+ caller_context_t *);
extern int fop_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
- uchar_t, uchar_t, uint_t, cred_t *);
+ uchar_t, uchar_t, uint_t, cred_t *,
+ caller_context_t *);
extern int fop_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
- uint_t, uint_t, uint_t, cred_t *);
-extern int fop_poll(vnode_t *, short, int, short *, struct pollhead **);
-extern int fop_dump(vnode_t *, caddr_t, int, int);
-extern int fop_pathconf(vnode_t *, int, ulong_t *, cred_t *);
+ uint_t, uint_t, uint_t, cred_t *,
+ caller_context_t *);
+extern int fop_poll(vnode_t *, short, int, short *, struct pollhead **,
+ caller_context_t *);
+extern int fop_dump(vnode_t *, caddr_t, int, int, caller_context_t *);
+extern int fop_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+ caller_context_t *);
extern int fop_pageio(vnode_t *, struct page *, u_offset_t, size_t, int,
- cred_t *);
-extern int fop_dumpctl(vnode_t *, int, int *);
-extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *);
-extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *);
-extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *);
-extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *);
+ cred_t *, caller_context_t *);
+extern int fop_dumpctl(vnode_t *, int, int *, caller_context_t *);
+extern void fop_dispose(vnode_t *, struct page *, int, int, cred_t *,
+ caller_context_t *);
+extern int fop_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+ caller_context_t *);
+extern int fop_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+ caller_context_t *);
+extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *,
+ caller_context_t *);
#endif /* _KERNEL */
-#define VOP_OPEN(vpp, mode, cr) \
- fop_open(vpp, mode, cr)
-#define VOP_CLOSE(vp, f, c, o, cr) \
- fop_close(vp, f, c, o, cr)
+#define VOP_OPEN(vpp, mode, cr, ct) \
+ fop_open(vpp, mode, cr, ct)
+#define VOP_CLOSE(vp, f, c, o, cr, ct) \
+ fop_close(vp, f, c, o, cr, ct)
#define VOP_READ(vp, uiop, iof, cr, ct) \
fop_read(vp, uiop, iof, cr, ct)
#define VOP_WRITE(vp, uiop, iof, cr, ct) \
fop_write(vp, uiop, iof, cr, ct)
-#define VOP_IOCTL(vp, cmd, a, f, cr, rvp) \
- fop_ioctl(vp, cmd, a, f, cr, rvp)
-#define VOP_SETFL(vp, f, a, cr) \
- fop_setfl(vp, f, a, cr)
-#define VOP_GETATTR(vp, vap, f, cr) \
- fop_getattr(vp, vap, f, cr)
+#define VOP_IOCTL(vp, cmd, a, f, cr, rvp, ct) \
+ fop_ioctl(vp, cmd, a, f, cr, rvp, ct)
+#define VOP_SETFL(vp, f, a, cr, ct) \
+ fop_setfl(vp, f, a, cr, ct)
+#define VOP_GETATTR(vp, vap, f, cr, ct) \
+ fop_getattr(vp, vap, f, cr, ct)
#define VOP_SETATTR(vp, vap, f, cr, ct) \
fop_setattr(vp, vap, f, cr, ct)
-#define VOP_ACCESS(vp, mode, f, cr) \
- fop_access(vp, mode, f, cr)
-#define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr) \
- fop_lookup(vp, cp, vpp, pnp, f, rdir, cr)
-#define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr, flag) \
- fop_create(dvp, p, vap, ex, mode, vpp, cr, flag)
-#define VOP_REMOVE(dvp, p, cr) \
- fop_remove(dvp, p, cr)
-#define VOP_LINK(tdvp, fvp, p, cr) \
- fop_link(tdvp, fvp, p, cr)
-#define VOP_RENAME(fvp, fnm, tdvp, tnm, cr) \
- fop_rename(fvp, fnm, tdvp, tnm, cr)
-#define VOP_MKDIR(dp, p, vap, vpp, cr) \
- fop_mkdir(dp, p, vap, vpp, cr)
-#define VOP_RMDIR(dp, p, cdir, cr) \
- fop_rmdir(dp, p, cdir, cr)
-#define VOP_READDIR(vp, uiop, cr, eofp) \
- fop_readdir(vp, uiop, cr, eofp)
-#define VOP_SYMLINK(dvp, lnm, vap, tnm, cr) \
- fop_symlink(dvp, lnm, vap, tnm, cr)
-#define VOP_READLINK(vp, uiop, cr) \
- fop_readlink(vp, uiop, cr)
-#define VOP_FSYNC(vp, syncflag, cr) \
- fop_fsync(vp, syncflag, cr)
-#define VOP_INACTIVE(vp, cr) \
- fop_inactive(vp, cr)
-#define VOP_FID(vp, fidp) \
- fop_fid(vp, fidp)
+#define VOP_ACCESS(vp, mode, f, cr, ct) \
+ fop_access(vp, mode, f, cr, ct)
+#define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp) \
+ fop_lookup(vp, cp, vpp, pnp, f, rdir, cr, ct, defp, rpnp)
+#define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap) \
+ fop_create(dvp, p, vap, ex, mode, vpp, cr, flag, ct, vsap)
+#define VOP_REMOVE(dvp, p, cr, ct, f) \
+ fop_remove(dvp, p, cr, ct, f)
+#define VOP_LINK(tdvp, fvp, p, cr, ct, f) \
+ fop_link(tdvp, fvp, p, cr, ct, f)
+#define VOP_RENAME(fvp, fnm, tdvp, tnm, cr, ct, f) \
+ fop_rename(fvp, fnm, tdvp, tnm, cr, ct, f)
+#define VOP_MKDIR(dp, p, vap, vpp, cr, ct, f, vsap) \
+ fop_mkdir(dp, p, vap, vpp, cr, ct, f, vsap)
+#define VOP_RMDIR(dp, p, cdir, cr, ct, f) \
+ fop_rmdir(dp, p, cdir, cr, ct, f)
+#define VOP_READDIR(vp, uiop, cr, eofp, ct, f) \
+ fop_readdir(vp, uiop, cr, eofp, ct, f)
+#define VOP_SYMLINK(dvp, lnm, vap, tnm, cr, ct, f) \
+ fop_symlink(dvp, lnm, vap, tnm, cr, ct, f)
+#define VOP_READLINK(vp, uiop, cr, ct) \
+ fop_readlink(vp, uiop, cr, ct)
+#define VOP_FSYNC(vp, syncflag, cr, ct) \
+ fop_fsync(vp, syncflag, cr, ct)
+#define VOP_INACTIVE(vp, cr, ct) \
+ fop_inactive(vp, cr, ct)
+#define VOP_FID(vp, fidp, ct) \
+ fop_fid(vp, fidp, ct)
#define VOP_RWLOCK(vp, w, ct) \
fop_rwlock(vp, w, ct)
#define VOP_RWUNLOCK(vp, w, ct) \
fop_rwunlock(vp, w, ct)
-#define VOP_SEEK(vp, ooff, noffp) \
- fop_seek(vp, ooff, noffp)
-#define VOP_CMP(vp1, vp2) \
- fop_cmp(vp1, vp2)
-#define VOP_FRLOCK(vp, cmd, a, f, o, cb, cr) \
- fop_frlock(vp, cmd, a, f, o, cb, cr)
+#define VOP_SEEK(vp, ooff, noffp, ct) \
+ fop_seek(vp, ooff, noffp, ct)
+#define VOP_CMP(vp1, vp2, ct) \
+ fop_cmp(vp1, vp2, ct)
+#define VOP_FRLOCK(vp, cmd, a, f, o, cb, cr, ct) \
+ fop_frlock(vp, cmd, a, f, o, cb, cr, ct)
#define VOP_SPACE(vp, cmd, a, f, o, cr, ct) \
fop_space(vp, cmd, a, f, o, cr, ct)
-#define VOP_REALVP(vp1, vp2) \
- fop_realvp(vp1, vp2)
-#define VOP_GETPAGE(vp, of, sz, pr, pl, ps, sg, a, rw, cr) \
- fop_getpage(vp, of, sz, pr, pl, ps, sg, a, rw, cr)
-#define VOP_PUTPAGE(vp, of, sz, fl, cr) \
- fop_putpage(vp, of, sz, fl, cr)
-#define VOP_MAP(vp, of, as, a, sz, p, mp, fl, cr) \
- fop_map(vp, of, as, a, sz, p, mp, fl, cr)
-#define VOP_ADDMAP(vp, of, as, a, sz, p, mp, fl, cr) \
- fop_addmap(vp, of, as, a, sz, p, mp, fl, cr)
-#define VOP_DELMAP(vp, of, as, a, sz, p, mp, fl, cr) \
- fop_delmap(vp, of, as, a, sz, p, mp, fl, cr)
-#define VOP_POLL(vp, events, anyyet, reventsp, phpp) \
- fop_poll(vp, events, anyyet, reventsp, phpp)
-#define VOP_DUMP(vp, addr, bn, count) \
- fop_dump(vp, addr, bn, count)
-#define VOP_PATHCONF(vp, cmd, valp, cr) \
- fop_pathconf(vp, cmd, valp, cr)
-#define VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr) \
- fop_pageio(vp, pp, io_off, io_len, flags, cr)
-#define VOP_DUMPCTL(vp, action, blkp) \
- fop_dumpctl(vp, action, blkp)
-#define VOP_DISPOSE(vp, pp, flag, dn, cr) \
- fop_dispose(vp, pp, flag, dn, cr)
-#define VOP_GETSECATTR(vp, vsap, f, cr) \
- fop_getsecattr(vp, vsap, f, cr)
-#define VOP_SETSECATTR(vp, vsap, f, cr) \
- fop_setsecattr(vp, vsap, f, cr)
-#define VOP_SHRLOCK(vp, cmd, shr, f, cr) \
- fop_shrlock(vp, cmd, shr, f, cr)
-#define VOP_VNEVENT(vp, vnevent, dvp, fnm) \
- fop_vnevent(vp, vnevent, dvp, fnm)
+#define VOP_REALVP(vp1, vp2, ct) \
+ fop_realvp(vp1, vp2, ct)
+#define VOP_GETPAGE(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct) \
+ fop_getpage(vp, of, sz, pr, pl, ps, sg, a, rw, cr, ct)
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) \
+ fop_putpage(vp, of, sz, fl, cr, ct)
+#define VOP_MAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_map(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_ADDMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_addmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_DELMAP(vp, of, as, a, sz, p, mp, fl, cr, ct) \
+ fop_delmap(vp, of, as, a, sz, p, mp, fl, cr, ct)
+#define VOP_POLL(vp, events, anyyet, reventsp, phpp, ct) \
+ fop_poll(vp, events, anyyet, reventsp, phpp, ct)
+#define VOP_DUMP(vp, addr, bn, count, ct) \
+ fop_dump(vp, addr, bn, count, ct)
+#define VOP_PATHCONF(vp, cmd, valp, cr, ct) \
+ fop_pathconf(vp, cmd, valp, cr, ct)
+#define VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct) \
+ fop_pageio(vp, pp, io_off, io_len, flags, cr, ct)
+#define VOP_DUMPCTL(vp, action, blkp, ct) \
+ fop_dumpctl(vp, action, blkp, ct)
+#define VOP_DISPOSE(vp, pp, flag, dn, cr, ct) \
+ fop_dispose(vp, pp, flag, dn, cr, ct)
+#define VOP_GETSECATTR(vp, vsap, f, cr, ct) \
+ fop_getsecattr(vp, vsap, f, cr, ct)
+#define VOP_SETSECATTR(vp, vsap, f, cr, ct) \
+ fop_setsecattr(vp, vsap, f, cr, ct)
+#define VOP_SHRLOCK(vp, cmd, shr, f, cr, ct) \
+ fop_shrlock(vp, cmd, shr, f, cr, ct)
+#define VOP_VNEVENT(vp, vnevent, dvp, fnm, ct) \
+ fop_vnevent(vp, vnevent, dvp, fnm, ct)
#define VOPNAME_OPEN "open"
#define VOPNAME_CLOSE "close"
@@ -834,10 +1116,19 @@ extern int fop_vnevent(vnode_t *, vnevent_t, vnode_t *, char *);
/*
* Flags for VOP_LOOKUP
+ *
+ * Defined in file.h, but also possible, FIGNORECASE
+ *
*/
#define LOOKUP_DIR 0x01 /* want parent dir vp */
#define LOOKUP_XATTR 0x02 /* lookup up extended attr dir */
#define CREATE_XATTR_DIR 0x04 /* Create extended attr dir */
+#define LOOKUP_HAVE_SYSATTR_DIR 0x08 /* Already created virtual GFS dir */
+
+/*
+ * Flags for VOP_READDIR
+ */
+#define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */
/*
* Flags for VOP_RWLOCK/VOP_RWUNLOCK
@@ -866,6 +1157,9 @@ void vn_free(vnode_t *);
int vn_is_readonly(vnode_t *);
int vn_is_opened(vnode_t *, v_mode_t);
int vn_is_mapped(vnode_t *, v_mode_t);
+int vn_has_other_opens(vnode_t *, v_mode_t);
+void vn_open_upgrade(vnode_t *, int);
+void vn_open_downgrade(vnode_t *, int);
int vn_can_change_zones(vnode_t *vp);
@@ -890,7 +1184,7 @@ int vn_open(char *pnamep, enum uio_seg seg, int filemode, int createmode,
struct vnode **vpp, enum create crwhy, mode_t umask);
int vn_openat(char *pnamep, enum uio_seg seg, int filemode, int createmode,
struct vnode **vpp, enum create crwhy,
- mode_t umask, struct vnode *startvp);
+ mode_t umask, struct vnode *startvp, int fd);
int vn_create(char *pnamep, enum uio_seg seg, struct vattr *vap,
enum vcexcl excl, int mode, struct vnode **vpp,
enum create why, int flag, mode_t umask);
@@ -927,15 +1221,15 @@ void vn_setpath(vnode_t *rootvp, struct vnode *startvp, struct vnode *vp,
const char *path, size_t plen);
/* Vnode event notification */
-void vnevent_rename_src(vnode_t *, vnode_t *, char *);
-void vnevent_rename_dest(vnode_t *, vnode_t *, char *);
-void vnevent_remove(vnode_t *, vnode_t *, char *);
-void vnevent_rmdir(vnode_t *, vnode_t *, char *);
-void vnevent_create(vnode_t *);
-void vnevent_link(vnode_t *);
-void vnevent_rename_dest_dir(vnode_t *);
-void vnevent_mountedover(vnode_t *);
-int vnevent_support(vnode_t *);
+void vnevent_rename_src(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rename_dest(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_remove(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_rmdir(vnode_t *, vnode_t *, char *, caller_context_t *);
+void vnevent_create(vnode_t *, caller_context_t *);
+void vnevent_link(vnode_t *, caller_context_t *);
+void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
+void vnevent_mountedover(vnode_t *, caller_context_t *);
+int vnevent_support(vnode_t *, caller_context_t *);
/* Vnode specific data */
void vsd_create(uint_t *, void (*)(void *));
@@ -944,6 +1238,19 @@ void *vsd_get(vnode_t *, uint_t);
int vsd_set(vnode_t *, uint_t, void *);
void vsd_free(vnode_t *);
+/*
+ * Extensible vnode attribute (xva) routines:
+ * xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
+ * xva_getxoptattr() returns a ponter to the xoptattr_t section of xvattr_t
+ */
+void xva_init(xvattr_t *);
+xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
+
+void xattr_init(void); /* Initialize vnodeops for xattrs */
+
+/* GFS tunnel for xattrs */
+int xattr_dir_lookup(vnode_t *, vnode_t **, int, cred_t *);
+
/* Context identification */
u_longlong_t fs_new_caller_id();
@@ -976,7 +1283,7 @@ extern uint_t pvn_vmodsort_supported;
*/
#define VN_CMP(VP1, VP2) ((VP1) == (VP2) ? 1 : \
((VP1) && (VP2) && (vn_getops(VP1) == vn_getops(VP2)) ? \
- VOP_CMP(VP1, VP2) : 0))
+ VOP_CMP(VP1, VP2, NULL) : 0))
extern struct vnode kvp;
extern struct vnode zvp;
@@ -993,8 +1300,8 @@ extern struct vnode zvp;
#define ATTR_COMM 0x04 /* yield common vp attributes */
#define ATTR_HINT 0x08 /* information returned will be `hint' */
#define ATTR_REAL 0x10 /* yield attributes of the real vp */
+#define ATTR_NOACLCHECK 0x20 /* Don't check ACL when checking permissions */
#define ATTR_TRIGGER 0x40 /* Mount first if vnode is a trigger mount */
-
/*
* Generally useful macros.
*/
@@ -1026,7 +1333,7 @@ struct async_reqs {
#define VN_DISPOSE(pp, flag, dn, cr) { \
extern struct vnode kvp; \
if ((pp)->p_vnode != NULL && !VN_ISKAS((pp)->p_vnode)) \
- VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr)); \
+ VOP_DISPOSE((pp)->p_vnode, (pp), (flag), (dn), (cr), NULL); \
else if ((flag) == B_FREE) \
page_free((pp), (dn)); \
else \
diff --git a/usr/src/uts/common/syscall/access.c b/usr/src/uts/common/syscall/access.c
index 0c19d8898a..467cb4ecb1 100644
--- a/usr/src/uts/common/syscall/access.c
+++ b/usr/src/uts/common/syscall/access.c
@@ -101,7 +101,7 @@ lookup:
}
if (mode) {
- error = VOP_ACCESS(vp, mode, 0, tmpcr);
+ error = VOP_ACCESS(vp, mode, 0, tmpcr, NULL);
if (error) {
if ((error == ESTALE) &&
fs_need_estale_retry(estale_retry++)) {
diff --git a/usr/src/uts/common/syscall/acctctl.c b/usr/src/uts/common/syscall/acctctl.c
index 8c134b0a62..1f614f23fb 100644
--- a/usr/src/uts/common/syscall/acctctl.c
+++ b/usr/src/uts/common/syscall/acctctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -161,7 +160,8 @@ ac_file_set(ac_info_t *info, void *ubuf, size_t bufsz)
* Closing accounting file
*/
if (info->ac_vnode != NULL) {
- error = VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0, CRED());
+ error = VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0,
+ CRED(), NULL);
if (error) {
mutex_exit(&info->ac_lock);
return (error);
@@ -265,7 +265,7 @@ ac_file_set(ac_info_t *info, void *ubuf, size_t bufsz)
/*
* We still need to close the old file.
*/
- if ((error = VOP_CLOSE(vp, FWRITE, 1, 0, CRED())) != 0) {
+ if ((error = VOP_CLOSE(vp, FWRITE, 1, 0, CRED(), NULL)) != 0) {
VN_RELE(vp);
mutex_exit(&info->ac_lock);
kmem_free(namebuf, namelen);
@@ -545,7 +545,7 @@ exacct_free_info(ac_info_t *info)
{
mutex_enter(&info->ac_lock);
if (info->ac_vnode) {
- (void) VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0, kcred);
+ (void) VOP_CLOSE(info->ac_vnode, FWRITE, 1, 0, kcred, NULL);
VN_RELE(info->ac_vnode);
kmem_free(info->ac_file, strlen(info->ac_file) + 1);
}
diff --git a/usr/src/uts/common/syscall/acl.c b/usr/src/uts/common/syscall/acl.c
index 1a7321928d..5c2fe3a9bc 100644
--- a/usr/src/uts/common/syscall/acl.c
+++ b/usr/src/uts/common/syscall/acl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,6 +133,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
caddr_t uaddrp;
aclent_t *aclp, *aaclp;
vsecattr_t vsecattr;
+ size_t entry_size;
ASSERT(vp);
@@ -142,20 +143,23 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
case ACE_GETACLCNT:
case GETACLCNT:
- if (cmd == GETACLCNT)
+ if (cmd == GETACLCNT) {
+ entry_size = sizeof (aclent_t);
vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT;
- else
+ } else {
+ entry_size = sizeof (ace_t);
vsecattr.vsa_mask = VSA_ACECNT;
- if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED()))
+ }
+ if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL))
return (error);
*rv = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt;
if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp) {
kmem_free(vsecattr.vsa_aclentp,
- vsecattr.vsa_aclcnt * sizeof (aclent_t));
+ vsecattr.vsa_aclcnt * entry_size);
}
if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp) {
kmem_free(vsecattr.vsa_dfaclentp,
- vsecattr.vsa_dfaclcnt * sizeof (aclent_t));
+ vsecattr.vsa_dfaclcnt * entry_size);
}
break;
case GETACL:
@@ -172,7 +176,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
return (EFAULT);
vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
VSA_DFACLCNT;
- if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED()))
+ if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL))
return (error);
/* Check user's buffer is big enough */
numacls = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt;
@@ -222,7 +226,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
return (EFAULT);
vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT;
- if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED()))
+ if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL))
return (error);
aclbsize = vsecattr.vsa_aclcnt * sizeof (ace_t);
@@ -240,8 +244,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
*rv = vsecattr.vsa_aclcnt;
if (vsecattr.vsa_aclcnt) {
- kmem_free(vsecattr.vsa_aclentp,
- vsecattr.vsa_aclcnt * sizeof (ace_t));
+ kmem_free(vsecattr.vsa_aclentp, vsecattr.vsa_aclentsz);
}
break;
@@ -300,7 +303,7 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
return (ENOTDIR);
}
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED())) {
+ if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) {
kmem_free(aaclp, aclbsize);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
return (error);
@@ -327,13 +330,14 @@ cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv)
vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP);
aaclp = vsecattr.vsa_aclentp;
vsecattr.vsa_aclcnt = nentries;
+ vsecattr.vsa_aclentsz = aclbsize;
uaddrp = (caddr_t)aclbufp;
if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) {
kmem_free(aaclp, aclbsize);
return (EFAULT);
}
(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
- if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED())) {
+ if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) {
kmem_free(aaclp, aclbsize);
VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
return (error);
diff --git a/usr/src/uts/common/syscall/chdir.c b/usr/src/uts/common/syscall/chdir.c
index 28abd43076..02bc93da74 100644
--- a/usr/src/uts/common/syscall/chdir.c
+++ b/usr/src/uts/common/syscall/chdir.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -174,7 +174,7 @@ chdirec(vnode_t *vp, int ischroot, int do_traverse)
error = ENOTDIR;
goto bad;
}
- if (error = VOP_ACCESS(vp, VEXEC, 0, CRED()))
+ if (error = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL))
goto bad;
/*
@@ -199,11 +199,11 @@ chdirec(vnode_t *vp, int ischroot, int do_traverse)
vnode_t *zonevp = curproc->p_zone->zone_rootvp;
tattr.va_mask = AT_FSID|AT_NODEID;
- if (error = VOP_GETATTR(vp, &tattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &tattr, 0, CRED(), NULL))
goto bad;
rattr.va_mask = AT_FSID|AT_NODEID;
- if (error = VOP_GETATTR(zonevp, &rattr, 0, CRED()))
+ if (error = VOP_GETATTR(zonevp, &rattr, 0, CRED(), NULL))
goto bad;
if ((tattr.va_fsid != rattr.va_fsid ||
diff --git a/usr/src/uts/common/syscall/fcntl.c b/usr/src/uts/common/syscall/fcntl.c
index 15245e4c8c..2e0807e697 100644
--- a/usr/src/uts/common/syscall/fcntl.c
+++ b/usr/src/uts/common/syscall/fcntl.c
@@ -20,7 +20,7 @@
*/
/* ONC_PLUS EXTRACT START */
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -205,7 +205,8 @@ fcntl(int fdes, int cmd, intptr_t arg)
flag = fp->f_flag;
if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
iarg &= ~FNDELAY;
- if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred)) == 0) {
+ if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
+ 0) {
iarg &= FMASK;
mutex_enter(&fp->f_tlock);
fp->f_flag &= ~FMASK | (FREAD|FWRITE);
@@ -317,7 +318,7 @@ fcntl(int fdes, int cmd, intptr_t arg)
* there's no need for them to know. Map it to F_GETLK.
*/
if ((error = VOP_FRLOCK(vp, (cmd == F_O_GETLK) ? F_GETLK : cmd,
- &bf, flag, offset, NULL, fp->f_cred)) != 0)
+ &bf, flag, offset, NULL, fp->f_cred, NULL)) != 0)
break;
/*
@@ -527,12 +528,14 @@ fcntl(int fdes, int cmd, intptr_t arg)
nbl_start_crit(vp, RW_READER);
in_crit = 1;
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, CRED())) != 0)
+ if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
+ != 0)
break;
begin = start > vattr.va_size ? vattr.va_size : start;
length = vattr.va_size > start ? vattr.va_size - start :
start - vattr.va_size;
- if (nbl_conflict(vp, NBL_WRITE, begin, length, 0)) {
+ if (nbl_conflict(vp, NBL_WRITE, begin, length, 0,
+ NULL)) {
error = EACCES;
break;
}
@@ -599,7 +602,7 @@ fcntl(int fdes, int cmd, intptr_t arg)
break;
if ((error = VOP_FRLOCK(vp, cmd, &bf, flag, offset,
- NULL, fp->f_cred)) != 0)
+ NULL, fp->f_cred, NULL)) != 0)
break;
if ((cmd == F_GETLK) && bf.l_type == F_UNLCK) {
@@ -658,7 +661,7 @@ fcntl(int fdes, int cmd, intptr_t arg)
shr_own.sl_id = fsh.f_id;
shr.s_own_len = sizeof (shr_own);
shr.s_owner = (caddr_t)&shr_own;
- error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred);
+ error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred, NULL);
/* ONC_PLUS EXTRACT END */
break;
@@ -710,7 +713,7 @@ flock_check(vnode_t *vp, flock64_t *flp, offset_t offset, offset_t max)
break;
case 2: /* SEEK_END */
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
if (flp->l_start > (max - (offset_t)vattr.va_size))
return (EOVERFLOW);
@@ -774,7 +777,7 @@ flock_get_start(vnode_t *vp, flock64_t *flp, offset_t offset, u_offset_t *start)
break;
case 2: /* SEEK_END */
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, CRED()))
+ if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
return (error);
*start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size);
break;
diff --git a/usr/src/uts/common/syscall/fdsync.c b/usr/src/uts/common/syscall/fdsync.c
index 9951eb8727..8d8eaeab14 100644
--- a/usr/src/uts/common/syscall/fdsync.c
+++ b/usr/src/uts/common/syscall/fdsync.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1998 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,7 +31,7 @@
* under license from the Regents of the University of California.
*/
-#ident "%Z%%M% %I% %E% SMI"
+#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/param.h>
#include <sys/isa_defs.h>
@@ -65,7 +64,7 @@ fdsync(int fd, int flag)
*/
syncflag = flag & (FSYNC|FDSYNC);
- if (error = VOP_FSYNC(fp->f_vnode, syncflag, fp->f_cred))
+ if (error = VOP_FSYNC(fp->f_vnode, syncflag, fp->f_cred, NULL))
(void) set_errno(error);
releasef(fd);
} else
diff --git a/usr/src/uts/common/syscall/fsat.c b/usr/src/uts/common/syscall/fsat.c
index a558518d85..0ad6a6446e 100644
--- a/usr/src/uts/common/syscall/fsat.c
+++ b/usr/src/uts/common/syscall/fsat.c
@@ -42,6 +42,7 @@ extern int fchownat(int, char *, uid_t, gid_t, int);
extern int fstatat(int, char *, struct stat *, int);
extern int futimesat(int, char *, struct timeval *);
extern int accessat(int, char *, int);
+extern int openattrdirat(int, char *);
#if defined(_SYSCALL32_IMPL) || defined(_ILP32)
extern int fstatat64_32(int, char *, struct stat64_32 *, int);
extern int fstatat32(int, char *, struct stat32 *, int);
@@ -65,6 +66,7 @@ extern int fstatat64_32(int, char *, struct stat64_32 *, int);
* 6 - futimesat
* 7 - renameat
* 8 - accessat
+ * 9 - openattrdirat
*
* The code for handling the at functionality exists in the file where the
* base syscall is defined. For example openat is in open.c
@@ -81,43 +83,45 @@ fsat32(int code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
case 0: /* openat */
#if defined(_LP64)
return (openat32((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
#else
return (openat((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
#endif
case 1: /* openat64 */
return (openat64((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
case 2: /* fstatat64 */
#if defined(_LP64)
return (fstatat64_32((int)arg1, (char *)arg2,
- (struct stat64_32 *)arg3, (int)arg4));
+ (struct stat64_32 *)arg3, (int)arg4));
#else
return (fstatat64((int)arg1, (char *)arg2,
- (struct stat64 *)arg3, (int)arg4));
+ (struct stat64 *)arg3, (int)arg4));
#endif
case 3: /* fstatat */
#if defined(_LP64)
return (fstatat32((int)arg1, (char *)arg2,
- (struct stat32 *)arg3, (int)arg4));
+ (struct stat32 *)arg3, (int)arg4));
#else
return (fstatat((int)arg1, (char *)arg2,
- (struct stat *)arg3, (int)arg4));
+ (struct stat *)arg3, (int)arg4));
#endif
case 4: /* fchownat */
return (fchownat((int)arg1, (char *)arg2,
- (uid_t)arg3, (gid_t)arg4, (int)arg5));
+ (uid_t)arg3, (gid_t)arg4, (int)arg5));
case 5: /* unlinkat */
return (unlinkat((int)arg1, (char *)arg2, (int)arg3));
case 6: /* futimesat */
return (futimesat((int)arg1,
- (char *)arg2, (struct timeval *)arg3));
+ (char *)arg2, (struct timeval *)arg3));
case 7: /* renameat */
return (renameat((int)arg1, (char *)arg2, (int)arg3,
- (char *)arg4));
+ (char *)arg4));
case 8: /* accessat */
return (accessat((int)arg1, (char *)arg2, (int)arg3));
+ case 9: /* openattrdirat */
+ return (openattrdirat((int)arg1, (char *)arg2));
default:
return (set_errno(EINVAL));
}
@@ -139,27 +143,29 @@ fsat64(int code, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
case 0: /* openat */
return (openat((int)arg1, (char *)arg2,
- (int)arg3, (int)arg4));
+ (int)arg3, (int)arg4));
case 1: /* openat64 */
return (set_errno(ENOSYS));
case 2: /* fstatat64 */
return (set_errno(ENOSYS));
case 3: /* fstatat */
return (fstatat((int)arg1, (char *)arg2,
- (struct stat *)arg3, (int)arg4));
+ (struct stat *)arg3, (int)arg4));
case 4: /* fchownat */
return (fchownat((int)arg1, (char *)arg2,
- (uid_t)arg3, (gid_t)arg4, (int)arg5));
+ (uid_t)arg3, (gid_t)arg4, (int)arg5));
case 5: /* unlinkat */
return (unlinkat((int)arg1, (char *)arg2, (int)arg3));
case 6: /* futimesat */
return (futimesat((int)arg1,
- (char *)arg2, (struct timeval *)arg3));
+ (char *)arg2, (struct timeval *)arg3));
case 7: /* renameat */
return (renameat((int)arg1, (char *)arg2, (int)arg3,
- (char *)arg4));
+ (char *)arg4));
case 8: /* accessat */
return (accessat((int)arg1, (char *)arg2, (int)arg3));
+ case 9: /* openattrdirat */
+ return (openattrdirat((int)arg1, (char *)arg2));
default:
return (set_errno(EINVAL));
}
diff --git a/usr/src/uts/common/syscall/getdents.c b/usr/src/uts/common/syscall/getdents.c
index a7d410d2a6..5daa9c39b4 100644
--- a/usr/src/uts/common/syscall/getdents.c
+++ b/usr/src/uts/common/syscall/getdents.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -119,7 +118,7 @@ getdents32(int fd, void *buf, size_t count)
auio.uio_fmode = 0;
auio.uio_extflg = UIO_COPY_CACHED;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(vp, &auio, fp->f_cred, &sink);
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &sink, NULL, 0);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
if (error)
goto out;
@@ -222,7 +221,7 @@ getdents64(int fd, void *buf, size_t count)
auio.uio_fmode = 0;
auio.uio_extflg = UIO_COPY_CACHED;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
- error = VOP_READDIR(vp, &auio, fp->f_cred, &sink);
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &sink, NULL, 0);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
if (error) {
releasef(fd);
diff --git a/usr/src/uts/common/syscall/ioctl.c b/usr/src/uts/common/syscall/ioctl.c
index c4b514d4de..f3c068dc6b 100644
--- a/usr/src/uts/common/syscall/ioctl.c
+++ b/usr/src/uts/common/syscall/ioctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -90,7 +89,7 @@ ioctl(int fdes, int cmd, intptr_t arg)
int32_t offset;
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error) {
releasef(fdes);
return (set_errno(error));
@@ -127,7 +126,7 @@ ioctl(int fdes, int cmd, intptr_t arg)
* ioctl() now passes in the model information in some high bits.
*/
flag = fp->f_flag | get_udatamodel();
- error = VOP_IOCTL(fp->f_vnode, cmd, arg, flag, CRED(), &rv);
+ error = VOP_IOCTL(fp->f_vnode, cmd, arg, flag, CRED(), &rv, NULL);
if (error != 0) {
releasef(fdes);
return (set_errno(error));
diff --git a/usr/src/uts/common/syscall/lseek.c b/usr/src/uts/common/syscall/lseek.c
index d03687eb68..b5cc2e5d4e 100644
--- a/usr/src/uts/common/syscall/lseek.c
+++ b/usr/src/uts/common/syscall/lseek.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -113,7 +112,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
case SEEK_END:
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred)) {
+ if (error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) {
goto out;
}
if (reg && (off > (max - (offset_t)vattr.va_size))) {
@@ -134,7 +133,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
*/
noff = (u_offset_t)off;
error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&noff),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY)
return (error);
@@ -143,7 +142,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
* "off" is not past the end of file
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
return (error);
if (noff >= (u_offset_t)vattr.va_size)
@@ -163,7 +162,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
*/
noff = (u_offset_t)off;
error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&noff),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY)
return (error);
@@ -172,7 +171,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
* the "virtual hole" at the end of the file.
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
return (error);
if (off < (offset_t)vattr.va_size)
@@ -194,7 +193,7 @@ lseek32_common(file_t *fp, int stype, offset_t off, offset_t max,
ASSERT((reg && noff <= max) || !reg);
newoff = (offset_t)noff;
- if ((error = VOP_SEEK(vp, curoff, &newoff)) == 0) {
+ if ((error = VOP_SEEK(vp, curoff, &newoff, NULL)) == 0) {
fp->f_offset = newoff;
(*retoff) = newoff;
return (0);
@@ -294,7 +293,7 @@ lseek64(int fdes, off_t off, int stype)
case SEEK_END:
vattr.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred)) != 0)
+ if ((error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL)) != 0)
goto lseek64error;
new_off += vattr.va_size;
break;
@@ -309,7 +308,7 @@ lseek64(int fdes, off_t off, int stype)
*/
new_off = (offset_t)off;
error = VOP_IOCTL(vp, _FIO_SEEK_DATA, (intptr_t)(&new_off),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY) {
goto lseek64error;
@@ -319,7 +318,7 @@ lseek64(int fdes, off_t off, int stype)
* is not past end of file
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
goto lseek64error;
if (new_off >= (offset_t)vattr.va_size) {
@@ -338,7 +337,7 @@ lseek64(int fdes, off_t off, int stype)
*/
new_off = off;
error = VOP_IOCTL(vp, _FIO_SEEK_HOLE, (intptr_t)(&new_off),
- FKIOCTL, kcred, NULL);
+ FKIOCTL, kcred, NULL, NULL);
if (error) {
if (error != ENOTTY)
goto lseek64error;
@@ -347,7 +346,7 @@ lseek64(int fdes, off_t off, int stype)
* the "virtual hole" at the end of the file.
*/
vattr.va_mask = AT_SIZE;
- error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred);
+ error = VOP_GETATTR(vp, &vattr, 0, fp->f_cred, NULL);
if (error)
goto lseek64error;
if (off < (offset_t)vattr.va_size) {
@@ -367,7 +366,7 @@ lseek64(int fdes, off_t off, int stype)
}
old_off = fp->f_offset;
- if ((error = VOP_SEEK(vp, old_off, &new_off)) == 0) {
+ if ((error = VOP_SEEK(vp, old_off, &new_off, NULL)) == 0) {
fp->f_offset = new_off;
releasef(fdes);
return (new_off);
diff --git a/usr/src/uts/common/syscall/open.c b/usr/src/uts/common/syscall/open.c
index f5b873bdb7..b45f7bf35b 100644
--- a/usr/src/uts/common/syscall/open.c
+++ b/usr/src/uts/common/syscall/open.c
@@ -49,6 +49,7 @@
#include <sys/uio.h>
#include <sys/debug.h>
#include <c2/audit.h>
+#include <sys/cmn_err.h>
/*
* Common code for open()/openat() and creat(). Check permissions, allocate
@@ -66,6 +67,8 @@ copen(int startfd, char *fname, int filemode, int createmode)
int fd, dupfd;
vnode_t *startvp;
proc_t *p = curproc;
+ uio_seg_t seg = UIO_USERSPACE;
+ char *open_filename = fname;
if (startfd == AT_FDCWD) {
/*
@@ -95,7 +98,31 @@ copen(int startfd, char *fname, int filemode, int createmode)
}
}
- if (filemode & FXATTR) {
+ /*
+ * Handle openattrdirat request
+ */
+ if (filemode & FXATTRDIROPEN) {
+#ifdef C2_AUDIT
+ if (audit_active)
+ audit_setfsat_path(1);
+#endif /* C2_AUDIT */
+
+ if (error = lookupnameat(fname, seg, FOLLOW,
+ NULLVPP, &vp, startvp))
+ return (set_errno(error));
+ if (startvp) {
+ VN_RELE(startvp);
+ startvp = NULL;
+ }
+
+ startvp = vp;
+ }
+
+ /*
+ * Do we need to go into extended attribute space?
+ */
+ if (filemode & (FXATTR|FXATTRDIROPEN)) {
+ vattr_t vattr;
/*
* Make sure we have a valid request.
@@ -111,7 +138,7 @@ copen(int startfd, char *fname, int filemode, int createmode)
goto out;
}
- if (startfd == AT_FDCWD) {
+ if (startfd == AT_FDCWD && !(filemode & FXATTRDIROPEN)) {
mutex_enter(&p->p_lock);
startvp = PTOU(p)->u_cdir;
VN_HOLD(startvp);
@@ -119,23 +146,34 @@ copen(int startfd, char *fname, int filemode, int createmode)
}
/*
- * Verify permission to put attributes on file
+ * In order to access hidden attribute directory the
+ * user must be able to stat() the file
*/
- if ((VOP_ACCESS(startvp, VREAD, 0, CRED()) != 0) &&
- (VOP_ACCESS(startvp, VWRITE, 0, CRED()) != 0) &&
- (VOP_ACCESS(startvp, VEXEC, 0, CRED()) != 0)) {
- error = EACCES;
+ vattr.va_mask = AT_ALL;
+ if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) {
pn_free(&pn);
goto out;
}
- if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0) {
+ if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 ||
+ vfs_has_feature(startvp->v_vfsp, VFSFT_XVATTR)) {
error = VOP_LOOKUP(startvp, "", &sdvp, &pn,
- LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED());
+ LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(),
+ NULL, NULL, NULL);
} else {
error = EINVAL;
}
+
+ /*
+ * For openattrdirat use "." as filename to open
+ * as part of vn_openat()
+ */
+ if (error == 0 && (filemode & FXATTRDIROPEN)) {
+ open_filename = ".";
+ seg = UIO_SYSSPACE;
+ }
+
pn_free(&pn);
if (error != 0)
goto out;
@@ -144,7 +182,7 @@ copen(int startfd, char *fname, int filemode, int createmode)
startvp = sdvp;
}
- if ((filemode & (FREAD|FWRITE)) != 0) {
+ if ((filemode & (FREAD|FWRITE|FXATTRDIROPEN)) != 0) {
if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
filemode &= ~FNDELAY;
error = falloc((vnode_t *)NULL, filemode, &fp, &fd);
@@ -157,9 +195,11 @@ copen(int startfd, char *fname, int filemode, int createmode)
* Last arg is a don't-care term if
* !(filemode & FCREAT).
*/
- error = vn_openat(fname, UIO_USERSPACE, filemode,
- (int)(createmode & MODEMASK), &vp, CRCREAT,
- PTOU(curproc)->u_cmask, startvp);
+
+ error = vn_openat(open_filename, seg, filemode,
+ (int)(createmode & MODEMASK),
+ &vp, CRCREAT, PTOU(curproc)->u_cmask,
+ startvp, fd);
if (startvp != NULL)
VN_RELE(startvp);
@@ -223,6 +263,7 @@ out:
#define OPENMODE32(fmode) ((int)((fmode)-FOPEN))
#define CREATMODE32 (FWRITE|FCREAT|FTRUNC)
#define OPENMODE64(fmode) (OPENMODE32(fmode) | FOFFMAX)
+#define OPENMODEATTRDIR FXATTRDIROPEN
#define CREATMODE64 (CREATMODE32 | FOFFMAX)
#ifdef _LP64
#define OPENMODE(fmode) OPENMODE64(fmode)
@@ -301,4 +342,14 @@ openat32(int fd, char *path, int fmode, int cmode)
{
return (copen(fd, path, OPENMODE32(fmode), cmode));
}
+
#endif /* _SYSCALL32_IMPL */
+
+/*
+ * Special interface to open hidden attribute directory.
+ */
+int
+openattrdirat(int fd, char *fname)
+{
+ return (copen(fd, fname, OPENMODEATTRDIR, 0));
+}
diff --git a/usr/src/uts/common/syscall/pathconf.c b/usr/src/uts/common/syscall/pathconf.c
index f6b38d4d84..5ef8ce1675 100644
--- a/usr/src/uts/common/syscall/pathconf.c
+++ b/usr/src/uts/common/syscall/pathconf.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,7 +59,7 @@ cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
switch (cmd) {
case _PC_2_SYMLINKS:
- if (error = VOP_PATHCONF(vp, _PC_SYMLINK_MAX, &val, cr))
+ if (error = VOP_PATHCONF(vp, _PC_SYMLINK_MAX, &val, cr, NULL))
return ((long)set_errno(error));
return ((long)(val > 0));
@@ -77,7 +77,7 @@ cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
return ((long)set_errno(EINVAL));
case _PC_SYNC_IO:
- if (!(error = VOP_FSYNC(vp, FSYNC, cr)))
+ if (!(error = VOP_FSYNC(vp, FSYNC, cr, NULL)))
return (1l);
return ((long)set_errno(error));
@@ -85,7 +85,7 @@ cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
return ((vp->v_vfsp->vfs_flag & VFS_XATTR) ? 1 : 0);
default:
- if (error = VOP_PATHCONF(vp, cmd, &val, cr))
+ if (error = VOP_PATHCONF(vp, cmd, &val, cr, NULL))
return ((long)set_errno(error));
return (val);
}
diff --git a/usr/src/uts/common/syscall/pipe.c b/usr/src/uts/common/syscall/pipe.c
index c980270a55..7721cd2764 100644
--- a/usr/src/uts/common/syscall/pipe.c
+++ b/usr/src/uts/common/syscall/pipe.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -142,7 +141,7 @@ pipe()
if (error = fifo_stropen(&vp2, FWRITE|FREAD, fp2->f_cred, 0, 0)) {
(void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0,
- fp1->f_cred);
+ fp1->f_cred, NULL);
goto out;
}
diff --git a/usr/src/uts/common/syscall/poll.c b/usr/src/uts/common/syscall/poll.c
index c5ab2b83e4..2fdac673b3 100644
--- a/usr/src/uts/common/syscall/poll.c
+++ b/usr/src/uts/common/syscall/poll.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1264,7 +1264,7 @@ pcache_insert(pollstate_t *ps, file_t *fp, pollfd_t *pollfdp, int *fdcntp,
*/
ASSERT(curthread->t_pollcache == NULL);
error = VOP_POLL(fp->f_vnode, pollfdp->events, 0, &pollfdp->revents,
- &memphp);
+ &memphp, NULL);
if (error) {
return (error);
}
@@ -1979,7 +1979,7 @@ retry:
*/
ASSERT(curthread->t_pollcache == NULL);
error = VOP_POLL(fp->f_vnode, pollfdp[entry].events, 0,
- &pollfdp[entry].revents, &php);
+ &pollfdp[entry].revents, &php, NULL);
/*
* releasef after completely done with this cached
* poll entry. To prevent close() coming in to clear
@@ -2804,7 +2804,7 @@ plist_chkdupfd(file_t *fp, polldat_t *pdp, pollstate_t *psp, pollfd_t *pollfdp,
ASSERT(curthread->t_pollcache == NULL);
error = VOP_POLL(fp->f_vnode,
pollfdp[i].events, 0,
- &pollfdp[i].revents, &php);
+ &pollfdp[i].revents, &php, NULL);
if (error) {
return (error);
}
diff --git a/usr/src/uts/common/syscall/readlink.c b/usr/src/uts/common/syscall/readlink.c
index aaeff14c0d..4c31e16d3f 100644
--- a/usr/src/uts/common/syscall/readlink.c
+++ b/usr/src/uts/common/syscall/readlink.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -77,7 +77,7 @@ lookup:
* object to look like a symlink at user-level.
*/
vattr.va_mask = AT_TYPE;
- error = VOP_GETATTR(vp, &vattr, 0, CRED());
+ error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL);
if (error || vattr.va_type != VLNK) {
VN_RELE(vp);
if ((error == ESTALE) &&
@@ -94,7 +94,7 @@ lookup:
auio.uio_segflg = UIO_USERSPACE;
auio.uio_extflg = UIO_COPY_CACHED;
auio.uio_resid = cnt;
- error = VOP_READLINK(vp, &auio, CRED());
+ error = VOP_READLINK(vp, &auio, CRED(), NULL);
VN_RELE(vp);
if (error) {
if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
diff --git a/usr/src/uts/common/syscall/rw.c b/usr/src/uts/common/syscall/rw.c
index 3eb98b50ac..f614761e33 100644
--- a/usr/src/uts/common/syscall/rw.c
+++ b/usr/src/uts/common/syscall/rw.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -115,7 +115,8 @@ read(int fdes, void *cbuf, size_t count)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fp->f_offset, cnt, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fp->f_offset, cnt, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -138,7 +139,7 @@ read(int fdes, void *cbuf, size_t count)
if (fileoff >= OFFSET_MAX(fp) && (vp->v_type == VREG)) {
struct vattr va;
va.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred))) {
+ if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) {
VOP_RWUNLOCK(vp, rwflag, NULL);
goto out;
}
@@ -250,7 +251,8 @@ write(int fdes, void *cbuf, size_t count)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, cnt, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, cnt, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -402,7 +404,8 @@ pread(int fdes, void *cbuf, size_t count, off_t offset)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -414,7 +417,7 @@ pread(int fdes, void *cbuf, size_t count, off_t offset)
if (vp->v_type == VREG && fileoff == (u_offset_t)maxoff) {
struct vattr va;
va.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred))) {
+ if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) {
VOP_RWUNLOCK(vp, rwflag, NULL);
goto out;
}
@@ -555,7 +558,8 @@ pwrite(int fdes, void *cbuf, size_t count, off_t offset)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -682,7 +686,8 @@ readv(int fdes, struct iovec *iovp, int iovcnt)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fp->f_offset, count, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fp->f_offset, count, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -698,7 +703,7 @@ readv(int fdes, struct iovec *iovp, int iovcnt)
if ((vp->v_type == VREG) && (fileoff >= OFFSET_MAX(fp))) {
struct vattr va;
va.va_mask = AT_SIZE;
- if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred))) {
+ if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) {
VOP_RWUNLOCK(vp, rwflag, NULL);
goto out;
}
@@ -839,7 +844,8 @@ writev(int fdes, struct iovec *iovp, int iovcnt)
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, count, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, count, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -980,7 +986,8 @@ pread64(int fdes, void *cbuf, size32_t count, uint32_t offset_1,
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
@@ -1112,7 +1119,8 @@ pwrite64(int fdes, void *cbuf, size32_t count, uint32_t offset_1,
error = nbl_svmand(vp, fp->f_cred, &svmand);
if (error != 0)
goto out;
- if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand)) {
+ if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand,
+ NULL)) {
error = EACCES;
goto out;
}
diff --git a/usr/src/uts/common/syscall/sendfile.c b/usr/src/uts/common/syscall/sendfile.c
index c9c14df59a..72c1e84465 100644
--- a/usr/src/uts/common/syscall/sendfile.c
+++ b/usr/src/uts/common/syscall/sendfile.c
@@ -916,7 +916,7 @@ sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv,
}
readvp = ffp->f_vnode;
- if (VOP_REALVP(readvp, &realvp) == 0)
+ if (VOP_REALVP(readvp, &realvp, NULL) == 0)
readvp = realvp;
if (readvp->v_type != VREG) {
releasef(sfv->sfv_fd);
diff --git a/usr/src/uts/common/syscall/stat.c b/usr/src/uts/common/syscall/stat.c
index 33403cf89e..c559747e2f 100644
--- a/usr/src/uts/common/syscall/stat.c
+++ b/usr/src/uts/common/syscall/stat.c
@@ -252,7 +252,7 @@ cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr)
int error;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if ((error = VOP_GETATTR(vp, &vattr, flag, cr)) != 0)
+ if ((error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) != 0)
return (error);
#ifdef _ILP32
/*
@@ -339,7 +339,6 @@ out:
*/
static int cstatat32(int, char *, int, struct stat32 *, int, int);
static int cstat32(vnode_t *, struct stat32 *, int, cred_t *);
-
int
stat32(char *fname, struct stat32 *sb)
{
@@ -401,7 +400,7 @@ cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr)
dev32_t st_dev, st_rdev;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, flag, cr))
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
return (error);
/* devices are a special case, see comments in cstat */
@@ -521,7 +520,7 @@ cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr)
int error;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, flag, cr))
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
return (error);
bzero(&lsb, sizeof (lsb));
@@ -627,7 +626,7 @@ cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr)
dev32_t st_dev, st_rdev;
vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
- if (error = VOP_GETATTR(vp, &vattr, flag, cr))
+ if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL))
return (error);
if (!cmpldev(&st_dev, vattr.va_fsid) ||
diff --git a/usr/src/uts/common/syscall/symlink.c b/usr/src/uts/common/syscall/symlink.c
index 915fc9d050..1db42e474e 100644
--- a/usr/src/uts/common/syscall/symlink.c
+++ b/usr/src/uts/common/syscall/symlink.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -83,7 +83,7 @@ top:
vattr.va_mode = 0777;
vattr.va_mask = AT_TYPE|AT_MODE;
error = VOP_SYMLINK(dvp, lpn.pn_path, &vattr,
- tbuf, CRED());
+ tbuf, CRED(), NULL, 0);
#ifdef C2_AUDIT
if (audit_active)
audit_symlink_create(dvp, lpn.pn_path,
diff --git a/usr/src/uts/common/syscall/ucredsys.c b/usr/src/uts/common/syscall/ucredsys.c
index 38d13884c7..0f5c0e6303 100644
--- a/usr/src/uts/common/syscall/ucredsys.c
+++ b/usr/src/uts/common/syscall/ucredsys.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -66,7 +66,7 @@ getpeerucred(int fd, void *buf)
case VFIFO:
case VSOCK:
err = VOP_IOCTL(vp, _I_GETPEERCRED, (intptr_t)&kpc,
- FKIOCTL, CRED(), &rval);
+ FKIOCTL, CRED(), &rval, NULL);
break;
case VCHR: {
struct strioctl strioc;
diff --git a/usr/src/uts/common/vm/seg_dev.c b/usr/src/uts/common/vm/seg_dev.c
index f24a1d46ed..02e2306703 100644
--- a/usr/src/uts/common/vm/seg_dev.c
+++ b/usr/src/uts/common/vm/seg_dev.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -422,7 +422,7 @@ segdev_create(struct seg *seg, void *argsp)
*/
error = VOP_ADDMAP(VTOCVP(sdp->vp), sdp->offset,
seg->s_as, seg->s_base, seg->s_size,
- sdp->prot, sdp->maxprot, sdp->type, CRED());
+ sdp->prot, sdp->maxprot, sdp->type, CRED(), NULL);
if (error != 0) {
sdp->devmap_data = NULL;
@@ -522,7 +522,7 @@ segdev_dup(struct seg *seg, struct seg *newseg)
return (VOP_ADDMAP(VTOCVP(newsdp->vp),
newsdp->offset, newseg->s_as,
newseg->s_base, newseg->s_size, newsdp->prot,
- newsdp->maxprot, sdp->type, CRED()));
+ newsdp->maxprot, sdp->type, CRED(), NULL));
}
/*
@@ -707,7 +707,7 @@ segdev_unmap(struct seg *seg, caddr_t addr, size_t len)
*/
ASSERT(sdp->vp != NULL);
(void) VOP_DELMAP(VTOCVP(sdp->vp), off, seg->s_as, addr, len,
- sdp->prot, sdp->maxprot, sdp->type, CRED());
+ sdp->prot, sdp->maxprot, sdp->type, CRED(), NULL);
/*
* Check for entire segment
@@ -2889,7 +2889,7 @@ devmap_get_large_pgsize(devmap_handle_t *dhp, size_t len, caddr_t addr,
*llen += pgsize;
off = ptob(pfn - dhp->dh_pfn) + pgsize;
}
- /* Large page mapping len/addr cover more range than orginal fault */
+ /* Large page mapping len/addr cover more range than original fault */
ASSERT(*llen >= len && *laddr <= addr);
ASSERT((*laddr + *llen) >= (addr + len));
}
@@ -3799,7 +3799,7 @@ devmap_alloc_pages(vmem_t *vmp, size_t size, int vmflag)
}
/*
- * This is where things are a bit incestrous with seg_kmem: unlike
+ * This is where things are a bit incestuous with seg_kmem: unlike
* seg_kp, seg_kmem does not keep its pages long-term sharelocked, so
* we need to do a bit of a dance around that to prevent duplication of
* code until we decide to bite the bullet and implement a new kernel
@@ -3851,7 +3851,7 @@ devmap_free_pages(vmem_t *vmp, void *inaddr, size_t size)
* default request. For now we allocate our own pages and we keep
* them long-term sharelocked, since: A) the fault routines expect the
* memory to already be locked; B) pageable umem is already long-term
- * locked; C) it's a lot of work to make it otherwise, particuarly
+ * locked; C) it's a lot of work to make it otherwise, particularly
* since the nexus layer expects the pages to never fault. An RFE is to
* not keep the pages long-term locked, but instead to be able to
* take faults on them and simply look them up in kvp in case we
diff --git a/usr/src/uts/common/vm/seg_kp.c b/usr/src/uts/common/vm/seg_kp.c
index d58e873a19..d65b3062bc 100644
--- a/usr/src/uts/common/vm/seg_kp.c
+++ b/usr/src/uts/common/vm/seg_kp.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -536,7 +536,7 @@ segkp_get_internal(
*/
err = VOP_GETPAGE(vp, (offset_t)off, PAGESIZE,
NULL, pl, PAGESIZE, seg, va, S_CREATE,
- kcred);
+ kcred, NULL);
if (err) {
/*
* XXX - This should not fail.
@@ -1129,7 +1129,7 @@ segkp_load(
* which is returned to us already kept.
*/
err = VOP_GETPAGE(vp, (offset_t)off, PAGESIZE, NULL,
- pl, PAGESIZE, seg, va, S_READ, kcred);
+ pl, PAGESIZE, seg, va, S_READ, kcred, NULL);
if (err) {
/*
@@ -1242,7 +1242,7 @@ segkp_unlock(
* use kcred.
*/
(void) VOP_PUTPAGE(vp, (offset_t)off, PAGESIZE,
- B_ASYNC | B_FREE, kcred);
+ B_ASYNC | B_FREE, kcred, NULL);
VN_RELE(vp);
} else {
page_unlock(pp);
diff --git a/usr/src/uts/common/vm/seg_map.c b/usr/src/uts/common/vm/seg_map.c
index de27f6e2ff..ad18a2cb31 100644
--- a/usr/src/uts/common/vm/seg_map.c
+++ b/usr/src/uts/common/vm/seg_map.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -707,7 +707,7 @@ segmap_fault(
TRACE_3(TR_FAC_VM, TR_SEGMAP_GETPAGE,
"segmap_getpage:seg %p addr %p vp %p", seg, addr, vp);
err = VOP_GETPAGE(vp, (offset_t)off, len, &prot, pl, MAXBSIZE,
- seg, addr, rw, CRED());
+ seg, addr, rw, CRED(), NULL);
if (err)
return (FC_MAKE_ERR(err));
@@ -829,7 +829,7 @@ segmap_faulta(struct seg *seg, caddr_t addr)
err = VOP_GETPAGE(vp, (offset_t)(off + ((offset_t)((uintptr_t)addr
& MAXBOFFSET))), PAGESIZE, (uint_t *)NULL, (page_t **)NULL, 0,
- seg, addr, S_READ, CRED());
+ seg, addr, S_READ, CRED(), NULL);
if (err)
return (FC_MAKE_ERR(err));
@@ -1369,7 +1369,7 @@ next_smap:
*/
/*
- * Create pages (without using VOP_GETPAGE) and load up tranlations to them.
+ * Create pages (without using VOP_GETPAGE) and load up translations to them.
* If softlock is TRUE, then set things up so that it looks like a call
* to segmap_fault with F_SOFTLOCK.
*
@@ -1455,7 +1455,7 @@ segmap_pagecreate(struct seg *seg, caddr_t addr, size_t len, int softlock)
* "exclusive" lock will not be dropped to prevent
* other users from accessing the page. We also
* have to lock the translation to prevent a fault
- * from occuring when the virtual address mapped by
+ * from occurring when the virtual address mapped by
* this page is written into. This is necessary to
* avoid a deadlock since we haven't dropped the
* "exclusive" lock.
@@ -1898,7 +1898,7 @@ vrfy_smp:
base = segkpm_create_va(baseoff);
error = VOP_GETPAGE(vp, (offset_t)baseoff, len, &prot, pl, MAXBSIZE,
- seg, base, rw, CRED());
+ seg, base, rw, CRED(), NULL);
pp = pl[0];
if (error || pp == NULL) {
@@ -2010,7 +2010,7 @@ segmap_release(struct seg *seg, caddr_t addr, uint_t flags)
smtx = SMAPMTX(smp);
/*
- * For compatibilty reasons segmap_pagecreate_kpm sets this
+ * For compatibility reasons segmap_pagecreate_kpm sets this
* flag to allow a following segmap_pagecreate to return
* this as "newpage" flag. When segmap_pagecreate is not
* called at all we clear it now.
@@ -2117,7 +2117,7 @@ segmap_release(struct seg *seg, caddr_t addr, uint_t flags)
*/
if ((flags & ~SM_DONTNEED) != 0) {
error = VOP_PUTPAGE(vp, offset, MAXBSIZE,
- bflags, CRED());
+ bflags, CRED(), NULL);
} else {
error = 0;
}
diff --git a/usr/src/uts/common/vm/seg_vn.c b/usr/src/uts/common/vm/seg_vn.c
index b7fe798061..e3f67cf336 100644
--- a/usr/src/uts/common/vm/seg_vn.c
+++ b/usr/src/uts/common/vm/seg_vn.c
@@ -466,7 +466,7 @@ segvn_setvnode_mpss(vnode_t *vp)
if (vp->v_mpssdata == NULL) {
if (vn_vmpss_usepageio(vp)) {
err = VOP_PAGEIO(vp, (page_t *)NULL,
- (u_offset_t)0, 0, 0, CRED());
+ (u_offset_t)0, 0, 0, CRED(), NULL);
} else {
err = ENOSYS;
}
@@ -594,7 +594,7 @@ segvn_create(struct seg *seg, void *argsp)
if (a->vp != NULL) {
error = VOP_ADDMAP(a->vp, a->offset & PAGEMASK,
seg->s_as, seg->s_base, seg->s_size, a->prot,
- a->maxprot, a->type, cred);
+ a->maxprot, a->type, cred, NULL);
if (error) {
if (swresv != 0) {
anon_unresv(swresv);
@@ -1614,7 +1614,7 @@ retry:
if (newsvd->vp != NULL) {
error = VOP_ADDMAP(newsvd->vp, (offset_t)newsvd->offset,
newseg->s_as, newseg->s_base, newseg->s_size, newsvd->prot,
- newsvd->maxprot, newsvd->type, newsvd->cred);
+ newsvd->maxprot, newsvd->type, newsvd->cred, NULL);
}
out:
if (error == 0 && HAT_IS_REGION_COOKIE_VALID(svd->rcookie)) {
@@ -1771,7 +1771,7 @@ retry:
error = VOP_DELMAP(svd->vp,
(offset_t)svd->offset + (uintptr_t)(addr - seg->s_base),
seg->s_as, addr, len, svd->prot, svd->maxprot,
- svd->type, svd->cred);
+ svd->type, svd->cred, NULL);
if (error == EAGAIN)
return (error);
@@ -2265,7 +2265,7 @@ ulong_t segvn_lpglck_limit = 0;
* Support routines used by segvn_pagelock() and softlock faults for anonymous
* pages to implement availrmem accounting in a way that makes sure the
* same memory is accounted just once for all softlock/pagelock purposes.
- * This prevents a bug when availrmem is quickly incorrectly exausted from
+ * This prevents a bug when availrmem is quickly incorrectly exhausted from
* several pagelocks to different parts of the same large page since each
* pagelock has to decrement availrmem by the size of the entire large
* page. Note those pages are not COW shared until softunlock/pageunlock so
@@ -2274,7 +2274,7 @@ ulong_t segvn_lpglck_limit = 0;
* entire large page because large anon pages can't be demoted when any of
* constituent pages is locked. The caller calls this routine for every page_t
* it locks. The very first page in the range may not be the root page of a
- * large page. For all other pages it's guranteed we are going to visit the
+ * large page. For all other pages it's guaranteed we are going to visit the
* root of a particular large page before any other constituent page as we are
* locking sequential pages belonging to the same anon map. So we do all the
* locking when the root is encountered except for the very first page. Since
@@ -3255,9 +3255,9 @@ segvn_full_szcpages(page_t **ppa, uint_t szc, int *upgrdfail, uint_t *pszc)
* page_size(szc)) range and for private segment return them in ppa array.
* Pages are created either via IO or relocations.
*
- * Return 1 on sucess and 0 on failure.
+ * Return 1 on success and 0 on failure.
*
- * If physically contiguos pages already exist for this range return 1 without
+ * If physically contiguous pages already exist for this range return 1 without
* filling ppa array. Caller initializes ppa[0] as NULL to detect that ppa
* array wasn't filled. In this case caller fills ppa array via VOP_GETPAGE().
*/
@@ -3394,7 +3394,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
* XXX fix NFS to remove this check.
*/
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred, NULL)) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[6]);
page_unlock(targpp);
goto out;
@@ -3407,7 +3407,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
goto out;
}
io_err = VOP_PAGEIO(vp, io_pplist, io_off, io_len,
- B_READ, svd->cred);
+ B_READ, svd->cred, NULL);
if (io_err) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[8]);
page_unlock(targpp);
@@ -3464,7 +3464,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
VM_STAT_ADD(segvnvmstats.fill_vp_pages[12]);
io_len = eoff - io_off;
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, ATTR_HINT, svd->cred, NULL) != 0) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[13]);
goto out;
}
@@ -3475,7 +3475,7 @@ segvn_fill_vp_pages(struct segvn_data *svd, vnode_t *vp, u_offset_t off,
goto out;
}
io_err = VOP_PAGEIO(vp, io_pplist, io_off, io_len,
- B_READ, svd->cred);
+ B_READ, svd->cred, NULL);
if (io_err) {
VM_STAT_ADD(segvnvmstats.fill_vp_pages[15]);
if (io_err == EDEADLK) {
@@ -3966,7 +3966,7 @@ segvn_fault_vnodepages(struct hat *hat, struct seg *seg, caddr_t lpgaddr,
ppa[0] = NULL;
ierr = VOP_GETPAGE(vp, (offset_t)off, pgsz,
&vpprot, ppa, pgsz, seg, a, arw,
- svd->cred);
+ svd->cred, NULL);
#ifdef DEBUG
if (ierr == 0) {
for (i = 0; i < pages; i++) {
@@ -4003,7 +4003,7 @@ segvn_fault_vnodepages(struct hat *hat, struct seg *seg, caddr_t lpgaddr,
goto out;
}
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vp, &va, 0, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, 0, svd->cred, NULL)) {
SEGVN_VMSTAT_FLTVNPAGES(20);
err = FC_MAKE_ERR(EIO);
goto out;
@@ -5313,7 +5313,7 @@ slow:
(void) VOP_PUTPAGE(fvp,
(offset_t)fpgoff, PAGESIZE,
(B_DONTNEED|B_FREE|B_ASYNC),
- svd->cred);
+ svd->cred, NULL);
VN_RELE(fvp);
} else {
/*
@@ -5429,7 +5429,7 @@ slow:
seg, addr, vp);
err = VOP_GETPAGE(vp, (offset_t)vp_off, vp_len,
&vpprot, plp, plsz, seg, addr + (vp_off - off), arw,
- svd->cred);
+ svd->cred, NULL);
if (err) {
SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
segvn_pagelist_rele(plp);
@@ -5661,7 +5661,7 @@ segvn_faulta(struct seg *seg, caddr_t addr)
err = VOP_GETPAGE(vp,
(offset_t)(svd->offset + (uintptr_t)(addr - seg->s_base)),
PAGESIZE, NULL, NULL, 0, seg, addr,
- S_OTHER, svd->cred);
+ S_OTHER, svd->cred, NULL);
SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
if (err)
@@ -5745,7 +5745,7 @@ segvn_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
/*
* If we are holding the as lock as a reader then
* we need to return IE_RETRY and let the as
- * layer drop and re-aquire the lock as a writer.
+ * layer drop and re-acquire the lock as a writer.
*/
if (AS_READ_HELD(seg->s_as, &seg->s_as->a_lock))
return (IE_RETRY);
@@ -6207,7 +6207,7 @@ segvn_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
va.va_mask = AT_SIZE;
eoffpage += seg->s_size;
eoffpage = btopr(eoffpage);
- if (VOP_GETATTR(svd->vp, &va, 0, svd->cred) != 0) {
+ if (VOP_GETATTR(svd->vp, &va, 0, svd->cred, NULL) != 0) {
segvn_setpgsz_getattr_err++;
return (EINVAL);
}
@@ -6451,7 +6451,7 @@ segvn_claim_pages(
}
/*
- * Returns right (upper address) segment if split occured.
+ * Returns right (upper address) segment if split occurred.
* If the address is equal to the beginning or end of its segment it returns
* the current segment.
*/
@@ -6920,7 +6920,7 @@ segvn_kluster(struct seg *seg, caddr_t addr, ssize_t delta)
swap_xlate(oap, &vp2, &off2);
- if (!VOP_CMP(vp1, vp2) || off1 - off2 != delta)
+ if (!VOP_CMP(vp1, vp2, NULL) || off1 - off2 != delta)
return (-1);
return (0);
}
@@ -7194,7 +7194,7 @@ segvn_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
* is not on, just use one big request.
*/
err = VOP_PUTPAGE(svd->vp, (offset_t)offset, len,
- bflags, svd->cred);
+ bflags, svd->cred, NULL);
SEGVN_LOCK_EXIT(seg->s_as, &svd->lock);
return (err);
}
@@ -7270,7 +7270,7 @@ segvn_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
}
} else if (svd->type == MAP_SHARED && amp != NULL) {
/*
- * Avoid writting out to disk ISM's large pages
+ * Avoid writing out to disk ISM's large pages
* because segspt_free_pages() relies on NULL an_pvp
* of anon slots of such pages.
*/
@@ -7303,7 +7303,7 @@ segvn_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
*/
VN_HOLD(vp);
err = VOP_PUTPAGE(vp, (offset_t)off, PAGESIZE,
- bflags, svd->cred);
+ bflags, svd->cred, NULL);
VN_RELE(vp);
if (err)
break;
@@ -7734,7 +7734,7 @@ segvn_lockop(struct seg *seg, caddr_t addr, size_t len,
error = VOP_GETPAGE(vp, (offset_t)off, PAGESIZE,
(uint_t *)NULL, pl, PAGESIZE, seg, addr,
- S_OTHER, svd->cred);
+ S_OTHER, svd->cred, NULL);
/*
* If the error is EDEADLK then we must bounce
@@ -7759,7 +7759,7 @@ segvn_lockop(struct seg *seg, caddr_t addr, size_t len,
if (error && svd->vp) {
va.va_mask = AT_SIZE;
if (VOP_GETATTR(svd->vp, &va, 0,
- svd->cred) != 0) {
+ svd->cred, NULL) != 0) {
err = EIO;
goto out;
}
@@ -9007,7 +9007,7 @@ segvn_textrepl(struct seg *seg)
* If VOP_GETATTR() call fails bail out.
*/
va.va_mask = AT_SIZE | AT_MTIME | AT_CTIME;
- if (VOP_GETATTR(vp, &va, 0, svd->cred) != 0) {
+ if (VOP_GETATTR(vp, &va, 0, svd->cred, NULL) != 0) {
svd->tr_state = SEGVN_TR_OFF;
SEGVN_TR_ADDSTAT(gaerr);
return;
@@ -9337,7 +9337,7 @@ done:
}
/*
- * This is called when a MAP_SHARED writabble mapping is created to a vnode
+ * This is called when a MAP_SHARED writable mapping is created to a vnode
* that is currently used for execution (VVMEXEC flag is set). In this case we
* need to prevent further use of existing replicas.
*/
diff --git a/usr/src/uts/common/vm/vm_anon.c b/usr/src/uts/common/vm/vm_anon.c
index 58b505f0a6..10f6ccafa1 100644
--- a/usr/src/uts/common/vm/vm_anon.c
+++ b/usr/src/uts/common/vm/vm_anon.c
@@ -1418,7 +1418,8 @@ anon_fill_cow_holes(
page_t *pp;
err = VOP_GETPAGE(vp, vp_off, PAGESIZE, NULL,
- pl, PAGESIZE, seg, addr, S_READ, cred);
+ pl, PAGESIZE, seg, addr, S_READ, cred,
+ NULL);
if (err) {
break;
}
@@ -1770,7 +1771,7 @@ anon_getpage(
seg, addr, vp);
err = VOP_GETPAGE(vp, (u_offset_t)off, PAGESIZE, protp, pl, plsz,
- seg, addr, rw, cred);
+ seg, addr, rw, cred, NULL);
if (err == 0 && pl != NULL) {
ahm = &anonhash_lock[AH_LOCK(ap->an_vp, ap->an_off)];
@@ -1787,8 +1788,8 @@ anon_getpage(
* page cannot be allocated. returns -2 if some other process has allocated a
* larger page.
*
- * For cowfault it will alocate any size pages to fill the requested area to
- * avoid partially overwritting anon slots (i.e. sharing only some of the anon
+ * For cowfault it will allocate any size pages to fill the requested area to
+ * avoid partially overwriting anon slots (i.e. sharing only some of the anon
* slots within a large page with other processes). This policy greatly
* simplifies large page freeing (which is only freed when all anon slot
* refcnts are 0).
@@ -2271,7 +2272,7 @@ anon_private(
* vnode at the same time.
*/
err = VOP_GETPAGE(vp, (u_offset_t)off, PAGESIZE, NULL,
- anon_pl, PAGESIZE, seg, addr, S_CREATE, cred);
+ anon_pl, PAGESIZE, seg, addr, S_CREATE, cred, NULL);
if (err)
goto out;
@@ -2640,7 +2641,7 @@ anon_zero(struct seg *seg, caddr_t addr, struct anon **app, struct cred *cred)
* the vnode at the same time since it is locked.
*/
err = VOP_GETPAGE(vp, off, PAGESIZE, NULL,
- anon_pl, PAGESIZE, seg, addr, S_CREATE, cred);
+ anon_pl, PAGESIZE, seg, addr, S_CREATE, cred, NULL);
if (err) {
*app = NULL;
anon_decref(ap);
@@ -3109,7 +3110,7 @@ top:
* have at most one reference at this point. This means underlying pages can
* be exclusively locked and demoted or freed. If not freeing the entire
* large pages demote the ends of the region we free to be able to free
- * subpages. Page roots correspend to aligned index positions in anon map.
+ * subpages. Page roots correspond to aligned index positions in anon map.
*/
void
anon_shmap_free_pages(struct anon_map *amp, ulong_t sidx, size_t len)
@@ -3216,7 +3217,7 @@ anonmap_free(struct anon_map *amp)
/*
* Returns true if the app array has some empty slots.
- * The offp and lenp paramters are in/out paramters. On entry
+ * The offp and lenp parameters are in/out parameters. On entry
* these values represent the starting offset and length of the
* mapping. When true is returned, these values may be modified
* to be the largest range which includes empty slots.
@@ -3272,7 +3273,7 @@ anon_pages(struct anon_hdr *ahp, ulong_t anon_index, pgcnt_t nslots)
/*
* Move reserved phys swap into memory swap (unreserve phys swap
* and reserve mem swap by the same amount).
- * Used by segspt when it needs to lock resrved swap npages in memory
+ * Used by segspt when it needs to lock reserved swap npages in memory
*/
int
anon_swap_adjust(pgcnt_t npages)
diff --git a/usr/src/uts/common/vm/vm_as.c b/usr/src/uts/common/vm/vm_as.c
index d7ed7da8ec..86d7bc982f 100644
--- a/usr/src/uts/common/vm/vm_as.c
+++ b/usr/src/uts/common/vm/vm_as.c
@@ -1160,7 +1160,7 @@ setprot_top:
/*
* Normally we only lock the as as a reader. But
* if due to setprot the segment driver needs to split
- * a segment it will return IE_RETRY. Therefore we re-aquire
+ * a segment it will return IE_RETRY. Therefore we re-acquire
* the as lock as a writer so the segment driver can change
* the seg list. Also the segment driver will return IE_RETRY
* after it has changed the segment list so we therefore keep
@@ -1602,7 +1602,7 @@ again:
}
va.va_mask = AT_SIZE;
- if (VOP_GETATTR(vn_a->vp, &va, ATTR_HINT, vn_a->cred) != 0) {
+ if (VOP_GETATTR(vn_a->vp, &va, ATTR_HINT, vn_a->cred, NULL) != 0) {
szcvec = 0;
goto again;
}
diff --git a/usr/src/uts/common/vm/vm_page.c b/usr/src/uts/common/vm/vm_page.c
index c725b13f17..bb1adbe42a 100644
--- a/usr/src/uts/common/vm/vm_page.c
+++ b/usr/src/uts/common/vm/vm_page.c
@@ -109,11 +109,11 @@ pgcnt_t availrmem_initial;
* segvn_pages_locked : This keeps track on a global basis how many pages
* are currently locked because of I/O.
*
- * pages_locked : How many pages are locked becuase of user specified
+ * pages_locked : How many pages are locked because of user specified
* locking through mlock or plock.
*
* pages_useclaim,pages_claimed : These two variables track the
- * cliam adjustments because of the protection changes on a segvn segment.
+ * claim adjustments because of the protection changes on a segvn segment.
*
* All these globals are protected by the same lock which protects availrmem.
*/
@@ -503,7 +503,7 @@ page_free_large_ctr(pgcnt_t npages)
}
/*
- * Add a physical chunk of memory to the system freee lists during startup.
+ * Add a physical chunk of memory to the system free lists during startup.
* Platform specific startup() allocates the memory for the page structs.
*
* num - number of page structures
@@ -670,7 +670,7 @@ page_lookup(vnode_t *vp, u_offset_t off, se_t se)
* Find a page representing the specified [vp, offset].
* We either return the one we found or, if passed in,
* create one with identity of [vp, offset] of the
- * pre-allocated page. If we find exsisting page but it is
+ * pre-allocated page. If we find existing page but it is
* intransit coming in, it will have an "exclusive" lock
* and we wait for the i/o to complete. A page found on
* the free list is always reclaimed and then locked.
@@ -1466,7 +1466,7 @@ page_create_throttle(pgcnt_t npages, int flags)
}
/*
- * page_create_wait() is called to either coalecse pages from the
+ * page_create_wait() is called to either coalesce pages from the
* different pcf buckets or to wait because there simply are not
* enough pages to satisfy the caller's request.
*
@@ -2410,7 +2410,7 @@ page_create_va(vnode_t *vp, u_offset_t off, size_t bytes, uint_t flags,
if (!enough) {
/*
* Have to look harder. If npages is greater than
- * one, then we might have to coalecse the counters.
+ * one, then we might have to coalesce the counters.
*
* Go wait. We come back having accounted
* for the memory.
@@ -4394,7 +4394,7 @@ page_busy(int cleanit)
VN_HOLD(vp);
page_unlock(pp);
(void) VOP_PUTPAGE(vp, off, PAGESIZE,
- B_ASYNC | B_FREE, kcred);
+ B_ASYNC | B_FREE, kcred, NULL);
VN_RELE(vp);
}
} while ((pp = page_next(pp)) != page0);
@@ -4527,7 +4527,7 @@ top:
* if this putpage fails.
*/
(void) VOP_PUTPAGE(vp, offset, PAGESIZE, B_INVAL,
- kcred);
+ kcred, NULL);
VN_RELE(vp);
} else {
page_destroy(pp, 0);
@@ -4542,7 +4542,7 @@ top:
/*
* Replace the page "old" with the page "new" on the page hash and vnode lists
*
- * the replacemnt must be done in place, ie the equivalent sequence:
+ * the replacement must be done in place, ie the equivalent sequence:
*
* vp = old->p_vnode;
* off = old->p_offset;
@@ -4690,7 +4690,7 @@ page_relocate_hash(page_t *pp_new, page_t *pp_old)
*
* Returns 1 on success, 0 on failure.
*
- * If success is returned this routine gurantees p_szc for all constituent
+ * If success is returned this routine guarantees p_szc for all constituent
* pages of a large page pp belongs to can't change. To achieve this we
* recheck szc of pp after locking all constituent pages and retry if szc
* changed (it could only decrease). Since hat_page_demote() needs an EXCL
@@ -4698,7 +4698,7 @@ page_relocate_hash(page_t *pp_new, page_t *pp_old)
* pages are locked. hat_page_demote() with a lock on a constituent page
* outside of this large page (i.e. pp belonged to a larger large page) is
* already done with all constituent pages of pp since the root's p_szc is
- * changed last. Thefore no need to synchronize with hat_page_demote() that
+ * changed last. Therefore no need to synchronize with hat_page_demote() that
* locked a constituent page outside of pp's current large page.
*/
#ifdef DEBUG
@@ -5335,7 +5335,7 @@ page_try_demote_pages(page_t *pp)
* cache). However file system pages can be truncated or invalidated at a
* PAGESIZE level from the file system side and end up in page_free() or
* page_destroy() (we also allow only part of the large page to be SOFTLOCKed
- * and therfore pageout should be able to demote a large page by EXCL locking
+ * and therefore pageout should be able to demote a large page by EXCL locking
* any constituent page that is not under SOFTLOCK). In those cases we cannot
* rely on being able to lock EXCL all constituent pages.
*
@@ -5354,9 +5354,9 @@ page_try_demote_pages(page_t *pp)
*
* This routine calls page_szc_lock() before calling hat_page_demote() to
* allow segvn in one special case not to lock all constituent pages SHARED
- * before calling hat_memload_array() that relies on p_szc not changeing even
+ * before calling hat_memload_array() that relies on p_szc not changing even
* before hat level mlist lock is taken. In that case segvn uses
- * page_szc_lock() to prevent hat_page_demote() changeing p_szc values.
+ * page_szc_lock() to prevent hat_page_demote() changing p_szc values.
*
* Anonymous or kernel page demotion still has to lock all pages exclusively
* and do hat_pageunload() on all constituent pages before demoting the page
@@ -5371,7 +5371,7 @@ page_try_demote_pages(page_t *pp)
* pages within szc 1 area to prevent szc changes because hat_page_demote()
* that started on this page when it had szc > 1 is done for this szc 1 area.
*
- * We are guranteed that all constituent pages of pp's large page belong to
+ * We are guaranteed that all constituent pages of pp's large page belong to
* the same vnode with the consecutive offsets increasing in the direction of
* the pfn i.e. the identity of constituent pages can't change until their
* p_szc is decreased. Therefore it's safe for hat_page_demote() to remove
@@ -5443,7 +5443,7 @@ page_mark_migrate(struct seg *seg, caddr_t addr, size_t len,
len = P2ROUNDUP(len, segpgsz);
/*
- * Allocate page array to accomodate largest page size
+ * Allocate page array to accommodate largest page size
*/
pgsz = page_get_pagesize(page_num_pagesizes() - 1);
ppa_nentries = btop(pgsz);
diff --git a/usr/src/uts/common/vm/vm_rm.c b/usr/src/uts/common/vm/vm_rm.c
index 36cd5f0375..eb920214f7 100644
--- a/usr/src/uts/common/vm/vm_rm.c
+++ b/usr/src/uts/common/vm/vm_rm.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -118,7 +117,8 @@ rm_assize(struct as *as)
if (seg->s_ops == &segvn_ops &&
SEGOP_GETVP(seg, addr, &vp) == 0 &&
vp != NULL && vp->v_type == VREG &&
- VOP_GETATTR(vp, &vattr, ATTR_HINT, CRED()) == 0) {
+ VOP_GETATTR(vp, &vattr, ATTR_HINT,
+ CRED(), NULL) == 0) {
u_offset_t filesize = vattr.va_size;
u_offset_t offset = SEGOP_GETOFFSET(seg, addr);
diff --git a/usr/src/uts/common/vm/vm_swap.c b/usr/src/uts/common/vm/vm_swap.c
index d7028b6f29..d39c85f069 100644
--- a/usr/src/uts/common/vm/vm_swap.c
+++ b/usr/src/uts/common/vm/vm_swap.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -653,7 +652,7 @@ lout:
if (vp->v_vfsp && vn_is_readonly(vp))
error = EROFS;
else
- error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED());
+ error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL);
break;
case VDIR:
@@ -858,7 +857,7 @@ lout:
if (vp->v_vfsp && vn_is_readonly(vp))
error = EROFS;
else
- error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED());
+ error = VOP_ACCESS(vp, VREAD|VWRITE, 0, CRED(), NULL);
break;
case VDIR:
@@ -918,7 +917,7 @@ swapadd(struct vnode *vp, ulong_t lowblk, ulong_t nblks, char *swapname)
mutex_exit(&cvp->v_lock);
mutex_enter(&swap_lock);
- if (error = VOP_OPEN(&cvp, FREAD|FWRITE, CRED())) {
+ if (error = VOP_OPEN(&cvp, FREAD|FWRITE, CRED(), NULL)) {
mutex_exit(&swap_lock);
/* restore state of v_flag */
if (!wasswap) {
@@ -939,7 +938,7 @@ swapadd(struct vnode *vp, ulong_t lowblk, ulong_t nblks, char *swapname)
* on a machine with a different size swap partition.
*/
vattr.va_mask = AT_SIZE;
- if (error = VOP_GETATTR(cvp, &vattr, ATTR_COMM, CRED()))
+ if (error = VOP_GETATTR(cvp, &vattr, ATTR_COMM, CRED(), NULL))
goto out;
/*
@@ -973,7 +972,8 @@ swapadd(struct vnode *vp, ulong_t lowblk, ulong_t nblks, char *swapname)
goto out;
/* Fail if fs does not support VOP_PAGEIO */
- error = VOP_PAGEIO(cvp, (page_t *)NULL, (u_offset_t)0, 0, 0, CRED());
+ error = VOP_PAGEIO(cvp, (page_t *)NULL, (u_offset_t)0, 0, 0, CRED(),
+ NULL);
if (error == ENOSYS)
goto out;
@@ -1165,7 +1165,8 @@ out:
kmem_free(nsip, sizeof (*nsip));
}
mutex_enter(&swap_lock);
- (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED(),
+ NULL);
mutex_exit(&swap_lock);
}
return (error);
@@ -1361,7 +1362,7 @@ top:
/* Release the vnode */
mutex_enter(&swap_lock);
- (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED());
+ (void) VOP_CLOSE(cvp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
mutex_enter(&cvp->v_lock);
cvp->v_flag &= ~VISSWAP;
mutex_exit(&cvp->v_lock);
@@ -1391,7 +1392,7 @@ swapslot_free(
* Users of the physical slot will synchronize on the i/o lock.
*/
if (error = VOP_GETPAGE(vp, (offset_t)off, ptob(1), NULL,
- pl, ptob(1), segkmap, NULL, S_READ, CRED())) {
+ pl, ptob(1), segkmap, NULL, S_READ, CRED(), NULL)) {
/*
* Anon slot went away (EIDRM) or vp was truncated (EFAULT)
* while we got the page. Thus the physical slot must be
diff --git a/usr/src/uts/common/vm/vpm.c b/usr/src/uts/common/vm/vpm.c
index 935680d600..5cb72b628f 100644
--- a/usr/src/uts/common/vm/vpm.c
+++ b/usr/src/uts/common/vm/vpm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -237,7 +237,7 @@ vpm_init()
* Use prefetch as we have to walk thru a large number of
* these data structures. We just use the smap's prefetch
* routine as it does the same. This should work fine
- * for x64(this needs to be modifed when enabled on sparc).
+ * for x64(this needs to be modified when enabled on sparc).
*/
prefetch_smap_w((void *)vpm);
@@ -866,7 +866,7 @@ vpm_map_pages(
base = segkpm_create_va(baseoff);
error = VOP_GETPAGE(vp, baseoff, len, &prot, &pplist[i],
- len, segkmap, base, rw, CRED());
+ len, segkmap, base, rw, CRED(), NULL);
if (error) {
VPM_DEBUG(vpmd_getpagefailed);
pplist[i] = NULL;
@@ -1070,7 +1070,7 @@ vpm_sync_pages(struct vnode *vp,
if (flags & SM_DONTNEED)
bflags |= B_DONTNEED;
- error = VOP_PUTPAGE(vp, off, psize, bflags, CRED());
+ error = VOP_PUTPAGE(vp, off, psize, bflags, CRED(), NULL);
}
return (error);