/** * ntfs_cluster_write - write ntfs clusters * @vol: volume to write to * @lcn: starting logical cluster number * @count: number of clusters to write * @b: data buffer to write to disk * * Write @count ntfs clusters starting at logical cluster number @lcn from * buffer @b to volume @vol. Return the number of clusters written or -1 on * error, with errno set to the error code. */ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, const s64 count, const void *b) { s64 bw; if (!vol || lcn < 0 || count < 0) { errno = EINVAL; return -1; } if (vol->nr_clusters < lcn + count) { errno = ESPIPE; ntfs_log_perror("Trying to write outside of volume " "(%lld < %lld)", (long long)vol->nr_clusters, (long long)lcn + count); return -1; } if (!NVolReadOnly(vol)) bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits, count << vol->cluster_size_bits, b); else bw = count << vol->cluster_size_bits; if (bw < 0) { ntfs_log_perror("Error writing cluster(s)"); return bw; } return bw >> vol->cluster_size_bits; }
/** * ntfs_mst_pwrite - multi sector transfer (mst) positioned write * @dev: device to write to * @pos: position in file descriptor to write to * @count: number of blocks to write * @bksize: size of each block that needs mst protecting * @b: data buffer to write to disk * * Multi sector transfer (mst) positioned write. This function will write * @count blocks of size @bksize bytes each from data buffer @b to the device * @dev at position @pos. * * On success, return the number of successfully written blocks. If this number * is lower than @count this means that the write has been interrupted or that * an error was encountered during the write so that the write is partial. 0 * means nothing was written (also return 0 when @count or @bksize are 0). * * On error and nothing has been written, return -1 with errno set * appropriately to the return code of either seek, write, or set * to EINVAL in case of invalid arguments. * * NOTE: We mst protect the data, write it, then mst deprotect it using a quick * deprotect algorithm (no checking). This saves us from making a copy before * the write and at the same time causes the usn to be incremented in the * buffer. This conceptually fits in better with the idea that cached data is * always deprotected and protection is performed when the data is actually * going to hit the disk and the cache is immediately deprotected again * simulating an mst read on the written data. This way cache coherency is * achieved. */ s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b) { s64 written, i; if (count < 0 || bksize % NTFS_BLOCK_SIZE) { errno = EINVAL; return -1; } if (!count) return 0; /* Prepare data for writing. */ for (i = 0; i < count; ++i) { int err; err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) ((u8*)b + i * bksize), bksize); if (err < 0) { /* Abort write at this position. */ if (!i) return err; count = i; break; } } /* Write the prepared data. */ written = ntfs_pwrite(dev, pos, count * bksize, b); /* Quickly deprotect the data again. */ for (i = 0; i < count; ++i) ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize)); if (written <= 0) return written; /* Finally, return the number of complete blocks written. */ return written / bksize; }
static int ntfs_inner_zero(ntfs_attr *na, runlist_element *rl) { ntfs_volume *vol; char *buf; runlist_element *zrl; s64 cofs; s64 pos; s64 zeroed; int err; err = 0; vol = na->ni->vol; buf = (char*)malloc(vol->cluster_size); if (buf) { memset(buf, 0, vol->cluster_size); zrl = rl; pos = zrl->vcn << vol->cluster_size_bits; while (zrl->length && !err && (pos < na->initialized_size)) { for (cofs=0; cofs<zrl->length && !err; cofs++) { zeroed = ntfs_pwrite(vol->dev, (rl->lcn + cofs) << vol->cluster_size_bits, vol->cluster_size, buf); if (zeroed != vol->cluster_size) { ntfs_log_error("Failed to zero at " "offset %lld\n", (long long)pos); errno = EIO; err = -1; } pos += vol->cluster_size; } zrl++; pos = zrl->vcn << vol->cluster_size_bits; } free(buf); } else { ntfs_log_error("Failed to allocate memory\n"); errno = ENOSPC; err = -1; } return (err); }
static int change_serial(ntfs_volume *vol, u64 sector, le64 serial_number, NTFS_BOOT_SECTOR *bs, NTFS_BOOT_SECTOR *oldbs) { int res; le64 mask; BOOL same; res = -1; if ((ntfs_pread(vol->dev, sector << vol->sector_size_bits, vol->sector_size, bs) == vol->sector_size)) { same = TRUE; if (!sector) /* save the real bootsector */ memcpy(oldbs, bs, vol->sector_size); else /* backup bootsector must be similar */ same = !memcmp(oldbs, bs, vol->sector_size); if (same) { if (opts.new_serial & 2) bs->volume_serial_number = serial_number; else { mask = const_cpu_to_le64(~0x0ffffffffULL); bs->volume_serial_number = (serial_number & mask) | (bs->volume_serial_number & ~mask); } if (opts.noaction || (ntfs_pwrite(vol->dev, sector << vol->sector_size_bits, vol->sector_size, bs) == vol->sector_size)) { res = 0; } } else { ntfs_log_info("* Warning : the backup boot sector" " does not match (leaving unchanged)\n"); res = 0; } } return (res); }