open.c

Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001, Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2.1 of the GNU Lesser General Public License 
00007   as published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU Lesser General Public 
00021   License along with this program; if not, write the Free Software 
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, 
00023   USA.
00024 
00025   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00026   Mountain View, CA 94043, or:
00027 
00028   http://www.sgi.com
00029 
00030   For further information regarding this notice, see:
00031 
00032   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00033 
00034 */
00035 
00036 
00037 
00038 #pragma ident "@(#) libf/fio/open.c     92.3    08/02/99 10:37:16"
00039 
00040 #include <sys/param.h>  /* PATH_MAX */
00041 #include <string.h>
00042 #ifdef  _ABSOFT
00043 #include <stdlib.h>
00044 #else
00045 #include <malloc.h>
00046 #endif
00047 #include <errno.h>
00048 #include <liberrno.h>
00049 #include <fcntl.h>
00050 #include <unistd.h>
00051 #include <cray/assign.h>
00052 #include <sys/stat.h>
00053 #include <stdio.h>
00054 #include "fio.h"
00055 
00056 #define FERROR(cond, n) {       \
00057         if (!cond)              \
00058                 _ferr(css, n);  \
00059         else                    \
00060                 return(n);      \
00061 }
00062 
00063 #define FERROR1(cond, n, p) {   \
00064         if (!cond)              \
00065                 _ferr(css, n, p); \
00066         else                    \
00067                 return(n);      \
00068         }
00069 
00070 static void freeit(void *);             /* forward reference */
00071 
00072 /*
00073  *      _f_open
00074  *
00075  *              Primary Fortran OPEN and implicit open processing routine.
00076  *              All external file units are connected via this routine.
00077  *
00078  *              It is assumed that _openlock is locked upon entry to this
00079  *              routine.  Upon successful exit from this routine, the unit 
00080  *              will be locked.
00081  *
00082  *      Side effect
00083  *
00084  *              *cup_p is assigned the pointer to a newly allocated (and 
00085  *              locked) unit structure on exit.  On input, *cup_p, if not
00086  *              null, is a valid open unit.  This unit is closed and unlocked
00087  *              prior to reassignment of this pointer to the new unit.   Note
00088  *              that the new unit may be a different unit with the same
00089  *              number.  The new unit may have thread, process, or application
00090  *              team scope, depending on what the -P assign option specifies.
00091  *      
00092  *      Return value is:
00093  *
00094  *               0 - normal return
00095  *              >0 - error code if an error occurred
00096  */
00097 
00098 int
00099 _f_open(
00100         FIOSPTR css,    /* Fortran statement state                            */
00101         unit    **cup_p,/* input: pointer to currently open unit.  output:    */
00102                         /* pointer to new unit.                               */
00103         olist   *olptr, /* OPEN information                                   */
00104         int     isf90)  /* 1 if being opened from CF90, 0 if CF77             */
00105 {
00106         register short  is_bin;         /* 1 if binary; else 0          */
00107         register short  is_fmt;         /* 1 if formatted; 0 if unformatted */
00108         register short  is_seq;         /* 1 if sequential; 0 if direct */
00109         register short  is_sys;         /* 1 if system; else 0          */
00110         register short  no_mem;         /* 1 if malloc() fails */
00111         register int    aifound;        /* 1 if assign/asgcmd info found */
00112         register int    errn;           /* Error code */
00113         register int    gamask;         /* Global assign mask */
00114         register int    oflags;         /* O_EXCL/O_CREAT */
00115         register int    P_value;        /* -P option value */
00116         register int    stdfn;          /* 1 if std file stdin/stdout/stderr */
00117         register int    stdfnum;        /* standard file descriptor number */
00118         register int    stat_ok;        /* 1 if statbuf is valid */
00119         register int    tufs;           /* requested file structure (default) */
00120         register int    uscope;         /* File scope */
00121         register unum_t unum;           /* unit number */
00122         char            namebuf[MXUNITSZ]; /* buffer to construct file name */
00123         char            *fname;         /* FILE= specifier or default filename*/
00124         char            *aname;         /* actual file name */
00125         char            *atstr;         /* assign attributes string */
00126         unit            *cup;
00127         assign_info     ai;
00128         struct stat     statbuf;
00129 
00130         unum    = olptr->ounit;
00131 
00132         if (! GOOD_UNUM(unum))
00133                 FERROR1(olptr->oerr, FEIVUNIT, unum);
00134 
00135 /*
00136  *      Check for a re-open before initializing any unit table fields.
00137  */
00138         if (OPEN_UPTR(*cup_p)) {
00139                 /*
00140                  * The unit is connected, but we have already checked in
00141                  * $OPN for reconnection to the same file with unchanged
00142                  * attributes.  Thus, we know that we may disconnect the unit
00143                  * here before continuing the set up of the new connection.
00144                  *
00145                  * We unlock it so that _alloc_unit may find it again and
00146                  * lock it.  
00147                  */
00148 
00149                 errn    = _unit_close(*cup_p, CLST_UNSPEC, NULL);
00150 
00151                 if (errn != 0)
00152                         FERROR(olptr->oerr, errn);
00153 
00154                 _release_cup(*cup_p);           /* unlock the unit */
00155         }
00156 
00157 /*
00158  *      "aname" receives the actual name to be opened by the system.
00159  *      It starts out the same as fname, but might later be reassigned
00160  *      by assign.
00161  */
00162 
00163         aname   = NULL;
00164         fname   = NULL;
00165         stdfn   = 0;
00166         no_mem  = 0;
00167 
00168         if (olptr->ofile == NULL) {             /* If no name specified */
00169 
00170                 if (olptr->ostatus == OS_SCRATCH) {      /* If SCRATCH */
00171                         int scratchfd;
00172                         /*
00173                          * Scratch files have no name (see INQUIRE).
00174                          */
00175                         fname   = NULL;
00176                         aname = strdup("FXXXXXX");
00177                         scratchfd = mkstemp(aname);
00178                         close(scratchfd); /* because mkstemp opens the file */
00179                 }
00180                 else if (unum == 0 || unum == 5 || unum == 6 ||
00181                          RSVD_UNUM(unum)) {
00182                         stdfn   = 1;    /* Possible standard file */
00183                         stdfnum = -1;
00184 
00185                         switch (unum) {
00186 
00187                         case 5: /* Connect 5 and 100 to stdin */
00188                         case 100:
00189                                 stdfnum = STDIN_FILENO;
00190                                 break;
00191                         case 6: /* Connect 6 and 101 to stdout */
00192                         case 101:
00193                                 stdfnum = STDOUT_FILENO;
00194                                 break;
00195                         case 0: /* Connect 0 and 102 to stderr/errfile */
00196                         case 102:               /* (see finit.c) */
00197                                 stdfnum = fileno(errfile);
00198                                 break;
00199                         default:
00200                                 _ferr(css, FEINTUNK);   /* deep weeds */
00201                         }
00202                 }
00203                 else {                  /* not scratch nor standard file */
00204 
00205                         (void) _fortname(namebuf, unum); /* Make default name */
00206 
00207                         fname   = strdup(namebuf);
00208                         aname   = strdup(namebuf);
00209                         no_mem  = (aname == NULL) || (fname == NULL);
00210                 }
00211         }
00212         else {                          /* Copy user supplied name */
00213                 if ((fname = malloc(olptr->ofilelen + 1)) != NULL) {
00214                         _copy_n_trim(olptr->ofile, olptr->ofilelen, fname);
00215                         aname   = strdup(fname);
00216                 }
00217 
00218                 no_mem  = (aname == NULL) || (fname == NULL);
00219         }
00220 
00221         if (no_mem) {                   /* If malloc() failed */
00222 
00223                 freeit(aname);
00224                 freeit(fname);
00225 
00226                 FERROR(olptr->oerr, FENOMEMY);          /* No memory */
00227         }
00228 
00229 
00230         is_bin  = (olptr->oform == OS_BINARY) ? 1 : 0;
00231         is_fmt  = (olptr->oform == OS_FORMATTED) ? 1 : 0;
00232         is_seq  = (olptr->oaccess == OS_SEQUENTIAL ? 1 : 0);
00233         is_sys  = (olptr->oform == OS_SYSTEM) ? 1 : 0;
00234 
00235 /*
00236  *      The ASN_G_SF/SU/DF/DU masks map to the ACCESS/FORM specifiers on OPEN.
00237  */
00238         switch ((is_seq << 3) | is_fmt) {
00239 
00240                 case 011:       /* Sequential Formatted */
00241                         gamask  = ASN_G_SF;
00242                         break;
00243 
00244                 case 010:       /* Sequential Unformatted */
00245                         gamask  = ASN_G_SU;
00246                         break;
00247 
00248                 case 001:       /* Direct Formatted */
00249                         gamask  = ASN_G_DF;
00250                         break;
00251 
00252                 case 000:       /* Direct Unformatted */
00253                         gamask  = ASN_G_DU;
00254                         break;
00255         }
00256 
00257         gamask  = gamask | ASN_G_ALL;
00258         atstr   = NULL;
00259         aifound = _assign_asgcmd_info(fname, unum, gamask, &ai, &atstr,
00260                              olptr->oerr);
00261 
00262         if (aifound == -1) {
00263                 freeit(fname);
00264                 freeit(aname);
00265                 freeit(atstr);
00266                 FERROR(olptr->oerr, errno);
00267         }
00268 
00269 /*
00270  *      Set up the scoping of this unit.   -P process is default.
00271  */
00272         uscope  = AS_PROCESS;           /* actual scope */
00273         P_value = AS_PROCESS;           /* -P option value, if any */
00274 
00275         if (aifound == 1 && ai.P_ioscop_flg) {
00276                 uscope  = ai.P_ioscop;
00277                 P_value = ai.P_ioscop;
00278                 /* Map -P private and -P global to the new spelling */
00279 #ifdef _CRAYMPP
00280                 if (ai.P_ioscop == AS_PRIVATE)
00281                         uscope  = AS_PROCESS;
00282 #else
00283                 if (ai.P_ioscop == AS_PRIVATE)
00284                         uscope  = AS_THREAD;
00285 
00286                 if (ai.P_ioscop == AS_GLOBAL)
00287                         uscope  = AS_PROCESS;
00288 #endif
00289         }
00290 
00291 #ifdef  _CRAYMPP
00292         if (uscope == AS_GLOBAL)
00293                 FERROR(olptr->oerr, FENOGLOB);
00294 
00295         if (uscope == AS_THREAD)
00296                 FERROR(olptr->oerr, FENOTHRD);
00297 
00298         if (uscope == AS_TEAM)
00299                 FERROR(olptr->oerr, FENOTEAM);
00300 #else
00301         if (uscope == AS_TEAM)
00302                 FERROR(olptr->oerr, FENOTEAM);
00303 #endif
00304 
00305 /*
00306  *      Now that we know the unit number and scope we can get a pointer to the 
00307  *      unit table.
00308  */
00309 #ifdef _CRAYMPP
00310         cup     = _alloc_unit(unum, 1);         /* TEMPORARY */
00311 #else
00312         cup     = _alloc_unit(unum, (uscope == AS_THREAD));
00313 #endif
00314         if (cup == NULL)
00315                 FERROR1(olptr->oerr, errno, unum);
00316 
00317         *cup_p          = cup;
00318 
00319 /*
00320  *      Record OPEN specifiers in unit table
00321  */
00322         cup->ubinary    = is_bin;
00323         cup->ufmt       = is_fmt;
00324         cup->useq       = is_seq;
00325         cup->usystem    = is_sys;
00326         cup->ublnk      = (olptr->oblank == OS_ZERO ? 1 : 0);
00327         cup->uposition  = olptr->oposition;
00328         cup->uaction    = olptr->oaction;
00329         cup->udelim     = olptr->odelim;
00330         cup->upad       = olptr->opad;
00331         cup->urecl      = olptr->orecl;
00332 
00333 /*
00334  *      Initialize the cf77/f90 mode.  It might be changed in f_asgn() later.
00335  */
00336         cup->uft90      = isf90;
00337 
00338         if (aifound == 1 && ai.a_actfil_flg) {
00339                 stdfn   = 0;    /* standard file overridden */
00340 
00341                 freeit(aname);
00342                 aname   = strdup(ai.a_actfil);
00343 
00344                 if (aname == NULL) {
00345                         freeit(atstr);
00346                         freeit(fname);
00347                         FERROR(olptr->oerr, FENOMEMY);
00348                 }
00349         }
00350  
00351         if (aifound == 1 && ai.D_fildes_flg) {
00352                 stdfn   = 1;    /* indicate standard file */
00353                 stdfnum = ai.D_fildes;
00354 
00355                 freeit(aname);
00356                 aname   = NULL;
00357         }
00358 
00359 /*
00360  *      Units connected to stdin, stdout, or stderr may not have thread scope
00361  *      on PVP systems.
00362  */
00363 #ifdef  _CRAYMPP
00364         if (stdfn && uscope == AS_TEAM) {
00365                 freeit(fname);
00366                 freeit(aname);
00367                 freeit(atstr);
00368                 FERROR(olptr->oerr, FENOTEAM);
00369         }
00370 #else
00371         if (stdfn && uscope == AS_THREAD) {
00372                 freeit(fname);
00373                 freeit(aname);
00374                 freeit(atstr);
00375                 FERROR(olptr->oerr, (P_value==AS_PRIVATE)? FENOPRIV: FENOTHRD);
00376         }
00377 #endif
00378 
00379 /*
00380  *      Set up cup->urecsize, the maximum record size.  If RECL was
00381  *      specified (it's required on direct access files; optional
00382  *      on sequential access files), then RECL becomes the maximum
00383  *      record size for all formatted I/O on this unit.  Otherwise
00384  *      we use default values for the maximum record size for both
00385  *      regular I/O and list-directed/namelist output.
00386  */
00387 
00388         if (cup->ufmt) {        /* If formatted file */
00389 
00390                 if (cup->urecl > 0) {   /* If RECL specified */
00391                         cup->urecsize   = cup->urecl;
00392                         cup->uldwsize   = cup->urecl;
00393                 }
00394                 else {                  /* Else set defaults */
00395                         cup->urecsize   = _f_rcsz;
00396                         cup->uldwsize   = _f_ldsz;
00397                 }
00398 
00399                 /* Allocate line buffer for formatted files */
00400 
00401                 cup->ulinebuf   = (long *) malloc(sizeof(long) *
00402                                                 (cup->urecsize + 1));
00403 
00404                 if (cup->ulinebuf == NULL) {
00405                         freeit(fname);
00406                         freeit(aname);
00407                         freeit(atstr);
00408                         FERROR(olptr->oerr, FENOMEMY);
00409                 }
00410         }
00411 
00412 /*
00413  *      See if the file exists.  We don't know the filename for sure if FFIO
00414  *      is being used though.
00415  */
00416         errn    = 0;
00417         stat_ok = 0;
00418 
00419         if (stdfn) {
00420                 errn    = fstat(stdfnum, &statbuf);
00421                 stat_ok = 1;
00422         }
00423         else if (aifound == 0 || ai.F_filter_flg == 0) {
00424                 errn    = stat(aname, &statbuf);
00425                 stat_ok = 1;
00426         }
00427 
00428         /*
00429          * ENOENT means the file doesn't exist.  EINTR means the request
00430          * was interrupted.  If we got an EINTR error, retry the stat
00431          * request a few times.  A persistent EINTR error or any other
00432          * stat error besides ENOENT is fatal.
00433          *
00434          * On UNICOS and UNICOS/mk systems, a EINTR error should never
00435          * occur on a stat request... but we've seen some on UNICOS/mk
00436          * for a reason the kernel developers do not understand.
00437          */
00438 
00439         if (stat_ok && errn == -1) {    /* If we did a stat and it failed */
00440                 register short  retry = 0;
00441 
00442                 while (errn == -1 && errno == EINTR && retry++ < 10) {
00443                         if (stdfn)
00444                                 errn    = fstat(stdfnum, &statbuf);
00445                         else 
00446                                 errn    = stat(aname, &statbuf);
00447                 }
00448 
00449                 if (errn == -1) {       /* We have a hard failure */
00450 
00451                         stat_ok = 0;
00452 
00453                         if (errno != ENOENT) {  /* If not ENOENT, abort */
00454                                 freeit(fname);
00455                                 freeit(aname);
00456                                 freeit(atstr);
00457                                 freeit(cup->ulinebuf);
00458                                 FERROR(olptr->oerr, errno);
00459                         }
00460                 }
00461         }
00462 
00463         /* Select the file structure */
00464 
00465         if (aifound == 1 && (ai.s_fstrct_flg || ai.F_filter_flg)) {
00466                 if (ai.F_filter_flg)
00467                         tufs    = FS_FDC;
00468                 else
00469                         tufs    = ai.s_fstrct;
00470         }
00471         else {
00472                 /* Select default file structure */
00473 
00474                 if ( cup->ufmt )                /* if formatted */
00475 #if     defined(__mips) || defined(_LITTLE_ENDIAN)
00476                         tufs    = (cup->useq) ? FS_TEXT : FS_UNBLOCKED;
00477 #else
00478                         tufs    = FS_TEXT;
00479 #endif
00480                 else {                          /* else unformatted */
00481 #ifdef  _UNICOS
00482                         tufs    = (cup->useq) ? FS_COS : FS_UNBLOCKED;
00483 #else   /* else NOT _UNICOS */
00484                         tufs    = (cup->useq) ? FS_F77 : FS_UNBLOCKED;
00485 #endif  /* END _UNICOS */
00486                         if (is_bin || is_sys) {
00487                                 /*
00488                                  * Use UNBLOCKED layer for direct or
00489                                  * sequential unformatted IO that does
00490                                  * not contain record control images.
00491                                  * Formatted IO is not allowed (i.e., a) 
00492                                  */
00493                                 tufs    = FS_UNBLOCKED;
00494                         }
00495 
00496                 }
00497 
00498                 /* See if the device is a tape and handle it accordingly */
00499 
00500                 if (stat_ok && _gsys_qtape(&statbuf) != 0)
00501                         tufs    = FS_TAPE;
00502         }
00503  
00504         /*
00505          * Process the open for standard files (STDIN_FILENO, STDOUT_FILENO
00506          * or STDERR_FILENO)
00507          */
00508 
00509         if (stdfn) {
00510                 FILE    *stdf;
00511 
00512 #if     defined(_LITTLE_ENDIAN) && !defined(__sv2)
00513                 /* iob not the same on non-sv2 little endian systems.
00514                  * Use the following:
00515                  */
00516                 switch(stdfnum) {
00517                 case(STDIN_FILENO):
00518                         stdf    = _IO_stdin;
00519                         break;
00520                 case(STDOUT_FILENO):
00521                         stdf    = _IO_stdout;
00522                         break;
00523                 default:
00524                         stdf    = _IO_stderr;
00525                         break;
00526                 }
00527 #else
00528                 stdf    = &__iob[stdfnum];
00529 #endif
00530 
00531                 if (!cup->useq || !cup->ufmt ||
00532                     (tufs != FS_TEXT && tufs != STD)) {
00533                         freeit(fname);
00534                         freeit(aname);
00535                         freeit(atstr);
00536                         freeit(cup->ulinebuf);
00537                         FERROR(olptr->oerr, FEOPSTFN); /* Std file mismatch */
00538                 }
00539 
00540                 if (stdfnum < STDIN_FILENO || stdfnum > STDERR_FILENO) {
00541                         /* Should not happen because assign filters out */
00542                         /* unsupported file descriptor values */
00543                         freeit(fname);
00544                         freeit(aname);
00545                         freeit(atstr);
00546                         freeit(cup->ulinebuf);
00547                         FERROR(olptr->oerr,FEINTUNK);
00548                 }
00549 
00550                 if (fileno(stdf) != stdfnum) {
00551                         /* Stdio file has been reopened with an alternate */
00552                         /* file descriptor! */
00553                         freeit(fname);
00554                         freeit(aname);
00555                         freeit(atstr);
00556                         freeit(cup->ulinebuf);
00557                         FERROR(olptr->oerr,FEINTUNK);
00558                 }
00559                 
00560                 cup->ufp.std    = stdf;
00561 
00562                 /*
00563                  * The auxiliary lock protects multiple units connected to
00564                  * the same standard file.
00565                  */
00566                 switch (stdfnum) {
00567                         case STDIN_FILENO:
00568                                 cup->auxlockp   = &_stdin_lock;
00569                                 break;
00570 
00571                         case STDOUT_FILENO:
00572                                 cup->auxlockp   = &_stdout_lock;
00573                                 break;
00574 
00575                         case STDERR_FILENO:
00576                                 cup->auxlockp   = &_stderr_lock;
00577                                 break;
00578                 }
00579 
00580                 /*
00581                  * Standard files have no Fortran name.
00582                  */
00583 
00584                 freeit(aname);
00585                 freeit(fname);
00586                 aname   = NULL;
00587                 fname   = NULL;
00588         }
00589 
00590         /*
00591          * Record the file name and unit number in the unit.  The alfnm field
00592          * might be changed later.
00593          */
00594 
00595         cup->ufnm       = fname;
00596         cup->alfnm      = aname;
00597         cup->uid        = unum;
00598 
00599         /* Process the STATUS specifier */
00600 
00601         cup->uostatus   = olptr->ostatus;
00602 
00603         switch (olptr->ostatus) {
00604 
00605                 case OS_UNKNOWN:
00606                 default:
00607                         oflags  = O_CREAT;
00608                         break;
00609  
00610                 case OS_SCRATCH:
00611                         cup->uscrtch    = 1;
00612                         oflags  = O_CREAT;
00613                         break;
00614 
00615                 case OS_OLD:
00616                         oflags  = 0;
00617                         break;
00618 
00619                 case OS_NEW:
00620                         /* Unless tape or pipe, file is not allowed to exist */
00621 
00622                         if (stat_ok && !S_ISCHR(statbuf.st_mode) &&
00623                             !S_ISFIFO(statbuf.st_mode)) {
00624                                 freeit(fname);
00625                                 freeit(aname);
00626                                 freeit(atstr);
00627                                 freeit(cup->ulinebuf);
00628                                 FERROR(olptr->oerr, FEOPFNNX);
00629                         }
00630 
00631                         cup->uostatus   = OS_OLD;       /* NEW becomes OLD */
00632 
00633                         oflags  = O_EXCL | O_CREAT;
00634                         break;
00635 
00636                 case OS_REPLACE:
00637                         /*
00638                          * Fortran 90 addition to replace existing file with
00639                          * a new file or create new file if no file exists.
00640                          * The error check on use of filename with the new
00641                          * option is in opn.c.
00642                          */
00643                         cup->uostatus   = OS_OLD;  /* REPLACE becomes OLD */
00644 
00645                         oflags  = O_CREAT;
00646                         break;
00647 
00648         } /* switch */
00649 
00650         /* Open the file; use whatever permissions are available */
00651 
00652         errn    = _f_opn(aname, cup, css, tufs, aifound, &ai, &statbuf, 
00653                         stat_ok, olptr->oerr, oflags);
00654 
00655         if (errn != OK) {
00656                 errn    = errno;
00657                 /*
00658                  * Map EEXIST to something more meaningfull to Fortran users.
00659                  */
00660                 if (errn == EEXIST)
00661                         errn    = FEOPFNNX;
00662 
00663                 goto open_error;
00664         }
00665 
00666 #ifdef  _CRAYMPP
00667         /* Don't trunc() standard files on the MPP, since they're shared */
00668         if (stdfn)
00669                 cup->utrunc     = 0;    /* Clear trunc() flag */
00670 #endif
00671 
00672 /*
00673  *      Check that another unit hasn't been opened to the same file
00674  */ 
00675         _set_device_and_inode(cup->usysfd, &cup->udevice, &cup->uinode);
00676 
00677         errn    = _uniqinod(cup, (aifound ? &ai : NULL));
00678 
00679         if (errn != 0)
00680                 goto open_error;
00681 
00682 /*
00683  *      Check that the same unit number is not opened at more than one
00684  *      scoping level.
00685  */
00686         errn    = _mixed_scope(cup);
00687 
00688         if (errn != 0)
00689                 goto open_error;
00690 
00691 /***************************************************************************
00692  *                                                                         *
00693  *      The unit is now a valid connected unit.                            *
00694  *                                                                         *
00695  ***************************************************************************/
00696 
00697 /*
00698  *      Truncate the file to zero size if STATUS='REPLACE'.
00699  */
00700         if (olptr->ostatus == OS_REPLACE) {
00701                 errn    = _unit_trunc(cup);
00702 
00703                 if (errn != 0)
00704                         goto open_error;
00705 
00706                 /*
00707                  * Some FDC layers cannot read after write, and
00708                  * unit_trunc is like a write to FDC layers; so
00709                  * do a seek to clear the last-operation-was-a-write
00710                  * status.
00711                  */
00712                 if (cup->ufs == FS_FDC) {
00713                         struct ffsw     fst;
00714 
00715                         XRCALL(cup->ufp.fdc, seekrtn) cup->ufp.fdc, 0, 0, &fst);
00716                 }
00717 
00718                 cup->udamax     = 0;
00719         }
00720 
00721 /*
00722  *      Position the file as specified with the POSITION specifier 
00723  */
00724         switch (cup->uposition) {
00725 
00726                 case OS_REWIND:
00727                 case OS_ASIS:   /* do nothing */
00728                         break;
00729 
00730                 case OS_APPEND: /* Position to end of file. */
00731 
00732                         /* position to end */
00733                         {
00734                                 int     neg1;
00735 
00736                                 neg1    = -1;
00737                                 errn    = _setpos(css, cup, &neg1, 1);
00738 
00739                                 if (errn != 0)
00740                                         goto open_error;
00741 
00742                                 errn    = _unit_bksp(cup);
00743 
00744                                 if (errn != 0)
00745                                         goto open_error;
00746                         }
00747                         break;
00748 
00749         } /* switch */
00750 
00751 /*
00752  *      If assigned with -t, unlink it now.
00753  */
00754         if (cup->utmpfil) {
00755                 errn    = _unit_scratch(cup);
00756 
00757                 if (errn != 0)
00758                         goto open_error;
00759         }
00760 
00761 /*
00762  *      Set up OK flags to speed up error checking in I/O statements.
00763  */
00764         _set_ok_flags(cup);
00765 
00766         if (FORTSTATS) {
00767                 /*
00768                  * Now initialize statistics counting for this unit.
00769                  */
00770                 if (_ft_stopen(cup, atstr) == -1) {
00771                         errn    = errno;
00772                         goto open_error;
00773                 }
00774         }
00775 
00776         freeit(atstr);
00777 
00778 /*
00779  *      The auxliary lock needs to be locked.   If this is a reopen,
00780  *      _unit_close() unlocked it.   Otherwise it has not yet been locked. 
00781  */
00782 
00783         if (cup->auxlockp != NULL)
00784                 MEM_LOCK(cup->auxlockp);
00785 
00786         return(0);
00787 
00788         /* Process error(s) */
00789 
00790 open_error:             /* Error code is in errn */
00791         freeit(atstr);
00792         (void)_unit_close(cup, CLST_UNSPEC, NULL);
00793 
00794         FERROR(olptr->oerr, errn);
00795 
00796         return(0);      /* not reached */
00797 }
00798 
00799 /*
00800  *      Free a pointer if it's non-null.
00801  */
00802 static void
00803 freeit(void *ptr)
00804 {
00805         if (ptr != NULL)
00806                 free(ptr);
00807 }
00808 
00809 /*
00810  *      _set_ok_flags
00811  *
00812  *              Initialize all cup->ok_* flags in a unit.  This function is 
00813  *              called by _f_open() and _init_internal_unit().
00814  */
00815 
00816 void
00817 _set_ok_flags(unit *cup)
00818 {
00819         cup->ok_wr_seq_fmt = _get_mismatch_error(1, T_WSF, cup, NULL) == 0;
00820         cup->ok_wr_seq_unf = _get_mismatch_error(1, T_WSU, cup, NULL) == 0;
00821         cup->ok_wr_dir_fmt = _get_mismatch_error(1, T_WDF, cup, NULL) == 0;
00822         cup->ok_wr_dir_unf = _get_mismatch_error(1, T_WDU, cup, NULL) == 0;
00823 
00824         cup->ok_rd_seq_fmt = _get_mismatch_error(1, T_RSF, cup, NULL) == 0;
00825         cup->ok_rd_seq_unf = _get_mismatch_error(1, T_RSU, cup, NULL) == 0;
00826         cup->ok_rd_dir_fmt = _get_mismatch_error(1, T_RDF, cup, NULL) == 0;
00827         cup->ok_rd_dir_unf = _get_mismatch_error(1, T_RDU, cup, NULL) == 0;
00828 
00829         return;
00830 }
00831 
00832 /*
00833  *      _get_mismatch_error
00834  *
00835  *              This function evaluates the unchanging properties of
00836  *              a unit (ie. cup->ufmt, etc.), to determine whether particular
00837  *              types of I/O statements are valid for this unit.  This routine
00838  *              is called once at open time to set up the cup->ok_* fields in
00839  *              the unit table.  They are also called if an error is detected
00840  *              in _FWF, _FRF, _FWU, or _FRU.
00841  *
00842  *      Return Value:
00843  *
00844  *              The error number.  If the noabort argument is 0, then this
00845  *              function calls _ferr().
00846  */
00847 
00848 int
00849 _get_mismatch_error(
00850         int     noabort,/* nonzero if we should not abort on error */
00851         int     iost,   /* type of I/O statement (T_WSF, ...) */
00852         unit    *cup,   /* unit pointer */
00853         FIOSPTR css)    /* Fortran I/O statement state; May be NULL if
00854                          * noabort is nonzero */ 
00855 {
00856         register int    errn = 0;
00857 
00858         if (cup->ufs == FS_AUX) {
00859                 errn    = FEMIXAUX;
00860                 goto ret;
00861         }
00862 
00863         /* if write statement, else read statement ... */
00864 
00865         if (iost & TF_WRITE) {
00866                 if ((cup->uaction & OS_WRITE) == 0) {
00867                         errn    = FENOWRIT;     /* No write permission */
00868                         goto ret;
00869                 }
00870         }
00871         else {
00872                 if ((cup->uaction & OS_READ) == 0) {
00873                         errn    = FENOREAD;     /* No read permission */
00874                         goto ret;
00875                 }
00876         }
00877 
00878         /* if formatted I/O statement, else unformatted ... */
00879 
00880         if (iost & TF_FMT) {
00881                 if (!cup->ufmt) {
00882                         errn    = FEFMTTIV;     /* Formatted not allowed */
00883                         goto ret;
00884                 }
00885         }
00886         else {
00887                 if (cup->ufmt) {
00888                         errn    = FEUNFMIV;     /* Unformatted not allowed */
00889                         goto ret;
00890                 }
00891         }
00892 
00893         /* if direct access I/O statement, else sequential ... */
00894 
00895         if (iost == T_WDF || iost == T_WDU || iost == T_RDF || iost == T_RDU) {
00896                 if (cup->useq) {
00897                         errn    = FEDIRTIV;     /* Direct access not allowed */
00898                         goto ret;
00899                 }
00900         } else {
00901                 if (cup->useq == 0) {
00902                         errn    = FESEQTIV;     /* Sequential not allowed */
00903                         goto ret;
00904                 }
00905         }
00906 
00907 ret:
00908         if (noabort)
00909                 return(errn);
00910         else {
00911                 if (errn == 0)
00912                         errn    = FEINTUNK;     /* force an abort */
00913         
00914                 _ferr(css, errn);
00915         }
00916 
00917         return(FEINTUNK);       /* not reached */
00918 }
00919 
00920 #ifdef  _UNICOS
00921 /*
00922  *      The module open.c must have hard references to any routines which
00923  *      are needed for Fortran I/O initialization.  The functions referenced
00924  *      here are accessed with soft references by $START and are called at
00925  *      startup time only if they have hard reverences.
00926  *
00927  *      It is assumed that any Fortran program which does Fortran I/O has
00928  *      hard references to some entry point in this module (usually _f_open
00929  *      through _implicit_open).  Internal file I/O processing is integrated 
00930  *      with the external I/O path, so internal Fortran I/O statements DO 
00931  *      cause hard references to open.c.
00932  *
00933  *      __fio_hardrefs() should NEVER be called.
00934  */
00935 
00936 void
00937 __fio_hardrefs()
00938 {
00939         (void) _finit();        /* Has a soft reference in $START.  It is
00940                                  * called only for programs which do Fortran
00941                                  * I/O. */
00942 
00943 #if     defined(_CRAY1) 
00944         (void) _repriev();      /* A hard reference of _repriev causes the
00945                                  * appropriate style of program abort
00946                                  * handling for programs which do Fortran
00947                                  * I/O. */
00948 #endif
00949 }
00950 
00951 #endif  /* _UNICOS */

Generated on Tue Nov 17 05:54:42 2009 for Open64 (mfef90, whirl2f, and IR tools) by  doxygen 1.6.1