APR's handling of seeks to APR_END in buffered files has a sign error.
I've included a patch (see the end), and a test case.

I verified that nothing in Subversion or httpd uses APR_END, so it
seems likely that nothing is relying on the sign error.  And the
documentation of apr_file_seek is very clear:

 *            APR_END  --  add the offset to the current file size 

I have tested the fix on Unix.  I can't test the change to the Windows
or OS/2 code, but it's a pretty obvious fix.

---- Test case ---

#include <apr.h>
#include <apr_pools.h>
#include <apr_file_io.h>

int main()
{
  apr_pool_t *pool;
  apr_file_t *file;
  char buf[128];
  apr_size_t len;
  apr_off_t off;

  apr_initialize();
  apr_pool_create(&pool, NULL);
  apr_file_open(&file, "testfile", APR_READ|APR_BUFFERED, 0, pool);
  off = -5;
  apr_file_seek(file, APR_END, &off);
  len = sizeof(buf) - 1;
  apr_file_read(file, buf, &len);
  buf[len] = 0;
  printf("%s", buf);
  return 0;
}

To see the problem, echo something like "1234567890" into the file
"testfile" and then compile and run the test case.  You will see no
output.  If you remove the APR_BUFFERED flag, you will see "7890\n" as
expected.

Index: os2/seek.c
===================================================================
RCS file: /home/cvspublic/apr/file_io/os2/seek.c,v
retrieving revision 1.26
diff -u -r1.26 seek.c
--- os2/seek.c  13 Feb 2004 09:38:24 -0000      1.26
+++ os2/seek.c  29 Apr 2004 14:01:40 -0000
@@ -70,7 +70,7 @@
         case APR_END:
             rc = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile);
             if (rc == APR_SUCCESS)
-                rc = setptr(thefile, finfo.size - *offset);
+                rc = setptr(thefile, finfo.size + *offset);
             break;
         }
 
Index: unix/seek.c
===================================================================
RCS file: /home/cvspublic/apr/file_io/unix/seek.c,v
retrieving revision 1.34
diff -u -r1.34 seek.c
--- unix/seek.c 27 Mar 2004 13:11:17 -0000      1.34
+++ unix/seek.c 29 Apr 2004 14:01:40 -0000
@@ -69,7 +69,7 @@
         case APR_END:
             rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile);
             if (rc == APR_SUCCESS)
-                rc = setptr(thefile, finfo.size - *offset);
+                rc = setptr(thefile, finfo.size + *offset);
             break;
         }
 
Index: win32/seek.c
===================================================================
RCS file: /home/cvspublic/apr/file_io/win32/seek.c,v
retrieving revision 1.28
diff -u -r1.28 seek.c
--- win32/seek.c        13 Feb 2004 09:38:27 -0000      1.28
+++ win32/seek.c        29 Apr 2004 14:01:40 -0000
@@ -73,7 +73,7 @@
             case APR_END:
                 rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile);
                 if (rc == APR_SUCCESS)
-                    rc = setptr(thefile, finfo.size - *offset);
+                    rc = setptr(thefile, finfo.size + *offset);
                 break;
 
             default:

Reply via email to