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 }