Pat Galea
2003-11-25 16:04:15 UTC
I'm trying to open a file for read-only access using CreateFile(),
then convert the Windows file handle to a file descriptor (suitable
for use by functions such as read()). [1]
The following test program demonstrates what I'm trying to do:
int main(void)
{
int fd;
char c;
HANDLE hFile;
HANDLE hFile2;
hFile = CreateFile("C:\\home\\try\\junk.txt",
GENERIC_READ,
0, // no sharing
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed\n");
fd = -1;
}
else
{
// Get the file descriptor from the handle
fd = _open_osfhandle((long)hFile, O_RDONLY);
printf("File descriptor = %d\n",fd);
// Get the handle from the file descriptor
hFile2 = (void*) _get_osfhandle(fd);
printf("hFile = %d, hFile2 = %d\n",hFile,hFile2);
if (hFile == hFile2)
printf("Handles match\n");
else
printf("Handles don't match\n");
// Do a simple dump of the file contents
if (fd>0)
{
lseek(fd,0,0);
printf("File contents:\n");
while (read(fd, &c, 1) == 1)
printf("%c",c);
printf("\n");
if (errno>0)
perror("Error: ");
}
}
return 0;
}
When I build this in Visual C++ 6.0 (with all the MFC stuff), it runs
exactly as expected, dumping the file contents to the screen.
When I build it in Cygwin, the _open_osfhandle() call produces a
valid-looking fd (3), but it doesn't appear to work; the
_get_osfhandle() doesn't successfully convert it back to a handle, and
the read() call fails ("Bad file descriptor").
I don't know why it's a problem in Cygwin.
One area of suspicion I have is the way I've linked with the msvcrt
library (C++ run-time library). Linking with the libmsvcrt.a library
in /lib (I think it's actually from MinGW) doesn't satisfy the symbol
_open_osfhandle, even though running nm on the library shows that it
is in there.
So what I did (and I can hear the shrieks already ;-) ) is this:
In /lib, I did:
ln -s /c/WINNT/system32/msvcrt.dll libnewmsvcrt.a
Then in the gcc line, I added -lnewmsvcrt. This works, in that the
code builds successfully. The _open_osfhandle() call produces a fd
that looks right, so this method of linking isn't obviously absurd.
However, it does feels really 'filthy' to me, but I couldn't find a
way to use the actual libmsvcrt.a. If you know of a solution to this
problem, I'd be most grateful.
And if you know what's going on with my file descriptor problem,
please let me know.
Many thanks
Pat Galea
[1] I realise this might appear to be an odd thing to want to do. I'm
updating some code to support long paths. Currently, files are opened
by calling open() (which returns the file descriptor), but
unfortunately there isn't an open() equivalent which supports long
paths, so I'm stuck with using CreateFileW(), which only returns the
handle. The problems I describe in this post occur with both
CreateFile() and CreateFileW(), so I figured I'd better solve it for
normal paths before I tackle the other problem. Eliminate variables,
and all that.
then convert the Windows file handle to a file descriptor (suitable
for use by functions such as read()). [1]
The following test program demonstrates what I'm trying to do:
int main(void)
{
int fd;
char c;
HANDLE hFile;
HANDLE hFile2;
hFile = CreateFile("C:\\home\\try\\junk.txt",
GENERIC_READ,
0, // no sharing
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile failed\n");
fd = -1;
}
else
{
// Get the file descriptor from the handle
fd = _open_osfhandle((long)hFile, O_RDONLY);
printf("File descriptor = %d\n",fd);
// Get the handle from the file descriptor
hFile2 = (void*) _get_osfhandle(fd);
printf("hFile = %d, hFile2 = %d\n",hFile,hFile2);
if (hFile == hFile2)
printf("Handles match\n");
else
printf("Handles don't match\n");
// Do a simple dump of the file contents
if (fd>0)
{
lseek(fd,0,0);
printf("File contents:\n");
while (read(fd, &c, 1) == 1)
printf("%c",c);
printf("\n");
if (errno>0)
perror("Error: ");
}
}
return 0;
}
When I build this in Visual C++ 6.0 (with all the MFC stuff), it runs
exactly as expected, dumping the file contents to the screen.
When I build it in Cygwin, the _open_osfhandle() call produces a
valid-looking fd (3), but it doesn't appear to work; the
_get_osfhandle() doesn't successfully convert it back to a handle, and
the read() call fails ("Bad file descriptor").
I don't know why it's a problem in Cygwin.
One area of suspicion I have is the way I've linked with the msvcrt
library (C++ run-time library). Linking with the libmsvcrt.a library
in /lib (I think it's actually from MinGW) doesn't satisfy the symbol
_open_osfhandle, even though running nm on the library shows that it
is in there.
So what I did (and I can hear the shrieks already ;-) ) is this:
In /lib, I did:
ln -s /c/WINNT/system32/msvcrt.dll libnewmsvcrt.a
Then in the gcc line, I added -lnewmsvcrt. This works, in that the
code builds successfully. The _open_osfhandle() call produces a fd
that looks right, so this method of linking isn't obviously absurd.
However, it does feels really 'filthy' to me, but I couldn't find a
way to use the actual libmsvcrt.a. If you know of a solution to this
problem, I'd be most grateful.
And if you know what's going on with my file descriptor problem,
please let me know.
Many thanks
Pat Galea
[1] I realise this might appear to be an odd thing to want to do. I'm
updating some code to support long paths. Currently, files are opened
by calling open() (which returns the file descriptor), but
unfortunately there isn't an open() equivalent which supports long
paths, so I'm stuck with using CreateFileW(), which only returns the
handle. The problems I describe in this post occur with both
CreateFile() and CreateFileW(), so I figured I'd better solve it for
normal paths before I tackle the other problem. Eliminate variables,
and all that.