Upgrade ntvfs_map_*info to ntvfs_map_async_setup/ntvfs_map_async_finish
[metze/samba/wip.git] / source4 / ntvfs / ntvfs_generic.c
index d70575847574f6a6ca361fdf2f32e99b6bb661bd..5838178d9e225c952c7db3a323cb7f95cf5ca742 100644 (file)
@@ -56,7 +56,8 @@ struct ntvfs_map_async {
 */
 static void ntvfs_map_async_send(struct ntvfs_request *req)
 {
-       struct ntvfs_map_async *m = req->async_states->private_data;
+       struct ntvfs_map_async *m = talloc_get_type(req->async_states->private_data,
+                                   struct ntvfs_map_async);
 
        ntvfs_async_state_pop(req);
 
@@ -105,7 +106,8 @@ static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS statu
 
        /* the backend is replying immediately. call the 2nd stage function after popping our local
           async state */
-       m = req->async_states->private_data;
+       m = talloc_get_type(req->async_states->private_data,
+                           struct ntvfs_map_async);
 
        ntvfs_async_state_pop(req);
 
@@ -281,6 +283,8 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                               uint16_t open_func, const char *fname,
                               union smb_open *io2)
 {
+       io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+
        if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
                io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
        }
@@ -532,16 +536,16 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                }
 
                /* we need to check these bits before we check the private mask */
-               if (io2->generic.in.create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
+               if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
+                       DEBUG(2,(__location__ " create_options 0x%x not supported\n",
+                                io2->generic.in.create_options));
                        status = NT_STATUS_NOT_SUPPORTED;
                        break;
                }
 
-               /* we use a couple of bits of the create options internally */
-               if (io2->generic.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) {
-                       status = NT_STATUS_INVALID_PARAMETER;
-                       break;
-               }
+               /* TODO: find out why only SMB2 ignores these */
+               io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
+               io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
 
                status = ntvfs->ops->open(ntvfs, req, io2);             
                break;
@@ -556,31 +560,14 @@ done:
 
 
 /* 
-   NTVFS fsinfo generic to any mapper
+   NTVFS any to fsinfo mapper
 */
-NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
-                                  struct ntvfs_request *req,
-                                  union smb_fsinfo *fs)
+static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fsinfo *fs,
+                                     union smb_fsinfo *fs2,
+                                     NTSTATUS status)
 {
-       NTSTATUS status;
-       union smb_fsinfo *fs2;
-
-       fs2 = talloc(req, union smb_fsinfo);
-       if (fs2 == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       if (fs->generic.level == RAW_QFS_GENERIC) {
-               return NT_STATUS_INVALID_LEVEL;
-       }
-       
-       /* only used by the simple backend, which doesn't do async */
-       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-
-       /* ask the backend for the generic info */
-       fs2->generic.level = RAW_QFS_GENERIC;
-
-       status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -683,6 +670,38 @@ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
        return NT_STATUS_INVALID_LEVEL;
 }
 
+/*
+   NTVFS fsinfo any to generic mapper
+*/
+NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
+                         struct ntvfs_request *req,
+                         union smb_fsinfo *fs)
+{
+       NTSTATUS status;
+       union smb_fsinfo *fs2;
+
+       fs2 = talloc(req, union smb_fsinfo);
+       if (fs2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (fs->generic.level == RAW_QFS_GENERIC) {
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
+       status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
+                                      (second_stage_t)ntvfs_map_fsinfo_finish);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* ask the backend for the generic info */
+       fs2->generic.level = RAW_QFS_GENERIC;
+
+       status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
+       return ntvfs_map_async_finish(req, status);
+}
+
 
 /* 
    NTVFS fileinfo generic to any mapper
@@ -854,7 +873,7 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
                                        return NT_STATUS_NO_MEMORY;
                                }
                                info->all_eas.out.eas[i].value.data = 
-                                       talloc_memdup(info->all_eas.out.eas,
+                                       (uint8_t *)talloc_memdup(info->all_eas.out.eas,
                                                info2->generic.out.eas[i].value.data,
                                                info2->generic.out.eas[i].value.length);
                                if (!info->all_eas.out.eas[i].value.data) {
@@ -916,6 +935,22 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
 }
 
 /* 
+   NTVFS any to fileinfo mapper
+*/
+static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fileinfo *info,
+                                     union smb_fileinfo *info2,
+                                     NTSTATUS status)
+{
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return ntvfs_map_fileinfo(req, info, info2);
+}
+
+/*
    NTVFS fileinfo generic to any mapper
 */
 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
@@ -934,17 +969,33 @@ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       status = ntvfs_map_async_setup(ntvfs, req, info, info2,
+                                      (second_stage_t)ntvfs_map_qfileinfo_finish);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* ask the backend for the generic info */
        info2->generic.level = RAW_FILEINFO_GENERIC;
        info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
 
-       /* only used by the simple backend, which doesn't do async */
-       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-
        status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
+       return ntvfs_map_async_finish(req, status);
+}
+
+/*
+   NTVFS any to fileinfo mapper
+*/
+static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fileinfo *info,
+                                     union smb_fileinfo *info2,
+                                     NTSTATUS status)
+{
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
+
        return ntvfs_map_fileinfo(req, info, info2);
 }
 
@@ -967,18 +1018,18 @@ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       status = ntvfs_map_async_setup(ntvfs, req, info, info2,
+                                      (second_stage_t)ntvfs_map_qpathinfo_finish);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* ask the backend for the generic info */
        info2->generic.level            = RAW_FILEINFO_GENERIC;
        info2->generic.in.file.path     = info->generic.in.file.path;
 
-       /* only used by the simple backend, which doesn't do async */
-       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-
        status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       return ntvfs_map_fileinfo(req, info, info2);
+       return ntvfs_map_async_finish(req, status);
 }
 
 
@@ -986,8 +1037,8 @@ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
    NTVFS lock generic to any mapper
 */
 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
-                                struct ntvfs_request *req,
-                                union smb_lock *lck)
+                       struct ntvfs_request *req,
+                       union smb_lock *lck)
 {
        union smb_lock *lck2;
        struct smb_lock_entry *locks;
@@ -1035,7 +1086,8 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
        case RAW_LOCK_SMB2: {
                /* this is only approximate! We need to change the
                   generic structure to fix this properly */
-               int i, j;
+               int i;
+               bool isunlock;
                if (lck->smb2.in.lock_count < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
@@ -1051,32 +1103,28 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
                if (lck2->generic.in.locks == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
+               /* only the first lock gives the UNLOCK bit - see
+                  MS-SMB2 3.3.5.14 */
+               if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
+                       lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
+                       isunlock = true;
+               } else {
+                       lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
+                       isunlock = false;
+               }
                for (i=0;i<lck->smb2.in.lock_count;i++) {
-                       if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
-                               break;
-                       }
-                       j = lck2->generic.in.ulock_cnt;
-                       if (lck->smb2.in.locks[i].flags & 
-                           (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE)) {
+                       if (isunlock && 
+                           (lck->smb2.in.locks[i].flags & 
+                            (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
                                return NT_STATUS_INVALID_PARAMETER;
                        }
-                       lck2->generic.in.ulock_cnt++;
-                       lck2->generic.in.locks[j].pid = 0;
-                       lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
-                       lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
-                       lck2->generic.in.locks[j].pid = 0;
-               }
-               for (;i<lck->smb2.in.lock_count;i++) {
-                       if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
-                               /* w2008 requires unlocks to come first */
+                       if (!isunlock && 
+                           (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
                                return NT_STATUS_INVALID_PARAMETER;
                        }
-                       j = lck2->generic.in.ulock_cnt + lck2->generic.in.lock_cnt;
-                       lck2->generic.in.lock_cnt++;
-                       lck2->generic.in.locks[j].pid = 0;
-                       lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
-                       lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
-                       lck2->generic.in.locks[j].pid = 0;
+                       lck2->generic.in.locks[i].pid    = req->smbpid;
+                       lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
+                       lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
                        if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
                                lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
                        }