]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/io/unix.c
2012-04-15 Janus Weil <janus@gcc.gnu.org>
[thirdparty/gcc.git] / libgfortran / io / unix.c
CommitLineData
e213d8e0 1/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
33123ed7 2 2011, 2012
a0007dfa 3 Free Software Foundation, Inc.
4ee9c684 4 Contributed by Andy Vaught
84d33b91 5 F2003 I/O support contributed by Jerry DeLisle
4ee9c684 6
5e62a3cc 7This file is part of the GNU Fortran runtime library (libgfortran).
4ee9c684 8
9Libgfortran is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
6bc9506f 11the Free Software Foundation; either version 3, or (at your option)
4ee9c684 12any later version.
13
14Libgfortran is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
6bc9506f 19Under Section 7 of GPL version 3, you are granted additional
20permissions described in the GCC Runtime Library Exception, version
213.1, as published by the Free Software Foundation.
22
23You should have received a copy of the GNU General Public License and
24a copy of the GCC Runtime Library Exception along with this program;
25see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
26<http://www.gnu.org/licenses/>. */
4ee9c684 27
28/* Unix stream I/O module */
29
41f2d5e8 30#include "io.h"
f65f6629 31#include "unix.h"
4ee9c684 32#include <stdlib.h>
33#include <limits.h>
34
35#include <unistd.h>
36#include <sys/stat.h>
37#include <fcntl.h>
2639e4cd 38#include <assert.h>
4ee9c684 39
4ee9c684 40#include <string.h>
41#include <errno.h>
42
c0ecd33c 43
de28dd31 44/* min macro that evaluates its arguments only once. */
45#define min(a,b) \
46 ({ typeof (a) _a = (a); \
47 typeof (b) _b = (b); \
48 _a < _b ? _a : _b; })
49
50
c0ecd33c 51/* For mingw, we don't identify files by their inode number, but by a
52 64-bit identifier created from a BY_HANDLE_FILE_INFORMATION. */
7a4491a4 53#ifdef __MINGW32__
c0ecd33c 54
55#define WIN32_LEAN_AND_MEAN
56#include <windows.h>
57
f6854450 58#if !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64
59#undef lseek
4dbc0658 60#define lseek _lseeki64
f6854450 61#undef fstat
7a4491a4 62#define fstat _fstati64
f6854450 63#undef stat
7a4491a4 64#define stat _stati64
f6854450 65#endif
4dbc0658 66
7a4491a4 67#ifndef HAVE_WORKING_STAT
c0ecd33c 68static uint64_t
69id_from_handle (HANDLE hFile)
70{
71 BY_HANDLE_FILE_INFORMATION FileInformation;
72
73 if (hFile == INVALID_HANDLE_VALUE)
74 return 0;
75
76 memset (&FileInformation, 0, sizeof(FileInformation));
77 if (!GetFileInformationByHandle (hFile, &FileInformation))
78 return 0;
79
80 return ((uint64_t) FileInformation.nFileIndexLow)
81 | (((uint64_t) FileInformation.nFileIndexHigh) << 32);
82}
83
84
85static uint64_t
86id_from_path (const char *path)
87{
88 HANDLE hFile;
89 uint64_t res;
90
91 if (!path || !*path || access (path, F_OK))
92 return (uint64_t) -1;
93
94 hFile = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
95 FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
96 NULL);
97 res = id_from_handle (hFile);
98 CloseHandle (hFile);
99 return res;
100}
101
102
103static uint64_t
104id_from_fd (const int fd)
105{
106 return id_from_handle ((HANDLE) _get_osfhandle (fd));
107}
108
109#endif
7a4491a4 110#endif
111
4ee9c684 112#ifndef PATH_MAX
113#define PATH_MAX 1024
114#endif
115
7dfba97b 116/* These flags aren't defined on all targets (mingw32), so provide them
117 here. */
118#ifndef S_IRGRP
119#define S_IRGRP 0
120#endif
121
122#ifndef S_IWGRP
123#define S_IWGRP 0
124#endif
125
126#ifndef S_IROTH
127#define S_IROTH 0
128#endif
129
130#ifndef S_IWOTH
131#define S_IWOTH 0
132#endif
133
76c0a846 134
fb053cd1 135#ifndef HAVE_ACCESS
136
137#ifndef W_OK
138#define W_OK 2
139#endif
140
141#ifndef R_OK
142#define R_OK 4
143#endif
144
145#ifndef F_OK
146#define F_OK 0
147#endif
148
149/* Fallback implementation of access() on systems that don't have it.
150 Only modes R_OK, W_OK and F_OK are used in this file. */
151
152static int
153fallback_access (const char *path, int mode)
154{
398e846b 155 int fd;
156
157 if ((mode & R_OK) && (fd = open (path, O_RDONLY)) < 0)
fb053cd1 158 return -1;
398e846b 159 close (fd);
fb053cd1 160
398e846b 161 if ((mode & W_OK) && (fd = open (path, O_WRONLY)) < 0)
fb053cd1 162 return -1;
398e846b 163 close (fd);
fb053cd1 164
165 if (mode == F_OK)
166 {
f6854450 167 struct stat st;
fb053cd1 168 return stat (path, &st);
169 }
170
171 return 0;
172}
173
174#undef access
175#define access fallback_access
176#endif
177
178
65f15010 179/* Unix and internal stream I/O module */
76c0a846 180
65f15010 181static const int BUFFER_SIZE = 8192;
76c0a846 182
3479b863 183typedef struct
184{
185 stream st;
186
187 gfc_offset buffer_offset; /* File offset of the start of the buffer */
188 gfc_offset physical_offset; /* Current physical file offset */
189 gfc_offset logical_offset; /* Current logical file offset */
cc65b133 190 gfc_offset file_length; /* Length of the file. */
3479b863 191
192 char *buffer; /* Pointer to the buffer. */
193 int fd; /* The POSIX file descriptor. */
194
195 int active; /* Length of valid bytes in the buffer */
196
197 int ndirty; /* Dirty bytes starting at buffer_offset */
198
01cd2c93 199 /* Cached stat(2) values. */
200 dev_t st_dev;
201 ino_t st_ino;
3479b863 202}
203unix_stream;
204
205
4ee9c684 206/* fix_fd()-- Given a file descriptor, make sure it is not one of the
207 * standard descriptors, returning a non-standard descriptor. If the
208 * user specifies that system errors should go to standard output,
209 * then closes standard output, we don't want the system errors to a
210 * file that has been given file descriptor 1 or 0. We want to send
211 * the error to the invalid descriptor. */
212
213static int
214fix_fd (int fd)
215{
e0582811 216#ifdef HAVE_DUP
4ee9c684 217 int input, output, error;
218
219 input = output = error = 0;
220
7145fd06 221 /* Unix allocates the lowest descriptors first, so a loop is not
222 required, but this order is. */
4ee9c684 223 if (fd == STDIN_FILENO)
224 {
225 fd = dup (fd);
226 input = 1;
227 }
228 if (fd == STDOUT_FILENO)
229 {
230 fd = dup (fd);
231 output = 1;
232 }
233 if (fd == STDERR_FILENO)
234 {
235 fd = dup (fd);
236 error = 1;
237 }
238
239 if (input)
240 close (STDIN_FILENO);
241 if (output)
242 close (STDOUT_FILENO);
243 if (error)
244 close (STDERR_FILENO);
e0582811 245#endif
4ee9c684 246
247 return fd;
248}
249
250
2488b3b6 251/* If the stream corresponds to a preconnected unit, we flush the
252 corresponding C stream. This is bugware for mixed C-Fortran codes
253 where the C code doesn't flush I/O before returning. */
254void
255flush_if_preconnected (stream * s)
256{
257 int fd;
258
259 fd = ((unix_stream *) s)->fd;
260 if (fd == STDIN_FILENO)
261 fflush (stdin);
262 else if (fd == STDOUT_FILENO)
263 fflush (stdout);
264 else if (fd == STDERR_FILENO)
265 fflush (stderr);
266}
267
4ee9c684 268
65f15010 269/********************************************************************
270Raw I/O functions (read, write, seek, tell, truncate, close).
271
272These functions wrap the basic POSIX I/O syscalls. Any deviation in
273semantics is a bug, except the following: write restarts in case
274of being interrupted by a signal, and as the first argument the
275functions take the unix_stream struct rather than an integer file
276descriptor. Also, for POSIX read() and write() a nbyte argument larger
277than SSIZE_MAX is undefined; here the type of nbyte is ssize_t rather
278than size_t as for POSIX read/write.
279*********************************************************************/
4ee9c684 280
b2a112ca 281static int
65f15010 282raw_flush (unix_stream * s __attribute__ ((unused)))
b2a112ca 283{
65f15010 284 return 0;
4ee9c684 285}
286
65f15010 287static ssize_t
288raw_read (unix_stream * s, void * buf, ssize_t nbyte)
289{
290 /* For read we can't do I/O in a loop like raw_write does, because
291 that will break applications that wait for interactive I/O. */
292 return read (s->fd, buf, nbyte);
293}
4ee9c684 294
65f15010 295static ssize_t
296raw_write (unix_stream * s, const void * buf, ssize_t nbyte)
4ee9c684 297{
65f15010 298 ssize_t trans, bytes_left;
b2a112ca 299 char *buf_st;
b2a112ca 300
65f15010 301 bytes_left = nbyte;
b2a112ca 302 buf_st = (char *) buf;
303
304 /* We must write in a loop since some systems don't restart system
305 calls in case of a signal. */
306 while (bytes_left > 0)
4ee9c684 307 {
65f15010 308 trans = write (s->fd, buf_st, bytes_left);
b2a112ca 309 if (trans < 0)
310 {
311 if (errno == EINTR)
312 continue;
313 else
65f15010 314 return trans;
b2a112ca 315 }
316 buf_st += trans;
317 bytes_left -= trans;
4ee9c684 318 }
319
65f15010 320 return nbyte - bytes_left;
4ee9c684 321}
4ee9c684 322
4dbc0658 323static gfc_offset
324raw_seek (unix_stream * s, gfc_offset offset, int whence)
65f15010 325{
326 return lseek (s->fd, offset, whence);
327}
4ee9c684 328
4dbc0658 329static gfc_offset
65f15010 330raw_tell (unix_stream * s)
331{
332 return lseek (s->fd, 0, SEEK_CUR);
333}
4ee9c684 334
41178014 335static gfc_offset
336raw_size (unix_stream * s)
337{
338 struct stat statbuf;
339 int ret = fstat (s->fd, &statbuf);
340 if (ret == -1)
341 return ret;
342 return statbuf.st_size;
343}
344
65f15010 345static int
4dbc0658 346raw_truncate (unix_stream * s, gfc_offset length)
4ee9c684 347{
4dbc0658 348#ifdef __MINGW32__
349 HANDLE h;
350 gfc_offset cur;
351
352 if (isatty (s->fd))
353 {
354 errno = EBADF;
355 return -1;
356 }
db23ac43 357 h = (HANDLE) _get_osfhandle (s->fd);
4dbc0658 358 if (h == INVALID_HANDLE_VALUE)
359 {
360 errno = EBADF;
361 return -1;
362 }
363 cur = lseek (s->fd, 0, SEEK_CUR);
364 if (cur == -1)
365 return -1;
366 if (lseek (s->fd, length, SEEK_SET) == -1)
367 goto error;
368 if (!SetEndOfFile (h))
369 {
370 errno = EBADF;
371 goto error;
372 }
373 if (lseek (s->fd, cur, SEEK_SET) == -1)
374 return -1;
375 return 0;
376 error:
377 lseek (s->fd, cur, SEEK_SET);
378 return -1;
379#elif defined HAVE_FTRUNCATE
65f15010 380 return ftruncate (s->fd, length);
381#elif defined HAVE_CHSIZE
382 return chsize (s->fd, length);
383#else
384 runtime_error ("required ftruncate or chsize support not present");
385 return -1;
386#endif
4ee9c684 387}
388
65f15010 389static int
390raw_close (unix_stream * s)
391{
392 int retval;
393
8b89aa85 394 if (s->fd != STDOUT_FILENO
395 && s->fd != STDERR_FILENO
396 && s->fd != STDIN_FILENO)
397 retval = close (s->fd);
398 else
6ffeb312 399 retval = 0;
5e62a3cc 400 free (s);
65f15010 401 return retval;
402}
4ee9c684 403
292d5498 404static const struct stream_vtable raw_vtable = {
405 .read = (void *) raw_read,
406 .write = (void *) raw_write,
407 .seek = (void *) raw_seek,
408 .tell = (void *) raw_tell,
409 .size = (void *) raw_size,
410 .trunc = (void *) raw_truncate,
411 .close = (void *) raw_close,
412 .flush = (void *) raw_flush
413};
414
65f15010 415static int
416raw_init (unix_stream * s)
417{
292d5498 418 s->st.vptr = &raw_vtable;
4ee9c684 419
65f15010 420 s->buffer = NULL;
421 return 0;
422}
b2a112ca 423
4ee9c684 424
65f15010 425/*********************************************************************
426Buffered I/O functions. These functions have the same semantics as the
427raw I/O functions above, except that they are buffered in order to
428improve performance. The buffer must be flushed when switching from
cc65b133 429reading to writing and vice versa. Only supported for regular files.
65f15010 430*********************************************************************/
431
432static int
433buf_flush (unix_stream * s)
4ee9c684 434{
65f15010 435 int writelen;
436
437 /* Flushing in read mode means discarding read bytes. */
438 s->active = 0;
b2a112ca 439
4ee9c684 440 if (s->ndirty == 0)
65f15010 441 return 0;
352597f9 442
cc65b133 443 if (s->physical_offset != s->buffer_offset
65f15010 444 && lseek (s->fd, s->buffer_offset, SEEK_SET) < 0)
445 return -1;
4ee9c684 446
65f15010 447 writelen = raw_write (s, s->buffer, s->ndirty);
4ee9c684 448
65f15010 449 s->physical_offset = s->buffer_offset + writelen;
5a78b88f 450
cc65b133 451 if (s->physical_offset > s->file_length)
65f15010 452 s->file_length = s->physical_offset;
b2a112ca 453
454 s->ndirty -= writelen;
455 if (s->ndirty != 0)
65f15010 456 return -1;
4ee9c684 457
65f15010 458 return 0;
4ee9c684 459}
460
65f15010 461static ssize_t
462buf_read (unix_stream * s, void * buf, ssize_t nbyte)
4ee9c684 463{
65f15010 464 if (s->active == 0)
465 s->buffer_offset = s->logical_offset;
5d5f00d5 466
65f15010 467 /* Is the data we want in the buffer? */
468 if (s->logical_offset + nbyte <= s->buffer_offset + s->active
469 && s->buffer_offset <= s->logical_offset)
470 memcpy (buf, s->buffer + (s->logical_offset - s->buffer_offset), nbyte);
5d5f00d5 471 else
472 {
65f15010 473 /* First copy the active bytes if applicable, then read the rest
474 either directly or filling the buffer. */
475 char *p;
476 int nread = 0;
477 ssize_t to_read, did_read;
478 gfc_offset new_logical;
479
480 p = (char *) buf;
481 if (s->logical_offset >= s->buffer_offset
482 && s->buffer_offset + s->active >= s->logical_offset)
483 {
484 nread = s->active - (s->logical_offset - s->buffer_offset);
485 memcpy (buf, s->buffer + (s->logical_offset - s->buffer_offset),
486 nread);
487 p += nread;
488 }
489 /* At this point we consider all bytes in the buffer discarded. */
490 to_read = nbyte - nread;
491 new_logical = s->logical_offset + nread;
cc65b133 492 if (s->physical_offset != new_logical
65f15010 493 && lseek (s->fd, new_logical, SEEK_SET) < 0)
494 return -1;
495 s->buffer_offset = s->physical_offset = new_logical;
496 if (to_read <= BUFFER_SIZE/2)
497 {
498 did_read = raw_read (s, s->buffer, BUFFER_SIZE);
499 s->physical_offset += did_read;
500 s->active = did_read;
501 did_read = (did_read > to_read) ? to_read : did_read;
502 memcpy (p, s->buffer, did_read);
503 }
504 else
505 {
506 did_read = raw_read (s, p, to_read);
507 s->physical_offset += did_read;
508 s->active = 0;
509 }
510 nbyte = did_read + nread;
4ee9c684 511 }
65f15010 512 s->logical_offset += nbyte;
513 return nbyte;
4ee9c684 514}
515
65f15010 516static ssize_t
517buf_write (unix_stream * s, const void * buf, ssize_t nbyte)
4ee9c684 518{
65f15010 519 if (s->ndirty == 0)
520 s->buffer_offset = s->logical_offset;
521
522 /* Does the data fit into the buffer? As a special case, if the
523 buffer is empty and the request is bigger than BUFFER_SIZE/2,
524 write directly. This avoids the case where the buffer would have
525 to be flushed at every write. */
526 if (!(s->ndirty == 0 && nbyte > BUFFER_SIZE/2)
527 && s->logical_offset + nbyte <= s->buffer_offset + BUFFER_SIZE
528 && s->buffer_offset <= s->logical_offset
529 && s->buffer_offset + s->ndirty >= s->logical_offset)
fef3501c 530 {
65f15010 531 memcpy (s->buffer + (s->logical_offset - s->buffer_offset), buf, nbyte);
532 int nd = (s->logical_offset - s->buffer_offset) + nbyte;
533 if (nd > s->ndirty)
534 s->ndirty = nd;
fef3501c 535 }
536 else
537 {
65f15010 538 /* Flush, and either fill the buffer with the new data, or if
539 the request is bigger than the buffer size, write directly
540 bypassing the buffer. */
541 buf_flush (s);
542 if (nbyte <= BUFFER_SIZE/2)
543 {
544 memcpy (s->buffer, buf, nbyte);
545 s->buffer_offset = s->logical_offset;
546 s->ndirty += nbyte;
547 }
548 else
35a97371 549 {
cc65b133 550 if (s->physical_offset != s->logical_offset)
35a97371 551 {
552 if (lseek (s->fd, s->logical_offset, SEEK_SET) < 0)
553 return -1;
554 s->physical_offset = s->logical_offset;
555 }
556
557 nbyte = raw_write (s, buf, nbyte);
558 s->physical_offset += nbyte;
559 }
4ee9c684 560 }
65f15010 561 s->logical_offset += nbyte;
cc65b133 562 if (s->logical_offset > s->file_length)
65f15010 563 s->file_length = s->logical_offset;
564 return nbyte;
4ee9c684 565}
566
4dbc0658 567static gfc_offset
568buf_seek (unix_stream * s, gfc_offset offset, int whence)
4ee9c684 569{
65f15010 570 switch (whence)
352597f9 571 {
65f15010 572 case SEEK_SET:
573 break;
574 case SEEK_CUR:
575 offset += s->logical_offset;
576 break;
577 case SEEK_END:
578 offset += s->file_length;
579 break;
580 default:
581 return -1;
352597f9 582 }
65f15010 583 if (offset < 0)
72909c79 584 {
65f15010 585 errno = EINVAL;
586 return -1;
72909c79 587 }
65f15010 588 s->logical_offset = offset;
589 return offset;
4ee9c684 590}
591
4dbc0658 592static gfc_offset
65f15010 593buf_tell (unix_stream * s)
56f281a2 594{
f22f0b38 595 return buf_seek (s, 0, SEEK_CUR);
56f281a2 596}
b2a112ca 597
41178014 598static gfc_offset
599buf_size (unix_stream * s)
600{
601 return s->file_length;
602}
603
b2a112ca 604static int
4dbc0658 605buf_truncate (unix_stream * s, gfc_offset length)
b2a112ca 606{
65f15010 607 int r;
b2a112ca 608
65f15010 609 if (buf_flush (s) != 0)
610 return -1;
611 r = raw_truncate (s, length);
612 if (r == 0)
613 s->file_length = length;
614 return r;
b2a112ca 615}
616
b2a112ca 617static int
65f15010 618buf_close (unix_stream * s)
4ee9c684 619{
65f15010 620 if (buf_flush (s) != 0)
621 return -1;
5e62a3cc 622 free (s->buffer);
65f15010 623 return raw_close (s);
4ee9c684 624}
625
292d5498 626static const struct stream_vtable buf_vtable = {
627 .read = (void *) buf_read,
628 .write = (void *) buf_write,
629 .seek = (void *) buf_seek,
630 .tell = (void *) buf_tell,
631 .size = (void *) buf_size,
632 .trunc = (void *) buf_truncate,
633 .close = (void *) buf_close,
634 .flush = (void *) buf_flush
635};
636
65f15010 637static int
638buf_init (unix_stream * s)
4ee9c684 639{
292d5498 640 s->st.vptr = &buf_vtable;
4ee9c684 641
25c067ae 642 s->buffer = xmalloc (BUFFER_SIZE);
65f15010 643 return 0;
4ee9c684 644}
645
646
4ee9c684 647/*********************************************************************
648 memory stream functions - These are used for internal files
649
650 The idea here is that a single stream structure is created and all
651 requests must be satisfied from it. The location and size of the
652 buffer is the character variable supplied to the READ or WRITE
653 statement.
654
655*********************************************************************/
656
65f15010 657char *
658mem_alloc_r (stream * strm, int * len)
4ee9c684 659{
65f15010 660 unix_stream * s = (unix_stream *) strm;
b093181d 661 gfc_offset n;
d875179d 662 gfc_offset where = s->logical_offset;
4ee9c684 663
664 if (where < s->buffer_offset || where > s->buffer_offset + s->active)
665 return NULL;
666
11de4bf9 667 n = s->buffer_offset + s->active - where;
4ee9c684 668 if (*len > n)
669 *len = n;
670
65f15010 671 s->logical_offset = where + *len;
672
4ee9c684 673 return s->buffer + (where - s->buffer_offset);
674}
675
676
e0aaacb7 677char *
678mem_alloc_r4 (stream * strm, int * len)
679{
680 unix_stream * s = (unix_stream *) strm;
681 gfc_offset n;
682 gfc_offset where = s->logical_offset;
683
684 if (where < s->buffer_offset || where > s->buffer_offset + s->active)
685 return NULL;
686
687 n = s->buffer_offset + s->active - where;
688 if (*len > n)
689 *len = n;
690
691 s->logical_offset = where + *len;
692
693 return s->buffer + (where - s->buffer_offset) * 4;
694}
695
696
65f15010 697char *
698mem_alloc_w (stream * strm, int * len)
4ee9c684 699{
65f15010 700 unix_stream * s = (unix_stream *) strm;
b093181d 701 gfc_offset m;
d875179d 702 gfc_offset where = s->logical_offset;
4ee9c684 703
4ee9c684 704 m = where + *len;
705
2639e4cd 706 if (where < s->buffer_offset)
4ee9c684 707 return NULL;
708
2639e4cd 709 if (m > s->file_length)
72231bd6 710 return NULL;
2639e4cd 711
4ee9c684 712 s->logical_offset = m;
713
714 return s->buffer + (where - s->buffer_offset);
715}
716
717
1bb7bffb 718gfc_char4_t *
e0aaacb7 719mem_alloc_w4 (stream * strm, int * len)
720{
721 unix_stream * s = (unix_stream *) strm;
722 gfc_offset m;
723 gfc_offset where = s->logical_offset;
1bb7bffb 724 gfc_char4_t *result = (gfc_char4_t *) s->buffer;
e0aaacb7 725
726 m = where + *len;
727
728 if (where < s->buffer_offset)
729 return NULL;
730
731 if (m > s->file_length)
732 return NULL;
733
734 s->logical_offset = m;
1bb7bffb 735 return &result[where - s->buffer_offset];
e0aaacb7 736}
737
738
739/* Stream read function for character(kine=1) internal units. */
b2a112ca 740
65f15010 741static ssize_t
742mem_read (stream * s, void * buf, ssize_t nbytes)
b2a112ca 743{
744 void *p;
65f15010 745 int nb = nbytes;
b2a112ca 746
65f15010 747 p = mem_alloc_r (s, &nb);
b2a112ca 748 if (p)
749 {
65f15010 750 memcpy (buf, p, nb);
751 return (ssize_t) nb;
b2a112ca 752 }
753 else
65f15010 754 return 0;
b2a112ca 755}
756
757
e0aaacb7 758/* Stream read function for chracter(kind=4) internal units. */
759
760static ssize_t
761mem_read4 (stream * s, void * buf, ssize_t nbytes)
762{
763 void *p;
764 int nb = nbytes;
765
766 p = mem_alloc_r (s, &nb);
767 if (p)
768 {
769 memcpy (buf, p, nb);
770 return (ssize_t) nb;
771 }
772 else
773 return 0;
774}
775
776
777/* Stream write function for character(kind=1) internal units. */
b2a112ca 778
65f15010 779static ssize_t
780mem_write (stream * s, const void * buf, ssize_t nbytes)
b2a112ca 781{
782 void *p;
65f15010 783 int nb = nbytes;
b2a112ca 784
65f15010 785 p = mem_alloc_w (s, &nb);
b2a112ca 786 if (p)
787 {
65f15010 788 memcpy (p, buf, nb);
789 return (ssize_t) nb;
b2a112ca 790 }
791 else
65f15010 792 return 0;
b2a112ca 793}
794
795
e0aaacb7 796/* Stream write function for character(kind=4) internal units. */
797
798static ssize_t
799mem_write4 (stream * s, const void * buf, ssize_t nwords)
800{
801 gfc_char4_t *p;
802 int nw = nwords;
803
1bb7bffb 804 p = mem_alloc_w4 (s, &nw);
e0aaacb7 805 if (p)
806 {
807 while (nw--)
808 *p++ = (gfc_char4_t) *((char *) buf);
809 return nwords;
810 }
811 else
812 return 0;
813}
814
815
4dbc0658 816static gfc_offset
817mem_seek (stream * strm, gfc_offset offset, int whence)
4ee9c684 818{
65f15010 819 unix_stream * s = (unix_stream *) strm;
820 switch (whence)
821 {
822 case SEEK_SET:
823 break;
824 case SEEK_CUR:
825 offset += s->logical_offset;
826 break;
827 case SEEK_END:
828 offset += s->file_length;
829 break;
830 default:
831 return -1;
832 }
833
834 /* Note that for internal array I/O it's actually possible to have a
835 negative offset, so don't check for that. */
4ee9c684 836 if (offset > s->file_length)
837 {
65f15010 838 errno = EINVAL;
839 return -1;
4ee9c684 840 }
841
842 s->logical_offset = offset;
65f15010 843
844 /* Returning < 0 is the error indicator for sseek(), so return 0 if
845 offset is negative. Thus if the return value is 0, the caller
846 has to use stell() to get the real value of logical_offset. */
847 if (offset >= 0)
848 return offset;
849 return 0;
4ee9c684 850}
851
852
4dbc0658 853static gfc_offset
65f15010 854mem_tell (stream * s)
56f281a2 855{
65f15010 856 return ((unix_stream *)s)->logical_offset;
56f281a2 857}
858
859
4ee9c684 860static int
65f15010 861mem_truncate (unix_stream * s __attribute__ ((unused)),
4dbc0658 862 gfc_offset length __attribute__ ((unused)))
4ee9c684 863{
65f15010 864 return 0;
4ee9c684 865}
866
867
65f15010 868static int
869mem_flush (unix_stream * s __attribute__ ((unused)))
4ee9c684 870{
65f15010 871 return 0;
4ee9c684 872}
873
874
65f15010 875static int
876mem_close (unix_stream * s)
4ee9c684 877{
dd045aee 878 free (s);
4ee9c684 879
65f15010 880 return 0;
881}
4ee9c684 882
292d5498 883static const struct stream_vtable mem_vtable = {
884 .read = (void *) mem_read,
885 .write = (void *) mem_write,
886 .seek = (void *) mem_seek,
887 .tell = (void *) mem_tell,
888 /* buf_size is not a typo, we just reuse an identical
889 implementation. */
890 .size = (void *) buf_size,
891 .trunc = (void *) mem_truncate,
892 .close = (void *) mem_close,
893 .flush = (void *) mem_flush
894};
895
896static const struct stream_vtable mem4_vtable = {
897 .read = (void *) mem_read4,
898 .write = (void *) mem_write4,
899 .seek = (void *) mem_seek,
900 .tell = (void *) mem_tell,
901 /* buf_size is not a typo, we just reuse an identical
902 implementation. */
903 .size = (void *) buf_size,
904 .trunc = (void *) mem_truncate,
905 .close = (void *) mem_close,
906 .flush = (void *) mem_flush
907};
4ee9c684 908
909/*********************************************************************
910 Public functions -- A reimplementation of this module needs to
911 define functional equivalents of the following.
912*********************************************************************/
913
e0aaacb7 914/* open_internal()-- Returns a stream structure from a character(kind=1)
915 internal file */
4ee9c684 916
917stream *
cf4abc57 918open_internal (char *base, int length, gfc_offset offset)
4ee9c684 919{
65f15010 920 unix_stream *s;
4ee9c684 921
33123ed7 922 s = xcalloc (1, sizeof (unix_stream));
4ee9c684 923
924 s->buffer = base;
cf4abc57 925 s->buffer_offset = offset;
4ee9c684 926
4ee9c684 927 s->active = s->file_length = length;
928
292d5498 929 s->st.vptr = &mem_vtable;
4ee9c684 930
e0aaacb7 931 return (stream *) s;
932}
933
934/* open_internal4()-- Returns a stream structure from a character(kind=4)
935 internal file */
936
937stream *
938open_internal4 (char *base, int length, gfc_offset offset)
939{
940 unix_stream *s;
941
33123ed7 942 s = xcalloc (1, sizeof (unix_stream));
e0aaacb7 943
944 s->buffer = base;
945 s->buffer_offset = offset;
946
e0aaacb7 947 s->active = s->file_length = length;
948
292d5498 949 s->st.vptr = &mem4_vtable;
e0aaacb7 950
4ee9c684 951 return (stream *) s;
952}
953
954
955/* fd_to_stream()-- Given an open file descriptor, build a stream
956 * around it. */
957
958static stream *
aadbd4ae 959fd_to_stream (int fd)
4ee9c684 960{
f6854450 961 struct stat statbuf;
4ee9c684 962 unix_stream *s;
963
33123ed7 964 s = xcalloc (1, sizeof (unix_stream));
4ee9c684 965
966 s->fd = fd;
4ee9c684 967
968 /* Get the current length of the file. */
969
970 fstat (fd, &statbuf);
352597f9 971
01cd2c93 972 s->st_dev = statbuf.st_dev;
973 s->st_ino = statbuf.st_ino;
cc65b133 974 s->file_length = statbuf.st_size;
975
976 /* Only use buffered IO for regular files. */
977 if (S_ISREG (statbuf.st_mode)
978 && !options.all_unbuffered
979 && !(options.unbuffered_preconnected &&
980 (s->fd == STDIN_FILENO
981 || s->fd == STDOUT_FILENO
982 || s->fd == STDERR_FILENO)))
983 buf_init (s);
9bfd25a7 984 else
65f15010 985 raw_init (s);
4ee9c684 986
987 return (stream *) s;
988}
989
990
771c1b50 991/* Given the Fortran unit number, convert it to a C file descriptor. */
992
993int
60c514ba 994unit_to_fd (int unit)
771c1b50 995{
771c1b50 996 gfc_unit *us;
60c514ba 997 int fd;
771c1b50 998
60c514ba 999 us = find_unit (unit);
771c1b50 1000 if (us == NULL)
1001 return -1;
1002
60c514ba 1003 fd = ((unix_stream *) us->s)->fd;
1004 unlock_unit (us);
1005 return fd;
771c1b50 1006}
1007
1008
4ee9c684 1009/* unpack_filename()-- Given a fortran string and a pointer to a
1010 * buffer that is PATH_MAX characters, convert the fortran string to a
1011 * C string in the buffer. Returns nonzero if this is not possible. */
1012
1dc95e51 1013int
4ee9c684 1014unpack_filename (char *cstring, const char *fstring, int len)
1015{
d6e40722 1016 if (fstring == NULL)
de28dd31 1017 return EFAULT;
4ee9c684 1018 len = fstrlen (fstring, len);
1019 if (len >= PATH_MAX)
de28dd31 1020 return ENAMETOOLONG;
4ee9c684 1021
1022 memmove (cstring, fstring, len);
1023 cstring[len] = '\0';
1024
1025 return 0;
1026}
1027
1028
1029/* tempfile()-- Generate a temporary filename for a scratch file and
1030 * open it. mkstemp() opens the file for reading and writing, but the
1031 * library mode prevents anything that is not allowed. The descriptor
7dfba97b 1032 * is returned, which is -1 on error. The template is pointed to by
60c514ba 1033 * opp->file, which is copied into the unit structure
4ee9c684 1034 * and freed later. */
1035
1036static int
60c514ba 1037tempfile (st_parameter_open *opp)
4ee9c684 1038{
1039 const char *tempdir;
1040 char *template;
db23ac43 1041 const char *slash = "/";
4ee9c684 1042 int fd;
d06c5aaa 1043 size_t tempdirlen;
1044
1045#ifndef HAVE_MKSTEMP
1046 int count;
1047 size_t slashlen;
1048#endif
4ee9c684 1049
1050 tempdir = getenv ("GFORTRAN_TMPDIR");
db23ac43 1051#ifdef __MINGW32__
1052 if (tempdir == NULL)
1053 {
1054 char buffer[MAX_PATH + 1];
1055 DWORD ret;
1056 ret = GetTempPath (MAX_PATH, buffer);
1057 /* If we are not able to get a temp-directory, we use
1058 current directory. */
1059 if (ret > MAX_PATH || !ret)
1060 buffer[0] = 0;
1061 else
1062 buffer[ret] = 0;
1063 tempdir = strdup (buffer);
1064 }
1065#else
4ee9c684 1066 if (tempdir == NULL)
1067 tempdir = getenv ("TMP");
ac09d5cc 1068 if (tempdir == NULL)
1069 tempdir = getenv ("TEMP");
4ee9c684 1070 if (tempdir == NULL)
1071 tempdir = DEFAULT_TEMPDIR;
db23ac43 1072#endif
d06c5aaa 1073
db23ac43 1074 /* Check for special case that tempdir contains slash
1075 or backslash at end. */
d06c5aaa 1076 tempdirlen = strlen (tempdir);
1077 if (*tempdir == 0 || tempdir[tempdirlen - 1] == '/'
db23ac43 1078#ifdef __MINGW32__
d06c5aaa 1079 || tempdir[tempdirlen - 1] == '\\'
db23ac43 1080#endif
1081 )
1082 slash = "";
4ee9c684 1083
d06c5aaa 1084 // Take care that the template is longer in the mktemp() branch.
25c067ae 1085 template = xmalloc (tempdirlen + 23);
4ee9c684 1086
7dfba97b 1087#ifdef HAVE_MKSTEMP
d151c82c 1088 snprintf (template, tempdirlen + 23, "%s%sgfortrantmpXXXXXX",
1089 tempdir, slash);
4ee9c684 1090
1091 fd = mkstemp (template);
1092
7dfba97b 1093#else /* HAVE_MKSTEMP */
726fd258 1094 fd = -1;
d06c5aaa 1095 count = 0;
1096 slashlen = strlen (slash);
726fd258 1097 do
1098 {
d151c82c 1099 snprintf (template, tempdirlen + 23, "%s%sgfortrantmpaaaXXXXXX",
1100 tempdir, slash);
d06c5aaa 1101 if (count > 0)
1102 {
1103 int c = count;
1104 template[tempdirlen + slashlen + 13] = 'a' + (c% 26);
1105 c /= 26;
1106 template[tempdirlen + slashlen + 12] = 'a' + (c % 26);
1107 c /= 26;
1108 template[tempdirlen + slashlen + 11] = 'a' + (c % 26);
1109 if (c >= 26)
1110 break;
1111 }
1112
726fd258 1113 if (!mktemp (template))
d06c5aaa 1114 {
1115 errno = EEXIST;
1116 count++;
1117 continue;
1118 }
1119
cf6a3896 1120#if defined(HAVE_CRLF) && defined(O_BINARY)
cf55c3cf 1121 fd = open (template, O_RDWR | O_CREAT | O_EXCL | O_BINARY,
ec55604a 1122 S_IRUSR | S_IWUSR);
cf55c3cf 1123#else
ec55604a 1124 fd = open (template, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
cf55c3cf 1125#endif
726fd258 1126 }
1127 while (fd == -1 && errno == EEXIST);
7dfba97b 1128#endif /* HAVE_MKSTEMP */
1129
e213d8e0 1130 opp->file = template;
1131 opp->file_len = strlen (template); /* Don't include trailing nul */
4ee9c684 1132
1133 return fd;
1134}
1135
1136
6d12c489 1137/* regular_file()-- Open a regular file.
2d6ba0f9 1138 * Change flags->action if it is ACTION_UNSPECIFIED on entry,
1139 * unless an error occurs.
6d12c489 1140 * Returns the descriptor, which is less than zero on error. */
4ee9c684 1141
1142static int
60c514ba 1143regular_file (st_parameter_open *opp, unit_flags *flags)
4ee9c684 1144{
de28dd31 1145 char path[min(PATH_MAX, opp->file_len + 1)];
4ee9c684 1146 int mode;
6d12c489 1147 int rwflag;
2d6ba0f9 1148 int crflag;
6d12c489 1149 int fd;
de28dd31 1150 int err;
4ee9c684 1151
de28dd31 1152 err = unpack_filename (path, opp->file, opp->file_len);
1153 if (err)
4ee9c684 1154 {
de28dd31 1155 errno = err; /* Fake an OS error */
4ee9c684 1156 return -1;
1157 }
1158
3d17984e 1159#ifdef __CYGWIN__
1160 if (opp->file_len == 7)
1161 {
1162 if (strncmp (path, "CONOUT$", 7) == 0
1163 || strncmp (path, "CONERR$", 7) == 0)
1164 {
1165 fd = open ("/dev/conout", O_WRONLY);
1166 flags->action = ACTION_WRITE;
1167 return fd;
1168 }
1169 }
1170
1171 if (opp->file_len == 6 && strncmp (path, "CONIN$", 6) == 0)
1172 {
1173 fd = open ("/dev/conin", O_RDONLY);
1174 flags->action = ACTION_READ;
1175 return fd;
1176 }
1177#endif
1178
2058bc7e 1179
1180#ifdef __MINGW32__
1181 if (opp->file_len == 7)
1182 {
1183 if (strncmp (path, "CONOUT$", 7) == 0
1184 || strncmp (path, "CONERR$", 7) == 0)
1185 {
1186 fd = open ("CONOUT$", O_WRONLY);
1187 flags->action = ACTION_WRITE;
1188 return fd;
1189 }
1190 }
1191
1192 if (opp->file_len == 6 && strncmp (path, "CONIN$", 6) == 0)
1193 {
1194 fd = open ("CONIN$", O_RDONLY);
1195 flags->action = ACTION_READ;
1196 return fd;
1197 }
1198#endif
1199
6d12c489 1200 rwflag = 0;
4ee9c684 1201
6d12c489 1202 switch (flags->action)
4ee9c684 1203 {
1204 case ACTION_READ:
6d12c489 1205 rwflag = O_RDONLY;
4ee9c684 1206 break;
1207
1208 case ACTION_WRITE:
6d12c489 1209 rwflag = O_WRONLY;
4ee9c684 1210 break;
1211
1212 case ACTION_READWRITE:
6d12c489 1213 case ACTION_UNSPECIFIED:
1214 rwflag = O_RDWR;
4ee9c684 1215 break;
1216
1217 default:
60c514ba 1218 internal_error (&opp->common, "regular_file(): Bad action");
4ee9c684 1219 }
1220
6d12c489 1221 switch (flags->status)
4ee9c684 1222 {
1223 case STATUS_NEW:
2d6ba0f9 1224 crflag = O_CREAT | O_EXCL;
4ee9c684 1225 break;
1226
2d6ba0f9 1227 case STATUS_OLD: /* open will fail if the file does not exist*/
1228 crflag = 0;
4ee9c684 1229 break;
1230
1231 case STATUS_UNKNOWN:
1232 case STATUS_SCRATCH:
2d6ba0f9 1233 crflag = O_CREAT;
4ee9c684 1234 break;
1235
1236 case STATUS_REPLACE:
a638be8f 1237 crflag = O_CREAT | O_TRUNC;
4ee9c684 1238 break;
1239
1240 default:
60c514ba 1241 internal_error (&opp->common, "regular_file(): Bad status");
4ee9c684 1242 }
1243
6d12c489 1244 /* rwflag |= O_LARGEFILE; */
4ee9c684 1245
cf6a3896 1246#if defined(HAVE_CRLF) && defined(O_BINARY)
cf55c3cf 1247 crflag |= O_BINARY;
1248#endif
1249
6d12c489 1250 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
2d6ba0f9 1251 fd = open (path, rwflag | crflag, mode);
1252 if (flags->action != ACTION_UNSPECIFIED)
a638be8f 1253 return fd;
2d6ba0f9 1254
1255 if (fd >= 0)
6d12c489 1256 {
2d6ba0f9 1257 flags->action = ACTION_READWRITE;
1258 return fd;
6d12c489 1259 }
a638be8f 1260 if (errno != EACCES && errno != EROFS)
2d6ba0f9 1261 return fd;
1262
1263 /* retry for read-only access */
1264 rwflag = O_RDONLY;
1265 fd = open (path, rwflag | crflag, mode);
1266 if (fd >=0)
1267 {
1268 flags->action = ACTION_READ;
84d33b91 1269 return fd; /* success */
2d6ba0f9 1270 }
1271
1272 if (errno != EACCES)
84d33b91 1273 return fd; /* failure */
2d6ba0f9 1274
1275 /* retry for write-only access */
1276 rwflag = O_WRONLY;
1277 fd = open (path, rwflag | crflag, mode);
1278 if (fd >=0)
1279 {
1280 flags->action = ACTION_WRITE;
84d33b91 1281 return fd; /* success */
2d6ba0f9 1282 }
84d33b91 1283 return fd; /* failure */
4ee9c684 1284}
1285
1286
1287/* open_external()-- Open an external file, unix specific version.
6d12c489 1288 * Change flags->action if it is ACTION_UNSPECIFIED on entry.
4ee9c684 1289 * Returns NULL on operating system error. */
1290
1291stream *
60c514ba 1292open_external (st_parameter_open *opp, unit_flags *flags)
4ee9c684 1293{
aadbd4ae 1294 int fd;
4ee9c684 1295
6d12c489 1296 if (flags->status == STATUS_SCRATCH)
1297 {
60c514ba 1298 fd = tempfile (opp);
6d12c489 1299 if (flags->action == ACTION_UNSPECIFIED)
84d33b91 1300 flags->action = ACTION_READWRITE;
1dc95e51 1301
1302#if HAVE_UNLINK_OPEN_FILE
6d12c489 1303 /* We can unlink scratch files now and it will go away when closed. */
60c514ba 1304 if (fd >= 0)
1305 unlink (opp->file);
1dc95e51 1306#endif
6d12c489 1307 }
1308 else
1309 {
2d6ba0f9 1310 /* regular_file resets flags->action if it is ACTION_UNSPECIFIED and
1311 * if it succeeds */
60c514ba 1312 fd = regular_file (opp, flags);
6d12c489 1313 }
4ee9c684 1314
1315 if (fd < 0)
1316 return NULL;
1317 fd = fix_fd (fd);
1318
aadbd4ae 1319 return fd_to_stream (fd);
4ee9c684 1320}
1321
1322
1323/* input_stream()-- Return a stream pointer to the default input stream.
1324 * Called on initialization. */
1325
1326stream *
1327input_stream (void)
1328{
aadbd4ae 1329 return fd_to_stream (STDIN_FILENO);
4ee9c684 1330}
1331
1332
ff81ee3b 1333/* output_stream()-- Return a stream pointer to the default output stream.
4ee9c684 1334 * Called on initialization. */
1335
1336stream *
1337output_stream (void)
1338{
3e45a719 1339 stream * s;
1340
e693d7f1 1341#if defined(HAVE_CRLF) && defined(HAVE_SETMODE)
1342 setmode (STDOUT_FILENO, O_BINARY);
1343#endif
3e45a719 1344
aadbd4ae 1345 s = fd_to_stream (STDOUT_FILENO);
3e45a719 1346 return s;
4ee9c684 1347}
1348
1349
ff81ee3b 1350/* error_stream()-- Return a stream pointer to the default error stream.
1351 * Called on initialization. */
1352
1353stream *
1354error_stream (void)
1355{
3e45a719 1356 stream * s;
1357
e693d7f1 1358#if defined(HAVE_CRLF) && defined(HAVE_SETMODE)
1359 setmode (STDERR_FILENO, O_BINARY);
1360#endif
3e45a719 1361
aadbd4ae 1362 s = fd_to_stream (STDERR_FILENO);
3e45a719 1363 return s;
ff81ee3b 1364}
1365
4ee9c684 1366
4ee9c684 1367/* compare_file_filename()-- Given an open stream and a fortran string
1368 * that is a filename, figure out if the file is the same as the
1369 * filename. */
1370
1371int
daad4fd5 1372compare_file_filename (gfc_unit *u, const char *name, int len)
4ee9c684 1373{
de28dd31 1374 char path[min(PATH_MAX, len + 1)];
f6854450 1375 struct stat st;
daad4fd5 1376#ifdef HAVE_WORKING_STAT
01cd2c93 1377 unix_stream *s;
c0ecd33c 1378#else
1379# ifdef __MINGW32__
1380 uint64_t id1, id2;
1381# endif
daad4fd5 1382#endif
4ee9c684 1383
1384 if (unpack_filename (path, name, len))
1385 return 0; /* Can't be the same */
1386
1387 /* If the filename doesn't exist, then there is no match with the
1388 * existing file. */
1389
01cd2c93 1390 if (stat (path, &st) < 0)
4ee9c684 1391 return 0;
1392
daad4fd5 1393#ifdef HAVE_WORKING_STAT
01cd2c93 1394 s = (unix_stream *) (u->s);
1395 return (st.st_dev == s->st_dev) && (st.st_ino == s->st_ino);
daad4fd5 1396#else
c0ecd33c 1397
1398# ifdef __MINGW32__
1399 /* We try to match files by a unique ID. On some filesystems (network
1400 fs and FAT), we can't generate this unique ID, and will simply compare
1401 filenames. */
1402 id1 = id_from_path (path);
1403 id2 = id_from_fd (((unix_stream *) (u->s))->fd);
1404 if (id1 || id2)
1405 return (id1 == id2);
1406# endif
1407
daad4fd5 1408 if (len != u->file_len)
1409 return 0;
1410 return (memcmp(path, u->file, len) == 0);
1411#endif
4ee9c684 1412}
1413
1414
60c514ba 1415#ifdef HAVE_WORKING_STAT
f6854450 1416# define FIND_FILE0_DECL struct stat *st
60c514ba 1417# define FIND_FILE0_ARGS st
1418#else
c0ecd33c 1419# define FIND_FILE0_DECL uint64_t id, const char *file, gfc_charlen_type file_len
1420# define FIND_FILE0_ARGS id, file, file_len
60c514ba 1421#endif
1422
4ee9c684 1423/* find_file0()-- Recursive work function for find_file() */
1424
f02dd226 1425static gfc_unit *
60c514ba 1426find_file0 (gfc_unit *u, FIND_FILE0_DECL)
4ee9c684 1427{
f02dd226 1428 gfc_unit *v;
c0ecd33c 1429#if defined(__MINGW32__) && !HAVE_WORKING_STAT
1430 uint64_t id1;
1431#endif
4ee9c684 1432
1433 if (u == NULL)
1434 return NULL;
1435
daad4fd5 1436#ifdef HAVE_WORKING_STAT
01cd2c93 1437 if (u->s != NULL)
1438 {
1439 unix_stream *s = (unix_stream *) (u->s);
1440 if (st[0].st_dev == s->st_dev && st[0].st_ino == s->st_ino)
1441 return u;
1442 }
daad4fd5 1443#else
c0ecd33c 1444# ifdef __MINGW32__
1445 if (u->s && ((id1 = id_from_fd (((unix_stream *) u->s)->fd)) || id1))
1446 {
1447 if (id == id1)
1448 return u;
1449 }
1450 else
1451# endif
1452 if (compare_string (u->file_len, u->file, file_len, file) == 0)
1453 return u;
daad4fd5 1454#endif
4ee9c684 1455
60c514ba 1456 v = find_file0 (u->left, FIND_FILE0_ARGS);
4ee9c684 1457 if (v != NULL)
1458 return v;
1459
60c514ba 1460 v = find_file0 (u->right, FIND_FILE0_ARGS);
4ee9c684 1461 if (v != NULL)
1462 return v;
1463
1464 return NULL;
1465}
1466
1467
1468/* find_file()-- Take the current filename and see if there is a unit
1469 * that has the file already open. Returns a pointer to the unit if so. */
1470
f02dd226 1471gfc_unit *
60c514ba 1472find_file (const char *file, gfc_charlen_type file_len)
4ee9c684 1473{
de28dd31 1474 char path[min(PATH_MAX, file_len + 1)];
f6854450 1475 struct stat st[1];
60c514ba 1476 gfc_unit *u;
c12dc7d7 1477#if defined(__MINGW32__) && !HAVE_WORKING_STAT
1478 uint64_t id = 0ULL;
1479#endif
4ee9c684 1480
60c514ba 1481 if (unpack_filename (path, file, file_len))
4ee9c684 1482 return NULL;
1483
60c514ba 1484 if (stat (path, &st[0]) < 0)
4ee9c684 1485 return NULL;
1486
c0ecd33c 1487#if defined(__MINGW32__) && !HAVE_WORKING_STAT
c12dc7d7 1488 id = id_from_path (path);
c0ecd33c 1489#endif
1490
60c514ba 1491 __gthread_mutex_lock (&unit_lock);
1492retry:
1493 u = find_file0 (unit_root, FIND_FILE0_ARGS);
1494 if (u != NULL)
1495 {
1496 /* Fast path. */
1497 if (! __gthread_mutex_trylock (&u->lock))
1498 {
1499 /* assert (u->closed == 0); */
1500 __gthread_mutex_unlock (&unit_lock);
1501 return u;
1502 }
1503
1504 inc_waiting_locked (u);
1505 }
1506 __gthread_mutex_unlock (&unit_lock);
1507 if (u != NULL)
1508 {
1509 __gthread_mutex_lock (&u->lock);
1510 if (u->closed)
1511 {
1512 __gthread_mutex_lock (&unit_lock);
1513 __gthread_mutex_unlock (&u->lock);
1514 if (predec_waiting_locked (u) == 0)
5e62a3cc 1515 free (u);
60c514ba 1516 goto retry;
1517 }
1518
1519 dec_waiting_unlocked (u);
1520 }
1521 return u;
1522}
1523
1524static gfc_unit *
1525flush_all_units_1 (gfc_unit *u, int min_unit)
1526{
1527 while (u != NULL)
1528 {
1529 if (u->unit_number > min_unit)
1530 {
1531 gfc_unit *r = flush_all_units_1 (u->left, min_unit);
1532 if (r != NULL)
1533 return r;
1534 }
1535 if (u->unit_number >= min_unit)
1536 {
1537 if (__gthread_mutex_trylock (&u->lock))
1538 return u;
1539 if (u->s)
65f15010 1540 sflush (u->s);
60c514ba 1541 __gthread_mutex_unlock (&u->lock);
1542 }
1543 u = u->right;
1544 }
1545 return NULL;
1546}
1547
1548void
1549flush_all_units (void)
1550{
1551 gfc_unit *u;
1552 int min_unit = 0;
1553
1554 __gthread_mutex_lock (&unit_lock);
1555 do
1556 {
1557 u = flush_all_units_1 (unit_root, min_unit);
1558 if (u != NULL)
1559 inc_waiting_locked (u);
1560 __gthread_mutex_unlock (&unit_lock);
1561 if (u == NULL)
1562 return;
1563
1564 __gthread_mutex_lock (&u->lock);
1565
1566 min_unit = u->unit_number + 1;
1567
1568 if (u->closed == 0)
1569 {
65f15010 1570 sflush (u->s);
60c514ba 1571 __gthread_mutex_lock (&unit_lock);
1572 __gthread_mutex_unlock (&u->lock);
1573 (void) predec_waiting_locked (u);
1574 }
1575 else
1576 {
1577 __gthread_mutex_lock (&unit_lock);
1578 __gthread_mutex_unlock (&u->lock);
1579 if (predec_waiting_locked (u) == 0)
5e62a3cc 1580 free (u);
60c514ba 1581 }
1582 }
1583 while (1);
4ee9c684 1584}
1585
1586
4ee9c684 1587/* delete_file()-- Given a unit structure, delete the file associated
1588 * with the unit. Returns nonzero if something went wrong. */
1589
1590int
f02dd226 1591delete_file (gfc_unit * u)
4ee9c684 1592{
de28dd31 1593 char path[min(PATH_MAX, u->file_len + 1)];
1594 int err = unpack_filename (path, u->file, u->file_len);
4ee9c684 1595
de28dd31 1596 if (err)
4ee9c684 1597 { /* Shouldn't be possible */
de28dd31 1598 errno = err;
4ee9c684 1599 return 1;
1600 }
1601
1602 return unlink (path);
1603}
1604
1605
1606/* file_exists()-- Returns nonzero if the current filename exists on
1607 * the system */
1608
1609int
60c514ba 1610file_exists (const char *file, gfc_charlen_type file_len)
4ee9c684 1611{
de28dd31 1612 char path[min(PATH_MAX, file_len + 1)];
4ee9c684 1613
60c514ba 1614 if (unpack_filename (path, file, file_len))
4ee9c684 1615 return 0;
1616
fb053cd1 1617 return !(access (path, F_OK));
4ee9c684 1618}
1619
1620
f4e9c676 1621/* file_size()-- Returns the size of the file. */
1622
1623GFC_IO_INT
1624file_size (const char *file, gfc_charlen_type file_len)
1625{
de28dd31 1626 char path[min(PATH_MAX, file_len + 1)];
f6854450 1627 struct stat statbuf;
f4e9c676 1628
1629 if (unpack_filename (path, file, file_len))
1630 return -1;
1631
1632 if (stat (path, &statbuf) < 0)
1633 return -1;
1634
1635 return (GFC_IO_INT) statbuf.st_size;
1636}
4ee9c684 1637
fb35179a 1638static const char yes[] = "YES", no[] = "NO", unknown[] = "UNKNOWN";
4ee9c684 1639
1640/* inquire_sequential()-- Given a fortran string, determine if the
1641 * file is suitable for sequential access. Returns a C-style
1642 * string. */
1643
1644const char *
1645inquire_sequential (const char *string, int len)
1646{
de28dd31 1647 char path[min(PATH_MAX, len + 1)];
f6854450 1648 struct stat statbuf;
4ee9c684 1649
1650 if (string == NULL ||
1651 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1652 return unknown;
1653
1654 if (S_ISREG (statbuf.st_mode) ||
1655 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
2e1fa727 1656 return unknown;
4ee9c684 1657
1658 if (S_ISDIR (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
1659 return no;
1660
1661 return unknown;
1662}
1663
1664
1665/* inquire_direct()-- Given a fortran string, determine if the file is
1666 * suitable for direct access. Returns a C-style string. */
1667
1668const char *
1669inquire_direct (const char *string, int len)
1670{
de28dd31 1671 char path[min(PATH_MAX, len + 1)];
f6854450 1672 struct stat statbuf;
4ee9c684 1673
1674 if (string == NULL ||
1675 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1676 return unknown;
1677
1678 if (S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
2e1fa727 1679 return unknown;
4ee9c684 1680
1681 if (S_ISDIR (statbuf.st_mode) ||
1682 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
1683 return no;
1684
1685 return unknown;
1686}
1687
1688
1689/* inquire_formatted()-- Given a fortran string, determine if the file
1690 * is suitable for formatted form. Returns a C-style string. */
1691
1692const char *
1693inquire_formatted (const char *string, int len)
1694{
de28dd31 1695 char path[min(PATH_MAX, len + 1)];
f6854450 1696 struct stat statbuf;
4ee9c684 1697
1698 if (string == NULL ||
1699 unpack_filename (path, string, len) || stat (path, &statbuf) < 0)
1700 return unknown;
1701
1702 if (S_ISREG (statbuf.st_mode) ||
1703 S_ISBLK (statbuf.st_mode) ||
1704 S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode))
2e1fa727 1705 return unknown;
4ee9c684 1706
1707 if (S_ISDIR (statbuf.st_mode))
1708 return no;
1709
1710 return unknown;
1711}
1712
1713
1714/* inquire_unformatted()-- Given a fortran string, determine if the file
1715 * is suitable for unformatted form. Returns a C-style string. */
1716
1717const char *
1718inquire_unformatted (const char *string, int len)
1719{
4ee9c684 1720 return inquire_formatted (string, len);
1721}
1722
1723
1724/* inquire_access()-- Given a fortran string, determine if the file is
1725 * suitable for access. */
1726
1727static const char *
1728inquire_access (const char *string, int len, int mode)
1729{
de28dd31 1730 char path[min(PATH_MAX, len + 1)];
4ee9c684 1731
1732 if (string == NULL || unpack_filename (path, string, len) ||
1733 access (path, mode) < 0)
1734 return no;
1735
1736 return yes;
1737}
1738
1739
1740/* inquire_read()-- Given a fortran string, determine if the file is
1741 * suitable for READ access. */
1742
1743const char *
1744inquire_read (const char *string, int len)
1745{
4ee9c684 1746 return inquire_access (string, len, R_OK);
1747}
1748
1749
1750/* inquire_write()-- Given a fortran string, determine if the file is
1751 * suitable for READ access. */
1752
1753const char *
1754inquire_write (const char *string, int len)
1755{
4ee9c684 1756 return inquire_access (string, len, W_OK);
1757}
1758
1759
1760/* inquire_readwrite()-- Given a fortran string, determine if the file is
1761 * suitable for read and write access. */
1762
1763const char *
1764inquire_readwrite (const char *string, int len)
1765{
4ee9c684 1766 return inquire_access (string, len, R_OK | W_OK);
1767}
1768
1769
60d77e0d 1770int
1771stream_isatty (stream *s)
1772{
1773 return isatty (((unix_stream *) s)->fd);
1774}
1775
57f34837 1776int
1777stream_ttyname (stream *s __attribute__ ((unused)),
1778 char * buf __attribute__ ((unused)),
1779 size_t buflen __attribute__ ((unused)))
1780{
1781#ifdef HAVE_TTYNAME_R
1782 return ttyname_r (((unix_stream *) s)->fd, buf, buflen);
1783#elif defined HAVE_TTYNAME
1784 char *p;
1785 size_t plen;
1786 p = ttyname (((unix_stream *) s)->fd);
1787 if (!p)
1788 return errno;
1789 plen = strlen (p);
1790 if (buflen < plen)
1791 plen = buflen;
1792 memcpy (buf, p, plen);
1793 return 0;
f2c0a16d 1794#else
57f34837 1795 return ENOSYS;
3479b863 1796#endif
57f34837 1797}
1798
3479b863 1799
60d77e0d 1800
4ee9c684 1801
1802/* How files are stored: This is an operating-system specific issue,
1803 and therefore belongs here. There are three cases to consider.
1804
1805 Direct Access:
1806 Records are written as block of bytes corresponding to the record
1807 length of the file. This goes for both formatted and unformatted
1808 records. Positioning is done explicitly for each data transfer,
1809 so positioning is not much of an issue.
1810
1811 Sequential Formatted:
1812 Records are separated by newline characters. The newline character
1813 is prohibited from appearing in a string. If it does, this will be
1814 messed up on the next read. End of file is also the end of a record.
1815
1816 Sequential Unformatted:
1817 In this case, we are merely copying bytes to and from main storage,
1818 yet we need to keep track of varying record lengths. We adopt
1819 the solution used by f2c. Each record contains a pair of length
1820 markers:
1821
84d33b91 1822 Length of record n in bytes
1823 Data of record n
1824 Length of record n in bytes
4ee9c684 1825
84d33b91 1826 Length of record n+1 in bytes
1827 Data of record n+1
1828 Length of record n+1 in bytes
4ee9c684 1829
1830 The length is stored at the end of a record to allow backspacing to the
1831 previous record. Between data transfer statements, the file pointer
1832 is left pointing to the first length of the current record.
1833
1834 ENDFILE records are never explicitly stored.
1835
1836*/