s3:smbd: split out smbd_do_setfilepathinfo() from call_trans2setfilepathinfo()
authorStefan Metzmacher <metze@samba.org>
Mon, 13 Jul 2009 06:59:32 +0000 (08:59 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 13 Jul 2009 09:18:50 +0000 (11:18 +0200)
metze

source3/smbd/trans2.c

index 6554fb67b75677da095908aca268522e080498f5..54d873065c96f586915ac3d407ba20e8b0618479 100644 (file)
@@ -7055,200 +7055,45 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
        return close_file(req, fsp, NORMAL_CLOSE);
 }
 
-/****************************************************************************
- Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
-****************************************************************************/
-
-static void call_trans2setfilepathinfo(connection_struct *conn,
-                                      struct smb_request *req,
-                                      unsigned int tran_call,
-                                      char **pparams, int total_params,
-                                      char **ppdata, int total_data,
-                                      unsigned int max_data_bytes)
+static NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
+                                       struct smb_request *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       uint16_t info_level,
+                                       files_struct *fsp,
+                                       struct smb_filename *smb_fname,
+                                       char **ppdata, int total_data,
+                                       int *ret_data_size)
 {
-       char *params = *pparams;
        char *pdata = *ppdata;
-       uint16 info_level;
        SMB_STRUCT_STAT sbuf;
        char *fname = NULL;
-       struct smb_filename *smb_fname = NULL;
-       files_struct *fsp = NULL;
        NTSTATUS status = NT_STATUS_OK;
        int data_return_size = 0;
-       TALLOC_CTX *ctx = talloc_tos();
-
-       if (!params) {
-               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-               return;
-       }
-
-       if (tran_call == TRANSACT2_SETFILEINFO) {
-               if (total_params < 4) {
-                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-                       return;
-               }
-
-               fsp = file_fsp(req, SVAL(params,0));
-               /* Basic check for non-null fsp. */
-               if (!check_fsp_open(conn, req, fsp)) {
-                       return;
-               }
-               info_level = SVAL(params,2);
-
-               fname = talloc_strdup(talloc_tos(),fsp->fsp_name);
-               if (!fname) {
-                       reply_nterror(req, NT_STATUS_NO_MEMORY);
-                       return;
-               }
-
-               status = create_synthetic_smb_fname_split(talloc_tos(), fname,
-                                                         NULL, &smb_fname);
-               if (!NT_STATUS_IS_OK(status)) {
-                       reply_nterror(req, status);
-                       return;
-               }
 
-               if(fsp->is_directory || fsp->fh->fd == -1) {
-                       /*
-                        * This is actually a SETFILEINFO on a directory
-                        * handle (returned from an NT SMB). NT5.0 seems
-                        * to do this call. JRA.
-                        */
-                       if (INFO_LEVEL_IS_UNIX(info_level)) {
-                               /* Always do lstat for UNIX calls. */
-                               if (SMB_VFS_LSTAT(conn, smb_fname)) {
-                                       DEBUG(3,("call_trans2setfilepathinfo: "
-                                                "SMB_VFS_LSTAT of %s failed "
-                                                "(%s)\n",
-                                                smb_fname_str_dbg(smb_fname),
-                                                strerror(errno)));
-                                       reply_nterror(req, map_nt_error_from_unix(errno));
-                                       return;
-                               }
-                       } else {
-                               if (SMB_VFS_STAT(conn, smb_fname) != 0) {
-                                       DEBUG(3,("call_trans2setfilepathinfo: "
-                                                "fileinfo of %s failed (%s)\n",
-                                                smb_fname_str_dbg(smb_fname),
-                                                strerror(errno)));
-                                       reply_nterror(req, map_nt_error_from_unix(errno));
-                                       return;
-                               }
-                       }
-               } else if (fsp->print_file) {
-                       /*
-                        * Doing a DELETE_ON_CLOSE should cancel a print job.
-                        */
-                       if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
-                               fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
-
-                               DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
-
-                               SSVAL(params,0,0);
-                               send_trans2_replies(conn, req, params, 2,
-                                                   *ppdata, 0,
-                                                   max_data_bytes);
-                               return;
-                       } else {
-                               reply_doserror(req, ERRDOS, ERRbadpath);
-                               return;
-                       }
-               } else {
-                       /*
-                        * Original code - this is an open file.
-                        */
-                       if (!check_fsp(conn, req, fsp)) {
-                               return;
-                       }
-
-                       if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
-                               DEBUG(3,("call_trans2setfilepathinfo: fstat "
-                                        "of fnum %d failed (%s)\n", fsp->fnum,
-                                        strerror(errno)));
-                               reply_nterror(req, map_nt_error_from_unix(errno));
-                               return;
-                       }
-               }
-       } else {
-               /* set path info */
-               if (total_params < 7) {
-                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-                       return;
-               }
-
-               info_level = SVAL(params,0);
-               srvstr_get_path(ctx, params, req->flags2, &fname, &params[6],
-                               total_params - 6, STR_TERMINATE,
-                               &status);
-               if (!NT_STATUS_IS_OK(status)) {
-                       reply_nterror(req, status);
-                       return;
-               }
-
-               status = filename_convert(ctx, conn,
-                                        req->flags2 & FLAGS2_DFS_PATHNAMES,
-                                        fname,
-                                        &smb_fname,
-                                        &fname);
-               if (!NT_STATUS_IS_OK(status)) {
-                       if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
-                               reply_botherror(req,
-                                               NT_STATUS_PATH_NOT_COVERED,
-                                               ERRSRV, ERRbadpath);
-                               return;
-                       }
-                       reply_nterror(req, status);
-                       return;
-               }
-
-               if (INFO_LEVEL_IS_UNIX(info_level)) {
-                       /*
-                        * For CIFS UNIX extensions the target name may not exist.
-                        */
-
-                       /* Always do lstat for UNIX calls. */
-                       SMB_VFS_LSTAT(conn, smb_fname);
-
-               } else if (!VALID_STAT(smb_fname->st) &&
-                          SMB_VFS_STAT(conn, smb_fname)) {
-                       DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
-                                "%s failed (%s)\n",
-                                smb_fname_str_dbg(smb_fname),
-                                strerror(errno)));
-                       reply_nterror(req, map_nt_error_from_unix(errno));
-                       return;
-               }
-       }
+       *ret_data_size = 0;
 
        /* Set sbuf for use below. */
        sbuf = smb_fname->st;
 
        if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
-               reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-               return;
+               return NT_STATUS_INVALID_LEVEL;
        }
 
        if (!CAN_WRITE(conn)) {
                /* Allow POSIX opens. The open path will deny
                 * any non-readonly opens. */
                if (info_level != SMB_POSIX_PATH_OPEN) {
-                       reply_doserror(req, ERRSRV, ERRaccess);
-                       return;
+                       return NT_STATUS_DOS(ERRSRV, ERRaccess);
                }
        }
 
-       DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
-               tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
-
-       /* Realloc the parameter size */
-       *pparams = (char *)SMB_REALLOC(*pparams,2);
-       if (*pparams == NULL) {
-               reply_nterror(req, NT_STATUS_NO_MEMORY);
-               return;
+       status = get_full_smb_filename(mem_ctx, smb_fname, &fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
-       params = *pparams;
 
-       SSVAL(params,0,0);
+       DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d totdata=%d\n",
+               fname, fsp ? fsp->fnum : -1, info_level, total_data));
 
        switch (info_level) {
 
@@ -7374,10 +7219,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 
                case SMB_SET_FILE_UNIX_LINK:
                {
-                       if (tran_call != TRANSACT2_SETPATHINFO) {
+                       if (fsp) {
                                /* We must have a pathname for this. */
-                               reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-                               return;
+                               return NT_STATUS_INVALID_LEVEL;
                        }
                        status = smb_set_file_unix_link(conn, req, pdata,
                                                        total_data, fname);
@@ -7386,10 +7230,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 
                case SMB_SET_FILE_UNIX_HLINK:
                {
-                       if (tran_call != TRANSACT2_SETPATHINFO || smb_fname == NULL) {
+                       if (fsp || smb_fname == NULL) {
                                /* We must have a pathname for this. */
-                               reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-                               return;
+                               return NT_STATUS_INVALID_LEVEL;
                        }
                        status = smb_set_file_unix_hlink(conn, req,
                                                         pdata, total_data,
@@ -7420,9 +7263,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 
                case SMB_SET_POSIX_LOCK:
                {
-                       if (tran_call != TRANSACT2_SETFILEINFO) {
-                               reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-                               return;
+                       if (fsp) {
+                               return NT_STATUS_INVALID_LEVEL;
                        }
                        status = smb_set_posix_lock(conn, req,
                                                    pdata, total_data, fsp);
@@ -7431,10 +7273,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 
                case SMB_POSIX_PATH_OPEN:
                {
-                       if (tran_call != TRANSACT2_SETPATHINFO) {
+                       if (fsp) {
                                /* We must have a pathname for this. */
-                               reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-                               return;
+                               return NT_STATUS_INVALID_LEVEL;
                        }
 
                        status = smb_posix_open(conn, req,
@@ -7448,10 +7289,9 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 
                case SMB_POSIX_PATH_UNLINK:
                {
-                       if (tran_call != TRANSACT2_SETPATHINFO) {
+                       if (fsp) {
                                /* We must have a pathname for this. */
-                               reply_nterror(req, NT_STATUS_INVALID_LEVEL);
-                               return;
+                               return NT_STATUS_INVALID_LEVEL;
                        }
 
                        status = smb_posix_unlink(conn, req,
@@ -7462,10 +7302,199 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                }
 
                default:
-                       reply_nterror(req, NT_STATUS_INVALID_LEVEL);
+                       return NT_STATUS_INVALID_LEVEL;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       *ret_data_size = data_return_size;
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
+****************************************************************************/
+
+static void call_trans2setfilepathinfo(connection_struct *conn,
+                                      struct smb_request *req,
+                                      unsigned int tran_call,
+                                      char **pparams, int total_params,
+                                      char **ppdata, int total_data,
+                                      unsigned int max_data_bytes)
+{
+       char *params = *pparams;
+       char *pdata = *ppdata;
+       uint16 info_level;
+       char *fname = NULL;
+       struct smb_filename *smb_fname = NULL;
+       files_struct *fsp = NULL;
+       NTSTATUS status = NT_STATUS_OK;
+       int data_return_size = 0;
+
+       if (!params) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       if (tran_call == TRANSACT2_SETFILEINFO) {
+               if (total_params < 4) {
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       return;
+               }
+
+               fsp = file_fsp(req, SVAL(params,0));
+               /* Basic check for non-null fsp. */
+               if (!check_fsp_open(conn, req, fsp)) {
+                       return;
+               }
+               info_level = SVAL(params,2);
+
+               fname = talloc_strdup(talloc_tos(),fsp->fsp_name);
+               if (!fname) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
+                       return;
+               }
+
+               status = create_synthetic_smb_fname_split(talloc_tos(), fname,
+                                                         NULL, &smb_fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+
+               if(fsp->is_directory || fsp->fh->fd == -1) {
+                       /*
+                        * This is actually a SETFILEINFO on a directory
+                        * handle (returned from an NT SMB). NT5.0 seems
+                        * to do this call. JRA.
+                        */
+                       if (INFO_LEVEL_IS_UNIX(info_level)) {
+                               /* Always do lstat for UNIX calls. */
+                               if (SMB_VFS_LSTAT(conn, smb_fname)) {
+                                       DEBUG(3,("call_trans2setfilepathinfo: "
+                                                "SMB_VFS_LSTAT of %s failed "
+                                                "(%s)\n",
+                                                smb_fname_str_dbg(smb_fname),
+                                                strerror(errno)));
+                                       reply_nterror(req, map_nt_error_from_unix(errno));
+                                       return;
+                               }
+                       } else {
+                               if (SMB_VFS_STAT(conn, smb_fname) != 0) {
+                                       DEBUG(3,("call_trans2setfilepathinfo: "
+                                                "fileinfo of %s failed (%s)\n",
+                                                smb_fname_str_dbg(smb_fname),
+                                                strerror(errno)));
+                                       reply_nterror(req, map_nt_error_from_unix(errno));
+                                       return;
+                               }
+                       }
+               } else if (fsp->print_file) {
+                       /*
+                        * Doing a DELETE_ON_CLOSE should cancel a print job.
+                        */
+                       if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
+                               fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
+
+                               DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
+
+                               SSVAL(params,0,0);
+                               send_trans2_replies(conn, req, params, 2,
+                                                   *ppdata, 0,
+                                                   max_data_bytes);
+                               return;
+                       } else {
+                               reply_doserror(req, ERRDOS, ERRbadpath);
+                               return;
+                       }
+               } else {
+                       /*
+                        * Original code - this is an open file.
+                        */
+                       if (!check_fsp(conn, req, fsp)) {
+                               return;
+                       }
+
+                       if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
+                               DEBUG(3,("call_trans2setfilepathinfo: fstat "
+                                        "of fnum %d failed (%s)\n", fsp->fnum,
+                                        strerror(errno)));
+                               reply_nterror(req, map_nt_error_from_unix(errno));
+                               return;
+                       }
+               }
+       } else {
+               /* set path info */
+               if (total_params < 7) {
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        return;
+               }
+
+               info_level = SVAL(params,0);
+               srvstr_get_path(req, params, req->flags2, &fname, &params[6],
+                               total_params - 6, STR_TERMINATE,
+                               &status);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+
+               status = filename_convert(req, conn,
+                                        req->flags2 & FLAGS2_DFS_PATHNAMES,
+                                        fname,
+                                        &smb_fname,
+                                        &fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                               reply_botherror(req,
+                                               NT_STATUS_PATH_NOT_COVERED,
+                                               ERRSRV, ERRbadpath);
+                               return;
+                       }
+                       reply_nterror(req, status);
+                       return;
+               }
+
+               if (INFO_LEVEL_IS_UNIX(info_level)) {
+                       /*
+                        * For CIFS UNIX extensions the target name may not exist.
+                        */
+
+                       /* Always do lstat for UNIX calls. */
+                       SMB_VFS_LSTAT(conn, smb_fname);
+
+               } else if (!VALID_STAT(smb_fname->st) &&
+                          SMB_VFS_STAT(conn, smb_fname)) {
+                       DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
+                                "%s failed (%s)\n",
+                                smb_fname_str_dbg(smb_fname),
+                                strerror(errno)));
+                       reply_nterror(req, map_nt_error_from_unix(errno));
+                       return;
+               }
        }
 
+       DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
+               tran_call, fname, fsp ? fsp->fnum : -1, info_level,total_data));
+
+       /* Realloc the parameter size */
+       *pparams = (char *)SMB_REALLOC(*pparams,2);
+       if (*pparams == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+       params = *pparams;
+
+       SSVAL(params,0,0);
+
+       status = smbd_do_setfilepathinfo(conn, req, req,
+                                        info_level,
+                                        fsp,
+                                        smb_fname,
+                                        ppdata, total_data,
+                                        &data_return_size);
        if (!NT_STATUS_IS_OK(status)) {
                if (open_was_deferred(req->mid)) {
                        /* We have re-scheduled this call. */
@@ -7489,7 +7518,6 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                return;
        }
 
-       SSVAL(params,0,0);
        send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
                            max_data_bytes);