From 70e5b1b2506e585adbdd8ffc85feaeb5954f8704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 23 Apr 2014 09:53:13 +0200 Subject: [PATCH] Fixed inserting a new ACL after they have been wiped out by chkdsk chkdsk deletes the ACLs when they are bad or when they are not used any more. This fixes inserting a new ACL after the previously last ACL (or even all of them) was deleted. --- include/ntfs-3g/attrib.h | 2 ++ libntfs-3g/attrib.c | 36 ++++++++++++++++++++++++++++++++ libntfs-3g/security.c | 45 ++++++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index 846bc9e1..b3752a60 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -396,6 +396,8 @@ extern int ntfs_attr_data_read(ntfs_inode *ni, extern int ntfs_attr_data_write(ntfs_inode *ni, ntfschar *stream_name, int stream_name_len, const char *buf, size_t size, off_t offset); +extern int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name, + int stream_name_len, off_t offset); #endif /* defined _NTFS_ATTRIB_H */ diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index 4b2be1bb..77b1f03a 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -6735,6 +6735,42 @@ exit: return res; } +/* + * Shrink the size of a data attribute if needed + * + * For non-resident attributes only. + * The space remains allocated. + * + * Returns 0 if successful + * -1 if failed, with errno telling why + */ + + +int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name, + int stream_name_len, off_t offset) +{ + ntfs_attr_search_ctx *ctx; + ATTR_RECORD *a; + int res; + + res = -1; + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (ctx) { + if (!ntfs_attr_lookup(AT_DATA, stream_name, stream_name_len, + CASE_SENSITIVE, 0, NULL, 0, ctx)) { + a = ctx->attr; + + if (a->non_resident + && (sle64_to_cpu(a->initialized_size) > offset)) { + a->initialized_size = cpu_to_le64(offset); + a->data_size = a->initialized_size; + } + res = 0; + } + ntfs_attr_put_search_ctx(ctx); + } + return (res); +} int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, const ntfschar *name, u32 name_len) diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index a42b38b6..bf8fd6e0 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -4,7 +4,7 @@ * Copyright (c) 2004 Anton Altaparmakov * Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2006 Yura Pakhuchiy - * Copyright (c) 2007-2012 Jean-Pierre Andre + * Copyright (c) 2007-2014 Jean-Pierre Andre * * 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 @@ -514,8 +514,18 @@ static int entersecurity_data(ntfs_volume *vol, STREAM_SDS, 4, fullattr, fullsz, offs - gap + ALIGN_SDS_BLOCK); if ((written1 == fullsz) - && (written2 == written1)) - res = 0; + && (written2 == written1)) { + /* + * Make sure the data size for $SDS marks the end + * of the last security attribute. Windows uses + * this to determine where the next attribute will + * be written, which causes issues if chkdsk had + * previously deleted the last entries without + * adjusting the size. + */ + res = ntfs_attr_shrink_size(vol->secure_ni,STREAM_SDS, + 4, offs - gap + ALIGN_SDS_BLOCK + fullsz); + } else errno = ENOSPC; free(fullattr); @@ -707,10 +717,24 @@ static le32 entersecurityattr(ntfs_volume *vol, sizeof(SII_INDEX_KEY), xsii); if (!found && (errno != ENOENT)) { ntfs_log_perror("Index $SII is broken"); + psii = (struct SII*)NULL; } else { /* restore errno */ errno = olderrno; entry = xsii->entry; + psii = (struct SII*)entry; + } + if (psii + && !(psii->flags & INDEX_ENTRY_END)) { + /* save first key and */ + /* available position */ + keyid = psii->keysecurid; + realign.parts.dataoffsh + = psii->dataoffsh; + realign.parts.dataoffsl + = psii->dataoffsl; + offs = le64_to_cpu(realign.all); + size = le32_to_cpu(psii->datasize); } retries++; } @@ -725,7 +749,8 @@ static le32 entersecurityattr(ntfs_volume *vol, securid = const_cpu_to_le32(0); na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4); if (na) { - if ((size_t)na->data_size < sizeof(struct SII)) { + if ((size_t)na->data_size < (sizeof(struct SII) + + sizeof(INDEX_ENTRY_HEADER))) { ntfs_log_error("Creating the first security_id\n"); securid = const_cpu_to_le32(FIRST_SECURITY_ID); } @@ -1814,11 +1839,13 @@ static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni) * with a default security descriptor inserted in an * attribute */ - if (test_nino_flag(ni, v3_Extensions) - && vol->secure_ni && ni->security_id) { - /* get v3.x descriptor in $Secure */ - securid.security_id = ni->security_id; - securattr = retrievesecurityattr(vol,securid); + if (test_nino_flag(ni, v3_Extensions) && vol->secure_ni) { + if (ni->security_id) { + /* get v3.x descriptor in $Secure */ + securid.security_id = ni->security_id; + securattr = retrievesecurityattr(vol,securid); + } else + securattr = (char*)NULL; if (!securattr) ntfs_log_error("Bad security descriptor for 0x%lx\n", (long)le32_to_cpu(ni->security_id));