From fe046210e2d5fa3ac4c0d0d5d48f6851b1dcbe24 Mon Sep 17 00:00:00 2001 From: Francois-Xavier Coudert Date: Thu, 20 Sep 2007 22:56:48 +0000 Subject: [PATCH] re PR libfortran/23272 ([mingw32] inquire via filename fails) PR libfortran/23272 * io/unix.c (id_from_handle, id_from_path, id_from_fd): New functions. (compare_file_filename, find_file, find_file0): Use the new functions above. * gfortran.dg/inquire_10.f90: New test. From-SVN: r128636 --- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gfortran.dg/inquire_10.f90 | 16 ++++ libgfortran/ChangeLog | 8 ++ libgfortran/io/unix.c | 94 +++++++++++++++++++++++- 4 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/inquire_10.f90 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e641604870e..a11d20b96f0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-09-21 Francois-Xavier Coudert + + PR libfortran/23272 + * gfortran.dg/inquire_10.f90: New test. + 2007-09-20 Joseph Myers * gcc.dg/c99-bool-2.c, gcc.dg/c99-bool-3.c: New tests. diff --git a/gcc/testsuite/gfortran.dg/inquire_10.f90 b/gcc/testsuite/gfortran.dg/inquire_10.f90 new file mode 100644 index 00000000000..5343f2b3a08 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/inquire_10.f90 @@ -0,0 +1,16 @@ + character(len=800) :: cwd + integer :: unit + + call getcwd(cwd) + + open(file='cseq', unit=23) + inquire(file='cseq',number=unit) + if (unit /= 23) call abort + inquire(file=trim(cwd) // '/cseq',number=unit) + if (unit /= 23) call abort + + inquire(file='foo/../cseq2',number=unit) + if (unit >= 0) call abort + inquire(file='cseq2',number=unit) + if (unit >= 0) call abort +end diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 1addbb746fc..337d2e17555 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,11 @@ +2007-09-21 Francois-Xavier Coudert + + PR libfortran/23272 + * io/unix.c (id_from_handle, id_from_path, id_from_fd): New + functions. + (compare_file_filename, find_file, find_file0): Use the new + functions above. + 2007-09-21 Francois-Xavier Coudert * acinclude.m4 (LIBGFOR_TARGET_ILP32): Remove test. diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 6cb578f1cc0..9b61507e274 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -42,6 +42,59 @@ Boston, MA 02110-1301, USA. */ #include #include + +/* For mingw, we don't identify files by their inode number, but by a + 64-bit identifier created from a BY_HANDLE_FILE_INFORMATION. */ +#if defined(__MINGW32__) && !HAVE_WORKING_STAT + +#define WIN32_LEAN_AND_MEAN +#include + +static uint64_t +id_from_handle (HANDLE hFile) +{ + BY_HANDLE_FILE_INFORMATION FileInformation; + + if (hFile == INVALID_HANDLE_VALUE) + return 0; + + memset (&FileInformation, 0, sizeof(FileInformation)); + if (!GetFileInformationByHandle (hFile, &FileInformation)) + return 0; + + return ((uint64_t) FileInformation.nFileIndexLow) + | (((uint64_t) FileInformation.nFileIndexHigh) << 32); +} + + +static uint64_t +id_from_path (const char *path) +{ + HANDLE hFile; + uint64_t res; + + if (!path || !*path || access (path, F_OK)) + return (uint64_t) -1; + + hFile = CreateFile (path, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, + NULL); + res = id_from_handle (hFile); + CloseHandle (hFile); + return res; +} + + +static uint64_t +id_from_fd (const int fd) +{ + return id_from_handle ((HANDLE) _get_osfhandle (fd)); +} + +#endif + + + #ifndef SSIZE_MAX #define SSIZE_MAX SHRT_MAX #endif @@ -1444,6 +1497,10 @@ compare_file_filename (gfc_unit *u, const char *name, int len) struct stat st1; #ifdef HAVE_WORKING_STAT struct stat st2; +#else +# ifdef __MINGW32__ + uint64_t id1, id2; +# endif #endif if (unpack_filename (path, name, len)) @@ -1459,6 +1516,17 @@ compare_file_filename (gfc_unit *u, const char *name, int len) fstat (((unix_stream *) (u->s))->fd, &st2); return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino); #else + +# ifdef __MINGW32__ + /* We try to match files by a unique ID. On some filesystems (network + fs and FAT), we can't generate this unique ID, and will simply compare + filenames. */ + id1 = id_from_path (path); + id2 = id_from_fd (((unix_stream *) (u->s))->fd); + if (id1 || id2) + return (id1 == id2); +# endif + if (len != u->file_len) return 0; return (memcmp(path, u->file, len) == 0); @@ -1470,8 +1538,8 @@ compare_file_filename (gfc_unit *u, const char *name, int len) # define FIND_FILE0_DECL struct stat *st # define FIND_FILE0_ARGS st #else -# define FIND_FILE0_DECL const char *file, gfc_charlen_type file_len -# define FIND_FILE0_ARGS file, file_len +# define FIND_FILE0_DECL uint64_t id, const char *file, gfc_charlen_type file_len +# define FIND_FILE0_ARGS id, file, file_len #endif /* find_file0()-- Recursive work function for find_file() */ @@ -1480,6 +1548,9 @@ static gfc_unit * find_file0 (gfc_unit *u, FIND_FILE0_DECL) { gfc_unit *v; +#if defined(__MINGW32__) && !HAVE_WORKING_STAT + uint64_t id1; +#endif if (u == NULL) return NULL; @@ -1490,8 +1561,16 @@ find_file0 (gfc_unit *u, FIND_FILE0_DECL) st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino) return u; #else - if (compare_string (u->file_len, u->file, file_len, file) == 0) - return u; +# ifdef __MINGW32__ + if (u->s && ((id1 = id_from_fd (((unix_stream *) u->s)->fd)) || id1)) + { + if (id == id1) + return u; + } + else +# endif + if (compare_string (u->file_len, u->file, file_len, file) == 0) + return u; #endif v = find_file0 (u->left, FIND_FILE0_ARGS); @@ -1515,6 +1594,7 @@ find_file (const char *file, gfc_charlen_type file_len) char path[PATH_MAX + 1]; struct stat st[2]; gfc_unit *u; + uint64_t id; if (unpack_filename (path, file, file_len)) return NULL; @@ -1522,6 +1602,12 @@ find_file (const char *file, gfc_charlen_type file_len) if (stat (path, &st[0]) < 0) return NULL; +#if defined(__MINGW32__) && !HAVE_WORKING_STAT + id = id_from_path (path); +#else + id = 0; +#endif + __gthread_mutex_lock (&unit_lock); retry: u = find_file0 (unit_root, FIND_FILE0_ARGS); -- 2.30.2