Reputation: 3747
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
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
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
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