2 * mft.c - Mft record handling code. Part of the Linux-NTFS project.
4 * Copyright (c) 2000-2003 Anton Altaparmakov
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (in the main directory of the Linux-NTFS
18 * distribution in the file COPYING); if not, write to the Free Software
19 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 * ntfs_mft_records_read - read records from the mft from disk
41 * @vol: volume to read from
42 * @mref: starting mft record number to read
43 * @count: number of mft records to read
44 * @b: output data buffer
46 * Read @count mft records starting at @mref from volume @vol into buffer
47 * @b. Return 0 on success or -1 on error, with errno set to the error
50 * The read mft records are mst deprotected and are hence ready to use. The
51 * caller should check each record with is_baad_record() in case mst
52 * deprotection failed.
54 * NOTE: @b has to be at least of size @count * vol->mft_record_size.
56 int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
57 const s64 count, MFT_RECORD *b)
62 Dprintf("%s(): Entering for inode 0x%Lx.\n", __FUNCTION__, MREF(mref));
63 if (!vol || !vol->mft_na || !b || count < 0) {
68 if (m + count > vol->nr_mft_records) {
72 br = ntfs_attr_mst_pread(vol->mft_na, m << vol->mft_record_size_bits,
73 count, vol->mft_record_size, b);
78 Dputs("Error: partition is smaller than it should be!");
80 Dperror("Error reading $Mft record(s)");
87 * ntfs_mft_records_write - write mft records to disk
88 * @vol: volume to write to
89 * @mref: starting mft record number to write
90 * @count: number of mft records to write
91 * @b: data buffer containing the mft records to write
93 * Write @count mft records starting at @mref from data buffer @b to volume
94 * @vol. Return 0 on success or -1 on error, with errno set to the error code.
96 * Before the mft records are written, they are mst protected. After the write,
97 * they are deprotected again, thus resulting in an increase in the update
98 * sequence number inside the data buffer @b.
100 * If any mft records are written which are also represented in the mft mirror
101 * $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a
102 * temporary buffer before we do the actual write. Then if at least one mft
103 * record was successfully written, we write the appropriate mft records from
104 * the copied buffer to the mft mirror, too.
106 int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
107 const s64 count, MFT_RECORD *b)
112 int cnt = 0, res = 0;
114 Dprintf("%s(): Entering for inode 0x%Lx.\n", __FUNCTION__, MREF(mref));
115 if (!vol || !vol->mft_na || !b || count < 0) {
120 if (m < vol->mftmirr_size) {
121 cnt = vol->mftmirr_size - m;
124 bmirr = malloc(cnt * vol->mft_record_size);
127 memcpy(bmirr, b, cnt * vol->mft_record_size);
129 if (m + count > vol->nr_mft_records) {
130 // TODO: Need to extend $MFT. This is not just normal attribute
131 // extension as many rules need to be observed. (AIA)
137 bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits,
138 count, vol->mft_record_size, b);
143 Dputs("Error: partial write while writing $Mft "
146 Dperror("Error writing $Mft record(s)");
149 if (bmirr && bw > 0) {
152 bw = ntfs_attr_mst_pwrite(vol->mftmirr_na,
153 m << vol->mft_record_size_bits, cnt,
154 vol->mft_record_size, bmirr);
158 Dputs("Error: failed to sync $MFTMirr! Run chkdsk.");
171 * ntfs_file_record_read - read a FILE record from the mft from disk
172 * @vol: volume to read from
173 * @mref: mft reference specifying mft record to read
174 * @mrec: address of pointer in which to return the mft record
175 * @attr: address of pointer in which to return the first attribute
177 * Read a FILE record from the mft of @vol from the storage medium. @mref
178 * specifies the mft record to read, including the sequence number, which can
179 * be 0 if no sequence number checking is to be performed.
181 * The function allocates a buffer large enough to hold the mft record and
182 * reads the record into the buffer (mst deprotecting it in the process).
183 * *@mrec is then set to point to the buffer.
185 * If @attr is not NULL, *@attr is set to point to the first attribute in the
186 * mft record, i.e. *@attr is a pointer into *@mrec.
188 * Return 0 on success, or -1 on error, with errno set to the error code.
190 * The read mft record is checked for having the magic FILE,
191 * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
192 * If either of these fails, -1 is returned and errno is set to EIO. If you get
193 * this, but you still want to read the mft record (e.g. in order to correct
194 * it), use ntfs_mft_record_read() directly.
196 * Note: Caller has to free *@mrec when finished.
198 * Note: We do not check if the mft record is flagged in use. The caller can
201 int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
202 MFT_RECORD **mrec, ATTR_RECORD **attr)
214 m = (MFT_RECORD*)malloc(vol->mft_record_size);
218 if (ntfs_mft_record_read(vol, mref, m)) {
222 if (!ntfs_is_file_record(m->magic))
224 if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number))
226 a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
227 if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)
234 Dputs("ntfs_file_record_read(): file is corrupt.");
244 * ntfs_mft_record_alloc - allocate an mft record on an ntfs volume
245 * @vol: mounted ntfs volume on which to allocate the mft record
246 * @start: starting mft record at which to allocate (or -1 if none)
248 * Allocate an mft record in $MFT/$DATA starting to search for a free record
249 * at mft record number @start or at the current allocator position if
250 * @start_mref is -1, on the mounted ntfs volume @vol.
252 * On success return the now opened ntfs inode of the mft record.
254 * On error return NULL with errno set to the error code.
256 ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, u64 start)
258 if (!vol || !vol->mftbmp_na) {
268 * ntfs_mft_record_free - free an mft record on an ntfs volume
269 * @vol: mounted ntfs volume on which to free the mft record
270 * @ni: open ntfs inode of the mft record to free
272 * Free the mft record of the open inode @ni on the mounted ntfs volume @vol.
273 * Note that this function calls ntfs_inode_close() internally and hence you
274 * cannot use the pointer @ni any more after this function returns success.
276 * On success return 0 and on error return -1 with errno set to the error code.
278 int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
283 if (!vol || !vol->mftbmp_na || !ni) {
288 /* Cache the mft reference for later. */
291 /* Mark the mft record as not in use. */
292 ni->mrec->flags &= ~MFT_RECORD_IN_USE;
294 /* Increment the sequence number, skipping zero, if it is not zero. */
295 seq_no = le16_to_cpu(ni->mrec->sequence_number);
296 if (seq_no == 0xffff)
300 ni->mrec->sequence_number = cpu_to_le16(seq_no);
302 /* Set the inode dirty and close it so it is written out. */
303 ntfs_inode_mark_dirty(ni);
304 if (ntfs_inode_close(ni)) {
306 // FIXME: Eeek! We need rollback! (AIA)
307 fprintf(stderr, "%s(): Eeek! Failed to close the inode."
308 "Leaving inconsistent metadata!\n",
314 /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
315 if (ntfs_bitmap_clear_run(vol->mftbmp_na, mft_no, 1)) {
316 // FIXME: Eeek! We need rollback! (AIA)
317 fprintf(stderr, "%s(): Eeek! Failed to clear the allocation "
318 "in the mft bitmap. Leaving deleted mft record "
319 "marked as in use in the mft bitmap and "
320 "pretending we succeeded. Error: %s\n",
321 __FUNCTION__, strerror(errno));