1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- S Y S T E M . F I L E _ I O --
9 -- Copyright (C) 1992-2013, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada
.Finalization
; use Ada
.Finalization
;
33 with Ada
.IO_Exceptions
; use Ada
.IO_Exceptions
;
36 with Interfaces
.C_Streams
; use Interfaces
.C_Streams
;
39 with System
.Case_Util
; use System
.Case_Util
;
41 with System
.Soft_Links
;
43 with Ada
.Unchecked_Deallocation
;
45 package body System
.File_IO
is
47 use System
.File_Control_Block
;
49 package SSL
renames System
.Soft_Links
;
51 use type Interfaces
.C
.int
;
54 subtype String_Access
is System
.OS_Lib
.String_Access
;
55 procedure Free
(X
: in out String_Access
) renames System
.OS_Lib
.Free
;
57 function "=" (X
, Y
: String_Access
) return Boolean
58 renames System
.OS_Lib
."=";
60 ----------------------
61 -- Global Variables --
62 ----------------------
64 Open_Files
: AFCB_Ptr
;
65 -- This points to a list of AFCB's for all open files. This is a doubly
66 -- linked list, with the Prev pointer of the first entry, and the Next
67 -- pointer of the last entry containing null. Note that this global
68 -- variable must be properly protected to provide thread safety.
70 type Temp_File_Record
;
71 type Temp_File_Record_Ptr
is access all Temp_File_Record
;
73 type Temp_File_Record
is record
74 Name
: String (1 .. max_path_len
+ 1);
75 Next
: Temp_File_Record_Ptr
;
77 -- One of these is allocated for each temporary file created
79 Temp_Files
: Temp_File_Record_Ptr
;
80 -- Points to list of names of temporary files. Note that this global
81 -- variable must be properly protected to provide thread safety.
83 type File_IO_Clean_Up_Type
is new Limited_Controlled
with null record;
84 -- The closing of all open files and deletion of temporary files is an
85 -- action that takes place at the end of execution of the main program.
86 -- This action is implemented using a library level object which gets
87 -- finalized at the end of program execution. Note that the type is
88 -- limited, in order to stop the compiler optimizing away the declaration
89 -- which would be allowed in the non-limited case.
91 procedure Finalize
(V
: in out File_IO_Clean_Up_Type
);
92 -- This is the finalize operation that is used to do the cleanup
94 File_IO_Clean_Up_Object
: File_IO_Clean_Up_Type
;
95 pragma Warnings
(Off
, File_IO_Clean_Up_Object
);
96 -- This is the single object of the type that triggers the finalization
97 -- call. Since it is at the library level, this happens just before the
98 -- environment task is finalized.
100 text_translation_required
: Boolean;
101 for text_translation_required
'Size use Character'Size;
103 (C
, text_translation_required
, "__gnat_text_translation_required");
104 -- If true, add appropriate suffix to control string for Open
106 VMS_Formstr
: String_Access
:= null;
107 -- For special VMS RMS keywords and values
109 -----------------------
110 -- Local Subprograms --
111 -----------------------
113 procedure Free_String
is new Ada
.Unchecked_Deallocation
(String, Pstring
);
115 subtype Fopen_String
is String (1 .. 4);
116 -- Holds open string (longest is "w+b" & nul)
123 Fopstr
: out Fopen_String
);
124 -- Determines proper open mode for a file to be opened in the given
125 -- Ada mode. Text is true for a text file and false otherwise, and
126 -- Creat is true for a create call, and False for an open call. The
127 -- value stored in Fopstr is a nul-terminated string suitable for a
128 -- call to fopen or freopen. Amethod is the character designating
129 -- the access method from the Access_Method field of the FCB.
131 function Errno_Message
133 Errno
: Integer := OS_Lib
.Errno
) return String;
134 -- Return Errno_Message for Errno, with file name prepended
136 procedure Raise_Device_Error
138 Errno
: Integer := OS_Lib
.Errno
);
139 pragma No_Return
(Raise_Device_Error
);
140 -- Clear error indication on File and raise Device_Error with an exception
141 -- message providing errno information.
143 procedure Form_VMS_RMS_Keys
(Form
: String; VMS_Form
: out String_Access
);
144 -- Parse the RMS Keys
146 function Form_RMS_Context_Key
148 VMS_Form
: String_Access
) return Natural;
149 -- Parse the RMS Context Key
155 procedure Append_Set
(File
: AFCB_Ptr
) is
157 if File
.Mode
= Append_File
then
158 if fseek
(File
.Stream
, 0, SEEK_END
) /= 0 then
159 Raise_Device_Error
(File
);
168 procedure Chain_File
(File
: AFCB_Ptr
) is
170 -- Take a task lock, to protect the global data value Open_Files
174 -- Do the chaining operation locked
176 File
.Next
:= Open_Files
;
180 if File
.Next
/= null then
181 File
.Next
.Prev
:= File
;
192 ---------------------
193 -- Check_File_Open --
194 ---------------------
196 procedure Check_File_Open
(File
: AFCB_Ptr
) is
199 raise Status_Error
with "file not open";
203 -----------------------
204 -- Check_Read_Status --
205 -----------------------
207 procedure Check_Read_Status
(File
: AFCB_Ptr
) is
210 raise Status_Error
with "file not open";
211 elsif File
.Mode
not in Read_File_Mode
then
212 raise Mode_Error
with "file not readable";
214 end Check_Read_Status
;
216 ------------------------
217 -- Check_Write_Status --
218 ------------------------
220 procedure Check_Write_Status
(File
: AFCB_Ptr
) is
223 raise Status_Error
with "file not open";
224 elsif File
.Mode
= In_File
then
225 raise Mode_Error
with "file not writable";
227 end Check_Write_Status
;
233 procedure Close
(File_Ptr
: access AFCB_Ptr
) is
234 Close_Status
: int
:= 0;
235 Dup_Strm
: Boolean := False;
236 File
: AFCB_Ptr
renames File_Ptr
.all;
237 Errno
: Integer := 0;
240 -- Take a task lock, to protect the global data value Open_Files
244 Check_File_Open
(File
);
247 -- Sever the association between the given file and its associated
248 -- external file. The given file is left closed. Do not perform system
249 -- closes on the standard input, output and error files and also do not
250 -- attempt to close a stream that does not exist (signalled by a null
251 -- stream value -- happens in some error situations).
253 if not File
.Is_System_File
and then File
.Stream
/= NULL_Stream
then
255 -- Do not do an fclose if this is a shared file and there is at least
256 -- one other instance of the stream that is open.
258 if File
.Shared_Status
= Yes
then
265 if P
/= File
and then File
.Stream
= P
.Stream
then
275 -- Do the fclose unless this was a duplicate in the shared case
278 Close_Status
:= fclose
(File
.Stream
);
280 if Close_Status
/= 0 then
281 Errno
:= OS_Lib
.Errno
;
286 -- Dechain file from list of open files and then free the storage
288 if File
.Prev
= null then
289 Open_Files
:= File
.Next
;
291 File
.Prev
.Next
:= File
.Next
;
294 if File
.Next
/= null then
295 File
.Next
.Prev
:= File
.Prev
;
298 -- Deallocate some parts of the file structure that were kept in heap
299 -- storage with the exception of system files (standard input, output
300 -- and error) since they had some information allocated in the stack.
302 if not File
.Is_System_File
then
303 Free_String
(File
.Name
);
304 Free_String
(File
.Form
);
310 if Close_Status
/= 0 then
311 Raise_Device_Error
(null, Errno
);
326 procedure Delete
(File_Ptr
: access AFCB_Ptr
) is
327 File
: AFCB_Ptr
renames File_Ptr
.all;
330 Check_File_Open
(File
);
332 if not File
.Is_Regular_File
then
333 raise Use_Error
with "cannot delete non-regular file";
337 Filename
: aliased constant String := File
.Name
.all;
342 -- Now unlink the external file. Note that we use the full name in
343 -- this unlink, because the working directory may have changed since
344 -- we did the open, and we want to unlink the right file.
346 if unlink
(Filename
'Address) = -1 then
347 raise Use_Error
with OS_Lib
.Errno_Message
;
356 function End_Of_File
(File
: AFCB_Ptr
) return Boolean is
358 Check_File_Open
(File
);
360 if feof
(File
.Stream
) /= 0 then
364 Check_Read_Status
(File
);
366 if ungetc
(fgetc
(File
.Stream
), File
.Stream
) = EOF
then
367 clearerr
(File
.Stream
);
379 function Errno_Message
381 Errno
: Integer := OS_Lib
.Errno
) return String
384 return Name
& ": " & OS_Lib
.Errno_Message
(Err
=> Errno
);
391 -- Note: we do not need to worry about locking against multiple task access
392 -- in this routine, since it is called only from the environment task just
393 -- before terminating execution.
395 procedure Finalize
(V
: in out File_IO_Clean_Up_Type
) is
396 pragma Warnings
(Off
, V
);
398 Fptr1
: aliased AFCB_Ptr
;
402 pragma Unreferenced
(Discard
);
405 -- Take a lock to protect global Open_Files data structure
409 -- First close all open files (the slightly complex form of this loop is
410 -- required because Close as a side effect nulls out its argument).
413 while Fptr1
/= null loop
415 Close
(Fptr1
'Access);
419 -- Now unlink all temporary files. We do not bother to free the blocks
420 -- because we are just about to terminate the program. We also ignore
421 -- any errors while attempting these unlink operations.
423 while Temp_Files
/= null loop
424 Discard
:= unlink
(Temp_Files
.Name
'Address);
425 Temp_Files
:= Temp_Files
.Next
;
440 procedure Flush
(File
: AFCB_Ptr
) is
442 Check_Write_Status
(File
);
444 if fflush
(File
.Stream
) /= 0 then
445 Raise_Device_Error
(File
);
453 -- The fopen mode to be used is shown by the following table:
456 -- Append_File "r+" "w+"
458 -- Out_File (Direct_IO) "r+" "w"
459 -- Out_File (all others) "w" "w"
460 -- Inout_File "r+" "w+"
462 -- Note: we do not use "a" or "a+" for Append_File, since this would not
463 -- work in the case of stream files, where even if in append file mode,
464 -- you can reset to earlier points in the file. The caller must use the
465 -- Append_Set routine to deal with the necessary positioning.
467 -- Note: in several cases, the fopen mode used allows reading and writing,
468 -- but the setting of the Ada mode is more restrictive. For instance,
469 -- Create in In_File mode uses "w+" which allows writing, but the Ada mode
470 -- In_File will cause any write operations to be rejected with Mode_Error
473 -- Note: for the Out_File/Open cases for other than the Direct_IO case, an
474 -- initial call will be made by the caller to first open the file in "r"
475 -- mode to be sure that it exists. The real open, in "w" mode, will then
476 -- destroy this file. This is peculiar, but that's what Ada semantics
477 -- require and the ACATS tests insist on.
479 -- If text file translation is required, then either "b" or "t" is appended
480 -- to the mode, depending on the setting of Text.
487 Fopstr
: out Fopen_String
)
504 if Amethod
= 'D' and then not Creat
then
513 when Inout_File | Append_File
=>
514 Fopstr
(1) := (if Creat
then 'w' else 'r');
519 -- If text_translation_required is true then we need to append either a
520 -- "t" or "b" to the string to get the right mode.
522 if text_translation_required
then
523 Fopstr
(Fptr
) := (if Text
then 't' else 'b');
527 Fopstr
(Fptr
) := ASCII
.NUL
;
534 function Form
(File
: AFCB_Ptr
) return String is
537 raise Status_Error
with "Form: file not open";
539 return File
.Form
.all (1 .. File
.Form
'Length - 1);
547 function Form_Boolean
550 Default
: Boolean) return Boolean
553 pragma Unreferenced
(V2
);
556 Form_Parameter
(Form
, Keyword
, V1
, V2
);
560 elsif Form
(V1
) = 'y' then
562 elsif Form
(V1
) = 'n' then
565 raise Use_Error
with "invalid Form";
573 function Form_Integer
576 Default
: Integer) return Integer
582 Form_Parameter
(Form
, Keyword
, V1
, V2
);
590 for J
in V1
.. V2
loop
591 if Form
(J
) not in '0' .. '9' then
592 raise Use_Error
with "invalid Form";
594 V
:= V
* 10 + Character'Pos (Form
(J
)) - Character'Pos ('0');
598 raise Use_Error
with "invalid Form";
610 procedure Form_Parameter
616 Klen
: constant Integer := Keyword
'Length;
619 for J
in Form
'First + Klen
.. Form
'Last - 1 loop
621 and then Form
(J
- Klen
.. J
- 1) = Keyword
625 while Form
(Stop
+ 1) /= ASCII
.NUL
626 and then Form
(Stop
+ 1) /= ','
639 --------------------------
640 -- Form_RMS_Context_Key --
641 --------------------------
643 function Form_RMS_Context_Key
645 VMS_Form
: String_Access
) return Natural
647 type Context_Parms
is
648 (Binary_Data
, Convert_Fortran_Carriage_Control
, Force_Record_Mode
,
649 Force_Stream_Mode
, Explicit_Write
);
650 -- Ada-fied list of all possible Context keyword values
657 -- Find the end of the occupation
659 for J
in VMS_Form
'First .. VMS_Form
'Last loop
660 if VMS_Form
(J
) = ASCII
.NUL
then
667 while Index
< Form
'Last loop
668 if Form
(Index
) = '=' then
671 -- Loop through the context values and look for a match
673 for Parm
in Context_Parms
loop
675 KImage
: String := Context_Parms
'Image (Parm
);
678 Klen
:= KImage
'Length;
681 if Index
+ Klen
- 1 <= Form
'Last
682 and then Form
(Index
.. Index
+ Klen
- 1) = KImage
685 when Force_Record_Mode
=>
686 VMS_Form
(Pos
) := '"';
688 VMS_Form
(Pos
.. Pos
+ 6) := "ctx=rec";
690 VMS_Form
(Pos
) := '"';
692 VMS_Form
(Pos
) := ',';
695 when Force_Stream_Mode
=>
696 VMS_Form
(Pos
) := '"';
698 VMS_Form
(Pos
.. Pos
+ 6) := "ctx=stm";
700 VMS_Form
(Pos
) := '"';
702 VMS_Form
(Pos
) := ',';
707 with "unimplemented RMS Context Value";
713 raise Use_Error
with "unrecognized RMS Context Value";
717 raise Use_Error
with "malformed RMS Context Value";
718 end Form_RMS_Context_Key
;
720 -----------------------
721 -- Form_VMS_RMS_Keys --
722 -----------------------
724 procedure Form_VMS_RMS_Keys
(Form
: String; VMS_Form
: out String_Access
)
726 VMS_RMS_Keys_Token
: constant String := "vms_rms_keys";
727 Klen
: Natural := VMS_RMS_Keys_Token
'Length;
730 -- Ada-fied list of all RMS keywords, translated from the HP C Run-Time
731 -- Library Reference Manual, Table REF-3: RMS Valid Keywords and Values.
734 (Access_Callback
, Allocation_Quantity
, Block_Size
, Context
,
735 Default_Extension_Quantity
, Default_File_Name_String
, Error_Callback
,
736 File_Processing_Options
, Fixed_Header_Size
, Global_Buffer_Count
,
737 Multiblock_Count
, Multibuffer_Count
, Maximum_Record_Size
,
738 Terminal_Input_Prompt
, Record_Attributes
, Record_Format
,
739 Record_Processing_Options
, Retrieval_Pointer_Count
, Sharing_Options
,
743 Index
:= Form
'First + Klen
- 1;
744 while Index
< Form
'Last loop
747 -- Scan for the token signalling VMS RMS Keys ahead. Should
748 -- whitespace be eaten???
750 if Form
(Index
- Klen
.. Index
- 1) = VMS_RMS_Keys_Token
then
752 -- Allocate the VMS form string that will contain the cryptic
753 -- CRTL RMS strings and initialize it to all nulls. Since the
754 -- CRTL strings are always shorter than the Ada-fied strings,
755 -- it follows that an allocation of the original size will be
756 -- more than adequate.
757 VMS_Form
:= new String'(Form (Form'First .. Form'Last));
758 VMS_Form.all := (others => ASCII.NUL);
760 if Form (Index) = '=' then
762 if Form (Index) = '(' then
763 while Index < Form'Last loop
766 -- Loop through the RMS Keys and dispatch.
768 for Key in RMS_Keys loop
770 KImage : String := RMS_Keys'Image (Key);
773 Klen := KImage'Length;
776 if Form (Index .. Index + Klen - 1) = KImage then
779 Index := Form_RMS_Context_Key
780 (Form (Index + Klen .. Form'Last),
786 with "unimplemented VMS RMS Form Key";
792 if Form (Index) = ')' then
794 -- Done, erase the unneeded trailing comma and return
796 for J in reverse VMS_Form'First .. VMS_Form'Last loop
797 if VMS_Form (J) = ',' then
798 VMS_Form (J) := ASCII.NUL;
803 -- Shouldn't be possible to get here
807 elsif Form (Index) = ',' then
809 -- Another key ahead, exit inner loop
815 -- Keyword value not terminated correctly
817 raise Use_Error with "malformed VMS RMS Form";
823 -- Found the keyword, but not followed by correct syntax
825 raise Use_Error with "malformed VMS RMS Form";
828 end Form_VMS_RMS_Keys;
834 function Is_Open (File : AFCB_Ptr) return Boolean is
836 -- We return True if the file is open, and the underlying file stream is
837 -- usable. In particular on Windows an application linked with -mwindows
838 -- option set does not have a console attached. In this case standard
839 -- files (Current_Output, Current_Error, Current_Input) are not created.
840 -- We want Is_Open (Current_Output) to return False in this case.
842 return File /= null and then fileno (File.Stream) /= -1;
849 procedure Make_Buffered
851 Buf_Siz : Interfaces.C_Streams.size_t)
854 pragma Unreferenced (status);
857 status := setvbuf (File.Stream, Null_Address, IOFBF, Buf_Siz);
860 ------------------------
861 -- Make_Line_Buffered --
862 ------------------------
864 procedure Make_Line_Buffered
866 Line_Siz : Interfaces.C_Streams.size_t)
869 pragma Unreferenced (status);
872 status := setvbuf (File.Stream, Null_Address, IOLBF, Line_Siz);
873 -- No error checking???
874 end Make_Line_Buffered;
876 ---------------------
877 -- Make_Unbuffered --
878 ---------------------
880 procedure Make_Unbuffered (File : AFCB_Ptr) is
882 pragma Unreferenced (status);
885 status := setvbuf (File.Stream, Null_Address, IONBF, 0);
886 -- No error checking???
893 function Mode (File : AFCB_Ptr) return File_Mode is
896 raise Status_Error with "Mode: file not open";
906 function Name (File : AFCB_Ptr) return String is
909 raise Status_Error with "Name: file not open";
911 return File.Name.all (1 .. File.Name'Length - 1);
920 (File_Ptr : in out AFCB_Ptr;
921 Dummy_FCB : AFCB'Class;
928 C_Stream : FILEs := NULL_Stream)
930 pragma Warnings (Off, Dummy_FCB);
931 -- Yes we know this is never assigned a value. That's intended, since
932 -- all we ever use of this value is the tag for dispatching purposes.
934 procedure Tmp_Name (Buffer : Address);
935 pragma Import (C, Tmp_Name, "__gnat_tmp_name");
936 -- Set buffer (a String address) with a temporary filename
938 function Get_Case_Sensitive return Integer;
939 pragma Import (C, Get_Case_Sensitive,
940 "__gnat_get_file_names_case_sensitive");
942 File_Names_Case_Sensitive : constant Boolean := Get_Case_Sensitive /= 0;
943 -- Set to indicate whether the operating system convention is for file
944 -- names to be case sensitive (e.g., in Unix, set True), or not case
945 -- sensitive (e.g., in Windows, set False). Declared locally to avoid
946 -- breaking the Preelaborate rule that disallows function calls at the
949 Stream : FILEs := C_Stream;
950 -- Stream which we open in response to this request
952 Shared : Shared_Status_Type;
953 -- Setting of Shared_Status field for file
955 Fopstr : aliased Fopen_String;
956 -- Mode string used in fopen call
958 Formstr : aliased String (1 .. Form'Length + 1);
959 -- Form string with ASCII.NUL appended, folded to lower case
961 Is_Text_File : Boolean;
963 Tempfile : constant Boolean := (Name'Length = 0);
964 -- Indicates temporary file case
966 Namelen : constant Integer := max_path_len;
967 -- Length required for file name, not including final ASCII.NUL.
968 -- Note that we used to reference L_tmpnam here, which is not reliable
969 -- since __gnat_tmp_name does not always use tmpnam.
971 Namestr : aliased String (1 .. Namelen + 1);
972 -- Name as given or temporary file name with ASCII.NUL appended
974 Fullname : aliased String (1 .. max_path_len + 1);
975 -- Full name (as required for Name function, and as stored in the
976 -- control block in the Name field) with ASCII.NUL appended.
978 Full_Name_Len : Integer;
979 -- Length of name actually stored in Fullname
981 Encoding : CRTL.Filename_Encoding;
982 -- Filename encoding specified into the form parameter
985 if File_Ptr /= null then
986 raise Status_Error with "file already open";
989 -- Acquire form string, setting required NUL terminator
991 Formstr (1 .. Form'Length) := Form;
992 Formstr (Formstr'Last) := ASCII.NUL;
994 -- Convert form string to lower case
996 for J in Formstr'Range loop
997 if Formstr (J) in 'A
' .. 'Z
' then
998 Formstr (J) := Character'Val (Character'Pos (Formstr (J)) + 32);
1002 -- Acquire setting of shared parameter
1008 Form_Parameter (Formstr, "shared", V1, V2);
1012 elsif Formstr (V1 .. V2) = "yes" then
1014 elsif Formstr (V1 .. V2) = "no" then
1017 raise Use_Error with "invalid Form";
1021 -- Acquire setting of encoding parameter
1027 Form_Parameter (Formstr, "encoding", V1, V2);
1030 Encoding := CRTL.Unspecified;
1031 elsif Formstr (V1 .. V2) = "utf8" then
1032 Encoding := CRTL.UTF8;
1033 elsif Formstr (V1 .. V2) = "8bits" then
1034 Encoding := CRTL.ASCII_8bits;
1036 raise Use_Error with "invalid Form";
1040 -- Acquire setting of text_translation parameter. Only needed if this is
1041 -- a [Wide_[Wide_]]Text_IO file, in which case we default to True, but
1042 -- if the Form says Text_Translation=No, we use binary mode, so new-line
1043 -- will be just LF, even on Windows.
1045 Is_Text_File := Text;
1047 if Is_Text_File then
1049 Form_Boolean (Formstr, "text_translation", Default => True);
1052 -- Acquire settings of target specific form parameters on VMS. Only
1053 -- Context is currently implemented, for forcing a byte stream mode
1054 -- read. On non-VMS systems, the settings are ultimately ignored in
1055 -- the implementation of __gnat_fopen.
1057 -- Should a warning be issued on non-VMS systems? That's not possible
1058 -- without testing System.OpenVMS boolean which isn't present in most
1059 -- non-VMS versions of package System.
1061 Form_VMS_RMS_Keys (Formstr, VMS_Formstr);
1063 -- If we were given a stream (call from xxx.C_Streams.Open), then set
1064 -- the full name to the given one, and skip to end of processing.
1066 if Stream /= NULL_Stream then
1067 Full_Name_Len := Name'Length + 1;
1068 Fullname (1 .. Full_Name_Len - 1) := Name;
1069 Fullname (Full_Name_Len) := ASCII.NUL;
1071 -- Normal case of Open or Create
1074 -- If temporary file case, get temporary file name and add to the
1075 -- list of temporary files to be deleted on exit.
1079 raise Name_Error with "opening temp file without creating it";
1082 Tmp_Name (Namestr'Address);
1084 if Namestr (1) = ASCII.NUL then
1085 raise Use_Error with "invalid temp file name";
1088 -- Chain to temp file list, ensuring thread safety with a lock
1093 new Temp_File_Record'(Name
=> Namestr
, Next
=> Temp_Files
);
1094 SSL
.Unlock_Task
.all;
1098 SSL
.Unlock_Task
.all;
1102 -- Normal case of non-null name given
1105 if Name
'Length > Namelen
then
1106 raise Name_Error
with "file name too long";
1109 Namestr
(1 .. Name
'Length) := Name
;
1110 Namestr
(Name
'Length + 1) := ASCII
.NUL
;
1113 -- Get full name in accordance with the advice of RM A.8.2(22)
1115 full_name
(Namestr
'Address, Fullname
'Address);
1117 if Fullname
(1) = ASCII
.NUL
then
1118 raise Use_Error
with Errno_Message
(Name
);
1122 while Full_Name_Len
< Fullname
'Last
1123 and then Fullname
(Full_Name_Len
) /= ASCII
.NUL
1125 Full_Name_Len
:= Full_Name_Len
+ 1;
1128 -- Fullname is generated by calling system's full_name. The problem
1129 -- is, full_name does nothing about the casing, so a file name
1130 -- comparison may generally speaking not be valid on non-case-
1131 -- sensitive systems, and in particular we get unexpected failures
1132 -- on Windows/Vista because of this. So we use s-casuti to force
1133 -- the name to lower case.
1135 if not File_Names_Case_Sensitive
then
1136 To_Lower
(Fullname
(1 .. Full_Name_Len
));
1139 -- If Shared=None or Shared=Yes, then check for the existence of
1140 -- another file with exactly the same full name.
1142 if Shared
/= No
then
1147 -- Take a task lock to protect Open_Files
1151 -- Search list of open files
1154 while P
/= null loop
1155 if Fullname
(1 .. Full_Name_Len
) = P
.Name
.all then
1157 -- If we get a match, and either file has Shared=None,
1158 -- then raise Use_Error, since we don't allow two files
1159 -- of the same name to be opened unless they specify the
1160 -- required sharing mode.
1163 or else P
.Shared_Status
= None
1165 raise Use_Error
with "reopening shared file";
1167 -- If both files have Shared=Yes, then we acquire the
1168 -- stream from the located file to use as our stream.
1171 and then P
.Shared_Status
= Yes
1176 -- Otherwise one of the files has Shared=Yes and one has
1177 -- Shared=No. If the current file has Shared=No then all
1178 -- is well but we don't want to share any other file's
1179 -- stream. If the current file has Shared=Yes, we would
1180 -- like to share a stream, but not from a file that has
1181 -- Shared=No, so either way, we just continue the search.
1191 SSL
.Unlock_Task
.all;
1195 SSL
.Unlock_Task
.all;
1200 -- Open specified file if we did not find an existing stream
1202 if Stream
= NULL_Stream
then
1203 Fopen_Mode
(Mode
, Is_Text_File
, Creat
, Amethod
, Fopstr
);
1205 -- A special case, if we are opening (OPEN case) a file and the
1206 -- mode returned by Fopen_Mode is not "r" or "r+", then we first
1207 -- make sure that the file exists as required by Ada semantics.
1209 if not Creat
and then Fopstr
(1) /= 'r' then
1210 if file_exists
(Namestr
'Address) = 0 then
1211 raise Name_Error
with Errno_Message
(Name
);
1215 -- Now open the file. Note that we use the name as given in the
1216 -- original Open call for this purpose, since that seems the
1217 -- clearest implementation of the intent. It would presumably
1218 -- work to use the full name here, but if there is any difference,
1219 -- then we should use the name used in the call.
1221 -- Note: for a corresponding delete, we will use the full name,
1222 -- since by the time of the delete, the current working directory
1223 -- may have changed and we do not want to delete a different file.
1225 if VMS_Formstr
= null then
1226 Stream
:= fopen
(Namestr
'Address, Fopstr
'Address, Encoding
,
1229 Stream
:= fopen
(Namestr
'Address, Fopstr
'Address, Encoding
,
1230 VMS_Formstr
.all'Address);
1233 -- No need to keep this around
1235 if VMS_Formstr
/= null then
1239 if Stream
= NULL_Stream
then
1241 -- Raise Name_Error if trying to open a non-existent file.
1242 -- Otherwise raise Use_Error.
1244 -- Should we raise Device_Error for ENOSPC???
1247 function Is_File_Not_Found_Error
1248 (Errno_Value
: Integer) return Integer;
1250 (C
, Is_File_Not_Found_Error
,
1251 "__gnat_is_file_not_found_error");
1252 -- Non-zero when the given errno value indicates a non-
1255 Errno
: constant Integer := OS_Lib
.Errno
;
1256 Message
: constant String := Errno_Message
(Name
, Errno
);
1259 if Is_File_Not_Found_Error
(Errno
) /= 0 then
1260 raise Name_Error
with Message
;
1262 raise Use_Error
with Message
;
1269 -- Stream has been successfully located or opened, so now we are
1270 -- committed to completing the opening of the file. Allocate block on
1271 -- heap and fill in its fields.
1273 File_Ptr
:= AFCB_Allocate
(Dummy_FCB
);
1275 File_Ptr
.Is_Regular_File
:= (is_regular_file
(fileno
(Stream
)) /= 0);
1276 File_Ptr
.Is_System_File
:= False;
1277 File_Ptr
.Is_Text_File
:= Is_Text_File
;
1278 File_Ptr
.Shared_Status
:= Shared
;
1279 File_Ptr
.Access_Method
:= Amethod
;
1280 File_Ptr
.Stream
:= Stream
;
1281 File_Ptr
.Form
:= new String'(Formstr);
1282 File_Ptr.Name := new String'(Fullname
(1 .. Full_Name_Len
));
1283 File_Ptr
.Mode
:= Mode
;
1284 File_Ptr
.Is_Temporary_File
:= Tempfile
;
1285 File_Ptr
.Encoding
:= Encoding
;
1287 Chain_File
(File_Ptr
);
1288 Append_Set
(File_Ptr
);
1291 ------------------------
1292 -- Raise_Device_Error --
1293 ------------------------
1295 procedure Raise_Device_Error
1297 Errno
: Integer := OS_Lib
.Errno
)
1300 -- Clear error status so that the same error is not reported twice
1302 if File
/= null then
1303 clearerr
(File
.Stream
);
1306 raise Device_Error
with OS_Lib
.Errno_Message
(Err
=> Errno
);
1307 end Raise_Device_Error
;
1313 procedure Read_Buf
(File
: AFCB_Ptr
; Buf
: Address
; Siz
: size_t
) is
1317 Nread
:= fread
(Buf
, 1, Siz
, File
.Stream
);
1322 elsif ferror
(File
.Stream
) /= 0 then
1323 Raise_Device_Error
(File
);
1325 elsif Nread
= 0 then
1328 else -- 0 < Nread < Siz
1329 raise Data_Error
with "not enough data read";
1336 Siz
: Interfaces
.C_Streams
.size_t
;
1337 Count
: out Interfaces
.C_Streams
.size_t
)
1340 Count
:= fread
(Buf
, 1, Siz
, File
.Stream
);
1342 if Count
= 0 and then ferror
(File
.Stream
) /= 0 then
1343 Raise_Device_Error
(File
);
1351 -- The reset which does not change the mode simply does a rewind
1353 procedure Reset
(File_Ptr
: access AFCB_Ptr
) is
1354 File
: AFCB_Ptr
renames File_Ptr
.all;
1356 Check_File_Open
(File
);
1357 Reset
(File_Ptr
, File
.Mode
);
1360 -- The reset with a change in mode is done using freopen, and is not
1361 -- permitted except for regular files (since otherwise there is no name for
1362 -- the freopen, and in any case it seems meaningless).
1364 procedure Reset
(File_Ptr
: access AFCB_Ptr
; Mode
: File_Mode
) is
1365 File
: AFCB_Ptr
renames File_Ptr
.all;
1366 Fopstr
: aliased Fopen_String
;
1369 Check_File_Open
(File
);
1371 -- Change of mode not allowed for shared file or file with no name or
1372 -- file that is not a regular file, or for a system file. Note that we
1373 -- allow the "change" of mode if it is not in fact doing a change.
1375 if Mode
/= File
.Mode
then
1376 if File
.Shared_Status
= Yes
then
1377 raise Use_Error
with "cannot change mode of shared file";
1378 elsif File
.Name
'Length <= 1 then
1379 raise Use_Error
with "cannot change mode of temp file";
1380 elsif File
.Is_System_File
then
1381 raise Use_Error
with "cannot change mode of system file";
1382 elsif not File
.Is_Regular_File
then
1383 raise Use_Error
with "cannot change mode of non-regular file";
1387 -- For In_File or Inout_File for a regular file, we can just do a rewind
1388 -- if the mode is unchanged, which is more efficient than doing a full
1392 and then Mode
in Read_File_Mode
1394 rewind
(File
.Stream
);
1396 -- Here the change of mode is permitted, we do it by reopening the file
1397 -- in the new mode and replacing the stream with a new stream.
1401 (Mode
, File
.Is_Text_File
, False, File
.Access_Method
, Fopstr
);
1403 Form_VMS_RMS_Keys
(File
.Form
.all, VMS_Formstr
);
1405 if VMS_Formstr
= null then
1406 File
.Stream
:= freopen
1407 (File
.Name
.all'Address, Fopstr
'Address, File
.Stream
,
1408 File
.Encoding
, Null_Address
);
1410 File
.Stream
:= freopen
1411 (File
.Name
.all'Address, Fopstr
'Address, File
.Stream
,
1412 File
.Encoding
, VMS_Formstr
.all'Address);
1415 if VMS_Formstr
/= null then
1419 if File
.Stream
= NULL_Stream
then
1433 procedure Write_Buf
(File
: AFCB_Ptr
; Buf
: Address
; Siz
: size_t
) is
1435 -- Note: for most purposes, the Siz and 1 parameters in the fwrite call
1436 -- could be reversed, but on VMS, this is a better choice, since for
1437 -- some file formats, reversing the parameters results in records of one
1440 SSL
.Abort_Defer
.all;
1442 if fwrite
(Buf
, Siz
, 1, File
.Stream
) /= 1 then
1444 SSL
.Abort_Undefer
.all;
1445 Raise_Device_Error
(File
);
1449 SSL
.Abort_Undefer
.all;