s3:smbd: implement FSCTL_SET_SPARSE more correctly
authorBjörn Jacke <bj@sernet.de>
Thu, 18 Nov 2010 16:24:00 +0000 (17:24 +0100)
committerJeremy Allison <jra@samba.org>
Fri, 17 Dec 2010 20:11:04 +0000 (21:11 +0100)
this is a port of a patch from metze for 3.3:

We don't do the "strict allocation" when the sparse bit isn't
set, but that shouldn't matter.

We now allow windows applications to set and unset the sparse
bit.

Note that in order to implement this 100% like described
in [MS-FSA], we'd have to change our data model and support
the sparse flag per stream.

source3/smbd/nttrans.c

index ad585337b8559248b2e7baa3aab402062256d836..8d92d606428daf2826b6899b8b4d86b7a8d1cdd2 100644 (file)
@@ -2107,14 +2107,52 @@ static void call_nt_transact_ioctl(connection_struct *conn,
 
        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 */
+       {
+               bool set_sparse = true;
+               NTSTATUS status;
+
+               if (data_count >= 1 && pdata[0] == 0) {
+                       set_sparse = false;
+               }
+
+               DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X]set[%u]\n",
+                        fidnum, set_sparse));
+
+               if (!check_fsp_open(conn, req, fsp)) {
+                       return;
+               }
+
+               if (!CAN_WRITE(conn)) {
+                       DEBUG(9,("FSCTL_SET_SPARSE: fname[%s] set[%u] "
+                                "on readonly share[%s]\n",
+                                smb_fname_str_dbg(fsp->fsp_name), set_sparse,
+                                lp_servicename(SNUM(conn))));
+                       reply_nterror(req, NT_STATUS_MEDIA_WRITE_PROTECTED);
+                       return;
+               }
+
+               if (!(fsp->access_mask & FILE_WRITE_DATA) &&
+                   !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
+                       DEBUG(9,("FSCTL_SET_SPARSE: fname[%s] set[%u] "
+                                "access_mask[0x%08X] - access denied\n",
+                                smb_fname_str_dbg(fsp->fsp_name), set_sparse, fsp->access_mask));
+                       reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return;
+               }
 
-               DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum));
+               status = file_set_sparse(conn, fsp->fsp_name, set_sparse);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(9,("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
+                                smb_fname_str_dbg(fsp->fsp_name), set_sparse, nt_errstr(status)));
+                       reply_nterror(req, status);
+                       return;
+               }
+
+               DEBUG(10,("FSCTL_SET_SPARSE: fname[%s] set[%u] - %s\n",
+                        smb_fname_str_dbg(fsp->fsp_name), set_sparse, nt_errstr(status)));
                send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
                return;
-
+       }
        case FSCTL_CREATE_OR_GET_OBJECT_ID:
        {
                unsigned char objid[16];