nc4file.c 92 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203
  1. /** \file
  2. The netCDF-4 file functions.
  3. This file is part of netcdf-4, a netCDF-like interface for HDF5, or
  4. a HDF5 backend for netCDF, depending on your point of view.
  5. Copyright 2003, University Corporation for Atmospheric Research. See
  6. COPYRIGHT file for copying and redistribution conditions.
  7. */
  8. #include "nc4internal.h"
  9. #include "nc.h"
  10. #include <H5DSpublic.h>
  11. #include "nc4dispatch.h"
  12. #include "ncdispatch.h"
  13. #ifdef USE_HDF4
  14. #include <mfhdf.h>
  15. #endif
  16. #ifdef USE_PNETCDF
  17. #include <pnetcdf.h>
  18. #endif
  19. /* This is to track opened HDF5 objects to make sure they are
  20. * closed. */
  21. #ifdef EXTRA_TESTS
  22. extern int num_plists;
  23. extern int num_spaces;
  24. #endif /* EXTRA_TESTS */
  25. #define MIN_DEFLATE_LEVEL 0
  26. #define MAX_DEFLATE_LEVEL 9
  27. /* These are the special attributes added by the HDF5 dimension scale
  28. * API. They will be ignored by netCDF-4. */
  29. #define REFERENCE_LIST "REFERENCE_LIST"
  30. #define CLASS "CLASS"
  31. #define DIMENSION_LIST "DIMENSION_LIST"
  32. #define NAME "NAME"
  33. /* Forward */
  34. static int NC4_enddef(int ncid);
  35. static int nc4_rec_read_types(NC_GRP_INFO_T *grp);
  36. static int nc4_rec_read_vars(NC_GRP_INFO_T *grp);
  37. #ifdef IGNORE
  38. /* This extern points to the pointer that holds the list of open
  39. * netCDF files. */
  40. extern NC_FILE_INFO_T *nc_file;
  41. #endif
  42. /* These are the default chunk cache sizes for HDF5 files created or
  43. * opened with netCDF-4. */
  44. size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
  45. size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
  46. float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
  47. /* This is set by nc_set_default_format in libsrc/nc.c. */
  48. extern int default_create_format;
  49. /* To turn off HDF5 error messages, I have to catch an early
  50. invocation of a netcdf function. */
  51. static int virgin = 1;
  52. /* For performance, fill this array only the first time, and keep it
  53. * in global memory for each further use. */
  54. #define NUM_TYPES 12
  55. static hid_t native_type_constant[NUM_TYPES];
  56. static char nc_type_name[NUM_TYPES][NC_MAX_NAME + 1] = {"char", "byte", "short", "int", "float",
  57. "double", "ubyte", "ushort", "uint",
  58. "int64", "uint64", "string"};
  59. int nc4_free_global_hdf_string_typeid();
  60. /* Set chunk cache size. Only affects files opened/created *after* it
  61. * is called. */
  62. int
  63. nc_set_chunk_cache(size_t size, size_t nelems, float preemption)
  64. {
  65. if (preemption < 0 || preemption > 1)
  66. return NC_EINVAL;
  67. nc4_chunk_cache_size = size;
  68. nc4_chunk_cache_nelems = nelems;
  69. nc4_chunk_cache_preemption = preemption;
  70. return NC_NOERR;
  71. }
  72. /* Get chunk cache size. Only affects files opened/created *after* it
  73. * is called. */
  74. int
  75. nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp)
  76. {
  77. if (sizep)
  78. *sizep = nc4_chunk_cache_size;
  79. if (nelemsp)
  80. *nelemsp = nc4_chunk_cache_nelems;
  81. if (preemptionp)
  82. *preemptionp = nc4_chunk_cache_preemption;
  83. return NC_NOERR;
  84. }
  85. /* Required for fortran to avoid size_t issues. */
  86. int
  87. nc_set_chunk_cache_ints(int size, int nelems, int preemption)
  88. {
  89. if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100)
  90. return NC_EINVAL;
  91. nc4_chunk_cache_size = size;
  92. nc4_chunk_cache_nelems = nelems;
  93. nc4_chunk_cache_preemption = (float)preemption / 100;
  94. return NC_NOERR;
  95. }
  96. int
  97. nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp)
  98. {
  99. if (sizep)
  100. *sizep = (int)nc4_chunk_cache_size;
  101. if (nelemsp)
  102. *nelemsp = (int)nc4_chunk_cache_nelems;
  103. if (preemptionp)
  104. *preemptionp = (int)(nc4_chunk_cache_preemption * 100);
  105. return NC_NOERR;
  106. }
  107. /* This will return the length of a netcdf data type in bytes. */
  108. int
  109. nc4typelen(nc_type type)
  110. {
  111. switch(type){
  112. case NC_BYTE:
  113. case NC_CHAR:
  114. case NC_UBYTE:
  115. return 1;
  116. case NC_USHORT:
  117. case NC_SHORT:
  118. return 2;
  119. case NC_FLOAT:
  120. case NC_INT:
  121. case NC_UINT:
  122. return 4;
  123. case NC_DOUBLE:
  124. case NC_INT64:
  125. case NC_UINT64:
  126. return 8;
  127. }
  128. return -1;
  129. }
  130. /* Given a filename, check to see if it is a HDF5 file. */
  131. #define MAGIC_NUMBER_LEN 4
  132. #define NC_HDF5_FILE 1
  133. #define NC_HDF4_FILE 2
  134. static int
  135. nc_check_for_hdf(const char *path, int use_parallel, MPI_Comm comm, MPI_Info info,
  136. int *hdf_file)
  137. {
  138. char blob[MAGIC_NUMBER_LEN];
  139. assert(hdf_file && path);
  140. LOG((3, "nc_check_for_hdf: path %s", path));
  141. /* Get the 4-byte blob from the beginning of the file. Don't use posix
  142. * for parallel, use the MPI functions instead. */
  143. #ifdef USE_PARALLEL
  144. if (use_parallel)
  145. {
  146. MPI_File fh;
  147. MPI_Status status;
  148. int retval;
  149. if ((retval = MPI_File_open(comm, (char *)path, MPI_MODE_RDONLY,
  150. info, &fh)) != MPI_SUCCESS)
  151. return NC_EPARINIT;
  152. if ((retval = MPI_File_read(fh, blob, MAGIC_NUMBER_LEN, MPI_CHAR,
  153. &status)) != MPI_SUCCESS)
  154. return NC_EPARINIT;
  155. if ((retval = MPI_File_close(&fh)) != MPI_SUCCESS)
  156. return NC_EPARINIT;
  157. }
  158. else
  159. #endif /* USE_PARALLEL */
  160. {
  161. FILE *fp;
  162. if (!(fp = fopen(path, "r")) ||
  163. fread(blob, MAGIC_NUMBER_LEN, 1, fp) != 1)
  164. return errno;
  165. fclose(fp);
  166. }
  167. /* Ignore the first byte for HDF5. */
  168. if (blob[1] == 'H' && blob[2] == 'D' && blob[3] == 'F')
  169. *hdf_file = NC_HDF5_FILE;
  170. else if (!strncmp(blob, "\016\003\023\001", MAGIC_NUMBER_LEN))
  171. *hdf_file = NC_HDF4_FILE;
  172. else
  173. *hdf_file = 0;
  174. return NC_NOERR;
  175. }
  176. /* Create a HDF5/netcdf-4 file. In this case, ncid has already been
  177. * selected in ncfunc.c. */
  178. static int
  179. nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info,
  180. NC_FILE_INFO_T *nc)
  181. {
  182. hid_t fcpl_id, fapl_id;
  183. unsigned flags;
  184. FILE *fp;
  185. int retval = NC_NOERR;
  186. int persist = 0; /* Should diskless try to persist its data into file?*/
  187. if(cmode & NC_DISKLESS)
  188. flags = H5F_ACC_TRUNC;
  189. else if(cmode & NC_NOCLOBBER)
  190. flags = H5F_ACC_EXCL;
  191. else
  192. flags = H5F_ACC_TRUNC;
  193. LOG((3, "nc4_create_file: path %s mode 0x%x", path, cmode));
  194. assert(nc && path);
  195. /* If this file already exists, and NC_NOCLOBBER is specified,
  196. return an error. */
  197. if (cmode & NC_DISKLESS) {
  198. if(cmode & NC_WRITE)
  199. persist = 1;
  200. } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) {
  201. fclose(fp);
  202. return NC_EEXIST;
  203. }
  204. /* Add necessary structs to hold netcdf-4 file data. */
  205. if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode))))
  206. BAIL(retval);
  207. assert(nc->nc4_info && nc->nc4_info->root_grp);
  208. /* Need this access plist to control how HDF5 handles open onjects
  209. * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
  210. * fail if there are any open objects in the file. */
  211. if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
  212. BAIL(NC_EHDFERR);
  213. #ifdef EXTRA_TESTS
  214. num_plists++;
  215. #endif
  216. #ifdef EXTRA_TESTS
  217. if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
  218. BAIL(NC_EHDFERR);
  219. #else
  220. if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG))
  221. BAIL(NC_EHDFERR);
  222. #endif /* EXTRA_TESTS */
  223. #ifdef USE_PARALLEL
  224. /* If this is a parallel file create, set up the file creation
  225. property list. */
  226. if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX))
  227. {
  228. nc->nc4_info->parallel++;
  229. if (cmode & NC_MPIIO) /* MPI/IO */
  230. {
  231. LOG((4, "creating parallel file with MPI/IO"));
  232. if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
  233. BAIL(NC_EPARINIT);
  234. }
  235. else /* MPI/POSIX */
  236. {
  237. LOG((4, "creating parallel file with MPI/posix"));
  238. if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
  239. BAIL(NC_EPARINIT);
  240. }
  241. }
  242. #else /* only set cache for non-parallel... */
  243. if(cmode & NC_DISKLESS) {
  244. if (H5Pset_fapl_core(fapl_id, 4096, persist))
  245. BAIL(NC_EDISKLESS);
  246. }
  247. if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
  248. nc4_chunk_cache_preemption) < 0)
  249. BAIL(NC_EHDFERR);
  250. LOG((4, "nc4_create_file: set HDF raw chunk cache to size %d nelems %d preemption %f",
  251. nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption));
  252. #endif /* USE_PARALLEL */
  253. if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_18, H5F_LIBVER_18) < 0)
  254. BAIL(NC_EHDFERR);
  255. /* Create the property list. */
  256. if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0)
  257. BAIL(NC_EHDFERR);
  258. #ifdef EXTRA_TESTS
  259. num_plists++;
  260. #endif
  261. /* Set latest_format in access propertly list and
  262. * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
  263. * on HDF5 creation ordering. */
  264. if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
  265. H5P_CRT_ORDER_INDEXED)) < 0)
  266. BAIL(NC_EHDFERR);
  267. if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
  268. H5P_CRT_ORDER_INDEXED)) < 0)
  269. BAIL(NC_EHDFERR);
  270. /* Create the file. */
  271. if ((nc->nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
  272. BAIL(NC_EFILEMETA);
  273. /* Open the root group. */
  274. if ((nc->nc4_info->root_grp->hdf_grpid = H5Gopen2(nc->nc4_info->hdfid, "/",
  275. H5P_DEFAULT)) < 0)
  276. BAIL(NC_EFILEMETA);
  277. /* Release the property lists. */
  278. if (H5Pclose(fapl_id) < 0 ||
  279. H5Pclose(fcpl_id) < 0)
  280. BAIL(NC_EHDFERR);
  281. #ifdef EXTRA_TESTS
  282. num_plists--;
  283. num_plists--;
  284. #endif
  285. /* Define mode gets turned on automatically on create. */
  286. nc->nc4_info->flags |= NC_INDEF;
  287. return NC_NOERR;
  288. exit:
  289. if (nc->nc4_info->hdfid > 0) H5Fclose(nc->nc4_info->hdfid);
  290. return retval;
  291. }
  292. /** \ingroup netcdf4
  293. Create a netCDF-4/HDF5 file.
  294. \param path The file name of the new file.
  295. \param cmode The creation mode flag.
  296. \param initialsz Ignored by this function.
  297. \param basepe Ignored by this function.
  298. \param chunksizehintp Ignored by this function.
  299. \param use_parallel 0 for sequential, non-zero for parallel I/O.
  300. \param mpidata pointer to struct holdind data for parallel I/O
  301. layer. Ignored if NULL.
  302. \param dispatch Pointer to the dispatch table for this file.
  303. \param ncpp Pointer to start of linked list of open files.
  304. \return NC_INVAL Invalid input (check cmode).
  305. */
  306. int
  307. NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
  308. size_t *chunksizehintp, int use_parallel, void *mpidata,
  309. NC_Dispatch *dispatch, NC **ncpp)
  310. {
  311. NC_FILE_INFO_T *nc_file = NULL;
  312. #ifdef USE_PARALLEL
  313. MPI_Comm comm = 0;
  314. MPI_Info info = 0;
  315. #else
  316. int comm = 0, info = 0;
  317. #endif /* USE_PARALLEL */
  318. int res;
  319. assert(ncpp && path);
  320. LOG((1, "nc4_create_file: path %s cmode 0x%x comm %d info %d",
  321. path, cmode, comm, info));
  322. #ifdef USE_PARALLEL
  323. if (mpidata)
  324. {
  325. comm = ((NC_MPI_INFO *)mpidata)->comm;
  326. info = ((NC_MPI_INFO *)mpidata)->info;
  327. }
  328. #endif /* USE_PARALLEL */
  329. /* If this is our first file, turn off HDF5 error messages. */
  330. if (virgin)
  331. {
  332. if (H5Eset_auto(NULL, NULL) < 0)
  333. LOG((0, "Couldn't turn off HDF5 error messages!"));
  334. LOG((1, "HDF5 error messages have been turned off."));
  335. virgin = 0;
  336. }
  337. /* Check the cmode for validity. */
  338. if (cmode & ~(NC_NOCLOBBER | NC_64BIT_OFFSET
  339. | NC_NETCDF4 | NC_CLASSIC_MODEL
  340. | NC_SHARE | NC_MPIIO | NC_MPIPOSIX | NC_LOCK | NC_PNETCDF
  341. | NC_DISKLESS
  342. | NC_WRITE /* to support diskless persistence */
  343. )
  344. || (cmode & NC_MPIIO && cmode & NC_MPIPOSIX)
  345. || (cmode & NC_64BIT_OFFSET && cmode & NC_NETCDF4)
  346. || (cmode & (NC_MPIIO | NC_MPIPOSIX) && cmode & NC_DISKLESS)
  347. )
  348. return NC_EINVAL;
  349. /* Allocate the storage for this file info struct, and fill it with
  350. zeros. This add the file metadata to the front of the global
  351. nc_file list. */
  352. if ((res = nc4_file_list_add(&nc_file, dispatch)))
  353. return res;
  354. /* Apply default create format. */
  355. if (default_create_format == NC_FORMAT_64BIT)
  356. cmode |= NC_64BIT_OFFSET;
  357. else if (default_create_format == NC_FORMAT_NETCDF4)
  358. cmode |= NC_NETCDF4;
  359. else if (default_create_format == NC_FORMAT_NETCDF4_CLASSIC)
  360. {
  361. cmode |= NC_NETCDF4;
  362. cmode |= NC_CLASSIC_MODEL;
  363. }
  364. LOG((2, "cmode after applying default format: 0x%x", cmode));
  365. /* Check to see if we want a netcdf3 or netcdf4 file. Open it, and
  366. call the appropriate nc*_create. */
  367. if (cmode & NC_NETCDF4)
  368. {
  369. nc_file->int_ncid = nc_file->ext_ncid;
  370. res = nc4_create_file(path, cmode, comm, info, nc_file);
  371. }
  372. #ifdef USE_PNETCDF
  373. else if (cmode & NC_PNETCDF)
  374. {
  375. nc_file->pnetcdf_file++;
  376. res = ncmpi_create(comm, path, cmode, info, &(nc_file->int_ncid));
  377. }
  378. #endif /* USE_PNETCDF */
  379. else
  380. {
  381. return NC_EINVAL;
  382. }
  383. /* Delete this file list entry if there was a failure. */
  384. if (res)
  385. {
  386. if (nc_file)
  387. nc4_file_list_del(nc_file);
  388. }
  389. else
  390. *ncpp = (NC *)nc_file;
  391. return res;
  392. }
  393. /* This function is called by read_dataset when a dimension scale
  394. * dataset is encountered. It reads in the dimension data (creating a
  395. * new NC_DIM_INFO_T object), and also checks to see if this is a
  396. * dimension without a variable - that is, a coordinate dimension
  397. * which does not have any coordinate data. */
  398. static int
  399. read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, char *obj_name,
  400. hsize_t scale_size, hsize_t max_scale_size,
  401. int *dim_without_var)
  402. {
  403. /*char *start_of_len;*/
  404. char dimscale_name_att[NC_MAX_NAME + 1] = "";
  405. hid_t attid = 0;
  406. int max_len;
  407. int retval;
  408. /* Add a dimension for this scale. */
  409. if ((retval = nc4_dim_list_add(&grp->dim)))
  410. return retval;
  411. /* Assign dimid and increment number of dimensions. */
  412. grp->dim->dimid = grp->file->nc4_info->next_dimid++;
  413. grp->ndims++;
  414. /* Does this dataset have a hidden attribute that tells us its
  415. * dimid? If so, read it. */
  416. H5E_BEGIN_TRY {
  417. if ((attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME,
  418. H5P_DEFAULT, H5P_DEFAULT)) > 0)
  419. {
  420. if (H5Aread(attid, H5T_NATIVE_INT, &grp->dim->dimid) < 0)
  421. return NC_EHDFERR;
  422. if (H5Aclose(attid) < 0)
  423. return NC_EHDFERR;
  424. }
  425. } H5E_END_TRY;
  426. max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
  427. if (!(grp->dim->name = malloc((max_len + 1) * sizeof(char))))
  428. return NC_ENOMEM;
  429. strncpy(grp->dim->name, obj_name, max_len + 1);
  430. if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT)
  431. {
  432. grp->dim->len = NC_MAX_UINT;
  433. grp->dim->too_long = 1;
  434. }
  435. else
  436. grp->dim->len = scale_size;
  437. grp->dim->hdf_dimscaleid = datasetid;
  438. /* If the dimscale has an unlimited dimension, then this dimension
  439. * is unlimited. */
  440. if (max_scale_size == H5S_UNLIMITED)
  441. grp->dim->unlimited++;
  442. /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a
  443. * dimension, but not a variable. (If get_scale_name returns an
  444. * error, just move on, there's no NAME.) */
  445. if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0)
  446. {
  447. if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE,
  448. strlen(DIM_WITHOUT_VARIABLE)))
  449. {
  450. if (grp->dim->unlimited)
  451. {
  452. size_t len = 0, *lenp = &len;
  453. if ((retval = nc4_find_dim_len(grp, grp->dim->dimid, &lenp)))
  454. return retval;
  455. grp->dim->len = *lenp;
  456. }
  457. (*dim_without_var)++;
  458. }
  459. }
  460. return NC_NOERR;
  461. }
  462. /* This function reads the hacked in coordinates attribute I use for
  463. * multi-dimensional coordinates. */
  464. static int
  465. read_coord_dimids(NC_VAR_INFO_T *var)
  466. {
  467. hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1;
  468. hssize_t coord_array_size;
  469. int ret = 0;
  470. /* There is a hidden attribute telling us the ids of the
  471. * dimensions that apply to this multi-dimensional coordinate
  472. * variable. Read it. */
  473. if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++;
  474. if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++;
  475. if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++;
  476. LOG((4, "dimscale %s is multidimensional and has coords", var->name));
  477. /* How many dimensions are there? */
  478. if ((spaceid = H5Aget_space(coord_attid)) < 0) ret++;
  479. #ifdef EXTRA_TESTS
  480. num_spaces++;
  481. #endif
  482. if ((coord_array_size = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++;
  483. /* Malloc space to the array of pointers to dims. */
  484. /* Set my HDF5 IDs free! */
  485. if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++;
  486. #ifdef EXTRA_TESTS
  487. num_spaces--;
  488. #endif
  489. if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++;
  490. if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++;
  491. return ret ? NC_EATTMETA : NC_NOERR;
  492. }
  493. /* This function is called when reading a file's metadata for each
  494. * dimension scale attached to a variable.*/
  495. static herr_t
  496. dimscale_visitor(hid_t did, unsigned dim, hid_t dsid,
  497. void *dimscale_hdf5_objids)
  498. {
  499. H5G_stat_t statbuf;
  500. /* Get more info on the dimscale object.*/
  501. if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0)
  502. return -1;
  503. /* Pass this information back to caller. */
  504. /* (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno = statbuf.fileno;
  505. (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno = statbuf.objno;*/
  506. (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0];
  507. (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1];
  508. (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0];
  509. (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1];
  510. return 0;
  511. }
  512. /* Given an HDF5 type, set a pointer to netcdf type. */
  513. static int
  514. get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid,
  515. nc_type *xtype)
  516. {
  517. NC_TYPE_INFO_T *type;
  518. hid_t class;
  519. htri_t is_str, equal = 0;
  520. assert(h5 && xtype);
  521. if ((class = H5Tget_class(native_typeid)) < 0)
  522. return NC_EHDFERR;
  523. /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
  524. * H5Tget_class will return H5T_STRING if this is a string. */
  525. if (class == H5T_STRING)
  526. {
  527. if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
  528. return NC_EHDFERR;
  529. if (is_str)
  530. *xtype = NC_STRING;
  531. else
  532. *xtype = NC_CHAR;
  533. return NC_NOERR;
  534. }
  535. else if (class == H5T_INTEGER || class == H5T_FLOAT)
  536. {
  537. /* For integers and floats, we don't have to worry about
  538. * endianness if we compare native types. */
  539. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0)
  540. return NC_EHDFERR;
  541. if (equal)
  542. {
  543. *xtype = NC_BYTE;
  544. return NC_NOERR;
  545. }
  546. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0)
  547. return NC_EHDFERR;
  548. if (equal)
  549. {
  550. *xtype = NC_SHORT;
  551. return NC_NOERR;
  552. }
  553. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0)
  554. return NC_EHDFERR;
  555. if (equal)
  556. {
  557. *xtype = NC_INT;
  558. return NC_NOERR;
  559. }
  560. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0)
  561. return NC_EHDFERR;
  562. if (equal)
  563. {
  564. *xtype = NC_FLOAT;
  565. return NC_NOERR;
  566. }
  567. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0)
  568. return NC_EHDFERR;
  569. if (equal)
  570. {
  571. *xtype = NC_DOUBLE;
  572. return NC_NOERR;
  573. }
  574. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0)
  575. return NC_EHDFERR;
  576. if (equal)
  577. {
  578. *xtype = NC_UBYTE;
  579. return NC_NOERR;
  580. }
  581. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0)
  582. return NC_EHDFERR;
  583. if (equal)
  584. {
  585. *xtype = NC_USHORT;
  586. return NC_NOERR;
  587. }
  588. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0)
  589. return NC_EHDFERR;
  590. if (equal)
  591. {
  592. *xtype = NC_UINT;
  593. return NC_NOERR;
  594. }
  595. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0)
  596. return NC_EHDFERR;
  597. if (equal)
  598. {
  599. *xtype = NC_INT64;
  600. return NC_NOERR;
  601. }
  602. if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0)
  603. return NC_EHDFERR;
  604. if (equal)
  605. {
  606. *xtype = NC_UINT64;
  607. return NC_NOERR;
  608. }
  609. }
  610. /* Maybe we already know about this type. */
  611. if (!equal)
  612. if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
  613. {
  614. *xtype = type->nc_typeid;
  615. return NC_NOERR;
  616. }
  617. *xtype = NC_NAT;
  618. return NC_EBADTYPID;
  619. }
  620. /* Given an HDF5 type, set a pointer to netcdf type_info struct,
  621. * either an existing one (for user-defined types) or a newly created
  622. * one. */
  623. static int
  624. get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid,
  625. nc_type *xtype, NC_TYPE_INFO_T **type_info)
  626. {
  627. NC_TYPE_INFO_T *type;
  628. htri_t is_str, equal = 0;
  629. hid_t class, native_typeid, hdf_typeid;
  630. #if 0
  631. nc_type my_nc_type = 0;
  632. #endif
  633. H5T_order_t order;
  634. int endianness;
  635. nc_type nc_type_constant[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT, NC_INT, NC_FLOAT,
  636. NC_DOUBLE, NC_UBYTE, NC_USHORT, NC_UINT,
  637. NC_INT64, NC_UINT64, NC_STRING};
  638. int type_size[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short),
  639. sizeof(int), sizeof(float), sizeof(double),
  640. sizeof(unsigned char), sizeof(unsigned short),
  641. sizeof(unsigned int), sizeof(long long),
  642. sizeof(unsigned long long), 0};
  643. int t;
  644. assert(h5 && xtype && type_info);
  645. /* Because these N5T_NATIVE_* constants are actually function calls
  646. * (!) in H5Tpublic.h, I can't initialize this array in the usual
  647. * way, because at least some C compilers (like Irix) complain
  648. * about calling functions when defining constants. So I have to do
  649. * it like this. Note that there's no native types for char or
  650. * string. Those are handled later. */
  651. if (!native_type_constant[1])
  652. {
  653. native_type_constant[1] = H5T_NATIVE_SCHAR;
  654. native_type_constant[2] = H5T_NATIVE_SHORT;
  655. native_type_constant[3] = H5T_NATIVE_INT;
  656. native_type_constant[4] = H5T_NATIVE_FLOAT;
  657. native_type_constant[5] = H5T_NATIVE_DOUBLE;
  658. native_type_constant[6] = H5T_NATIVE_UCHAR;
  659. native_type_constant[7] = H5T_NATIVE_USHORT;
  660. native_type_constant[8] = H5T_NATIVE_UINT;
  661. native_type_constant[9] = H5T_NATIVE_LLONG;
  662. native_type_constant[10] = H5T_NATIVE_ULLONG;
  663. }
  664. /* Get the HDF5 typeid - we'll need it later. */
  665. if ((hdf_typeid = H5Dget_type(datasetid)) < 0)
  666. return NC_EHDFERR;
  667. /* Get the native typeid. Will be equivalent to hdf_typeid when
  668. * creating but not necessarily when reading, a variable. */
  669. if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
  670. return NC_EHDFERR;
  671. /* Is this type an integer, string, compound, or what? */
  672. if ((class = H5Tget_class(native_typeid)) < 0)
  673. return NC_EHDFERR;
  674. /* Is this an atomic type? */
  675. if (class == H5T_STRING || class == H5T_INTEGER || class == H5T_FLOAT)
  676. {
  677. /* Allocate a phony NC_TYPE_INFO_T struct to hold type info. */
  678. if (!(*type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
  679. return NC_ENOMEM;
  680. (*type_info)->class = class;
  681. /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
  682. * H5Tget_class will return H5T_STRING if this is a string. */
  683. if (class == H5T_STRING)
  684. {
  685. if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
  686. return NC_EHDFERR;
  687. /* Make sure fixed-len strings will work like variable-len strings */
  688. if (is_str || H5Tget_size(hdf_typeid) > 1)
  689. t = NUM_TYPES - 1;
  690. else
  691. t = 0;
  692. }
  693. else if (class == H5T_INTEGER || class == H5T_FLOAT)
  694. {
  695. for (t = 1; t < NUM_TYPES - 1; t++)
  696. {
  697. if ((equal = H5Tequal(native_typeid, native_type_constant[t])) < 0)
  698. return NC_EHDFERR;
  699. if (equal)
  700. {
  701. #if 0
  702. my_nc_type = nc_type_constant[t];
  703. #endif
  704. break;
  705. }
  706. }
  707. /* Find out about endianness. */
  708. if (class == H5T_INTEGER)
  709. {
  710. if ((order = H5Tget_order(hdf_typeid)) < 0)
  711. return NC_EHDFERR;
  712. if (order == H5T_ORDER_LE)
  713. endianness = NC_ENDIAN_LITTLE;
  714. else if (order == H5T_ORDER_BE)
  715. endianness = NC_ENDIAN_BIG;
  716. else /* don't support H5T_ORDER_VAX, H5T_ORDER_MIXED, H5T_ORDER_NONE */
  717. return NC_EBADTYPE;
  718. /* Copy this into the type_info struct. */
  719. (*type_info)->endianness = endianness;
  720. }
  721. }
  722. *xtype = nc_type_constant[t];
  723. (*type_info)->nc_typeid = nc_type_constant[t];
  724. (*type_info)->size = type_size[t];
  725. if (!((*type_info)->name = malloc((strlen(nc_type_name[t]) + 1) * sizeof(char))))
  726. return NC_ENOMEM;
  727. strcpy((*type_info)->name, nc_type_name[t]);
  728. (*type_info)->class = class;
  729. (*type_info)->hdf_typeid = hdf_typeid;
  730. (*type_info)->native_typeid = native_typeid;
  731. (*type_info)->close_hdf_typeid = 1;
  732. return NC_NOERR;
  733. }
  734. else
  735. {
  736. /* This is a user-defined type. */
  737. if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
  738. {
  739. *xtype = type->nc_typeid;
  740. *type_info = type;
  741. }
  742. /* The type entry in the array of user-defined types already has
  743. * an open data typeid (and native typeid), so close the ones we
  744. * opened above. */
  745. if (H5Tclose(native_typeid) < 0)
  746. return NC_EHDFERR;
  747. if (H5Tclose(hdf_typeid) < 0)
  748. return NC_EHDFERR;
  749. if (type)
  750. return NC_NOERR;
  751. }
  752. *xtype = NC_NAT;
  753. return NC_EBADTYPID;
  754. }
  755. /* Read an attribute. */
  756. static int
  757. read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att)
  758. {
  759. hid_t spaceid = 0, file_typeid = 0;
  760. hsize_t dims[1]; /* netcdf attributes always 1-D. */
  761. int retval = NC_NOERR;
  762. size_t type_size;
  763. int att_ndims;
  764. hssize_t att_npoints;
  765. H5T_class_t att_class;
  766. int fixed_len_string = 0;
  767. size_t fixed_size = 0;
  768. assert(att->name);
  769. LOG((5, "read_hdf5_att: att->attnum %d att->name %s "
  770. "att->xtype %d att->len %d", att->attnum, att->name,
  771. att->xtype, att->len));
  772. /* Get type of attribute in file. */
  773. if ((file_typeid = H5Aget_type(attid)) < 0)
  774. return NC_EATTMETA;
  775. if ((att->native_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0)
  776. BAIL(NC_EHDFERR);
  777. if ((att_class = H5Tget_class(att->native_typeid)) < 0)
  778. BAIL(NC_EATTMETA);
  779. if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_typeid))
  780. {
  781. fixed_len_string++;
  782. if (!(fixed_size = H5Tget_size(att->native_typeid)))
  783. BAIL(NC_EATTMETA);
  784. }
  785. if ((retval = get_netcdf_type(grp->file->nc4_info, att->native_typeid, &(att->xtype))))
  786. BAIL(retval);
  787. /* Get len. */
  788. if ((spaceid = H5Aget_space(attid)) < 0)
  789. BAIL(NC_EATTMETA);
  790. #ifdef EXTRA_TESTS
  791. num_spaces++;
  792. #endif
  793. if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
  794. BAIL(NC_EATTMETA);
  795. if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0)
  796. BAIL(NC_EATTMETA);
  797. /* If both att_ndims and att_npoints are zero, then this is a
  798. * zero length att. */
  799. if (att_ndims == 0 && att_npoints == 0)
  800. {
  801. dims[0] = 0;
  802. }
  803. else if (att->xtype == NC_STRING) {
  804. dims[0] = att_npoints;
  805. }
  806. else if (att->xtype == NC_CHAR)
  807. {
  808. /* NC_CHAR attributes are written as a scalar in HDF5, of type
  809. * H5T_C_S1, of variable length. */
  810. if (att_ndims == 0)
  811. {
  812. if (!(dims[0] = H5Tget_size(file_typeid)))
  813. BAIL(NC_EATTMETA);
  814. }
  815. else
  816. {
  817. /* This is really a string type! */
  818. att->xtype = NC_STRING;
  819. dims[0] = att_npoints;
  820. }
  821. }
  822. else
  823. {
  824. /* All netcdf attributes are scalar or 1-D only. */
  825. if (att_ndims > 1)
  826. BAIL(NC_EATTMETA);
  827. /* Read the size of this attribute. */
  828. if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0)
  829. BAIL(NC_EATTMETA);
  830. }
  831. /* Tell the user what the length if this attribute is. */
  832. att->len = dims[0];
  833. /* Allocate some memory if the len is not zero, and read the
  834. attribute. */
  835. if (dims[0])
  836. {
  837. if ((retval = nc4_get_typelen_mem(grp->file->nc4_info, att->xtype, 0,
  838. &type_size)))
  839. return retval;
  840. if (att_class == H5T_VLEN)
  841. {
  842. if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t)))))
  843. BAIL(NC_ENOMEM);
  844. if (H5Aread(attid, att->native_typeid, att->vldata) < 0)
  845. BAIL(NC_EATTMETA);
  846. }
  847. else if (att->xtype == NC_STRING)
  848. {
  849. if (!(att->stdata = calloc(att->len, sizeof(char *))))
  850. BAIL(NC_ENOMEM);
  851. /* For a fixed length HDF5 string, the read requires
  852. * contiguous memory. Meanwhile, the netCDF API requires that
  853. * nc_free_string be called on string arrays, which would not
  854. * work if one contiguous memory block were used. So here I
  855. * convert the contiguous block of strings into an array of
  856. * malloced strings (each string with its own malloc). Then I
  857. * copy the data and free the contiguous memory. This
  858. * involves copying the data, which is bad, but this only
  859. * occurs for fixed length string attributes, and presumably
  860. * these are small. (And netCDF-4 does not create them - it
  861. * always uses variable length strings. */
  862. if (fixed_len_string)
  863. {
  864. int i;
  865. char *contig_buf, *cur;
  866. /* Alloc space for the contiguous memory read. */
  867. if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char))))
  868. BAIL(NC_ENOMEM);
  869. /* Read the fixed-len strings as one big block. */
  870. if (H5Aread(attid, att->native_typeid, contig_buf) < 0)
  871. BAIL(NC_EATTMETA);
  872. /* Copy strings, one at a time, into their new home. Alloc
  873. space for each string. The user will later free this
  874. space with nc_free_string. */
  875. cur = contig_buf;
  876. for (i = 0; i < att->len; i++)
  877. {
  878. if (!(att->stdata[i] = malloc(fixed_size)))
  879. BAIL(NC_ENOMEM);
  880. strncpy(att->stdata[i], cur, fixed_size);
  881. cur += fixed_size;
  882. }
  883. /* Free contiguous memory buffer. */
  884. free(contig_buf);
  885. }
  886. else
  887. {
  888. /* Read variable-length string atts. */
  889. if (H5Aread(attid, att->native_typeid, att->stdata) < 0)
  890. BAIL(NC_EATTMETA);
  891. }
  892. }
  893. else
  894. {
  895. if (!(att->data = malloc((unsigned int)(att->len * type_size))))
  896. BAIL(NC_ENOMEM);
  897. if (H5Aread(attid, att->native_typeid, att->data) < 0)
  898. BAIL(NC_EATTMETA);
  899. }
  900. }
  901. if (H5Tclose(file_typeid) < 0)
  902. BAIL(NC_EHDFERR);
  903. if (H5Sclose(spaceid) < 0)
  904. return NC_EHDFERR;
  905. #ifdef EXTRA_TESTS
  906. num_spaces--;
  907. #endif
  908. return NC_NOERR;
  909. exit:
  910. if (H5Tclose(file_typeid) < 0)
  911. BAIL2(NC_EHDFERR);
  912. if (spaceid > 0 && H5Sclose(spaceid) < 0)
  913. BAIL2(NC_EHDFERR);
  914. #ifdef EXTRA_TESTS
  915. num_spaces--;
  916. #endif
  917. return retval;
  918. }
  919. /* Read information about a user defined type from the HDF5 file, and
  920. * stash it in the group's list of types. Return the netcdf typeid
  921. * through a pointer, if caller desires it. */
  922. static int
  923. read_type(NC_GRP_INFO_T *grp, char *type_name)
  924. {
  925. NC_TYPE_INFO_T *type;
  926. H5T_class_t class;
  927. hid_t hdf_typeid, native_typeid = 0;
  928. int nmembers;
  929. hid_t member_hdf_typeid, base_hdf_typeid = 0;
  930. char *member_name = NULL;
  931. size_t type_size = 0, member_offset;
  932. unsigned int m;
  933. nc_type ud_type_type = NC_NAT, base_nc_type = NC_NAT, member_xtype;
  934. htri_t ret;
  935. int retval = NC_NOERR;
  936. void *value;
  937. int i;
  938. assert(grp && type_name);
  939. if (strlen(type_name) > NC_MAX_NAME)
  940. return NC_EBADNAME;
  941. LOG((4, "read_type: type_name %s grp->name %s", type_name, grp->name));
  942. if ((hdf_typeid = H5Topen2(grp->hdf_grpid, type_name, H5P_DEFAULT)) < 0)
  943. return NC_EHDFERR;
  944. /* What is the native type for this platform? */
  945. if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
  946. return NC_EHDFERR;
  947. /* What is the size of this type on this platform. */
  948. if (!(type_size = H5Tget_size(native_typeid)))
  949. return NC_EHDFERR;
  950. LOG((5, "type_size %d", type_size));
  951. /* What is the class of this type, compound, vlen, etc. */
  952. if ((class = H5Tget_class(hdf_typeid)) < 0)
  953. return NC_EHDFERR;
  954. switch (class)
  955. {
  956. case H5T_STRING:
  957. ud_type_type = NC_STRING;
  958. break;
  959. case H5T_COMPOUND:
  960. ud_type_type = NC_COMPOUND;
  961. break;
  962. case H5T_VLEN:
  963. /* For conveninence we allow user to pass vlens of strings
  964. * with null terminated strings. This means strings are
  965. * treated slightly differently by the API, although they are
  966. * really just VLENs of characters. */
  967. if ((ret = H5Tis_variable_str(hdf_typeid)) < 0)
  968. return NC_EHDFERR;
  969. if (ret)
  970. ud_type_type = NC_STRING;
  971. else
  972. {
  973. ud_type_type = NC_VLEN;
  974. /* Find the base type of this vlen (i.e. what is this a
  975. * vlen of?) */
  976. if (!(base_hdf_typeid = H5Tget_super(native_typeid)))
  977. return NC_EHDFERR;
  978. /* What size is this type? */
  979. if (!(type_size = H5Tget_size(base_hdf_typeid)))
  980. return NC_EHDFERR;
  981. /* What is the netcdf corresponding type. */
  982. if ((retval = get_netcdf_type(grp->file->nc4_info, base_hdf_typeid,
  983. &base_nc_type)))
  984. return retval;
  985. LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
  986. base_hdf_typeid, type_size, base_nc_type));
  987. }
  988. break;
  989. case H5T_OPAQUE:
  990. ud_type_type = NC_OPAQUE;
  991. /* What size is this type? */
  992. if (!(type_size = H5Tget_size(hdf_typeid)))
  993. return NC_EHDFERR;
  994. LOG((5, "type_size %d", type_size));
  995. break;
  996. case H5T_ENUM:
  997. ud_type_type = NC_ENUM;
  998. /* Find the base type of this enum (i.e. what is this a
  999. * enum of?) */
  1000. if (!(base_hdf_typeid = H5Tget_super(hdf_typeid)))
  1001. return NC_EHDFERR;
  1002. /* What size is this type? */
  1003. if (!(type_size = H5Tget_size(base_hdf_typeid)))
  1004. return NC_EHDFERR;
  1005. /* What is the netcdf corresponding type. */
  1006. if ((retval = get_netcdf_type(grp->file->nc4_info, base_hdf_typeid,
  1007. &base_nc_type)))
  1008. return retval;
  1009. LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
  1010. base_hdf_typeid, type_size, base_nc_type));
  1011. break;
  1012. default:
  1013. LOG((0, "unknown class"));
  1014. return NC_EBADCLASS;
  1015. }
  1016. /* Add to the list for this new type, and get a local pointer to it. */
  1017. if ((retval = nc4_type_list_add(&grp->type, &type)))
  1018. return retval;
  1019. assert(type);
  1020. /* Remember info about this type. */
  1021. type->nc_typeid = grp->file->nc4_info->next_typeid++;
  1022. type->size = type_size;
  1023. if (!(type->name = malloc((strlen(type_name) + 1) * sizeof(char))))
  1024. return NC_ENOMEM;
  1025. strcpy(type->name, type_name);
  1026. type->class = ud_type_type;
  1027. type->base_nc_type = base_nc_type;
  1028. type->committed++;
  1029. type->hdf_typeid = hdf_typeid;
  1030. type->native_typeid = native_typeid;
  1031. /* Read info about each member of this compound type. */
  1032. if (ud_type_type == NC_COMPOUND)
  1033. {
  1034. if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0)
  1035. return NC_EHDFERR;
  1036. LOG((5, "compound type has %d members", nmembers));
  1037. for (m = 0; m < nmembers; m++)
  1038. {
  1039. H5T_class_t mem_class;
  1040. hid_t member_native_typeid;
  1041. int ndims = 0, dim_size[NC_MAX_VAR_DIMS];
  1042. hsize_t dims[NC_MAX_VAR_DIMS];
  1043. int d;
  1044. /* Get the typeid and native typeid of this member of the
  1045. * compound type. */
  1046. if ((member_hdf_typeid = H5Tget_member_type(type->native_typeid, m)) < 0)
  1047. return NC_EHDFERR;
  1048. if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0)
  1049. return NC_EHDFERR;
  1050. /* Get the name of the member.*/
  1051. member_name = H5Tget_member_name(type->native_typeid, m);
  1052. if (!member_name || strlen(member_name) > NC_MAX_NAME)
  1053. return NC_EBADNAME;
  1054. /* Offset in bytes on *this* platform. */
  1055. member_offset = H5Tget_member_offset(type->native_typeid, m);
  1056. /* Get dimensional data if this member is an array of something. */
  1057. if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0)
  1058. return NC_EHDFERR;
  1059. if (mem_class == H5T_ARRAY)
  1060. {
  1061. if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0)
  1062. return NC_EHDFERR;
  1063. if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims)
  1064. return NC_EHDFERR;
  1065. for (d = 0; d < ndims; d++)
  1066. dim_size[d] = dims[d];
  1067. /* What is the netCDF typeid of this member? */
  1068. if ((retval = get_netcdf_type(grp->file->nc4_info, H5Tget_super(member_hdf_typeid),
  1069. &member_xtype)))
  1070. return retval;
  1071. }
  1072. else
  1073. {
  1074. /* What is the netCDF typeid of this member? */
  1075. if ((retval = get_netcdf_type(grp->file->nc4_info, member_native_typeid,
  1076. &member_xtype)))
  1077. return retval;
  1078. }
  1079. /* Add this member to our list of fields in this compound type. */
  1080. if (ndims)
  1081. {
  1082. if ((retval = nc4_field_list_add(&type->field, type->num_fields++, member_name,
  1083. member_offset, H5Tget_super(member_hdf_typeid),
  1084. H5Tget_super(member_native_typeid),
  1085. member_xtype, ndims, dim_size)))
  1086. return retval;
  1087. }
  1088. else
  1089. {
  1090. if ((retval = nc4_field_list_add(&type->field, type->num_fields++, member_name,
  1091. member_offset, member_hdf_typeid, member_native_typeid,
  1092. member_xtype, 0, NULL)))
  1093. return retval;
  1094. }
  1095. /* HDF5 allocated this for us. */
  1096. free(member_name);
  1097. }
  1098. }
  1099. else if (ud_type_type == NC_VLEN)
  1100. {
  1101. type->base_hdf_typeid = base_hdf_typeid;
  1102. }
  1103. else if (ud_type_type == NC_ENUM)
  1104. {
  1105. /* Remember the base HDF5 type for this enum. */
  1106. type->base_hdf_typeid = base_hdf_typeid;
  1107. /* Find out how many member are in the enum. */
  1108. if ((type->num_enum_members = H5Tget_nmembers(hdf_typeid)) < 0)
  1109. return NC_EHDFERR;
  1110. /* Allocate space for one value. */
  1111. if (!(value = calloc(1, type_size)))
  1112. return NC_ENOMEM;
  1113. /* Read each name and value defined in the enum. */
  1114. for (i = 0; i < type->num_enum_members; i++)
  1115. {
  1116. /* Get the name and value from HDF5. */
  1117. if (!(member_name = H5Tget_member_name(hdf_typeid, i)))
  1118. return NC_EHDFERR;
  1119. if (!member_name || strlen(member_name) > NC_MAX_NAME)
  1120. return NC_EBADNAME;
  1121. if (H5Tget_member_value(hdf_typeid, i, value) < 0)
  1122. return NC_EHDFERR;
  1123. /* Insert new field into this type's list of fields. */
  1124. if ((retval = nc4_enum_member_add(&type->enum_member, type->size,
  1125. member_name, value)))
  1126. return retval;
  1127. free(member_name);
  1128. }
  1129. /* Free the tempory memory for one value, and the member name
  1130. * (which HDF5 allocated for us). */
  1131. free(value);
  1132. }
  1133. return retval;
  1134. }
  1135. /* This function is called by read_dataset, (which is called by
  1136. * nc4_rec_read_metadata) when a netCDF variable is found in the
  1137. * file. This function reads in all the metadata about the var,
  1138. * including the attributes. */
  1139. static int
  1140. read_var(NC_GRP_INFO_T *grp, hid_t datasetid, char *obj_name,
  1141. size_t ndims, int is_scale, int num_scales, hid_t access_pid)
  1142. {
  1143. NC_VAR_INFO_T *var;
  1144. int natts, a, d;
  1145. NC_ATT_INFO_T *att;
  1146. hid_t attid = 0;
  1147. char att_name[NC_MAX_HDF5_NAME + 1];
  1148. #define CD_NELEMS_ZLIB 1
  1149. #define CD_NELEMS_SZIP 4
  1150. H5Z_filter_t filter;
  1151. int num_filters;
  1152. unsigned int cd_values[CD_NELEMS_SZIP];
  1153. size_t cd_nelems = CD_NELEMS_SZIP;
  1154. hid_t propid = 0;
  1155. H5D_fill_value_t fill_status;
  1156. H5D_layout_t layout;
  1157. hsize_t chunksize[NC_MAX_VAR_DIMS];
  1158. int retval = NC_NOERR;
  1159. double rdcc_w0;
  1160. int f;
  1161. assert(obj_name && grp);
  1162. LOG((4, "read_var: obj_name %s", obj_name));
  1163. /* Add a variable to the end of the group's var list. */
  1164. if ((retval = nc4_var_list_add(&grp->var, &var)))
  1165. return retval;
  1166. /* Fill in what we already know. */
  1167. var->hdf_datasetid = datasetid;
  1168. var->varid = grp->nvars++;
  1169. var->created++;
  1170. var->ndims = ndims;
  1171. /* We need some room to store information about dimensions for this
  1172. * var. */
  1173. if (var->ndims)
  1174. {
  1175. if (!(var->dim = calloc(var->ndims, sizeof(NC_DIM_INFO_T *))))
  1176. return NC_ENOMEM;
  1177. if (!(var->dimids = calloc(var->ndims, sizeof(int))))
  1178. return NC_ENOMEM;
  1179. }
  1180. /* Learn about current chunk cache settings. */
  1181. if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems),
  1182. &(var->chunk_cache_size), &rdcc_w0)) < 0)
  1183. return NC_EHDFERR;
  1184. var->chunk_cache_preemption = rdcc_w0;
  1185. /* Allocate space for the name. */
  1186. if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char))))
  1187. return NC_ENOMEM;
  1188. /* Check for a weird case: a non-coordinate (and non-scalar)
  1189. * variable that has the same name as a dimension. It's legal in
  1190. * netcdf, and requires that the HDF5 dataset name be changed. */
  1191. if (var->ndims &&
  1192. !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)))
  1193. {
  1194. if (strlen(obj_name) > NC_MAX_NAME)
  1195. return NC_EMAXNAME;
  1196. strcpy(var->name, &obj_name[strlen(NON_COORD_PREPEND)]);
  1197. }
  1198. else
  1199. strcpy(var->name, obj_name);
  1200. /* Find out what filters are applied to this HDF5 dataset,
  1201. * fletcher32, deflate, and/or shuffle. All other filters are
  1202. * ignored. */
  1203. if ((propid = H5Dget_create_plist(datasetid)) < 0)
  1204. BAIL(NC_EHDFERR);
  1205. #ifdef EXTRA_TESTS
  1206. num_plists++;
  1207. #endif /* EXTRA_TESTS */
  1208. /* Get the chunking info for non-scalar vars. */
  1209. if ((layout = H5Pget_layout(propid)) < -1)
  1210. BAIL(NC_EHDFERR);
  1211. if (layout == H5D_CHUNKED)
  1212. {
  1213. if (H5Pget_chunk(propid, NC_MAX_VAR_DIMS, chunksize) < 0)
  1214. BAIL(NC_EHDFERR);
  1215. if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t))))
  1216. BAIL(NC_ENOMEM);
  1217. for (d = 0; d < var->ndims; d++)
  1218. var->chunksizes[d] = chunksize[d];
  1219. }
  1220. else if (layout == H5D_CONTIGUOUS)
  1221. var->contiguous++;
  1222. /* The possible values of filter (which is just an int) can be
  1223. * found in H5Zpublic.h. */
  1224. if ((num_filters = H5Pget_nfilters(propid)) < 0)
  1225. BAIL(NC_EHDFERR);
  1226. for (f = 0; f < num_filters; f++)
  1227. {
  1228. if ((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
  1229. cd_values, 0, NULL, NULL)) < 0)
  1230. BAIL(NC_EHDFERR);
  1231. switch (filter)
  1232. {
  1233. case H5Z_FILTER_SHUFFLE:
  1234. var->shuffle = 1;
  1235. break;
  1236. case H5Z_FILTER_FLETCHER32:
  1237. var->fletcher32 = 1;
  1238. break;
  1239. case H5Z_FILTER_DEFLATE:
  1240. var->deflate++;
  1241. if (cd_nelems != CD_NELEMS_ZLIB ||
  1242. cd_values[0] > MAX_DEFLATE_LEVEL)
  1243. BAIL(NC_EHDFERR);
  1244. var->deflate_level = cd_values[0];
  1245. break;
  1246. case H5Z_FILTER_SZIP:
  1247. var->deflate++;
  1248. if (cd_nelems != CD_NELEMS_SZIP)
  1249. BAIL(NC_EHDFERR);
  1250. var->options_mask = cd_values[0];
  1251. var->pixels_per_block = cd_values[1];
  1252. break;
  1253. default:
  1254. LOG((1, "Yikes! Unknown filter type found on dataset!"));
  1255. break;
  1256. }
  1257. }
  1258. /* Learn all about the type of this variable. */
  1259. if ((retval = get_type_info2(grp->file->nc4_info, datasetid,
  1260. &var->xtype, &var->type_info)))
  1261. BAIL(retval);
  1262. /* Is there a fill value associated with this dataset? */
  1263. if (H5Pfill_value_defined(propid, &fill_status) < 0)
  1264. BAIL(NC_EHDFERR);
  1265. /* Get the fill value, if there is one defined. */
  1266. if (fill_status == H5D_FILL_VALUE_USER_DEFINED)
  1267. {
  1268. /* Allocate space to hold the fill value. */
  1269. if (!var->fill_value)
  1270. {
  1271. if (var->type_info->class == NC_VLEN)
  1272. {
  1273. if (!(var->fill_value = malloc(sizeof(nc_vlen_t))))
  1274. BAIL(NC_ENOMEM);
  1275. }
  1276. else if (var->type_info->size)
  1277. {
  1278. if (!(var->fill_value = malloc(var->type_info->size)))
  1279. BAIL(NC_ENOMEM);
  1280. }
  1281. else
  1282. {
  1283. if (!(var->fill_value = malloc(sizeof(char *))))
  1284. BAIL(NC_ENOMEM);
  1285. }
  1286. }
  1287. /* Get the fill value from the HDF5 property lust. */
  1288. if (H5Pget_fill_value(propid, var->type_info->native_typeid,
  1289. var->fill_value) < 0)
  1290. BAIL(NC_EHDFERR);
  1291. }
  1292. else
  1293. var->no_fill = 1;
  1294. /* If it's a scale, mark it as such. If not, allocate space to
  1295. * remember whether the dimscale has been attached for each
  1296. * dimension. */
  1297. if (is_scale)
  1298. {
  1299. assert(ndims);
  1300. var->dimscale++;
  1301. if (var->ndims > 1)
  1302. {
  1303. if ((retval = read_coord_dimids(var)))
  1304. BAIL(retval);
  1305. }
  1306. else
  1307. {
  1308. var->dimids[0] = grp->dim->dimid;
  1309. var->dim[0] = grp->dim;
  1310. }
  1311. }
  1312. else
  1313. if (num_scales && ndims &&
  1314. !(var->dimscale_attached = calloc(ndims, sizeof(int))))
  1315. BAIL(NC_ENOMEM);
  1316. /* If this is not a scale, and has scales, iterate
  1317. * through them. (i.e. this is a variable that is not a
  1318. * coordinate variable) */
  1319. if (!is_scale && num_scales)
  1320. {
  1321. /* Store id information allowing us to match hdf5
  1322. * dimscales to netcdf dimensions. */
  1323. if (!(var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid))))
  1324. BAIL(NC_ENOMEM);
  1325. for (d = 0; d < var->ndims; d++)
  1326. {
  1327. LOG((5, "read_var: about to iterate over scales for dim %d", d));
  1328. if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor,
  1329. &(var->dimscale_hdf5_objids[d])) < 0)
  1330. BAIL(NC_EHDFERR);
  1331. /* LOG((5, "read_var: collected scale info for dim %d "
  1332. "var %s fileno[0] %d objno[0] %d fileno[1] %d objno[1] %d",
  1333. d, var->name, var->dimscale_hdf5_objids[d].fileno[0],
  1334. var->dimscale_hdf5_objids[d].objno[0],
  1335. var->dimscale_hdf5_objids[d].fileno[1],
  1336. var->dimscale_hdf5_objids[d].objno[1]));*/
  1337. var->dimscale_attached[d]++;
  1338. }
  1339. }
  1340. /* Now read all the attributes of this variable, ignoring the
  1341. ones that hold HDF5 dimension scale information. */
  1342. if ((natts = H5Aget_num_attrs(var->hdf_datasetid)) < 0)
  1343. BAIL(NC_EATTMETA);
  1344. for (a = 0; a < natts; a++)
  1345. {
  1346. /* Close the attribute and try to move on with our
  1347. * lives. Like bits through the network port, so
  1348. * flows the Days of Our Lives! */
  1349. if (attid && H5Aclose(attid) < 0)
  1350. BAIL(NC_EHDFERR);
  1351. /* Open the att and get its name. */
  1352. if ((attid = H5Aopen_idx(var->hdf_datasetid, (unsigned int)a)) < 0)
  1353. BAIL(NC_EATTMETA);
  1354. if (H5Aget_name(attid, NC_MAX_HDF5_NAME, att_name) < 0)
  1355. BAIL(NC_EATTMETA);
  1356. LOG((4, "read_var: a %d att_name %s", a, att_name));
  1357. /* Should we ignore this attribute? */
  1358. if (strcmp(att_name, REFERENCE_LIST) &&
  1359. strcmp(att_name, CLASS) &&
  1360. strcmp(att_name, DIMENSION_LIST) &&
  1361. strcmp(att_name, NAME) &&
  1362. strcmp(att_name, COORDINATES))
  1363. {
  1364. /* Is this the hidden attribute that holds the netCDF
  1365. * dimension id for a coordinate variable? */
  1366. if (!strcmp(att_name, NC_DIMID_ATT_NAME))
  1367. {
  1368. }
  1369. else
  1370. {
  1371. /* Add to the end of the list of atts for this var. */
  1372. if ((retval = nc4_att_list_add(&var->att)))
  1373. BAIL(retval);
  1374. for (att = var->att; att->next; att = att->next)
  1375. ;
  1376. /* Fill in the information we know. */
  1377. att->attnum = var->natts++;
  1378. if (!(att->name = malloc((strlen(att_name) + 1) * sizeof(char))))
  1379. BAIL(NC_ENOMEM);
  1380. strcpy(att->name, att_name);
  1381. /* Read the rest of the info about the att,
  1382. * including its values. */
  1383. if ((retval = read_hdf5_att(grp, attid, att)))
  1384. BAIL(retval);
  1385. att->created++;
  1386. } /* endif not HDF5 att */
  1387. }
  1388. } /* next attribute */
  1389. /* Is this a deflated variable with a chunksize greater than the
  1390. * current cache size? */
  1391. if ((retval = nc4_adjust_var_cache(grp, var)))
  1392. BAIL(retval);
  1393. exit:
  1394. if (propid > 0 && H5Pclose(propid) < 0)
  1395. BAIL2(NC_EHDFERR);
  1396. #ifdef EXTRA_TESTS
  1397. num_plists--;
  1398. #endif
  1399. if (attid > 0 && H5Aclose(attid) < 0)
  1400. BAIL2(NC_EHDFERR);
  1401. return retval;
  1402. }
  1403. /* This function is called by nc4_rec_read_metadata to read all the
  1404. * group level attributes (the NC_GLOBAL atts for this group). */
  1405. static int
  1406. read_grp_atts(NC_GRP_INFO_T *grp)
  1407. {
  1408. hid_t attid = 0;
  1409. hsize_t num_obj, i;
  1410. NC_ATT_INFO_T *att;
  1411. NC_TYPE_INFO_T *type;
  1412. char obj_name[NC_MAX_HDF5_NAME + 1];
  1413. int max_len;
  1414. int retval = NC_NOERR;
  1415. num_obj = H5Aget_num_attrs(grp->hdf_grpid);
  1416. for (i = 0; i < num_obj; i++)
  1417. {
  1418. if (attid > 0)
  1419. H5Aclose(attid);
  1420. if ((attid = H5Aopen_idx(grp->hdf_grpid, (unsigned int)i)) < 0)
  1421. BAIL(NC_EATTMETA);
  1422. if (H5Aget_name(attid, NC_MAX_NAME + 1, obj_name) < 0)
  1423. BAIL(NC_EATTMETA);
  1424. LOG((3, "reading attribute of _netCDF group, named %s", obj_name));
  1425. /* This may be an attribute telling us that strict netcdf-3
  1426. * rules are in effect. If so, we will make note of the fact,
  1427. * but not add this attribute to the metadata. It's not a user
  1428. * attribute, but an internal netcdf-4 one. */
  1429. if (!strcmp(obj_name, NC3_STRICT_ATT_NAME))
  1430. grp->file->nc4_info->cmode |= NC_CLASSIC_MODEL;
  1431. else
  1432. {
  1433. /* Add an att struct at the end of the list, and then go to it. */
  1434. if ((retval = nc4_att_list_add(&grp->att)))
  1435. BAIL(retval);
  1436. for (att = grp->att; att->next; att = att->next)
  1437. ;
  1438. /* Add the info about this attribute. */
  1439. max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
  1440. if (!(att->name = malloc((max_len + 1) * sizeof(char))))
  1441. BAIL(NC_ENOMEM);
  1442. strncpy(att->name, obj_name, max_len);
  1443. att->name[max_len] = 0;
  1444. att->attnum = grp->natts++;
  1445. if ((retval = read_hdf5_att(grp, attid, att)))
  1446. BAIL(retval);
  1447. att->created++;
  1448. if ((retval = nc4_find_type(grp->file->nc4_info, att->xtype, &type)))
  1449. BAIL(retval);
  1450. if (type)
  1451. att->class = type->class;
  1452. }
  1453. }
  1454. exit:
  1455. if (attid > 0 && H5Aclose(attid) < 0)
  1456. BAIL2(NC_EHDFERR);
  1457. return retval;
  1458. }
  1459. /* This function is called when nc4_rec_read_vars encounters an HDF5
  1460. * dataset when reading a file. */
  1461. static int
  1462. read_dataset(NC_GRP_INFO_T *grp, char *obj_name)
  1463. {
  1464. hid_t datasetid = 0;
  1465. hid_t spaceid = 0, access_pid = 0;
  1466. int ndims;
  1467. hsize_t dims[NC_MAX_DIMS], max_dims[NC_MAX_DIMS];
  1468. int is_scale = 0;
  1469. int dim_without_var = 0;
  1470. int num_scales = 0;
  1471. int retval = NC_NOERR;
  1472. /* Open this dataset. */
  1473. if ((datasetid = H5Dopen2(grp->hdf_grpid, obj_name, H5P_DEFAULT)) < 0)
  1474. BAIL(NC_EVARMETA);
  1475. /* Get the current chunk cache settings. */
  1476. if ((access_pid = H5Dget_access_plist(datasetid)) < 0)
  1477. BAIL(NC_EVARMETA);
  1478. #ifdef EXTRA_TESTS
  1479. num_plists++;
  1480. #endif
  1481. /* Get the dimension information for this dataset. */
  1482. if ((spaceid = H5Dget_space(datasetid)) < 0)
  1483. BAIL(NC_EHDFERR);
  1484. #ifdef EXTRA_TESTS
  1485. num_spaces++;
  1486. #endif
  1487. if ((ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
  1488. BAIL(NC_EHDFERR);
  1489. if (ndims > NC_MAX_DIMS)
  1490. BAIL(NC_EMAXDIMS);
  1491. if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0)
  1492. BAIL(NC_EHDFERR);
  1493. /* Is this a dimscale? */
  1494. if ((is_scale = H5DSis_scale(datasetid)) < 0)
  1495. BAIL(NC_EHDFERR);
  1496. if (is_scale)
  1497. {
  1498. /* Read the scale information. */
  1499. if ((retval = read_scale(grp, datasetid, obj_name, dims[0],
  1500. max_dims[0], &dim_without_var)))
  1501. BAIL(retval);
  1502. }
  1503. else
  1504. {
  1505. /* Find out how many scales are attached to this
  1506. * dataset. H5DSget_num_scales returns an error if there are no
  1507. * scales, so convert a negative return value to zero. */
  1508. num_scales = H5DSget_num_scales(datasetid, 0);
  1509. if (num_scales < 0)
  1510. num_scales = 0;
  1511. }
  1512. /* Add a var to the linked list, and get its metadata,
  1513. * unless this is one of those funny dimscales that are a
  1514. * dimension in netCDF but not a variable. (Spooky!) */
  1515. if (!dim_without_var)
  1516. if ((retval = read_var(grp, datasetid, obj_name, ndims,
  1517. is_scale, num_scales, access_pid)))
  1518. BAIL(retval);
  1519. if (access_pid && H5Pclose(access_pid) < 0)
  1520. BAIL2(retval);
  1521. #ifdef EXTRA_TESTS
  1522. num_plists--;
  1523. #endif
  1524. if (spaceid && H5Sclose(spaceid) < 0)
  1525. BAIL2(retval);
  1526. #ifdef EXTRA_TESTS
  1527. num_spaces--;
  1528. #endif
  1529. return NC_NOERR;
  1530. exit:
  1531. if (access_pid && H5Pclose(access_pid) < 0)
  1532. BAIL2(retval);
  1533. #ifdef EXTRA_TESTS
  1534. num_plists--;
  1535. #endif
  1536. if (datasetid && H5Dclose(datasetid) < 0)
  1537. BAIL2(retval);
  1538. if (spaceid && H5Sclose(spaceid) <0)
  1539. BAIL2(retval);
  1540. #ifdef EXTRA_TESTS
  1541. num_spaces--;
  1542. #endif
  1543. return retval;
  1544. }
  1545. /* Given index, get the HDF5 name of an object and the class of the
  1546. * object (group, type, dataset, etc.). This function will try to use
  1547. * creation ordering, but if that fails it will use default
  1548. * (i.e. alphabetical) ordering. (This is necessary to read existing
  1549. * HDF5 archives without creation ordering). */
  1550. /* static int */
  1551. /* get_name_by_idx(NC_HDF5_FILE_INFO_T *h5, hid_t hdf_grpid, int i, */
  1552. /* int *obj_class, char *obj_name) */
  1553. /* { */
  1554. /* H5O_info_t obj_info; */
  1555. /* H5_index_t idx_field = H5_INDEX_CRT_ORDER; */
  1556. /* ssize_t size; */
  1557. /* herr_t res; */
  1558. /* /\* These HDF5 macros prevent an HDF5 error message when a */
  1559. /* * non-creation-ordered HDF5 file is opened. *\/ */
  1560. /* H5E_BEGIN_TRY { */
  1561. /* res = H5Oget_info_by_idx(hdf_grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, */
  1562. /* i, &obj_info, H5P_DEFAULT); */
  1563. /* } H5E_END_TRY; */
  1564. /* /\* Creation ordering not available, so make sure this file is */
  1565. /* * opened for read-only access. This is a plain old HDF5 file being */
  1566. /* * read by netCDF-4. *\/ */
  1567. /* if (res < 0) */
  1568. /* { */
  1569. /* if (H5Oget_info_by_idx(hdf_grpid, ".", H5_INDEX_NAME, H5_ITER_INC, */
  1570. /* i, &obj_info, H5P_DEFAULT) < 0) */
  1571. /* return NC_EHDFERR; */
  1572. /* if (!h5->no_write) */
  1573. /* return NC_ECANTWRITE; */
  1574. /* h5->ignore_creationorder = 1; */
  1575. /* idx_field = H5_INDEX_NAME; */
  1576. /* } */
  1577. /* *obj_class = obj_info.type; */
  1578. /* if ((size = H5Lget_name_by_idx(hdf_grpid, ".", idx_field, H5_ITER_INC, i, */
  1579. /* NULL, 0, H5P_DEFAULT)) < 0) */
  1580. /* return NC_EHDFERR; */
  1581. /* if (size > NC_MAX_NAME) */
  1582. /* return NC_EMAXNAME; */
  1583. /* if (H5Lget_name_by_idx(hdf_grpid, ".", idx_field, H5_ITER_INC, i, */
  1584. /* obj_name, size+1, H5P_DEFAULT) < 0) */
  1585. /* return NC_EHDFERR; */
  1586. /* LOG((4, "get_name_by_idx: encountered HDF5 object obj_name %s", obj_name)); */
  1587. /* return NC_NOERR; */
  1588. /* } */
  1589. #define USE_ITERATE_CODE
  1590. #ifdef USE_ITERATE_CODE
  1591. static int
  1592. nc4_rec_read_types_cb(hid_t grpid, const char *name, const H5L_info_t *info,
  1593. void *_op_data)
  1594. {
  1595. hid_t oid=-1;
  1596. H5I_type_t otype=-1;
  1597. char oname[NC_MAX_NAME + 1];
  1598. NC_GRP_INFO_T *child_grp;
  1599. NC_GRP_INFO_T *grp = (NC_GRP_INFO_T *) (_op_data);
  1600. NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
  1601. /* Open this critter. */
  1602. if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
  1603. return H5_ITER_ERROR;
  1604. if ((otype = H5Iget_type( oid ))<0) {
  1605. H5Oclose(oid);
  1606. return H5_ITER_ERROR;
  1607. }
  1608. H5Oclose(oid);
  1609. strncpy(oname, name, NC_MAX_NAME);
  1610. /* Deal with groups and types; ignore the rest. */
  1611. if (otype == H5I_GROUP)
  1612. {
  1613. LOG((3, "found group %s", oname));
  1614. if (nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
  1615. grp, grp->file, oname, &child_grp))
  1616. return H5_ITER_ERROR;
  1617. if (nc4_rec_read_types(child_grp))
  1618. return H5_ITER_ERROR;
  1619. }
  1620. else if (otype == H5I_DATATYPE)
  1621. {
  1622. LOG((3, "found datatype %s", oname));
  1623. if (read_type(grp, oname))
  1624. return H5_ITER_ERROR;
  1625. }
  1626. return (H5_ITER_CONT);
  1627. }
  1628. static int
  1629. nc4_rec_read_types(NC_GRP_INFO_T *grp)
  1630. {
  1631. hsize_t idx=0;
  1632. int res = 0;
  1633. hid_t pid = 0;
  1634. unsigned crt_order_flags = 0;
  1635. NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
  1636. assert(grp && grp->name);
  1637. LOG((3, "nc4_rec_read_types: grp->name %s", grp->name));
  1638. /* Open this HDF5 group and retain its grpid. It will remain open
  1639. * with HDF5 until this file is nc_closed. */
  1640. if (!grp->hdf_grpid)
  1641. {
  1642. if (grp->parent)
  1643. {
  1644. if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
  1645. grp->name, H5P_DEFAULT)) < 0)
  1646. return NC_EHDFERR;
  1647. }
  1648. else
  1649. {
  1650. if ((grp->hdf_grpid = H5Gopen2(grp->file->nc4_info->hdfid,
  1651. "/", H5P_DEFAULT)) < 0)
  1652. return NC_EHDFERR;
  1653. }
  1654. }
  1655. assert(grp->hdf_grpid > 0);
  1656. pid = H5Gget_create_plist(grp->hdf_grpid);
  1657. H5Pget_link_creation_order(pid, &crt_order_flags);
  1658. H5Pclose(pid);
  1659. crt_order_flags = crt_order_flags & H5_INDEX_CRT_ORDER;
  1660. if (crt_order_flags == H5_INDEX_CRT_ORDER)
  1661. {
  1662. res = H5Literate(grp->hdf_grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC,
  1663. &idx, nc4_rec_read_types_cb, (void *)grp);
  1664. } else
  1665. {
  1666. /* Without creation ordering, file must be read-only. */
  1667. if (!idx && !h5->no_write)
  1668. return NC_ECANTWRITE;
  1669. res = H5Literate(grp->hdf_grpid, H5_INDEX_NAME, H5_ITER_INC,
  1670. &idx, nc4_rec_read_types_cb, (void *)grp);
  1671. }
  1672. if (res<0)
  1673. return NC_EHDFERR;
  1674. return NC_NOERR; /* everything worked! */
  1675. }
  1676. static int
  1677. nc4_rec_read_vars_cb(hid_t grpid, const char *name, const H5L_info_t *info,
  1678. void *_op_data)
  1679. {
  1680. hid_t oid=-1;
  1681. H5I_type_t otype=-1;
  1682. char oname[NC_MAX_NAME + 1];
  1683. NC_GRP_INFO_T *child_grp;
  1684. NC_GRP_INFO_T *grp = (NC_GRP_INFO_T *) (_op_data);
  1685. #if 0
  1686. NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
  1687. #endif
  1688. memset(oname, 0, NC_MAX_NAME);
  1689. /* Open this critter. */
  1690. if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
  1691. return H5_ITER_ERROR;
  1692. if ((otype = H5Iget_type( oid ))<0) {
  1693. H5Oclose(oid);
  1694. return H5_ITER_ERROR;
  1695. }
  1696. H5Oclose(oid);
  1697. strncpy(oname, name, NC_MAX_NAME);
  1698. /* Deal with datasets. */
  1699. switch(otype)
  1700. {
  1701. case H5I_GROUP:
  1702. LOG((3, "re-encountering group %s", oname));
  1703. /* The NC_GROUP_INFO_T for this group already exists. Find it. */
  1704. for (child_grp = grp->children; child_grp; child_grp = child_grp->next)
  1705. if (!strcmp(child_grp->name, oname))
  1706. break;
  1707. if (!child_grp)
  1708. return H5_ITER_ERROR;
  1709. /* Recursively read the child group's vars. */
  1710. if (nc4_rec_read_vars(child_grp))
  1711. return H5_ITER_ERROR;
  1712. break;
  1713. case H5I_DATASET:
  1714. LOG((3, "found dataset %s", oname));
  1715. /* Learn all about this dataset, which may be a dimscale
  1716. * (i.e. dimension metadata), or real data. */
  1717. if (read_dataset(grp, oname))
  1718. return H5_ITER_ERROR;
  1719. break;
  1720. case H5I_DATATYPE:
  1721. LOG((3, "already handled type %s", oname));
  1722. break;
  1723. default:
  1724. LOG((0, "Unknown object class %d in nc4_rec_read_vars!", otype));
  1725. }
  1726. return (H5_ITER_CONT);
  1727. }
  1728. static int
  1729. nc4_rec_read_vars(NC_GRP_INFO_T *grp)
  1730. {
  1731. hsize_t idx = 0;
  1732. int retval = NC_NOERR;
  1733. int res = 0;
  1734. hid_t pid = 0;
  1735. unsigned crt_order_flags = 0;
  1736. NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
  1737. assert(grp && grp->name && grp->hdf_grpid > 0);
  1738. LOG((3, "nc4_rec_read_vars: grp->name %s", grp->name));
  1739. pid = H5Gget_create_plist(grp->hdf_grpid);
  1740. H5Pget_link_creation_order(pid, &crt_order_flags);
  1741. H5Pclose(pid);
  1742. crt_order_flags = crt_order_flags & H5_INDEX_CRT_ORDER;
  1743. if (crt_order_flags == H5_INDEX_CRT_ORDER)
  1744. {
  1745. res = H5Literate(grp->hdf_grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC,
  1746. &idx, nc4_rec_read_vars_cb, (void *)grp);
  1747. } else
  1748. {
  1749. /* Without creation ordering, file must be read-only. */
  1750. if (!idx && !h5->no_write)
  1751. return NC_ECANTWRITE;
  1752. res = H5Literate(grp->hdf_grpid, H5_INDEX_NAME, H5_ITER_INC,
  1753. &idx, nc4_rec_read_vars_cb, (void *)grp);
  1754. }
  1755. if (res<0)
  1756. return NC_EHDFERR;
  1757. /* Scan the group for global (i.e. group-level) attributes. */
  1758. if ((retval = read_grp_atts(grp)))
  1759. return retval;
  1760. return NC_NOERR; /* everything worked! */
  1761. }
  1762. #else
  1763. /** \internal
  1764. This struct is used to pass information back from the callback
  1765. function used with H5Literate.
  1766. */
  1767. struct nc_hdf5_link_info
  1768. {
  1769. char name[NC_MAX_NAME + 1];
  1770. H5I_type_t obj_type;
  1771. };
  1772. /* This is a callback function for H5Literate().
  1773. The parameters of this callback function have the following values or
  1774. meanings:
  1775. g_id Group that serves as root of the iteration; same value as the
  1776. H5Lvisit group_id parameter
  1777. name Name of link, relative to g_id, being examined at current step of
  1778. the iteration
  1779. info H5L_info_t struct containing information regarding that link
  1780. op_data User-defined pointer to data required by the application in
  1781. processing the link; a pass-through of the op_data pointer provided
  1782. with the H5Lvisit function call
  1783. */
  1784. static herr_t
  1785. visit_link(hid_t g_id, const char *name, const H5L_info_t *info,
  1786. void *op_data)
  1787. {
  1788. /* A positive return value causes the visit iterator to immediately
  1789. * return that positive value, indicating short-circuit
  1790. * success. The iterator can be restarted at the next group
  1791. * member. */
  1792. int ret = 1;
  1793. hid_t id;
  1794. /* Get the name, truncating at NC_MAX_NAME. */
  1795. strncpy(((struct nc_hdf5_link_info *)op_data)->name, name,
  1796. NC_MAX_NAME);
  1797. /* Open this critter. */
  1798. if ((id = H5Oopen_by_addr(g_id, info->u.address)) < 0)
  1799. return NC_EHDFERR;
  1800. /* Is this critter a group, type, data, attribute, or what? */
  1801. if ((((struct nc_hdf5_link_info *)op_data)->obj_type = H5Iget_type(id)) < 0)
  1802. ret = NC_EHDFERR;
  1803. /* Close the critter to release resouces. */
  1804. if (H5Oclose(id) < 0)
  1805. return NC_EHDFERR;
  1806. return ret;
  1807. }
  1808. /* Iterate over one link in the group at a time, returning
  1809. * link_info. The creation_ordering and idx pointers keep track of
  1810. * whether creation ordering works and the most recently examined
  1811. * link. */
  1812. static int
  1813. nc4_iterate_link(int *ordering_checked, int *creation_ordering,
  1814. hid_t grpid, hsize_t *idx, struct nc_hdf5_link_info *link_info)
  1815. {
  1816. int res = 0;
  1817. if (*creation_ordering)
  1818. {
  1819. /* These HDF5 macros prevent an HDF5 error message when a
  1820. * non-creation-ordered HDF5 file is opened. */
  1821. H5E_BEGIN_TRY {
  1822. res = H5Literate(grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC,
  1823. idx, visit_link, (void *)link_info);
  1824. if (res < 0 && *ordering_checked)
  1825. return NC_EHDFERR;
  1826. } H5E_END_TRY;
  1827. }
  1828. if (!*creation_ordering || res < 0)
  1829. {
  1830. if (H5Literate(grpid, H5_INDEX_NAME, H5_ITER_INC, idx,
  1831. visit_link, link_info) != 1)
  1832. return NC_EHDFERR;
  1833. /* If it didn't work with creation ordering, but did without,
  1834. * then we don't have creation ordering. */
  1835. *creation_ordering = 0;
  1836. }
  1837. *ordering_checked = 1;
  1838. return NC_NOERR;
  1839. }
  1840. /* Recursively open groups and read types. */
  1841. int
  1842. nc4_rec_read_types(NC_GRP_INFO_T *grp)
  1843. {
  1844. hsize_t num_obj, i;
  1845. NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
  1846. NC_GRP_INFO_T *child_grp;
  1847. hsize_t idx = 0;
  1848. struct nc_hdf5_link_info link_info;
  1849. int ordering_checked = 0;
  1850. int creation_ordering = 1; /* Assume we have it. */
  1851. int retval = NC_NOERR;
  1852. assert(grp && grp->name);
  1853. LOG((3, "nc4_rec_read_types: grp->name %s", grp->name));
  1854. /* Open this HDF5 group and retain its grpid. It will remain open
  1855. * with HDF5 until this file is nc_closed. */
  1856. if (!grp->hdf_grpid)
  1857. {
  1858. if (grp->parent)
  1859. {
  1860. if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
  1861. grp->name, H5P_DEFAULT)) < 0)
  1862. return NC_EHDFERR;
  1863. }
  1864. else
  1865. {
  1866. if ((grp->hdf_grpid = H5Gopen2(grp->file->nc4_info->hdfid,
  1867. "/", H5P_DEFAULT)) < 0)
  1868. return NC_EHDFERR;
  1869. }
  1870. }
  1871. assert(grp->hdf_grpid > 0);
  1872. /* How many objects in this group? */
  1873. if (H5Gget_num_objs(grp->hdf_grpid, &num_obj) < 0)
  1874. return NC_EVARMETA;
  1875. /* For each object in the group... */
  1876. for (i = 0; i < num_obj; i++)
  1877. {
  1878. if ((retval = nc4_iterate_link(&ordering_checked, &creation_ordering,
  1879. grp->hdf_grpid, &idx, &link_info)))
  1880. return retval;
  1881. /* Without creation ordering, file must be read-only. */
  1882. if (!i && !creation_ordering && !h5->no_write)
  1883. return NC_ECANTWRITE;
  1884. /* Deal with groups and types; ignore the rest. */
  1885. if (link_info.obj_type == H5I_GROUP)
  1886. {
  1887. LOG((3, "found group %s", link_info.name));
  1888. if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
  1889. grp, grp->file, link_info.name, &child_grp)))
  1890. return retval;
  1891. if ((retval = nc4_rec_read_types(child_grp)))
  1892. return retval;
  1893. }
  1894. else if (link_info.obj_type == H5I_DATATYPE)
  1895. {
  1896. LOG((3, "found datatype %s", link_info.name));
  1897. if ((retval = read_type(grp, link_info.name)))
  1898. return retval;
  1899. }
  1900. }
  1901. return NC_NOERR; /* everything worked! */
  1902. }
  1903. /* This function recursively reads all the var and attribute metadata
  1904. in a HDF5 group, and creates and fills in the netCDF-4 global
  1905. metadata structure. */
  1906. int
  1907. nc4_rec_read_vars(NC_GRP_INFO_T *grp)
  1908. {
  1909. hsize_t num_obj, i;
  1910. NC_GRP_INFO_T *child_grp;
  1911. struct nc_hdf5_link_info link_info;
  1912. hsize_t idx = 0;
  1913. int ordering_checked = 0;
  1914. int creation_ordering = 1; /* Assume we have it. */
  1915. int retval = NC_NOERR;
  1916. assert(grp && grp->name && grp->hdf_grpid > 0);
  1917. LOG((3, "nc4_rec_read_vars: grp->name %s", grp->name));
  1918. /* How many objects in this group? */
  1919. if (H5Gget_num_objs(grp->hdf_grpid, &num_obj) < 0)
  1920. return NC_EVARMETA;
  1921. /* For each object in the group... */
  1922. for (i = 0; i < num_obj; i++)
  1923. {
  1924. if ((retval = nc4_iterate_link(&ordering_checked, &creation_ordering,
  1925. grp->hdf_grpid, &idx, &link_info)))
  1926. return retval;
  1927. /* Deal with datasets. */
  1928. switch(link_info.obj_type)
  1929. {
  1930. case H5I_GROUP:
  1931. LOG((3, "re-encountering group %s", link_info.name));
  1932. /* The NC_GROUP_INFO_T for this group already exists. Find it. */
  1933. for (child_grp = grp->children; child_grp; child_grp = child_grp->next)
  1934. if (!strcmp(child_grp->name, link_info.name))
  1935. break;
  1936. if (!child_grp)
  1937. return NC_EHDFERR;
  1938. /* Recursively read the child group's vars. */
  1939. if ((retval = nc4_rec_read_vars(child_grp)))
  1940. return retval;
  1941. break;
  1942. case H5I_DATASET:
  1943. LOG((3, "found dataset %s", link_info.name));
  1944. /* Learn all about this dataset, which may be a dimscale
  1945. * (i.e. dimension metadata), or real data. */
  1946. if ((retval = read_dataset(grp, link_info.name)))
  1947. return retval;
  1948. break;
  1949. case H5I_DATATYPE:
  1950. LOG((3, "already handled type %s", link_info.name));
  1951. break;
  1952. default:
  1953. LOG((0, "Unknown object class %d in nc4_rec_read_vars!",
  1954. link_info.obj_type));
  1955. }
  1956. }
  1957. /* Scan the group for global (i.e. group-level) attributes. */
  1958. if ((retval = read_grp_atts(grp)))
  1959. return retval;
  1960. return NC_NOERR; /* everything worked! */
  1961. }
  1962. #endif
  1963. /* Open a netcdf-4 file. Things have already been kicked off in
  1964. * ncfunc.c in nc_open, but here the netCDF-4 part of opening a file
  1965. * is handled. */
  1966. static int
  1967. nc4_open_file(const char *path, int mode, MPI_Comm comm,
  1968. MPI_Info info, NC_FILE_INFO_T *nc)
  1969. {
  1970. hid_t fapl_id = H5P_DEFAULT;
  1971. unsigned flags = (mode & NC_WRITE) ?
  1972. H5F_ACC_RDWR : H5F_ACC_RDONLY;
  1973. int retval;
  1974. LOG((3, "nc4_open_file: path %s mode %d", path, mode));
  1975. assert(path && nc);
  1976. /* Stop diskless open in its tracks */
  1977. if(mode & NC_DISKLESS)
  1978. return NC_EDISKLESS;
  1979. /* Add necessary structs to hold netcdf-4 file data. */
  1980. if ((retval = nc4_nc4f_list_add(nc, path, mode)))
  1981. BAIL(retval);
  1982. assert(nc->nc4_info && nc->nc4_info->root_grp);
  1983. /* Need this access plist to control how HDF5 handles open onjects
  1984. * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
  1985. * fail if there are any open objects in the file. */
  1986. if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
  1987. BAIL(NC_EHDFERR);
  1988. #ifdef EXTRA_TESTS
  1989. num_plists++;
  1990. #endif
  1991. #ifdef EXTRA_TESTS
  1992. if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
  1993. BAIL(NC_EHDFERR);
  1994. #else
  1995. if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG))
  1996. BAIL(NC_EHDFERR);
  1997. #endif
  1998. #ifdef USE_PARALLEL
  1999. /* If this is a parallel file create, set up the file creation
  2000. property list. */
  2001. if (mode & NC_MPIIO || mode & NC_MPIPOSIX)
  2002. {
  2003. nc->nc4_info->parallel++;
  2004. if (mode & NC_MPIIO) /* MPI/IO */
  2005. {
  2006. LOG((4, "opening parallel file with MPI/IO"));
  2007. if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
  2008. BAIL(NC_EPARINIT);
  2009. }
  2010. else /* MPI/POSIX */
  2011. {
  2012. LOG((4, "opening parallel file with MPI/posix"));
  2013. if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
  2014. BAIL(NC_EPARINIT);
  2015. }
  2016. }
  2017. #else /* only set cache for non-parallel. */
  2018. if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
  2019. nc4_chunk_cache_preemption) < 0)
  2020. BAIL(NC_EHDFERR);
  2021. LOG((4, "nc4_open_file: set HDF raw chunk cache to size %d nelems %d preemption %f",
  2022. nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption));
  2023. #endif /* USE_PARALLEL */
  2024. /* The NetCDF-3.x prototype contains an mode option NC_SHARE for
  2025. multiple processes accessing the dataset concurrently. As there
  2026. is no HDF5 equivalent, NC_SHARE is treated as NC_NOWRITE. */
  2027. if ((nc->nc4_info->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
  2028. BAIL(NC_EHDFERR);
  2029. /* Does the mode specify that this file is read-only? */
  2030. if ((mode & NC_WRITE) == 0)
  2031. nc->nc4_info->no_write++;
  2032. /* Now read in all the metadata. Some types and dimscale
  2033. * information may be difficult to resolve here, if, for example, a
  2034. * dataset of user-defined type is encountered before the
  2035. * definition of that type. */
  2036. if ((retval = nc4_rec_read_types(nc->nc4_info->root_grp)))
  2037. BAIL(retval);
  2038. if ((retval = nc4_rec_read_vars(nc->nc4_info->root_grp)))
  2039. BAIL(retval);
  2040. /* Now figure out which netCDF dims are indicated by the dimscale
  2041. * information. */
  2042. if ((retval = nc4_rec_match_dimscales(nc->nc4_info->root_grp)))
  2043. BAIL(retval);
  2044. #ifdef LOGGING
  2045. /* This will print out the names, types, lens, etc of the vars and
  2046. atts in the file, if the logging level is 2 or greater. */
  2047. log_metadata_nc(nc);
  2048. #endif
  2049. /* Close the property list. */
  2050. if (H5Pclose(fapl_id) < 0)
  2051. BAIL(NC_EHDFERR);
  2052. #ifdef EXTRA_TESTS
  2053. num_plists--;
  2054. #endif
  2055. return NC_NOERR;
  2056. exit:
  2057. if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
  2058. #ifdef EXTRA_TESTS
  2059. num_plists--;
  2060. #endif
  2061. if (nc->nc4_info->hdfid > 0) H5Fclose(nc->nc4_info->hdfid);
  2062. if (nc->nc4_info) free(nc->nc4_info);
  2063. return retval;
  2064. }
  2065. /* Given an HDF4 type, set a pointer to netcdf type. */
  2066. #ifdef USE_HDF4
  2067. static int
  2068. get_netcdf_type_from_hdf4(NC_HDF5_FILE_INFO_T *h5, int32 hdf4_typeid,
  2069. nc_type *xtype, NC_TYPE_INFO_T *type_info)
  2070. {
  2071. int t;
  2072. assert(h5 && xtype);
  2073. switch(hdf4_typeid)
  2074. {
  2075. case DFNT_CHAR:
  2076. *xtype = NC_CHAR;
  2077. t = 0;
  2078. break;
  2079. case DFNT_UCHAR:
  2080. case DFNT_UINT8:
  2081. *xtype = NC_UBYTE;
  2082. t = 6;
  2083. break;
  2084. case DFNT_INT8:
  2085. *xtype = NC_BYTE;
  2086. t = 1;
  2087. break;
  2088. case DFNT_INT16:
  2089. *xtype = NC_SHORT;
  2090. t = 2;
  2091. break;
  2092. case DFNT_UINT16:
  2093. *xtype = NC_USHORT;
  2094. t = 7;
  2095. break;
  2096. case DFNT_INT32:
  2097. *xtype = NC_INT;
  2098. t = 3;
  2099. break;
  2100. case DFNT_UINT32:
  2101. *xtype = NC_UINT;
  2102. t = 8;
  2103. break;
  2104. case DFNT_FLOAT32:
  2105. *xtype = NC_FLOAT;
  2106. t = 4;
  2107. break;
  2108. case DFNT_FLOAT64:
  2109. *xtype = NC_DOUBLE;
  2110. t = 5;
  2111. break;
  2112. default:
  2113. *xtype = NC_NAT;
  2114. return NC_EBADTYPID;
  2115. }
  2116. if (type_info)
  2117. {
  2118. if (hdf4_typeid == DFNT_FLOAT32 || hdf4_typeid == DFNT_FLOAT64)
  2119. type_info->class = H5T_FLOAT;
  2120. else if (hdf4_typeid == DFNT_CHAR)
  2121. type_info->class = H5T_STRING;
  2122. else
  2123. type_info->class = H5T_INTEGER;
  2124. type_info->endianness = NC_ENDIAN_BIG;
  2125. type_info->nc_typeid = *xtype;
  2126. if (type_info->name)
  2127. free(type_info->name);
  2128. if (!(type_info->name = malloc((strlen(nc_type_name[t]) + 1) * sizeof(char))))
  2129. return NC_ENOMEM;
  2130. strcpy(type_info->name, nc_type_name[t]);
  2131. }
  2132. return NC_NOERR;
  2133. }
  2134. #endif /* USE_HDF4 */
  2135. /* Open a HDF4 file. Things have already been kicked off in nc_open,
  2136. * but here the netCDF-4 part of opening a file is handled. */
  2137. static int
  2138. nc4_open_hdf4_file(const char *path, int mode, NC_FILE_INFO_T *nc)
  2139. {
  2140. #ifdef USE_HDF4
  2141. NC_HDF5_FILE_INFO_T *h5;
  2142. NC_GRP_INFO_T *grp;
  2143. NC_ATT_INFO_T *att;
  2144. NC_VAR_INFO_T *var;
  2145. int32 num_datasets, num_gatts;
  2146. int32 rank;
  2147. int v, d, a;
  2148. int retval;
  2149. LOG((3, "nc4_open_hdf4_file: path %s mode %d", path, mode));
  2150. assert(path && nc);
  2151. /* Must be read-only access to hdf4 files. */
  2152. if (mode & NC_WRITE)
  2153. return NC_EINVAL;
  2154. /* Add necessary structs to hold netcdf-4 file data. */
  2155. if ((retval = nc4_nc4f_list_add(nc, path, mode)))
  2156. return retval;
  2157. assert(nc->nc4_info && nc->nc4_info->root_grp);
  2158. h5 = nc->nc4_info;
  2159. h5->hdf4++;
  2160. grp = h5->root_grp;
  2161. h5->no_write++;
  2162. /* Open the file and initialize SD interface. */
  2163. if ((h5->sdid = SDstart(path, DFACC_READ)) == FAIL)
  2164. return NC_EHDFERR;
  2165. /* Learn how many datasets and global atts we have. */
  2166. if (SDfileinfo(h5->sdid, &num_datasets, &num_gatts))
  2167. return NC_EHDFERR;
  2168. /* Read the atts. */
  2169. for (a = 0; a < num_gatts; a++)
  2170. {
  2171. int32 att_data_type, att_count;
  2172. size_t att_type_size;
  2173. /* Add to the end of the list of atts for this var. */
  2174. if ((retval = nc4_att_list_add(&h5->root_grp->att)))
  2175. return retval;
  2176. for (att = h5->root_grp->att; att->next; att = att->next)
  2177. ;
  2178. att->attnum = grp->natts++;
  2179. att->created++;
  2180. /* Learn about this attribute. */
  2181. if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char))))
  2182. return NC_ENOMEM;
  2183. if (SDattrinfo(h5->sdid, a, att->name, &att_data_type, &att_count))
  2184. return NC_EATTMETA;
  2185. if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
  2186. &att->xtype, NULL)))
  2187. return retval;
  2188. att->len = att_count;
  2189. /* Allocate memory to hold the data. */
  2190. if ((retval = nc4_get_typelen_mem(h5, att->xtype, 0, &att_type_size)))
  2191. return retval;
  2192. if (!(att->data = malloc(att_type_size * att->len)))
  2193. return NC_ENOMEM;
  2194. /* Read the data. */
  2195. if (SDreadattr(h5->sdid, a, att->data))
  2196. return NC_EHDFERR;
  2197. }
  2198. /* Read each dataset. */
  2199. for (v = 0; v < num_datasets; v++)
  2200. {
  2201. int32 data_type, num_atts;
  2202. int32 dimsize[NC_MAX_DIMS];
  2203. size_t var_type_size;
  2204. int a;
  2205. /* Add a variable to the end of the group's var list. */
  2206. if ((retval = nc4_var_list_add(&grp->var, &var)))
  2207. return retval;
  2208. var->varid = grp->nvars++;
  2209. var->created = 1;
  2210. var->written_to = 1;
  2211. /* Open this dataset in HDF4 file. */
  2212. if ((var->sdsid = SDselect(h5->sdid, v)) == FAIL)
  2213. return NC_EVARMETA;
  2214. /* Get shape, name, type, and attribute info about this dataset. */
  2215. if (!(var->name = malloc(NC_MAX_HDF4_NAME + 1)))
  2216. return NC_ENOMEM;
  2217. if (SDgetinfo(var->sdsid, var->name, &rank, dimsize, &data_type, &num_atts))
  2218. return NC_EVARMETA;
  2219. var->ndims = rank;
  2220. var->hdf4_data_type = data_type;
  2221. /* Fill special type_info struct for variable type information. */
  2222. if (!(var->type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
  2223. return NC_ENOMEM;
  2224. if ((retval = get_netcdf_type_from_hdf4(h5, data_type, &var->xtype, var->type_info)))
  2225. return retval;
  2226. if ((retval = nc4_get_typelen_mem(h5, var->xtype, 0, &var_type_size)))
  2227. return retval;
  2228. var->type_info->size = var_type_size;
  2229. LOG((3, "reading HDF4 dataset %s, rank %d netCDF type %d", var->name,
  2230. rank, var->xtype));
  2231. /* Get the fill value. */
  2232. if (!(var->fill_value = malloc(var_type_size)))
  2233. return NC_ENOMEM;
  2234. if (SDgetfillvalue(var->sdsid, var->fill_value))
  2235. {
  2236. /* Whoops! No fill value! */
  2237. free(var->fill_value);
  2238. var->fill_value = NULL;
  2239. }
  2240. /* Allocate storage for dimension info in this variable. */
  2241. if (var->ndims)
  2242. {
  2243. if (!(var->dim = malloc(sizeof(NC_DIM_INFO_T *) * var->ndims)))
  2244. return NC_ENOMEM;
  2245. if (!(var->dimids = malloc(sizeof(int) * var->ndims)))
  2246. return NC_ENOMEM;
  2247. }
  2248. /* Find its dimensions. */
  2249. for (d = 0; d < var->ndims; d++)
  2250. {
  2251. int32 dimid, dim_len, dim_data_type, dim_num_attrs;
  2252. char dim_name[NC_MAX_NAME + 1];
  2253. NC_DIM_INFO_T *dim;
  2254. if ((dimid = SDgetdimid(var->sdsid, d)) == FAIL)
  2255. return NC_EDIMMETA;
  2256. if (SDdiminfo(dimid, dim_name, &dim_len, &dim_data_type,
  2257. &dim_num_attrs))
  2258. return NC_EDIMMETA;
  2259. /* Do we already have this dimension? HDF4 explicitly uses
  2260. * the name to tell. */
  2261. for (dim = grp->dim; dim; dim = dim->next)
  2262. if (!strcmp(dim->name, dim_name))
  2263. break;
  2264. /* If we didn't find this dimension, add one. */
  2265. if (!dim)
  2266. {
  2267. LOG((4, "adding dimension %s for HDF4 dataset %s",
  2268. dim_name, var->name));
  2269. if ((retval = nc4_dim_list_add(&grp->dim)))
  2270. return retval;
  2271. grp->ndims++;
  2272. dim = grp->dim;
  2273. dim->dimid = grp->file->nc4_info->next_dimid++;
  2274. if (strlen(dim_name) > NC_MAX_HDF4_NAME)
  2275. return NC_EMAXNAME;
  2276. if (!(dim->name = malloc(NC_MAX_HDF4_NAME + 1)))
  2277. return NC_ENOMEM;
  2278. strcpy(dim->name, dim_name);
  2279. if (dim_len)
  2280. dim->len = dim_len;
  2281. else
  2282. dim->len = *dimsize;
  2283. }
  2284. /* Tell the variable the id of this dimension. */
  2285. var->dimids[d] = dim->dimid;
  2286. }
  2287. /* Read the atts. */
  2288. for (a = 0; a < num_atts; a++)
  2289. {
  2290. int32 att_data_type, att_count;
  2291. size_t att_type_size;
  2292. /* Add to the end of the list of atts for this var. */
  2293. if ((retval = nc4_att_list_add(&var->att)))
  2294. return retval;
  2295. for (att = var->att; att->next; att = att->next)
  2296. ;
  2297. att->attnum = var->natts++;
  2298. att->created++;
  2299. /* Learn about this attribute. */
  2300. if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char))))
  2301. return NC_ENOMEM;
  2302. if (SDattrinfo(var->sdsid, a, att->name, &att_data_type, &att_count))
  2303. return NC_EATTMETA;
  2304. if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
  2305. &att->xtype, NULL)))
  2306. return retval;
  2307. att->len = att_count;
  2308. /* Allocate memory to hold the data. */
  2309. if ((retval = nc4_get_typelen_mem(h5, att->xtype, 0, &att_type_size)))
  2310. return retval;
  2311. if (!(att->data = malloc(att_type_size * att->len)))
  2312. return NC_ENOMEM;
  2313. /* Read the data. */
  2314. if (SDreadattr(var->sdsid, a, att->data))
  2315. return NC_EHDFERR;
  2316. }
  2317. } /* next var */
  2318. #ifdef LOGGING
  2319. /* This will print out the names, types, lens, etc of the vars and
  2320. atts in the file, if the logging level is 2 or greater. */
  2321. log_metadata_nc(h5->root_grp->file);
  2322. #endif
  2323. return NC_NOERR;
  2324. #endif /* USE_HDF4 */
  2325. return NC_ENOTBUILT;
  2326. }
  2327. int
  2328. NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp,
  2329. int use_parallel, void *mpidata, NC_Dispatch *dispatch, NC **ncpp)
  2330. {
  2331. int hdf_file = 0;
  2332. NC_FILE_INFO_T *nc_file;
  2333. #ifdef USE_PARALLEL
  2334. MPI_Comm comm = 0;
  2335. MPI_Info info = 0;
  2336. #else
  2337. int comm = 0, info = 0;
  2338. #endif /* USE_PARALLEL */
  2339. int res;
  2340. assert(ncpp && path);
  2341. LOG((1, "nc_open_file: path %s mode %d comm %d info %d",
  2342. path, mode, comm, info));
  2343. #ifdef USE_PARALLEL
  2344. if (mpidata)
  2345. {
  2346. NC_MPI_INFO *nmi = (NC_MPI_INFO *)mpidata;
  2347. comm = nmi->comm; info = nmi->info;
  2348. }
  2349. #endif /* USE_PARALLEL */
  2350. /* If this is our first file, turn off HDF5 error messages. */
  2351. if (virgin)
  2352. {
  2353. if (H5Eset_auto(NULL, NULL) < 0)
  2354. LOG((0, "Couldn't turn off HDF5 error messages!"));
  2355. LOG((1, "HDF5 error messages turned off!"));
  2356. virgin = 0;
  2357. }
  2358. /* Check the mode for validity. First make sure only certain bits
  2359. * are turned on. Also MPI I/O and MPI POSIX cannot both be
  2360. * selected at once. */
  2361. if (mode & ~(NC_WRITE | NC_SHARE | NC_MPIIO | NC_MPIPOSIX |
  2362. NC_PNETCDF | NC_NOCLOBBER | NC_NETCDF4 | NC_CLASSIC_MODEL) ||
  2363. (mode & NC_MPIIO && mode & NC_MPIPOSIX))
  2364. return NC_EINVAL;
  2365. /* Figure out if this is a hdf4 or hdf5 file. */
  2366. if ((res = nc_check_for_hdf(path, use_parallel, comm, info, &hdf_file)))
  2367. return res;
  2368. /* Allocate the storage for this file info struct, and fill it with
  2369. zeros. */
  2370. if ((res = nc4_file_list_add(&nc_file,dispatch)))
  2371. return res;
  2372. /* Depending on the type of file, open it. */
  2373. if (hdf_file == NC_HDF5_FILE)
  2374. {
  2375. nc_file->int_ncid = nc_file->ext_ncid;
  2376. res = nc4_open_file(path, mode, comm, info, nc_file);
  2377. }
  2378. else if (hdf_file == NC_HDF4_FILE)
  2379. {
  2380. nc_file->int_ncid = nc_file->ext_ncid;
  2381. res = nc4_open_hdf4_file(path, mode, nc_file);
  2382. }
  2383. #ifdef USE_PNETCDF
  2384. else if (mode & NC_PNETCDF)
  2385. {
  2386. int pnetcdf_nvars, i;
  2387. res = ncmpi_open(comm, path, mode, info, &(nc_file->int_ncid));
  2388. nc_file->pnetcdf_file++;
  2389. /* Default to independent access, like netCDF-4/HDF5 files. */
  2390. if (!res)
  2391. res = ncmpi_begin_indep_data(nc_file->int_ncid);
  2392. /* I need to keep track of the ndims of each var to translate
  2393. * start, count, and stride arrays to MPI_Offset type. */
  2394. if (!res)
  2395. {
  2396. res = ncmpi_inq_nvars(nc_file->int_ncid, &pnetcdf_nvars);
  2397. for (i = 0; i < pnetcdf_nvars; i++)
  2398. res = ncmpi_inq_varndims(nc_file->int_ncid, i,
  2399. &(nc_file->pnetcdf_ndims[i]));
  2400. }
  2401. }
  2402. #endif /* USE_PNETCDF */
  2403. else /* netcdf */
  2404. {
  2405. assert(0);
  2406. }
  2407. /* If it succeeds, pass back the new ncid. Otherwise, remove this
  2408. file from the list. */
  2409. if (res)
  2410. {
  2411. if(nc_file != NULL) nc4_file_list_del(nc_file);
  2412. }
  2413. else
  2414. {
  2415. *ncpp = (NC*)nc_file;
  2416. }
  2417. return res;
  2418. }
  2419. /* Unfortunately HDF only allows specification of fill value only when
  2420. a dataset is created. Whereas in netcdf, you first create the
  2421. variable and then (optionally) specify the fill value. To
  2422. accomplish this in HDF5 I have to delete the dataset, and recreate
  2423. it, with the fill value specified. */
  2424. int
  2425. NC4_set_fill(int ncid, int fillmode, int *old_modep)
  2426. {
  2427. NC_FILE_INFO_T *nc;
  2428. LOG((2, "nc_set_fill: ncid 0x%x fillmode %d", ncid, fillmode));
  2429. if (!(nc = nc4_find_nc_file(ncid)))
  2430. return NC_EBADID;
  2431. /* Is this a netcdf-3 file? */
  2432. assert(nc->nc4_info);
  2433. /* Trying to set fill on a read-only file? You sicken me! */
  2434. if (nc->nc4_info->no_write)
  2435. return NC_EPERM;
  2436. /* Did you pass me some weird fillmode? */
  2437. if (fillmode != NC_FILL && fillmode != NC_NOFILL)
  2438. return NC_EINVAL;
  2439. /* If the user wants to know, tell him what the old mode was. */
  2440. if (old_modep)
  2441. *old_modep = nc->nc4_info->fill_mode;
  2442. nc->nc4_info->fill_mode = fillmode;
  2443. return NC_NOERR;
  2444. }
  2445. /* Put the file back in redef mode. This is done automatically for
  2446. * netcdf-4 files, if the user forgets. */
  2447. int
  2448. NC4_redef(int ncid)
  2449. {
  2450. NC_FILE_INFO_T *nc;
  2451. LOG((1, "nc_redef: ncid 0x%x", ncid));
  2452. /* Find this file's metadata. */
  2453. if (!(nc = nc4_find_nc_file(ncid)))
  2454. return NC_EBADID;
  2455. #ifdef USE_PNETCDF
  2456. /* Take care of files created/opened with parallel-netcdf library. */
  2457. if (nc->pnetcdf_file)
  2458. return ncmpi_redef(nc->int_ncid);
  2459. #endif /* USE_PNETCDF */
  2460. /* Handle netcdf-3 files. */
  2461. assert(nc->nc4_info);
  2462. /* If we're already in define mode, return an error. */
  2463. if (nc->nc4_info->flags & NC_INDEF)
  2464. return NC_EINDEFINE;
  2465. /* If the file is read-only, return an error. */
  2466. if (nc->nc4_info->no_write)
  2467. return NC_EPERM;
  2468. /* Set define mode. */
  2469. nc->nc4_info->flags |= NC_INDEF;
  2470. /* For nc_abort, we need to remember if we're in define mode as a
  2471. redef. */
  2472. nc->nc4_info->redef++;
  2473. return NC_NOERR;
  2474. }
  2475. /* For netcdf-4 files, this just calls nc_enddef, ignoring the extra
  2476. * parameters. */
  2477. int
  2478. NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
  2479. size_t v_minfree, size_t r_align)
  2480. {
  2481. if (!nc4_find_nc_file(ncid))
  2482. return NC_EBADID;
  2483. return NC4_enddef(ncid);
  2484. }
  2485. /* Take the file out of define mode. This is called automatically for
  2486. * netcdf-4 files, if the user forgets. */
  2487. static int NC4_enddef(int ncid)
  2488. {
  2489. NC_FILE_INFO_T *nc;
  2490. LOG((1, "nc_enddef: ncid 0x%x", ncid));
  2491. if (!(nc = nc4_find_nc_file(ncid)))
  2492. return NC_EBADID;
  2493. #ifdef USE_PNETCDF
  2494. if (nc->pnetcdf_file)
  2495. {
  2496. int res;
  2497. res = ncmpi_enddef(nc->int_ncid);
  2498. if (!res)
  2499. {
  2500. if (nc->pnetcdf_access_mode == NC_INDEPENDENT)
  2501. res = ncmpi_begin_indep_data(nc->int_ncid);
  2502. }
  2503. return res;
  2504. }
  2505. #endif /* USE_PNETCDF */
  2506. /* Take care of netcdf-3 files. */
  2507. assert(nc->nc4_info);
  2508. return nc4_enddef_netcdf4_file(nc->nc4_info);
  2509. }
  2510. /* This function will write all changed metadata, and (someday) reread
  2511. * all metadata from the file. */
  2512. static int
  2513. sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
  2514. {
  2515. int retval;
  2516. assert(h5);
  2517. LOG((3, "sync_netcdf4_file"));
  2518. /* If we're in define mode, that's an error, for strict nc3 rules,
  2519. * otherwise, end define mode. */
  2520. if (h5->flags & NC_INDEF)
  2521. {
  2522. if (h5->cmode & NC_CLASSIC_MODEL)
  2523. return NC_EINDEFINE;
  2524. /* Turn define mode off. */
  2525. h5->flags ^= NC_INDEF;
  2526. /* Redef mode needs to be tracked seperately for nc_abort. */
  2527. h5->redef = 0;
  2528. }
  2529. #ifdef LOGGING
  2530. /* This will print out the names, types, lens, etc of the vars and
  2531. atts in the file, if the logging level is 2 or greater. */
  2532. log_metadata_nc(h5->root_grp->file);
  2533. #endif
  2534. /* Write any metadata that has changed. */
  2535. if (!(h5->cmode & NC_NOWRITE))
  2536. {
  2537. if ((retval = nc4_rec_write_types(h5->root_grp)))
  2538. return retval;
  2539. if ((retval = nc4_rec_write_metadata(h5->root_grp)))
  2540. return retval;
  2541. }
  2542. H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL);
  2543. /* Reread all the metadata. */
  2544. /*if ((retval = nc4_rec_read_metadata(grp)))
  2545. return retval;*/
  2546. return retval;
  2547. }
  2548. /* Flushes all buffers associated with the file, after writing all
  2549. changed metadata. This may only be called in data mode. */
  2550. int
  2551. NC4_sync(int ncid)
  2552. {
  2553. NC_FILE_INFO_T *nc;
  2554. int retval;
  2555. LOG((2, "nc_sync: ncid 0x%x", ncid));
  2556. if (!(nc = nc4_find_nc_file(ncid)))
  2557. return NC_EBADID;
  2558. #ifdef USE_PNETCDF
  2559. /* Take care of files created/opened with parallel-netcdf library. */
  2560. if (nc->pnetcdf_file)
  2561. return ncmpi_sync(nc->int_ncid);
  2562. #endif /* USE_PNETCDF */
  2563. /* Take care of netcdf-3 files. */
  2564. assert(nc->nc4_info);
  2565. /* If we're in define mode, we can't sync. */
  2566. if (nc->nc4_info && nc->nc4_info->flags & NC_INDEF)
  2567. {
  2568. if (nc->nc4_info->cmode & NC_CLASSIC_MODEL)
  2569. return NC_EINDEFINE;
  2570. if ((retval = nc_enddef(ncid)))
  2571. return retval;
  2572. }
  2573. return sync_netcdf4_file(nc->nc4_info);
  2574. }
  2575. /* This function will free all allocated metadata memory, and close
  2576. the HDF5 file. The group that is passed in must be the root group
  2577. of the file. */
  2578. static int
  2579. close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort)
  2580. {
  2581. int retval;
  2582. assert(h5 && h5->root_grp);
  2583. LOG((3, "close_netcdf4_file: h5->path %s abort %d",
  2584. h5->path, abort));
  2585. /* According to the docs, always end define mode on close. */
  2586. if (h5->flags & NC_INDEF)
  2587. h5->flags ^= NC_INDEF;
  2588. /* Sync the file, unless we're aborting, or this is a read-only
  2589. * file. */
  2590. if (!h5->no_write && !abort)
  2591. if ((retval = sync_netcdf4_file(h5)))
  2592. return retval;
  2593. /* Delete all the list contents for vars, dims, and atts, in each
  2594. * group. */
  2595. if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp)))
  2596. return retval;
  2597. /* Close hdf file. */
  2598. if (h5->hdf4)
  2599. {
  2600. #ifdef USE_HDF4
  2601. if (SDend(h5->sdid))
  2602. return NC_EHDFERR;
  2603. #endif /* USE_HDF4 */
  2604. }
  2605. else
  2606. {
  2607. if (H5Fclose(h5->hdfid) < 0)
  2608. {
  2609. int nobjs;
  2610. nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL);
  2611. /* Apparently we can get an error even when nobjs == 0 */
  2612. if(nobjs < 0) {
  2613. return NC_EHDFERR;
  2614. } else if(nobjs > 0) {
  2615. #ifdef LOGGING
  2616. /* If the close doesn't work, probably there are still some HDF5
  2617. * objects open, which means there's a bug in the library. So
  2618. * print out some info on to help the poor programmer figure it
  2619. * out. */
  2620. LOG((0, "There are %d HDF5 objects open!", nobjs));
  2621. #endif
  2622. return NC_EHDFERR;
  2623. }
  2624. }
  2625. /* if (H5garbage_collect() < 0)
  2626. return NC_EHDFERR; */
  2627. }
  2628. /* Delete the memory for the path, if it's been allocated. */
  2629. if (h5->path)
  2630. free(h5->path);
  2631. /* Free the nc4_info struct. */
  2632. free(h5);
  2633. return NC_NOERR;
  2634. }
  2635. /* From the netcdf-3 docs: The function nc_abort just closes the
  2636. netCDF dataset, if not in define mode. If the dataset is being
  2637. created and is still in define mode, the dataset is deleted. If
  2638. define mode was entered by a call to nc_redef, the netCDF dataset
  2639. is restored to its state before definition mode was entered and the
  2640. dataset is closed. */
  2641. int
  2642. NC4_abort(int ncid)
  2643. {
  2644. NC_FILE_INFO_T *nc;
  2645. int delete_file = 0;
  2646. char path[NC_MAX_NAME + 1];
  2647. int retval = NC_NOERR;
  2648. LOG((2, "nc_abort: ncid 0x%x", ncid));
  2649. /* Find metadata for this file. */
  2650. if (!(nc = nc4_find_nc_file(ncid)))
  2651. return NC_EBADID;
  2652. #ifdef USE_PNETCDF
  2653. /* Take care of files created/opened with parallel-netcdf library. */
  2654. if (nc->pnetcdf_file)
  2655. return ncmpi_abort(nc->int_ncid);
  2656. #endif /* USE_PNETCDF */
  2657. /* If this is a netcdf-3 file, let the netcdf-3 library handle it. */
  2658. assert(nc->nc4_info);
  2659. /* If we're in define mode, but not redefing the file, delete it. */
  2660. if (nc->nc4_info->flags & NC_INDEF && !nc->nc4_info->redef)
  2661. {
  2662. delete_file++;
  2663. strcpy(path, nc->nc4_info->path);
  2664. /*strcpy(path, nc->path);*/
  2665. }
  2666. /* Free any resources the netcdf-4 library has for this file's
  2667. * metadata. */
  2668. if ((retval = close_netcdf4_file(nc->nc4_info, 1)))
  2669. return retval;
  2670. /* Delete the file, if we should. */
  2671. if (delete_file)
  2672. remove(path);
  2673. /* Delete this entry from our list of open files. */
  2674. nc4_file_list_del(nc);
  2675. return retval;
  2676. }
  2677. /* Close the netcdf file, writing any changes first. */
  2678. int
  2679. NC4_close(int ncid)
  2680. {
  2681. NC_GRP_INFO_T *grp;
  2682. NC_FILE_INFO_T *nc;
  2683. NC_HDF5_FILE_INFO_T *h5;
  2684. int retval;
  2685. LOG((1, "nc_close: ncid 0x%x", ncid));
  2686. /* Find our metadata for this file. */
  2687. if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
  2688. return retval;
  2689. #ifdef USE_PNETCDF
  2690. /* Take care of files created/opened with parallel-netcdf library. */
  2691. if (nc->pnetcdf_file)
  2692. return ncmpi_close(nc->int_ncid);
  2693. #endif /* USE_PNETCDF */
  2694. assert(h5 && nc);
  2695. /* This must be the root group. */
  2696. if (grp->parent)
  2697. return NC_EBADGRPID;
  2698. /* Call the nc4 close. */
  2699. if ((retval = close_netcdf4_file(grp->file->nc4_info, 0)))
  2700. return retval;
  2701. /* Delete this entry from our list of open files. */
  2702. if (nc->path)
  2703. free(nc->path);
  2704. nc4_file_list_del(nc);
  2705. /* Reset the ncid numbers if there are no more files open. */
  2706. if(count_NCList() == 0)
  2707. nc4_file_list_free();
  2708. return NC_NOERR;
  2709. }
  2710. /* It's possible for any of these pointers to be NULL, in which case
  2711. don't try to figure out that value. */
  2712. int
  2713. NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
  2714. {
  2715. NC_FILE_INFO_T *nc;
  2716. NC_HDF5_FILE_INFO_T *h5;
  2717. NC_GRP_INFO_T *grp;
  2718. NC_DIM_INFO_T *dim;
  2719. NC_ATT_INFO_T *att;
  2720. NC_VAR_INFO_T *var;
  2721. int retval;
  2722. LOG((2, "nc_inq: ncid 0x%x", ncid));
  2723. /* Find file metadata. */
  2724. if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
  2725. return retval;
  2726. #ifdef USE_PNETCDF
  2727. /* Take care of files created/opened with parallel-netcdf library. */
  2728. if (nc->pnetcdf_file)
  2729. return ncmpi_inq(nc->int_ncid, ndimsp, nvarsp, nattsp, unlimdimidp);
  2730. #endif /* USE_PNETCDF */
  2731. /* Netcdf-3 files are already taken care of. */
  2732. assert(h5 && grp && nc);
  2733. /* Count the number of dims, vars, and global atts. */
  2734. if (ndimsp)
  2735. {
  2736. *ndimsp = 0;
  2737. for (dim = grp->dim; dim; dim = dim->next)
  2738. (*ndimsp)++;
  2739. }
  2740. if (nvarsp)
  2741. {
  2742. *nvarsp = 0;
  2743. for (var = grp->var; var; var= var->next)
  2744. (*nvarsp)++;
  2745. }
  2746. if (nattsp)
  2747. {
  2748. *nattsp = 0;
  2749. for (att = grp->att; att; att = att->next)
  2750. (*nattsp)++;
  2751. }
  2752. if (unlimdimidp)
  2753. {
  2754. /* Default, no unlimited dimension */
  2755. int found = 0;
  2756. *unlimdimidp = -1;
  2757. /* If there's more than one unlimited dim, which was not possible
  2758. with netcdf-3, then only the last unlimited one will be reported
  2759. back in xtendimp. */
  2760. /* Note that this code is inconsistent with nc_inq_unlimid() */
  2761. for (dim = grp->dim; dim; dim = dim->next)
  2762. if (dim->unlimited)
  2763. {
  2764. *unlimdimidp = dim->dimid;
  2765. break;
  2766. }
  2767. }
  2768. return NC_NOERR;
  2769. }
  2770. /* This function will do the enddef stuff for a netcdf-4 file. */
  2771. int
  2772. nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
  2773. {
  2774. assert(h5);
  2775. LOG((3, "nc4_enddef_netcdf4_file"));
  2776. /* If we're not in define mode, return an error. */
  2777. if (!(h5->flags & NC_INDEF))
  2778. return NC_ENOTINDEFINE;
  2779. /* Turn define mode off. */
  2780. h5->flags ^= NC_INDEF;
  2781. /* Redef mode needs to be tracked seperately for nc_abort. */
  2782. h5->redef = 0;
  2783. return sync_netcdf4_file(h5);
  2784. }
  2785. #ifdef EXTRA_TESTS
  2786. int
  2787. nc_exit()
  2788. {
  2789. if (num_plists || num_spaces)
  2790. return NC_EHDFERR;
  2791. return NC_NOERR;
  2792. }
  2793. #endif /* EXTRA_TESTS */
  2794. #ifdef USE_PARALLEL
  2795. int
  2796. nc_use_parallel_enabled()
  2797. {
  2798. return 0;
  2799. }
  2800. #endif /* USE_PARALLEL */