/* Note that the offset is just the caller letting us know where * the current file position is in the file. The use_seek arg tells * us that we should seek over matching data instead of writing it. */ static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int len) { int l1 = 0, l2 = 0; int ret; for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {} for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {} sparse_seek += l1; if (l1 == len) return len; if (sparse_seek) { if (sparse_past_write >= preallocated_len) { if (do_lseek(f, sparse_seek, SEEK_CUR) < 0) return -1; } else if (do_punch_hole(f, sparse_past_write, sparse_seek) < 0) { sparse_seek = 0; return -1; } } sparse_seek = l2; sparse_past_write = offset + len - l2; if (use_seek) { /* The in-place data already matches. */ if (do_lseek(f, len - (l1+l2), SEEK_CUR) < 0) return -1; return len; } while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) { if (ret < 0 && errno == EINTR) continue; sparse_seek = 0; return ret; } if (ret != (int)(len - (l1+l2))) { sparse_seek = 0; return l1+ret; } return len; }
void test(void) { unsigned long offset; unsigned long size = maxoplen; unsigned long rv = random(); unsigned long op; if (simulatedopcount > 0 && testcalls == simulatedopcount) writefileimage(); testcalls++; if (closeprob) closeopen = (rv >> 3) < (1u << 28) / (unsigned)closeprob; if (debugstart > 0 && testcalls >= debugstart) debug = 1; if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) prt("%lu...\n", testcalls); offset = random(); if (randomoplen) size = random() % (maxoplen + 1); /* calculate appropriate op to run */ if (lite) op = rv % OP_MAX_LITE; else op = rv % OP_MAX_FULL; switch (op) { case OP_MAPREAD: if (!mapped_reads) op = OP_READ; break; case OP_MAPWRITE: if (!mapped_writes) op = OP_WRITE; break; case OP_FALLOCATE: if (!fallocate_calls) { log4(OP_SKIPPED, OP_FALLOCATE, offset, size); goto out; } break; case OP_PUNCH_HOLE: if (!punch_hole_calls) { log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, size); goto out; } break; } switch (op) { case OP_READ: TRIM_OFF_LEN(offset, size, file_size); doread(offset, size); break; case OP_WRITE: TRIM_OFF_LEN(offset, size, maxfilelen); dowrite(offset, size); break; case OP_MAPREAD: TRIM_OFF_LEN(offset, size, file_size); exit(183); break; case OP_MAPWRITE: TRIM_OFF_LEN(offset, size, maxfilelen); exit(182); break; case OP_TRUNCATE: if (!style) size = random() % maxfilelen; dotruncate(size); break; case OP_PUNCH_HOLE: TRIM_OFF_LEN(offset, size, file_size); do_punch_hole(offset, size); break; default: prterr("test: unknown operation"); report_failure(42); break; } out: if (sizechecks && testcalls > simulatedopcount) check_size(); if (closeopen) docloseopen(); }