Fix SMBseek and get/set position information SMBs. Works against
authorJeremy Allison <jra@samba.org>
Thu, 14 Aug 2003 21:16:06 +0000 (21:16 +0000)
committerJeremy Allison <jra@samba.org>
Thu, 14 Aug 2003 21:16:06 +0000 (21:16 +0000)
Samba4 tester. You will need a make clean; make all after this !
Jeremy.
(This used to be commit 10d90171ed58bee3e5ab6476341059b585034134)

source3/include/smb.h
source3/smbd/fileio.c
source3/smbd/open.c
source3/smbd/reply.c
source3/smbd/trans2.c

index deeb61034da3c3eaf9c94f5faabbd2f5f9fb1c73..2cafd1b9b1ef6e4c3c50397282f532158755c89f 100644 (file)
@@ -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;
index 6be5f6af7d001b2200864bf32cfe6474dd5074aa..6cf701484636359a6ac7ff16985d6bb4537c3a62 100644 (file)
@@ -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 ....
index 2c9d3290d8140b8516f0bba9a1c7d5851850afee..06f1ddfcf2dc9713115f6a608cd349f48b484ce4 100644 (file)
@@ -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;
index 8347daf26bbe2af3f0c1cf80a67fc68ce2ea1f33..8df118ab1605e909364be408124769ce0e50d980 100644 (file)
@@ -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) {
index f81486b1ad45325671c7252c9251b95f6834f8d0..8adac1930f408b61d87aee0a7ad8b4a085e7ff1e 100644 (file)
@@ -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.
                 */