From da5a8b539d39d2765de22c3e55e9f284992ff966 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Apr 2005 01:20:32 +0000 Subject: [PATCH] r6203: Fix attribute return on creating a directory with nttrans_create. Fix strange allocation semantics of openX. Jeremy. --- source/smbd/nttrans.c | 62 +++++++++++++++++++++---------------------- source/smbd/reply.c | 31 +++++++++++++--------- source/smbd/trans2.c | 14 +++++++--- 3 files changed, 61 insertions(+), 46 deletions(-) diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 6abea78239f..6421a14b28f 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -918,8 +918,9 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib file_len = sbuf.st_size; fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) + if(fmode == 0) { fmode = FILE_ATTRIBUTE_NORMAL; + } if (!fsp->is_directory && (fmode & aDIR)) { close_file(fsp,False); END_PROFILE(SMBntcreateX); @@ -956,11 +957,13 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib * correct bit for extended oplock reply. */ - if (oplock_request && lp_fake_oplocks(SNUM(conn))) + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { extended_oplock_granted = True; + } - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { extended_oplock_granted = True; + } #if 0 /* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */ @@ -1481,7 +1484,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o oplock_request,&rmode,&smb_action); if (!fsp) { - if(errno == EISDIR) { /* @@ -1511,32 +1513,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } - - file_len = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) - fmode = FILE_ATTRIBUTE_NORMAL; - - if (fmode & aDIR) { - talloc_destroy(ctx); - close_file(fsp,False); - restore_case_semantics(conn, file_attributes); - return ERROR_NT(NT_STATUS_ACCESS_DENIED); - } - - /* - * If the caller set the extended oplock request bit - * and we granted one (by whatever means) - set the - * correct bit for extended oplock reply. - */ - - if (oplock_request && lp_fake_oplocks(SNUM(conn))) { - extended_oplock_granted = True; - } - - if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - extended_oplock_granted = True; - } } /* @@ -1578,7 +1554,18 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } restore_case_semantics(conn, file_attributes); + talloc_destroy(ctx); + file_len = sbuf.st_size; + fmode = dos_mode(conn,fname,&sbuf); + if(fmode == 0) { + fmode = FILE_ATTRIBUTE_NORMAL; + } + if (!fsp->is_directory && (fmode & aDIR)) { + close_file(fsp,False); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } + /* Save the requested allocation size. */ if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) { SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(params,12); @@ -1589,7 +1576,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); if (fsp->is_directory) { close_file(fsp,False); - END_PROFILE(SMBntcreateX); /* Can't set allocation size on a directory. */ return ERROR_NT(NT_STATUS_ACCESS_DENIED); } @@ -1602,6 +1588,20 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } } + /* + * If the caller set the extended oplock request bit + * and we granted one (by whatever means) - set the + * correct bit for extended oplock reply. + */ + + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { + extended_oplock_granted = True; + } + + if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { + extended_oplock_granted = True; + } + /* Realloc the size of parameters and data we will return */ params = nttrans_realloc(ppparams, 69); if(params == NULL) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 22cb599195f..0d1523ae3bb 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1268,6 +1268,9 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt BOOL bad_path = False; files_struct *fsp; NTSTATUS status; + SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9); + ssize_t retval = -1; + START_PROFILE(SMBopenX); /* If it's an IPC, pass off the pipe handler. */ @@ -1320,18 +1323,22 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt size = sbuf.st_size; - if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) { - SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9); - if (allocation_size && (allocation_size > (SMB_BIG_UINT)size)) { - fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); - if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { - close_file(fsp,False); - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_DISK_FULL); - } - } else { - fsp->initial_allocation_size = smb_roundup(fsp->conn,(SMB_BIG_UINT)size); + /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size, + if the file is truncated or created. */ + if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) { + fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size); + if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { + close_file(fsp,False); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_DISK_FULL); } + retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size); + if (retval < 0) { + close_file(fsp,False); + END_PROFILE(SMBwrite); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + size = get_allocation_size(conn,fsp,&sbuf); } fmode = dos_mode(conn,fname,&sbuf); @@ -1371,7 +1378,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt put_dos_date3(outbuf,smb_vwv4,mtime & ~1); else put_dos_date3(outbuf,smb_vwv4,mtime); - SIVAL(outbuf,smb_vwv6,(uint32)get_allocation_size(conn,fsp,&sbuf)); + SIVAL(outbuf,smb_vwv6,(uint32)size); SSVAL(outbuf,smb_vwv8,rmode); SSVAL(outbuf,smb_vwv11,smb_action); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index e7f44a65925..f8123bc11a1 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -58,14 +58,18 @@ SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, SMB { SMB_BIG_UINT ret; + if(S_ISDIR(sbuf->st_mode)) { + return 0; + } + #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks; #else ret = (SMB_BIG_UINT)get_file_size(*sbuf); #endif - if (!ret && fsp && fsp->initial_allocation_size) - ret = fsp->initial_allocation_size; + if (fsp && fsp->initial_allocation_size) + ret = MAX(ret,fsp->initial_allocation_size); return smb_roundup(conn, ret); } @@ -2800,7 +2804,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * fullpathname = fname; file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(conn,fsp,&sbuf); if (mode & aDIR) { /* This is necessary, as otherwise the desktop.ini file in * this folder is ignored */ @@ -2858,6 +2861,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + allocation_size = get_allocation_size(conn,fsp,&sbuf); + if (fsp) { if (fsp->pending_modtime) { /* the pending modtime overrides the current modtime */ @@ -2870,6 +2875,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd /* the pending modtime overrides the current modtime */ sbuf.st_mtime = fsp1->pending_modtime; } + if (fsp1 && fsp1->initial_allocation_size) { + allocation_size = get_allocation_size(conn, fsp1, &sbuf); + } } if (lp_dos_filetime_resolution(SNUM(conn))) {