1/* 2 * ntfs_quota.c - NTFS kernel quota ($Quota) handling. 3 * 4 * Copyright (c) 2006-2011 Anton Altaparmakov. All Rights Reserved. 5 * Portions Copyright (c) 2006-2011 Apple Inc. All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ALTERNATIVELY, provided that this notice and licensing terms are retained in 31 * full, this file may be redistributed and/or modified under the terms of the 32 * GNU General Public License (GPL) Version 2, in which case the provisions of 33 * that version of the GPL will apply to you instead of the license terms 34 * above. You can obtain a copy of the GPL Version 2 at 35 * http://developer.apple.com/opensource/licenses/gpl-2.txt. 36 */ 37 38#include <sys/errno.h> 39#include <sys/stat.h> 40#include <sys/ucred.h> 41#include <sys/vnode.h> 42 43#include "ntfs_debug.h" 44#include "ntfs_endian.h" 45#include "ntfs_index.h" 46#include "ntfs_inode.h" 47#include "ntfs_layout.h" 48#include "ntfs_quota.h" 49#include "ntfs_time.h" 50#include "ntfs_types.h" 51#include "ntfs_volume.h" 52 53/** 54 * ntfs_quotas_mark_out_of_date - mark the quotas out of date on an ntfs volume 55 * @vol: ntfs volume on which to mark the quotas out of date 56 * 57 * Mark the quotas out of date on the ntfs volume @vol and return 0 on success 58 * and errno on error. 59 */ 60errno_t ntfs_quotas_mark_out_of_date(ntfs_volume *vol) 61{ 62 ntfs_inode *quota_ni; 63 ntfs_index_context *ictx; 64 INDEX_ENTRY *ie; 65 QUOTA_CONTROL_ENTRY *qce; 66 const le32 qid = QUOTA_DEFAULTS_ID; 67 errno_t err; 68 69 ntfs_debug("Entering."); 70 if (NVolQuotaOutOfDate(vol)) 71 goto done; 72 quota_ni = vol->quota_ni; 73 if (!quota_ni || !vol->quota_q_ni) { 74 ntfs_error(vol->mp, "Quota inodes are not open."); 75 return EINVAL; 76 } 77 err = vnode_get(vol->quota_q_ni->vn); 78 if (err) { 79 ntfs_error(vol->mp, "Failed to get index vnode for " 80 "$Quota/$Q."); 81 return err; 82 } 83 lck_rw_lock_exclusive(&vol->quota_q_ni->lock); 84 ictx = ntfs_index_ctx_get(vol->quota_q_ni); 85 if (!ictx) { 86 ntfs_error(vol->mp, "Failed to get index context."); 87 err = ENOMEM; 88 goto err; 89 } 90 err = ntfs_index_lookup(&qid, sizeof(qid), &ictx); 91 if (err) { 92 if (err == ENOENT) 93 ntfs_error(vol->mp, "Quota defaults entry is not " 94 "present."); 95 else 96 ntfs_error(vol->mp, "Lookup of quota defaults entry " 97 "failed."); 98 goto err; 99 } 100 ie = ictx->entry; 101 if (le16_to_cpu(ie->data_length) < 102 offsetof(QUOTA_CONTROL_ENTRY, sid)) { 103 ntfs_error(vol->mp, "Quota defaults entry size is invalid. " 104 "Run chkdsk."); 105 err = EIO; 106 goto err; 107 } 108 qce = (QUOTA_CONTROL_ENTRY*)((u8*)ie + le16_to_cpu(ie->data_offset)); 109 if (le32_to_cpu(qce->version) != QUOTA_VERSION) { 110 ntfs_error(vol->mp, "Quota defaults entry version 0x%x is not " 111 "supported.", le32_to_cpu(qce->version)); 112 err = EIO; 113 goto err; 114 } 115 ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags)); 116 /* If quotas are already marked out of date, no need to do anything. */ 117 if (qce->flags & QUOTA_FLAG_OUT_OF_DATE) 118 goto set_done; 119 /* 120 * If quota tracking is neither requested nor enabled and there are no 121 * pending deletes, no need to mark the quotas out of date. 122 */ 123 if (!(qce->flags & (QUOTA_FLAG_TRACKING_ENABLED | 124 QUOTA_FLAG_TRACKING_REQUESTED | 125 QUOTA_FLAG_PENDING_DELETES))) 126 goto set_done; 127 /* 128 * Set the QUOTA_FLAG_OUT_OF_DATE bit thus marking quotas out of date. 129 * This is verified on WinXP to be sufficient to cause windows to 130 * rescan the volume on boot and update all quota entries. 131 */ 132 qce->flags |= QUOTA_FLAG_OUT_OF_DATE; 133 /* Ensure the modified flags are written to disk. */ 134 ntfs_index_entry_mark_dirty(ictx); 135 /* Update the atime, mtime and ctime of the base inode @quota_ni. */ 136 quota_ni->last_access_time = quota_ni->last_mft_change_time = 137 quota_ni->last_data_change_time = 138 ntfs_utc_current_time(); 139 NInoSetDirtyTimes(quota_ni); 140set_done: 141 ntfs_index_ctx_put(ictx); 142 lck_rw_unlock_exclusive(&vol->quota_q_ni->lock); 143 (void)vnode_put(vol->quota_q_ni->vn); 144 /* 145 * We set the flag so we do not try to mark the quotas out of date 146 * again on remount. 147 */ 148 NVolSetQuotaOutOfDate(vol); 149done: 150 ntfs_debug("Done."); 151 return 0; 152err: 153 if (ictx) 154 ntfs_index_ctx_put(ictx); 155 lck_rw_unlock_exclusive(&vol->quota_q_ni->lock); 156 (void)vnode_put(vol->quota_q_ni->vn); 157 return err; 158} 159