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