2 Unix SMB/CIFS implementation.
3 Wrap VxFS calls in vfs functions.
4 This module is for ACL and XATTR handling.
6 Copyright (C) Symantec Corporation <www.symantec.com> 2014
7 Copyright (C) Veritas Technologies LLC <www.veritas.com> 2016
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "smbd/smbd.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26 #include "../libcli/security/security.h"
27 #include "../librpc/gen_ndr/ndr_security.h"
28 #include "system/filesys.h"
32 #define DBGC_CLASS DBGC_VFS
34 #define MODULE_NAME "vxfs"
37 * WARNING !! WARNING !!
39 * DO NOT CHANGE THIS FROM "system." space to
40 * "user." space unless you are shipping a product
41 * that RESTRICTS access to extended attributes
42 * to smbd-only. "system." space is restricted
43 * to root access only, "user." space is available
46 * If this is changed to "user." and access
47 * to extended attributes is available via
48 * local processes or other remote file system
49 * (e.g. NFS) then the security of the system
50 * WILL BE COMPROMISED. i.e. non-root users
51 * WILL be able to overwrite Samba ACLs on
54 * If you need to modify this define, do
55 * so using CFLAGS on your build command
57 * e.g. CFLAGS=-DXATTR_USER_NTACL="user.NTACL"
59 * Added by: <jra@samba.org> 17 Sept. 2014.
63 #ifndef XATTR_USER_NTACL
64 #define XATTR_USER_NTACL "system.NTACL"
68 #define VXFS_ACL_UNDEFINED_TYPE 0
69 #define VXFS_ACL_USER_OBJ 1
70 #define VXFS_ACL_GROUP_OBJ 2
71 #define VXFS_ACL_USER 3
72 #define VXFS_ACL_GROUP 4
73 #define VXFS_ACL_OTHER 5
74 #define VXFS_ACL_MASK 6
79 * This will compare two ace entries for sorting
80 * each entry contains: type, perms and id
81 * Sort by type first, if type is same sort by id.
83 static int vxfs_ace_cmp(const void *ace1
, const void *ace2
)
86 uint16_t type_a1
, type_a2
;
87 uint32_t id_a1
, id_a2
;
89 /* Type must be compared first */
90 type_a1
= SVAL(ace1
, 0);
91 type_a2
= SVAL(ace2
, 0);
93 ret
= (type_a1
- type_a2
);
95 /* Compare ID under type */
96 /* skip perm thus take offset as 4*/
97 id_a1
= IVAL(ace1
, 4);
98 id_a2
= IVAL(ace2
, 4);
105 static void vxfs_print_ace_buf(char *buf
, int count
) {
111 DEBUG(10, ("vfs_vxfs: Printing aces:\n"));
112 for (i
= 0; i
< count
; i
++) {
113 type
= SVAL(buf
, offset
);
115 perm
= SVAL(buf
, offset
);
117 id
= IVAL(buf
, offset
);
120 DEBUG(10, ("vfs_vxfs: type = %u, perm = %u, id = %u\n",
121 (unsigned int)type
, (unsigned int)perm
,
127 * Sort aces so that comparing 2 ACLs will be straight forward.
128 * This function will fill buffer as follows:
130 * 1. ace->a_type will be filled as first 2 bytes in buf.
131 * 2. ace->a_perm will be filled as next 2 bytes.
132 * 3. ace->xid will be filled as next 4 bytes.
133 * Thus each ace entry in buf is equal to 8 bytes.
134 * Also a_type is mapped to VXFS_ACL_* so that ordering aces
137 static char * vxfs_sort_acl(SMB_ACL_T theacl
, TALLOC_CTX
*mem_ctx
,
141 struct smb_acl_entry
*smb_ace
;
148 count
= theacl
->count
;
150 buf
= talloc_zero_size(mem_ctx
, count
* 8);
155 smb_ace
= theacl
->acl
;
157 for (i
= 0; i
< count
; i
++) {
159 /* Map type to SMB_ACL_* to VXFS_ACL_* */
160 switch(smb_ace
->a_type
) {
162 type
= VXFS_ACL_USER
;
164 case SMB_ACL_USER_OBJ
:
165 type
= VXFS_ACL_USER_OBJ
;
168 type
= VXFS_ACL_GROUP
;
170 case SMB_ACL_GROUP_OBJ
:
171 type
= VXFS_ACL_GROUP_OBJ
;
174 type
= VXFS_ACL_OTHER
;
177 type
= VXFS_ACL_MASK
;
188 * We get owner uid and owner group gid in o_uid and o_gid
189 * Put these ids instead of -1
191 switch(smb_ace
->a_type
) {
193 id
= smb_ace
->info
.user
.uid
;
196 id
= smb_ace
->info
.group
.gid
;
198 case SMB_ACL_USER_OBJ
:
201 case SMB_ACL_GROUP_OBJ
:
215 perm
= smb_ace
->a_perm
& 0xff;
217 /* TYPE is the first 2 bytes of an entry */
218 SSVAL(buf
, offset
, type
);
221 /* PERM is the next 2 bytes of an entry */
222 SSVAL(buf
, offset
, perm
);
225 /* ID is the last 4 bytes of an entry */
226 SIVAL(buf
, offset
, id
);
232 qsort(buf
, count
, 8, vxfs_ace_cmp
);
234 DEBUG(10, ("vfs_vxfs: Print sorted aces:\n"));
235 vxfs_print_ace_buf(buf
, count
);
240 /* This function gets e_buf as an arg which is sorted and created out of
241 * existing ACL. This function will compact this e_buf to c_buf where USER
242 * and GROUP aces matching with USER_OBJ and GROUP_OBJ will be merged
244 * This is similar to what posix_acls.c does. This will make sure existing
245 * acls are converted much similar to what posix_acls calculates.
248 static char * vxfs_compact_buf(char *e_buf
, int *new_count
, int count
,
251 int i
, e_offset
= 0, c_offset
= 0;
252 uint16_t type
, perm
, o_perm
;
253 uint32_t id
, owner_id
, group_id
;
261 c_buf
= talloc_zero_size(mem_ctx
, count
* 8);
266 /*Copy first two enries from e_buf to c_buf
267 *These are USER_OBJ and GROUP_OBJ
270 memcpy(c_buf
, e_buf
, 16);
274 owner_id
= IVAL(e_buf
, 4);
275 group_id
= IVAL(e_buf
, 12);
277 c_offset
= e_offset
= 16;
279 /* Start comparing other entries */
280 for (i
= 2; i
< count
; i
++) {
282 type
= SVAL(e_buf
, e_offset
);
284 perm
= SVAL(e_buf
, e_offset
);
286 id
= IVAL(e_buf
, e_offset
);
291 if (id
== owner_id
) {
292 o_perm
= SVAL(c_buf
, 2);
294 SSVAL(c_buf
, 2, o_perm
);
295 DEBUG(10, ("vfs_vxfs: merging with owner"
298 "e_id = %u\n", (unsigned int)type
,
305 if (id
== group_id
) {
306 o_perm
= SVAL(c_buf
, 10);
308 SSVAL(c_buf
, 10, o_perm
);
309 DEBUG(10, ("vfs_vxfs: merging with owner group"
312 "e_id = %u\n", (unsigned int)type
,
320 SSVAL(c_buf
, c_offset
, type
);
323 SSVAL(c_buf
, c_offset
, perm
);
326 SIVAL(c_buf
, c_offset
, id
);
331 DEBUG(10, ("vfs_vxfs: new_count is %d\n", *new_count
));
335 /* Actually compare New ACL and existing ACL buf */
336 static bool vxfs_compare_acls(char *e_buf
, char *n_buf
, int n_count
,
339 uint16_t e_type
, n_type
, e_perm
, n_perm
;
343 if (!e_buf
&& !n_buf
) {
344 DEBUG(10, ("vfs_vxfs: Empty buffers!\n"));
348 if ((e_count
< 2) || (n_count
< 2)) {
351 /*Get type from last entry from both buffers.
352 * It may or may not be ACL_MASK
354 n_type
= SVAL(n_buf
, offset
+ (8 * (n_count
-1)));
355 e_type
= SVAL(e_buf
, offset
+ (8 * (e_count
-1)));
357 /* Check for ACL_MASK entry properly. Handle all 4 cases*/
359 /* If ACL_MASK entry is present in any of the buffers,
360 * it will be always the last one. Calculate count to compare
361 * based on if ACL_MASK is present on new and existing ACL
363 if ((n_type
!= VXFS_ACL_MASK
) && (e_type
== VXFS_ACL_MASK
)){
364 DEBUG(10, ("vfs_vxfs: New ACL does not have mask entry,"
365 "reduce count by 1 and compare\n"));
366 e_count
= e_count
-1;
368 if ((n_type
== VXFS_ACL_MASK
) && (e_type
!= VXFS_ACL_MASK
)){
369 DEBUG(10, ("vfs_vxfs: new ACL to be set contains mask"
370 "existing ACL does not have mask entry\n"
371 "Need to set New ACL\n"));
375 if (memcmp(e_buf
, n_buf
, (e_count
* 8)) != 0) {
376 DEBUG(10, ("vfs_vxfs: Compare with memcmp,"
377 "buffers not same!\n"));
384 /* In VxFS, POSIX ACLs are pointed by separate inode for each file/dir.
385 * However, files/dir share same POSIX ACL inode if ACLs are inherited
387 * To retain this behaviour, below function avoids ACL set call if
388 * underlying ACLs are already same and thus saves creating extra inode.
390 * This function will execute following steps:
391 * 1. Get existing ACL
392 * 2. Sort New ACL and existing ACL into buffers
393 * 3. Compact existing ACL buf
394 * 4. Finally compare New ACL buf and Compact buf
395 * 5. If same, return true
396 * 6. Else need to set New ACL
399 static bool vxfs_compare(connection_struct
*conn
, char *name
, SMB_ACL_T the_acl
,
400 SMB_ACL_TYPE_T the_acl_type
)
402 SMB_ACL_T existing_acl
= NULL
;
405 TALLOC_CTX
*mem_ctx
= talloc_tos();
406 char *existing_buf
= NULL
, *new_buf
= NULL
, *compact_buf
= NULL
;
407 struct smb_filename
*smb_fname
= NULL
;
410 DEBUG(10, ("vfs_vxfs: Getting existing ACL for %s\n", name
));
412 smb_fname
= synthetic_smb_fname(mem_ctx
, name
, NULL
, NULL
, 0);
413 if (smb_fname
== NULL
) {
414 DEBUG(10, ("vfs_vxfs: Failed to create smb_fname\n"));
418 existing_acl
= SMB_VFS_SYS_ACL_GET_FILE(conn
, smb_fname
, the_acl_type
,
420 if (existing_acl
== NULL
) {
421 DEBUG(10, ("vfs_vxfs: Failed to get ACL\n"));
425 DEBUG(10, ("vfs_vxfs: Existing ACL count=%d\n", existing_acl
->count
));
426 DEBUG(10, ("vfs_vxfs: New ACL count=%d\n", the_acl
->count
));
428 if (existing_acl
->count
== 0) {
429 DEBUG(10, ("vfs_vxfs: ACL count is 0, Need to set\n"));
433 status
= SMB_VFS_STAT(conn
, smb_fname
);
435 DEBUG(10, ("vfs_vxfs: stat failed!\n"));
439 DEBUG(10, ("vfs_vxfs: Sorting existing ACL\n"));
440 existing_buf
= vxfs_sort_acl(existing_acl
, mem_ctx
,
441 smb_fname
->st
.st_ex_uid
,
442 smb_fname
->st
.st_ex_gid
);
446 DEBUG(10, ("vfs_vxfs: Sorting new ACL\n"));
447 new_buf
= vxfs_sort_acl(the_acl
, mem_ctx
, smb_fname
->st
.st_ex_uid
,
448 smb_fname
->st
.st_ex_gid
);
453 DEBUG(10, ("vfs_vxfs: Compact existing buf\n"));
454 compact_buf
= vxfs_compact_buf(existing_buf
, &count
,
461 vxfs_print_ace_buf(compact_buf
, count
);
463 /* COmpare ACLs only if count is same or mismatch by 1 */
464 if ((count
== the_acl
->count
) ||
465 (count
== the_acl
->count
+ 1) ||
466 (count
+1 == the_acl
->count
)) {
468 if (vxfs_compare_acls(compact_buf
, new_buf
, the_acl
->count
,
470 DEBUG(10, ("vfs_vxfs: ACLs matched. Not setting.\n"));
474 DEBUG(10, ("vfs_vxfs: ACLs NOT matched. Setting\n"));
476 DEBUG(10, ("vfs_vxfs: ACLs count does not match. Setting\n"));
481 TALLOC_FREE(existing_acl
);
482 TALLOC_FREE(smb_fname
);
483 TALLOC_FREE(existing_buf
);
484 TALLOC_FREE(compact_buf
);
485 TALLOC_FREE(new_buf
);
490 static int vxfs_sys_acl_set_fd(vfs_handle_struct
*handle
, files_struct
*fsp
,
494 if (vxfs_compare(fsp
->conn
, fsp
->fsp_name
->base_name
, theacl
,
495 SMB_ACL_TYPE_ACCESS
)) {
499 return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle
, fsp
, theacl
);
502 static int vxfs_sys_acl_set_file(vfs_handle_struct
*handle
,
503 const struct smb_filename
*smb_fname
,
504 SMB_ACL_TYPE_T acltype
,
507 if (vxfs_compare(handle
->conn
, (char *)smb_fname
->base_name
,
512 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle
, smb_fname
,
516 static int vxfs_set_xattr(struct vfs_handle_struct
*handle
,
517 const struct smb_filename
*smb_fname_in
,
523 struct smb_filename
*smb_fname
= NULL
;
528 DEBUG(10, ("In vxfs_set_xattr\n"));
530 smb_fname
= cp_smb_filename_nostream(talloc_tos(), smb_fname_in
);
531 if (smb_fname
== NULL
) {
536 if (SMB_VFS_NEXT_STAT(handle
, smb_fname
) != 0) {
537 TALLOC_FREE(smb_fname
);
541 is_dir
= S_ISDIR(smb_fname
->st
.st_ex_mode
);
543 ret
= vxfs_setxattr_path(smb_fname_in
->base_name
, name
, value
, size
,
546 ((ret
== -1) && (errno
!= ENOTSUP
) && (errno
!= ENOSYS
))) {
548 * Now remve old style xattr if it exists
550 SMB_VFS_NEXT_REMOVEXATTR(handle
, smb_fname
, name
);
552 * Do not bother about return value
560 DEBUG(10, ("Fallback to xattr\n"));
561 if (strcmp(name
, XATTR_NTACL_NAME
) == 0) {
562 ret
= SMB_VFS_NEXT_SETXATTR(handle
, smb_fname
,
572 /* Clients can't set XATTR_USER_NTACL directly. */
573 if (strcasecmp(name
, XATTR_USER_NTACL
) == 0) {
574 saved_errno
= EACCES
;
579 ret
= SMB_VFS_NEXT_SETXATTR(handle
, smb_fname
,
580 name
, value
, size
, flags
);
587 TALLOC_FREE(smb_fname
);
588 if (saved_errno
!= 0) {
594 static int vxfs_fset_xattr(struct vfs_handle_struct
*handle
,
595 struct files_struct
*fsp
, const char *name
,
596 const void *value
, size_t size
, int flags
){
599 DEBUG(10, ("In vxfs_fset_xattr\n"));
601 ret
= vxfs_setxattr_fd(fsp
->fh
->fd
, name
, value
, size
, flags
);
603 ((ret
== -1) && (errno
!= ENOTSUP
) && (errno
!= ENOSYS
))) {
604 SMB_VFS_NEXT_FREMOVEXATTR(handle
, fsp
, name
);
608 DEBUG(10, ("Fallback to xattr"));
609 if (strcmp(name
, XATTR_NTACL_NAME
) == 0) {
610 return SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, XATTR_USER_NTACL
,
614 /* Clients can't set XATTR_USER_NTACL directly. */
615 if (strcasecmp(name
, XATTR_USER_NTACL
) == 0) {
620 return SMB_VFS_NEXT_FSETXATTR(handle
, fsp
, name
, value
, size
, flags
);
623 static ssize_t
vxfs_get_xattr(struct vfs_handle_struct
*handle
,
624 const struct smb_filename
*smb_fname
,
630 DEBUG(10, ("In vxfs_get_xattr\n"));
631 ret
= vxfs_getxattr_path(smb_fname
->base_name
, name
, value
, size
);
632 if ((ret
!= -1) || ((errno
!= ENOTSUP
) &&
633 (errno
!= ENOSYS
) && (errno
!= ENODATA
))) {
637 DEBUG(10, ("Fallback to xattr\n"));
638 if (strcmp(name
, XATTR_NTACL_NAME
) == 0) {
639 return SMB_VFS_NEXT_GETXATTR(handle
, smb_fname
,
640 XATTR_USER_NTACL
, value
, size
);
643 /* Clients can't see XATTR_USER_NTACL directly. */
644 if (strcasecmp(name
, XATTR_USER_NTACL
) == 0) {
649 return SMB_VFS_NEXT_GETXATTR(handle
, smb_fname
, name
, value
, size
);
652 static ssize_t
vxfs_fget_xattr(struct vfs_handle_struct
*handle
,
653 struct files_struct
*fsp
, const char *name
,
654 void *value
, size_t size
){
657 DEBUG(10, ("In vxfs_fget_xattr\n"));
659 ret
= vxfs_getxattr_fd(fsp
->fh
->fd
, name
, value
, size
);
660 if ((ret
!= -1) || ((errno
!= ENOTSUP
) &&
661 (errno
!= ENOSYS
) && (errno
!= ENODATA
))) {
665 DEBUG(10, ("Fallback to xattr\n"));
666 if (strcmp(name
, XATTR_NTACL_NAME
) == 0) {
667 return SMB_VFS_NEXT_FGETXATTR(handle
, fsp
, XATTR_USER_NTACL
,
671 /* Clients can't see XATTR_USER_NTACL directly. */
672 if (strcasecmp(name
, XATTR_USER_NTACL
) == 0) {
677 return SMB_VFS_NEXT_FGETXATTR(handle
, fsp
, name
, value
, size
);
680 static int vxfs_remove_xattr(struct vfs_handle_struct
*handle
,
681 const struct smb_filename
*smb_fname_in
,
685 int ret
= 0, ret_new
= 0, old_errno
;
686 struct smb_filename
*smb_fname
= NULL
;
688 DEBUG(10, ("In vxfs_remove_xattr\n"));
690 smb_fname
= cp_smb_filename_nostream(talloc_tos(), smb_fname_in
);
691 if (smb_fname
== NULL
) {
696 /* Remove with old way */
697 if (strcmp(name
, XATTR_NTACL_NAME
) == 0) {
698 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
, smb_fname
,
701 if (strcasecmp(name
, XATTR_USER_NTACL
) != 0) {
702 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
, smb_fname
,
706 /* Remove with new way */
709 if (SMB_VFS_NEXT_STAT(handle
, smb_fname
) != 0) {
710 TALLOC_FREE(smb_fname
);
714 is_dir
= S_ISDIR(smb_fname
->st
.st_ex_mode
);
715 TALLOC_FREE(smb_fname
);
717 * If both fail, return failuer else return whichever succeeded
719 ret_new
= vxfs_removexattr_path(smb_fname_in
->base_name
, name
, is_dir
);
720 if (errno
== ENOTSUP
|| errno
== ENOSYS
) {
723 if ((ret_new
!= -1) && (ret
== -1)) {
731 static int vxfs_fremove_xattr(struct vfs_handle_struct
*handle
,
732 struct files_struct
*fsp
, const char *name
){
733 int ret
= 0, ret_new
= 0, old_errno
;
735 DEBUG(10, ("In vxfs_fremove_xattr\n"));
737 /* Remove with old way */
738 if (strcmp(name
, XATTR_NTACL_NAME
) == 0) {
739 ret
= SMB_VFS_NEXT_FREMOVEXATTR(handle
, fsp
,
742 /* Clients can't remove XATTR_USER_NTACL directly. */
743 if (strcasecmp(name
, XATTR_USER_NTACL
) != 0) {
744 ret
= SMB_VFS_NEXT_FREMOVEXATTR(handle
, fsp
,
750 /* Remove with new way */
751 ret_new
= vxfs_removexattr_fd(fsp
->fh
->fd
, name
);
753 * If both fail, return failuer else return whichever succeeded
755 if (errno
== ENOTSUP
|| errno
== ENOSYS
) {
758 if ((ret_new
!= -1) && (ret
== -1)) {
766 static size_t vxfs_filter_list(char *list
, size_t size
)
770 while (str
- list
< size
) {
771 size_t element_len
= strlen(str
) + 1;
772 if (strcasecmp(str
, XATTR_USER_NTACL
) == 0) {
775 size
- (str
- list
) - element_len
);
784 static ssize_t
vxfs_listxattr(vfs_handle_struct
*handle
,
785 const struct smb_filename
*smb_fname
,
791 result
= vxfs_listxattr_path(smb_fname
->base_name
, list
, size
);
792 if (result
>= 0 || ((errno
!= ENOTSUP
) && (errno
!= ENOSYS
))) {
796 result
= SMB_VFS_NEXT_LISTXATTR(handle
, smb_fname
, list
, size
);
802 /* Remove any XATTR_USER_NTACL elements from the returned list. */
803 result
= vxfs_filter_list(list
, result
);
808 static ssize_t
vxfs_flistxattr(struct vfs_handle_struct
*handle
,
809 struct files_struct
*fsp
, char *list
,
814 result
= vxfs_listxattr_fd(fsp
->fh
->fd
, list
, size
);
815 if (result
>= 0 || ((errno
!= ENOTSUP
) && (errno
!= ENOSYS
))) {
819 result
= SMB_VFS_NEXT_FLISTXATTR(handle
, fsp
, list
, size
);
825 /* Remove any XATTR_USER_NTACL elements from the returned list. */
826 result
= vxfs_filter_list(list
, result
);
831 static NTSTATUS
vxfs_set_ea_dos_attributes(struct vfs_handle_struct
*handle
,
832 const struct smb_filename
*smb_fname
,
837 bool attrset
= false;
840 DBG_DEBUG("Entered function\n");
842 is_dir
= S_ISDIR(smb_fname
->st
.st_ex_mode
);
843 if (!(dosmode
& FILE_ATTRIBUTE_READONLY
)) {
844 ret
= vxfs_checkwxattr_path(smb_fname
->base_name
);
846 DBG_DEBUG("ret:%d\n", ret
);
847 if ((errno
!= EOPNOTSUPP
) && (errno
!= ENOENT
)) {
848 return map_nt_error_from_unix(errno
);
852 if (dosmode
& FILE_ATTRIBUTE_READONLY
) {
853 ret
= vxfs_setwxattr_path(smb_fname
->base_name
, is_dir
);
854 DBG_DEBUG("ret:%d\n", ret
);
856 if ((errno
!= EOPNOTSUPP
) && (errno
!= EINVAL
)) {
857 return map_nt_error_from_unix(errno
);
863 err
= SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle
, smb_fname
, dosmode
);
864 if (!NT_STATUS_IS_OK(err
)) {
866 ret
= vxfs_clearwxattr_path(smb_fname
->base_name
, is_dir
);
867 DBG_DEBUG("ret:%d\n", ret
);
868 if ((ret
== -1) && (errno
!= ENOENT
)) {
869 return map_nt_error_from_unix(errno
);
877 static NTSTATUS
vxfs_fset_ea_dos_attributes(struct vfs_handle_struct
*handle
,
878 struct files_struct
*fsp
,
883 bool attrset
= false;
885 DBG_DEBUG("Entered function\n");
887 if (!(dosmode
& FILE_ATTRIBUTE_READONLY
)) {
888 ret
= vxfs_checkwxattr_fd(fsp
->fh
->fd
);
890 DBG_DEBUG("ret:%d\n", ret
);
891 if ((errno
!= EOPNOTSUPP
) && (errno
!= ENOENT
)) {
892 return map_nt_error_from_unix(errno
);
896 if (dosmode
& FILE_ATTRIBUTE_READONLY
) {
897 ret
= vxfs_setwxattr_fd(fsp
->fh
->fd
);
898 DBG_DEBUG("ret:%d\n", ret
);
900 if ((errno
!= EOPNOTSUPP
) && (errno
!= EINVAL
)) {
901 return map_nt_error_from_unix(errno
);
907 err
= SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle
, fsp
, dosmode
);
908 if (!NT_STATUS_IS_OK(err
)) {
910 ret
= vxfs_clearwxattr_fd(fsp
->fh
->fd
);
911 DBG_DEBUG("ret:%d\n", ret
);
912 if ((ret
== -1) && (errno
!= ENOENT
)) {
913 return map_nt_error_from_unix(errno
);
920 static int vfs_vxfs_connect(struct vfs_handle_struct
*handle
,
921 const char *service
, const char *user
)
926 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
936 static struct vfs_fn_pointers vfs_vxfs_fns
= {
937 .connect_fn
= vfs_vxfs_connect
,
939 #ifdef VXFS_ACL_SHARE
940 .sys_acl_set_file_fn
= vxfs_sys_acl_set_file
,
941 .sys_acl_set_fd_fn
= vxfs_sys_acl_set_fd
,
944 .set_dos_attributes_fn
= vxfs_set_ea_dos_attributes
,
945 .fset_dos_attributes_fn
= vxfs_fset_ea_dos_attributes
,
946 .getxattr_fn
= vxfs_get_xattr
,
947 .getxattrat_send_fn
= vfs_not_implemented_getxattrat_send
,
948 .getxattrat_recv_fn
= vfs_not_implemented_getxattrat_recv
,
949 .fgetxattr_fn
= vxfs_fget_xattr
,
950 .listxattr_fn
= vxfs_listxattr
,
951 .flistxattr_fn
= vxfs_flistxattr
,
952 .removexattr_fn
= vxfs_remove_xattr
,
953 .fremovexattr_fn
= vxfs_fremove_xattr
,
954 .setxattr_fn
= vxfs_set_xattr
,
955 .fsetxattr_fn
= vxfs_fset_xattr
,
959 NTSTATUS
vfs_vxfs_init(TALLOC_CTX
*ctx
)
961 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "vxfs",