Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv28972
Added Files:
disk_io.c
Log Message:
Added disk io functions file.
--- NEW FILE ---
/*
* disk_io.c - Disk io functions. Part of the Linux-NTFS project.
*
* Copyright (c) 2000,2001 Anton Altaparmakov.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include <stdlib.h>
#include <linux/types.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "ntfs_rec.h"
#include "attrib.h"
#include "bitmap.h"
#include "volume.h"
__u64 ntfs_pwrite(int fd, const void *b, __u64 count, const __u64 pos)
{
__u64 written, total;
char retry;
if (!b) {
errno = EINVAL;
return -1;
}
if (!count)
return 0;
/* Locate to position. */
if (lseek(fd, pos, SEEK_SET) == (off_t)-1)
return -1;
/* Write the data. */
total = retry = 0;
do {
written = write(fd, ((char *)b) + total, count);
if (written == -1)
return written;
else if (!written)
++retry;
/* We just recycle count as a local variable here. */
count -= written;
total += written;
} while (count && (retry < 3));
/* Sync write to disk. */
if (fdatasync(fd) == -1)
return -1;
/* Finally return the number of bytes written. */
return total;
}
__u64 mst_pwrite(int fd, const void *b, __u64 count, const __u64 pos)
{
__u64 written, total;
char retry;
void *buf;
if (!b) {
errno = EINVAL;
return -1;
}
if (!count)
return 0;
/* Locate to position. */
if (lseek(fd, pos, SEEK_SET) == (off_t)-1)
return -1;
/* Get memory for copy of data. */
if (!(buf = malloc(count)))
return -1;
/* Make a copy of the data. */
memcpy(buf, b, count);
/* Prepare copied data for writing. */
if (pre_write_mst_fixup((NTFS_RECORD_HEADER*)buf, count)) {
__u16 *usn_pos;
__u16 usn;
/*
* Ok, need to update usn in original buffer (b) as well,
* otherwise two writes of the same data would result in the
* same usn being written on top of the same usn, which means
* no protection after first write and in fact it actually
* would cause corruption and not just lack of protection!!!
*/
usn_pos = (__u16*)((__u8*)b +
le16_to_cpu(((NTFS_RECORD_HEADER*)b)->usa_ofs));
usn = le16_to_cpup(usn_pos) + 1;
if (usn == 0xffff || !usn)
usn = 1;
*usn_pos = cpu_to_le16(usn);
}
/* Write the prepared data (copy). */
total = retry = 0;
do {
written = write(fd, ((char *)buf) + total, count);
if (written == -1) {
free(buf);
return written;
}
else if (!written)
++retry;
/* We just recycle count as a local variable here. */
count -= written;
total += written;
} while (count && (retry < 3));
/* Don't need the copy of the data anymore. */
free(buf);
/* Sync write to disk. */
if (fdatasync(fd) == -1)
return -1;
/* Finally return the number of bytes written. */
return total;
}
__u64 ntfs_pread(const int fd, void *b, const __u32 bksize, __u64 count,
const __u64 pos)
{
__u64 br, btr, total;
char bksize_bits;
/* Nothing to read so, return 0. */
if (!count || !bksize)
return 0;
/* Calculate bksize_bits. */
for (bksize_bits = 0, br = bksize; br > 1; br >>= 1)
++bksize_bits;
/* Check buffer. Only multiples of NTFS_SECTOR_SIZE and powers of
two are alowed for bksize. */
if (!b || (bksize_bits < NTFS_SECTOR_SIZE_BITS) ||
(bksize != 1 << bksize_bits)) {
#ifdef DEBUG
if (!b)
puts("ntfs_pread: b is NULL");
if (bksize_bits < NTFS_SECTOR_SIZE_BITS)
puts("ntfs_pread: bksize_bits < NTFS_SECTOR_SIZE_BITS");
if (bksize != 1 << bksize_bits)
puts("ntfs_pread: bksize != 1 << bksize_bits");
puts("Returning EINVAL");
#endif
errno = EINVAL;
return -1;
}
/* Locate to position. */
if (lseek(fd, pos, SEEK_SET) == (off_t)-1) {
#ifdef DEBUG
int eo = errno;
printf("ntfs_pread: lseek to 0x%Lx returned -1\n", pos);
errno = eo;
#endif
return -1;
}
/* Read the data. */
total = 0;
btr = count << bksize_bits;
/* Loop until we have read all data even if it happens only a byte at
a time. */
do {
br = read(fd, ((char *)b) + total, btr);
if (br == -1)
return br;
if (!br) {
/* Calculate the number of complete blocks read
(and recycle count as a local variable). */
count -= btr >> bksize_bits;
break;
}
btr -= br;
total += br;
} while (btr);
/* Finally, return the number of blocks read. */
return count;
}
__u64 mst_pread(const int fd, void *b, const __u32 bksize, __u64 count,
const __u64 pos)
{
__u64 br, i;
char bksize_bits;
/* Do the read. */
count = ntfs_pread(fd, b, bksize, count, pos);
/* Calculate bksize_bits. */
for (bksize_bits = 0, br = bksize; br > 1; br >>= 1)
++bksize_bits;
/* Apply fixups to successfully read data. Note, that we disregard
any errors returned from the MST fixup function. This is because we
want to fixup everything possible and we rely on the fact that the
"BAAD" magic will be detected later on anyway (before the data is
made use of). */
for (i = 0; i < count; ++i)
post_read_mst_fixup((NTFS_RECORD_HEADER*)(b +
(i << bksize_bits)), bksize);
/* Finally, return the number of blocks read. */
return count;
}
int get_clusters(const ntfs_volume *vol, __u8 *buf, const __s64 lcn,
const int count)
{
__u64 br;
if (!vol || !buf || count < 0 || lcn < 0)
return -EINVAL;
if (!vol->fd)
return -EBADF;
if (vol->number_of_clusters < lcn + count)
return -ESPIPE;
br = ntfs_pread(vol->fd, buf, vol->cluster_size, count,
lcn << vol->cluster_size_bits);
if (br != count) {
int eo = errno;
#define ESTR "Error reading cluster(s)"
if (br == -1) {
perror(ESTR);
return -eo;
} else if (!br)
fprintf(stderr, "Error: partition is smaller than "
"it should be!?! Weird!\n");
else
fprintf(stderr, ESTR ": unknown error\n");
#undef ESTR
return -EIO;
}
return br;
}
int put_clusters(ntfs_volume *vol, const __u8 *buf, const __s64 lcn, int count)
{
__u64 bw;
if (!vol || !buf || count < 0 || lcn < 0)
return -EINVAL;
if (!vol->fd)
return -EBADF;
if (vol->number_of_clusters < lcn + count)
return -ESPIPE;
bw = ntfs_pwrite(vol->fd, buf, count << vol->cluster_size_bits,
lcn << vol->cluster_size_bits);
if (bw != count << vol->cluster_size_bits) {
int eo = errno;
#define ESTR "Error writting cluster(s)"
if (bw == -1) {
perror(ESTR);
return -eo;
} else if (!bw)
fprintf(stderr, ESTR ": Ran out of input data!\n");
else
fprintf(stderr, ESTR ": unknown error\n");
#undef ESTR
return -EIO;
}
return bw >> vol->cluster_size_bits;
}
int get_mft_records(const ntfs_volume *vol, __u8 *buf, const __s64 mftrec,
const int count)
{
__u64 br;
__s64 lcn, ofs;
if (!vol || !buf || mftrec < 0)
return -EINVAL;
if (!vol->fd)
return -EBADF;
if (vol->number_of_mft_records < mftrec + count)
return -ESPIPE;
if (!get_bit(vol->mft_bitmap, mftrec))
return -ENOENT;
/* Size of mft record != size of cluster thus need to work with
offsets into clusters. */
if (vol->mft_records_per_cluster) {
lcn = vcn_to_lcn(vol->mft_runlist,
mftrec / vol->mft_records_per_cluster);
/* FIXME: Change "/" above and "%" below to ">>" and "&"
respectively! */
ofs = mftrec % vol->mft_records_per_cluster;
ofs <<= vol->mft_record_size_bits;
} else {
lcn = vcn_to_lcn(vol->mft_runlist,
mftrec * vol->clusters_per_mft_record);
/* FIXME: Change "*" above to "<<"! */
ofs = 0;
}
if (lcn < 0) {
int eo = errno;
perror("Error determining on disk location of $Mft record");
return -eo;
}
br = mst_pread(vol->fd, buf, vol->mft_record_size, count,
(lcn << vol->cluster_size_bits) + ofs);
if (br != count) {
int eo = errno;
#define ESTR "Error reading $Mft record"
if (br == -1) {
perror(ESTR);
return -eo;
} else if (!br)
fprintf(stderr, "Error: partition is smaller than "
"it should be!?! Weird!\n");
else
fprintf(stderr, ESTR ": unknown error\n");
#undef ESTR
return -EIO;
}
return br;
}
int put_mft_record(ntfs_volume *vol, const __u8 *buf, const __s64 mftrec)
{
__u64 bw;
__s64 lcn, ofs;
if (!vol || !buf || mftrec < 0)
return -EINVAL;
if (!vol->fd)
return -EBADF;
if (vol->number_of_mft_records <= mftrec)
return -ESPIPE;
if (!get_bit(vol->mft_bitmap, mftrec))
return -ENOENT;
/* Size of mft record != size of cluster thus need to work with offsets
into clusters. */
if (vol->mft_records_per_cluster) {
lcn = vcn_to_lcn(vol->mft_runlist,
mftrec / vol->mft_records_per_cluster);
/* FIXME: Change "/" above and "%" below to ">>" and "&"
respectively! */
ofs = mftrec % vol->mft_records_per_cluster;
ofs <<= vol->mft_record_size_bits;
} else {
lcn = vcn_to_lcn(vol->mft_runlist,
mftrec * vol->clusters_per_mft_record);
/* FIXME: Change "*" above to "<<"! */
ofs = 0;
}
if (lcn < 0) {
int eo = errno;
perror("Error determining on disk location of $Mft record");
return -eo;
}
bw = mst_pwrite(vol->fd, buf, vol->mft_record_size,
(lcn << vol->cluster_size_bits) + ofs);
if (bw != vol->mft_record_size) {
int eo = errno;
#define ESTR "Error writing $Mft record"
if (bw == -1) {
perror(ESTR);
return -eo;
} else if (!bw)
fprintf(stderr, ESTR ": Ran out of input data!\n");
else
fprintf(stderr, ESTR ": unknown error\n");
#undef ESTR
return -EIO;
}
return 1;
}
|