/* * _mem_fr_sds moves data into user memory from a secondary data segment (SDS). * * Returns 0 on normal return, or else -1 with error code in errno. */ _mem_fr_sds( bitptr ubuf, /* user buffer to receive data */ bitptr sdsaddr, /* SDS bit address of data */ int nbits /* number of bits to move */ ) { long sds_bit_offset; char *ucaddr; long *uwaddr; int ret; if (nbits & (BITPBLOCK - 1)) { errno = FDC_ERR_GRAN; /* must be block multiple */ return -1; } ucaddr = BPTR2CP(ubuf); uwaddr = BPTR2WP(ubuf); if (ucaddr != (char*)uwaddr) { errno = FDC_ERR_SDSWB; /* must be word-aligned */ return -1; } sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); if (sds_bit_offset & (BITPBLOCK - 1)) { errno = FDC_ERR_GRAN; /* must be block multiple */ return -1; } ret = ssread(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(nbits)); if (ret == -1) errno = FDC_ERR_SDSIO; return ret; }
if (do_cksum) { if (do_byteswap) fletcher_4_incremental_byteswap(buf, len, cksum); else fletcher_4_incremental_native(buf, len, cksum); } total_stream_len += len; return (outlen); } static size_t read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum) { ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t)); size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum); if (r == 0) return (0); zio_cksum_t saved_cksum = *cksum; r = ssread(&drr->drr_u.drr_checksum.drr_checksum, sizeof (zio_cksum_t), cksum); if (r == 0) return (0); if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) && !ZIO_CHECKSUM_EQUAL(saved_cksum, drr->drr_u.drr_checksum.drr_checksum)) { fprintf(stderr, "invalid checksum\n"); (void) printf("Incorrect checksum in record header.\n"); (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n", saved_cksum.zc_word[0], saved_cksum.zc_word[1],
int main(int argc, char *argv[]) { char *buf = malloc(INITIAL_BUFLEN); dmu_replay_record_t thedrr; dmu_replay_record_t *drr = &thedrr; struct drr_begin *drrb = &thedrr.drr_u.drr_begin; struct drr_end *drre = &thedrr.drr_u.drr_end; struct drr_object *drro = &thedrr.drr_u.drr_object; struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects; struct drr_write *drrw = &thedrr.drr_u.drr_write; struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref; struct drr_free *drrf = &thedrr.drr_u.drr_free; struct drr_spill *drrs = &thedrr.drr_u.drr_spill; char c; boolean_t verbose = B_FALSE; boolean_t first = B_TRUE; int err; zio_cksum_t zc = { 0 }; zio_cksum_t pcksum = { 0 }; while ((c = getopt(argc, argv, ":vC")) != -1) { switch (c) { case 'C': do_cksum = B_FALSE; break; case 'v': verbose = B_TRUE; break; case ':': (void) fprintf(stderr, "missing argument for '%c' option\n", optopt); usage(); break; case '?': (void) fprintf(stderr, "invalid option '%c'\n", optopt); usage(); } } if (isatty(STDIN_FILENO)) { (void) fprintf(stderr, "Error: Backup stream can not be read " "from a terminal.\n" "You must redirect standard input.\n"); exit(1); } send_stream = stdin; pcksum = zc; while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) { if (first) { if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { do_byteswap = B_TRUE; if (do_cksum) { ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); /* * recalculate header checksum now * that we know it needs to be * byteswapped. */ fletcher_4_incremental_byteswap(drr, sizeof (dmu_replay_record_t), &zc); } } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) { (void) fprintf(stderr, "Invalid stream " "(bad magic number)\n"); exit(1); } first = B_FALSE; } if (do_byteswap) { drr->drr_type = BSWAP_32(drr->drr_type); drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); } /* * At this point, the leading fields of the replay record * (drr_type and drr_payloadlen) have been byte-swapped if * necessary, but the rest of the data structure (the * union of type-specific structures) is still in its * original state. */ if (drr->drr_type >= DRR_NUMTYPES) { (void) printf("INVALID record found: type 0x%x\n", drr->drr_type); (void) printf("Aborting.\n"); exit(1); } drr_record_count[drr->drr_type]++; switch (drr->drr_type) { case DRR_BEGIN: if (do_byteswap) { drrb->drr_magic = BSWAP_64(drrb->drr_magic); drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); drrb->drr_type = BSWAP_32(drrb->drr_type); drrb->drr_flags = BSWAP_32(drrb->drr_flags); drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); } (void) printf("BEGIN record\n"); (void) printf("\thdrtype = %lld\n", DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo)); (void) printf("\tfeatures = %llx\n", DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo)); (void) printf("\tmagic = %llx\n", (u_longlong_t)drrb->drr_magic); (void) printf("\tcreation_time = %llx\n", (u_longlong_t)drrb->drr_creation_time); (void) printf("\ttype = %u\n", drrb->drr_type); (void) printf("\tflags = 0x%x\n", drrb->drr_flags); (void) printf("\ttoguid = %llx\n", (u_longlong_t)drrb->drr_toguid); (void) printf("\tfromguid = %llx\n", (u_longlong_t)drrb->drr_fromguid); (void) printf("\ttoname = %s\n", drrb->drr_toname); if (verbose) (void) printf("\n"); if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) { nvlist_t *nv; int sz = drr->drr_payloadlen; if (sz > 1<<20) { free(buf); buf = malloc(sz); } (void) ssread(buf, sz, &zc); if (ferror(send_stream)) perror("fread"); err = nvlist_unpack(buf, sz, &nv, 0); if (err) perror(strerror(err)); nvlist_print(stdout, nv); nvlist_free(nv); } break; case DRR_END: if (do_byteswap) { drre->drr_checksum.zc_word[0] = BSWAP_64(drre->drr_checksum.zc_word[0]); drre->drr_checksum.zc_word[1] = BSWAP_64(drre->drr_checksum.zc_word[1]); drre->drr_checksum.zc_word[2] = BSWAP_64(drre->drr_checksum.zc_word[2]); drre->drr_checksum.zc_word[3] = BSWAP_64(drre->drr_checksum.zc_word[3]); } /* * We compare against the *previous* checksum * value, because the stored checksum is of * everything before the DRR_END record. */ if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum, pcksum)) { (void) printf("Expected checksum differs from " "checksum in stream.\n"); (void) printf("Expected checksum = %" FX64 "/%" FX64 "/%" FX64 "/%" FX64 "\n", pcksum.zc_word[0], pcksum.zc_word[1], pcksum.zc_word[2], pcksum.zc_word[3]); } (void) printf("END checksum = %" FX64 "/%" FX64 "/%" FX64 "/%" FX64 "\n", drre->drr_checksum.zc_word[0], drre->drr_checksum.zc_word[1], drre->drr_checksum.zc_word[2], drre->drr_checksum.zc_word[3]); ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); break; case DRR_OBJECT: if (do_byteswap) { drro->drr_object = BSWAP_64(drro->drr_object); drro->drr_type = BSWAP_32(drro->drr_type); drro->drr_bonustype = BSWAP_32(drro->drr_bonustype); drro->drr_blksz = BSWAP_32(drro->drr_blksz); drro->drr_bonuslen = BSWAP_32(drro->drr_bonuslen); drro->drr_toguid = BSWAP_64(drro->drr_toguid); } if (verbose) { (void) printf("OBJECT object = %llu type = %u " "bonustype = %u blksz = %u bonuslen = %u\n", (u_longlong_t)drro->drr_object, drro->drr_type, drro->drr_bonustype, drro->drr_blksz, drro->drr_bonuslen); } if (drro->drr_bonuslen > 0) { (void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen, 8), &zc); } break; case DRR_FREEOBJECTS: if (do_byteswap) { drrfo->drr_firstobj = BSWAP_64(drrfo->drr_firstobj); drrfo->drr_numobjs = BSWAP_64(drrfo->drr_numobjs); drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid); } if (verbose) { (void) printf("FREEOBJECTS firstobj = %llu " "numobjs = %llu\n", (u_longlong_t)drrfo->drr_firstobj, (u_longlong_t)drrfo->drr_numobjs); } break; case DRR_WRITE: if (do_byteswap) { drrw->drr_object = BSWAP_64(drrw->drr_object); drrw->drr_type = BSWAP_32(drrw->drr_type); drrw->drr_offset = BSWAP_64(drrw->drr_offset); drrw->drr_length = BSWAP_64(drrw->drr_length); drrw->drr_toguid = BSWAP_64(drrw->drr_toguid); drrw->drr_key.ddk_prop = BSWAP_64(drrw->drr_key.ddk_prop); } if (verbose) { (void) printf("WRITE object = %llu type = %u " "checksum type = %u\n" "offset = %llu length = %llu " "props = %llx\n", (u_longlong_t)drrw->drr_object, drrw->drr_type, drrw->drr_checksumtype, (u_longlong_t)drrw->drr_offset, (u_longlong_t)drrw->drr_length, (u_longlong_t)drrw->drr_key.ddk_prop); } (void) ssread(buf, drrw->drr_length, &zc); total_write_size += drrw->drr_length; break; case DRR_WRITE_BYREF: if (do_byteswap) { drrwbr->drr_object = BSWAP_64(drrwbr->drr_object); drrwbr->drr_offset = BSWAP_64(drrwbr->drr_offset); drrwbr->drr_length = BSWAP_64(drrwbr->drr_length); drrwbr->drr_toguid = BSWAP_64(drrwbr->drr_toguid); drrwbr->drr_refguid = BSWAP_64(drrwbr->drr_refguid); drrwbr->drr_refobject = BSWAP_64(drrwbr->drr_refobject); drrwbr->drr_refoffset = BSWAP_64(drrwbr->drr_refoffset); drrwbr->drr_key.ddk_prop = BSWAP_64(drrwbr->drr_key.ddk_prop); } if (verbose) { (void) printf("WRITE_BYREF object = %llu " "checksum type = %u props = %llx\n" "offset = %llu length = %llu\n" "toguid = %llx refguid = %llx\n" "refobject = %llu refoffset = %llu\n", (u_longlong_t)drrwbr->drr_object, drrwbr->drr_checksumtype, (u_longlong_t)drrwbr->drr_key.ddk_prop, (u_longlong_t)drrwbr->drr_offset, (u_longlong_t)drrwbr->drr_length, (u_longlong_t)drrwbr->drr_toguid, (u_longlong_t)drrwbr->drr_refguid, (u_longlong_t)drrwbr->drr_refobject, (u_longlong_t)drrwbr->drr_refoffset); } break; case DRR_FREE: if (do_byteswap) { drrf->drr_object = BSWAP_64(drrf->drr_object); drrf->drr_offset = BSWAP_64(drrf->drr_offset); drrf->drr_length = BSWAP_64(drrf->drr_length); } if (verbose) { (void) printf("FREE object = %llu " "offset = %llu length = %lld\n", (u_longlong_t)drrf->drr_object, (u_longlong_t)drrf->drr_offset, (longlong_t)drrf->drr_length); } break; case DRR_SPILL: if (do_byteswap) { drrs->drr_object = BSWAP_64(drrs->drr_object); drrs->drr_length = BSWAP_64(drrs->drr_length); } if (verbose) { (void) printf("SPILL block for object = %" FU64 "length = %" FU64 "\n", drrs->drr_object, drrs->drr_length); } (void) ssread(buf, drrs->drr_length, &zc); break; } pcksum = zc; } free(buf); /* Print final summary */ (void) printf("SUMMARY:\n"); (void) printf("\tTotal DRR_BEGIN records = %lld\n", (u_longlong_t)drr_record_count[DRR_BEGIN]); (void) printf("\tTotal DRR_END records = %lld\n", (u_longlong_t)drr_record_count[DRR_END]); (void) printf("\tTotal DRR_OBJECT records = %lld\n", (u_longlong_t)drr_record_count[DRR_OBJECT]); (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n", (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]); (void) printf("\tTotal DRR_WRITE records = %lld\n", (u_longlong_t)drr_record_count[DRR_WRITE]); (void) printf("\tTotal DRR_FREE records = %lld\n", (u_longlong_t)drr_record_count[DRR_FREE]); (void) printf("\tTotal DRR_SPILL records = %lld\n", (u_longlong_t)drr_record_count[DRR_SPILL]); (void) printf("\tTotal records = %lld\n", (u_longlong_t)(drr_record_count[DRR_BEGIN] + drr_record_count[DRR_OBJECT] + drr_record_count[DRR_FREEOBJECTS] + drr_record_count[DRR_WRITE] + drr_record_count[DRR_FREE] + drr_record_count[DRR_SPILL] + drr_record_count[DRR_END])); (void) printf("\tTotal write size = %lld (0x%llx)\n", (u_longlong_t)total_write_size, (u_longlong_t)total_write_size); (void) printf("\tTotal stream length = %lld (0x%llx)\n", (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len); return (0); }
/* * _any_sds_fr_mem moves data into a secondary data segment (SDS) from * user memory * * unlike _sds_fr_mem, _any_sds_fr_mem handles moving a number of bits that * may not be a multiple of 512. * * Returns 0 on normal return, or else -1 with error code in errno. */ _any_sds_fr_mem( bitptr sdsaddr, /* SDS bit address of data */ bitptr ubuf, /* user buffer to receive data */ int nbits /* number of bits to move */ ) { int sds_bit_offset; int sds_bit_offset_blk; int rbits; char localbuf[BYTPBLOCK]; bitptr locptr; long *uwaddr; char *ucaddr; sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); if (sds_bit_offset & (BITPBLOCK -1)) { /* The sds address is not on a block boundary. */ /* Read data from sds to a local buffer. Copy the */ /* user's memory to the appropriate part of the local */ /* buffer, and write it back out to sds. */ sds_bit_offset_blk = (sds_bit_offset & ~(BITPBLOCK - 1)); if (ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset_blk), 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } rbits = MIN(nbits, BITPBLOCK - (sds_bit_offset - sds_bit_offset_blk)); locptr = CPTR2BP(localbuf); SET_BPTR(locptr, INC_BPTR(locptr, sds_bit_offset - sds_bit_offset_blk)); MOV_BITS(locptr, ubuf, rbits); SET_BPTR(ubuf, INC_BPTR(ubuf, rbits)); nbits -= rbits; if(sswrite((int *)localbuf, BITS2BLOCKS(sds_bit_offset_blk), 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits)); if (nbits == 0) return(0); assert(((SUBT_BPTR(sdsaddr, WPTR2BP(0))) & (BITPBLOCK -1)) == 0); } sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); uwaddr = BPTR2WP(ubuf); ucaddr = BPTR2CP(ubuf); if ((nbits & (BITPBLOCK-1)) || (ucaddr != (char *)uwaddr)){ int left; locptr = CPTR2BP(localbuf); /* round down nbits to a block boundary */ rbits = nbits & ~(BITPBLOCK-1); if (rbits) { if (ucaddr != (char*)uwaddr) { /* ubuf is not word aligned. */ left = rbits; sds_bit_offset_blk = BITS2BLOCKS(sds_bit_offset); while (left > 0) { if( ssread((int *)localbuf, sds_bit_offset_blk, 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } MOV_BITS(locptr, ubuf, BITPBLOCK); SET_BPTR(ubuf, INC_BPTR(ubuf, BITPBLOCK)); if( sswrite((int *)localbuf, sds_bit_offset_blk, 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, BITPBLOCK)); sds_bit_offset_blk++; left-= BITPBLOCK; } } else { if (_sds_fr_mem(sdsaddr, ubuf, rbits) == -1) { return(-1); } SET_BPTR(ubuf, INC_BPTR(ubuf, rbits)); SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits)); } sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); } /* Get last block into local memory. Merge in user's memory */ /* and write it back out to sds. */ if( ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset), 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } MOV_BITS(locptr, ubuf, nbits - rbits); if( sswrite((int *)localbuf, BITS2BLOCKS(sds_bit_offset), 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } } else { if(sswrite(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(nbits)) == -1) { errno = FDC_ERR_SDSIO; return(-1); } } return(0); }
/* * _any_mem_fr_sds moves data into user memory from a secondary data segment (SDS). * * unlike _mem_fr_sds, _any_mem_fr_sds handles moving a number of bits that * may not be a multiple of 512. * * Returns 0 on normal return, or else -1 with error code in errno. */ _any_mem_fr_sds( bitptr ubuf, /* user buffer to receive data */ bitptr sdsaddr, /* SDS bit address of data */ int nbits /* number of bits to move */ ) { int sds_bit_offset; int sds_bit_offset_blk; int rbits; char localbuf[BYTPBLOCK]; bitptr locptr; long *uwaddr; char *ucaddr; sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); if (sds_bit_offset & (BITPBLOCK -1)) { /* The sds address is not on a block boundary. */ /* Read data from sds to a local buffer. Copy the */ /* appropriate part of the local buffer to user's memory. */ sds_bit_offset_blk = (sds_bit_offset & ~(BITPBLOCK - 1)); if(ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset_blk), 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } rbits = MIN(nbits, BITPBLOCK - (sds_bit_offset - sds_bit_offset_blk)); locptr = CPTR2BP(localbuf); SET_BPTR(locptr, INC_BPTR(locptr, sds_bit_offset - sds_bit_offset_blk)); MOV_BITS(ubuf, locptr, rbits); SET_BPTR(ubuf, INC_BPTR(ubuf, rbits)); nbits -= rbits; SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits)); if (nbits == 0) return(0); /* Verify that our sds address is now on a block boundary */ assert (((SUBT_BPTR(sdsaddr, WPTR2BP(0))) & (BITPBLOCK -1)) == 0); } sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); uwaddr = BPTR2WP(ubuf); ucaddr = BPTR2CP(ubuf); if ((nbits & (BITPBLOCK-1)) || (ucaddr != (char *)uwaddr)){ int left; /* Either we are not reading in a multiple of blocks or */ /* the user's address is not word-aligned. */ /* Round nbits down to a block boundary and */ /* move those to user's memory. */ locptr = CPTR2BP(localbuf); rbits = nbits & ~(BITPBLOCK-1); if (rbits) { if (ucaddr != (char*)uwaddr) { /* ubuf is not word aligned. */ /* Read the data from sds into a local */ /* buffer and copy to the user's memory */ left = rbits; sds_bit_offset_blk = BITS2BLOCKS(sds_bit_offset); while (left > 0) { if (ssread((int *)localbuf, sds_bit_offset_blk, 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } MOV_BITS(ubuf, locptr, BITPBLOCK); SET_BPTR(ubuf, INC_BPTR(ubuf, BITPBLOCK)); SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, BITPBLOCK)); sds_bit_offset_blk++; left-= BITPBLOCK; } } else { if (ssread(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(rbits)) == -1) { errno = FDC_ERR_SDSIO; return(-1); } SET_BPTR(ubuf, INC_BPTR(ubuf, rbits)); SET_BPTR(sdsaddr, INC_BPTR(sdsaddr, rbits)); } sds_bit_offset = SUBT_BPTR(sdsaddr, WPTR2BP(0)); } /* get last block into local memory and */ /* transfer to user's memory */ if (ssread((int *)localbuf, BITS2BLOCKS(sds_bit_offset), 1) == -1) { errno = FDC_ERR_SDSIO; return(-1); } assert((nbits - rbits) < BITPBLOCK); MOV_BITS(ubuf, locptr, nbits - rbits); } else { if(ssread(uwaddr, BITS2BLOCKS(sds_bit_offset), BITS2BLOCKS(nbits)) == -1) { errno = FDC_ERR_SDSIO; return(-1); } } return(0); }
_sdsset_any( int byte_offset, /* Byte offset into SDS area */ int value, /* Value to which all bytes should be set */ int nbytes) /* Number of bytes to set */ { #define _BUFFER_BLOCKS 10 char bytebuf[_BUFFER_BLOCKS * BYTPBLOCK]; /* must be word-aligned */ int nblocks; int blk_offset; int ret; int this_chunk; int left; int lblk_offset; int headbytes,tailbytes; int orig_byte_offset; orig_byte_offset = byte_offset; nblocks = BYTES2BLOCKS(nbytes); blk_offset = BYTES2BLOCKS(byte_offset); /* if byte_offset is not on a block boundary */ if ((byte_offset) & (BYTPBLOCK - 1)) { headbytes = BYTPBLOCK - (byte_offset & (BYTPBLOCK -1 )); if (headbytes > nbytes) headbytes = nbytes; ret = ssread(bytebuf, blk_offset, 1); if (ret == -1) { errno = FDC_ERR_SDSIO; return -1; } memset(bytebuf + (byte_offset & (BYTPBLOCK-1)), value, headbytes); ret = sswrite(bytebuf, blk_offset, 1); if (ret == -1) { errno = FDC_ERR_SDSIO; return -1; } nbytes -= headbytes; nblocks = BYTES2BLOCKS(nbytes); byte_offset += headbytes; blk_offset = BYTES2BLOCKS(byte_offset); } if (nbytes & (BYTPBLOCK - 1)){ /* these will be the bytes left over at the end */ tailbytes = nbytes & (BYTPBLOCK - 1); lblk_offset = BYTES2BLOCKS(byte_offset + nbytes -1); ret = ssread(bytebuf, lblk_offset, 1); if (ret == -1) { errno = FDC_ERR_SDSIO; return -1; } memset(bytebuf, value, tailbytes); ret = sswrite(bytebuf, lblk_offset, 1); if (ret == -1) { errno = FDC_ERR_SDSIO; return -1; } nbytes -= tailbytes; } if (nbytes & (BYTPBLOCK -1 )){ abort(); } (void)memset(bytebuf, value, MIN(nblocks, _BUFFER_BLOCKS) * BYTPBLOCK); left = nblocks; while (left > 0) { this_chunk = MIN(left, _BUFFER_BLOCKS); ret = sswrite((long)bytebuf, blk_offset, this_chunk); if (ret == -1) { errno = FDC_ERR_SDSIO; return -1; } left -= this_chunk; blk_offset += this_chunk; } return orig_byte_offset; }