Shadow copy API - Original work by "Ken Cross" <kcross@nssolutions.com>, adapted
authorJeremy Allison <jra@samba.org>
Thu, 7 Aug 2003 21:47:46 +0000 (21:47 +0000)
committerJeremy Allison <jra@samba.org>
Thu, 7 Aug 2003 21:47:46 +0000 (21:47 +0000)
into a patch by "Stefan (metze) Metzmacher" <metze@metzemix.de>.
Jeremy.

source/include/ntioctl.h
source/include/smb_macros.h
source/include/vfs.h
source/include/vfs_macros.h
source/smbd/nttrans.c
source/smbd/vfs-wrap.c
source/smbd/vfs.c

index 17791fde18f13b8ba2353106bf7783dad73ce462..9814c88e5e5c3741f47b43bd158a6b3b6dfb00fb 100644 (file)
@@ -23,6 +23,8 @@
   we only need the sparse flag
 */
 
+#ifndef _NTIOCTL_H
+#define _NTIOCTL_H
 
 /* IOCTL information */
 /* List of ioctl function codes that look to be of interest to remote clients like this. */
@@ -53,6 +55,8 @@
 #define FSCTL_SIS_COPYFILE           0x00090100
 #define FSCTL_SIS_LINK_FILES         0x0009C104
 
+#define FSCTL_GET_SHADOW_COPY_DATA   0x00144064   /* KJC -- Shadow Copy information */
+
 #if 0
 #define FSCTL_SECURITY_ID_CHECK
 #define FSCTL_DISMOUNT_VOLUME
 #define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
 #define IO_REPARSE_TAG_HSM           0xC0000004
 #define IO_REPARSE_TAG_SIS           0x80000007
+
+
+/* For FSCTL_GET_SHADOW_COPY_DATA ...*/
+typedef char SHADOW_COPY_LABEL[25];
+
+typedef struct shadow_copy_data {
+       TALLOC_CTX *mem_ctx;
+       /* Total number of shadow volumes currently mounted */
+       uint32 num_volumes;
+       /* Concatenated list of labels */
+       SHADOW_COPY_LABEL *labels;
+} SHADOW_COPY_DATA;
+
+
+#endif /* _NTIOCTL_H */
index 21ccdf295c4554ffb0f0e9a687d7fe0fe88d7aba..178fd9c3580923851da2e53a157f56cdbd293394 100644 (file)
 #define OPEN_CONN(conn)    ((conn) && (conn)->open)
 #define IS_IPC(conn)       ((conn) && (conn)->ipc)
 #define IS_PRINT(conn)       ((conn) && (conn)->printer)
+#define FSP_BELONGS_CONN(fsp,conn) do {\
+                       extern struct current_user current_user;\
+                       if (!((fsp) && (conn) && ((conn)==(fsp)->conn) && (current_user.vuid==(fsp)->vuid))) \
+                               return(ERROR_DOS(ERRDOS,ERRbadfid));\
+                       } while(0)
+
 #define FNUM_OK(fsp,c) (OPEN_FSP(fsp) && (c)==(fsp)->conn && current_user.vuid==(fsp)->vuid)
 
 #define CHECK_FSP(fsp,conn) do {\
index 452f4dc23b94c35b78b74c0a33a59cbbfcb53233..dd489702aa9a5d62b2f1532e52f1f02128b8a45e 100644 (file)
@@ -50,8 +50,8 @@
 /* Changed to version 6 for the new module system, fixed cascading and quota functions. --metze */
 /* Changed to version 7 to include the get_nt_acl info parameter. JRA. */
 /* Changed to version 8 includes EA calls. JRA. */
-
-#define SMB_VFS_INTERFACE_VERSION 8
+/* Changed to version 9 to include the get_shadow_data call. --metze */
+#define SMB_VFS_INTERFACE_VERSION 9
 
 
 /* to bug old modules witch are trying to compile with the old functions */
@@ -91,6 +91,8 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_DISK_FREE,
        SMB_VFS_OP_GET_QUOTA,
        SMB_VFS_OP_SET_QUOTA,
+       SMB_VFS_OP_GET_SHADOW_COPY_DATA,
+
 
        /* Directory operations */
 
@@ -196,6 +198,7 @@ struct vfs_ops {
                        SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
                int (*get_quota)(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
                int (*set_quota)(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
+               int (*get_shadow_copy_data)(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels);
                
                /* Directory operations */
                
@@ -293,6 +296,7 @@ struct vfs_ops {
                struct vfs_handle_struct *disk_free;
                struct vfs_handle_struct *get_quota;
                struct vfs_handle_struct *set_quota;
+               struct vfs_handle_struct *get_shadow_copy_data;
 
                /* Directory operations */
 
@@ -379,6 +383,7 @@ struct vfs_ops {
                struct vfs_handle_struct *setxattr;
                struct vfs_handle_struct *lsetxattr;
                struct vfs_handle_struct *fsetxattr;
+
        } handles;
 };
 
index fdbc1516e310cce0dca9e04c658c95a7f763f9bf..c4f63c352e4c335679029c19d937d8fb995eea9b 100644 (file)
@@ -33,6 +33,7 @@
 #define SMB_VFS_DISK_FREE(conn, path, small_query, bsize, dfree ,dsize) ((conn)->vfs.ops.disk_free((conn)->vfs.handles.disk_free, (conn), (path), (small_query), (bsize), (dfree), (dsize)))
 #define SMB_VFS_GET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.get_quota((conn)->vfs.handles.get_quota, (conn), (qtype), (id), (qt)))
 #define SMB_VFS_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.set_quota((conn)->vfs.handles.set_quota, (conn), (qtype), (id), (qt)))
+#define SMB_VFS_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs.ops.get_shadow_copy_data((fsp)->conn->vfs.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
 
 /* Directory operations */
 #define SMB_VFS_OPENDIR(conn, fname) ((conn)->vfs.ops.opendir((conn)->vfs.handles.opendir, (conn), (fname)))
 #define SMB_VFS_OPAQUE_DISK_FREE(conn, path, small_query, bsize, dfree ,dsize) ((conn)->vfs_opaque.ops.disk_free((conn)->vfs_opaque.handles.disk_free, (conn), (path), (small_query), (bsize), (dfree), (dsize)))
 #define SMB_VFS_OPAQUE_GET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.get_quota((conn)->vfs_opaque.handles.get_quota, (conn), (qtype), (id), (qt)))
 #define SMB_VFS_OPAQUE_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.set_quota((conn)->vfs_opaque.handles.set_quota, (conn), (qtype), (id), (qt)))
+#define SMB_VFS_OPAQUE_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs_opaque.ops.get_shadow_copy_data((fsp)->conn->vfs_opaque.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
 
 /* Directory operations */
 #define SMB_VFS_OPAQUE_OPENDIR(conn, fname) ((conn)->vfs_opaque.ops.opendir((conn)->vfs_opaque.handles.opendir, (conn), (fname)))
 #define SMB_VFS_NEXT_DISK_FREE(handle, conn, path, small_query, bsize, dfree ,dsize) ((handle)->vfs_next.ops.disk_free((handle)->vfs_next.handles.disk_free, (conn), (path), (small_query), (bsize), (dfree), (dsize)))
 #define SMB_VFS_NEXT_GET_QUOTA(handle, conn, qtype, id, qt) ((handle)->vfs_next.ops.get_quota((handle)->vfs_next.handles.get_quota, (conn), (qtype), (id), (qt)))
 #define SMB_VFS_NEXT_SET_QUOTA(handle, conn, qtype, id, qt) ((handle)->vfs_next.ops.set_quota((handle)->vfs_next.handles.set_quota, (conn), (qtype), (id), (qt)))
+#define SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data ,labels) ((handle)->vfs_next.ops.get_shadow_copy_data((handle)->vfs_next.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
 
 /* Directory operations */
 #define SMB_VFS_NEXT_OPENDIR(handle, conn, fname) ((handle)->vfs_next.ops.opendir((handle)->vfs_next.handles.opendir, (conn), (fname)))
index 3ffa6efa77a693a0f4829d3aa8ad6878c244b750..7a58e838772e98bc9886a1fb3099824f6b46e437 100644 (file)
@@ -1724,7 +1724,11 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                                  char **ppparams, uint32 parameter_count,
                                  char **ppdata, uint32 data_count)
 {
-       unsigned fnum, control;
+       uint32 function;
+       uint16 fidnum;
+       files_struct *fsp;
+       uint8 isFSctl;
+       uint8 compfilter;
        static BOOL logged_message;
        char *pdata = *ppdata;
 
@@ -1733,19 +1737,26 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
        }
 
-       fnum = SVAL(*ppsetup, 4);
-       control = IVAL(*ppsetup, 0);
+       function = IVAL(*ppsetup, 0);
+       fidnum = SVAL(*ppsetup, 4);
+       isFSctl = CVAL(*ppsetup, 6);
+       compfilter = CVAL(*ppsetup, 7);
+
+       DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n", 
+                function, fidnum, isFSctl, compfilter));
 
-       DEBUG(10,("call_nt_transact_ioctl: fnum=%d control=0x%08x\n", 
-                fnum, control));
+       fsp=file_fsp(*ppsetup, 4);
+       /* this check is done in each implemented function case for now
+          because I don't want to break anything... --metze
+       FSP_BELONGS_CONN(fsp,conn);*/
 
-       switch (control) {
+       switch (function) {
        case FSCTL_SET_SPARSE:
                /* pretend this succeeded - tho strictly we should
                   mark the file sparse (if the local fs supports it)
                   so we can know if we need to pre-allocate or not */
 
-               DEBUG(10,("FSCTL_SET_SPARSE: fnum=%d control=0x%08x\n",fnum,control));
+               DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum));
                send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
                return -1;
        
@@ -1754,7 +1765,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                   but works ok like this --metze
                 */
 
-               DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control));
+               DEBUG(10,("FSCTL_0x000900C0: called on FID[0x%04X](but not implemented)\n",fidnum));
                send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
                return -1;
 
@@ -1763,7 +1774,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 * --metze
                 */
 
-               DEBUG(10,("FSCTL_GET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control));
+               DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
                send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0);
                return -1;
 
@@ -1772,10 +1783,125 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 * --metze
                 */
 
-               DEBUG(10,("FSCTL_SET_REPARSE_POINT: fnum=%d control=0x%08x\n",fnum,control));
+               DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
                send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0);
                return -1;
                        
+       case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/
+       {
+               /*
+                * This is called to retrieve the number of Shadow Copies (a.k.a. snapshots)
+                * and return their volume names.  If max_data_count is 16, then it is just
+                * asking for the number of volumes and length of the combined names.
+                *
+                * pdata is the data allocated by our caller, but that uses
+                * total_data_count (which is 0 in our case) rather than max_data_count.
+                * Allocate the correct amount and return the pointer to let
+                * it be deallocated when we return.
+                */
+               uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
+               SHADOW_COPY_DATA *shadow_data = NULL;
+               TALLOC_CTX *shadow_mem_ctx = NULL;
+               BOOL labels = False;
+               uint32 labels_data_count = 0;
+               uint32 i;
+               char *cur_pdata;
+
+               FSP_BELONGS_CONN(fsp,conn);
+
+               if (max_data_count < 16) {
+                       DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
+                               max_data_count));
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               if (max_data_count > 16) {
+                       labels = True;
+               }
+
+               shadow_mem_ctx = talloc_init("SHADOW_COPY_DATA");
+               if (shadow_mem_ctx == NULL) {
+                       DEBUG(0,("talloc_init(SHADOW_COPY_DATA) failed!\n"));
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+
+               shadow_data = (SHADOW_COPY_DATA *)talloc_zero(shadow_mem_ctx,sizeof(SHADOW_COPY_DATA));
+               if (shadow_data == NULL) {
+                       DEBUG(0,("talloc_zero() failed!\n"));
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+               
+               shadow_data->mem_ctx = shadow_mem_ctx;
+               
+               /*
+                * Call the VFS routine to actually do the work.
+                */
+               if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
+                       talloc_destroy(shadow_data->mem_ctx);
+                       if (errno == ENOSYS) {
+                               DEBUG(5,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, not supported.\n", 
+                                       conn->connectpath));
+                               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+                       } else {
+                               DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: connectpath %s, failed.\n", 
+                                       conn->connectpath));
+                               return ERROR_NT(NT_STATUS_UNSUCCESSFUL);                        
+                       }
+               }
+
+               labels_data_count = (shadow_data->num_volumes*2*sizeof(SHADOW_COPY_LABEL))+2;
+
+               if (!labels) {
+                       data_count = 16;
+               } else {
+                       data_count = 12+labels_data_count+4;
+               }
+
+               if (max_data_count<data_count) {
+                       DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
+                               max_data_count,data_count));
+                       talloc_destroy(shadow_data->mem_ctx);
+                       return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
+               }
+
+               pdata = nttrans_realloc(ppdata, data_count);
+               if (pdata == NULL) {
+                       talloc_destroy(shadow_data->mem_ctx);
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }               
+
+               cur_pdata = pdata;
+
+               /* num_volumes 4 bytes */
+               SIVAL(pdata,0,shadow_data->num_volumes);
+
+               if (labels) {
+                       /* num_labels 4 bytes */
+                       SIVAL(pdata,4,shadow_data->num_volumes);
+               }
+
+               /* needed_data_count 4 bytes */
+               SIVAL(pdata,8,labels_data_count);
+
+               cur_pdata+=12;
+
+               DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
+                       shadow_data->num_volumes,fsp->fsp_name));
+               if (labels && shadow_data->labels) {
+                       for (i=0;i<shadow_data->num_volumes;i++) {
+                               srvstr_push(outbuf, cur_pdata, shadow_data->labels[i], 2*sizeof(SHADOW_COPY_LABEL), STR_UNICODE|STR_TERMINATE);
+                               cur_pdata+=2*sizeof(SHADOW_COPY_LABEL);
+                               DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
+                       }
+               }
+
+               talloc_destroy(shadow_data->mem_ctx);
+
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, pdata, data_count);
+
+               return -1;
+        }
+        
        case FSCTL_FIND_FILES_BY_SID: /* I hope this name is right */
        {
                /* pretend this succeeded - 
@@ -1783,24 +1909,24 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 * we have to send back a list with all files owned by this SID
                 *
                 * but I have to check that --metze
-                */ 
-                  
+                */
                DOM_SID sid;
                uid_t uid;
-               size_t sid_len=SID_MAX_SIZE;
-               
-               DEBUG(10,("FSCTL_FIND_FILES_BY_SID: fnum=%d control=0x%08x\n",fnum,control));
+               size_t sid_len = MIN(data_count-4,SID_MAX_SIZE);
                
-               /* this is not the length of the sid :-( so unknown 4 bytes */
-               /*sid_len = IVAL(pdata,0);      
-               DEBUGADD(0,("sid_len: (%u)\n",sid_len));*/
+               DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum));
+
+               FSP_BELONGS_CONN(fsp,conn);
+
+               /* unknown 4 bytes: this is not the length of the sid :-(  */
+               /*unknown = IVAL(pdata,0);*/
                
                sid_parse(pdata+4,sid_len,&sid);
-               DEBUGADD(10,("SID: %s\n",sid_string_static(&sid)));
+               DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid)));
 
                if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &uid))) {
-                       DEBUG(0,("sid_to_uid: failed, sid[%s]\n",
-                               sid_string_static(&sid)));
+                       DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%u]\n",
+                               sid_string_static(&sid),sid_len));
                        uid = (-1);
                }
                
@@ -1813,6 +1939,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 * for each file
                 *
                 * but I don't know how to deal with the paged results
+                * (maybe we can hang the result anywhere in the fsp struct)
                 *
                 * we don't send all files at once
                 * and at the next we should *not* start from the beginning, 
@@ -1829,7 +1956,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                if (!logged_message) {
                        logged_message = True; /* Only print this once... */
                        DEBUG(0,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n",
-                                control));
+                                function));
                }
        }
 
index 8d44a1a0fa12ac44a45af07152986f89caa7d7f5..a76a7a6abdcd22413a4e20755bfed64da4d3f0ea 100644 (file)
@@ -49,6 +49,42 @@ SMB_BIG_UINT vfswrap_disk_free(vfs_handle_struct *handle, connection_struct *con
     result = sys_disk_free(path, small_query, bsize, dfree, dsize);
     return result;
 }
+
+int vfswrap_get_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+{
+#ifdef HAVE_SYS_QUOTAS
+       int result;
+
+       START_PROFILE(syscall_get_quota);
+       result = sys_get_quota(conn->connectpath, qtype, id, qt);
+       END_PROFILE(syscall_get_quota);
+       return result;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif 
+}
+
+int vfswrap_set_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
+{
+#ifdef HAVE_SYS_QUOTAS
+       int result;
+
+       START_PROFILE(syscall_set_quota);
+       result = sys_set_quota(conn->connectpath, qtype, id, qt);
+       END_PROFILE(syscall_set_quota);
+       return result;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif 
+}
+
+int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels)
+{
+       errno = ENOSYS;
+       return -1;  /* Not implemented. */
+}
     
 /* Directory operations */
 
@@ -756,36 +792,6 @@ int vfswrap_sys_acl_free_qualifier(vfs_handle_struct *handle, connection_struct
        return sys_acl_free_qualifier(qualifier, tagtype);
 }
 
-int vfswrap_get_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
-{
-#ifdef HAVE_SYS_QUOTAS
-       int result;
-
-       START_PROFILE(syscall_get_quota);
-       result = sys_get_quota(conn->connectpath, qtype, id, qt);
-       END_PROFILE(syscall_get_quota);
-       return result;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif 
-}
-
-int vfswrap_set_quota(struct vfs_handle_struct *handle, struct connection_struct *conn, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
-{
-#ifdef HAVE_SYS_QUOTAS
-       int result;
-
-       START_PROFILE(syscall_set_quota);
-       result = sys_set_quota(conn->connectpath, qtype, id, qt);
-       END_PROFILE(syscall_set_quota);
-       return result;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif 
-}
-
 /****************************************************************
  Extended attribute operations.
 *****************************************************************/
index 5f3abe7efea5b43dbda54b462cd9fcd6d4e36787..58a8a387925b808e5da1548b91a73468d9d2e23e 100644 (file)
@@ -56,6 +56,7 @@ static struct vfs_ops default_vfs = {
                vfswrap_disk_free,
                vfswrap_get_quota,
                vfswrap_set_quota,
+               vfswrap_get_shadow_copy_data,
        
                /* Directory operations */
        
@@ -140,7 +141,6 @@ static struct vfs_ops default_vfs = {
                vfswrap_setxattr,
                vfswrap_lsetxattr,
                vfswrap_fsetxattr
-
        }
 };