You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Marc Adkins <ma...@marchex.com> on 2009/04/21 00:18:29 UTC

apr_file_open() flag issue

I found this in mod_perl but the issue can be demonstrated without Perl.

Attempting to open a file for append using the following flags:

    APR_BUFFERED | APR_BINARY | APR_CREATE | APR_APPEND


will not work.  The apr_file_open() function returns APR_EACCES.  If the 
following flags are used:

    APR_BUFFERED | APR_BINARY | APR_CREATE | APR_WRITE | APR_APPEND


it works fine.  In a vacuum this behavior is debatable.  On the one 
hand, APR_APPEND could be seen to imply APR_WRITE.  On the other hand, 
it might be argued that the first case is incomplete flag-wise.

In the context of Perl, however, particularly when using the APR PerlIO 
filter, this becomes problematic.  Perl uses special character sequences 
which are converted to the proper flags down underneath the covers.  So 
in Perl '>' (write to a new file) converts properly but '>>' (append to 
an existing file or create a new one if necessary) does not.  There is 
no message either, AFAIK, it just fails silently.

I'm attaching a couple of my test files.  They demonstrate the problem 
but don't show why it happens.  I instrumented a copy of 
file_io/unix/open.c to figure out what was happening.  It fails in this 
code:

    if ((flag & APR_READ) && (flag & APR_WRITE)) {
        oflags = O_RDWR;
    }
    else if (flag & APR_READ) {
        oflags = O_RDONLY;
    }
    else if (flag & APR_WRITE) {
        oflags = O_WRONLY;
    }
    else {
        printf("fails here...\n");
        return APR_EACCES;
    }

I might suggest checking for APR_WRITE /or/ APR_APPEND, but there may be 
some reason why it's done this way.

Has anyone else stumbled on this or am I doing something that breaks the 
warranty?  Is there a work-around in Perl?

-- 
Marc M. Adkins
Software Development Engineer
520 Pike Street, Suite 500
Seattle, WA  98101
P: 206-331-3508
F: 206.331.3695
E: madkins@marchex.com

Marchex Inc.
www.marchex.com
 
This e-mail message and any attachments are solely for
intended recipients, and may contain information that is
privileged and confidential.  If you are not the intended
recipient, any dissemination, distribution or copying is
strictly prohibited.  If you believe that you may have
received this message in error, please immediately notify
the sender by replying to this e-mail message. 


Re: apr_file_open() flag issue

Posted by Jeff Trawick <tr...@gmail.com>.
(I'm not subscribed to dev@perl...)

On Mon, Apr 20, 2009 at 6:18 PM, Marc Adkins <ma...@marchex.com> wrote:

>  I found this in mod_perl but the issue can be demonstrated without Perl.
>
> Attempting to open a file for append using the following flags:
>
> APR_BUFFERED | APR_BINARY | APR_CREATE | APR_APPEND
>
>
> will not work.  The apr_file_open() function returns APR_EACCES.  If the
> following flags are used:
>
>  APR_BUFFERED | APR_BINARY | APR_CREATE | APR_WRITE | APR_APPEND
>
>
> it works fine.  In a vacuum this behavior is debatable.  On the one hand,
> APR_APPEND could be seen to imply APR_WRITE.  On the other hand, it might
> be argued that the first case is incomplete flag-wise.
>
> In the context of Perl, however, particularly when using the APR PerlIO
> filter, this becomes problematic.  Perl uses special character sequences
> which are converted to the proper flags down underneath the covers.  So in
> Perl '>' (write to a new file) converts properly but '>>' (append to an
> existing file or create a new one if necessary) does not.  There is no
> message either, AFAIK, it just fails silently.
>

The Perl code that builds the apr_file_open() flags needs to turn on
APR_WRITE.

I think that this patch to mod_perl is what you need:

--- modperl_apr_perlio.c.orig    2007-12-31 02:39:50.000000000 -0500
+++ modperl_apr_perlio.c    2009-04-20 19:37:25.954107404 -0400
@@ -85,7 +85,7 @@

     switch (*mode) {
       case 'a':
-        apr_flag = APR_APPEND | APR_CREATE;
+        apr_flag = APR_WRITE | APR_CREATE | APR_APPEND;
         break;
       case 'w':
         apr_flag = APR_WRITE | APR_CREATE | APR_TRUNCATE;