From 4e8b36a5749f4801022617b8fec1fe5d48529fef Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 14 Aug 2003 21:16:06 +0000 Subject: Fix SMBseek and get/set position information SMBs. Works against Samba4 tester. You will need a make clean; make all after this ! Jeremy. (This used to be commit 10d90171ed58bee3e5ab6476341059b585034134) --- source3/include/smb.h | 1 + source3/smbd/fileio.c | 22 ++++++++++++++++++++-- source3/smbd/open.c | 3 --- source3/smbd/reply.c | 33 +++++++++------------------------ source3/smbd/trans2.c | 25 ++++++++++++++++++++++--- 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index deeb61034d..2cafd1b9b1 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -390,6 +390,7 @@ typedef struct files_struct SMB_OFF_T pos; SMB_BIG_UINT size; SMB_BIG_UINT initial_allocation_size; /* Faked up initial allocation on disk. */ + SMB_BIG_UINT position_information; mode_t mode; uint16 vuid; write_bmpx_struct *wbmpx_ptr; diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 6be5f6af7d..6cf7014846 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -87,8 +87,11 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) * Serve from write cache if we can. */ - if(read_from_write_cache(fsp, data, pos, n)) + if(read_from_write_cache(fsp, data, pos, n)) { + fsp->pos = pos + n; + fsp->position_information = fsp->pos; return n; + } flush_write_cache(fsp, READ_FLUSH); @@ -123,6 +126,9 @@ tryagain: DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + fsp->pos += ret; + fsp->position_information = fsp->pos; + return(ret); } @@ -145,6 +151,16 @@ static ssize_t real_write_file(files_struct *fsp,char *data,SMB_OFF_T pos, size_ DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); + if (ret != -1) { + fsp->pos += ret; + +/* Yes - this is correct - writes don't update this. JRA. */ +/* Found by Samba4 tests. */ +#if 0 + fsp->position_information = fsp->pos; +#endif + } + return ret; } @@ -244,7 +260,7 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", if(!wcp) { DO_PROFILE_INC(writecache_direct_writes); total_written = real_write_file(fsp, data, pos, n); - if ((total_written != -1) && (pos + total_written > (SMB_OFF_T)fsp->size)) + if ((total_written != -1) && (pos + total_written > (SMB_OFF_T)fsp->size)) fsp->size = (SMB_BIG_UINT)(pos + total_written); return total_written; } @@ -252,6 +268,8 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); + fsp->pos = pos + n; + /* * If we have active cache and it isn't contiguous then we flush. * NOTE: There is a small problem with running out of disk .... diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 2c9d3290d8..06f1ddfcf2 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -227,7 +227,6 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, fsp->dev = psbuf->st_dev; fsp->vuid = current_user.vuid; fsp->size = psbuf->st_size; - fsp->pos = -1; fsp->can_lock = True; fsp->can_read = ((flags & O_WRONLY)==0); fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); @@ -1362,7 +1361,6 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST fsp->dev = psbuf->st_dev; fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; - fsp->pos = -1; fsp->can_lock = True; fsp->can_read = False; fsp->can_write = False; @@ -1425,7 +1423,6 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_ST fsp->dev = (SMB_DEV_T)0; fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; - fsp->pos = -1; fsp->can_lock = False; fsp->can_read = False; fsp->can_write = False; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 8347daf26b..8df118ab16 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -2308,39 +2308,25 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int switch (mode) { case 0: umode = SEEK_SET; + res = startpos; break; case 1: umode = SEEK_CUR; + res = fsp->pos + startpos; break; case 2: umode = SEEK_END; break; default: umode = SEEK_SET; + res = startpos; break; } - if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) { - /* - * Check for the special case where a seek before the start - * of the file sets the offset to zero. Added in the CIFS spec, - * section 4.2.7. - */ - - if(errno == EINVAL) { - SMB_OFF_T current_pos = startpos; - - if(umode == SEEK_CUR) { - - if((current_pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) { - END_PROFILE(SMBlseek); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - - current_pos += startpos; - - } else if (umode == SEEK_END) { - + if (umode == SEEK_END) { + if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) { + if(errno == EINVAL) { + SMB_OFF_T current_pos = startpos; SMB_STRUCT_STAT sbuf; if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) { @@ -2349,10 +2335,9 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } current_pos += sbuf.st_size; + if(current_pos < 0) + res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); } - - if(current_pos < 0) - res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); } if(res == -1) { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f81486b1ad..8adac1930f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1821,9 +1821,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } - if((pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) - return(UNIXERROR(ERRDOS,ERRnoaccess)); - + pos = fsp->position_information; delete_pending = fsp->delete_on_close; } } else { @@ -2702,6 +2700,27 @@ static int call_trans2setfilepathinfo(connection_struct *conn, break; } + case SMB_FILE_POSITION_INFORMATION: + { + SMB_BIG_UINT position_information; + + if (total_data < 8) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + position_information = (SMB_BIG_UINT)IVAL(pdata,0); +#ifdef LARGE_SMB_OFF_T + position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32); +#else /* LARGE_SMB_OFF_T */ + if (IVAL(pdata,4) != 0) /* more than 32 bits? */ + return ERROR_DOS(ERRDOS,ERRunknownlevel); +#endif /* LARGE_SMB_OFF_T */ + DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n", + fname, (double)position_information )); + if (fsp) + fsp->position_information = position_information; + break; + } + /* * CIFS UNIX extensions. */ -- cgit