1 /*
2   Copyright 2011, UCAR/Unidata
3   See COPYRIGHT file for copying and redistribution conditions.
4 
5   This is part of netCDF.
6 
7   This program tests for a bug discovered with nofill mode that failed
8   only on file systems with block size in a particular range.  It fails
9   when invoked with the blksize argument between 2091953 and 2150032,
10   inclusive, and succeeds for other blksizes.
11 */
12 
13 #include <config.h>
14 #include <nc_tests.h>
15 #include "err_macros.h"
16 #include <stdio.h>
17 #include <limits.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <netcdf.h>
21 
22 #define FILE_NAME "tst_nofill2.nc"
23 #define LON_LEN 240
24 #define LAT_LEN 121
25 #define LVL_LEN 31
26 #define TIME_LEN 1
27 #define NDIMS1 1
28 #define NDIMS4 4
29 
30 int
create_file(char * file_name,int fill_mode,size_t * sizehintp)31 create_file(char *file_name, int fill_mode, size_t* sizehintp)
32 {
33    int ncid, time_id, zonal_wnd_id;
34    int dimids[NDIMS4];
35    size_t start[NDIMS4] = {0, 0, 0, 0};
36    size_t count[NDIMS4] = {TIME_LEN, 1, LAT_LEN, LON_LEN};
37    float zonal_wnd[LON_LEN * LAT_LEN * TIME_LEN];
38    size_t default_initialsize = 0;
39    double time[TIME_LEN] = {1.};
40    int i;
41 
42    /* Init data. */
43    for(i = 0; i < TIME_LEN * LAT_LEN * LON_LEN; i++)
44       zonal_wnd[i] = 100 + i;
45 
46    /* To test bug on filesystem without large block size, we can get
47     * the same effect by providing the desired value as sizehint to
48     * nc__create() instead of calling nc_create() and getting the
49     * block size reported by fstat */
50    if (nc__create(file_name, NC_CLOBBER, default_initialsize, sizehintp, &ncid)) ERR;
51    if (nc_set_fill(ncid, fill_mode, NULL)) ERR;
52 
53    /* define dimensions */
54    if (nc_def_dim(ncid, "lon", LON_LEN, &dimids[3])) ERR;
55    if (nc_def_dim(ncid, "lat", LAT_LEN, &dimids[2])) ERR;
56    if (nc_def_dim(ncid, "lvl", LVL_LEN, &dimids[1])) ERR;
57    if (nc_def_dim(ncid, "time", TIME_LEN, &dimids[0])) ERR;
58 
59    /* define variables */
60    if (nc_def_var(ncid, "time", NC_DOUBLE, NDIMS1, &dimids[0], &time_id)) ERR;
61    if (nc_def_var(ncid, "zonal_wnd", NC_FLOAT, NDIMS4, dimids, &zonal_wnd_id)) ERR;
62 
63    if (nc_enddef (ncid)) ERR;
64    if (nc_put_var_double(ncid, time_id, time)) ERR;
65 
66    /* Bug exposed when written in reverse order. */
67    for(i = LVL_LEN - 1; i>=0; i--)
68    {
69       start[1] = i;
70       if (nc_put_vara_float(ncid, zonal_wnd_id, start, count, zonal_wnd)) ERR;
71    }
72    if (nc_close(ncid)) ERR;
73    return 0;
74 }
75 
76 int
main(int argc,char ** argv)77 main(int argc, char **argv)
78 {
79    size_t sizehint = (1750000);	/* default if not set on command line,
80 				 * exposes bug.  It turns out any
81 				 * value between 2091953 and 2150032
82 				 * triggers bug, whereas all other
83 				 * values work fine. */
84 
85    printf("\n*** Testing nofill mode.\n");
86    printf("*** Create file in nofill mode, writing all values...");
87    {
88 #define NUM_TRIES 1
89       int ncid;
90       size_t idx[1] = {0};
91       double data;
92       int i;
93 
94       for (i = 0; i < NUM_TRIES; i++)
95       {
96 	printf(", trying sizehint of %lu ...", (unsigned long)sizehint);
97 	 if (create_file(FILE_NAME, NC_NOFILL, &sizehint)) ERR;
98 	 if (nc_open(FILE_NAME, 0, &ncid)) ERR;
99 	 if (nc_get_var1(ncid, 0, idx, &data)) ERR;
100 	 if (!data) ERR;
101 	 if (nc_close(ncid)) ERR;
102 	 sizehint += 10000;
103       }
104    }
105    SUMMARIZE_ERR;
106    FINAL_RESULTS;
107 }
108