Noz.i.kor
Noz.i.kor

Reputation: 3747

Incorrect file permissions when calling C's open() function from fortran

I have a fortran program which calls a C function and opens a file using open()

main.f90:

PROGRAM TEST

    integer                        :: oflag, mode

    !Set oflag to O_CREAT|O_RDWR
    oflag = 66   
    mode = 600 

    call test2("test.txt", oflag, mode)

END PROGRAM

test.c:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>

#pragma weak test2_     = test2
#pragma weak test2__    = test2
#pragma weak TEST2      = test2

void test2(char* filename, int* flag, int* mode)
{
    int fd; 
    if(-1 == (fd = open(filename, *flag, *mode)))
        puts("Returned -1");
}

I compile as:

gcc -c test.c
gfortran main.f90 test.o

When I run the program, it creates the file test.txt, but with incorrect permissions:

---x--x--T 1 xyz users    0 2011-09-24 16:40 test.txt

when it should have been

-rw------- 1 xyz users    0 2011-09-24 16:45 test.txt

If I call this function from another C program, it works fine. Can someone point out what is going wrong?

Specs: 64 bit linux GNU Fortran (SUSE Linux) 4.5.0, GCC (SUSE Linux) 4.5.0

Thanks, Kshitij

Upvotes: 0

Views: 646

Answers (3)

M. S. B.
M. S. B.

Reputation: 29401

Here is an example using the Fortran ISO C Binding for a standard & portable interface between the Fortran and C portions. On my computer I found O_CREAT|O_RDWR to have a different value, i.e., 514, so setting flag to a specific value is not portable.

PROGRAM TEST

    use iso_c_binding

    implicit none

    interface test2_interface

       subroutine test2 ( filename, flag, mode )  bind (C, name="test2")

       import

       character (kind=c_char, len=1), dimension (100), intent (in) :: filename
       integer (c_int), intent (in), VALUE :: flag, mode

       end subroutine test2

    end interface test2_interface


    integer (c_int) :: oflag, mode
    character (kind=c_char, len=100) :: filename


    !Set oflag to O_CREAT|O_RDWR
    oflag = 66  ! incorrect value ... not used
    mode = int ( o'600', c_int)

    filename = "test.txt" // C_NULL_CHAR

    call test2 (filename, oflag, mode)

END PROGRAM

and

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>

void test2(char* filename, int flag, int mode)
{
    int fd;
    printf ( "filename = '%s'\n", filename );
    flag = O_CREAT | O_RDWR;
    printf ( "flag = %d\n", flag );
    printf ( "mode = octal %o\n", mode );
    if(-1 == (fd = open(filename, flag, mode)))
        puts("Returned -1");
}

Upvotes: 2

John Flatness
John Flatness

Reputation: 33809

open expects you to give it a value for the mode in octal, not decimal (this is why you basically always see an extra leading zero when dealing with modes in C code, since in C you write an octal literal with a leading zero).

600 in decimal is 1130 in octal. 1130 would correspond to ---x-wx--T, and you likely have a umask of 022, leaving you with ---x--x--T.

I believe you can specify an octal value in Fortran like this: o'600' (that's the letter o and then the octal value inside single quotes). Or, as David Schwartz suggested in his answer, you can just use the decimal equivalent of the mode you want. That's likely to be confusing when you look back at it later, though.

Edit: M. S. B. has pointed out that, while GNU Fortran may be more permissive, to comply with the standard you'd have to declare an octal constant in a data statement or (since Fortran 2003) as int(o'600').

Upvotes: 2

David Schwartz
David Schwartz

Reputation: 182865

Your constants are wrong because permissions are typically specified in octal. Try this program:

#include <stdio.h>
#include <fcntl.h>

int main(void)
{
 printf("oflag=%d mode=%d\n", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
}

I get:

oflag=66 mode=384

600 octal eqals 384 decimal.

Upvotes: 5

Related Questions