1 /**
   2  * logfile.c - NTFS journal handling. Part of the Linux-NTFS project.
   3  *
   4  * Copyright (c) 2002-2005 Anton Altaparmakov
   5  * Copyright (c) 2005 Yura Pakhuchiy
   6  *
   7  * This program/include file is free software; you can redistribute it and/or
   8  * modify it under the terms of the GNU General Public License as published
   9  * by the Free Software Foundation; either version 2 of the License, or
  10  * (at your option) any later version.
  11  *
  12  * This program/include file is distributed in the hope that it will be
  13  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  *
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program (in the main directory of the Linux-NTFS
  19  * distribution in the file COPYING); if not, write to the Free Software
  20  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21  */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include "config.h"
  25 #endif
  26 
  27 #ifdef HAVE_STDLIB_H
  28 #include <stdlib.h>
  29 #endif
  30 #ifdef HAVE_STRING_H
  31 #include <string.h>
  32 #endif
  33 #ifdef HAVE_ERRNO_H
  34 #include <errno.h>
  35 #endif
  36 
  37 #include "compat.h"
  38 #include "attrib.h"
  39 #include "debug.h"
  40 #include "logfile.h"
  41 #include "volume.h"
  42 #include "mst.h"
  43 #include "logging.h"
  44 
  45 /**
  46  * ntfs_check_restart_page_header - check the page header for consistency
  47  * @rp:         restart page header to check
  48  * @pos:        position in logfile at which the restart page header resides
  49  *
  50  * Check the restart page header @rp for consistency and return TRUE if it is
  51  * consistent and FALSE otherwise.
  52  *
  53  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
  54  * require the full restart page.
  55  */
  56 static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
  57 {
  58         u32 logfile_system_page_size, logfile_log_page_size;
  59         u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
  60         BOOL have_usa = TRUE;
  61 
  62         ntfs_log_trace("Entering.\n");
  63         /*
  64          * If the system or log page sizes are smaller than the ntfs block size
  65          * or either is not a power of 2 we cannot handle this log file.
  66          */
  67         logfile_system_page_size = le32_to_cpu(rp->system_page_size);
  68         logfile_log_page_size = le32_to_cpu(rp->log_page_size);
  69         if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
  70                         logfile_log_page_size < NTFS_BLOCK_SIZE ||
  71                         logfile_system_page_size &
  72                         (logfile_system_page_size - 1) ||
  73                         logfile_log_page_size & (logfile_log_page_size - 1)) {
  74                 ntfs_log_error("$LogFile uses unsupported page size.\n");
  75                 return FALSE;
  76         }
  77         /*
  78          * We must be either at !pos (1st restart page) or at pos = system page
  79          * size (2nd restart page).
  80          */
  81         if (pos && pos != logfile_system_page_size) {
  82                 ntfs_log_error("Found restart area in incorrect "
  83                                 "position in $LogFile.\n");
  84                 return FALSE;
  85         }
  86         /* We only know how to handle version 1.1. */
  87         if (sle16_to_cpu(rp->major_ver) != 1 ||
  88                         sle16_to_cpu(rp->minor_ver) != 1) {
  89                 ntfs_log_error("$LogFile version %i.%i is not "
  90                                 "supported.  (This driver supports version "
  91                                 "1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
  92                                 (int)sle16_to_cpu(rp->minor_ver));
  93                 return FALSE;
  94         }
  95         /*
  96          * If chkdsk has been run the restart page may not be protected by an
  97          * update sequence array.
  98          */
  99         if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
 100                 have_usa = FALSE;
 101                 goto skip_usa_checks;
 102         }
 103         /* Verify the size of the update sequence array. */
 104         usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
 105         if (usa_count != le16_to_cpu(rp->usa_count)) {
 106                 ntfs_log_error("$LogFile restart page specifies "
 107                                 "inconsistent update sequence array count.\n");
 108                 return FALSE;
 109         }
 110         /* Verify the position of the update sequence array. */
 111         usa_ofs = le16_to_cpu(rp->usa_ofs);
 112         usa_end = usa_ofs + usa_count * sizeof(u16);
 113         if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
 114                         usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
 115                 ntfs_log_error("$LogFile restart page specifies "
 116                                 "inconsistent update sequence array offset.\n");
 117                 return FALSE;
 118         }
 119 skip_usa_checks:
 120         /*
 121          * Verify the position of the restart area.  It must be:
 122          *      - aligned to 8-byte boundary,
 123          *      - after the update sequence array, and
 124          *      - within the system page size.
 125          */
 126         ra_ofs = le16_to_cpu(rp->restart_area_offset);
 127         if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
 128                         ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
 129                         ra_ofs > logfile_system_page_size) {
 130                 ntfs_log_error("$LogFile restart page specifies "
 131                                 "inconsistent restart area offset.\n");
 132                 return FALSE;
 133         }
 134         /*
 135          * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
 136          * set.
 137          */
 138         if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
 139                 ntfs_log_error("$LogFile restart page is not modified "
 140                                 "by chkdsk but a chkdsk LSN is specified.\n");
 141                 return FALSE;
 142         }
 143         ntfs_log_trace("Done.\n");
 144         return TRUE;
 145 }
 146 
 147 /**
 148  * ntfs_check_restart_area - check the restart area for consistency
 149  * @rp:         restart page whose restart area to check
 150  *
 151  * Check the restart area of the restart page @rp for consistency and return
 152  * TRUE if it is consistent and FALSE otherwise.
 153  *
 154  * This function assumes that the restart page header has already been
 155  * consistency checked.
 156  *
 157  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
 158  * require the full restart page.
 159  */
 160 static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
 161 {
 162         u64 file_size;
 163         RESTART_AREA *ra;
 164         u16 ra_ofs, ra_len, ca_ofs;
 165         u8 fs_bits;
 166 
 167         ntfs_log_trace("Entering.\n");
 168         ra_ofs = le16_to_cpu(rp->restart_area_offset);
 169         ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
 170         /*
 171          * Everything before ra->file_size must be before the first word
 172          * protected by an update sequence number.  This ensures that it is
 173          * safe to access ra->client_array_offset.
 174          */
 175         if (ra_ofs + offsetof(RESTART_AREA, file_size) >
 176                         NTFS_BLOCK_SIZE - sizeof(u16)) {
 177                 ntfs_log_error("$LogFile restart area specifies "
 178                                 "inconsistent file offset.\n");
 179                 return FALSE;
 180         }
 181         /*
 182          * Now that we can access ra->client_array_offset, make sure everything
 183          * up to the log client array is before the first word protected by an
 184          * update sequence number.  This ensures we can access all of the
 185          * restart area elements safely.  Also, the client array offset must be
 186          * aligned to an 8-byte boundary.
 187          */
 188         ca_ofs = le16_to_cpu(ra->client_array_offset);
 189         if (((ca_ofs + 7) & ~7) != ca_ofs ||
 190                         ra_ofs + ca_ofs > (u16)(NTFS_BLOCK_SIZE -
 191                         sizeof(u16))) {
 192                 ntfs_log_error("$LogFile restart area specifies "
 193                                 "inconsistent client array offset.\n");
 194                 return FALSE;
 195         }
 196         /*
 197          * The restart area must end within the system page size both when
 198          * calculated manually and as specified by ra->restart_area_length.
 199          * Also, the calculated length must not exceed the specified length.
 200          */
 201         ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
 202                         sizeof(LOG_CLIENT_RECORD);
 203         if ((u32)(ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) ||
 204                         (u32)(ra_ofs + le16_to_cpu(ra->restart_area_length)) >
 205                         le32_to_cpu(rp->system_page_size) ||
 206                         ra_len > le16_to_cpu(ra->restart_area_length)) {
 207                 ntfs_log_error("$LogFile restart area is out of bounds "
 208                                 "of the system page size specified by the "
 209                                 "restart page header and/or the specified "
 210                                 "restart area length is inconsistent.\n");
 211                 return FALSE;
 212         }
 213         /*
 214          * The ra->client_free_list and ra->client_in_use_list must be either
 215          * LOGFILE_NO_CLIENT or less than ra->log_clients or they are
 216          * overflowing the client array.
 217          */
 218         if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
 219                         le16_to_cpu(ra->client_free_list) >=
 220                         le16_to_cpu(ra->log_clients)) ||
 221                         (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
 222                         le16_to_cpu(ra->client_in_use_list) >=
 223                         le16_to_cpu(ra->log_clients))) {
 224                 ntfs_log_error("$LogFile restart area specifies "
 225                                 "overflowing client free and/or in use lists.\n");
 226                 return FALSE;
 227         }
 228         /*
 229          * Check ra->seq_number_bits against ra->file_size for consistency.
 230          * We cannot just use ffs() because the file size is not a power of 2.
 231          */
 232         file_size = (u64)sle64_to_cpu(ra->file_size);
 233         fs_bits = 0;
 234         while (file_size) {
 235                 file_size >>= 1;
 236                 fs_bits++;
 237         }
 238         if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
 239                 ntfs_log_error("$LogFile restart area specifies "
 240                                 "inconsistent sequence number bits.\n");
 241                 return FALSE;
 242         }
 243         /* The log record header length must be a multiple of 8. */
 244         if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
 245                         le16_to_cpu(ra->log_record_header_length)) {
 246                 ntfs_log_error("$LogFile restart area specifies "
 247                                 "inconsistent log record header length.\n");
 248                 return FALSE;
 249         }
 250         /* Ditto for the log page data offset. */
 251         if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
 252                         le16_to_cpu(ra->log_page_data_offset)) {
 253                 ntfs_log_error("$LogFile restart area specifies "
 254                                 "inconsistent log page data offset.\n");
 255                 return FALSE;
 256         }
 257         ntfs_log_trace("Done.\n");
 258         return TRUE;
 259 }
 260 
 261 /**
 262  * ntfs_check_log_client_array - check the log client array for consistency
 263  * @rp:         restart page whose log client array to check
 264  *
 265  * Check the log client array of the restart page @rp for consistency and
 266  * return TRUE if it is consistent and FALSE otherwise.
 267  *
 268  * This function assumes that the restart page header and the restart area have
 269  * already been consistency checked.
 270  *
 271  * Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this
 272  * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
 273  * restart page and the page must be multi sector transfer deprotected.
 274  */
 275 static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
 276 {
 277         RESTART_AREA *ra;
 278         LOG_CLIENT_RECORD *ca, *cr;
 279         u16 nr_clients, idx;
 280         BOOL in_free_list, idx_is_first;
 281 
 282         ntfs_log_trace("Entering.\n");
 283         ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
 284         ca = (LOG_CLIENT_RECORD*)((u8*)ra +
 285                         le16_to_cpu(ra->client_array_offset));
 286         /*
 287          * Check the ra->client_free_list first and then check the
 288          * ra->client_in_use_list.  Check each of the log client records in
 289          * each of the lists and check that the array does not overflow the
 290          * ra->log_clients value.  Also keep track of the number of records
 291          * visited as there cannot be more than ra->log_clients records and
 292          * that way we detect eventual loops in within a list.
 293          */
 294         nr_clients = le16_to_cpu(ra->log_clients);
 295         idx = le16_to_cpu(ra->client_free_list);
 296         in_free_list = TRUE;
 297 check_list:
 298         for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
 299                         idx = le16_to_cpu(cr->next_client)) {
 300                 if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
 301                         goto err_out;
 302                 /* Set @cr to the current log client record. */
 303                 cr = ca + idx;
 304                 /* The first log client record must not have a prev_client. */
 305                 if (idx_is_first) {
 306                         if (cr->prev_client != LOGFILE_NO_CLIENT)
 307                                 goto err_out;
 308                         idx_is_first = FALSE;
 309                 }
 310         }
 311         /* Switch to and check the in use list if we just did the free list. */
 312         if (in_free_list) {
 313                 in_free_list = FALSE;
 314                 idx = le16_to_cpu(ra->client_in_use_list);
 315                 goto check_list;
 316         }
 317         ntfs_log_trace("Done.\n");
 318         return TRUE;
 319 err_out:
 320         ntfs_log_error("$LogFile log client array is corrupt.\n");
 321         return FALSE;
 322 }
 323 
 324 /**
 325  * ntfs_check_and_load_restart_page - check the restart page for consistency
 326  * @log_na:     opened ntfs attribute for journal $LogFile
 327  * @rp:         restart page to check
 328  * @pos:        position in @log_na at which the restart page resides
 329  * @wrp:       [OUT] copy of the multi sector transfer deprotected restart page
 330  * @lsn:       [OUT] set to the current logfile lsn on success
 331  *
 332  * Check the restart page @rp for consistency and return 0 if it is consistent
 333  * and errno otherwise.  The restart page may have been modified by chkdsk in
 334  * which case its magic is CHKD instead of RSTR.
 335  *
 336  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
 337  * require the full restart page.
 338  *
 339  * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
 340  * copy of the complete multi sector transfer deprotected page.  On failure,
 341  * *@wrp is undefined.
 342  *
 343  * Similarly, if @lsn is not NULL, on success *@lsn will be set to the current
 344  * logfile lsn according to this restart page.  On failure, *@lsn is undefined.
 345  *
 346  * The following error codes are defined:
 347  *     EINVAL - The restart page is inconsistent.
 348  *     ENOMEM - Not enough memory to load the restart page.
 349  *     EIO    - Failed to reading from $LogFile.
 350  */
 351 static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
 352                 RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
 353                 LSN *lsn)
 354 {
 355         RESTART_AREA *ra;
 356         RESTART_PAGE_HEADER *trp;
 357         int err;
 358 
 359         ntfs_log_trace("Entering.\n");
 360         /* Check the restart page header for consistency. */
 361         if (!ntfs_check_restart_page_header(rp, pos)) {
 362                 /* Error output already done inside the function. */
 363                 return EINVAL;
 364         }
 365         /* Check the restart area for consistency. */
 366         if (!ntfs_check_restart_area(rp)) {
 367                 /* Error output already done inside the function. */
 368                 return EINVAL;
 369         }
 370         ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
 371         /*
 372          * Allocate a buffer to store the whole restart page so we can multi
 373          * sector transfer deprotect it.
 374          */
 375         trp = ntfs_malloc(le32_to_cpu(rp->system_page_size));
 376         if (!trp)
 377                 return ENOMEM;
 378         /*
 379          * Read the whole of the restart page into the buffer.  If it fits
 380          * completely inside @rp, just copy it from there.  Otherwise read it
 381          * from disk.
 382          */
 383         if (le32_to_cpu(rp->system_page_size) <= NTFS_BLOCK_SIZE)
 384                 memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
 385         else if (ntfs_attr_pread(log_na, pos,
 386                         le32_to_cpu(rp->system_page_size), trp) !=
 387                         le32_to_cpu(rp->system_page_size)) {
 388                 err = errno;
 389                 ntfs_log_error("Failed to read whole restart page into the "
 390                                 "buffer.\n");
 391                 if (err != ENOMEM)
 392                         err = EIO;
 393                 goto err_out;
 394         }
 395         /*
 396          * Perform the multi sector transfer deprotection on the buffer if the
 397          * restart page is protected.
 398          */
 399         if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
 400                         && ntfs_mst_post_read_fixup((NTFS_RECORD*)trp,
 401                         le32_to_cpu(rp->system_page_size))) {
 402                 /*
 403                  * A multi sector tranfer error was detected.  We only need to
 404                  * abort if the restart page contents exceed the multi sector
 405                  * transfer fixup of the first sector.
 406                  */
 407                 if (le16_to_cpu(rp->restart_area_offset) +
 408                                 le16_to_cpu(ra->restart_area_length) >
 409                                 NTFS_BLOCK_SIZE - (int)sizeof(u16)) {
 410                         ntfs_log_error("Multi sector transfer error "
 411                                    "detected in $LogFile restart page.\n");
 412                         err = EINVAL;
 413                         goto err_out;
 414                 }
 415         }
 416         /*
 417          * If the restart page is modified by chkdsk or there are no active
 418          * logfile clients, the logfile is consistent.  Otherwise, need to
 419          * check the log client records for consistency, too.
 420          */
 421         err = 0;
 422         if (ntfs_is_rstr_record(rp->magic) &&
 423                         ra->client_in_use_list != LOGFILE_NO_CLIENT) {
 424                 if (!ntfs_check_log_client_array(trp)) {
 425                         err = EINVAL;
 426                         goto err_out;
 427                 }
 428         }
 429         if (lsn) {
 430                 if (ntfs_is_rstr_record(rp->magic))
 431                         *lsn = sle64_to_cpu(ra->current_lsn);
 432                 else /* if (ntfs_is_chkd_record(rp->magic)) */
 433                         *lsn = sle64_to_cpu(rp->chkdsk_lsn);
 434         }
 435         ntfs_log_trace("Done.\n");
 436         if (wrp)
 437                 *wrp = trp;
 438         else {
 439 err_out:
 440                 free(trp);
 441         }
 442         return err;
 443 }
 444 
 445 /**
 446  * ntfs_check_logfile - check in the journal if the volume is consistent
 447  * @log_na:     ntfs attribute of loaded journal $LogFile to check
 448  * @rp:         [OUT] on success this is a copy of the current restart page
 449  *
 450  * Check the $LogFile journal for consistency and return TRUE if it is
 451  * consistent and FALSE if not.  On success, the current restart page is
 452  * returned in *@rp.  Caller must call ntfs_free(*@rp) when finished with it.
 453  *
 454  * At present we only check the two restart pages and ignore the log record
 455  * pages.
 456  *
 457  * Note that the MstProtected flag is not set on the $LogFile inode and hence
 458  * when reading pages they are not deprotected.  This is because we do not know
 459  * if the $LogFile was created on a system with a different page size to ours
 460  * yet and mst deprotection would fail if our page size is smaller.
 461  */
 462 BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
 463 {
 464         s64 size, pos;
 465         LSN rstr1_lsn, rstr2_lsn;
 466         ntfs_volume *vol = log_na->ni->vol;
 467         u8 *kaddr = NULL;
 468         RESTART_PAGE_HEADER *rstr1_ph = NULL;
 469         RESTART_PAGE_HEADER *rstr2_ph = NULL;
 470         int log_page_size, log_page_mask, err;
 471         BOOL logfile_is_empty = TRUE;
 472         u8 log_page_bits;
 473 
 474         ntfs_log_trace("Entering.\n");
 475         /* An empty $LogFile must have been clean before it got emptied. */
 476         if (NVolLogFileEmpty(vol))
 477                 goto is_empty;
 478         size = log_na->data_size;
 479         /* Make sure the file doesn't exceed the maximum allowed size. */
 480         if (size > (s64)MaxLogFileSize)
 481                 size = MaxLogFileSize;
 482         log_page_size = DefaultLogPageSize;
 483         log_page_mask = log_page_size - 1;
 484         /*
 485          * Use generic_ffs() instead of ffs() to enable the compiler to
 486          * optimize log_page_size and log_page_bits into constants.
 487          */
 488         log_page_bits = ffs(log_page_size) - 1;
 489         size &= ~(log_page_size - 1);
 490 
 491         /*
 492          * Ensure the log file is big enough to store at least the two restart
 493          * pages and the minimum number of log record pages.
 494          */
 495         if (size < log_page_size * 2 || (size - log_page_size * 2) >>
 496                         log_page_bits < MinLogRecordPages) {
 497                 ntfs_log_error("$LogFile is too small.\n");
 498                 return FALSE;
 499         }
 500         /* Allocate memory for restart page. */
 501         kaddr = ntfs_malloc(NTFS_BLOCK_SIZE);
 502         if (!kaddr)
 503                 return FALSE;
 504         /*
 505          * Read through the file looking for a restart page.  Since the restart
 506          * page header is at the beginning of a page we only need to search at
 507          * what could be the beginning of a page (for each page size) rather
 508          * than scanning the whole file byte by byte.  If all potential places
 509          * contain empty and uninitialized records, the log file can be assumed
 510          * to be empty.
 511          */
 512         for (pos = 0; pos < size; pos <<= 1) {
 513                 /*
 514                  * Read first NTFS_BLOCK_SIZE bytes of potential restart page.
 515                  */
 516                 if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) !=
 517                                 NTFS_BLOCK_SIZE) {
 518                         ntfs_log_error("Failed to read first NTFS_BLOCK_SIZE "
 519                                         "bytes of potential restart page.\n");
 520                         goto err_out;
 521                 }
 522 
 523                 /*
 524                  * A non-empty block means the logfile is not empty while an
 525                  * empty block after a non-empty block has been encountered
 526                  * means we are done.
 527                  */
 528                 if (!ntfs_is_empty_recordp((le32*)kaddr))
 529                         logfile_is_empty = FALSE;
 530                 else if (!logfile_is_empty)
 531                         break;
 532                 /*
 533                  * A log record page means there cannot be a restart page after
 534                  * this so no need to continue searching.
 535                  */
 536                 if (ntfs_is_rcrd_recordp((le32*)kaddr))
 537                         break;
 538                 /* If not a (modified by chkdsk) restart page, continue. */
 539                 if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
 540                                 !ntfs_is_chkd_recordp((le32*)kaddr)) {
 541                         if (!pos)
 542                                 pos = NTFS_BLOCK_SIZE >> 1;
 543                         continue;
 544                 }
 545                 /*
 546                  * Check the (modified by chkdsk) restart page for consistency
 547                  * and get a copy of the complete multi sector transfer
 548                  * deprotected restart page.
 549                  */
 550                 err = ntfs_check_and_load_restart_page(log_na,
 551                                 (RESTART_PAGE_HEADER*)kaddr, pos,
 552                                 !rstr1_ph ? &rstr1_ph : &rstr2_ph,
 553                                 !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
 554                 if (!err) {
 555                         /*
 556                          * If we have now found the first (modified by chkdsk)
 557                          * restart page, continue looking for the second one.
 558                          */
 559                         if (!pos) {
 560                                 pos = NTFS_BLOCK_SIZE >> 1;
 561                                 continue;
 562                         }
 563                         /*
 564                          * We have now found the second (modified by chkdsk)
 565                          * restart page, so we can stop looking.
 566                          */
 567                         break;
 568                 }
 569                 /*
 570                  * Error output already done inside the function.  Note, we do
 571                  * not abort if the restart page was invalid as we might still
 572                  * find a valid one further in the file.
 573                  */
 574                 if (err != EINVAL)
 575                       goto err_out;
 576                 /* Continue looking. */
 577                 if (!pos)
 578                         pos = NTFS_BLOCK_SIZE >> 1;
 579         }
 580         if (kaddr) {
 581                 free(kaddr);
 582                 kaddr = NULL;
 583         }
 584         if (logfile_is_empty) {
 585                 NVolSetLogFileEmpty(vol);
 586 is_empty:
 587                 ntfs_log_trace("Done.  ($LogFile is empty.)\n");
 588                 return TRUE;
 589         }
 590         if (!rstr1_ph) {
 591                 if (rstr2_ph)
 592                         ntfs_log_error("BUG: rstr2_ph isn't NULL!\n");
 593                 ntfs_log_error("Did not find any restart pages in "
 594                            "$LogFile and it was not empty.\n");
 595                 return FALSE;
 596         }
 597         /* If both restart pages were found, use the more recent one. */
 598         if (rstr2_ph) {
 599                 /*
 600                  * If the second restart area is more recent, switch to it.
 601                  * Otherwise just throw it away.
 602                  */
 603                 if (rstr2_lsn > rstr1_lsn) {
 604                         ntfs_log_debug("Using second restart page as it is more "
 605                                         "recent.\n");
 606                         free(rstr1_ph);
 607                         rstr1_ph = rstr2_ph;
 608                         /* rstr1_lsn = rstr2_lsn; */
 609                 } else {
 610                         ntfs_log_debug("Using first restart page as it is more "
 611                                         "recent.\n");
 612                         free(rstr2_ph);
 613                 }
 614                 rstr2_ph = NULL;
 615         }
 616         /* All consistency checks passed. */
 617         if (rp)
 618                 *rp = rstr1_ph;
 619         else
 620                 free(rstr1_ph);
 621         ntfs_log_trace("Done.\n");
 622         return TRUE;
 623 err_out:
 624         free(kaddr);
 625         free(rstr1_ph);
 626         free(rstr2_ph);
 627         return FALSE;
 628 }
 629 
 630 /**
 631  * ntfs_is_logfile_clean - check in the journal if the volume is clean
 632  * @log_na:     ntfs attribute of loaded journal $LogFile to check
 633  * @rp:         copy of the current restart page
 634  *
 635  * Analyze the $LogFile journal and return TRUE if it indicates the volume was
 636  * shutdown cleanly and FALSE if not.
 637  *
 638  * At present we only look at the two restart pages and ignore the log record
 639  * pages.  This is a little bit crude in that there will be a very small number
 640  * of cases where we think that a volume is dirty when in fact it is clean.
 641  * This should only affect volumes that have not been shutdown cleanly but did
 642  * not have any pending, non-check-pointed i/o, i.e. they were completely idle
 643  * at least for the five seconds preceding the unclean shutdown.
 644  *
 645  * This function assumes that the $LogFile journal has already been consistency
 646  * checked by a call to ntfs_check_logfile() and in particular if the $LogFile
 647  * is empty this function requires that NVolLogFileEmpty() is true otherwise an
 648  * empty volume will be reported as dirty.
 649  */
 650 BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
 651 {
 652         RESTART_AREA *ra;
 653 
 654         ntfs_log_trace("Entering.\n");
 655         /* An empty $LogFile must have been clean before it got emptied. */
 656         if (NVolLogFileEmpty(log_na->ni->vol)) {
 657                 ntfs_log_trace("Done.  ($LogFile is empty.)\n");
 658                 return TRUE;
 659         }
 660         if (!rp) {
 661                 ntfs_log_error("Restart page header is NULL.\n");
 662                 return FALSE;
 663         }
 664         if (!ntfs_is_rstr_record(rp->magic) &&
 665                         !ntfs_is_chkd_record(rp->magic)) {
 666                 ntfs_log_error("Restart page buffer is invalid.  This is "
 667                            "probably a bug in that the $LogFile should "
 668                            "have been consistency checked before calling "
 669                            "this function.\n");
 670                 return FALSE;
 671         }
 672 
 673         ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
 674         /*
 675          * If the $LogFile has active clients, i.e. it is open, and we do not
 676          * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
 677          * we assume there was an unclean shutdown.
 678          */
 679         if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
 680                         !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
 681                 ntfs_log_debug("Done.  $LogFile indicates a dirty shutdown.\n");
 682                 return FALSE;
 683         }
 684         /* $LogFile indicates a clean shutdown. */
 685         ntfs_log_trace("Done.  $LogFile indicates a clean shutdown.\n");
 686         return TRUE;
 687 }
 688 
 689 /**
 690  * ntfs_empty_logfile - empty the contents of the $LogFile journal
 691  * @na:         ntfs attribute of journal $LogFile to empty
 692  *
 693  * Empty the contents of the $LogFile journal @na and return 0 on success and
 694  * -1 on error.
 695  *
 696  * This function assumes that the $LogFile journal has already been consistency
 697  * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
 698  * has been used to ensure that the $LogFile is clean.
 699  */
 700 int ntfs_empty_logfile(ntfs_attr *na)
 701 {
 702         s64 len, pos, count;
 703         char buf[NTFS_BUF_SIZE];
 704         int err;
 705 
 706         ntfs_log_trace("Entering.\n");
 707         if (NVolLogFileEmpty(na->ni->vol))
 708                 goto done;
 709 
 710         /* The $DATA attribute of the $LogFile has to be non-resident. */
 711         if (!NAttrNonResident(na)) {
 712                 err = EIO;
 713                 ntfs_log_debug("$LogFile $DATA attribute is resident!?!\n");
 714                 goto io_error_exit;
 715         }
 716 
 717         /* Get length of $LogFile contents. */
 718         len = na->data_size;
 719         if (!len) {
 720                 ntfs_log_debug("$LogFile has zero length, no disk write "
 721                                 "needed.\n");
 722                 return 0;
 723         }
 724 
 725         /* Read $LogFile until its end. We do this as a check for correct
 726            length thus making sure we are decompressing the mapping pairs
 727            array correctly and hence writing below is safe as well. */
 728         pos = 0;
 729         while ((count = ntfs_attr_pread(na, pos, NTFS_BUF_SIZE, buf)) > 0)
 730                 pos += count;
 731 
 732         if (count == -1 || pos != len) {
 733                 err = errno;
 734                 ntfs_log_debug("Amount of $LogFile data read does not "
 735                                 "correspond to expected length!\n");
 736                 if (count != -1)
 737                         err = EIO;
 738                 goto io_error_exit;
 739         }
 740 
 741         /* Fill the buffer with 0xff's. */
 742         memset(buf, -1, NTFS_BUF_SIZE);
 743 
 744         /* Set the $DATA attribute. */
 745         pos = 0;
 746         while ((count = len - pos) > 0) {
 747                 if (count > NTFS_BUF_SIZE)
 748                         count = NTFS_BUF_SIZE;
 749 
 750                 if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) {
 751                         err = errno;
 752                         ntfs_log_debug("Failed to set the $LogFile attribute "
 753                                         "value.\n");
 754                         if (count != -1)
 755                                 err = EIO;
 756                         goto io_error_exit;
 757                 }
 758                 pos += count;
 759         }
 760 
 761         /* Set the flag so we do not have to do it again on remount. */
 762         NVolSetLogFileEmpty(na->ni->vol);
 763 done:
 764         ntfs_log_trace("Done.\n");
 765         return 0;
 766 io_error_exit:
 767         errno = err;
 768         return -1;
 769 }