GRASS Programmer's Manual
6.4.2(2012)
|
00001 00015 #include <grass/config.h> 00016 #include <stdio.h> 00017 #include <string.h> 00018 #include <errno.h> 00019 #include <unistd.h> 00020 #include <limits.h> 00021 #include <grass/segment.h> 00022 00023 00024 static int _segment_format(int, int, int, int, int, int, int); 00025 static int write_int(int, int); 00026 static int zero_fill(int, off_t); 00027 00028 /* fd must be open for write */ 00029 00030 00062 int segment_format(int fd, int nrows, int ncols, int srows, int scols, 00063 int len) 00064 { 00065 return _segment_format(fd, nrows, ncols, srows, scols, len, 1); 00066 } 00067 00102 int segment_format_nofill(int fd, int nrows, int ncols, int srows, int scols, 00103 int len) 00104 { 00105 return _segment_format(fd, nrows, ncols, srows, scols, len, 0); 00106 } 00107 00108 00109 static int _segment_format(int fd, 00110 int nrows, int ncols, 00111 int srows, int scols, int len, int fill) 00112 { 00113 off_t nbytes; 00114 int spr, size; 00115 00116 if (nrows <= 0 || ncols <= 0 || len <= 0 || srows <= 0 || scols <= 0) { 00117 G_warning("segment_format(fd,%d,%d,%d,%d,%d): illegal value(s)", 00118 nrows, ncols, srows, scols, len); 00119 return -3; 00120 } 00121 00122 if (lseek(fd, 0L, SEEK_SET) == (off_t) -1) { 00123 G_warning("segment_format(): Unable to seek (%s)", strerror(errno)); 00124 return -1; 00125 } 00126 00127 if (!write_int(fd, nrows) || !write_int(fd, ncols) 00128 || !write_int(fd, srows) || !write_int(fd, scols) 00129 || !write_int(fd, len)) 00130 return -1; 00131 00132 if (!fill) 00133 return 1; 00134 00135 spr = ncols / scols; 00136 if (ncols % scols) 00137 spr++; 00138 00139 size = srows * scols * len; 00140 00141 /* calculate total number of segments */ 00142 nbytes = spr * ((nrows + srows - 1) / srows); 00143 nbytes *= size; 00144 00145 /* fill segment file with zeros */ 00146 /* NOTE: this could be done faster using lseek() by seeking 00147 * ahead nbytes and then writing a single byte of 0, 00148 * provided lseek() on all version of UNIX will create a file 00149 * with holes that read as zeros. 00150 */ 00151 if (zero_fill(fd, nbytes) < 0) 00152 return -1; 00153 00154 return 1; 00155 } 00156 00157 00158 static int write_int(int fd, int n) 00159 { 00160 if (write(fd, &n, sizeof(int)) != sizeof(int)) { 00161 G_warning("segment_format(): Unable to write (%s)", strerror(errno)); 00162 return 0; 00163 } 00164 00165 return 1; 00166 } 00167 00168 00169 static int zero_fill(int fd, off_t nbytes) 00170 { 00171 #ifndef USE_LSEEK 00172 char buf[10240]; 00173 register char *b; 00174 register int n; 00175 00176 /* zero buf */ 00177 n = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; 00178 b = buf; 00179 while (n-- > 0) 00180 *b++ = 0; 00181 00182 while (nbytes > 0) { 00183 n = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; 00184 if (write(fd, buf, n) != n) { 00185 G_warning("segment zero_fill(): Unable to write (%s)", strerror(errno)); 00186 return -1; 00187 } 00188 nbytes -= n; 00189 } 00190 return 1; 00191 #else 00192 /* Using lseek (faster upon initialization). 00193 NOTE: This version doesn't allocate disk storage for the file; storage will 00194 be allocated dynamically as blocks are actually written. This could 00195 result in zero_fill() succeeding but a subsequent call to write() failing 00196 with ENOSPC ("No space left on device"). 00197 */ 00198 00199 static const char buf[10]; 00200 00201 G_debug(3, "Using new segmentation code..."); 00202 if (lseek(fd, nbytes - 1, SEEK_CUR) < 0) { 00203 G_warning("segment zero_fill(): Unable to seek (%s)", strerror(errno)); 00204 return -1; 00205 } 00206 if (write(fd, buf, 1) != 1) { 00207 G_warning("segment zero_fill(): Unable to write (%s)", strerror(errno)); 00208 return -1; 00209 } 00210 00211 return 1; 00212 #endif 00213 }