ntfs-3g/libntfs/mft.c
!flatcap 6593450759 whitespace and include guards
2002/07/08 06:23:22-00:00 !antona
Don't use string concatenation with __FUNCTION__ as gcc-3.x don't like it.

2002/07/07 19:44:57-00:00 !antona
Change ntfs_read_file_record() not to abort if the inode is not in use. Adapt callers which care to check this themselves.

2002/07/02 23:47:10-00:00 !antona
Global replacement of __[su]{8,16,32,64} with [su]{8,16,32,64} and layout.h define it.

2002/06/08 14:12:01-00:00 !antona
ntfs_readdir() has arrived.

2002/06/05 20:32:53-00:00 !antona
Mft mirror now updated from ntfs_write_mft_record, yey! Fixup ntfstools accordingly.

2002/06/01 00:41:45-00:00 !antona
huge update!

2002/04/27 19:49:09-00:00 !antona
Update library, new APIs ntfs_attr_find_vcn(), misc fixes and cleanups, make all the utilities compile, fix bugs I noticed in ntfslabel and it now works properly.

2002/04/24 23:47:42-00:00 !antona
Hammer out the API for run list merging. Add calls for low level (using raw run lists and ATTR_RECORDs as parameters) run list merging, mappaing pairs decompression, and vcn to lcn conversion as well as high level (using ntfs_attr as parameter) calls for run list mapping and vcn to lcn conversion.

2002/04/22 10:34:31-00:00 !antona
Attribute list support (merging done, part 2, some stuff still incomplete). mkntfs ntfs volume creation. See the changelog...

2002/04/20 23:09:42-00:00 !antona
Port attribute lookup functions with attribute list support from ntfs tng driver. Port/reimplement extent mft record handling code as well. Rename out all dollar signs from type names and constants. Adapt all callers to new API. Note mkntfs is currently broken due to some needed work.

2002/04/20 01:53:02-00:00 !antona
Rename mft code adding ntfs_ prefix. Change all return values to zero on success. Thanks to mattjf for pointing out the inconsistencies.

2002/04/16 12:13:53-00:00 !antona
New API function mft.[ch]::read_file_record(). Also some cleanups.

2002/04/15 20:04:27-00:00 !antona
Fix all compiler warnings that came up with -Wall. Enabled -Wall for ./configure --enable-debug everywhere. Fix a few bugs in mkntfs that came up in the warnings (just error code paths, nothing major).

2002/04/15 19:02:40-00:00 !antona
Really fix the library and mkntfs while at it.

2002/04/15 18:54:07-00:00 !antona
Update library for the new API.

2002/04/15 18:39:37-00:00 !antona
Cleanup some mistakes.

2002/04/15 17:51:26-00:00 !antona
read/write_mft_record(s) are here

2002/04/15 00:42:07-00:00 !antona
Big rewrite of disk_io.c. Now should have stable API for low level disk access. Move all mft record related stuff from disk_io.c to mft.c.

2002/04/14 14:08:30-00:00 !antona
Cleanup library code. Throw away unused stuff.

2002/04/14 13:34:49-00:00 !antona
Throw away all unnecessary crap.

2001/12/15 05:13:08-00:00 !antona
Remove atomic ops and add compiler version check.

2001/06/01 02:07:26-00:00 !antona
It has been a long time since last commit. At moment have done a lot of work
on mkntfs but also at the moment ntfsfix and ntfsdump_logfile and libntfs are
broken. Basically only mkntfs works and that is not complete either.

2001/04/11 14:29:12-00:00 !antona
Almost fixed compilaton. Remember to declare a struct type with
struct NAME { declaration }; rather than the bogus struct { declaration NAME };
then can use typedef NAME othername; on a forward declaration of NAME
(struct NAME;) and all is fine...

2001/04/11 11:49:16-00:00 !antona

Header file reorganisation so that it compiles.

2001/04/10 23:37:19-00:00 !antona
Ok, ntfsd was a mistake for userspace. It increases complexity no end while
not giving us much functionality. Lets get it working and then worry about the
kernel. - As it was the idea originally anyway, so this is just a return on the
right track. (-8

We keep the timer and signal handler but the only thing we do is to set a bool
flag (ntfs_need_sync) and we will just check this in appropriate places and
if it is true we call ntfs_sync_volumes() which sets it back to false. This
means no more locking at all of any description and no need to worry about the
signal handler interrupting things in bad ways and/or at bad times in the main
code.

2001/04/09 00:05:37-00:00 !antona
More or less finished file handling. (Probably some useful functions are
still missing but they will be implemented as need arises.)

One thing that is stupid at the moment is we don't limit the amount of
cached mft_records so if you were to load loads the machine would eventually
run out of memory... Can't happen with files as they are limited to 1000,
unless you are short of memory. (Hard limit at the moment, set in ntfs_mount().
Maybe ntfsd should be monitoring memory usage and be throwing out unused cache
entries and closed_files? That would mean to have locking everywhere, though.)

Still missing: - Convert old code to use new stuff. - Add non-resident
attributes somewhere. Either into the mft_entry structure or into the
ntfs_file structure, but which? At the moment I tend to mft_entry so they can
be synced together with the entries by ntfsd.

2001/04/08 01:58:29-00:00 !antona
User space conversion of locking complete. I settled for using simple spinlocks
and atomic variables and instead of deadlocking/livelocking when using
spin_lock(), use spin_trylock() in a while letting go of the cpu between each
call and making a maximum of 100 iterations (or we return EDEADLK error code).

This is not the most efficient way, especially as can't have multiple readers
but it is the simplest way to go about things.

Should now have (almost) all required helper functions for dealing with mft
entries implemented.

Now need the file handling and then convert the whole project to use the new
code and then can finally get back to work on attribute searching...

2001/04/05 20:14:45-00:00 !antona
Commit of current state of development including locking a la kernel.
This doesn't work on user space (semaphores don't work).
Just want to have it committed. Will take out locking / modify it where
necessary to use pthreads ASAP.

2001/04/03 23:38:34-00:00 !antona
Mark mft entry dirty function complete

2001/03/05 03:04:40-00:00 !antona
Corresponding changes to the library.

2001/01/25 22:25:43-00:00 !antona
More files added to ntfs lib. Fixed some consistency problems.

(Logical change 1.5)
2002-08-22 18:09:47 +00:00

236 lines
7.0 KiB
C

/*
* $Id$
*
* mft.c - Mft record handling code. Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2002 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 <stdlib.h>
#include <errno.h>
#include <string.h>
#include "mft.h"
#include "disk_io.h"
#include "debug.h"
#include "bitmap.h"
#include "attrib.h"
/**
* ntfs_read_mft_records - read records from the mft from disk
* @vol: volume to read from
* @mref: starting mft record number to read
* @count: number of mft records to read
* @b: output data buffer
*
* Read @count mft records starting at @mref from volume @vol into buffer
* @b. Return 0 on success or -1 on error, with errno set to the error
* code.
*
* The read mft records are mst deprotected and are hence ready to use. The
* caller should check each record with is_baad_record() in case mst
* deprotection failed.
*
* NOTE: @b has to be at least of size @count * vol->mft_record_size.
*/
int ntfs_read_mft_records(const ntfs_volume *vol, const MFT_REF mref,
const s64 count, MFT_RECORD *b)
{
s64 br;
VCN m;
Dprintf("%s(): Entering for inode 0x%Lx.\n", __FUNCTION__, MREF(mref));
if (!vol || !vol->mft_na || !b || count < 0) {
errno = EINVAL;
return -1;
}
m = MREF(mref);
if (m + count > vol->nr_mft_records) {
errno = ESPIPE;
return -1;
}
br = ntfs_attr_mst_pread(vol->mft_na, m << vol->mft_record_size_bits,
count, vol->mft_record_size, b);
if (br != count) {
if (br != -1)
errno = EIO;
if (br >= 0)
Dputs("Error: partition is smaller than it should be!");
else
Dperror("Error reading $Mft record(s)");
return -1;
}
return 0;
}
/**
* ntfs_write_mft_records - write mft records to disk
* @vol: volume to write to
* @mref: starting mft record number to write
* @count: number of mft records to write
* @b: data buffer containing the mft records to write
*
* Write @count mft records starting at @mref from data buffer @b to volume
* @vol. Return 0 on success or -1 on error, with errno set to the error code.
*
* Before the mft records are written, they are mst protected. After the write,
* they are deprotected again, thus resulting in an increase in the update
* sequence number inside the data buffer @b.
*
* If any mft records are written which are also represented in the mft mirror
* $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a
* temporary buffer before we do the actual write. Then if at least one mft
* record was successfully written, we write the appropriate mft records from
* the copied buffer to the mft mirror, too.
*/
int ntfs_write_mft_records(const ntfs_volume *vol, const MFT_REF mref,
const s64 count, MFT_RECORD *b)
{
s64 bw;
VCN m;
void *bmirr = NULL;
int cnt = 0, res = 0;
Dprintf("%s(): Entering for inode 0x%Lx.\n", __FUNCTION__, MREF(mref));
if (!vol || !vol->mft_na || !b || count < 0) {
errno = EINVAL;
return -1;
}
m = MREF(mref);
if (m < vol->mftmirr_size) {
cnt = vol->mftmirr_size - m;
bmirr = malloc(cnt * vol->mft_record_size);
if (!bmirr)
return -1;
memcpy(bmirr, b, cnt * vol->mft_record_size);
}
if (m + count > vol->nr_mft_records) {
// TODO: Need to extend $MFT. This is not just normal attribute
// extension as many rules need to be observed. (AIA)
if (bmirr);
free(bmirr);
errno = ENOTSUP;
return -1;
}
bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits,
count, vol->mft_record_size, b);
if (bw != count) {
if (bw != -1)
errno = EIO;
if (bw >= 0)
Dputs("Error: partial write while writing $Mft "
"record(s)!\n");
else
Dperror("Error writing $Mft record(s)");
res = errno;
}
if (bmirr && bw > 0) {
if (bw < cnt)
cnt = bw;
bw = ntfs_attr_mst_pwrite(vol->mftmirr_na,
m << vol->mft_record_size_bits, cnt,
vol->mft_record_size, bmirr);
if (bw != cnt) {
if (bw != -1)
errno = EIO;
Dputs("Error: failed to sync $MFTMirr! Run chkdsk.");
res = errno;
}
}
if (bmirr)
free(bmirr);
if (!res)
return res;
errno = res;
return -1;
}
/**
* ntfs_read_file_record - read a FILE record from the mft from disk
* @vol: volume to read from
* @mref: mft reference specifying mft record to read
* @mrec: address of pointer in which to return the mft record
* @attr: address of pointer in which to return the first attribute
*
* Read a FILE record from the mft of @vol from the storage medium. @mref
* specifies the mft record to read, including the sequence number, which can
* be 0 if no sequence number checking is to be performed.
*
* The function allocates a buffer large enough to hold the mft record and
* reads the record into the buffer (mst deprotecting it in the process).
* *@mrec is then set to point to the buffer.
*
* If @attr is not NULL, *@attr is set to point to the first attribute in the
* mft record, i.e. *@attr is a pointer into *@mrec.
*
* Return 0 on success, or -1 on error, with errno set to the error code.
*
* The read mft record is checked for having the magic FILE,
* and for having a matching sequence number (if MSEQNO(*@mref) != 0).
* If either of these fails, -1 is returned and errno is set to EIO. If you get
* this, but you still want to read the mft record (e.g. in order to correct
* it), use ntfs_read_mft_record() directly.
*
* Note: Caller has to free *@mrec when finished.
*
* Note: We do not check if the mft record is flagged in use. The caller can
* check if desired.
*/
int ntfs_read_file_record(const ntfs_volume *vol, const MFT_REF mref,
MFT_RECORD **mrec, ATTR_RECORD **attr)
{
MFT_RECORD *m;
ATTR_RECORD *a;
int err;
if (!vol || !mrec) {
errno = EINVAL;
return -1;
}
m = *mrec;
if (!m) {
m = (MFT_RECORD*)malloc(vol->mft_record_size);
if (!m)
return -1;
}
if (ntfs_read_mft_record(vol, mref, m)) {
err = errno;
goto read_failed;
}
if (!is_file_record(m->magic))
goto file_corrupt;
if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number))
goto file_corrupt;
a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)
goto file_corrupt;
*mrec = m;
if (attr)
*attr = a;
return 0;
file_corrupt:
Dputs("ntfs_read_file_record(): file is corrupt.");
err = EIO;
read_failed:
if (m != *mrec)
free(m);
errno = err;
return -1;
}