12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203 |
- /** \file
- The netCDF-4 file functions.
- This file is part of netcdf-4, a netCDF-like interface for HDF5, or
- a HDF5 backend for netCDF, depending on your point of view.
- Copyright 2003, University Corporation for Atmospheric Research. See
- COPYRIGHT file for copying and redistribution conditions.
- */
- #include "nc4internal.h"
- #include "nc.h"
- #include <H5DSpublic.h>
- #include "nc4dispatch.h"
- #include "ncdispatch.h"
- #ifdef USE_HDF4
- #include <mfhdf.h>
- #endif
- #ifdef USE_PNETCDF
- #include <pnetcdf.h>
- #endif
- /* This is to track opened HDF5 objects to make sure they are
- * closed. */
- #ifdef EXTRA_TESTS
- extern int num_plists;
- extern int num_spaces;
- #endif /* EXTRA_TESTS */
- #define MIN_DEFLATE_LEVEL 0
- #define MAX_DEFLATE_LEVEL 9
- /* These are the special attributes added by the HDF5 dimension scale
- * API. They will be ignored by netCDF-4. */
- #define REFERENCE_LIST "REFERENCE_LIST"
- #define CLASS "CLASS"
- #define DIMENSION_LIST "DIMENSION_LIST"
- #define NAME "NAME"
- /* Forward */
- static int NC4_enddef(int ncid);
- static int nc4_rec_read_types(NC_GRP_INFO_T *grp);
- static int nc4_rec_read_vars(NC_GRP_INFO_T *grp);
- #ifdef IGNORE
- /* This extern points to the pointer that holds the list of open
- * netCDF files. */
- extern NC_FILE_INFO_T *nc_file;
- #endif
- /* These are the default chunk cache sizes for HDF5 files created or
- * opened with netCDF-4. */
- size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE;
- size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS;
- float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION;
- /* This is set by nc_set_default_format in libsrc/nc.c. */
- extern int default_create_format;
- /* To turn off HDF5 error messages, I have to catch an early
- invocation of a netcdf function. */
- static int virgin = 1;
- /* For performance, fill this array only the first time, and keep it
- * in global memory for each further use. */
- #define NUM_TYPES 12
- static hid_t native_type_constant[NUM_TYPES];
- static char nc_type_name[NUM_TYPES][NC_MAX_NAME + 1] = {"char", "byte", "short", "int", "float",
- "double", "ubyte", "ushort", "uint",
- "int64", "uint64", "string"};
- int nc4_free_global_hdf_string_typeid();
- /* Set chunk cache size. Only affects files opened/created *after* it
- * is called. */
- int
- nc_set_chunk_cache(size_t size, size_t nelems, float preemption)
- {
- if (preemption < 0 || preemption > 1)
- return NC_EINVAL;
- nc4_chunk_cache_size = size;
- nc4_chunk_cache_nelems = nelems;
- nc4_chunk_cache_preemption = preemption;
- return NC_NOERR;
- }
- /* Get chunk cache size. Only affects files opened/created *after* it
- * is called. */
- int
- nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp)
- {
- if (sizep)
- *sizep = nc4_chunk_cache_size;
- if (nelemsp)
- *nelemsp = nc4_chunk_cache_nelems;
-
- if (preemptionp)
- *preemptionp = nc4_chunk_cache_preemption;
- return NC_NOERR;
- }
- /* Required for fortran to avoid size_t issues. */
- int
- nc_set_chunk_cache_ints(int size, int nelems, int preemption)
- {
- if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100)
- return NC_EINVAL;
- nc4_chunk_cache_size = size;
- nc4_chunk_cache_nelems = nelems;
- nc4_chunk_cache_preemption = (float)preemption / 100;
- return NC_NOERR;
- }
- int
- nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp)
- {
- if (sizep)
- *sizep = (int)nc4_chunk_cache_size;
- if (nelemsp)
- *nelemsp = (int)nc4_chunk_cache_nelems;
- if (preemptionp)
- *preemptionp = (int)(nc4_chunk_cache_preemption * 100);
- return NC_NOERR;
- }
- /* This will return the length of a netcdf data type in bytes. */
- int
- nc4typelen(nc_type type)
- {
- switch(type){
- case NC_BYTE:
- case NC_CHAR:
- case NC_UBYTE:
- return 1;
- case NC_USHORT:
- case NC_SHORT:
- return 2;
- case NC_FLOAT:
- case NC_INT:
- case NC_UINT:
- return 4;
- case NC_DOUBLE:
- case NC_INT64:
- case NC_UINT64:
- return 8;
- }
- return -1;
- }
- /* Given a filename, check to see if it is a HDF5 file. */
- #define MAGIC_NUMBER_LEN 4
- #define NC_HDF5_FILE 1
- #define NC_HDF4_FILE 2
- static int
- nc_check_for_hdf(const char *path, int use_parallel, MPI_Comm comm, MPI_Info info,
- int *hdf_file)
- {
- char blob[MAGIC_NUMBER_LEN];
-
- assert(hdf_file && path);
- LOG((3, "nc_check_for_hdf: path %s", path));
- /* Get the 4-byte blob from the beginning of the file. Don't use posix
- * for parallel, use the MPI functions instead. */
- #ifdef USE_PARALLEL
- if (use_parallel)
- {
- MPI_File fh;
- MPI_Status status;
- int retval;
- if ((retval = MPI_File_open(comm, (char *)path, MPI_MODE_RDONLY,
- info, &fh)) != MPI_SUCCESS)
- return NC_EPARINIT;
- if ((retval = MPI_File_read(fh, blob, MAGIC_NUMBER_LEN, MPI_CHAR,
- &status)) != MPI_SUCCESS)
- return NC_EPARINIT;
- if ((retval = MPI_File_close(&fh)) != MPI_SUCCESS)
- return NC_EPARINIT;
- }
- else
- #endif /* USE_PARALLEL */
- {
- FILE *fp;
- if (!(fp = fopen(path, "r")) ||
- fread(blob, MAGIC_NUMBER_LEN, 1, fp) != 1)
- return errno;
- fclose(fp);
- }
- /* Ignore the first byte for HDF5. */
- if (blob[1] == 'H' && blob[2] == 'D' && blob[3] == 'F')
- *hdf_file = NC_HDF5_FILE;
- else if (!strncmp(blob, "\016\003\023\001", MAGIC_NUMBER_LEN))
- *hdf_file = NC_HDF4_FILE;
- else
- *hdf_file = 0;
- return NC_NOERR;
- }
-
- /* Create a HDF5/netcdf-4 file. In this case, ncid has already been
- * selected in ncfunc.c. */
- static int
- nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info,
- NC_FILE_INFO_T *nc)
- {
- hid_t fcpl_id, fapl_id;
- unsigned flags;
- FILE *fp;
- int retval = NC_NOERR;
- int persist = 0; /* Should diskless try to persist its data into file?*/
- if(cmode & NC_DISKLESS)
- flags = H5F_ACC_TRUNC;
- else if(cmode & NC_NOCLOBBER)
- flags = H5F_ACC_EXCL;
- else
- flags = H5F_ACC_TRUNC;
- LOG((3, "nc4_create_file: path %s mode 0x%x", path, cmode));
- assert(nc && path);
- /* If this file already exists, and NC_NOCLOBBER is specified,
- return an error. */
- if (cmode & NC_DISKLESS) {
- if(cmode & NC_WRITE)
- persist = 1;
- } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) {
- fclose(fp);
- return NC_EEXIST;
- }
-
- /* Add necessary structs to hold netcdf-4 file data. */
- if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode))))
- BAIL(retval);
- assert(nc->nc4_info && nc->nc4_info->root_grp);
- /* Need this access plist to control how HDF5 handles open onjects
- * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
- * fail if there are any open objects in the file. */
- if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists++;
- #endif
- #ifdef EXTRA_TESTS
- if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
- BAIL(NC_EHDFERR);
- #else
- if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG))
- BAIL(NC_EHDFERR);
- #endif /* EXTRA_TESTS */
- #ifdef USE_PARALLEL
- /* If this is a parallel file create, set up the file creation
- property list. */
- if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX))
- {
- nc->nc4_info->parallel++;
- if (cmode & NC_MPIIO) /* MPI/IO */
- {
- LOG((4, "creating parallel file with MPI/IO"));
- if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
- BAIL(NC_EPARINIT);
- }
- else /* MPI/POSIX */
- {
- LOG((4, "creating parallel file with MPI/posix"));
- if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
- BAIL(NC_EPARINIT);
- }
- }
- #else /* only set cache for non-parallel... */
- if(cmode & NC_DISKLESS) {
- if (H5Pset_fapl_core(fapl_id, 4096, persist))
- BAIL(NC_EDISKLESS);
- }
- if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
- nc4_chunk_cache_preemption) < 0)
- BAIL(NC_EHDFERR);
- LOG((4, "nc4_create_file: set HDF raw chunk cache to size %d nelems %d preemption %f",
- nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption));
- #endif /* USE_PARALLEL */
-
- if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_18, H5F_LIBVER_18) < 0)
- BAIL(NC_EHDFERR);
- /* Create the property list. */
- if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists++;
- #endif
- /* Set latest_format in access propertly list and
- * H5P_CRT_ORDER_TRACKED in the creation property list. This turns
- * on HDF5 creation ordering. */
- if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
- H5P_CRT_ORDER_INDEXED)) < 0)
- BAIL(NC_EHDFERR);
- if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED |
- H5P_CRT_ORDER_INDEXED)) < 0)
- BAIL(NC_EHDFERR);
- /* Create the file. */
- if ((nc->nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0)
- BAIL(NC_EFILEMETA);
- /* Open the root group. */
- if ((nc->nc4_info->root_grp->hdf_grpid = H5Gopen2(nc->nc4_info->hdfid, "/",
- H5P_DEFAULT)) < 0)
- BAIL(NC_EFILEMETA);
- /* Release the property lists. */
- if (H5Pclose(fapl_id) < 0 ||
- H5Pclose(fcpl_id) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists--;
- num_plists--;
- #endif
- /* Define mode gets turned on automatically on create. */
- nc->nc4_info->flags |= NC_INDEF;
- return NC_NOERR;
- exit:
- if (nc->nc4_info->hdfid > 0) H5Fclose(nc->nc4_info->hdfid);
- return retval;
- }
- /** \ingroup netcdf4
- Create a netCDF-4/HDF5 file.
- \param path The file name of the new file.
- \param cmode The creation mode flag.
- \param initialsz Ignored by this function.
- \param basepe Ignored by this function.
- \param chunksizehintp Ignored by this function.
- \param use_parallel 0 for sequential, non-zero for parallel I/O.
- \param mpidata pointer to struct holdind data for parallel I/O
- layer. Ignored if NULL.
- \param dispatch Pointer to the dispatch table for this file.
- \param ncpp Pointer to start of linked list of open files.
- \return NC_INVAL Invalid input (check cmode).
- */
- int
- NC4_create(const char* path, int cmode, size_t initialsz, int basepe,
- size_t *chunksizehintp, int use_parallel, void *mpidata,
- NC_Dispatch *dispatch, NC **ncpp)
- {
- NC_FILE_INFO_T *nc_file = NULL;
- #ifdef USE_PARALLEL
- MPI_Comm comm = 0;
- MPI_Info info = 0;
- #else
- int comm = 0, info = 0;
- #endif /* USE_PARALLEL */
- int res;
- assert(ncpp && path);
- LOG((1, "nc4_create_file: path %s cmode 0x%x comm %d info %d",
- path, cmode, comm, info));
-
- #ifdef USE_PARALLEL
- if (mpidata)
- {
- comm = ((NC_MPI_INFO *)mpidata)->comm;
- info = ((NC_MPI_INFO *)mpidata)->info;
- }
- #endif /* USE_PARALLEL */
- /* If this is our first file, turn off HDF5 error messages. */
- if (virgin)
- {
- if (H5Eset_auto(NULL, NULL) < 0)
- LOG((0, "Couldn't turn off HDF5 error messages!"));
- LOG((1, "HDF5 error messages have been turned off."));
- virgin = 0;
- }
- /* Check the cmode for validity. */
- if (cmode & ~(NC_NOCLOBBER | NC_64BIT_OFFSET
- | NC_NETCDF4 | NC_CLASSIC_MODEL
- | NC_SHARE | NC_MPIIO | NC_MPIPOSIX | NC_LOCK | NC_PNETCDF
- | NC_DISKLESS
- | NC_WRITE /* to support diskless persistence */
- )
- || (cmode & NC_MPIIO && cmode & NC_MPIPOSIX)
- || (cmode & NC_64BIT_OFFSET && cmode & NC_NETCDF4)
- || (cmode & (NC_MPIIO | NC_MPIPOSIX) && cmode & NC_DISKLESS)
- )
- return NC_EINVAL;
- /* Allocate the storage for this file info struct, and fill it with
- zeros. This add the file metadata to the front of the global
- nc_file list. */
- if ((res = nc4_file_list_add(&nc_file, dispatch)))
- return res;
- /* Apply default create format. */
- if (default_create_format == NC_FORMAT_64BIT)
- cmode |= NC_64BIT_OFFSET;
- else if (default_create_format == NC_FORMAT_NETCDF4)
- cmode |= NC_NETCDF4;
- else if (default_create_format == NC_FORMAT_NETCDF4_CLASSIC)
- {
- cmode |= NC_NETCDF4;
- cmode |= NC_CLASSIC_MODEL;
- }
- LOG((2, "cmode after applying default format: 0x%x", cmode));
- /* Check to see if we want a netcdf3 or netcdf4 file. Open it, and
- call the appropriate nc*_create. */
- if (cmode & NC_NETCDF4)
- {
- nc_file->int_ncid = nc_file->ext_ncid;
- res = nc4_create_file(path, cmode, comm, info, nc_file);
- }
- #ifdef USE_PNETCDF
- else if (cmode & NC_PNETCDF)
- {
- nc_file->pnetcdf_file++;
- res = ncmpi_create(comm, path, cmode, info, &(nc_file->int_ncid));
- }
- #endif /* USE_PNETCDF */
- else
- {
- return NC_EINVAL;
- }
-
- /* Delete this file list entry if there was a failure. */
- if (res)
- {
- if (nc_file)
- nc4_file_list_del(nc_file);
- }
- else
- *ncpp = (NC *)nc_file;
- return res;
- }
- /* This function is called by read_dataset when a dimension scale
- * dataset is encountered. It reads in the dimension data (creating a
- * new NC_DIM_INFO_T object), and also checks to see if this is a
- * dimension without a variable - that is, a coordinate dimension
- * which does not have any coordinate data. */
- static int
- read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, char *obj_name,
- hsize_t scale_size, hsize_t max_scale_size,
- int *dim_without_var)
- {
- /*char *start_of_len;*/
- char dimscale_name_att[NC_MAX_NAME + 1] = "";
- hid_t attid = 0;
- int max_len;
- int retval;
- /* Add a dimension for this scale. */
- if ((retval = nc4_dim_list_add(&grp->dim)))
- return retval;
- /* Assign dimid and increment number of dimensions. */
- grp->dim->dimid = grp->file->nc4_info->next_dimid++;
- grp->ndims++;
- /* Does this dataset have a hidden attribute that tells us its
- * dimid? If so, read it. */
- H5E_BEGIN_TRY {
- if ((attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME,
- H5P_DEFAULT, H5P_DEFAULT)) > 0)
- {
- if (H5Aread(attid, H5T_NATIVE_INT, &grp->dim->dimid) < 0)
- return NC_EHDFERR;
- if (H5Aclose(attid) < 0)
- return NC_EHDFERR;
- }
- } H5E_END_TRY;
- max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
- if (!(grp->dim->name = malloc((max_len + 1) * sizeof(char))))
- return NC_ENOMEM;
- strncpy(grp->dim->name, obj_name, max_len + 1);
- if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT)
- {
- grp->dim->len = NC_MAX_UINT;
- grp->dim->too_long = 1;
- }
- else
- grp->dim->len = scale_size;
- grp->dim->hdf_dimscaleid = datasetid;
- /* If the dimscale has an unlimited dimension, then this dimension
- * is unlimited. */
- if (max_scale_size == H5S_UNLIMITED)
- grp->dim->unlimited++;
- /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a
- * dimension, but not a variable. (If get_scale_name returns an
- * error, just move on, there's no NAME.) */
- if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0)
- {
- if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE,
- strlen(DIM_WITHOUT_VARIABLE)))
- {
- if (grp->dim->unlimited)
- {
- size_t len = 0, *lenp = &len;
- if ((retval = nc4_find_dim_len(grp, grp->dim->dimid, &lenp)))
- return retval;
- grp->dim->len = *lenp;
- }
- (*dim_without_var)++;
- }
- }
- return NC_NOERR;
- }
- /* This function reads the hacked in coordinates attribute I use for
- * multi-dimensional coordinates. */
- static int
- read_coord_dimids(NC_VAR_INFO_T *var)
- {
- hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1;
- hssize_t coord_array_size;
- int ret = 0;
- /* There is a hidden attribute telling us the ids of the
- * dimensions that apply to this multi-dimensional coordinate
- * variable. Read it. */
- if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++;
- if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++;
- if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++;
- LOG((4, "dimscale %s is multidimensional and has coords", var->name));
- /* How many dimensions are there? */
- if ((spaceid = H5Aget_space(coord_attid)) < 0) ret++;
- #ifdef EXTRA_TESTS
- num_spaces++;
- #endif
- if ((coord_array_size = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++;
-
- /* Malloc space to the array of pointers to dims. */
-
- /* Set my HDF5 IDs free! */
- if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++;
- #ifdef EXTRA_TESTS
- num_spaces--;
- #endif
- if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++;
- if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++;
- return ret ? NC_EATTMETA : NC_NOERR;
- }
- /* This function is called when reading a file's metadata for each
- * dimension scale attached to a variable.*/
- static herr_t
- dimscale_visitor(hid_t did, unsigned dim, hid_t dsid,
- void *dimscale_hdf5_objids)
- {
- H5G_stat_t statbuf;
- /* Get more info on the dimscale object.*/
- if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0)
- return -1;
- /* Pass this information back to caller. */
- /* (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno = statbuf.fileno;
- (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno = statbuf.objno;*/
- (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0];
- (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1];
- (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0];
- (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1];
- return 0;
- }
- /* Given an HDF5 type, set a pointer to netcdf type. */
- static int
- get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid,
- nc_type *xtype)
- {
- NC_TYPE_INFO_T *type;
- hid_t class;
- htri_t is_str, equal = 0;
- assert(h5 && xtype);
- if ((class = H5Tget_class(native_typeid)) < 0)
- return NC_EHDFERR;
- /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
- * H5Tget_class will return H5T_STRING if this is a string. */
- if (class == H5T_STRING)
- {
- if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
- return NC_EHDFERR;
- if (is_str)
- *xtype = NC_STRING;
- else
- *xtype = NC_CHAR;
- return NC_NOERR;
- }
- else if (class == H5T_INTEGER || class == H5T_FLOAT)
- {
- /* For integers and floats, we don't have to worry about
- * endianness if we compare native types. */
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_BYTE;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_SHORT;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_INT;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_FLOAT;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_DOUBLE;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_UBYTE;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_USHORT;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_UINT;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_INT64;
- return NC_NOERR;
- }
- if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- *xtype = NC_UINT64;
- return NC_NOERR;
- }
- }
- /* Maybe we already know about this type. */
- if (!equal)
- if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
- {
- *xtype = type->nc_typeid;
- return NC_NOERR;
- }
-
- *xtype = NC_NAT;
- return NC_EBADTYPID;
- }
- /* Given an HDF5 type, set a pointer to netcdf type_info struct,
- * either an existing one (for user-defined types) or a newly created
- * one. */
- static int
- get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid,
- nc_type *xtype, NC_TYPE_INFO_T **type_info)
- {
- NC_TYPE_INFO_T *type;
- htri_t is_str, equal = 0;
- hid_t class, native_typeid, hdf_typeid;
- #if 0
- nc_type my_nc_type = 0;
- #endif
- H5T_order_t order;
- int endianness;
- nc_type nc_type_constant[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT, NC_INT, NC_FLOAT,
- NC_DOUBLE, NC_UBYTE, NC_USHORT, NC_UINT,
- NC_INT64, NC_UINT64, NC_STRING};
- int type_size[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short),
- sizeof(int), sizeof(float), sizeof(double),
- sizeof(unsigned char), sizeof(unsigned short),
- sizeof(unsigned int), sizeof(long long),
- sizeof(unsigned long long), 0};
- int t;
- assert(h5 && xtype && type_info);
- /* Because these N5T_NATIVE_* constants are actually function calls
- * (!) in H5Tpublic.h, I can't initialize this array in the usual
- * way, because at least some C compilers (like Irix) complain
- * about calling functions when defining constants. So I have to do
- * it like this. Note that there's no native types for char or
- * string. Those are handled later. */
- if (!native_type_constant[1])
- {
- native_type_constant[1] = H5T_NATIVE_SCHAR;
- native_type_constant[2] = H5T_NATIVE_SHORT;
- native_type_constant[3] = H5T_NATIVE_INT;
- native_type_constant[4] = H5T_NATIVE_FLOAT;
- native_type_constant[5] = H5T_NATIVE_DOUBLE;
- native_type_constant[6] = H5T_NATIVE_UCHAR;
- native_type_constant[7] = H5T_NATIVE_USHORT;
- native_type_constant[8] = H5T_NATIVE_UINT;
- native_type_constant[9] = H5T_NATIVE_LLONG;
- native_type_constant[10] = H5T_NATIVE_ULLONG;
- }
-
- /* Get the HDF5 typeid - we'll need it later. */
- if ((hdf_typeid = H5Dget_type(datasetid)) < 0)
- return NC_EHDFERR;
- /* Get the native typeid. Will be equivalent to hdf_typeid when
- * creating but not necessarily when reading, a variable. */
- if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
- return NC_EHDFERR;
- /* Is this type an integer, string, compound, or what? */
- if ((class = H5Tget_class(native_typeid)) < 0)
- return NC_EHDFERR;
- /* Is this an atomic type? */
- if (class == H5T_STRING || class == H5T_INTEGER || class == H5T_FLOAT)
- {
- /* Allocate a phony NC_TYPE_INFO_T struct to hold type info. */
- if (!(*type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
- return NC_ENOMEM;
- (*type_info)->class = class;
- /* H5Tequal doesn't work with H5T_C_S1 for some reason. But
- * H5Tget_class will return H5T_STRING if this is a string. */
- if (class == H5T_STRING)
- {
- if ((is_str = H5Tis_variable_str(native_typeid)) < 0)
- return NC_EHDFERR;
- /* Make sure fixed-len strings will work like variable-len strings */
- if (is_str || H5Tget_size(hdf_typeid) > 1)
- t = NUM_TYPES - 1;
- else
- t = 0;
- }
- else if (class == H5T_INTEGER || class == H5T_FLOAT)
- {
- for (t = 1; t < NUM_TYPES - 1; t++)
- {
- if ((equal = H5Tequal(native_typeid, native_type_constant[t])) < 0)
- return NC_EHDFERR;
- if (equal)
- {
- #if 0
- my_nc_type = nc_type_constant[t];
- #endif
- break;
- }
- }
- /* Find out about endianness. */
- if (class == H5T_INTEGER)
- {
- if ((order = H5Tget_order(hdf_typeid)) < 0)
- return NC_EHDFERR;
- if (order == H5T_ORDER_LE)
- endianness = NC_ENDIAN_LITTLE;
- else if (order == H5T_ORDER_BE)
- endianness = NC_ENDIAN_BIG;
- else /* don't support H5T_ORDER_VAX, H5T_ORDER_MIXED, H5T_ORDER_NONE */
- return NC_EBADTYPE;
- /* Copy this into the type_info struct. */
- (*type_info)->endianness = endianness;
- }
- }
- *xtype = nc_type_constant[t];
- (*type_info)->nc_typeid = nc_type_constant[t];
- (*type_info)->size = type_size[t];
- if (!((*type_info)->name = malloc((strlen(nc_type_name[t]) + 1) * sizeof(char))))
- return NC_ENOMEM;
- strcpy((*type_info)->name, nc_type_name[t]);
- (*type_info)->class = class;
- (*type_info)->hdf_typeid = hdf_typeid;
- (*type_info)->native_typeid = native_typeid;
- (*type_info)->close_hdf_typeid = 1;
- return NC_NOERR;
- }
- else
- {
- /* This is a user-defined type. */
- if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid)))
- {
- *xtype = type->nc_typeid;
- *type_info = type;
- }
- /* The type entry in the array of user-defined types already has
- * an open data typeid (and native typeid), so close the ones we
- * opened above. */
- if (H5Tclose(native_typeid) < 0)
- return NC_EHDFERR;
- if (H5Tclose(hdf_typeid) < 0)
- return NC_EHDFERR;
- if (type)
- return NC_NOERR;
- }
- *xtype = NC_NAT;
- return NC_EBADTYPID;
- }
- /* Read an attribute. */
- static int
- read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att)
- {
- hid_t spaceid = 0, file_typeid = 0;
- hsize_t dims[1]; /* netcdf attributes always 1-D. */
- int retval = NC_NOERR;
- size_t type_size;
- int att_ndims;
- hssize_t att_npoints;
- H5T_class_t att_class;
- int fixed_len_string = 0;
- size_t fixed_size = 0;
- assert(att->name);
- LOG((5, "read_hdf5_att: att->attnum %d att->name %s "
- "att->xtype %d att->len %d", att->attnum, att->name,
- att->xtype, att->len));
- /* Get type of attribute in file. */
- if ((file_typeid = H5Aget_type(attid)) < 0)
- return NC_EATTMETA;
- if ((att->native_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0)
- BAIL(NC_EHDFERR);
- if ((att_class = H5Tget_class(att->native_typeid)) < 0)
- BAIL(NC_EATTMETA);
- if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_typeid))
- {
- fixed_len_string++;
- if (!(fixed_size = H5Tget_size(att->native_typeid)))
- BAIL(NC_EATTMETA);
- }
- if ((retval = get_netcdf_type(grp->file->nc4_info, att->native_typeid, &(att->xtype))))
- BAIL(retval);
- /* Get len. */
- if ((spaceid = H5Aget_space(attid)) < 0)
- BAIL(NC_EATTMETA);
- #ifdef EXTRA_TESTS
- num_spaces++;
- #endif
- if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
- BAIL(NC_EATTMETA);
- if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0)
- BAIL(NC_EATTMETA);
- /* If both att_ndims and att_npoints are zero, then this is a
- * zero length att. */
- if (att_ndims == 0 && att_npoints == 0)
- {
- dims[0] = 0;
- }
- else if (att->xtype == NC_STRING) {
- dims[0] = att_npoints;
- }
- else if (att->xtype == NC_CHAR)
- {
- /* NC_CHAR attributes are written as a scalar in HDF5, of type
- * H5T_C_S1, of variable length. */
- if (att_ndims == 0)
- {
- if (!(dims[0] = H5Tget_size(file_typeid)))
- BAIL(NC_EATTMETA);
- }
- else
- {
- /* This is really a string type! */
- att->xtype = NC_STRING;
- dims[0] = att_npoints;
- }
- }
- else
- {
- /* All netcdf attributes are scalar or 1-D only. */
- if (att_ndims > 1)
- BAIL(NC_EATTMETA);
- /* Read the size of this attribute. */
- if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0)
- BAIL(NC_EATTMETA);
- }
-
- /* Tell the user what the length if this attribute is. */
- att->len = dims[0];
- /* Allocate some memory if the len is not zero, and read the
- attribute. */
- if (dims[0])
- {
- if ((retval = nc4_get_typelen_mem(grp->file->nc4_info, att->xtype, 0,
- &type_size)))
- return retval;
- if (att_class == H5T_VLEN)
- {
- if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t)))))
- BAIL(NC_ENOMEM);
- if (H5Aread(attid, att->native_typeid, att->vldata) < 0)
- BAIL(NC_EATTMETA);
- }
- else if (att->xtype == NC_STRING)
- {
- if (!(att->stdata = calloc(att->len, sizeof(char *))))
- BAIL(NC_ENOMEM);
- /* For a fixed length HDF5 string, the read requires
- * contiguous memory. Meanwhile, the netCDF API requires that
- * nc_free_string be called on string arrays, which would not
- * work if one contiguous memory block were used. So here I
- * convert the contiguous block of strings into an array of
- * malloced strings (each string with its own malloc). Then I
- * copy the data and free the contiguous memory. This
- * involves copying the data, which is bad, but this only
- * occurs for fixed length string attributes, and presumably
- * these are small. (And netCDF-4 does not create them - it
- * always uses variable length strings. */
- if (fixed_len_string)
- {
- int i;
- char *contig_buf, *cur;
- /* Alloc space for the contiguous memory read. */
- if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char))))
- BAIL(NC_ENOMEM);
- /* Read the fixed-len strings as one big block. */
- if (H5Aread(attid, att->native_typeid, contig_buf) < 0)
- BAIL(NC_EATTMETA);
-
- /* Copy strings, one at a time, into their new home. Alloc
- space for each string. The user will later free this
- space with nc_free_string. */
- cur = contig_buf;
- for (i = 0; i < att->len; i++)
- {
- if (!(att->stdata[i] = malloc(fixed_size)))
- BAIL(NC_ENOMEM);
- strncpy(att->stdata[i], cur, fixed_size);
- cur += fixed_size;
- }
-
- /* Free contiguous memory buffer. */
- free(contig_buf);
- }
- else
- {
- /* Read variable-length string atts. */
- if (H5Aread(attid, att->native_typeid, att->stdata) < 0)
- BAIL(NC_EATTMETA);
- }
- }
- else
- {
- if (!(att->data = malloc((unsigned int)(att->len * type_size))))
- BAIL(NC_ENOMEM);
- if (H5Aread(attid, att->native_typeid, att->data) < 0)
- BAIL(NC_EATTMETA);
- }
- }
- if (H5Tclose(file_typeid) < 0)
- BAIL(NC_EHDFERR);
- if (H5Sclose(spaceid) < 0)
- return NC_EHDFERR;
- #ifdef EXTRA_TESTS
- num_spaces--;
- #endif
-
- return NC_NOERR;
- exit:
- if (H5Tclose(file_typeid) < 0)
- BAIL2(NC_EHDFERR);
- if (spaceid > 0 && H5Sclose(spaceid) < 0)
- BAIL2(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_spaces--;
- #endif
- return retval;
- }
- /* Read information about a user defined type from the HDF5 file, and
- * stash it in the group's list of types. Return the netcdf typeid
- * through a pointer, if caller desires it. */
- static int
- read_type(NC_GRP_INFO_T *grp, char *type_name)
- {
- NC_TYPE_INFO_T *type;
- H5T_class_t class;
- hid_t hdf_typeid, native_typeid = 0;
- int nmembers;
- hid_t member_hdf_typeid, base_hdf_typeid = 0;
- char *member_name = NULL;
- size_t type_size = 0, member_offset;
- unsigned int m;
- nc_type ud_type_type = NC_NAT, base_nc_type = NC_NAT, member_xtype;
- htri_t ret;
- int retval = NC_NOERR;
- void *value;
- int i;
- assert(grp && type_name);
- if (strlen(type_name) > NC_MAX_NAME)
- return NC_EBADNAME;
- LOG((4, "read_type: type_name %s grp->name %s", type_name, grp->name));
- if ((hdf_typeid = H5Topen2(grp->hdf_grpid, type_name, H5P_DEFAULT)) < 0)
- return NC_EHDFERR;
- /* What is the native type for this platform? */
- if ((native_typeid = H5Tget_native_type(hdf_typeid, H5T_DIR_DEFAULT)) < 0)
- return NC_EHDFERR;
-
- /* What is the size of this type on this platform. */
- if (!(type_size = H5Tget_size(native_typeid)))
- return NC_EHDFERR;
- LOG((5, "type_size %d", type_size));
- /* What is the class of this type, compound, vlen, etc. */
- if ((class = H5Tget_class(hdf_typeid)) < 0)
- return NC_EHDFERR;
- switch (class)
- {
- case H5T_STRING:
- ud_type_type = NC_STRING;
- break;
- case H5T_COMPOUND:
- ud_type_type = NC_COMPOUND;
- break;
- case H5T_VLEN:
- /* For conveninence we allow user to pass vlens of strings
- * with null terminated strings. This means strings are
- * treated slightly differently by the API, although they are
- * really just VLENs of characters. */
- if ((ret = H5Tis_variable_str(hdf_typeid)) < 0)
- return NC_EHDFERR;
- if (ret)
- ud_type_type = NC_STRING;
- else
- {
- ud_type_type = NC_VLEN;
- /* Find the base type of this vlen (i.e. what is this a
- * vlen of?) */
- if (!(base_hdf_typeid = H5Tget_super(native_typeid)))
- return NC_EHDFERR;
- /* What size is this type? */
- if (!(type_size = H5Tget_size(base_hdf_typeid)))
- return NC_EHDFERR;
- /* What is the netcdf corresponding type. */
- if ((retval = get_netcdf_type(grp->file->nc4_info, base_hdf_typeid,
- &base_nc_type)))
- return retval;
- LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
- base_hdf_typeid, type_size, base_nc_type));
- }
- break;
- case H5T_OPAQUE:
- ud_type_type = NC_OPAQUE;
- /* What size is this type? */
- if (!(type_size = H5Tget_size(hdf_typeid)))
- return NC_EHDFERR;
- LOG((5, "type_size %d", type_size));
- break;
- case H5T_ENUM:
- ud_type_type = NC_ENUM;
- /* Find the base type of this enum (i.e. what is this a
- * enum of?) */
- if (!(base_hdf_typeid = H5Tget_super(hdf_typeid)))
- return NC_EHDFERR;
- /* What size is this type? */
- if (!(type_size = H5Tget_size(base_hdf_typeid)))
- return NC_EHDFERR;
- /* What is the netcdf corresponding type. */
- if ((retval = get_netcdf_type(grp->file->nc4_info, base_hdf_typeid,
- &base_nc_type)))
- return retval;
- LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d",
- base_hdf_typeid, type_size, base_nc_type));
- break;
- default:
- LOG((0, "unknown class"));
- return NC_EBADCLASS;
- }
- /* Add to the list for this new type, and get a local pointer to it. */
- if ((retval = nc4_type_list_add(&grp->type, &type)))
- return retval;
- assert(type);
- /* Remember info about this type. */
- type->nc_typeid = grp->file->nc4_info->next_typeid++;
- type->size = type_size;
- if (!(type->name = malloc((strlen(type_name) + 1) * sizeof(char))))
- return NC_ENOMEM;
- strcpy(type->name, type_name);
- type->class = ud_type_type;
- type->base_nc_type = base_nc_type;
- type->committed++;
- type->hdf_typeid = hdf_typeid;
- type->native_typeid = native_typeid;
- /* Read info about each member of this compound type. */
- if (ud_type_type == NC_COMPOUND)
- {
- if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0)
- return NC_EHDFERR;
- LOG((5, "compound type has %d members", nmembers));
- for (m = 0; m < nmembers; m++)
- {
- H5T_class_t mem_class;
- hid_t member_native_typeid;
- int ndims = 0, dim_size[NC_MAX_VAR_DIMS];
- hsize_t dims[NC_MAX_VAR_DIMS];
- int d;
- /* Get the typeid and native typeid of this member of the
- * compound type. */
- if ((member_hdf_typeid = H5Tget_member_type(type->native_typeid, m)) < 0)
- return NC_EHDFERR;
- if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0)
- return NC_EHDFERR;
- /* Get the name of the member.*/
- member_name = H5Tget_member_name(type->native_typeid, m);
- if (!member_name || strlen(member_name) > NC_MAX_NAME)
- return NC_EBADNAME;
- /* Offset in bytes on *this* platform. */
- member_offset = H5Tget_member_offset(type->native_typeid, m);
- /* Get dimensional data if this member is an array of something. */
- if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0)
- return NC_EHDFERR;
- if (mem_class == H5T_ARRAY)
- {
- if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0)
- return NC_EHDFERR;
- if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims)
- return NC_EHDFERR;
- for (d = 0; d < ndims; d++)
- dim_size[d] = dims[d];
- /* What is the netCDF typeid of this member? */
- if ((retval = get_netcdf_type(grp->file->nc4_info, H5Tget_super(member_hdf_typeid),
- &member_xtype)))
- return retval;
- }
- else
- {
- /* What is the netCDF typeid of this member? */
- if ((retval = get_netcdf_type(grp->file->nc4_info, member_native_typeid,
- &member_xtype)))
- return retval;
- }
- /* Add this member to our list of fields in this compound type. */
- if (ndims)
- {
- if ((retval = nc4_field_list_add(&type->field, type->num_fields++, member_name,
- member_offset, H5Tget_super(member_hdf_typeid),
- H5Tget_super(member_native_typeid),
- member_xtype, ndims, dim_size)))
- return retval;
- }
- else
- {
- if ((retval = nc4_field_list_add(&type->field, type->num_fields++, member_name,
- member_offset, member_hdf_typeid, member_native_typeid,
- member_xtype, 0, NULL)))
- return retval;
- }
-
- /* HDF5 allocated this for us. */
- free(member_name);
- }
- }
- else if (ud_type_type == NC_VLEN)
- {
- type->base_hdf_typeid = base_hdf_typeid;
- }
- else if (ud_type_type == NC_ENUM)
- {
- /* Remember the base HDF5 type for this enum. */
- type->base_hdf_typeid = base_hdf_typeid;
- /* Find out how many member are in the enum. */
- if ((type->num_enum_members = H5Tget_nmembers(hdf_typeid)) < 0)
- return NC_EHDFERR;
- /* Allocate space for one value. */
- if (!(value = calloc(1, type_size)))
- return NC_ENOMEM;
- /* Read each name and value defined in the enum. */
- for (i = 0; i < type->num_enum_members; i++)
- {
- /* Get the name and value from HDF5. */
- if (!(member_name = H5Tget_member_name(hdf_typeid, i)))
- return NC_EHDFERR;
- if (!member_name || strlen(member_name) > NC_MAX_NAME)
- return NC_EBADNAME;
- if (H5Tget_member_value(hdf_typeid, i, value) < 0)
- return NC_EHDFERR;
- /* Insert new field into this type's list of fields. */
- if ((retval = nc4_enum_member_add(&type->enum_member, type->size,
- member_name, value)))
- return retval;
- free(member_name);
- }
-
- /* Free the tempory memory for one value, and the member name
- * (which HDF5 allocated for us). */
- free(value);
- }
-
- return retval;
- }
- /* This function is called by read_dataset, (which is called by
- * nc4_rec_read_metadata) when a netCDF variable is found in the
- * file. This function reads in all the metadata about the var,
- * including the attributes. */
- static int
- read_var(NC_GRP_INFO_T *grp, hid_t datasetid, char *obj_name,
- size_t ndims, int is_scale, int num_scales, hid_t access_pid)
- {
- NC_VAR_INFO_T *var;
- int natts, a, d;
- NC_ATT_INFO_T *att;
- hid_t attid = 0;
- char att_name[NC_MAX_HDF5_NAME + 1];
- #define CD_NELEMS_ZLIB 1
- #define CD_NELEMS_SZIP 4
- H5Z_filter_t filter;
- int num_filters;
- unsigned int cd_values[CD_NELEMS_SZIP];
- size_t cd_nelems = CD_NELEMS_SZIP;
- hid_t propid = 0;
- H5D_fill_value_t fill_status;
- H5D_layout_t layout;
- hsize_t chunksize[NC_MAX_VAR_DIMS];
- int retval = NC_NOERR;
- double rdcc_w0;
- int f;
- assert(obj_name && grp);
- LOG((4, "read_var: obj_name %s", obj_name));
- /* Add a variable to the end of the group's var list. */
- if ((retval = nc4_var_list_add(&grp->var, &var)))
- return retval;
-
- /* Fill in what we already know. */
- var->hdf_datasetid = datasetid;
- var->varid = grp->nvars++;
- var->created++;
- var->ndims = ndims;
- /* We need some room to store information about dimensions for this
- * var. */
- if (var->ndims)
- {
- if (!(var->dim = calloc(var->ndims, sizeof(NC_DIM_INFO_T *))))
- return NC_ENOMEM;
- if (!(var->dimids = calloc(var->ndims, sizeof(int))))
- return NC_ENOMEM;
- }
- /* Learn about current chunk cache settings. */
- if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems),
- &(var->chunk_cache_size), &rdcc_w0)) < 0)
- return NC_EHDFERR;
- var->chunk_cache_preemption = rdcc_w0;
- /* Allocate space for the name. */
- if (!(var->name = malloc((strlen(obj_name) + 1) * sizeof(char))))
- return NC_ENOMEM;
- /* Check for a weird case: a non-coordinate (and non-scalar)
- * variable that has the same name as a dimension. It's legal in
- * netcdf, and requires that the HDF5 dataset name be changed. */
- if (var->ndims &&
- !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)))
- {
- if (strlen(obj_name) > NC_MAX_NAME)
- return NC_EMAXNAME;
- strcpy(var->name, &obj_name[strlen(NON_COORD_PREPEND)]);
- }
- else
- strcpy(var->name, obj_name);
- /* Find out what filters are applied to this HDF5 dataset,
- * fletcher32, deflate, and/or shuffle. All other filters are
- * ignored. */
- if ((propid = H5Dget_create_plist(datasetid)) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists++;
- #endif /* EXTRA_TESTS */
- /* Get the chunking info for non-scalar vars. */
- if ((layout = H5Pget_layout(propid)) < -1)
- BAIL(NC_EHDFERR);
- if (layout == H5D_CHUNKED)
- {
- if (H5Pget_chunk(propid, NC_MAX_VAR_DIMS, chunksize) < 0)
- BAIL(NC_EHDFERR);
- if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t))))
- BAIL(NC_ENOMEM);
- for (d = 0; d < var->ndims; d++)
- var->chunksizes[d] = chunksize[d];
- }
- else if (layout == H5D_CONTIGUOUS)
- var->contiguous++;
- /* The possible values of filter (which is just an int) can be
- * found in H5Zpublic.h. */
- if ((num_filters = H5Pget_nfilters(propid)) < 0)
- BAIL(NC_EHDFERR);
- for (f = 0; f < num_filters; f++)
- {
- if ((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems,
- cd_values, 0, NULL, NULL)) < 0)
- BAIL(NC_EHDFERR);
- switch (filter)
- {
- case H5Z_FILTER_SHUFFLE:
- var->shuffle = 1;
- break;
- case H5Z_FILTER_FLETCHER32:
- var->fletcher32 = 1;
- break;
- case H5Z_FILTER_DEFLATE:
- var->deflate++;
- if (cd_nelems != CD_NELEMS_ZLIB ||
- cd_values[0] > MAX_DEFLATE_LEVEL)
- BAIL(NC_EHDFERR);
- var->deflate_level = cd_values[0];
- break;
- case H5Z_FILTER_SZIP:
- var->deflate++;
- if (cd_nelems != CD_NELEMS_SZIP)
- BAIL(NC_EHDFERR);
- var->options_mask = cd_values[0];
- var->pixels_per_block = cd_values[1];
- break;
- default:
- LOG((1, "Yikes! Unknown filter type found on dataset!"));
- break;
- }
- }
-
- /* Learn all about the type of this variable. */
- if ((retval = get_type_info2(grp->file->nc4_info, datasetid,
- &var->xtype, &var->type_info)))
- BAIL(retval);
- /* Is there a fill value associated with this dataset? */
- if (H5Pfill_value_defined(propid, &fill_status) < 0)
- BAIL(NC_EHDFERR);
- /* Get the fill value, if there is one defined. */
- if (fill_status == H5D_FILL_VALUE_USER_DEFINED)
- {
- /* Allocate space to hold the fill value. */
- if (!var->fill_value)
- {
- if (var->type_info->class == NC_VLEN)
- {
- if (!(var->fill_value = malloc(sizeof(nc_vlen_t))))
- BAIL(NC_ENOMEM);
- }
- else if (var->type_info->size)
- {
- if (!(var->fill_value = malloc(var->type_info->size)))
- BAIL(NC_ENOMEM);
- }
- else
- {
- if (!(var->fill_value = malloc(sizeof(char *))))
- BAIL(NC_ENOMEM);
- }
- }
-
- /* Get the fill value from the HDF5 property lust. */
- if (H5Pget_fill_value(propid, var->type_info->native_typeid,
- var->fill_value) < 0)
- BAIL(NC_EHDFERR);
- }
- else
- var->no_fill = 1;
- /* If it's a scale, mark it as such. If not, allocate space to
- * remember whether the dimscale has been attached for each
- * dimension. */
- if (is_scale)
- {
- assert(ndims);
- var->dimscale++;
- if (var->ndims > 1)
- {
- if ((retval = read_coord_dimids(var)))
- BAIL(retval);
- }
- else
- {
- var->dimids[0] = grp->dim->dimid;
- var->dim[0] = grp->dim;
- }
- }
- else
- if (num_scales && ndims &&
- !(var->dimscale_attached = calloc(ndims, sizeof(int))))
- BAIL(NC_ENOMEM);
-
- /* If this is not a scale, and has scales, iterate
- * through them. (i.e. this is a variable that is not a
- * coordinate variable) */
- if (!is_scale && num_scales)
- {
- /* Store id information allowing us to match hdf5
- * dimscales to netcdf dimensions. */
- if (!(var->dimscale_hdf5_objids = malloc(ndims * sizeof(struct hdf5_objid))))
- BAIL(NC_ENOMEM);
- for (d = 0; d < var->ndims; d++)
- {
- LOG((5, "read_var: about to iterate over scales for dim %d", d));
- if (H5DSiterate_scales(var->hdf_datasetid, d, NULL, dimscale_visitor,
- &(var->dimscale_hdf5_objids[d])) < 0)
- BAIL(NC_EHDFERR);
- /* LOG((5, "read_var: collected scale info for dim %d "
- "var %s fileno[0] %d objno[0] %d fileno[1] %d objno[1] %d",
- d, var->name, var->dimscale_hdf5_objids[d].fileno[0],
- var->dimscale_hdf5_objids[d].objno[0],
- var->dimscale_hdf5_objids[d].fileno[1],
- var->dimscale_hdf5_objids[d].objno[1]));*/
- var->dimscale_attached[d]++;
- }
- }
-
- /* Now read all the attributes of this variable, ignoring the
- ones that hold HDF5 dimension scale information. */
- if ((natts = H5Aget_num_attrs(var->hdf_datasetid)) < 0)
- BAIL(NC_EATTMETA);
- for (a = 0; a < natts; a++)
- {
- /* Close the attribute and try to move on with our
- * lives. Like bits through the network port, so
- * flows the Days of Our Lives! */
- if (attid && H5Aclose(attid) < 0)
- BAIL(NC_EHDFERR);
- /* Open the att and get its name. */
- if ((attid = H5Aopen_idx(var->hdf_datasetid, (unsigned int)a)) < 0)
- BAIL(NC_EATTMETA);
- if (H5Aget_name(attid, NC_MAX_HDF5_NAME, att_name) < 0)
- BAIL(NC_EATTMETA);
- LOG((4, "read_var: a %d att_name %s", a, att_name));
- /* Should we ignore this attribute? */
- if (strcmp(att_name, REFERENCE_LIST) &&
- strcmp(att_name, CLASS) &&
- strcmp(att_name, DIMENSION_LIST) &&
- strcmp(att_name, NAME) &&
- strcmp(att_name, COORDINATES))
- {
- /* Is this the hidden attribute that holds the netCDF
- * dimension id for a coordinate variable? */
- if (!strcmp(att_name, NC_DIMID_ATT_NAME))
- {
-
- }
- else
- {
- /* Add to the end of the list of atts for this var. */
- if ((retval = nc4_att_list_add(&var->att)))
- BAIL(retval);
- for (att = var->att; att->next; att = att->next)
- ;
-
- /* Fill in the information we know. */
- att->attnum = var->natts++;
- if (!(att->name = malloc((strlen(att_name) + 1) * sizeof(char))))
- BAIL(NC_ENOMEM);
- strcpy(att->name, att_name);
-
- /* Read the rest of the info about the att,
- * including its values. */
- if ((retval = read_hdf5_att(grp, attid, att)))
- BAIL(retval);
-
- att->created++;
- } /* endif not HDF5 att */
- }
- } /* next attribute */
- /* Is this a deflated variable with a chunksize greater than the
- * current cache size? */
- if ((retval = nc4_adjust_var_cache(grp, var)))
- BAIL(retval);
- exit:
- if (propid > 0 && H5Pclose(propid) < 0)
- BAIL2(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists--;
- #endif
- if (attid > 0 && H5Aclose(attid) < 0)
- BAIL2(NC_EHDFERR);
- return retval;
- }
- /* This function is called by nc4_rec_read_metadata to read all the
- * group level attributes (the NC_GLOBAL atts for this group). */
- static int
- read_grp_atts(NC_GRP_INFO_T *grp)
- {
- hid_t attid = 0;
- hsize_t num_obj, i;
- NC_ATT_INFO_T *att;
- NC_TYPE_INFO_T *type;
- char obj_name[NC_MAX_HDF5_NAME + 1];
- int max_len;
- int retval = NC_NOERR;
- num_obj = H5Aget_num_attrs(grp->hdf_grpid);
- for (i = 0; i < num_obj; i++)
- {
- if (attid > 0)
- H5Aclose(attid);
- if ((attid = H5Aopen_idx(grp->hdf_grpid, (unsigned int)i)) < 0)
- BAIL(NC_EATTMETA);
- if (H5Aget_name(attid, NC_MAX_NAME + 1, obj_name) < 0)
- BAIL(NC_EATTMETA);
- LOG((3, "reading attribute of _netCDF group, named %s", obj_name));
- /* This may be an attribute telling us that strict netcdf-3
- * rules are in effect. If so, we will make note of the fact,
- * but not add this attribute to the metadata. It's not a user
- * attribute, but an internal netcdf-4 one. */
- if (!strcmp(obj_name, NC3_STRICT_ATT_NAME))
- grp->file->nc4_info->cmode |= NC_CLASSIC_MODEL;
- else
- {
- /* Add an att struct at the end of the list, and then go to it. */
- if ((retval = nc4_att_list_add(&grp->att)))
- BAIL(retval);
- for (att = grp->att; att->next; att = att->next)
- ;
- /* Add the info about this attribute. */
- max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name);
- if (!(att->name = malloc((max_len + 1) * sizeof(char))))
- BAIL(NC_ENOMEM);
- strncpy(att->name, obj_name, max_len);
- att->name[max_len] = 0;
- att->attnum = grp->natts++;
- if ((retval = read_hdf5_att(grp, attid, att)))
- BAIL(retval);
- att->created++;
- if ((retval = nc4_find_type(grp->file->nc4_info, att->xtype, &type)))
- BAIL(retval);
- if (type)
- att->class = type->class;
- }
- }
- exit:
- if (attid > 0 && H5Aclose(attid) < 0)
- BAIL2(NC_EHDFERR);
- return retval;
- }
- /* This function is called when nc4_rec_read_vars encounters an HDF5
- * dataset when reading a file. */
- static int
- read_dataset(NC_GRP_INFO_T *grp, char *obj_name)
- {
- hid_t datasetid = 0;
- hid_t spaceid = 0, access_pid = 0;
- int ndims;
- hsize_t dims[NC_MAX_DIMS], max_dims[NC_MAX_DIMS];
- int is_scale = 0;
- int dim_without_var = 0;
- int num_scales = 0;
- int retval = NC_NOERR;
- /* Open this dataset. */
- if ((datasetid = H5Dopen2(grp->hdf_grpid, obj_name, H5P_DEFAULT)) < 0)
- BAIL(NC_EVARMETA);
- /* Get the current chunk cache settings. */
- if ((access_pid = H5Dget_access_plist(datasetid)) < 0)
- BAIL(NC_EVARMETA);
- #ifdef EXTRA_TESTS
- num_plists++;
- #endif
- /* Get the dimension information for this dataset. */
- if ((spaceid = H5Dget_space(datasetid)) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_spaces++;
- #endif
- if ((ndims = H5Sget_simple_extent_ndims(spaceid)) < 0)
- BAIL(NC_EHDFERR);
- if (ndims > NC_MAX_DIMS)
- BAIL(NC_EMAXDIMS);
- if (H5Sget_simple_extent_dims(spaceid, dims, max_dims) < 0)
- BAIL(NC_EHDFERR);
- /* Is this a dimscale? */
- if ((is_scale = H5DSis_scale(datasetid)) < 0)
- BAIL(NC_EHDFERR);
- if (is_scale)
- {
- /* Read the scale information. */
- if ((retval = read_scale(grp, datasetid, obj_name, dims[0],
- max_dims[0], &dim_without_var)))
- BAIL(retval);
- }
- else
- {
- /* Find out how many scales are attached to this
- * dataset. H5DSget_num_scales returns an error if there are no
- * scales, so convert a negative return value to zero. */
- num_scales = H5DSget_num_scales(datasetid, 0);
- if (num_scales < 0)
- num_scales = 0;
- }
- /* Add a var to the linked list, and get its metadata,
- * unless this is one of those funny dimscales that are a
- * dimension in netCDF but not a variable. (Spooky!) */
- if (!dim_without_var)
- if ((retval = read_var(grp, datasetid, obj_name, ndims,
- is_scale, num_scales, access_pid)))
- BAIL(retval);
-
- if (access_pid && H5Pclose(access_pid) < 0)
- BAIL2(retval);
- #ifdef EXTRA_TESTS
- num_plists--;
- #endif
- if (spaceid && H5Sclose(spaceid) < 0)
- BAIL2(retval);
- #ifdef EXTRA_TESTS
- num_spaces--;
- #endif
- return NC_NOERR;
- exit:
- if (access_pid && H5Pclose(access_pid) < 0)
- BAIL2(retval);
- #ifdef EXTRA_TESTS
- num_plists--;
- #endif
- if (datasetid && H5Dclose(datasetid) < 0)
- BAIL2(retval);
- if (spaceid && H5Sclose(spaceid) <0)
- BAIL2(retval);
- #ifdef EXTRA_TESTS
- num_spaces--;
- #endif
- return retval;
- }
- /* Given index, get the HDF5 name of an object and the class of the
- * object (group, type, dataset, etc.). This function will try to use
- * creation ordering, but if that fails it will use default
- * (i.e. alphabetical) ordering. (This is necessary to read existing
- * HDF5 archives without creation ordering). */
- /* static int */
- /* get_name_by_idx(NC_HDF5_FILE_INFO_T *h5, hid_t hdf_grpid, int i, */
- /* int *obj_class, char *obj_name) */
- /* { */
- /* H5O_info_t obj_info; */
- /* H5_index_t idx_field = H5_INDEX_CRT_ORDER; */
- /* ssize_t size; */
- /* herr_t res; */
- /* /\* These HDF5 macros prevent an HDF5 error message when a */
- /* * non-creation-ordered HDF5 file is opened. *\/ */
- /* H5E_BEGIN_TRY { */
- /* res = H5Oget_info_by_idx(hdf_grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, */
- /* i, &obj_info, H5P_DEFAULT); */
- /* } H5E_END_TRY; */
-
- /* /\* Creation ordering not available, so make sure this file is */
- /* * opened for read-only access. This is a plain old HDF5 file being */
- /* * read by netCDF-4. *\/ */
- /* if (res < 0) */
- /* { */
- /* if (H5Oget_info_by_idx(hdf_grpid, ".", H5_INDEX_NAME, H5_ITER_INC, */
- /* i, &obj_info, H5P_DEFAULT) < 0) */
- /* return NC_EHDFERR; */
- /* if (!h5->no_write) */
- /* return NC_ECANTWRITE; */
- /* h5->ignore_creationorder = 1; */
- /* idx_field = H5_INDEX_NAME; */
- /* } */
- /* *obj_class = obj_info.type; */
- /* if ((size = H5Lget_name_by_idx(hdf_grpid, ".", idx_field, H5_ITER_INC, i, */
- /* NULL, 0, H5P_DEFAULT)) < 0) */
- /* return NC_EHDFERR; */
- /* if (size > NC_MAX_NAME) */
- /* return NC_EMAXNAME; */
- /* if (H5Lget_name_by_idx(hdf_grpid, ".", idx_field, H5_ITER_INC, i, */
- /* obj_name, size+1, H5P_DEFAULT) < 0) */
- /* return NC_EHDFERR; */
- /* LOG((4, "get_name_by_idx: encountered HDF5 object obj_name %s", obj_name)); */
- /* return NC_NOERR; */
- /* } */
- #define USE_ITERATE_CODE
- #ifdef USE_ITERATE_CODE
- static int
- nc4_rec_read_types_cb(hid_t grpid, const char *name, const H5L_info_t *info,
- void *_op_data)
- {
- hid_t oid=-1;
- H5I_type_t otype=-1;
- char oname[NC_MAX_NAME + 1];
- NC_GRP_INFO_T *child_grp;
- NC_GRP_INFO_T *grp = (NC_GRP_INFO_T *) (_op_data);
- NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
- /* Open this critter. */
- if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
- return H5_ITER_ERROR;
-
- if ((otype = H5Iget_type( oid ))<0) {
- H5Oclose(oid);
- return H5_ITER_ERROR;
- }
- H5Oclose(oid);
-
- strncpy(oname, name, NC_MAX_NAME);
-
- /* Deal with groups and types; ignore the rest. */
- if (otype == H5I_GROUP)
- {
- LOG((3, "found group %s", oname));
- if (nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
- grp, grp->file, oname, &child_grp))
- return H5_ITER_ERROR;
-
- if (nc4_rec_read_types(child_grp))
- return H5_ITER_ERROR;
- }
- else if (otype == H5I_DATATYPE)
- {
- LOG((3, "found datatype %s", oname));
- if (read_type(grp, oname))
- return H5_ITER_ERROR;
- }
-
- return (H5_ITER_CONT);
- }
- static int
- nc4_rec_read_types(NC_GRP_INFO_T *grp)
- {
- hsize_t idx=0;
- int res = 0;
- hid_t pid = 0;
- unsigned crt_order_flags = 0;
- NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
- assert(grp && grp->name);
- LOG((3, "nc4_rec_read_types: grp->name %s", grp->name));
- /* Open this HDF5 group and retain its grpid. It will remain open
- * with HDF5 until this file is nc_closed. */
- if (!grp->hdf_grpid)
- {
- if (grp->parent)
- {
- if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
- grp->name, H5P_DEFAULT)) < 0)
- return NC_EHDFERR;
- }
- else
- {
- if ((grp->hdf_grpid = H5Gopen2(grp->file->nc4_info->hdfid,
- "/", H5P_DEFAULT)) < 0)
- return NC_EHDFERR;
- }
- }
- assert(grp->hdf_grpid > 0);
- pid = H5Gget_create_plist(grp->hdf_grpid);
- H5Pget_link_creation_order(pid, &crt_order_flags);
- H5Pclose(pid);
-
- crt_order_flags = crt_order_flags & H5_INDEX_CRT_ORDER;
-
- if (crt_order_flags == H5_INDEX_CRT_ORDER)
- {
- res = H5Literate(grp->hdf_grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC,
- &idx, nc4_rec_read_types_cb, (void *)grp);
- } else
- {
- /* Without creation ordering, file must be read-only. */
- if (!idx && !h5->no_write)
- return NC_ECANTWRITE;
-
- res = H5Literate(grp->hdf_grpid, H5_INDEX_NAME, H5_ITER_INC,
- &idx, nc4_rec_read_types_cb, (void *)grp);
- }
- if (res<0)
- return NC_EHDFERR;
- return NC_NOERR; /* everything worked! */
- }
- static int
- nc4_rec_read_vars_cb(hid_t grpid, const char *name, const H5L_info_t *info,
- void *_op_data)
- {
- hid_t oid=-1;
- H5I_type_t otype=-1;
- char oname[NC_MAX_NAME + 1];
- NC_GRP_INFO_T *child_grp;
- NC_GRP_INFO_T *grp = (NC_GRP_INFO_T *) (_op_data);
- #if 0
- NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
- #endif
- memset(oname, 0, NC_MAX_NAME);
- /* Open this critter. */
- if ((oid = H5Oopen(grpid, name, H5P_DEFAULT)) < 0)
- return H5_ITER_ERROR;
-
- if ((otype = H5Iget_type( oid ))<0) {
- H5Oclose(oid);
- return H5_ITER_ERROR;
- }
- H5Oclose(oid);
-
- strncpy(oname, name, NC_MAX_NAME);
-
- /* Deal with datasets. */
- switch(otype)
- {
- case H5I_GROUP:
- LOG((3, "re-encountering group %s", oname));
-
- /* The NC_GROUP_INFO_T for this group already exists. Find it. */
- for (child_grp = grp->children; child_grp; child_grp = child_grp->next)
- if (!strcmp(child_grp->name, oname))
- break;
- if (!child_grp)
- return H5_ITER_ERROR;
- /* Recursively read the child group's vars. */
- if (nc4_rec_read_vars(child_grp))
- return H5_ITER_ERROR;
- break;
- case H5I_DATASET:
- LOG((3, "found dataset %s", oname));
- /* Learn all about this dataset, which may be a dimscale
- * (i.e. dimension metadata), or real data. */
- if (read_dataset(grp, oname))
- return H5_ITER_ERROR;
- break;
- case H5I_DATATYPE:
- LOG((3, "already handled type %s", oname));
- break;
- default:
- LOG((0, "Unknown object class %d in nc4_rec_read_vars!", otype));
- }
- return (H5_ITER_CONT);
- }
- static int
- nc4_rec_read_vars(NC_GRP_INFO_T *grp)
- {
- hsize_t idx = 0;
- int retval = NC_NOERR;
- int res = 0;
- hid_t pid = 0;
- unsigned crt_order_flags = 0;
- NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
-
- assert(grp && grp->name && grp->hdf_grpid > 0);
- LOG((3, "nc4_rec_read_vars: grp->name %s", grp->name));
- pid = H5Gget_create_plist(grp->hdf_grpid);
- H5Pget_link_creation_order(pid, &crt_order_flags);
- H5Pclose(pid);
-
- crt_order_flags = crt_order_flags & H5_INDEX_CRT_ORDER;
- if (crt_order_flags == H5_INDEX_CRT_ORDER)
- {
- res = H5Literate(grp->hdf_grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC,
- &idx, nc4_rec_read_vars_cb, (void *)grp);
- } else
- {
- /* Without creation ordering, file must be read-only. */
- if (!idx && !h5->no_write)
- return NC_ECANTWRITE;
-
- res = H5Literate(grp->hdf_grpid, H5_INDEX_NAME, H5_ITER_INC,
- &idx, nc4_rec_read_vars_cb, (void *)grp);
- }
- if (res<0)
- return NC_EHDFERR;
-
- /* Scan the group for global (i.e. group-level) attributes. */
- if ((retval = read_grp_atts(grp)))
- return retval;
-
- return NC_NOERR; /* everything worked! */
- }
- #else
- /** \internal
- This struct is used to pass information back from the callback
- function used with H5Literate.
- */
- struct nc_hdf5_link_info
- {
- char name[NC_MAX_NAME + 1];
- H5I_type_t obj_type;
- };
- /* This is a callback function for H5Literate().
- The parameters of this callback function have the following values or
- meanings:
- g_id Group that serves as root of the iteration; same value as the
- H5Lvisit group_id parameter
- name Name of link, relative to g_id, being examined at current step of
- the iteration
- info H5L_info_t struct containing information regarding that link
- op_data User-defined pointer to data required by the application in
- processing the link; a pass-through of the op_data pointer provided
- with the H5Lvisit function call
- */
- static herr_t
- visit_link(hid_t g_id, const char *name, const H5L_info_t *info,
- void *op_data)
- {
- /* A positive return value causes the visit iterator to immediately
- * return that positive value, indicating short-circuit
- * success. The iterator can be restarted at the next group
- * member. */
- int ret = 1;
- hid_t id;
- /* Get the name, truncating at NC_MAX_NAME. */
- strncpy(((struct nc_hdf5_link_info *)op_data)->name, name,
- NC_MAX_NAME);
-
- /* Open this critter. */
- if ((id = H5Oopen_by_addr(g_id, info->u.address)) < 0)
- return NC_EHDFERR;
-
- /* Is this critter a group, type, data, attribute, or what? */
- if ((((struct nc_hdf5_link_info *)op_data)->obj_type = H5Iget_type(id)) < 0)
- ret = NC_EHDFERR;
- /* Close the critter to release resouces. */
- if (H5Oclose(id) < 0)
- return NC_EHDFERR;
-
- return ret;
- }
- /* Iterate over one link in the group at a time, returning
- * link_info. The creation_ordering and idx pointers keep track of
- * whether creation ordering works and the most recently examined
- * link. */
- static int
- nc4_iterate_link(int *ordering_checked, int *creation_ordering,
- hid_t grpid, hsize_t *idx, struct nc_hdf5_link_info *link_info)
- {
- int res = 0;
- if (*creation_ordering)
- {
- /* These HDF5 macros prevent an HDF5 error message when a
- * non-creation-ordered HDF5 file is opened. */
- H5E_BEGIN_TRY {
- res = H5Literate(grpid, H5_INDEX_CRT_ORDER, H5_ITER_INC,
- idx, visit_link, (void *)link_info);
- if (res < 0 && *ordering_checked)
- return NC_EHDFERR;
- } H5E_END_TRY;
- }
- if (!*creation_ordering || res < 0)
- {
- if (H5Literate(grpid, H5_INDEX_NAME, H5_ITER_INC, idx,
- visit_link, link_info) != 1)
- return NC_EHDFERR;
- /* If it didn't work with creation ordering, but did without,
- * then we don't have creation ordering. */
- *creation_ordering = 0;
- }
-
- *ordering_checked = 1;
- return NC_NOERR;
- }
- /* Recursively open groups and read types. */
- int
- nc4_rec_read_types(NC_GRP_INFO_T *grp)
- {
- hsize_t num_obj, i;
- NC_HDF5_FILE_INFO_T *h5 = grp->file->nc4_info;
- NC_GRP_INFO_T *child_grp;
- hsize_t idx = 0;
- struct nc_hdf5_link_info link_info;
- int ordering_checked = 0;
- int creation_ordering = 1; /* Assume we have it. */
- int retval = NC_NOERR;
- assert(grp && grp->name);
- LOG((3, "nc4_rec_read_types: grp->name %s", grp->name));
- /* Open this HDF5 group and retain its grpid. It will remain open
- * with HDF5 until this file is nc_closed. */
- if (!grp->hdf_grpid)
- {
- if (grp->parent)
- {
- if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid,
- grp->name, H5P_DEFAULT)) < 0)
- return NC_EHDFERR;
- }
- else
- {
- if ((grp->hdf_grpid = H5Gopen2(grp->file->nc4_info->hdfid,
- "/", H5P_DEFAULT)) < 0)
- return NC_EHDFERR;
- }
- }
- assert(grp->hdf_grpid > 0);
- /* How many objects in this group? */
- if (H5Gget_num_objs(grp->hdf_grpid, &num_obj) < 0)
- return NC_EVARMETA;
- /* For each object in the group... */
- for (i = 0; i < num_obj; i++)
- {
- if ((retval = nc4_iterate_link(&ordering_checked, &creation_ordering,
- grp->hdf_grpid, &idx, &link_info)))
- return retval;
- /* Without creation ordering, file must be read-only. */
- if (!i && !creation_ordering && !h5->no_write)
- return NC_ECANTWRITE;
- /* Deal with groups and types; ignore the rest. */
- if (link_info.obj_type == H5I_GROUP)
- {
- LOG((3, "found group %s", link_info.name));
- if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++,
- grp, grp->file, link_info.name, &child_grp)))
- return retval;
- if ((retval = nc4_rec_read_types(child_grp)))
- return retval;
- }
- else if (link_info.obj_type == H5I_DATATYPE)
- {
- LOG((3, "found datatype %s", link_info.name));
- if ((retval = read_type(grp, link_info.name)))
- return retval;
- }
- }
- return NC_NOERR; /* everything worked! */
- }
- /* This function recursively reads all the var and attribute metadata
- in a HDF5 group, and creates and fills in the netCDF-4 global
- metadata structure. */
- int
- nc4_rec_read_vars(NC_GRP_INFO_T *grp)
- {
- hsize_t num_obj, i;
- NC_GRP_INFO_T *child_grp;
- struct nc_hdf5_link_info link_info;
- hsize_t idx = 0;
- int ordering_checked = 0;
- int creation_ordering = 1; /* Assume we have it. */
- int retval = NC_NOERR;
- assert(grp && grp->name && grp->hdf_grpid > 0);
- LOG((3, "nc4_rec_read_vars: grp->name %s", grp->name));
- /* How many objects in this group? */
- if (H5Gget_num_objs(grp->hdf_grpid, &num_obj) < 0)
- return NC_EVARMETA;
- /* For each object in the group... */
- for (i = 0; i < num_obj; i++)
- {
- if ((retval = nc4_iterate_link(&ordering_checked, &creation_ordering,
- grp->hdf_grpid, &idx, &link_info)))
- return retval;
-
- /* Deal with datasets. */
- switch(link_info.obj_type)
- {
- case H5I_GROUP:
- LOG((3, "re-encountering group %s", link_info.name));
- /* The NC_GROUP_INFO_T for this group already exists. Find it. */
- for (child_grp = grp->children; child_grp; child_grp = child_grp->next)
- if (!strcmp(child_grp->name, link_info.name))
- break;
- if (!child_grp)
- return NC_EHDFERR;
- /* Recursively read the child group's vars. */
- if ((retval = nc4_rec_read_vars(child_grp)))
- return retval;
- break;
- case H5I_DATASET:
- LOG((3, "found dataset %s", link_info.name));
- /* Learn all about this dataset, which may be a dimscale
- * (i.e. dimension metadata), or real data. */
- if ((retval = read_dataset(grp, link_info.name)))
- return retval;
- break;
- case H5I_DATATYPE:
- LOG((3, "already handled type %s", link_info.name));
- break;
- default:
- LOG((0, "Unknown object class %d in nc4_rec_read_vars!",
- link_info.obj_type));
- }
- }
- /* Scan the group for global (i.e. group-level) attributes. */
- if ((retval = read_grp_atts(grp)))
- return retval;
- return NC_NOERR; /* everything worked! */
- }
- #endif
- /* Open a netcdf-4 file. Things have already been kicked off in
- * ncfunc.c in nc_open, but here the netCDF-4 part of opening a file
- * is handled. */
- static int
- nc4_open_file(const char *path, int mode, MPI_Comm comm,
- MPI_Info info, NC_FILE_INFO_T *nc)
- {
- hid_t fapl_id = H5P_DEFAULT;
- unsigned flags = (mode & NC_WRITE) ?
- H5F_ACC_RDWR : H5F_ACC_RDONLY;
- int retval;
- LOG((3, "nc4_open_file: path %s mode %d", path, mode));
- assert(path && nc);
- /* Stop diskless open in its tracks */
- if(mode & NC_DISKLESS)
- return NC_EDISKLESS;
- /* Add necessary structs to hold netcdf-4 file data. */
- if ((retval = nc4_nc4f_list_add(nc, path, mode)))
- BAIL(retval);
- assert(nc->nc4_info && nc->nc4_info->root_grp);
-
- /* Need this access plist to control how HDF5 handles open onjects
- * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to
- * fail if there are any open objects in the file. */
- if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists++;
- #endif
- #ifdef EXTRA_TESTS
- if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI))
- BAIL(NC_EHDFERR);
- #else
- if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG))
- BAIL(NC_EHDFERR);
- #endif
- #ifdef USE_PARALLEL
- /* If this is a parallel file create, set up the file creation
- property list. */
- if (mode & NC_MPIIO || mode & NC_MPIPOSIX)
- {
- nc->nc4_info->parallel++;
- if (mode & NC_MPIIO) /* MPI/IO */
- {
- LOG((4, "opening parallel file with MPI/IO"));
- if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0)
- BAIL(NC_EPARINIT);
- }
- else /* MPI/POSIX */
- {
- LOG((4, "opening parallel file with MPI/posix"));
- if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0)
- BAIL(NC_EPARINIT);
- }
- }
- #else /* only set cache for non-parallel. */
- if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size,
- nc4_chunk_cache_preemption) < 0)
- BAIL(NC_EHDFERR);
- LOG((4, "nc4_open_file: set HDF raw chunk cache to size %d nelems %d preemption %f",
- nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption));
- #endif /* USE_PARALLEL */
-
- /* The NetCDF-3.x prototype contains an mode option NC_SHARE for
- multiple processes accessing the dataset concurrently. As there
- is no HDF5 equivalent, NC_SHARE is treated as NC_NOWRITE. */
- if ((nc->nc4_info->hdfid = H5Fopen(path, flags, fapl_id)) < 0)
- BAIL(NC_EHDFERR);
- /* Does the mode specify that this file is read-only? */
- if ((mode & NC_WRITE) == 0)
- nc->nc4_info->no_write++;
- /* Now read in all the metadata. Some types and dimscale
- * information may be difficult to resolve here, if, for example, a
- * dataset of user-defined type is encountered before the
- * definition of that type. */
- if ((retval = nc4_rec_read_types(nc->nc4_info->root_grp)))
- BAIL(retval);
- if ((retval = nc4_rec_read_vars(nc->nc4_info->root_grp)))
- BAIL(retval);
- /* Now figure out which netCDF dims are indicated by the dimscale
- * information. */
- if ((retval = nc4_rec_match_dimscales(nc->nc4_info->root_grp)))
- BAIL(retval);
- #ifdef LOGGING
- /* This will print out the names, types, lens, etc of the vars and
- atts in the file, if the logging level is 2 or greater. */
- log_metadata_nc(nc);
- #endif
- /* Close the property list. */
- if (H5Pclose(fapl_id) < 0)
- BAIL(NC_EHDFERR);
- #ifdef EXTRA_TESTS
- num_plists--;
- #endif
- return NC_NOERR;
- exit:
- if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id);
- #ifdef EXTRA_TESTS
- num_plists--;
- #endif
- if (nc->nc4_info->hdfid > 0) H5Fclose(nc->nc4_info->hdfid);
- if (nc->nc4_info) free(nc->nc4_info);
- return retval;
- }
- /* Given an HDF4 type, set a pointer to netcdf type. */
- #ifdef USE_HDF4
- static int
- get_netcdf_type_from_hdf4(NC_HDF5_FILE_INFO_T *h5, int32 hdf4_typeid,
- nc_type *xtype, NC_TYPE_INFO_T *type_info)
- {
- int t;
- assert(h5 && xtype);
- switch(hdf4_typeid)
- {
- case DFNT_CHAR:
- *xtype = NC_CHAR;
- t = 0;
- break;
- case DFNT_UCHAR:
- case DFNT_UINT8:
- *xtype = NC_UBYTE;
- t = 6;
- break;
- case DFNT_INT8:
- *xtype = NC_BYTE;
- t = 1;
- break;
- case DFNT_INT16:
- *xtype = NC_SHORT;
- t = 2;
- break;
- case DFNT_UINT16:
- *xtype = NC_USHORT;
- t = 7;
- break;
- case DFNT_INT32:
- *xtype = NC_INT;
- t = 3;
- break;
- case DFNT_UINT32:
- *xtype = NC_UINT;
- t = 8;
- break;
- case DFNT_FLOAT32:
- *xtype = NC_FLOAT;
- t = 4;
- break;
- case DFNT_FLOAT64:
- *xtype = NC_DOUBLE;
- t = 5;
- break;
- default:
- *xtype = NC_NAT;
- return NC_EBADTYPID;
- }
- if (type_info)
- {
- if (hdf4_typeid == DFNT_FLOAT32 || hdf4_typeid == DFNT_FLOAT64)
- type_info->class = H5T_FLOAT;
- else if (hdf4_typeid == DFNT_CHAR)
- type_info->class = H5T_STRING;
- else
- type_info->class = H5T_INTEGER;
- type_info->endianness = NC_ENDIAN_BIG;
- type_info->nc_typeid = *xtype;
- if (type_info->name)
- free(type_info->name);
- if (!(type_info->name = malloc((strlen(nc_type_name[t]) + 1) * sizeof(char))))
- return NC_ENOMEM;
- strcpy(type_info->name, nc_type_name[t]);
- }
- return NC_NOERR;
- }
- #endif /* USE_HDF4 */
- /* Open a HDF4 file. Things have already been kicked off in nc_open,
- * but here the netCDF-4 part of opening a file is handled. */
- static int
- nc4_open_hdf4_file(const char *path, int mode, NC_FILE_INFO_T *nc)
- {
- #ifdef USE_HDF4
- NC_HDF5_FILE_INFO_T *h5;
- NC_GRP_INFO_T *grp;
- NC_ATT_INFO_T *att;
- NC_VAR_INFO_T *var;
- int32 num_datasets, num_gatts;
- int32 rank;
- int v, d, a;
- int retval;
- LOG((3, "nc4_open_hdf4_file: path %s mode %d", path, mode));
- assert(path && nc);
- /* Must be read-only access to hdf4 files. */
- if (mode & NC_WRITE)
- return NC_EINVAL;
- /* Add necessary structs to hold netcdf-4 file data. */
- if ((retval = nc4_nc4f_list_add(nc, path, mode)))
- return retval;
- assert(nc->nc4_info && nc->nc4_info->root_grp);
- h5 = nc->nc4_info;
- h5->hdf4++;
- grp = h5->root_grp;
- h5->no_write++;
- /* Open the file and initialize SD interface. */
- if ((h5->sdid = SDstart(path, DFACC_READ)) == FAIL)
- return NC_EHDFERR;
- /* Learn how many datasets and global atts we have. */
- if (SDfileinfo(h5->sdid, &num_datasets, &num_gatts))
- return NC_EHDFERR;
- /* Read the atts. */
- for (a = 0; a < num_gatts; a++)
- {
- int32 att_data_type, att_count;
- size_t att_type_size;
- /* Add to the end of the list of atts for this var. */
- if ((retval = nc4_att_list_add(&h5->root_grp->att)))
- return retval;
- for (att = h5->root_grp->att; att->next; att = att->next)
- ;
- att->attnum = grp->natts++;
- att->created++;
- /* Learn about this attribute. */
- if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char))))
- return NC_ENOMEM;
- if (SDattrinfo(h5->sdid, a, att->name, &att_data_type, &att_count))
- return NC_EATTMETA;
- if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
- &att->xtype, NULL)))
- return retval;
- att->len = att_count;
- /* Allocate memory to hold the data. */
- if ((retval = nc4_get_typelen_mem(h5, att->xtype, 0, &att_type_size)))
- return retval;
- if (!(att->data = malloc(att_type_size * att->len)))
- return NC_ENOMEM;
- /* Read the data. */
- if (SDreadattr(h5->sdid, a, att->data))
- return NC_EHDFERR;
- }
- /* Read each dataset. */
- for (v = 0; v < num_datasets; v++)
- {
- int32 data_type, num_atts;
- int32 dimsize[NC_MAX_DIMS];
- size_t var_type_size;
- int a;
- /* Add a variable to the end of the group's var list. */
- if ((retval = nc4_var_list_add(&grp->var, &var)))
- return retval;
- var->varid = grp->nvars++;
- var->created = 1;
- var->written_to = 1;
-
- /* Open this dataset in HDF4 file. */
- if ((var->sdsid = SDselect(h5->sdid, v)) == FAIL)
- return NC_EVARMETA;
- /* Get shape, name, type, and attribute info about this dataset. */
- if (!(var->name = malloc(NC_MAX_HDF4_NAME + 1)))
- return NC_ENOMEM;
- if (SDgetinfo(var->sdsid, var->name, &rank, dimsize, &data_type, &num_atts))
- return NC_EVARMETA;
- var->ndims = rank;
- var->hdf4_data_type = data_type;
- /* Fill special type_info struct for variable type information. */
- if (!(var->type_info = calloc(1, sizeof(NC_TYPE_INFO_T))))
- return NC_ENOMEM;
- if ((retval = get_netcdf_type_from_hdf4(h5, data_type, &var->xtype, var->type_info)))
- return retval;
- if ((retval = nc4_get_typelen_mem(h5, var->xtype, 0, &var_type_size)))
- return retval;
- var->type_info->size = var_type_size;
- LOG((3, "reading HDF4 dataset %s, rank %d netCDF type %d", var->name,
- rank, var->xtype));
- /* Get the fill value. */
- if (!(var->fill_value = malloc(var_type_size)))
- return NC_ENOMEM;
- if (SDgetfillvalue(var->sdsid, var->fill_value))
- {
- /* Whoops! No fill value! */
- free(var->fill_value);
- var->fill_value = NULL;
- }
- /* Allocate storage for dimension info in this variable. */
- if (var->ndims)
- {
- if (!(var->dim = malloc(sizeof(NC_DIM_INFO_T *) * var->ndims)))
- return NC_ENOMEM;
- if (!(var->dimids = malloc(sizeof(int) * var->ndims)))
- return NC_ENOMEM;
- }
- /* Find its dimensions. */
- for (d = 0; d < var->ndims; d++)
- {
- int32 dimid, dim_len, dim_data_type, dim_num_attrs;
- char dim_name[NC_MAX_NAME + 1];
- NC_DIM_INFO_T *dim;
- if ((dimid = SDgetdimid(var->sdsid, d)) == FAIL)
- return NC_EDIMMETA;
- if (SDdiminfo(dimid, dim_name, &dim_len, &dim_data_type,
- &dim_num_attrs))
- return NC_EDIMMETA;
- /* Do we already have this dimension? HDF4 explicitly uses
- * the name to tell. */
- for (dim = grp->dim; dim; dim = dim->next)
- if (!strcmp(dim->name, dim_name))
- break;
- /* If we didn't find this dimension, add one. */
- if (!dim)
- {
- LOG((4, "adding dimension %s for HDF4 dataset %s",
- dim_name, var->name));
- if ((retval = nc4_dim_list_add(&grp->dim)))
- return retval;
- grp->ndims++;
- dim = grp->dim;
- dim->dimid = grp->file->nc4_info->next_dimid++;
- if (strlen(dim_name) > NC_MAX_HDF4_NAME)
- return NC_EMAXNAME;
- if (!(dim->name = malloc(NC_MAX_HDF4_NAME + 1)))
- return NC_ENOMEM;
- strcpy(dim->name, dim_name);
- if (dim_len)
- dim->len = dim_len;
- else
- dim->len = *dimsize;
- }
- /* Tell the variable the id of this dimension. */
- var->dimids[d] = dim->dimid;
- }
- /* Read the atts. */
- for (a = 0; a < num_atts; a++)
- {
- int32 att_data_type, att_count;
- size_t att_type_size;
- /* Add to the end of the list of atts for this var. */
- if ((retval = nc4_att_list_add(&var->att)))
- return retval;
- for (att = var->att; att->next; att = att->next)
- ;
- att->attnum = var->natts++;
- att->created++;
- /* Learn about this attribute. */
- if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char))))
- return NC_ENOMEM;
- if (SDattrinfo(var->sdsid, a, att->name, &att_data_type, &att_count))
- return NC_EATTMETA;
- if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type,
- &att->xtype, NULL)))
- return retval;
- att->len = att_count;
- /* Allocate memory to hold the data. */
- if ((retval = nc4_get_typelen_mem(h5, att->xtype, 0, &att_type_size)))
- return retval;
- if (!(att->data = malloc(att_type_size * att->len)))
- return NC_ENOMEM;
- /* Read the data. */
- if (SDreadattr(var->sdsid, a, att->data))
- return NC_EHDFERR;
- }
- } /* next var */
- #ifdef LOGGING
- /* This will print out the names, types, lens, etc of the vars and
- atts in the file, if the logging level is 2 or greater. */
- log_metadata_nc(h5->root_grp->file);
- #endif
- return NC_NOERR;
- #endif /* USE_HDF4 */
- return NC_ENOTBUILT;
- }
- int
- NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp,
- int use_parallel, void *mpidata, NC_Dispatch *dispatch, NC **ncpp)
- {
- int hdf_file = 0;
- NC_FILE_INFO_T *nc_file;
- #ifdef USE_PARALLEL
- MPI_Comm comm = 0;
- MPI_Info info = 0;
- #else
- int comm = 0, info = 0;
- #endif /* USE_PARALLEL */
- int res;
- assert(ncpp && path);
- LOG((1, "nc_open_file: path %s mode %d comm %d info %d",
- path, mode, comm, info));
- #ifdef USE_PARALLEL
- if (mpidata)
- {
- NC_MPI_INFO *nmi = (NC_MPI_INFO *)mpidata;
- comm = nmi->comm; info = nmi->info;
- }
- #endif /* USE_PARALLEL */
-
- /* If this is our first file, turn off HDF5 error messages. */
- if (virgin)
- {
- if (H5Eset_auto(NULL, NULL) < 0)
- LOG((0, "Couldn't turn off HDF5 error messages!"));
- LOG((1, "HDF5 error messages turned off!"));
- virgin = 0;
- }
- /* Check the mode for validity. First make sure only certain bits
- * are turned on. Also MPI I/O and MPI POSIX cannot both be
- * selected at once. */
- if (mode & ~(NC_WRITE | NC_SHARE | NC_MPIIO | NC_MPIPOSIX |
- NC_PNETCDF | NC_NOCLOBBER | NC_NETCDF4 | NC_CLASSIC_MODEL) ||
- (mode & NC_MPIIO && mode & NC_MPIPOSIX))
- return NC_EINVAL;
- /* Figure out if this is a hdf4 or hdf5 file. */
- if ((res = nc_check_for_hdf(path, use_parallel, comm, info, &hdf_file)))
- return res;
- /* Allocate the storage for this file info struct, and fill it with
- zeros. */
- if ((res = nc4_file_list_add(&nc_file,dispatch)))
- return res;
- /* Depending on the type of file, open it. */
- if (hdf_file == NC_HDF5_FILE)
- {
- nc_file->int_ncid = nc_file->ext_ncid;
- res = nc4_open_file(path, mode, comm, info, nc_file);
- }
- else if (hdf_file == NC_HDF4_FILE)
- {
- nc_file->int_ncid = nc_file->ext_ncid;
- res = nc4_open_hdf4_file(path, mode, nc_file);
- }
- #ifdef USE_PNETCDF
- else if (mode & NC_PNETCDF)
- {
- int pnetcdf_nvars, i;
- res = ncmpi_open(comm, path, mode, info, &(nc_file->int_ncid));
- nc_file->pnetcdf_file++;
- /* Default to independent access, like netCDF-4/HDF5 files. */
- if (!res)
- res = ncmpi_begin_indep_data(nc_file->int_ncid);
- /* I need to keep track of the ndims of each var to translate
- * start, count, and stride arrays to MPI_Offset type. */
- if (!res)
- {
- res = ncmpi_inq_nvars(nc_file->int_ncid, &pnetcdf_nvars);
- for (i = 0; i < pnetcdf_nvars; i++)
- res = ncmpi_inq_varndims(nc_file->int_ncid, i,
- &(nc_file->pnetcdf_ndims[i]));
- }
- }
- #endif /* USE_PNETCDF */
- else /* netcdf */
- {
- assert(0);
- }
- /* If it succeeds, pass back the new ncid. Otherwise, remove this
- file from the list. */
- if (res)
- {
- if(nc_file != NULL) nc4_file_list_del(nc_file);
- }
- else
- {
- *ncpp = (NC*)nc_file;
- }
- return res;
- }
- /* Unfortunately HDF only allows specification of fill value only when
- a dataset is created. Whereas in netcdf, you first create the
- variable and then (optionally) specify the fill value. To
- accomplish this in HDF5 I have to delete the dataset, and recreate
- it, with the fill value specified. */
- int
- NC4_set_fill(int ncid, int fillmode, int *old_modep)
- {
- NC_FILE_INFO_T *nc;
-
- LOG((2, "nc_set_fill: ncid 0x%x fillmode %d", ncid, fillmode));
- if (!(nc = nc4_find_nc_file(ncid)))
- return NC_EBADID;
- /* Is this a netcdf-3 file? */
- assert(nc->nc4_info);
- /* Trying to set fill on a read-only file? You sicken me! */
- if (nc->nc4_info->no_write)
- return NC_EPERM;
- /* Did you pass me some weird fillmode? */
- if (fillmode != NC_FILL && fillmode != NC_NOFILL)
- return NC_EINVAL;
- /* If the user wants to know, tell him what the old mode was. */
- if (old_modep)
- *old_modep = nc->nc4_info->fill_mode;
- nc->nc4_info->fill_mode = fillmode;
- return NC_NOERR;
- }
- /* Put the file back in redef mode. This is done automatically for
- * netcdf-4 files, if the user forgets. */
- int
- NC4_redef(int ncid)
- {
- NC_FILE_INFO_T *nc;
- LOG((1, "nc_redef: ncid 0x%x", ncid));
- /* Find this file's metadata. */
- if (!(nc = nc4_find_nc_file(ncid)))
- return NC_EBADID;
- #ifdef USE_PNETCDF
- /* Take care of files created/opened with parallel-netcdf library. */
- if (nc->pnetcdf_file)
- return ncmpi_redef(nc->int_ncid);
- #endif /* USE_PNETCDF */
- /* Handle netcdf-3 files. */
- assert(nc->nc4_info);
- /* If we're already in define mode, return an error. */
- if (nc->nc4_info->flags & NC_INDEF)
- return NC_EINDEFINE;
- /* If the file is read-only, return an error. */
- if (nc->nc4_info->no_write)
- return NC_EPERM;
- /* Set define mode. */
- nc->nc4_info->flags |= NC_INDEF;
- /* For nc_abort, we need to remember if we're in define mode as a
- redef. */
- nc->nc4_info->redef++;
- return NC_NOERR;
- }
- /* For netcdf-4 files, this just calls nc_enddef, ignoring the extra
- * parameters. */
- int
- NC4__enddef(int ncid, size_t h_minfree, size_t v_align,
- size_t v_minfree, size_t r_align)
- {
- if (!nc4_find_nc_file(ncid))
- return NC_EBADID;
- return NC4_enddef(ncid);
- }
- /* Take the file out of define mode. This is called automatically for
- * netcdf-4 files, if the user forgets. */
- static int NC4_enddef(int ncid)
- {
- NC_FILE_INFO_T *nc;
- LOG((1, "nc_enddef: ncid 0x%x", ncid));
- if (!(nc = nc4_find_nc_file(ncid)))
- return NC_EBADID;
- #ifdef USE_PNETCDF
- if (nc->pnetcdf_file)
- {
- int res;
- res = ncmpi_enddef(nc->int_ncid);
- if (!res)
- {
- if (nc->pnetcdf_access_mode == NC_INDEPENDENT)
- res = ncmpi_begin_indep_data(nc->int_ncid);
- }
- return res;
- }
- #endif /* USE_PNETCDF */
- /* Take care of netcdf-3 files. */
- assert(nc->nc4_info);
- return nc4_enddef_netcdf4_file(nc->nc4_info);
- }
- /* This function will write all changed metadata, and (someday) reread
- * all metadata from the file. */
- static int
- sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
- {
- int retval;
- assert(h5);
- LOG((3, "sync_netcdf4_file"));
- /* If we're in define mode, that's an error, for strict nc3 rules,
- * otherwise, end define mode. */
- if (h5->flags & NC_INDEF)
- {
- if (h5->cmode & NC_CLASSIC_MODEL)
- return NC_EINDEFINE;
- /* Turn define mode off. */
- h5->flags ^= NC_INDEF;
-
- /* Redef mode needs to be tracked seperately for nc_abort. */
- h5->redef = 0;
- }
- #ifdef LOGGING
- /* This will print out the names, types, lens, etc of the vars and
- atts in the file, if the logging level is 2 or greater. */
- log_metadata_nc(h5->root_grp->file);
- #endif
- /* Write any metadata that has changed. */
- if (!(h5->cmode & NC_NOWRITE))
- {
- if ((retval = nc4_rec_write_types(h5->root_grp)))
- return retval;
- if ((retval = nc4_rec_write_metadata(h5->root_grp)))
- return retval;
- }
- H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL);
- /* Reread all the metadata. */
- /*if ((retval = nc4_rec_read_metadata(grp)))
- return retval;*/
- return retval;
- }
- /* Flushes all buffers associated with the file, after writing all
- changed metadata. This may only be called in data mode. */
- int
- NC4_sync(int ncid)
- {
- NC_FILE_INFO_T *nc;
- int retval;
- LOG((2, "nc_sync: ncid 0x%x", ncid));
- if (!(nc = nc4_find_nc_file(ncid)))
- return NC_EBADID;
- #ifdef USE_PNETCDF
- /* Take care of files created/opened with parallel-netcdf library. */
- if (nc->pnetcdf_file)
- return ncmpi_sync(nc->int_ncid);
- #endif /* USE_PNETCDF */
- /* Take care of netcdf-3 files. */
- assert(nc->nc4_info);
- /* If we're in define mode, we can't sync. */
- if (nc->nc4_info && nc->nc4_info->flags & NC_INDEF)
- {
- if (nc->nc4_info->cmode & NC_CLASSIC_MODEL)
- return NC_EINDEFINE;
- if ((retval = nc_enddef(ncid)))
- return retval;
- }
- return sync_netcdf4_file(nc->nc4_info);
- }
- /* This function will free all allocated metadata memory, and close
- the HDF5 file. The group that is passed in must be the root group
- of the file. */
- static int
- close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort)
- {
- int retval;
- assert(h5 && h5->root_grp);
- LOG((3, "close_netcdf4_file: h5->path %s abort %d",
- h5->path, abort));
- /* According to the docs, always end define mode on close. */
- if (h5->flags & NC_INDEF)
- h5->flags ^= NC_INDEF;
- /* Sync the file, unless we're aborting, or this is a read-only
- * file. */
- if (!h5->no_write && !abort)
- if ((retval = sync_netcdf4_file(h5)))
- return retval;
- /* Delete all the list contents for vars, dims, and atts, in each
- * group. */
- if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp)))
- return retval;
- /* Close hdf file. */
- if (h5->hdf4)
- {
- #ifdef USE_HDF4
- if (SDend(h5->sdid))
- return NC_EHDFERR;
- #endif /* USE_HDF4 */
- }
- else
- {
- if (H5Fclose(h5->hdfid) < 0)
- {
- int nobjs;
- nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL);
- /* Apparently we can get an error even when nobjs == 0 */
- if(nobjs < 0) {
- return NC_EHDFERR;
- } else if(nobjs > 0) {
- #ifdef LOGGING
- /* If the close doesn't work, probably there are still some HDF5
- * objects open, which means there's a bug in the library. So
- * print out some info on to help the poor programmer figure it
- * out. */
- LOG((0, "There are %d HDF5 objects open!", nobjs));
- #endif
- return NC_EHDFERR;
- }
- }
- /* if (H5garbage_collect() < 0)
- return NC_EHDFERR; */
- }
- /* Delete the memory for the path, if it's been allocated. */
- if (h5->path)
- free(h5->path);
- /* Free the nc4_info struct. */
- free(h5);
- return NC_NOERR;
- }
- /* From the netcdf-3 docs: The function nc_abort just closes the
- netCDF dataset, if not in define mode. If the dataset is being
- created and is still in define mode, the dataset is deleted. If
- define mode was entered by a call to nc_redef, the netCDF dataset
- is restored to its state before definition mode was entered and the
- dataset is closed. */
- int
- NC4_abort(int ncid)
- {
- NC_FILE_INFO_T *nc;
- int delete_file = 0;
- char path[NC_MAX_NAME + 1];
- int retval = NC_NOERR;
- LOG((2, "nc_abort: ncid 0x%x", ncid));
- /* Find metadata for this file. */
- if (!(nc = nc4_find_nc_file(ncid)))
- return NC_EBADID;
- #ifdef USE_PNETCDF
- /* Take care of files created/opened with parallel-netcdf library. */
- if (nc->pnetcdf_file)
- return ncmpi_abort(nc->int_ncid);
- #endif /* USE_PNETCDF */
- /* If this is a netcdf-3 file, let the netcdf-3 library handle it. */
- assert(nc->nc4_info);
- /* If we're in define mode, but not redefing the file, delete it. */
- if (nc->nc4_info->flags & NC_INDEF && !nc->nc4_info->redef)
- {
- delete_file++;
- strcpy(path, nc->nc4_info->path);
- /*strcpy(path, nc->path);*/
- }
- /* Free any resources the netcdf-4 library has for this file's
- * metadata. */
- if ((retval = close_netcdf4_file(nc->nc4_info, 1)))
- return retval;
-
- /* Delete the file, if we should. */
- if (delete_file)
- remove(path);
- /* Delete this entry from our list of open files. */
- nc4_file_list_del(nc);
- return retval;
- }
- /* Close the netcdf file, writing any changes first. */
- int
- NC4_close(int ncid)
- {
- NC_GRP_INFO_T *grp;
- NC_FILE_INFO_T *nc;
- NC_HDF5_FILE_INFO_T *h5;
- int retval;
- LOG((1, "nc_close: ncid 0x%x", ncid));
- /* Find our metadata for this file. */
- if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
- return retval;
- #ifdef USE_PNETCDF
- /* Take care of files created/opened with parallel-netcdf library. */
- if (nc->pnetcdf_file)
- return ncmpi_close(nc->int_ncid);
- #endif /* USE_PNETCDF */
- assert(h5 && nc);
- /* This must be the root group. */
- if (grp->parent)
- return NC_EBADGRPID;
- /* Call the nc4 close. */
- if ((retval = close_netcdf4_file(grp->file->nc4_info, 0)))
- return retval;
- /* Delete this entry from our list of open files. */
- if (nc->path)
- free(nc->path);
- nc4_file_list_del(nc);
- /* Reset the ncid numbers if there are no more files open. */
- if(count_NCList() == 0)
- nc4_file_list_free();
- return NC_NOERR;
- }
- /* It's possible for any of these pointers to be NULL, in which case
- don't try to figure out that value. */
- int
- NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
- {
- NC_FILE_INFO_T *nc;
- NC_HDF5_FILE_INFO_T *h5;
- NC_GRP_INFO_T *grp;
- NC_DIM_INFO_T *dim;
- NC_ATT_INFO_T *att;
- NC_VAR_INFO_T *var;
- int retval;
- LOG((2, "nc_inq: ncid 0x%x", ncid));
- /* Find file metadata. */
- if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
- return retval;
- #ifdef USE_PNETCDF
- /* Take care of files created/opened with parallel-netcdf library. */
- if (nc->pnetcdf_file)
- return ncmpi_inq(nc->int_ncid, ndimsp, nvarsp, nattsp, unlimdimidp);
- #endif /* USE_PNETCDF */
- /* Netcdf-3 files are already taken care of. */
- assert(h5 && grp && nc);
- /* Count the number of dims, vars, and global atts. */
- if (ndimsp)
- {
- *ndimsp = 0;
- for (dim = grp->dim; dim; dim = dim->next)
- (*ndimsp)++;
- }
- if (nvarsp)
- {
- *nvarsp = 0;
- for (var = grp->var; var; var= var->next)
- (*nvarsp)++;
- }
- if (nattsp)
- {
- *nattsp = 0;
- for (att = grp->att; att; att = att->next)
- (*nattsp)++;
- }
- if (unlimdimidp)
- {
- /* Default, no unlimited dimension */
- int found = 0;
- *unlimdimidp = -1;
- /* If there's more than one unlimited dim, which was not possible
- with netcdf-3, then only the last unlimited one will be reported
- back in xtendimp. */
- /* Note that this code is inconsistent with nc_inq_unlimid() */
- for (dim = grp->dim; dim; dim = dim->next)
- if (dim->unlimited)
- {
- *unlimdimidp = dim->dimid;
- break;
- }
- }
- return NC_NOERR;
- }
- /* This function will do the enddef stuff for a netcdf-4 file. */
- int
- nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5)
- {
- assert(h5);
- LOG((3, "nc4_enddef_netcdf4_file"));
- /* If we're not in define mode, return an error. */
- if (!(h5->flags & NC_INDEF))
- return NC_ENOTINDEFINE;
- /* Turn define mode off. */
- h5->flags ^= NC_INDEF;
- /* Redef mode needs to be tracked seperately for nc_abort. */
- h5->redef = 0;
- return sync_netcdf4_file(h5);
- }
- #ifdef EXTRA_TESTS
- int
- nc_exit()
- {
- if (num_plists || num_spaces)
- return NC_EHDFERR;
-
- return NC_NOERR;
- }
- #endif /* EXTRA_TESTS */
- #ifdef USE_PARALLEL
- int
- nc_use_parallel_enabled()
- {
- return 0;
- }
- #endif /* USE_PARALLEL */
|