1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
 SAF_PathInfo
 saf_readInfo_path(
    const char *path,    /* [IN] path of a file to get the info for */
    int independent      /* [IN] A flag for independent operation. If non-zero, perform the work and return the results only on
                            the calling processor. Otherwise, this function must be called collectively by all processors in
                            the communicator used to init the SAF library. In other words, call this function from one processor
                            with a non-zero value for this argument or call it an all processors with a zero argument on all
                            processors. Note also that if this call is made independently, then all succeeding calls involving
                            the returned SAF_PathInfo object must be made independently and by the same processor. */
 )
 {
    SAF_ENTER(saf_readInfo_path,NULL);

    int rank=0;
    SAF_PathInfo result;
    int theStats[2];

    SAF_REQUIRE(path!=NULL,SAF_LOW_CHK_COST,NULL,_saf_errmsg("path must be non-NULL"));

    independent = independent; /* quite the compiler */

 #ifdef HAVE_PARALLEL
    if (!independent)
       MPI_Comm_rank(_SAF_GLOBALS.p.LibComm,&rank);
 #endif

    /* allocate the SAF_PathInfo stuff */
    result = (SAF_PathInfo) calloc(1, sizeof(SAF_PathInfoPkt));

    /* in all cases, only stat the file on processor 0 in the lib communicator */
    if (rank == 0)
    {
       struct stat statBuf;

       /* stat the file */
       if (stat(path, &statBuf)==-1)
          theStats[0] = errno;
       else
       {
          theStats[0] = 0;

 #ifdef WIN32
         /* These S_* #defines dont exist in WIN32*/
         #define S_IRWXU _S_IREAD|_S_IWRITE|_S_IEXEC /*owner, = 00700*/
         #define S_IRWXG 00070 /*group*/
         #define S_IRWXO 00007 /*others*/
 #endif

          theStats[1] = (int) (statBuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
       }

       /* if the stat succeeded, theStats[0] will be zero and we can proceed. In such case, to save a broadcast, I next test
          whether the file is an HDF5 file and if not, set theStats[0] to a contrived error code for that case. The only worry
          is to make sure my contrived error code does not collide with another case in the switch statement below. */
       if (!theStats[0] && !H5Fis_hdf5(path))
          theStats[0] = ENOTHDF5;

    }

 #ifdef HAVE_PARALLEL
    if (!independent)
       MPI_Bcast(&theStats, 2, MPI_INT, 0, _SAF_GLOBALS.p.LibComm);
 #endif

    /* handle any inital errors */
    if (theStats[0])
    {
       result->statError = 1;
       result->permissions = theStats[1];
       switch (theStats[0])
       {
          case ENOTHDF5: result->errStr = _saf_strdup("not an hdf5 file"); break;
          case EACCES:   result->errStr = _saf_strdup("permission denied"); break;
          case ENOENT:   result->errStr = _saf_strdup("does not exist"); break;
          case ENOTDIR:  result->errStr = _saf_strdup("invalid path"); break;
          default:
          {
             result->errStr = (char *) malloc(32);
             sprintf(result->errStr,"unspecified stat error %d",theStats[0]);
             break;
          }
       }
       goto done;
    }
    else
    {
       result->statError = 0;
       result->permissions = theStats[1];
    }

    /* at this point, we know we can read the file and that it is an HDF5 file */

    /* we proceed using HDF interface to obtain SAF's version stuff because we can't always be assured we will have
       a valid SSlib file AND we'd like to return as much information to the client as possible AND, once we've coded
       to use HDF5, there is little point in also doing it with anything higher */
    {
        hid_t fid, topgroup, attr, dtype, fprop_id;

 #ifdef HAVE_PARALLEL
       fprop_id = H5Pcreate(H5P_FILE_ACCESS);
       if (independent) {
           H5Pset_fapl_mpio(fprop_id, MPI_COMM_SELF, MPI_INFO_NULL);
       } else {
           H5Pset_fapl_mpio(fprop_id, _SAF_GLOBALS.p.LibComm, MPI_INFO_NULL);
       }
 #else
       fprop_id = H5Pcopy(H5P_DEFAULT);
 #endif

       /* try to open the file */
       fid = H5Fopen(path, H5F_ACC_RDONLY, fprop_id);
       H5Pclose(fprop_id);

       if (fid < 0)
       {
          result->isHDFfile = 0;
          goto done;
       }
       else
          result->isHDFfile = 1;

       /* open the "/SAF" group, which is the name of the top-level scope in an SSlib file */
       H5E_BEGIN_TRY {
          topgroup = H5Gopen(fid,"/SAF");
       } H5E_END_TRY

       if (topgroup < 0)
       {
          H5Fclose(fid);
          goto done;
       }

       /* obtain data type, size information and allocate space for data */
       attr = H5Aopen_name(topgroup, "version");
       dtype = H5Aget_type(attr);
       result->dbPropsType = H5Tget_native_type(dtype, H5T_DIR_DEFAULT);
       result->dbPropsBuf = malloc(H5Tget_size(result->dbPropsType));

       /* read the DbProps attribute */
       H5Aread(attr, result->dbPropsType, result->dbPropsBuf);

       H5Tclose(dtype);
       H5Aclose(attr);
       H5Gclose(topgroup);
       H5Fclose(fid);
    }

    result->allOk = 1;

  done:
    SAF_LEAVE(result);
 }