1*11963SAfshin.Ardakani@Sun.COM /* 2*11963SAfshin.Ardakani@Sun.COM * CDDL HEADER START 3*11963SAfshin.Ardakani@Sun.COM * 4*11963SAfshin.Ardakani@Sun.COM * The contents of this file are subject to the terms of the 5*11963SAfshin.Ardakani@Sun.COM * Common Development and Distribution License (the "License"). 6*11963SAfshin.Ardakani@Sun.COM * You may not use this file except in compliance with the License. 7*11963SAfshin.Ardakani@Sun.COM * 8*11963SAfshin.Ardakani@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*11963SAfshin.Ardakani@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*11963SAfshin.Ardakani@Sun.COM * See the License for the specific language governing permissions 11*11963SAfshin.Ardakani@Sun.COM * and limitations under the License. 12*11963SAfshin.Ardakani@Sun.COM * 13*11963SAfshin.Ardakani@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*11963SAfshin.Ardakani@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*11963SAfshin.Ardakani@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*11963SAfshin.Ardakani@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*11963SAfshin.Ardakani@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*11963SAfshin.Ardakani@Sun.COM * 19*11963SAfshin.Ardakani@Sun.COM * CDDL HEADER END 20*11963SAfshin.Ardakani@Sun.COM */ 21*11963SAfshin.Ardakani@Sun.COM /* 22*11963SAfshin.Ardakani@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*11963SAfshin.Ardakani@Sun.COM * Use is subject to license terms. 24*11963SAfshin.Ardakani@Sun.COM */ 25*11963SAfshin.Ardakani@Sun.COM #include <stdio.h> 26*11963SAfshin.Ardakani@Sun.COM #include <stdlib.h> 27*11963SAfshin.Ardakani@Sun.COM #include <fcntl.h> 28*11963SAfshin.Ardakani@Sun.COM #include <attr.h> 29*11963SAfshin.Ardakani@Sun.COM #include <unistd.h> 30*11963SAfshin.Ardakani@Sun.COM #include <libuutil.h> 31*11963SAfshin.Ardakani@Sun.COM #include <libzfs.h> 32*11963SAfshin.Ardakani@Sun.COM #include <assert.h> 33*11963SAfshin.Ardakani@Sun.COM #include <stddef.h> 34*11963SAfshin.Ardakani@Sun.COM #include <strings.h> 35*11963SAfshin.Ardakani@Sun.COM #include <errno.h> 36*11963SAfshin.Ardakani@Sun.COM #include <synch.h> 37*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_xdr.h> 38*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/ntstatus.h> 39*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/libmlsvc.h> 40*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_idmap.h> 41*11963SAfshin.Ardakani@Sun.COM #include <mlsvc.h> 42*11963SAfshin.Ardakani@Sun.COM #include <sys/avl.h> 43*11963SAfshin.Ardakani@Sun.COM 44*11963SAfshin.Ardakani@Sun.COM /* 45*11963SAfshin.Ardakani@Sun.COM * smb_quota subsystem interface - mlsvc.h 46*11963SAfshin.Ardakani@Sun.COM * --------------------------------------- 47*11963SAfshin.Ardakani@Sun.COM * Management of the smb_quota_fs_list (see below). 48*11963SAfshin.Ardakani@Sun.COM * smb_quota_init 49*11963SAfshin.Ardakani@Sun.COM * smb_quota_fini 50*11963SAfshin.Ardakani@Sun.COM * smb_quota_add_fs 51*11963SAfshin.Ardakani@Sun.COM * smb_quota_remove_fs 52*11963SAfshin.Ardakani@Sun.COM * 53*11963SAfshin.Ardakani@Sun.COM * smb_quota public interface - libmlsvc.h 54*11963SAfshin.Ardakani@Sun.COM * --------------------------------------- 55*11963SAfshin.Ardakani@Sun.COM * Handling of requests to query and set quota data on a filesystem. 56*11963SAfshin.Ardakani@Sun.COM * smb_quota_query - query user/group quotas on a filesystem 57*11963SAfshin.Ardakani@Sun.COM * smb_quota_set - set user/group quotas ona filesystem 58*11963SAfshin.Ardakani@Sun.COM * smb_quota_free - delete the quota list created in smb_quota_query 59*11963SAfshin.Ardakani@Sun.COM */ 60*11963SAfshin.Ardakani@Sun.COM 61*11963SAfshin.Ardakani@Sun.COM /* 62*11963SAfshin.Ardakani@Sun.COM * Querying user & group quotas - smb_quota_query 63*11963SAfshin.Ardakani@Sun.COM * 64*11963SAfshin.Ardakani@Sun.COM * In order to fulfill the quota query requests that can be received 65*11963SAfshin.Ardakani@Sun.COM * from clients, it is required that the quota data can be provided in 66*11963SAfshin.Ardakani@Sun.COM * a well defined and consistent order, and that a request can specify 67*11963SAfshin.Ardakani@Sun.COM * at which quota entry to begin the query. 68*11963SAfshin.Ardakani@Sun.COM * 69*11963SAfshin.Ardakani@Sun.COM * Quota Tree 70*11963SAfshin.Ardakani@Sun.COM * Since the file system does not support the above, an avl tree is 71*11963SAfshin.Ardakani@Sun.COM * populated with the file system's user and group quota data, and 72*11963SAfshin.Ardakani@Sun.COM * then used to provide the data to respond to query requests. The 73*11963SAfshin.Ardakani@Sun.COM * avl tree is indexed by the SID. 74*11963SAfshin.Ardakani@Sun.COM * Each node of the avl tree is an smb_quota_t structure. 75*11963SAfshin.Ardakani@Sun.COM * 76*11963SAfshin.Ardakani@Sun.COM * Quota List 77*11963SAfshin.Ardakani@Sun.COM * There is a list of avl trees, one per file system. 78*11963SAfshin.Ardakani@Sun.COM * Each node in the list is an smb_quota_tree_t structure. 79*11963SAfshin.Ardakani@Sun.COM * The list is created via a call to smb_quota_init() when the library 80*11963SAfshin.Ardakani@Sun.COM * is initialized, and destroyed via a call to smb_quota_fini() when 81*11963SAfshin.Ardakani@Sun.COM * the library is fini'd. 82*11963SAfshin.Ardakani@Sun.COM * 83*11963SAfshin.Ardakani@Sun.COM * An avl tree for a specific file system is created and added to the 84*11963SAfshin.Ardakani@Sun.COM * list via a call to smb_quota_add_fs() when the file system is shared, 85*11963SAfshin.Ardakani@Sun.COM * and removed from the list via a call to smb_quota_remove_fs() when 86*11963SAfshin.Ardakani@Sun.COM * the file system is unshared. 87*11963SAfshin.Ardakani@Sun.COM * 88*11963SAfshin.Ardakani@Sun.COM * An avl tree is (re)populated, if required, whenever a quota request 89*11963SAfshin.Ardakani@Sun.COM * (EXCLUDING a resume request) is received for its filesystem. The 90*11963SAfshin.Ardakani@Sun.COM * avl tree is considered to be expired (needs to be repopulated) if 91*11963SAfshin.Ardakani@Sun.COM * either of the following have occurred since it was last (re)populated: 92*11963SAfshin.Ardakani@Sun.COM * - SMB_QUOTA_REFRESH seconds have elapsed OR 93*11963SAfshin.Ardakani@Sun.COM * - a quota set operation has been performed on its file system 94*11963SAfshin.Ardakani@Sun.COM * 95*11963SAfshin.Ardakani@Sun.COM * In order to perform a smb_quota_query/set operation on a file system 96*11963SAfshin.Ardakani@Sun.COM * the appropriate quota tree must be identified and locked via a call 97*11963SAfshin.Ardakani@Sun.COM * to smb_quota_tree_lookup(), The quota tree is locked (qt_locked == B_TRUE) 98*11963SAfshin.Ardakani@Sun.COM * until the caller releases it via a call to smb_quota_tree_release(). 99*11963SAfshin.Ardakani@Sun.COM */ 100*11963SAfshin.Ardakani@Sun.COM 101*11963SAfshin.Ardakani@Sun.COM /* 102*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_t 103*11963SAfshin.Ardakani@Sun.COM * Represents an avl tree of user quotas for a file system. 104*11963SAfshin.Ardakani@Sun.COM * 105*11963SAfshin.Ardakani@Sun.COM * qt_refcnt - a count of the number of users of the tree. 106*11963SAfshin.Ardakani@Sun.COM * qt_refcnt is also incremented and decremented when the tree is 107*11963SAfshin.Ardakani@Sun.COM * added to and removed from the quota list. 108*11963SAfshin.Ardakani@Sun.COM * The tree cannot be deleted until this count is zero. 109*11963SAfshin.Ardakani@Sun.COM * 110*11963SAfshin.Ardakani@Sun.COM * qt_sharecnt - a count of the shares of the file system which the 111*11963SAfshin.Ardakani@Sun.COM * tree represents. smb_quota_remove_fs() cannot remove the tree from 112*11963SAfshin.Ardakani@Sun.COM * removed from the quota list until this count is zero. 113*11963SAfshin.Ardakani@Sun.COM * 114*11963SAfshin.Ardakani@Sun.COM * qt_locked - B_TRUE if someone is currently using the tree, in 115*11963SAfshin.Ardakani@Sun.COM * which case a lookup will wait for the tree to become available. 116*11963SAfshin.Ardakani@Sun.COM */ 117*11963SAfshin.Ardakani@Sun.COM typedef struct smb_quota_tree { 118*11963SAfshin.Ardakani@Sun.COM list_node_t qt_node; 119*11963SAfshin.Ardakani@Sun.COM char *qt_path; 120*11963SAfshin.Ardakani@Sun.COM time_t qt_timestamp; 121*11963SAfshin.Ardakani@Sun.COM uint32_t qt_refcnt; 122*11963SAfshin.Ardakani@Sun.COM uint32_t qt_sharecnt; 123*11963SAfshin.Ardakani@Sun.COM boolean_t qt_locked; 124*11963SAfshin.Ardakani@Sun.COM avl_tree_t qt_avl; 125*11963SAfshin.Ardakani@Sun.COM mutex_t qt_mutex; 126*11963SAfshin.Ardakani@Sun.COM }smb_quota_tree_t; 127*11963SAfshin.Ardakani@Sun.COM 128*11963SAfshin.Ardakani@Sun.COM /* 129*11963SAfshin.Ardakani@Sun.COM * smb_quota_fs_list 130*11963SAfshin.Ardakani@Sun.COM * list of quota trees; one per shared file system. 131*11963SAfshin.Ardakani@Sun.COM */ 132*11963SAfshin.Ardakani@Sun.COM static list_t smb_quota_fs_list; 133*11963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_list_init = B_FALSE; 134*11963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_shutdown = B_FALSE; 135*11963SAfshin.Ardakani@Sun.COM static mutex_t smb_quota_list_mutex; 136*11963SAfshin.Ardakani@Sun.COM static cond_t smb_quota_list_condvar; 137*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_tree_cnt = 0; 138*11963SAfshin.Ardakani@Sun.COM static int smb_quota_fini_timeout = 1; /* seconds */ 139*11963SAfshin.Ardakani@Sun.COM 140*11963SAfshin.Ardakani@Sun.COM /* 141*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_handle_t 142*11963SAfshin.Ardakani@Sun.COM * handle to zfs library and dataset 143*11963SAfshin.Ardakani@Sun.COM */ 144*11963SAfshin.Ardakani@Sun.COM typedef struct smb_quota_zfs_handle { 145*11963SAfshin.Ardakani@Sun.COM libzfs_handle_t *z_lib; 146*11963SAfshin.Ardakani@Sun.COM zfs_handle_t *z_fs; 147*11963SAfshin.Ardakani@Sun.COM } smb_quota_zfs_handle_t; 148*11963SAfshin.Ardakani@Sun.COM 149*11963SAfshin.Ardakani@Sun.COM /* 150*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_arg_t 151*11963SAfshin.Ardakani@Sun.COM * arg passed to zfs callback when querying quota properties 152*11963SAfshin.Ardakani@Sun.COM */ 153*11963SAfshin.Ardakani@Sun.COM typedef struct smb_quota_zfs_arg { 154*11963SAfshin.Ardakani@Sun.COM zfs_userquota_prop_t qa_prop; 155*11963SAfshin.Ardakani@Sun.COM avl_tree_t *qa_avl; 156*11963SAfshin.Ardakani@Sun.COM } smb_quota_zfs_arg_t; 157*11963SAfshin.Ardakani@Sun.COM 158*11963SAfshin.Ardakani@Sun.COM static void smb_quota_add_ctrldir(const char *); 159*11963SAfshin.Ardakani@Sun.COM static void smb_quota_remove_ctrldir(const char *); 160*11963SAfshin.Ardakani@Sun.COM 161*11963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t *smb_quota_tree_create(const char *); 162*11963SAfshin.Ardakani@Sun.COM static void smb_quota_tree_delete(smb_quota_tree_t *); 163*11963SAfshin.Ardakani@Sun.COM 164*11963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t *smb_quota_tree_lookup(const char *); 165*11963SAfshin.Ardakani@Sun.COM static void smb_quota_tree_release(smb_quota_tree_t *); 166*11963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_tree_match(smb_quota_tree_t *, const char *); 167*11963SAfshin.Ardakani@Sun.COM static int smb_quota_sid_cmp(const void *, const void *); 168*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_tree_populate(smb_quota_tree_t *); 169*11963SAfshin.Ardakani@Sun.COM static boolean_t smb_quota_tree_expired(smb_quota_tree_t *); 170*11963SAfshin.Ardakani@Sun.COM static void smb_quota_tree_set_expired(smb_quota_tree_t *); 171*11963SAfshin.Ardakani@Sun.COM 172*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_zfs_init(const char *, smb_quota_zfs_handle_t *); 173*11963SAfshin.Ardakani@Sun.COM static void smb_quota_zfs_fini(smb_quota_zfs_handle_t *); 174*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_zfs_get_quotas(smb_quota_tree_t *); 175*11963SAfshin.Ardakani@Sun.COM static int smb_quota_zfs_callback(void *, const char *, uid_t, uint64_t); 176*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_zfs_set_quotas(smb_quota_tree_t *, smb_quota_set_t *); 177*11963SAfshin.Ardakani@Sun.COM static int smb_quota_sidstr(uint32_t, zfs_userquota_prop_t, char *); 178*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_sidtype(smb_quota_tree_t *, char *); 179*11963SAfshin.Ardakani@Sun.COM static int smb_quota_getid(char *, uint32_t, uint32_t *); 180*11963SAfshin.Ardakani@Sun.COM 181*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_query_all(smb_quota_tree_t *, 182*11963SAfshin.Ardakani@Sun.COM smb_quota_query_t *, smb_quota_response_t *); 183*11963SAfshin.Ardakani@Sun.COM static uint32_t smb_quota_query_list(smb_quota_tree_t *, 184*11963SAfshin.Ardakani@Sun.COM smb_quota_query_t *, smb_quota_response_t *); 185*11963SAfshin.Ardakani@Sun.COM 186*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_REFRESH 2 187*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CMD_LENGTH 21 188*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CMD_STR_LENGTH SMB_SID_STRSZ+SMB_QUOTA_CMD_LENGTH 189*11963SAfshin.Ardakani@Sun.COM 190*11963SAfshin.Ardakani@Sun.COM /* 191*11963SAfshin.Ardakani@Sun.COM * In order to display the quota properties tab, windows clients 192*11963SAfshin.Ardakani@Sun.COM * check for the existence of the quota control file. 193*11963SAfshin.Ardakani@Sun.COM */ 194*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_DIR ".$EXTEND" 195*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_FILE "$QUOTA" 196*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_INDEX_XATTR "SUNWsmb:$Q:$INDEX_ALLOCATION" 197*11963SAfshin.Ardakani@Sun.COM #define SMB_QUOTA_CNTRL_PERM "everyone@:rwpaARWc::allow" 198*11963SAfshin.Ardakani@Sun.COM 199*11963SAfshin.Ardakani@Sun.COM /* 200*11963SAfshin.Ardakani@Sun.COM * smb_quota_init 201*11963SAfshin.Ardakani@Sun.COM * Initialize the list to hold the quota trees. 202*11963SAfshin.Ardakani@Sun.COM */ 203*11963SAfshin.Ardakani@Sun.COM void 204*11963SAfshin.Ardakani@Sun.COM smb_quota_init(void) 205*11963SAfshin.Ardakani@Sun.COM { 206*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex); 207*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init) { 208*11963SAfshin.Ardakani@Sun.COM list_create(&smb_quota_fs_list, sizeof (smb_quota_tree_t), 209*11963SAfshin.Ardakani@Sun.COM offsetof(smb_quota_tree_t, qt_node)); 210*11963SAfshin.Ardakani@Sun.COM smb_quota_list_init = B_TRUE; 211*11963SAfshin.Ardakani@Sun.COM smb_quota_shutdown = B_FALSE; 212*11963SAfshin.Ardakani@Sun.COM } 213*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 214*11963SAfshin.Ardakani@Sun.COM } 215*11963SAfshin.Ardakani@Sun.COM 216*11963SAfshin.Ardakani@Sun.COM /* 217*11963SAfshin.Ardakani@Sun.COM * smb_quota_fini 218*11963SAfshin.Ardakani@Sun.COM * 219*11963SAfshin.Ardakani@Sun.COM * Wait for each quota tree to not be in use (qt_refcnt == 1) 220*11963SAfshin.Ardakani@Sun.COM * then remove it from the list and delete it. 221*11963SAfshin.Ardakani@Sun.COM */ 222*11963SAfshin.Ardakani@Sun.COM void 223*11963SAfshin.Ardakani@Sun.COM smb_quota_fini(void) 224*11963SAfshin.Ardakani@Sun.COM { 225*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree, *qtree_next; 226*11963SAfshin.Ardakani@Sun.COM boolean_t remove; 227*11963SAfshin.Ardakani@Sun.COM struct timespec tswait; 228*11963SAfshin.Ardakani@Sun.COM tswait.tv_sec = smb_quota_fini_timeout; 229*11963SAfshin.Ardakani@Sun.COM tswait.tv_nsec = 0; 230*11963SAfshin.Ardakani@Sun.COM 231*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex); 232*11963SAfshin.Ardakani@Sun.COM smb_quota_shutdown = B_TRUE; 233*11963SAfshin.Ardakani@Sun.COM 234*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init) { 235*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 236*11963SAfshin.Ardakani@Sun.COM return; 237*11963SAfshin.Ardakani@Sun.COM } 238*11963SAfshin.Ardakani@Sun.COM 239*11963SAfshin.Ardakani@Sun.COM (void) cond_broadcast(&smb_quota_list_condvar); 240*11963SAfshin.Ardakani@Sun.COM 241*11963SAfshin.Ardakani@Sun.COM while (smb_quota_tree_cnt != 0) { 242*11963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list); 243*11963SAfshin.Ardakani@Sun.COM while (qtree != NULL) { 244*11963SAfshin.Ardakani@Sun.COM qtree_next = list_next(&smb_quota_fs_list, qtree); 245*11963SAfshin.Ardakani@Sun.COM 246*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex); 247*11963SAfshin.Ardakani@Sun.COM remove = (qtree->qt_refcnt == 1); 248*11963SAfshin.Ardakani@Sun.COM if (remove) { 249*11963SAfshin.Ardakani@Sun.COM list_remove(&smb_quota_fs_list, qtree); 250*11963SAfshin.Ardakani@Sun.COM --qtree->qt_refcnt; 251*11963SAfshin.Ardakani@Sun.COM } 252*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 253*11963SAfshin.Ardakani@Sun.COM 254*11963SAfshin.Ardakani@Sun.COM if (remove) 255*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(qtree); 256*11963SAfshin.Ardakani@Sun.COM 257*11963SAfshin.Ardakani@Sun.COM qtree = qtree_next; 258*11963SAfshin.Ardakani@Sun.COM } 259*11963SAfshin.Ardakani@Sun.COM 260*11963SAfshin.Ardakani@Sun.COM if (smb_quota_tree_cnt != 0) { 261*11963SAfshin.Ardakani@Sun.COM if (cond_reltimedwait(&smb_quota_list_condvar, 262*11963SAfshin.Ardakani@Sun.COM &smb_quota_list_mutex, &tswait) == ETIME) { 263*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, 264*11963SAfshin.Ardakani@Sun.COM "quota shutdown timeout expired"); 265*11963SAfshin.Ardakani@Sun.COM break; 266*11963SAfshin.Ardakani@Sun.COM } 267*11963SAfshin.Ardakani@Sun.COM } 268*11963SAfshin.Ardakani@Sun.COM } 269*11963SAfshin.Ardakani@Sun.COM 270*11963SAfshin.Ardakani@Sun.COM if (list_is_empty(&smb_quota_fs_list)) { 271*11963SAfshin.Ardakani@Sun.COM list_destroy(&smb_quota_fs_list); 272*11963SAfshin.Ardakani@Sun.COM smb_quota_list_init = B_FALSE; 273*11963SAfshin.Ardakani@Sun.COM } 274*11963SAfshin.Ardakani@Sun.COM 275*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 276*11963SAfshin.Ardakani@Sun.COM } 277*11963SAfshin.Ardakani@Sun.COM 278*11963SAfshin.Ardakani@Sun.COM /* 279*11963SAfshin.Ardakani@Sun.COM * smb_quota_add_fs 280*11963SAfshin.Ardakani@Sun.COM * 281*11963SAfshin.Ardakani@Sun.COM * If there is not a quota tree representing the specified path, 282*11963SAfshin.Ardakani@Sun.COM * create one and add it to the list. 283*11963SAfshin.Ardakani@Sun.COM */ 284*11963SAfshin.Ardakani@Sun.COM void 285*11963SAfshin.Ardakani@Sun.COM smb_quota_add_fs(const char *path) 286*11963SAfshin.Ardakani@Sun.COM { 287*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree; 288*11963SAfshin.Ardakani@Sun.COM 289*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex); 290*11963SAfshin.Ardakani@Sun.COM 291*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init || smb_quota_shutdown) { 292*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 293*11963SAfshin.Ardakani@Sun.COM return; 294*11963SAfshin.Ardakani@Sun.COM } 295*11963SAfshin.Ardakani@Sun.COM 296*11963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list); 297*11963SAfshin.Ardakani@Sun.COM while (qtree != NULL) { 298*11963SAfshin.Ardakani@Sun.COM if (smb_quota_tree_match(qtree, path)) { 299*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex); 300*11963SAfshin.Ardakani@Sun.COM ++qtree->qt_sharecnt; 301*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 302*11963SAfshin.Ardakani@Sun.COM break; 303*11963SAfshin.Ardakani@Sun.COM } 304*11963SAfshin.Ardakani@Sun.COM qtree = list_next(&smb_quota_fs_list, qtree); 305*11963SAfshin.Ardakani@Sun.COM } 306*11963SAfshin.Ardakani@Sun.COM 307*11963SAfshin.Ardakani@Sun.COM if (qtree == NULL) { 308*11963SAfshin.Ardakani@Sun.COM qtree = smb_quota_tree_create(path); 309*11963SAfshin.Ardakani@Sun.COM if (qtree) 310*11963SAfshin.Ardakani@Sun.COM list_insert_head(&smb_quota_fs_list, (void *)qtree); 311*11963SAfshin.Ardakani@Sun.COM } 312*11963SAfshin.Ardakani@Sun.COM 313*11963SAfshin.Ardakani@Sun.COM if (qtree) 314*11963SAfshin.Ardakani@Sun.COM smb_quota_add_ctrldir(path); 315*11963SAfshin.Ardakani@Sun.COM 316*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 317*11963SAfshin.Ardakani@Sun.COM } 318*11963SAfshin.Ardakani@Sun.COM 319*11963SAfshin.Ardakani@Sun.COM /* 320*11963SAfshin.Ardakani@Sun.COM * smb_quota_remove_fs 321*11963SAfshin.Ardakani@Sun.COM * 322*11963SAfshin.Ardakani@Sun.COM * If this is the last share that the quota tree represents 323*11963SAfshin.Ardakani@Sun.COM * (qtree->qt_sharecnt == 0) remove the qtree from the list. 324*11963SAfshin.Ardakani@Sun.COM * The qtree will be deleted if/when there is nobody using it 325*11963SAfshin.Ardakani@Sun.COM * (qtree->qt_refcnt == 0). 326*11963SAfshin.Ardakani@Sun.COM */ 327*11963SAfshin.Ardakani@Sun.COM void 328*11963SAfshin.Ardakani@Sun.COM smb_quota_remove_fs(const char *path) 329*11963SAfshin.Ardakani@Sun.COM { 330*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree; 331*11963SAfshin.Ardakani@Sun.COM boolean_t delete = B_FALSE; 332*11963SAfshin.Ardakani@Sun.COM 333*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex); 334*11963SAfshin.Ardakani@Sun.COM 335*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init || smb_quota_shutdown) { 336*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 337*11963SAfshin.Ardakani@Sun.COM return; 338*11963SAfshin.Ardakani@Sun.COM } 339*11963SAfshin.Ardakani@Sun.COM 340*11963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list); 341*11963SAfshin.Ardakani@Sun.COM while (qtree != NULL) { 342*11963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt > 0); 343*11963SAfshin.Ardakani@Sun.COM if (smb_quota_tree_match(qtree, path)) { 344*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex); 345*11963SAfshin.Ardakani@Sun.COM --qtree->qt_sharecnt; 346*11963SAfshin.Ardakani@Sun.COM if (qtree->qt_sharecnt == 0) { 347*11963SAfshin.Ardakani@Sun.COM list_remove(&smb_quota_fs_list, (void *)qtree); 348*11963SAfshin.Ardakani@Sun.COM smb_quota_remove_ctrldir(qtree->qt_path); 349*11963SAfshin.Ardakani@Sun.COM --(qtree->qt_refcnt); 350*11963SAfshin.Ardakani@Sun.COM delete = (qtree->qt_refcnt == 0); 351*11963SAfshin.Ardakani@Sun.COM } 352*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 353*11963SAfshin.Ardakani@Sun.COM if (delete) 354*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(qtree); 355*11963SAfshin.Ardakani@Sun.COM break; 356*11963SAfshin.Ardakani@Sun.COM } 357*11963SAfshin.Ardakani@Sun.COM qtree = list_next(&smb_quota_fs_list, qtree); 358*11963SAfshin.Ardakani@Sun.COM } 359*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 360*11963SAfshin.Ardakani@Sun.COM } 361*11963SAfshin.Ardakani@Sun.COM 362*11963SAfshin.Ardakani@Sun.COM /* 363*11963SAfshin.Ardakani@Sun.COM * smb_quota_query 364*11963SAfshin.Ardakani@Sun.COM * 365*11963SAfshin.Ardakani@Sun.COM * Get list of user/group quotas entries. 366*11963SAfshin.Ardakani@Sun.COM * Request->qq_query_op determines whether to get quota entries 367*11963SAfshin.Ardakani@Sun.COM * for the specified SIDs (smb_quota_query_list) OR to get all 368*11963SAfshin.Ardakani@Sun.COM * quota entries, optionally starting at a specified SID. 369*11963SAfshin.Ardakani@Sun.COM * 370*11963SAfshin.Ardakani@Sun.COM * Returns NT_STATUS codes. 371*11963SAfshin.Ardakani@Sun.COM */ 372*11963SAfshin.Ardakani@Sun.COM uint32_t 373*11963SAfshin.Ardakani@Sun.COM smb_quota_query(smb_quota_query_t *request, smb_quota_response_t *reply) 374*11963SAfshin.Ardakani@Sun.COM { 375*11963SAfshin.Ardakani@Sun.COM uint32_t status; 376*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree; 377*11963SAfshin.Ardakani@Sun.COM smb_quota_query_op_t query_op = request->qq_query_op; 378*11963SAfshin.Ardakani@Sun.COM 379*11963SAfshin.Ardakani@Sun.COM list_create(&reply->qr_quota_list, sizeof (smb_quota_t), 380*11963SAfshin.Ardakani@Sun.COM offsetof(smb_quota_t, q_list_node)); 381*11963SAfshin.Ardakani@Sun.COM 382*11963SAfshin.Ardakani@Sun.COM qtree = smb_quota_tree_lookup(request->qq_root_path); 383*11963SAfshin.Ardakani@Sun.COM if (qtree == NULL) 384*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER); 385*11963SAfshin.Ardakani@Sun.COM 386*11963SAfshin.Ardakani@Sun.COM /* If NOT resuming a previous query all, refresh qtree if required */ 387*11963SAfshin.Ardakani@Sun.COM if ((query_op != SMB_QUOTA_QUERY_ALL) || (request->qq_restart)) { 388*11963SAfshin.Ardakani@Sun.COM status = smb_quota_tree_populate(qtree); 389*11963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS) { 390*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(qtree); 391*11963SAfshin.Ardakani@Sun.COM return (status); 392*11963SAfshin.Ardakani@Sun.COM } 393*11963SAfshin.Ardakani@Sun.COM } 394*11963SAfshin.Ardakani@Sun.COM 395*11963SAfshin.Ardakani@Sun.COM switch (query_op) { 396*11963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_SIDLIST: 397*11963SAfshin.Ardakani@Sun.COM status = smb_quota_query_list(qtree, request, reply); 398*11963SAfshin.Ardakani@Sun.COM break; 399*11963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_STARTSID: 400*11963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_ALL: 401*11963SAfshin.Ardakani@Sun.COM status = smb_quota_query_all(qtree, request, reply); 402*11963SAfshin.Ardakani@Sun.COM break; 403*11963SAfshin.Ardakani@Sun.COM case SMB_QUOTA_QUERY_INVALID_OP: 404*11963SAfshin.Ardakani@Sun.COM default: 405*11963SAfshin.Ardakani@Sun.COM status = NT_STATUS_INVALID_PARAMETER; 406*11963SAfshin.Ardakani@Sun.COM break; 407*11963SAfshin.Ardakani@Sun.COM } 408*11963SAfshin.Ardakani@Sun.COM 409*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(qtree); 410*11963SAfshin.Ardakani@Sun.COM 411*11963SAfshin.Ardakani@Sun.COM return (status); 412*11963SAfshin.Ardakani@Sun.COM } 413*11963SAfshin.Ardakani@Sun.COM 414*11963SAfshin.Ardakani@Sun.COM /* 415*11963SAfshin.Ardakani@Sun.COM * smb_quota_set 416*11963SAfshin.Ardakani@Sun.COM * 417*11963SAfshin.Ardakani@Sun.COM * Set the list of quota entries. 418*11963SAfshin.Ardakani@Sun.COM */ 419*11963SAfshin.Ardakani@Sun.COM uint32_t 420*11963SAfshin.Ardakani@Sun.COM smb_quota_set(smb_quota_set_t *request) 421*11963SAfshin.Ardakani@Sun.COM { 422*11963SAfshin.Ardakani@Sun.COM uint32_t status; 423*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree; 424*11963SAfshin.Ardakani@Sun.COM 425*11963SAfshin.Ardakani@Sun.COM qtree = smb_quota_tree_lookup(request->qs_root_path); 426*11963SAfshin.Ardakani@Sun.COM if (qtree == NULL) 427*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER); 428*11963SAfshin.Ardakani@Sun.COM 429*11963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_set_quotas(qtree, request); 430*11963SAfshin.Ardakani@Sun.COM 431*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_set_expired(qtree); 432*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(qtree); 433*11963SAfshin.Ardakani@Sun.COM 434*11963SAfshin.Ardakani@Sun.COM return (status); 435*11963SAfshin.Ardakani@Sun.COM } 436*11963SAfshin.Ardakani@Sun.COM 437*11963SAfshin.Ardakani@Sun.COM /* 438*11963SAfshin.Ardakani@Sun.COM * smb_quota_free 439*11963SAfshin.Ardakani@Sun.COM * 440*11963SAfshin.Ardakani@Sun.COM * This method frees quota entries. 441*11963SAfshin.Ardakani@Sun.COM */ 442*11963SAfshin.Ardakani@Sun.COM void 443*11963SAfshin.Ardakani@Sun.COM smb_quota_free(smb_quota_response_t *reply) 444*11963SAfshin.Ardakani@Sun.COM { 445*11963SAfshin.Ardakani@Sun.COM list_t *list = &reply->qr_quota_list; 446*11963SAfshin.Ardakani@Sun.COM smb_quota_t *quota; 447*11963SAfshin.Ardakani@Sun.COM 448*11963SAfshin.Ardakani@Sun.COM while ((quota = list_head(list)) != NULL) { 449*11963SAfshin.Ardakani@Sun.COM list_remove(list, quota); 450*11963SAfshin.Ardakani@Sun.COM free(quota); 451*11963SAfshin.Ardakani@Sun.COM } 452*11963SAfshin.Ardakani@Sun.COM 453*11963SAfshin.Ardakani@Sun.COM list_destroy(list); 454*11963SAfshin.Ardakani@Sun.COM } 455*11963SAfshin.Ardakani@Sun.COM 456*11963SAfshin.Ardakani@Sun.COM /* 457*11963SAfshin.Ardakani@Sun.COM * smb_quota_query_all 458*11963SAfshin.Ardakani@Sun.COM * 459*11963SAfshin.Ardakani@Sun.COM * Query quotas sequentially from tree, optionally starting at a 460*11963SAfshin.Ardakani@Sun.COM * specified sid. If request->qq_single is TRUE only one quota 461*11963SAfshin.Ardakani@Sun.COM * should be returned, otherwise up to request->qq_max_quota 462*11963SAfshin.Ardakani@Sun.COM * should be returned. 463*11963SAfshin.Ardakani@Sun.COM * 464*11963SAfshin.Ardakani@Sun.COM * SMB_QUOTA_QUERY_STARTSID 465*11963SAfshin.Ardakani@Sun.COM * The query should start at the startsid, the first sid in 466*11963SAfshin.Ardakani@Sun.COM * request->qq_sid_list. 467*11963SAfshin.Ardakani@Sun.COM * 468*11963SAfshin.Ardakani@Sun.COM * SMQ_QUOTA_QUERY_ALL 469*11963SAfshin.Ardakani@Sun.COM * If request->qq_restart the query should restart at the start 470*11963SAfshin.Ardakani@Sun.COM * of the avl tree. Otherwise the first sid in request->qq_sid_list 471*11963SAfshin.Ardakani@Sun.COM * is the resume sid and the query should start at the tree entry 472*11963SAfshin.Ardakani@Sun.COM * after the one it refers to. 473*11963SAfshin.Ardakani@Sun.COM * 474*11963SAfshin.Ardakani@Sun.COM * Returns NT_STATUS codes. 475*11963SAfshin.Ardakani@Sun.COM */ 476*11963SAfshin.Ardakani@Sun.COM static uint32_t 477*11963SAfshin.Ardakani@Sun.COM smb_quota_query_all(smb_quota_tree_t *qtree, smb_quota_query_t *request, 478*11963SAfshin.Ardakani@Sun.COM smb_quota_response_t *reply) 479*11963SAfshin.Ardakani@Sun.COM { 480*11963SAfshin.Ardakani@Sun.COM avl_tree_t *avl_tree = &qtree->qt_avl; 481*11963SAfshin.Ardakani@Sun.COM avl_index_t where; 482*11963SAfshin.Ardakani@Sun.COM list_t *sid_list, *quota_list; 483*11963SAfshin.Ardakani@Sun.COM smb_quota_sid_t *sid; 484*11963SAfshin.Ardakani@Sun.COM smb_quota_t *quota, *quotal, key; 485*11963SAfshin.Ardakani@Sun.COM uint32_t count; 486*11963SAfshin.Ardakani@Sun.COM 487*11963SAfshin.Ardakani@Sun.COM /* find starting sid */ 488*11963SAfshin.Ardakani@Sun.COM if (request->qq_query_op == SMB_QUOTA_QUERY_STARTSID) { 489*11963SAfshin.Ardakani@Sun.COM sid_list = &request->qq_sid_list; 490*11963SAfshin.Ardakani@Sun.COM sid = list_head(sid_list); 491*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sid->qs_sidstr, SMB_SID_STRSZ); 492*11963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where); 493*11963SAfshin.Ardakani@Sun.COM if (quota == NULL) 494*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER); 495*11963SAfshin.Ardakani@Sun.COM } else if (request->qq_restart) { 496*11963SAfshin.Ardakani@Sun.COM quota = avl_first(avl_tree); 497*11963SAfshin.Ardakani@Sun.COM if (quota == NULL) 498*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MORE_DATA); 499*11963SAfshin.Ardakani@Sun.COM } else { 500*11963SAfshin.Ardakani@Sun.COM sid_list = &request->qq_sid_list; 501*11963SAfshin.Ardakani@Sun.COM sid = list_head(sid_list); 502*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sid->qs_sidstr, SMB_SID_STRSZ); 503*11963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where); 504*11963SAfshin.Ardakani@Sun.COM if (quota == NULL) 505*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER); 506*11963SAfshin.Ardakani@Sun.COM quota = AVL_NEXT(avl_tree, quota); 507*11963SAfshin.Ardakani@Sun.COM if (quota == NULL) 508*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MORE_DATA); 509*11963SAfshin.Ardakani@Sun.COM } 510*11963SAfshin.Ardakani@Sun.COM 511*11963SAfshin.Ardakani@Sun.COM if ((request->qq_single) && (request->qq_max_quota > 1)) 512*11963SAfshin.Ardakani@Sun.COM request->qq_max_quota = 1; 513*11963SAfshin.Ardakani@Sun.COM 514*11963SAfshin.Ardakani@Sun.COM quota_list = &reply->qr_quota_list; 515*11963SAfshin.Ardakani@Sun.COM count = 0; 516*11963SAfshin.Ardakani@Sun.COM while (quota) { 517*11963SAfshin.Ardakani@Sun.COM if (count >= request->qq_max_quota) 518*11963SAfshin.Ardakani@Sun.COM break; 519*11963SAfshin.Ardakani@Sun.COM 520*11963SAfshin.Ardakani@Sun.COM quotal = malloc(sizeof (smb_quota_t)); 521*11963SAfshin.Ardakani@Sun.COM if (quotal == NULL) 522*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MEMORY); 523*11963SAfshin.Ardakani@Sun.COM bcopy(quota, quotal, sizeof (smb_quota_t)); 524*11963SAfshin.Ardakani@Sun.COM 525*11963SAfshin.Ardakani@Sun.COM list_insert_tail(quota_list, quotal); 526*11963SAfshin.Ardakani@Sun.COM ++count; 527*11963SAfshin.Ardakani@Sun.COM 528*11963SAfshin.Ardakani@Sun.COM quota = AVL_NEXT(avl_tree, quota); 529*11963SAfshin.Ardakani@Sun.COM } 530*11963SAfshin.Ardakani@Sun.COM 531*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS); 532*11963SAfshin.Ardakani@Sun.COM } 533*11963SAfshin.Ardakani@Sun.COM 534*11963SAfshin.Ardakani@Sun.COM /* 535*11963SAfshin.Ardakani@Sun.COM * smb_quota_query_list 536*11963SAfshin.Ardakani@Sun.COM * 537*11963SAfshin.Ardakani@Sun.COM * Iterate through request sid list querying the avl tree for each. 538*11963SAfshin.Ardakani@Sun.COM * Insert an entry in the reply quota list for each sid. 539*11963SAfshin.Ardakani@Sun.COM * For any sid that cannot be found in the avl tree, the reply 540*11963SAfshin.Ardakani@Sun.COM * quota list entry should contain zeros. 541*11963SAfshin.Ardakani@Sun.COM */ 542*11963SAfshin.Ardakani@Sun.COM static uint32_t 543*11963SAfshin.Ardakani@Sun.COM smb_quota_query_list(smb_quota_tree_t *qtree, smb_quota_query_t *request, 544*11963SAfshin.Ardakani@Sun.COM smb_quota_response_t *reply) 545*11963SAfshin.Ardakani@Sun.COM { 546*11963SAfshin.Ardakani@Sun.COM avl_tree_t *avl_tree = &qtree->qt_avl; 547*11963SAfshin.Ardakani@Sun.COM avl_index_t where; 548*11963SAfshin.Ardakani@Sun.COM list_t *sid_list, *quota_list; 549*11963SAfshin.Ardakani@Sun.COM smb_quota_sid_t *sid; 550*11963SAfshin.Ardakani@Sun.COM smb_quota_t *quota, *quotal, key; 551*11963SAfshin.Ardakani@Sun.COM 552*11963SAfshin.Ardakani@Sun.COM quota_list = &reply->qr_quota_list; 553*11963SAfshin.Ardakani@Sun.COM sid_list = &request->qq_sid_list; 554*11963SAfshin.Ardakani@Sun.COM sid = list_head(sid_list); 555*11963SAfshin.Ardakani@Sun.COM while (sid) { 556*11963SAfshin.Ardakani@Sun.COM quotal = malloc(sizeof (smb_quota_t)); 557*11963SAfshin.Ardakani@Sun.COM if (quotal == NULL) 558*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MEMORY); 559*11963SAfshin.Ardakani@Sun.COM 560*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sid->qs_sidstr, SMB_SID_STRSZ); 561*11963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where); 562*11963SAfshin.Ardakani@Sun.COM if (quota) { 563*11963SAfshin.Ardakani@Sun.COM bcopy(quota, quotal, sizeof (smb_quota_t)); 564*11963SAfshin.Ardakani@Sun.COM } else { 565*11963SAfshin.Ardakani@Sun.COM bzero(quotal, sizeof (smb_quota_t)); 566*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(quotal->q_sidstr, sid->qs_sidstr, 567*11963SAfshin.Ardakani@Sun.COM SMB_SID_STRSZ); 568*11963SAfshin.Ardakani@Sun.COM } 569*11963SAfshin.Ardakani@Sun.COM 570*11963SAfshin.Ardakani@Sun.COM list_insert_tail(quota_list, quotal); 571*11963SAfshin.Ardakani@Sun.COM sid = list_next(sid_list, sid); 572*11963SAfshin.Ardakani@Sun.COM } 573*11963SAfshin.Ardakani@Sun.COM 574*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS); 575*11963SAfshin.Ardakani@Sun.COM } 576*11963SAfshin.Ardakani@Sun.COM 577*11963SAfshin.Ardakani@Sun.COM /* 578*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_set_quotas 579*11963SAfshin.Ardakani@Sun.COM * 580*11963SAfshin.Ardakani@Sun.COM * This method sets the list of quota entries. 581*11963SAfshin.Ardakani@Sun.COM * 582*11963SAfshin.Ardakani@Sun.COM * A quota list or threshold value of SMB_QUOTA_UNLIMITED means that 583*11963SAfshin.Ardakani@Sun.COM * the user / group does not have a quota limit. In ZFS this maps to 584*11963SAfshin.Ardakani@Sun.COM * 0 (none). 585*11963SAfshin.Ardakani@Sun.COM * A quota list or threshold value of (SMB_QUOTA_UNLIMITED - 1) means 586*11963SAfshin.Ardakani@Sun.COM * that the user / group quota should be removed. In ZFS this maps to 587*11963SAfshin.Ardakani@Sun.COM * 0 (none). 588*11963SAfshin.Ardakani@Sun.COM */ 589*11963SAfshin.Ardakani@Sun.COM static uint32_t 590*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_set_quotas(smb_quota_tree_t *qtree, smb_quota_set_t *request) 591*11963SAfshin.Ardakani@Sun.COM { 592*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_handle_t zfs_hdl; 593*11963SAfshin.Ardakani@Sun.COM char *typestr, qsetstr[SMB_QUOTA_CMD_STR_LENGTH]; 594*11963SAfshin.Ardakani@Sun.COM char qlimit[SMB_QUOTA_CMD_LENGTH]; 595*11963SAfshin.Ardakani@Sun.COM list_t *quota_list; 596*11963SAfshin.Ardakani@Sun.COM smb_quota_t *quota; 597*11963SAfshin.Ardakani@Sun.COM uint32_t id; 598*11963SAfshin.Ardakani@Sun.COM uint32_t status = NT_STATUS_SUCCESS; 599*11963SAfshin.Ardakani@Sun.COM uint32_t sidtype; 600*11963SAfshin.Ardakani@Sun.COM 601*11963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_init(request->qs_root_path, &zfs_hdl); 602*11963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS) 603*11963SAfshin.Ardakani@Sun.COM return (status); 604*11963SAfshin.Ardakani@Sun.COM 605*11963SAfshin.Ardakani@Sun.COM quota_list = &request->qs_quota_list; 606*11963SAfshin.Ardakani@Sun.COM quota = list_head(quota_list); 607*11963SAfshin.Ardakani@Sun.COM 608*11963SAfshin.Ardakani@Sun.COM while (quota) { 609*11963SAfshin.Ardakani@Sun.COM if ((quota->q_limit == SMB_QUOTA_UNLIMITED) || 610*11963SAfshin.Ardakani@Sun.COM (quota->q_limit == (SMB_QUOTA_UNLIMITED - 1))) { 611*11963SAfshin.Ardakani@Sun.COM quota->q_limit = 0; 612*11963SAfshin.Ardakani@Sun.COM } 613*11963SAfshin.Ardakani@Sun.COM (void) snprintf(qlimit, SMB_QUOTA_CMD_LENGTH, "%llu", 614*11963SAfshin.Ardakani@Sun.COM quota->q_limit); 615*11963SAfshin.Ardakani@Sun.COM 616*11963SAfshin.Ardakani@Sun.COM sidtype = smb_quota_sidtype(qtree, quota->q_sidstr); 617*11963SAfshin.Ardakani@Sun.COM switch (sidtype) { 618*11963SAfshin.Ardakani@Sun.COM case SidTypeUser: 619*11963SAfshin.Ardakani@Sun.COM typestr = "userquota"; 620*11963SAfshin.Ardakani@Sun.COM break; 621*11963SAfshin.Ardakani@Sun.COM case SidTypeWellKnownGroup: 622*11963SAfshin.Ardakani@Sun.COM case SidTypeGroup: 623*11963SAfshin.Ardakani@Sun.COM case SidTypeAlias: 624*11963SAfshin.Ardakani@Sun.COM typestr = "groupquota"; 625*11963SAfshin.Ardakani@Sun.COM break; 626*11963SAfshin.Ardakani@Sun.COM default: 627*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "Failed to set quota for %s: " 628*11963SAfshin.Ardakani@Sun.COM "%s (%d) not valid for quotas", quota->q_sidstr, 629*11963SAfshin.Ardakani@Sun.COM smb_sid_type2str(sidtype), sidtype); 630*11963SAfshin.Ardakani@Sun.COM quota = list_next(quota_list, quota); 631*11963SAfshin.Ardakani@Sun.COM continue; 632*11963SAfshin.Ardakani@Sun.COM } 633*11963SAfshin.Ardakani@Sun.COM 634*11963SAfshin.Ardakani@Sun.COM if ((smb_quota_getid(quota->q_sidstr, sidtype, &id) == 0) && 635*11963SAfshin.Ardakani@Sun.COM !(IDMAP_ID_IS_EPHEMERAL(id))) { 636*11963SAfshin.Ardakani@Sun.COM (void) snprintf(qsetstr, SMB_QUOTA_CMD_STR_LENGTH, 637*11963SAfshin.Ardakani@Sun.COM "%s@%d", typestr, id); 638*11963SAfshin.Ardakani@Sun.COM } else { 639*11963SAfshin.Ardakani@Sun.COM (void) snprintf(qsetstr, SMB_QUOTA_CMD_STR_LENGTH, 640*11963SAfshin.Ardakani@Sun.COM "%s@%s", typestr, quota->q_sidstr); 641*11963SAfshin.Ardakani@Sun.COM } 642*11963SAfshin.Ardakani@Sun.COM 643*11963SAfshin.Ardakani@Sun.COM errno = 0; 644*11963SAfshin.Ardakani@Sun.COM if (zfs_prop_set(zfs_hdl.z_fs, qsetstr, qlimit) != 0) { 645*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "Failed to set quota for %s: %s", 646*11963SAfshin.Ardakani@Sun.COM quota->q_sidstr, strerror(errno)); 647*11963SAfshin.Ardakani@Sun.COM status = NT_STATUS_INVALID_PARAMETER; 648*11963SAfshin.Ardakani@Sun.COM break; 649*11963SAfshin.Ardakani@Sun.COM } 650*11963SAfshin.Ardakani@Sun.COM 651*11963SAfshin.Ardakani@Sun.COM quota = list_next(quota_list, quota); 652*11963SAfshin.Ardakani@Sun.COM } 653*11963SAfshin.Ardakani@Sun.COM 654*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_fini(&zfs_hdl); 655*11963SAfshin.Ardakani@Sun.COM return (status); 656*11963SAfshin.Ardakani@Sun.COM } 657*11963SAfshin.Ardakani@Sun.COM 658*11963SAfshin.Ardakani@Sun.COM /* 659*11963SAfshin.Ardakani@Sun.COM * smb_quota_sidtype 660*11963SAfshin.Ardakani@Sun.COM * 661*11963SAfshin.Ardakani@Sun.COM * Determine the type of the sid. If the sid exists in 662*11963SAfshin.Ardakani@Sun.COM * the qtree get its type from there, otherwise do an 663*11963SAfshin.Ardakani@Sun.COM * lsa_lookup_sid(). 664*11963SAfshin.Ardakani@Sun.COM */ 665*11963SAfshin.Ardakani@Sun.COM static uint32_t 666*11963SAfshin.Ardakani@Sun.COM smb_quota_sidtype(smb_quota_tree_t *qtree, char *sidstr) 667*11963SAfshin.Ardakani@Sun.COM { 668*11963SAfshin.Ardakani@Sun.COM smb_quota_t key, *quota; 669*11963SAfshin.Ardakani@Sun.COM avl_index_t where; 670*11963SAfshin.Ardakani@Sun.COM smb_sid_t *sid = NULL; 671*11963SAfshin.Ardakani@Sun.COM smb_account_t ainfo; 672*11963SAfshin.Ardakani@Sun.COM uint32_t sidtype = SidTypeUnknown; 673*11963SAfshin.Ardakani@Sun.COM 674*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(key.q_sidstr, sidstr, SMB_SID_STRSZ); 675*11963SAfshin.Ardakani@Sun.COM quota = avl_find(&qtree->qt_avl, &key, &where); 676*11963SAfshin.Ardakani@Sun.COM if (quota) 677*11963SAfshin.Ardakani@Sun.COM return (quota->q_sidtype); 678*11963SAfshin.Ardakani@Sun.COM 679*11963SAfshin.Ardakani@Sun.COM sid = smb_sid_fromstr(sidstr); 680*11963SAfshin.Ardakani@Sun.COM if (sid != NULL) { 681*11963SAfshin.Ardakani@Sun.COM if (lsa_lookup_sid(sid, &ainfo) == NT_STATUS_SUCCESS) { 682*11963SAfshin.Ardakani@Sun.COM sidtype = ainfo.a_type; 683*11963SAfshin.Ardakani@Sun.COM smb_account_free(&ainfo); 684*11963SAfshin.Ardakani@Sun.COM } 685*11963SAfshin.Ardakani@Sun.COM smb_sid_free(sid); 686*11963SAfshin.Ardakani@Sun.COM } 687*11963SAfshin.Ardakani@Sun.COM return (sidtype); 688*11963SAfshin.Ardakani@Sun.COM } 689*11963SAfshin.Ardakani@Sun.COM 690*11963SAfshin.Ardakani@Sun.COM /* 691*11963SAfshin.Ardakani@Sun.COM * smb_quota_getid 692*11963SAfshin.Ardakani@Sun.COM * 693*11963SAfshin.Ardakani@Sun.COM * Get the user/group id for the sid. 694*11963SAfshin.Ardakani@Sun.COM */ 695*11963SAfshin.Ardakani@Sun.COM static int 696*11963SAfshin.Ardakani@Sun.COM smb_quota_getid(char *sidstr, uint32_t sidtype, uint32_t *id) 697*11963SAfshin.Ardakani@Sun.COM { 698*11963SAfshin.Ardakani@Sun.COM int rc = 0; 699*11963SAfshin.Ardakani@Sun.COM smb_sid_t *sid = NULL; 700*11963SAfshin.Ardakani@Sun.COM int idtype; 701*11963SAfshin.Ardakani@Sun.COM 702*11963SAfshin.Ardakani@Sun.COM sid = smb_sid_fromstr(sidstr); 703*11963SAfshin.Ardakani@Sun.COM if (sid == NULL) 704*11963SAfshin.Ardakani@Sun.COM return (-1); 705*11963SAfshin.Ardakani@Sun.COM 706*11963SAfshin.Ardakani@Sun.COM switch (sidtype) { 707*11963SAfshin.Ardakani@Sun.COM case SidTypeUser: 708*11963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_USER; 709*11963SAfshin.Ardakani@Sun.COM break; 710*11963SAfshin.Ardakani@Sun.COM case SidTypeWellKnownGroup: 711*11963SAfshin.Ardakani@Sun.COM case SidTypeGroup: 712*11963SAfshin.Ardakani@Sun.COM case SidTypeAlias: 713*11963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_GROUP; 714*11963SAfshin.Ardakani@Sun.COM break; 715*11963SAfshin.Ardakani@Sun.COM default: 716*11963SAfshin.Ardakani@Sun.COM rc = -1; 717*11963SAfshin.Ardakani@Sun.COM break; 718*11963SAfshin.Ardakani@Sun.COM } 719*11963SAfshin.Ardakani@Sun.COM 720*11963SAfshin.Ardakani@Sun.COM if (rc == 0) 721*11963SAfshin.Ardakani@Sun.COM rc = smb_idmap_getid(sid, id, &idtype); 722*11963SAfshin.Ardakani@Sun.COM 723*11963SAfshin.Ardakani@Sun.COM smb_sid_free(sid); 724*11963SAfshin.Ardakani@Sun.COM 725*11963SAfshin.Ardakani@Sun.COM return (rc); 726*11963SAfshin.Ardakani@Sun.COM } 727*11963SAfshin.Ardakani@Sun.COM 728*11963SAfshin.Ardakani@Sun.COM /* 729*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_lookup 730*11963SAfshin.Ardakani@Sun.COM * 731*11963SAfshin.Ardakani@Sun.COM * Find the quota tree in smb_quota_fs_list. 732*11963SAfshin.Ardakani@Sun.COM * 733*11963SAfshin.Ardakani@Sun.COM * If the tree is found but is locked, waits for it to become available. 734*11963SAfshin.Ardakani@Sun.COM * If the tree is available, locks it and returns it. 735*11963SAfshin.Ardakani@Sun.COM * Otherwise, returns NULL. 736*11963SAfshin.Ardakani@Sun.COM */ 737*11963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t * 738*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_lookup(const char *path) 739*11963SAfshin.Ardakani@Sun.COM { 740*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree = NULL; 741*11963SAfshin.Ardakani@Sun.COM 742*11963SAfshin.Ardakani@Sun.COM assert(path); 743*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex); 744*11963SAfshin.Ardakani@Sun.COM 745*11963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list); 746*11963SAfshin.Ardakani@Sun.COM while (qtree != NULL) { 747*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_list_init || smb_quota_shutdown) { 748*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 749*11963SAfshin.Ardakani@Sun.COM return (NULL); 750*11963SAfshin.Ardakani@Sun.COM } 751*11963SAfshin.Ardakani@Sun.COM 752*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex); 753*11963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt > 0); 754*11963SAfshin.Ardakani@Sun.COM 755*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_tree_match(qtree, path)) { 756*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 757*11963SAfshin.Ardakani@Sun.COM qtree = list_next(&smb_quota_fs_list, qtree); 758*11963SAfshin.Ardakani@Sun.COM continue; 759*11963SAfshin.Ardakani@Sun.COM } 760*11963SAfshin.Ardakani@Sun.COM 761*11963SAfshin.Ardakani@Sun.COM if (qtree->qt_locked) { 762*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 763*11963SAfshin.Ardakani@Sun.COM (void) cond_wait(&smb_quota_list_condvar, 764*11963SAfshin.Ardakani@Sun.COM &smb_quota_list_mutex); 765*11963SAfshin.Ardakani@Sun.COM qtree = list_head(&smb_quota_fs_list); 766*11963SAfshin.Ardakani@Sun.COM continue; 767*11963SAfshin.Ardakani@Sun.COM } 768*11963SAfshin.Ardakani@Sun.COM 769*11963SAfshin.Ardakani@Sun.COM ++(qtree->qt_refcnt); 770*11963SAfshin.Ardakani@Sun.COM qtree->qt_locked = B_TRUE; 771*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 772*11963SAfshin.Ardakani@Sun.COM break; 773*11963SAfshin.Ardakani@Sun.COM }; 774*11963SAfshin.Ardakani@Sun.COM 775*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 776*11963SAfshin.Ardakani@Sun.COM return (qtree); 777*11963SAfshin.Ardakani@Sun.COM } 778*11963SAfshin.Ardakani@Sun.COM 779*11963SAfshin.Ardakani@Sun.COM /* 780*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_release 781*11963SAfshin.Ardakani@Sun.COM */ 782*11963SAfshin.Ardakani@Sun.COM static void 783*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_release(smb_quota_tree_t *qtree) 784*11963SAfshin.Ardakani@Sun.COM { 785*11963SAfshin.Ardakani@Sun.COM boolean_t delete; 786*11963SAfshin.Ardakani@Sun.COM 787*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&qtree->qt_mutex); 788*11963SAfshin.Ardakani@Sun.COM assert(qtree->qt_locked); 789*11963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt > 0); 790*11963SAfshin.Ardakani@Sun.COM 791*11963SAfshin.Ardakani@Sun.COM --(qtree->qt_refcnt); 792*11963SAfshin.Ardakani@Sun.COM qtree->qt_locked = B_FALSE; 793*11963SAfshin.Ardakani@Sun.COM delete = (qtree->qt_refcnt == 0); 794*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&qtree->qt_mutex); 795*11963SAfshin.Ardakani@Sun.COM 796*11963SAfshin.Ardakani@Sun.COM (void) mutex_lock(&smb_quota_list_mutex); 797*11963SAfshin.Ardakani@Sun.COM if (delete) 798*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(qtree); 799*11963SAfshin.Ardakani@Sun.COM (void) cond_broadcast(&smb_quota_list_condvar); 800*11963SAfshin.Ardakani@Sun.COM (void) mutex_unlock(&smb_quota_list_mutex); 801*11963SAfshin.Ardakani@Sun.COM } 802*11963SAfshin.Ardakani@Sun.COM 803*11963SAfshin.Ardakani@Sun.COM /* 804*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_match 805*11963SAfshin.Ardakani@Sun.COM * 806*11963SAfshin.Ardakani@Sun.COM * Determine if qtree represents the file system identified by path 807*11963SAfshin.Ardakani@Sun.COM */ 808*11963SAfshin.Ardakani@Sun.COM static boolean_t 809*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_match(smb_quota_tree_t *qtree, const char *path) 810*11963SAfshin.Ardakani@Sun.COM { 811*11963SAfshin.Ardakani@Sun.COM return (strncmp(qtree->qt_path, path, MAXPATHLEN) == 0); 812*11963SAfshin.Ardakani@Sun.COM } 813*11963SAfshin.Ardakani@Sun.COM 814*11963SAfshin.Ardakani@Sun.COM /* 815*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_create 816*11963SAfshin.Ardakani@Sun.COM * 817*11963SAfshin.Ardakani@Sun.COM * Create and initialize an smb_quota_tree_t structure 818*11963SAfshin.Ardakani@Sun.COM */ 819*11963SAfshin.Ardakani@Sun.COM static smb_quota_tree_t * 820*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_create(const char *path) 821*11963SAfshin.Ardakani@Sun.COM { 822*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_t *qtree; 823*11963SAfshin.Ardakani@Sun.COM 824*11963SAfshin.Ardakani@Sun.COM assert(MUTEX_HELD(&smb_quota_list_mutex)); 825*11963SAfshin.Ardakani@Sun.COM 826*11963SAfshin.Ardakani@Sun.COM qtree = malloc(sizeof (smb_quota_tree_t)); 827*11963SAfshin.Ardakani@Sun.COM if (qtree == NULL) 828*11963SAfshin.Ardakani@Sun.COM return (NULL); 829*11963SAfshin.Ardakani@Sun.COM 830*11963SAfshin.Ardakani@Sun.COM qtree->qt_path = strdup(path); 831*11963SAfshin.Ardakani@Sun.COM if (qtree->qt_path == NULL) { 832*11963SAfshin.Ardakani@Sun.COM free(qtree); 833*11963SAfshin.Ardakani@Sun.COM return (NULL); 834*11963SAfshin.Ardakani@Sun.COM } 835*11963SAfshin.Ardakani@Sun.COM 836*11963SAfshin.Ardakani@Sun.COM qtree->qt_timestamp = 0; 837*11963SAfshin.Ardakani@Sun.COM qtree->qt_locked = B_FALSE; 838*11963SAfshin.Ardakani@Sun.COM qtree->qt_refcnt = 1; 839*11963SAfshin.Ardakani@Sun.COM qtree->qt_sharecnt = 1; 840*11963SAfshin.Ardakani@Sun.COM 841*11963SAfshin.Ardakani@Sun.COM avl_create(&qtree->qt_avl, smb_quota_sid_cmp, 842*11963SAfshin.Ardakani@Sun.COM sizeof (smb_quota_t), offsetof(smb_quota_t, q_avl_node)); 843*11963SAfshin.Ardakani@Sun.COM 844*11963SAfshin.Ardakani@Sun.COM ++smb_quota_tree_cnt; 845*11963SAfshin.Ardakani@Sun.COM return (qtree); 846*11963SAfshin.Ardakani@Sun.COM } 847*11963SAfshin.Ardakani@Sun.COM 848*11963SAfshin.Ardakani@Sun.COM /* 849*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_delete 850*11963SAfshin.Ardakani@Sun.COM * 851*11963SAfshin.Ardakani@Sun.COM * Free and delete the smb_quota_tree_t structure. 852*11963SAfshin.Ardakani@Sun.COM * qtree must have no users (refcnt == 0). 853*11963SAfshin.Ardakani@Sun.COM */ 854*11963SAfshin.Ardakani@Sun.COM static void 855*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_delete(smb_quota_tree_t *qtree) 856*11963SAfshin.Ardakani@Sun.COM { 857*11963SAfshin.Ardakani@Sun.COM void *cookie = NULL; 858*11963SAfshin.Ardakani@Sun.COM smb_quota_t *node; 859*11963SAfshin.Ardakani@Sun.COM 860*11963SAfshin.Ardakani@Sun.COM assert(MUTEX_HELD(&smb_quota_list_mutex)); 861*11963SAfshin.Ardakani@Sun.COM assert(qtree->qt_refcnt == 0); 862*11963SAfshin.Ardakani@Sun.COM 863*11963SAfshin.Ardakani@Sun.COM while ((node = avl_destroy_nodes(&qtree->qt_avl, &cookie)) != NULL) 864*11963SAfshin.Ardakani@Sun.COM free(node); 865*11963SAfshin.Ardakani@Sun.COM avl_destroy(&qtree->qt_avl); 866*11963SAfshin.Ardakani@Sun.COM 867*11963SAfshin.Ardakani@Sun.COM free(qtree->qt_path); 868*11963SAfshin.Ardakani@Sun.COM free(qtree); 869*11963SAfshin.Ardakani@Sun.COM 870*11963SAfshin.Ardakani@Sun.COM --smb_quota_tree_cnt; 871*11963SAfshin.Ardakani@Sun.COM } 872*11963SAfshin.Ardakani@Sun.COM 873*11963SAfshin.Ardakani@Sun.COM /* 874*11963SAfshin.Ardakani@Sun.COM * smb_quota_sid_cmp 875*11963SAfshin.Ardakani@Sun.COM * 876*11963SAfshin.Ardakani@Sun.COM * Comparision function for nodes in an AVL tree which holds quota 877*11963SAfshin.Ardakani@Sun.COM * entries indexed by SID. 878*11963SAfshin.Ardakani@Sun.COM */ 879*11963SAfshin.Ardakani@Sun.COM static int 880*11963SAfshin.Ardakani@Sun.COM smb_quota_sid_cmp(const void *l_arg, const void *r_arg) 881*11963SAfshin.Ardakani@Sun.COM { 882*11963SAfshin.Ardakani@Sun.COM const char *l_sid = ((smb_quota_t *)l_arg)->q_sidstr; 883*11963SAfshin.Ardakani@Sun.COM const char *r_sid = ((smb_quota_t *)r_arg)->q_sidstr; 884*11963SAfshin.Ardakani@Sun.COM int ret; 885*11963SAfshin.Ardakani@Sun.COM 886*11963SAfshin.Ardakani@Sun.COM ret = strncasecmp(l_sid, r_sid, SMB_SID_STRSZ); 887*11963SAfshin.Ardakani@Sun.COM 888*11963SAfshin.Ardakani@Sun.COM if (ret > 0) 889*11963SAfshin.Ardakani@Sun.COM return (1); 890*11963SAfshin.Ardakani@Sun.COM if (ret < 0) 891*11963SAfshin.Ardakani@Sun.COM return (-1); 892*11963SAfshin.Ardakani@Sun.COM return (0); 893*11963SAfshin.Ardakani@Sun.COM } 894*11963SAfshin.Ardakani@Sun.COM 895*11963SAfshin.Ardakani@Sun.COM /* 896*11963SAfshin.Ardakani@Sun.COM * smb_quota_tree_populate 897*11963SAfshin.Ardakani@Sun.COM * 898*11963SAfshin.Ardakani@Sun.COM * If the quota tree needs to be (re)populated: 899*11963SAfshin.Ardakani@Sun.COM * - delete the qtree's contents 900*11963SAfshin.Ardakani@Sun.COM * - repopulate the qtree from zfs 901*11963SAfshin.Ardakani@Sun.COM * - set the qtree's timestamp. 902*11963SAfshin.Ardakani@Sun.COM */ 903*11963SAfshin.Ardakani@Sun.COM static uint32_t 904*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_populate(smb_quota_tree_t *qtree) 905*11963SAfshin.Ardakani@Sun.COM { 906*11963SAfshin.Ardakani@Sun.COM void *cookie = NULL; 907*11963SAfshin.Ardakani@Sun.COM void *node; 908*11963SAfshin.Ardakani@Sun.COM uint32_t status; 909*11963SAfshin.Ardakani@Sun.COM 910*11963SAfshin.Ardakani@Sun.COM assert(qtree->qt_locked); 911*11963SAfshin.Ardakani@Sun.COM 912*11963SAfshin.Ardakani@Sun.COM if (!smb_quota_tree_expired(qtree)) 913*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS); 914*11963SAfshin.Ardakani@Sun.COM 915*11963SAfshin.Ardakani@Sun.COM while ((node = avl_destroy_nodes(&qtree->qt_avl, &cookie)) != NULL) 916*11963SAfshin.Ardakani@Sun.COM free(node); 917*11963SAfshin.Ardakani@Sun.COM 918*11963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_get_quotas(qtree); 919*11963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS) 920*11963SAfshin.Ardakani@Sun.COM return (status); 921*11963SAfshin.Ardakani@Sun.COM 922*11963SAfshin.Ardakani@Sun.COM qtree->qt_timestamp = time(NULL); 923*11963SAfshin.Ardakani@Sun.COM 924*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS); 925*11963SAfshin.Ardakani@Sun.COM } 926*11963SAfshin.Ardakani@Sun.COM 927*11963SAfshin.Ardakani@Sun.COM static boolean_t 928*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_expired(smb_quota_tree_t *qtree) 929*11963SAfshin.Ardakani@Sun.COM { 930*11963SAfshin.Ardakani@Sun.COM time_t tnow = time(NULL); 931*11963SAfshin.Ardakani@Sun.COM return ((tnow - qtree->qt_timestamp) > SMB_QUOTA_REFRESH); 932*11963SAfshin.Ardakani@Sun.COM } 933*11963SAfshin.Ardakani@Sun.COM 934*11963SAfshin.Ardakani@Sun.COM static void 935*11963SAfshin.Ardakani@Sun.COM smb_quota_tree_set_expired(smb_quota_tree_t *qtree) 936*11963SAfshin.Ardakani@Sun.COM { 937*11963SAfshin.Ardakani@Sun.COM qtree->qt_timestamp = 0; 938*11963SAfshin.Ardakani@Sun.COM } 939*11963SAfshin.Ardakani@Sun.COM 940*11963SAfshin.Ardakani@Sun.COM /* 941*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_get_quotas 942*11963SAfshin.Ardakani@Sun.COM * 943*11963SAfshin.Ardakani@Sun.COM * Get user and group quotas from ZFS and use them to 944*11963SAfshin.Ardakani@Sun.COM * populate the quota tree. 945*11963SAfshin.Ardakani@Sun.COM */ 946*11963SAfshin.Ardakani@Sun.COM static uint32_t 947*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_get_quotas(smb_quota_tree_t *qtree) 948*11963SAfshin.Ardakani@Sun.COM { 949*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_handle_t zfs_hdl; 950*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_arg_t arg; 951*11963SAfshin.Ardakani@Sun.COM zfs_userquota_prop_t p; 952*11963SAfshin.Ardakani@Sun.COM uint32_t status = NT_STATUS_SUCCESS; 953*11963SAfshin.Ardakani@Sun.COM 954*11963SAfshin.Ardakani@Sun.COM status = smb_quota_zfs_init(qtree->qt_path, &zfs_hdl); 955*11963SAfshin.Ardakani@Sun.COM if (status != NT_STATUS_SUCCESS) 956*11963SAfshin.Ardakani@Sun.COM return (status); 957*11963SAfshin.Ardakani@Sun.COM 958*11963SAfshin.Ardakani@Sun.COM arg.qa_avl = &qtree->qt_avl; 959*11963SAfshin.Ardakani@Sun.COM for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) { 960*11963SAfshin.Ardakani@Sun.COM arg.qa_prop = p; 961*11963SAfshin.Ardakani@Sun.COM if (zfs_userspace(zfs_hdl.z_fs, p, 962*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_callback, &arg) != 0) { 963*11963SAfshin.Ardakani@Sun.COM status = NT_STATUS_INTERNAL_ERROR; 964*11963SAfshin.Ardakani@Sun.COM break; 965*11963SAfshin.Ardakani@Sun.COM } 966*11963SAfshin.Ardakani@Sun.COM } 967*11963SAfshin.Ardakani@Sun.COM 968*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_fini(&zfs_hdl); 969*11963SAfshin.Ardakani@Sun.COM return (status); 970*11963SAfshin.Ardakani@Sun.COM } 971*11963SAfshin.Ardakani@Sun.COM 972*11963SAfshin.Ardakani@Sun.COM /* 973*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_callback 974*11963SAfshin.Ardakani@Sun.COM * 975*11963SAfshin.Ardakani@Sun.COM * Find or create a node in the avl tree (arg->qa_avl) that matches 976*11963SAfshin.Ardakani@Sun.COM * the SID derived from domain and rid. If no domain is specified, 977*11963SAfshin.Ardakani@Sun.COM * lookup the sid (smb_quota_sidstr()). 978*11963SAfshin.Ardakani@Sun.COM * Populate the node. 979*11963SAfshin.Ardakani@Sun.COM * The property type (arg->qa_prop) determines which property 'space' 980*11963SAfshin.Ardakani@Sun.COM * refers to. 981*11963SAfshin.Ardakani@Sun.COM */ 982*11963SAfshin.Ardakani@Sun.COM static int 983*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_callback(void *arg, const char *domain, uid_t rid, uint64_t space) 984*11963SAfshin.Ardakani@Sun.COM { 985*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_arg_t *qarg = (smb_quota_zfs_arg_t *)arg; 986*11963SAfshin.Ardakani@Sun.COM zfs_userquota_prop_t qprop = qarg->qa_prop; 987*11963SAfshin.Ardakani@Sun.COM avl_tree_t *avl_tree = qarg->qa_avl; 988*11963SAfshin.Ardakani@Sun.COM avl_index_t where; 989*11963SAfshin.Ardakani@Sun.COM smb_quota_t *quota, key; 990*11963SAfshin.Ardakani@Sun.COM 991*11963SAfshin.Ardakani@Sun.COM if (domain == NULL || domain[0] == '\0') { 992*11963SAfshin.Ardakani@Sun.COM if (smb_quota_sidstr(rid, qprop, key.q_sidstr) != 0) 993*11963SAfshin.Ardakani@Sun.COM return (0); 994*11963SAfshin.Ardakani@Sun.COM } else { 995*11963SAfshin.Ardakani@Sun.COM (void) snprintf(key.q_sidstr, SMB_SID_STRSZ, "%s-%u", 996*11963SAfshin.Ardakani@Sun.COM domain, (uint32_t)rid); 997*11963SAfshin.Ardakani@Sun.COM } 998*11963SAfshin.Ardakani@Sun.COM 999*11963SAfshin.Ardakani@Sun.COM quota = avl_find(avl_tree, &key, &where); 1000*11963SAfshin.Ardakani@Sun.COM if (quota == NULL) { 1001*11963SAfshin.Ardakani@Sun.COM quota = malloc(sizeof (smb_quota_t)); 1002*11963SAfshin.Ardakani@Sun.COM if (quota == NULL) 1003*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_NO_MEMORY); 1004*11963SAfshin.Ardakani@Sun.COM bzero(quota, sizeof (smb_quota_t)); 1005*11963SAfshin.Ardakani@Sun.COM quota->q_thresh = SMB_QUOTA_UNLIMITED; 1006*11963SAfshin.Ardakani@Sun.COM quota->q_limit = SMB_QUOTA_UNLIMITED; 1007*11963SAfshin.Ardakani@Sun.COM avl_insert(avl_tree, (void *)quota, where); 1008*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(quota->q_sidstr, key.q_sidstr, SMB_SID_STRSZ); 1009*11963SAfshin.Ardakani@Sun.COM } 1010*11963SAfshin.Ardakani@Sun.COM 1011*11963SAfshin.Ardakani@Sun.COM switch (qprop) { 1012*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERUSED: 1013*11963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeUser; 1014*11963SAfshin.Ardakani@Sun.COM quota->q_used = space; 1015*11963SAfshin.Ardakani@Sun.COM break; 1016*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPUSED: 1017*11963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeGroup; 1018*11963SAfshin.Ardakani@Sun.COM quota->q_used = space; 1019*11963SAfshin.Ardakani@Sun.COM break; 1020*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERQUOTA: 1021*11963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeUser; 1022*11963SAfshin.Ardakani@Sun.COM quota->q_limit = space; 1023*11963SAfshin.Ardakani@Sun.COM break; 1024*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPQUOTA: 1025*11963SAfshin.Ardakani@Sun.COM quota->q_sidtype = SidTypeGroup; 1026*11963SAfshin.Ardakani@Sun.COM quota->q_limit = space; 1027*11963SAfshin.Ardakani@Sun.COM break; 1028*11963SAfshin.Ardakani@Sun.COM default: 1029*11963SAfshin.Ardakani@Sun.COM break; 1030*11963SAfshin.Ardakani@Sun.COM } 1031*11963SAfshin.Ardakani@Sun.COM 1032*11963SAfshin.Ardakani@Sun.COM quota->q_thresh = quota->q_limit; 1033*11963SAfshin.Ardakani@Sun.COM 1034*11963SAfshin.Ardakani@Sun.COM return (0); 1035*11963SAfshin.Ardakani@Sun.COM } 1036*11963SAfshin.Ardakani@Sun.COM 1037*11963SAfshin.Ardakani@Sun.COM /* 1038*11963SAfshin.Ardakani@Sun.COM * smb_quota_sidstr 1039*11963SAfshin.Ardakani@Sun.COM * 1040*11963SAfshin.Ardakani@Sun.COM * Use idmap to get the sid for the specified id and return 1041*11963SAfshin.Ardakani@Sun.COM * the string version of the sid in sidstr. 1042*11963SAfshin.Ardakani@Sun.COM * sidstr must be a buffer of at least SMB_SID_STRSZ. 1043*11963SAfshin.Ardakani@Sun.COM */ 1044*11963SAfshin.Ardakani@Sun.COM static int 1045*11963SAfshin.Ardakani@Sun.COM smb_quota_sidstr(uint32_t id, zfs_userquota_prop_t qprop, char *sidstr) 1046*11963SAfshin.Ardakani@Sun.COM { 1047*11963SAfshin.Ardakani@Sun.COM int idtype; 1048*11963SAfshin.Ardakani@Sun.COM smb_sid_t *sid; 1049*11963SAfshin.Ardakani@Sun.COM 1050*11963SAfshin.Ardakani@Sun.COM switch (qprop) { 1051*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERUSED: 1052*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_USERQUOTA: 1053*11963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_USER; 1054*11963SAfshin.Ardakani@Sun.COM break; 1055*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPUSED: 1056*11963SAfshin.Ardakani@Sun.COM case ZFS_PROP_GROUPQUOTA: 1057*11963SAfshin.Ardakani@Sun.COM idtype = SMB_IDMAP_GROUP; 1058*11963SAfshin.Ardakani@Sun.COM break; 1059*11963SAfshin.Ardakani@Sun.COM default: 1060*11963SAfshin.Ardakani@Sun.COM return (-1); 1061*11963SAfshin.Ardakani@Sun.COM } 1062*11963SAfshin.Ardakani@Sun.COM 1063*11963SAfshin.Ardakani@Sun.COM if (smb_idmap_getsid(id, idtype, &sid) != IDMAP_SUCCESS) 1064*11963SAfshin.Ardakani@Sun.COM return (-1); 1065*11963SAfshin.Ardakani@Sun.COM 1066*11963SAfshin.Ardakani@Sun.COM smb_sid_tostr(sid, sidstr); 1067*11963SAfshin.Ardakani@Sun.COM smb_sid_free(sid); 1068*11963SAfshin.Ardakani@Sun.COM 1069*11963SAfshin.Ardakani@Sun.COM return (0); 1070*11963SAfshin.Ardakani@Sun.COM } 1071*11963SAfshin.Ardakani@Sun.COM 1072*11963SAfshin.Ardakani@Sun.COM /* 1073*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_init 1074*11963SAfshin.Ardakani@Sun.COM * 1075*11963SAfshin.Ardakani@Sun.COM * Initialize zfs library and dataset handles 1076*11963SAfshin.Ardakani@Sun.COM */ 1077*11963SAfshin.Ardakani@Sun.COM static uint32_t 1078*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_init(const char *path, smb_quota_zfs_handle_t *zfs_hdl) 1079*11963SAfshin.Ardakani@Sun.COM { 1080*11963SAfshin.Ardakani@Sun.COM char dataset[MAXPATHLEN]; 1081*11963SAfshin.Ardakani@Sun.COM 1082*11963SAfshin.Ardakani@Sun.COM if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 1083*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INVALID_PARAMETER); 1084*11963SAfshin.Ardakani@Sun.COM 1085*11963SAfshin.Ardakani@Sun.COM if ((zfs_hdl->z_lib = libzfs_init()) == NULL) 1086*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_INTERNAL_ERROR); 1087*11963SAfshin.Ardakani@Sun.COM 1088*11963SAfshin.Ardakani@Sun.COM zfs_hdl->z_fs = zfs_open(zfs_hdl->z_lib, dataset, ZFS_TYPE_DATASET); 1089*11963SAfshin.Ardakani@Sun.COM if (zfs_hdl->z_fs == NULL) { 1090*11963SAfshin.Ardakani@Sun.COM libzfs_fini(zfs_hdl->z_lib); 1091*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_ACCESS_DENIED); 1092*11963SAfshin.Ardakani@Sun.COM } 1093*11963SAfshin.Ardakani@Sun.COM 1094*11963SAfshin.Ardakani@Sun.COM return (NT_STATUS_SUCCESS); 1095*11963SAfshin.Ardakani@Sun.COM } 1096*11963SAfshin.Ardakani@Sun.COM 1097*11963SAfshin.Ardakani@Sun.COM /* 1098*11963SAfshin.Ardakani@Sun.COM * smb_quota_zfs_fini 1099*11963SAfshin.Ardakani@Sun.COM * 1100*11963SAfshin.Ardakani@Sun.COM * Close zfs library and dataset handles 1101*11963SAfshin.Ardakani@Sun.COM */ 1102*11963SAfshin.Ardakani@Sun.COM static void 1103*11963SAfshin.Ardakani@Sun.COM smb_quota_zfs_fini(smb_quota_zfs_handle_t *zfs_hdl) 1104*11963SAfshin.Ardakani@Sun.COM { 1105*11963SAfshin.Ardakani@Sun.COM zfs_close(zfs_hdl->z_fs); 1106*11963SAfshin.Ardakani@Sun.COM libzfs_fini(zfs_hdl->z_lib); 1107*11963SAfshin.Ardakani@Sun.COM } 1108*11963SAfshin.Ardakani@Sun.COM 1109*11963SAfshin.Ardakani@Sun.COM /* 1110*11963SAfshin.Ardakani@Sun.COM * smb_quota_add_ctrldir 1111*11963SAfshin.Ardakani@Sun.COM * 1112*11963SAfshin.Ardakani@Sun.COM * In order to display the quota properties tab, windows clients 1113*11963SAfshin.Ardakani@Sun.COM * check for the existence of the quota control file, created 1114*11963SAfshin.Ardakani@Sun.COM * here as follows: 1115*11963SAfshin.Ardakani@Sun.COM * - Create SMB_QUOTA_CNTRL_DIR directory (with A_HIDDEN & A_SYSTEM 1116*11963SAfshin.Ardakani@Sun.COM * attributes). 1117*11963SAfshin.Ardakani@Sun.COM * - Create the SMB_QUOTA_CNTRL_FILE file (with extended attribute 1118*11963SAfshin.Ardakani@Sun.COM * SMB_QUOTA_CNTRL_INDEX_XATTR) in the SMB_QUOTA_CNTRL_DIR directory. 1119*11963SAfshin.Ardakani@Sun.COM * - Set the acl of SMB_QUOTA_CNTRL_FILE file to SMB_QUOTA_CNTRL_PERM. 1120*11963SAfshin.Ardakani@Sun.COM */ 1121*11963SAfshin.Ardakani@Sun.COM static void 1122*11963SAfshin.Ardakani@Sun.COM smb_quota_add_ctrldir(const char *path) 1123*11963SAfshin.Ardakani@Sun.COM { 1124*11963SAfshin.Ardakani@Sun.COM int newfd, dirfd, afd; 1125*11963SAfshin.Ardakani@Sun.COM nvlist_t *request; 1126*11963SAfshin.Ardakani@Sun.COM char dir[MAXPATHLEN], file[MAXPATHLEN]; 1127*11963SAfshin.Ardakani@Sun.COM acl_t *aclp; 1128*11963SAfshin.Ardakani@Sun.COM struct stat statbuf; 1129*11963SAfshin.Ardakani@Sun.COM 1130*11963SAfshin.Ardakani@Sun.COM assert(path != NULL); 1131*11963SAfshin.Ardakani@Sun.COM 1132*11963SAfshin.Ardakani@Sun.COM (void) snprintf(dir, MAXPATHLEN, ".%s/%s", path, SMB_QUOTA_CNTRL_DIR); 1133*11963SAfshin.Ardakani@Sun.COM (void) snprintf(file, MAXPATHLEN, "%s/%s", dir, SMB_QUOTA_CNTRL_FILE); 1134*11963SAfshin.Ardakani@Sun.COM if ((mkdir(dir, 0750) < 0) && (errno != EEXIST)) 1135*11963SAfshin.Ardakani@Sun.COM return; 1136*11963SAfshin.Ardakani@Sun.COM 1137*11963SAfshin.Ardakani@Sun.COM if ((dirfd = open(dir, O_RDONLY)) < 0) { 1138*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1139*11963SAfshin.Ardakani@Sun.COM return; 1140*11963SAfshin.Ardakani@Sun.COM } 1141*11963SAfshin.Ardakani@Sun.COM 1142*11963SAfshin.Ardakani@Sun.COM if (nvlist_alloc(&request, NV_UNIQUE_NAME, 0) == 0) { 1143*11963SAfshin.Ardakani@Sun.COM if ((nvlist_add_boolean_value(request, A_HIDDEN, 1) != 0) || 1144*11963SAfshin.Ardakani@Sun.COM (nvlist_add_boolean_value(request, A_SYSTEM, 1) != 0) || 1145*11963SAfshin.Ardakani@Sun.COM (fsetattr(dirfd, XATTR_VIEW_READWRITE, request))) { 1146*11963SAfshin.Ardakani@Sun.COM nvlist_free(request); 1147*11963SAfshin.Ardakani@Sun.COM (void) close(dirfd); 1148*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1149*11963SAfshin.Ardakani@Sun.COM return; 1150*11963SAfshin.Ardakani@Sun.COM } 1151*11963SAfshin.Ardakani@Sun.COM } 1152*11963SAfshin.Ardakani@Sun.COM nvlist_free(request); 1153*11963SAfshin.Ardakani@Sun.COM (void) close(dirfd); 1154*11963SAfshin.Ardakani@Sun.COM 1155*11963SAfshin.Ardakani@Sun.COM if (stat(file, &statbuf) != 0) { 1156*11963SAfshin.Ardakani@Sun.COM if ((newfd = creat(file, 0640)) < 0) { 1157*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1158*11963SAfshin.Ardakani@Sun.COM return; 1159*11963SAfshin.Ardakani@Sun.COM } 1160*11963SAfshin.Ardakani@Sun.COM (void) close(newfd); 1161*11963SAfshin.Ardakani@Sun.COM } 1162*11963SAfshin.Ardakani@Sun.COM 1163*11963SAfshin.Ardakani@Sun.COM afd = attropen(file, SMB_QUOTA_CNTRL_INDEX_XATTR, O_RDWR | O_CREAT, 1164*11963SAfshin.Ardakani@Sun.COM 0640); 1165*11963SAfshin.Ardakani@Sun.COM if (afd == -1) { 1166*11963SAfshin.Ardakani@Sun.COM (void) unlink(file); 1167*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1168*11963SAfshin.Ardakani@Sun.COM return; 1169*11963SAfshin.Ardakani@Sun.COM } 1170*11963SAfshin.Ardakani@Sun.COM (void) close(afd); 1171*11963SAfshin.Ardakani@Sun.COM 1172*11963SAfshin.Ardakani@Sun.COM if (acl_fromtext(SMB_QUOTA_CNTRL_PERM, &aclp) != 0) { 1173*11963SAfshin.Ardakani@Sun.COM (void) unlink(file); 1174*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1175*11963SAfshin.Ardakani@Sun.COM return; 1176*11963SAfshin.Ardakani@Sun.COM } 1177*11963SAfshin.Ardakani@Sun.COM 1178*11963SAfshin.Ardakani@Sun.COM if (acl_set(file, aclp) == -1) { 1179*11963SAfshin.Ardakani@Sun.COM (void) unlink(file); 1180*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1181*11963SAfshin.Ardakani@Sun.COM acl_free(aclp); 1182*11963SAfshin.Ardakani@Sun.COM return; 1183*11963SAfshin.Ardakani@Sun.COM } 1184*11963SAfshin.Ardakani@Sun.COM acl_free(aclp); 1185*11963SAfshin.Ardakani@Sun.COM } 1186*11963SAfshin.Ardakani@Sun.COM 1187*11963SAfshin.Ardakani@Sun.COM /* 1188*11963SAfshin.Ardakani@Sun.COM * smb_quota_remove_ctrldir 1189*11963SAfshin.Ardakani@Sun.COM * 1190*11963SAfshin.Ardakani@Sun.COM * Remove SMB_QUOTA_CNTRL_FILE and SMB_QUOTA_CNTRL_DIR. 1191*11963SAfshin.Ardakani@Sun.COM */ 1192*11963SAfshin.Ardakani@Sun.COM static void 1193*11963SAfshin.Ardakani@Sun.COM smb_quota_remove_ctrldir(const char *path) 1194*11963SAfshin.Ardakani@Sun.COM { 1195*11963SAfshin.Ardakani@Sun.COM char dir[MAXPATHLEN], file[MAXPATHLEN]; 1196*11963SAfshin.Ardakani@Sun.COM assert(path); 1197*11963SAfshin.Ardakani@Sun.COM 1198*11963SAfshin.Ardakani@Sun.COM (void) snprintf(dir, MAXPATHLEN, ".%s/%s", path, SMB_QUOTA_CNTRL_DIR); 1199*11963SAfshin.Ardakani@Sun.COM (void) snprintf(file, MAXPATHLEN, "%s/%s", dir, SMB_QUOTA_CNTRL_FILE); 1200*11963SAfshin.Ardakani@Sun.COM (void) unlink(file); 1201*11963SAfshin.Ardakani@Sun.COM (void) remove(dir); 1202*11963SAfshin.Ardakani@Sun.COM } 1203