Print this page
OS-3294 add support for inotify
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/udfs/udf_dir.c
+++ new/usr/src/uts/common/fs/udfs/udf_dir.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright (c) 2014, Joyent, Inc. All rights reserved.
23 24 */
24 25
25 26 #include <sys/types.h>
26 27 #include <sys/t_lock.h>
27 28 #include <sys/param.h>
28 29 #include <sys/time.h>
29 30 #include <sys/systm.h>
30 31 #include <sys/sysmacros.h>
31 32 #include <sys/resource.h>
32 33 #include <sys/signal.h>
33 34 #include <sys/cred.h>
34 35 #include <sys/user.h>
35 36 #include <sys/buf.h>
36 37 #include <sys/vfs.h>
37 38 #include <sys/stat.h>
38 39 #include <sys/vnode.h>
39 40 #include <sys/mode.h>
40 41 #include <sys/proc.h>
41 42 #include <sys/disp.h>
42 43 #include <sys/file.h>
43 44 #include <sys/fcntl.h>
44 45 #include <sys/flock.h>
45 46 #include <sys/kmem.h>
46 47 #include <sys/uio.h>
47 48 #include <sys/dnlc.h>
48 49 #include <sys/conf.h>
49 50 #include <sys/errno.h>
50 51 #include <sys/mman.h>
51 52 #include <sys/fbuf.h>
52 53 #include <sys/pathname.h>
53 54 #include <sys/debug.h>
54 55 #include <sys/vmsystm.h>
55 56 #include <sys/cmn_err.h>
56 57 #include <sys/dirent.h>
57 58 #include <sys/errno.h>
58 59 #include <sys/modctl.h>
59 60 #include <sys/statvfs.h>
60 61 #include <sys/mount.h>
61 62 #include <sys/sunddi.h>
62 63 #include <sys/bootconf.h>
63 64 #include <sys/policy.h>
64 65
65 66 #include <vm/hat.h>
66 67 #include <vm/page.h>
67 68 #include <vm/pvn.h>
68 69 #include <vm/as.h>
69 70 #include <vm/seg.h>
70 71 #include <vm/seg_map.h>
71 72 #include <vm/seg_kmem.h>
72 73 #include <vm/seg_vn.h>
73 74 #include <vm/rm.h>
74 75 #include <vm/page.h>
75 76 #include <sys/swap.h>
76 77
77 78
78 79 #include <fs/fs_subr.h>
79 80
80 81
81 82 #include <sys/fs/udf_volume.h>
82 83 #include <sys/fs/udf_inode.h>
83 84
84 85
85 86 struct slot {
86 87 enum {NONE, COMPACT, FOUND, EXIST} status;
87 88 off_t offset; /* offset of area with free space */
88 89 int size; /* size of area at slotoffset */
89 90 struct fbuf *fbp; /* dir buf where slot is */
90 91 struct file_id *ep; /* pointer to slot */
91 92 off_t endoff; /* last useful location found in search */
92 93 };
93 94
94 95
95 96 int32_t ud_dircheckforname(struct ud_inode *, char *, int,
96 97 struct slot *, struct ud_inode **, uint8_t *, struct cred *);
97 98 int32_t ud_dirempty(struct ud_inode *, uint64_t, struct cred *);
98 99 int32_t str2cmp(char *, int32_t, char *, int32_t, char *, int32_t);
99 100 int32_t ud_dircheckpath(int32_t, struct ud_inode *, struct cred *);
100 101 int32_t ud_dirmakeinode(struct ud_inode *, struct ud_inode **,
101 102 struct vattr *, enum de_op, struct cred *);
102 103 int32_t ud_diraddentry(struct ud_inode *, char *,
103 104 enum de_op, int, struct slot *, struct ud_inode *,
104 105 struct ud_inode *, struct cred *);
105 106 int32_t ud_dirmakedirect(struct ud_inode *, struct ud_inode *, struct cred *);
106 107 int32_t ud_dirrename(struct ud_inode *, struct ud_inode *,
107 108 struct ud_inode *, struct ud_inode *, char *, uint8_t *,
108 109 struct slot *, struct cred *);
109 110 int32_t ud_dirprepareentry(struct ud_inode *,
110 111 struct slot *, uint8_t *, struct cred *);
111 112 int32_t ud_dirfixdotdot(struct ud_inode *, struct ud_inode *,
112 113 struct ud_inode *);
113 114 int32_t ud_write_fid(struct ud_inode *, struct slot *, uint8_t *);
114 115
115 116 int
116 117 ud_dirlook(struct ud_inode *dip,
117 118 char *namep, struct ud_inode **ipp, struct cred *cr, int32_t skipdnlc)
118 119 {
119 120 struct udf_vfs *udf_vfsp;
120 121 int32_t error = 0, namelen, adhoc_search;
121 122 u_offset_t offset, adhoc_offset, dirsize, end;
122 123 struct vnode *dvp, *vp;
123 124 struct fbuf *fbp;
124 125 struct file_id *fid;
125 126 uint8_t *fname, dummy[3];
126 127 int32_t id_len, doingchk;
127 128 uint32_t old_loc;
128 129 uint16_t old_prn;
129 130
130 131 uint8_t *dname;
131 132 uint8_t *buf = NULL;
132 133
133 134 ud_printf("ud_dirlook\n");
134 135
135 136 udf_vfsp = dip->i_udf;
136 137
137 138 restart:
138 139 doingchk = 0;
139 140 old_prn = 0xFFFF;
140 141 old_loc = 0;
141 142 dvp = ITOV(dip);
142 143 /*
143 144 * Check accessibility of directory.
144 145 */
145 146 if (dip->i_type != VDIR) {
146 147 return (ENOTDIR);
147 148 }
148 149 if (error = ud_iaccess(dip, IEXEC, cr, 1)) {
149 150 return (error);
150 151 }
151 152
152 153 /*
153 154 * Null component name is synonym for directory being searched.
154 155 */
155 156 if (*namep == '\0') {
156 157 VN_HOLD(dvp);
157 158 *ipp = dip;
158 159 return (0);
159 160 }
160 161 namelen = strlen(namep);
161 162 if ((namelen == 1) &&
162 163 (namep[0] == '.') && (namep[1] == '\0')) {
163 164 /* Current directory */
164 165 VN_HOLD(dvp);
165 166 *ipp = dip;
166 167 dnlc_enter(dvp, namep, ITOV(*ipp));
167 168 return (0);
168 169 }
169 170
170 171 if ((!skipdnlc) && (vp = dnlc_lookup(dvp, namep))) {
171 172 /* vp is already held from dnlc_lookup */
172 173
173 174 *ipp = VTOI(vp);
174 175 return (0);
175 176 }
176 177
177 178 dname = kmem_zalloc(1024, KM_SLEEP);
178 179 buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
179 180
180 181 /*
181 182 * Read lock the inode we are searching. You will notice that we
182 183 * didn't hold the read lock while searching the dnlc. This means
183 184 * that the entry could now be in the dnlc. This doesn't cause any
184 185 * problems because dnlc_enter won't add an entry if it is already
185 186 * there.
186 187 */
187 188 rw_enter(&dip->i_rwlock, RW_READER);
188 189
189 190 /*
190 191 * Take care to look at dip->i_diroff only once, as it
191 192 * may be changing due to other threads/cpus.
192 193 */
193 194
194 195 recheck:
195 196 offset = dip->i_diroff;
196 197 end = dirsize = dip->i_size;
197 198
198 199 if (offset > dirsize) {
199 200 offset = 0;
200 201 }
201 202 adhoc_offset = offset;
202 203 adhoc_search = (offset == 0) ? 1 : 2;
203 204
204 205 fbp = NULL;
205 206
206 207 while (adhoc_search--) {
207 208 while (offset < end) {
208 209 error = ud_get_next_fid(dip, &fbp,
209 210 offset, &fid, &fname, buf);
210 211 if (error != 0) {
211 212 break;
212 213 }
213 214 if ((fid->fid_flags & FID_DELETED) == 0) {
214 215 if (fid->fid_flags & FID_PARENT) {
215 216 id_len = 2;
216 217 fname = dummy;
217 218 dummy[0] = '.';
218 219 dummy[1] = '.';
219 220 dummy[2] = '\0';
220 221 } else {
221 222 if ((error = ud_uncompress(
222 223 fid->fid_idlen, &id_len,
223 224 fname, dname)) != 0) {
224 225 break;
225 226 }
226 227 fname = (uint8_t *)dname;
227 228 fname[id_len] = '\0';
228 229 }
229 230 if ((namelen == id_len) &&
230 231 (strncmp(namep, (caddr_t)fname,
231 232 namelen) == 0)) {
232 233 uint32_t loc;
233 234 uint16_t prn;
234 235
235 236
236 237 loc = SWAP_32(fid->fid_icb.lad_ext_loc);
237 238 prn = SWAP_16(fid->fid_icb.lad_ext_prn);
238 239 dip->i_diroff = offset + FID_LEN(fid);
239 240
240 241 if (doingchk) {
241 242 if ((loc == old_loc) &&
242 243 (prn == old_prn)) {
243 244 goto checkok;
244 245 } else {
245 246 if (fbp != NULL) {
246 247 fbrelse(fbp,
247 248 S_READ);
248 249 fbp = NULL;
249 250 }
250 251 VN_RELE(ITOV(*ipp));
251 252 rw_exit(&dip->i_rwlock);
252 253 goto restart;
253 254 }
254 255 /* NOTREACHED */
255 256 }
256 257
257 258 if (namelen == 2 &&
258 259 fname[0] == '.' &&
259 260 fname[1] == '.') {
260 261
261 262 struct timespec32 omtime;
262 263
263 264 omtime = dip->i_mtime;
264 265 rw_exit(&dip->i_rwlock);
265 266
266 267 error = ud_iget(dip->i_vfs, prn,
267 268 loc, ipp, NULL, cr);
268 269
269 270 rw_enter(&dip->i_rwlock,
270 271 RW_READER);
271 272
272 273 if (error) {
273 274 goto done;
274 275 }
275 276
276 277 if ((omtime.tv_sec !=
277 278 dip->i_mtime.tv_sec) ||
278 279 (omtime.tv_nsec !=
279 280 dip->i_mtime.tv_nsec)) {
280 281
281 282 doingchk = 1;
282 283 old_prn = prn;
283 284 old_loc = loc;
284 285 dip->i_diroff = 0;
285 286 if (fbp != NULL) {
286 287 fbrelse(fbp,
287 288 S_READ);
288 289 fbp = NULL;
289 290 }
290 291 goto recheck;
291 292 }
292 293 } else {
293 294
294 295 error = ud_iget(dip->i_vfs, prn,
295 296 loc, ipp, NULL, cr);
296 297 }
297 298 checkok:
298 299 if (error == 0) {
299 300 dnlc_enter(dvp, namep,
300 301 ITOV(*ipp));
301 302 }
302 303 goto done;
303 304 }
304 305 }
305 306 offset += FID_LEN(fid);
306 307 }
307 308 if (fbp != NULL) {
308 309 fbrelse(fbp, S_READ);
309 310 fbp = NULL;
310 311 }
311 312 end = adhoc_offset;
312 313 offset = 0;
313 314 }
314 315 error = ENOENT;
315 316 done:
316 317 kmem_free(buf, udf_vfsp->udf_lbsize);
317 318 kmem_free(dname, 1024);
318 319 if (fbp != NULL) {
319 320 fbrelse(fbp, S_READ);
320 321 }
321 322 rw_exit(&dip->i_rwlock);
322 323 return (error);
323 324 }
324 325
325 326 int
326 327 ud_direnter(
327 328 struct ud_inode *tdp,
328 329 char *namep,
329 330 enum de_op op,
330 331 struct ud_inode *sdp,
331 332 struct ud_inode *sip,
332 333 struct vattr *vap,
333 334 struct ud_inode **ipp,
334 335 struct cred *cr,
335 336 caller_context_t *ctp)
336 337 {
337 338 struct udf_vfs *udf_vfsp;
338 339 struct ud_inode *tip;
339 340 struct slot slot;
340 341 int32_t namlen, err;
341 342 char *s;
342 343
343 344 uint8_t *buf = NULL;
344 345
345 346 ud_printf("ud_direnter\n");
346 347
347 348 udf_vfsp = tdp->i_udf;
348 349 /* don't allow '/' characters in pathname component */
349 350 for (s = namep, namlen = 0; *s; s++, namlen++) {
350 351 if (*s == '/') {
351 352 return (EACCES);
352 353 }
353 354 }
354 355
355 356 if (namlen == 0) {
356 357 cmn_err(CE_WARN, "name length == 0 in ud_direnter");
357 358 return (EINVAL);
358 359 }
359 360
360 361 ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
361 362 /*
362 363 * If name is "." or ".." then if this is a create look it up
363 364 * and return EEXIST. Rename or link TO "." or ".." is forbidden.
364 365 */
365 366 if (namep[0] == '.' &&
366 367 (namlen == 1 || (namlen == 2 && namep[1] == '.'))) {
367 368 if (op == DE_RENAME) {
368 369 return (EINVAL); /* *SIGH* should be ENOTEMPTY */
369 370 }
370 371 if (ipp) {
371 372 /*
372 373 * ud_dirlook will acquire the i_rwlock
373 374 */
374 375 rw_exit(&tdp->i_rwlock);
375 376 if (err = ud_dirlook(tdp, namep, ipp, cr, 0)) {
376 377 rw_enter(&tdp->i_rwlock, RW_WRITER);
377 378 return (err);
378 379 }
379 380 rw_enter(&tdp->i_rwlock, RW_WRITER);
380 381 }
381 382 return (EEXIST);
382 383 }
383 384
384 385 tip = NULL;
385 386 slot.status = NONE;
386 387 slot.offset = 0;
387 388 slot.size = 0;
388 389 slot.fbp = NULL;
389 390 slot.ep = NULL;
390 391 slot.endoff = 0;
391 392
392 393 /*
393 394 * For link and rename lock the source entry and check the link count
394 395 * to see if it has been removed while it was unlocked. If not, we
395 396 * increment the link count and force the inode to disk to make sure
396 397 * that it is there before any directory entry that points to it.
397 398 */
398 399 if (op == DE_LINK || op == DE_RENAME) {
399 400 rw_enter(&sip->i_contents, RW_WRITER);
400 401 if (sip->i_nlink == 0) {
401 402 rw_exit(&sip->i_contents);
402 403 return (ENOENT);
403 404 }
404 405 if (sip->i_nlink == MAXLINK) {
405 406 rw_exit(&sip->i_contents);
406 407 return (EMLINK);
407 408 }
408 409
409 410 sip->i_nlink++;
410 411 mutex_enter(&sip->i_tlock);
411 412 sip->i_flag |= ICHG;
412 413 mutex_exit(&sip->i_tlock);
413 414 ud_iupdat(sip, 1);
414 415 rw_exit(&sip->i_contents);
415 416 }
416 417 /*
417 418 * If target directory has not been removed, then we can consider
418 419 * allowing file to be created.
419 420 */
420 421 if (tdp->i_nlink == 0) {
421 422 err = ENOENT;
422 423 goto out2;
423 424 }
424 425 /*
425 426 * Check accessibility of directory.
426 427 */
427 428 if (tdp->i_type != VDIR) {
428 429 err = ENOTDIR;
429 430 goto out2;
430 431 }
431 432 /*
432 433 * Execute access is required to search the directory.
433 434 */
434 435 if (err = ud_iaccess(tdp, IEXEC, cr, 1)) {
435 436 goto out2;
436 437 }
437 438 /*
438 439 * If this is a rename of a directory and the parent is
439 440 * different (".." must be changed), then the source
440 441 * directory must not be in the directory hierarchy
441 442 * above the target, as this would orphan everything
442 443 * below the source directory. Also the user must have
443 444 * write permission in the source so as to be able to
444 445 * change "..".
445 446 */
446 447 if (op == DE_RENAME) {
447 448 if (sip == tdp) {
448 449 err = EINVAL;
449 450 goto out2;
450 451 }
451 452 rw_enter(&sip->i_contents, RW_READER);
452 453 if ((sip->i_type == VDIR) && (sdp != tdp)) {
453 454 uint32_t blkno;
454 455
455 456 if ((err = ud_iaccess(sip, IWRITE, cr, 0))) {
456 457 rw_exit(&sip->i_contents);
457 458 goto out2;
458 459 }
459 460 blkno = sip->i_icb_lbano;
460 461 rw_exit(&sip->i_contents);
461 462 if ((err = ud_dircheckpath(blkno, tdp, cr))) {
462 463 goto out2;
463 464 }
464 465 } else {
465 466 rw_exit(&sip->i_contents);
466 467 }
467 468 }
468 469
469 470 /*
470 471 * Search for the entry. Return VN_HELD tip if found.
471 472 */
472 473 buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
473 474 rw_enter(&tdp->i_contents, RW_WRITER);
474 475 if (err = ud_dircheckforname(tdp,
475 476 namep, namlen, &slot, &tip, buf, cr)) {
476 477 goto out;
477 478 }
478 479 if (tip) {
479 480 switch (op) {
480 481 case DE_CREATE :
481 482 case DE_MKDIR :
482 483 if (ipp) {
483 484 *ipp = tip;
484 485 err = EEXIST;
485 486 } else {
486 487 VN_RELE(ITOV(tip));
487 488 }
488 489 break;
489 490 case DE_RENAME :
490 491 err = ud_dirrename(sdp, sip, tdp, tip,
491 492 namep, buf, &slot, cr);
492 493 /*
493 494 * We used to VN_RELE() here, but this
494 495 * was moved down so that we could send
495 496 * a vnevent after the locks were dropped.
496 497 */
497 498 break;
498 499 case DE_LINK :
499 500 /*
500 501 * Can't link to an existing file.
501 502 */
502 503 VN_RELE(ITOV(tip));
503 504 err = EEXIST;
504 505 break;
505 506 }
506 507 } else {
507 508 /*
508 509 * The entry does not exist. Check write permission in
509 510 * directory to see if entry can be created.
510 511 */
511 512 if (err = ud_iaccess(tdp, IWRITE, cr, 0)) {
512 513 goto out;
513 514 }
514 515 if ((op == DE_CREATE) || (op == DE_MKDIR)) {
515 516 /*
516 517 * Make new inode and directory entry as required.
517 518 */
518 519 if (err = ud_dirmakeinode(tdp, &sip, vap, op, cr))
519 520 goto out;
520 521 }
521 522 if (err = ud_diraddentry(tdp, namep, op,
522 523 namlen, &slot, sip, sdp, cr)) {
523 524 if ((op == DE_CREATE) || (op == DE_MKDIR)) {
524 525 /*
525 526 * Unmake the inode we just made.
526 527 */
527 528 rw_enter(&sip->i_contents, RW_WRITER);
528 529 if (sip->i_type == VDIR) {
529 530 tdp->i_nlink--;
530 531 }
531 532 sip->i_nlink = 0;
532 533 mutex_enter(&sip->i_tlock);
533 534 sip->i_flag |= ICHG;
534 535 mutex_exit(&sip->i_tlock);
535 536 rw_exit(&sip->i_contents);
536 537 VN_RELE(ITOV(sip));
537 538 sip = NULL;
538 539 }
539 540 } else if (ipp) {
540 541 *ipp = sip;
541 542 } else if ((op == DE_CREATE) || (op == DE_MKDIR)) {
542 543 VN_RELE(ITOV(sip));
543 544 }
544 545 }
545 546 out:
546 547 if (buf != NULL) {
547 548 kmem_free(buf, udf_vfsp->udf_lbsize);
548 549 }
549 550 if (slot.fbp) {
550 551 fbrelse(slot.fbp, S_OTHER);
551 552 }
552 553 rw_exit(&tdp->i_contents);
553 554
554 555 if (op == DE_RENAME) {
|
↓ open down ↓ |
522 lines elided |
↑ open up ↑ |
555 556 /*
556 557 * If it's all good, send events after locks are dropped
557 558 * but before vnodes are released.
558 559 */
559 560 if (err == 0) {
560 561 if (tip) {
561 562 vnevent_rename_dest(ITOV(tip), ITOV(tdp),
562 563 namep, ctp);
563 564 }
564 565
565 - if (sdp != tdp) {
566 - vnevent_rename_dest_dir(ITOV(tdp), ctp);
567 - }
566 + vnevent_rename_dest_dir(ITOV(tdp), ITOV(tip),
567 + namep, ctp);
568 568 }
569 569
570 570 /*
571 571 * The following VN_RELE() was moved from the
572 572 * DE_RENAME case above
573 573 */
574 574 if (tip) {
575 575 VN_RELE(ITOV(tip));
576 576 }
577 577 }
578 578
579 579 out2:
580 580 if (err && ((op == DE_LINK) || (op == DE_RENAME))) {
581 581 /*
582 582 * Undo bumped link count.
583 583 */
584 584 rw_enter(&sip->i_contents, RW_WRITER);
585 585 sip->i_nlink--;
586 586 rw_exit(&sip->i_contents);
587 587
588 588 mutex_enter(&sip->i_tlock);
589 589 sip->i_flag |= ICHG;
590 590 mutex_exit(&sip->i_tlock);
591 591 }
592 592 return (err);
593 593 }
594 594
595 595 /*
596 596 * Locking i_contents in this
597 597 * function seems to be really weird
598 598 */
599 599 int
600 600 ud_dirremove(
601 601 struct ud_inode *dp,
602 602 char *namep,
603 603 struct ud_inode *oip,
604 604 struct vnode *cdir,
605 605 enum dr_op op,
606 606 struct cred *cr,
607 607 caller_context_t *ctp)
608 608 {
609 609 struct udf_vfs *udf_vfsp;
610 610 int32_t namelen, err = 0;
611 611 struct slot slot;
612 612 struct ud_inode *ip;
613 613 mode_t mode;
614 614 struct file_id *fid;
615 615 uint8_t *buf = NULL;
616 616 uint32_t tbno;
617 617
618 618 ud_printf("ud_dirremove\n");
619 619
620 620 ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
621 621
622 622 udf_vfsp = dp->i_udf;
623 623 namelen = (int)strlen(namep);
624 624 if (namelen == 0) {
625 625 cmn_err(CE_WARN, "name length == 0 in ud_dirremove");
626 626 return (EINVAL);
627 627 }
628 628
629 629 /*
630 630 * return err when removing . and ..
631 631 */
632 632 if (namep[0] == '.') {
633 633 if (namelen == 1) {
634 634 return (EINVAL);
635 635 } else if (namelen == 2 && namep[1] == '.') {
636 636 return (EEXIST); /* SIGH should be ENOTEMPTY */
637 637 }
638 638 }
639 639
640 640 ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
641 641
642 642 /*
643 643 * Check accessibility of directory.
644 644 */
645 645 if (dp->i_type != VDIR) {
646 646 return (ENOTDIR);
647 647 }
648 648
649 649 ip = NULL;
650 650 slot.status = FOUND; /* don't need to look for empty slot */
651 651 slot.offset = 0;
652 652 slot.size = 0;
653 653 slot.fbp = NULL;
654 654 slot.ep = NULL;
655 655 slot.endoff = 0;
656 656 /*
657 657 * Execute access is required to search the directory.
658 658 * Access for write is interpreted as allowing
659 659 * deletion of files in the directory.
660 660 */
661 661 if (err = ud_iaccess(dp, IEXEC|IWRITE, cr, 1)) {
662 662 return (err);
663 663 }
664 664
665 665 buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
666 666
667 667 rw_enter(&dp->i_contents, RW_WRITER);
668 668
669 669 if (err = ud_dircheckforname(dp, namep, namelen, &slot, &ip,
670 670 buf, cr)) {
671 671 goto out_novfs;
672 672 }
673 673 if (ip == NULL) {
674 674 err = ENOENT;
675 675 goto out_novfs;
676 676 }
677 677 if (oip && oip != ip) {
678 678 err = ENOENT;
679 679 goto out_novfs;
680 680 }
681 681
682 682 if ((mode = ip->i_type) == VDIR) {
683 683 /*
684 684 * vn_vfswlock() prevents races between mount and rmdir.
685 685 */
686 686 if (vn_vfswlock(ITOV(ip))) {
687 687 err = EBUSY;
688 688 goto out_novfs;
689 689 }
690 690 if (vn_mountedvfs(ITOV(ip)) != NULL && op != DR_RENAME) {
691 691 err = EBUSY;
692 692 goto out;
693 693 }
694 694 /*
695 695 * If we are removing a directory, get a lock on it.
696 696 * If the directory is empty, it will stay empty until
697 697 * we can remove it.
698 698 */
699 699 rw_enter(&ip->i_rwlock, RW_READER);
700 700 }
701 701 /* We must be holding i_contents */
702 702 rw_enter(&ip->i_contents, RW_READER);
703 703
704 704 if (err = ud_sticky_remove_access(dp, ip, cr)) {
705 705 rw_exit(&ip->i_contents);
706 706 if (mode == VDIR) {
707 707 rw_exit(&ip->i_rwlock);
708 708 }
709 709 goto out;
710 710 }
711 711 if (op == DR_RMDIR) {
712 712 /*
713 713 * For rmdir(2), some special checks are required.
714 714 * (a) Don't remove any alias of the parent (e.g. ".").
715 715 * (b) Don't remove the current directory.
716 716 * (c) Make sure the entry is (still) a directory.
717 717 * (d) Make sure the directory is empty.
718 718 */
719 719
720 720 if (dp == ip || ITOV(ip) == cdir) {
721 721 err = EINVAL;
722 722 } else if (ip->i_type != VDIR) {
723 723 err = ENOTDIR;
724 724 } else if ((ip->i_nlink != 1) ||
725 725 (!ud_dirempty(ip, dp->i_uniqid, cr))) {
726 726 /*
727 727 * Directories do not have an
728 728 * entry for "." so only one link
729 729 * will be there
730 730 */
731 731 err = EEXIST; /* SIGH should be ENOTEMPTY */
732 732 }
733 733 if (err) {
734 734 rw_exit(&ip->i_contents);
735 735 if (mode == VDIR) {
736 736 rw_exit(&ip->i_rwlock);
737 737 }
738 738 goto out;
739 739 }
740 740 } else if (op == DR_REMOVE) {
741 741 /*
742 742 * unlink(2) requires a different check: allow only
743 743 * privileged processes to unlink a directory.
744 744 */
745 745 struct vnode *vp = ITOV(ip);
746 746
747 747 if (vp->v_type == VDIR &&
748 748 secpolicy_fs_linkdir(cr, vp->v_vfsp)) {
749 749 err = EPERM;
750 750 rw_exit(&ip->i_contents);
751 751 rw_exit(&ip->i_rwlock);
752 752 goto out;
753 753 }
754 754 }
755 755 rw_exit(&ip->i_contents);
756 756
757 757 /*
758 758 * Remove the cache'd entry, if any.
759 759 */
760 760 dnlc_remove(ITOV(dp), namep);
761 761
762 762 /*
763 763 * We can collapse all the directory
764 764 * entries that are deleted into one big entry
765 765 * but the better way is to
766 766 * defer it till next directory entry
767 767 * creation. where we can do this
768 768 * in a more efficient way
769 769 */
770 770 fid = slot.ep;
771 771
772 772 /*
773 773 * If this is the last entry
774 774 * just truncate the file instead
775 775 * of marking it deleted
776 776 */
777 777 if ((slot.offset + FID_LEN(fid)) == dp->i_size) {
778 778 fbrelse(slot.fbp, S_OTHER);
779 779 if ((err = ud_itrunc(dp, slot.offset, 0, cr)) != 0) {
780 780 goto out;
781 781 }
782 782 } else {
783 783 fid->fid_flags |= FID_DELETED;
784 784
785 785 if ((err = ud_ip_off2bno(dp, slot.offset, &tbno)) != 0) {
786 786 goto out;
787 787 }
788 788
789 789 ud_make_tag(dp->i_udf, &fid->fid_tag,
790 790 UD_FILE_ID_DESC, tbno, FID_LEN(fid));
791 791
792 792 err = ud_write_fid(dp, &slot, buf);
793 793 }
794 794
795 795 slot.fbp = NULL;
796 796
797 797 /*
798 798 * If we were removing a directory, it is 'gone' now so we can
799 799 * unlock it.
800 800 */
801 801 if (mode == VDIR) {
802 802 rw_exit(&ip->i_rwlock);
803 803 }
804 804
805 805 mutex_enter(&dp->i_tlock);
806 806 dp->i_flag |= IUPD|ICHG;
807 807 mutex_exit(&dp->i_tlock);
808 808 mutex_enter(&ip->i_tlock);
809 809 ip->i_flag |= ICHG;
810 810 mutex_exit(&ip->i_tlock);
811 811
812 812 if (err != 0) {
813 813 goto out;
814 814 }
815 815
816 816 rw_enter(&ip->i_contents, RW_WRITER);
817 817
818 818 /*
819 819 * Now dispose of the inode.
820 820 */
821 821 if (ip->i_nlink > 0) {
822 822 if ((op == DR_RMDIR) && (ip->i_type == VDIR)) {
823 823 /*
824 824 * Decrement by 1 because there is no "."
825 825 * Clear the inode, but there may be other hard
826 826 * links so don't free the inode.
827 827 * Decrement the dp linkcount because we're
828 828 * trashing the ".." entry.
829 829 */
830 830 ip->i_nlink --;
831 831 dp->i_nlink--;
832 832 dnlc_remove(ITOV(ip), ".");
833 833 dnlc_remove(ITOV(ip), "..");
834 834 /*
835 835 * (void) ud_itrunc(ip, 0, 0, cr);
836 836 */
837 837 } else {
838 838 ip->i_nlink--;
839 839 }
840 840 }
841 841 ITIMES_NOLOCK(dp);
842 842 ITIMES_NOLOCK(ip);
843 843 rw_exit(&ip->i_contents);
844 844 out:
845 845 if (mode == VDIR) {
846 846 vn_vfsunlock(ITOV(ip));
847 847 }
848 848 out_novfs:
849 849 ASSERT(RW_WRITE_HELD(&dp->i_contents));
850 850
851 851 if (slot.fbp != NULL) {
852 852 fbrelse(slot.fbp, S_OTHER);
853 853 }
854 854 rw_exit(&dp->i_contents);
855 855
856 856 if (ip) {
857 857 /*
858 858 * If no errors, send any events after locks are dropped,
859 859 * but before the VN_RELE().
860 860 */
861 861 if (err == 0) {
862 862 if (op == DR_REMOVE) {
863 863 vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
864 864 } else if (op == DR_RMDIR) {
865 865 vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
866 866 }
867 867 }
868 868 VN_RELE(ITOV(ip));
869 869 }
870 870
871 871 kmem_free(buf, udf_vfsp->udf_lbsize);
872 872 return (err);
873 873 }
874 874
875 875 int
876 876 ud_dircheckforname(struct ud_inode *tdp,
877 877 char *namep, int32_t namelen, struct slot *slotp,
878 878 struct ud_inode **ipp, uint8_t *buf, struct cred *cr)
879 879 {
880 880 struct udf_vfs *udf_vfsp;
881 881 uint32_t dirsize, offset;
882 882 struct fbuf *fbp;
883 883 struct file_id *fid;
884 884 int32_t sz, error = 0, sz_req, matched = 0;
885 885 uint8_t *nm;
886 886
887 887 uint8_t *dname;
888 888 int32_t id_len;
889 889
890 890 ud_printf("ud_dircheckforname\n");
891 891
892 892 ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
893 893 fbp = NULL;
894 894
895 895 dname = (uint8_t *)kmem_zalloc(1024, KM_SLEEP);
896 896
897 897 udf_vfsp = tdp->i_udf;
898 898
899 899 offset = 0;
900 900 dirsize = tdp->i_size;
901 901
902 902 if (slotp->status != FOUND) {
903 903 int32_t temp;
904 904
905 905 temp = 1024; /* set to size of dname allocated above */
906 906 if ((error = ud_compress(namelen, &temp,
907 907 (uint8_t *)namep, dname)) != 0) {
908 908 goto end;
909 909 }
910 910 sz_req = F_LEN + temp;
911 911 sz_req = (sz_req + 3) & ~3;
912 912 }
913 913
914 914 while (offset < dirsize) {
915 915 if ((error = ud_get_next_fid(tdp, &fbp,
916 916 offset, &fid, &nm, buf)) != 0) {
917 917 break;
918 918 }
919 919 if ((error = ud_uncompress(fid->fid_idlen,
920 920 &id_len, nm, dname)) != 0) {
921 921 break;
922 922 }
923 923 if ((fid->fid_flags & FID_DELETED) == 0) {
924 924 /* Check for name match */
925 925 if (((namelen == id_len) &&
926 926 (strncmp(namep, (caddr_t)dname, namelen) == 0)) ||
927 927 ((fid->fid_flags & FID_PARENT) &&
928 928 (namep[0] == '.' &&
929 929 (namelen == 1 ||
930 930 (namelen == 2 && namep[1] == '.'))))) {
931 931
932 932 tdp->i_diroff = offset;
933 933 if ((fid->fid_flags & FID_PARENT) &&
934 934 (namelen == 1) && (namep[0] == '.')) {
935 935 struct vnode *vp = ITOV(tdp);
936 936
937 937 *ipp = tdp;
938 938 VN_HOLD(vp);
939 939 } else {
940 940 uint16_t prn;
941 941 uint32_t loc;
942 942
943 943 prn = SWAP_16(fid->fid_icb.lad_ext_prn);
944 944 loc = SWAP_32(fid->fid_icb.lad_ext_loc);
945 945 if ((error = ud_iget(tdp->i_vfs, prn,
946 946 loc, ipp, NULL, cr)) != 0) {
947 947
948 948 fbrelse(fbp, S_OTHER);
949 949 goto end;
950 950 }
951 951 }
952 952 slotp->status = EXIST;
953 953 slotp->offset = offset;
954 954 slotp->size = FID_LEN(fid);
955 955 slotp->fbp = fbp;
956 956 slotp->ep = fid;
957 957 slotp->endoff = 0;
958 958 goto end;
959 959 }
960 960 } else {
961 961 /*
962 962 * see if we need to find an
963 963 * empty slot and the current slot
964 964 * matches
965 965 */
966 966 if ((slotp->status != FOUND) || (matched == 0)) {
967 967 sz = FID_LEN(fid);
968 968 if (sz == sz_req) {
969 969 slotp->status = FOUND;
970 970 slotp->offset = offset;
971 971 slotp->size = sz;
972 972 }
973 973 if (matched == 0) {
974 974 if ((namelen == id_len) &&
975 975 (strncmp(namep, (caddr_t)dname,
976 976 namelen) == 0)) {
977 977 matched = 1;
978 978 slotp->status = FOUND;
979 979 slotp->offset = offset;
980 980 slotp->size = sz;
981 981 }
982 982 }
983 983 }
984 984 }
985 985 offset += FID_LEN(fid);
986 986 }
987 987 if (fbp) {
988 988 fbrelse(fbp, S_OTHER);
989 989 }
990 990 if (slotp->status == NONE) {
991 991 /*
992 992 * We didn't find a slot; the new directory entry should be put
993 993 * at the end of the directory. Return an indication of where
994 994 * this is, and set "endoff" to zero; since we're going to have
995 995 * to extend the directory, we're certainly not going to
996 996 * trucate it.
997 997 */
998 998 slotp->offset = dirsize;
999 999 if (tdp->i_desc_type == ICB_FLAG_ONE_AD) {
1000 1000 slotp->size = tdp->i_max_emb - tdp->i_size;
1001 1001 } else {
1002 1002 slotp->size = udf_vfsp->udf_lbsize -
1003 1003 slotp->offset & udf_vfsp->udf_lbmask;
1004 1004 }
1005 1005 slotp->endoff = 0;
1006 1006 }
1007 1007
1008 1008 *ipp = NULL;
1009 1009 end:
1010 1010 kmem_free((caddr_t)dname, 1024);
1011 1011 return (error);
1012 1012 }
1013 1013
1014 1014 /*
1015 1015 * Return 1 if the dir has all files
1016 1016 * deleted except the parent
1017 1017 * else return 0
1018 1018 */
1019 1019 /* ARGSUSED */
1020 1020 int
1021 1021 ud_dirempty(struct ud_inode *ip, uint64_t ino, struct cred *cr)
1022 1022 {
1023 1023 offset_t off;
1024 1024 int32_t empty = 1, error, count, entry_len, rcount;
1025 1025 struct file_id *fid;
1026 1026 caddr_t addr;
1027 1027 uint32_t tbno;
1028 1028 int32_t desc_len;
1029 1029
1030 1030 ud_printf("ud_dirempty\n");
1031 1031
1032 1032 ASSERT(RW_LOCK_HELD(&ip->i_contents));
1033 1033
1034 1034 if (ip->i_size == 0) {
1035 1035 return (empty);
1036 1036 }
1037 1037
1038 1038 desc_len = 1024;
1039 1039 addr = kmem_zalloc(desc_len, KM_SLEEP);
1040 1040 fid = (struct file_id *)addr;
1041 1041
1042 1042 for (off = 0; off < ip->i_size; off += entry_len) {
1043 1043
1044 1044 /*
1045 1045 * First read fid
1046 1046 * and verify checksum
1047 1047 */
1048 1048
1049 1049 rcount = sizeof (struct file_id);
1050 1050 error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1051 1051 UIO_SYSSPACE, &count, cr);
1052 1052 if ((error != 0) || (count != 0)) {
1053 1053 empty = 0;
1054 1054 break;
1055 1055 }
1056 1056
1057 1057 if ((error = ud_ip_off2bno(ip, off, &tbno)) != 0) {
1058 1058 empty = 0;
1059 1059 break;
1060 1060 }
1061 1061
1062 1062 /*
1063 1063 * We verify the tag id and also the FID_LEN.
1064 1064 * FID_LEN should be <= desc_len.
1065 1065 */
1066 1066 if (ud_verify_tag_and_desc(&fid->fid_tag,
1067 1067 UD_FILE_ID_DESC,
1068 1068 tbno, 0, desc_len) != 0) {
1069 1069 /* Corrupted directory */
1070 1070 empty = 0;
1071 1071 break;
1072 1072 }
1073 1073
1074 1074 /*
1075 1075 * Read the fid + iulen + len
1076 1076 * Now verify both checksum andCRC
1077 1077 */
1078 1078
1079 1079 rcount = FID_LEN(fid);
1080 1080 error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1081 1081 UIO_SYSSPACE, &count, cr);
1082 1082 if ((error != 0) || (count != 0)) {
1083 1083 empty = 0;
1084 1084 break;
1085 1085 }
1086 1086 /*
1087 1087 * Now that the entire decsriptor is read we verify the
1088 1088 * crc.
1089 1089 */
1090 1090 if (ud_verify_tag_and_desc(&fid->fid_tag,
1091 1091 UD_FILE_ID_DESC,
1092 1092 tbno,
1093 1093 1, rcount) != 0) {
1094 1094 /* Corrupted directory */
1095 1095 empty = 0;
1096 1096 break;
1097 1097 }
1098 1098
1099 1099 /*
1100 1100 * Is the file deleted
1101 1101 */
1102 1102
1103 1103 if ((fid->fid_flags & FID_DELETED) == 0) {
1104 1104 if ((fid->fid_flags & FID_PARENT) == 0) {
1105 1105 empty = 0;
1106 1106 break;
1107 1107 }
1108 1108 }
1109 1109 entry_len = FID_LEN(fid);
1110 1110 }
1111 1111
1112 1112 kmem_free(addr, 1024);
1113 1113
1114 1114 return (empty);
1115 1115 }
1116 1116
1117 1117
1118 1118 int
1119 1119 ud_dircheckpath(int32_t blkno,
1120 1120 struct ud_inode *target, struct cred *cr)
1121 1121 {
1122 1122 int32_t err = 0;
1123 1123 struct vfs *vfsp;
1124 1124 struct udf_vfs *udf_vfsp;
1125 1125 struct fbuf *fbp;
1126 1126 struct file_id *fid;
1127 1127 struct ud_inode *ip, *tip;
1128 1128 uint16_t prn;
1129 1129 uint32_t lbno, dummy, tbno;
1130 1130 daddr_t parent_icb_loc;
1131 1131
1132 1132 ud_printf("ud_dircheckpath\n");
1133 1133
1134 1134 udf_vfsp = target->i_udf;
1135 1135 ip = target;
1136 1136
1137 1137 ASSERT(udf_vfsp != NULL);
1138 1138 ASSERT(MUTEX_HELD(&target->i_udf->udf_rename_lck));
1139 1139 ASSERT(RW_WRITE_HELD(&ip->i_rwlock));
1140 1140
1141 1141 if (ip->i_icb_lbano == blkno) {
1142 1142 err = EINVAL;
1143 1143 goto out;
1144 1144 }
1145 1145 if (ip->i_icb_lbano == udf_vfsp->udf_root_blkno) {
1146 1146 goto out;
1147 1147 }
1148 1148
1149 1149 /*
1150 1150 * Search back through the directory tree, using the PARENT entries
1151 1151 * Fail any attempt to move a directory into an ancestor directory.
1152 1152 */
1153 1153 for (;;) {
1154 1154 if ((err = fbread(ITOV(ip), 0,
1155 1155 udf_vfsp->udf_lbsize, S_READ, &fbp)) != 0) {
1156 1156 break;
1157 1157 }
1158 1158
1159 1159 if ((err = ud_ip_off2bno(ip, 0, &tbno)) != 0) {
1160 1160 break;
1161 1161 }
1162 1162 fid = (struct file_id *)fbp->fb_addr;
1163 1163 /* IS this a valid file_identifier */
1164 1164 if (ud_verify_tag_and_desc(&fid->fid_tag,
1165 1165 UD_FILE_ID_DESC,
1166 1166 tbno,
1167 1167 1, udf_vfsp->udf_lbsize) != 0) {
1168 1168 break;
1169 1169 }
1170 1170 if ((fid->fid_flags & FID_DELETED) != 0) {
1171 1171 break;
1172 1172 }
1173 1173 if ((fid->fid_flags & FID_PARENT) == 0) {
1174 1174 /*
1175 1175 * This cannot happen unless
1176 1176 * something is grossly wrong
1177 1177 * First entry has to be parent
1178 1178 */
1179 1179 break;
1180 1180 }
1181 1181 prn = SWAP_16(fid->fid_icb.lad_ext_prn);
1182 1182 lbno = SWAP_32(fid->fid_icb.lad_ext_loc);
1183 1183 parent_icb_loc =
1184 1184 ud_xlate_to_daddr(udf_vfsp, prn, lbno, 1, &dummy);
1185 1185 ASSERT(dummy == 1);
1186 1186 if (parent_icb_loc == blkno) {
1187 1187 err = EINVAL;
1188 1188 break;
1189 1189 }
1190 1190 vfsp = ip->i_vfs;
1191 1191 udf_vfsp = ip->i_udf;
1192 1192 if (parent_icb_loc == udf_vfsp->udf_root_blkno) {
1193 1193 break;
1194 1194 }
1195 1195 if (fbp != NULL) {
1196 1196 fbrelse(fbp, S_OTHER);
1197 1197 fbp = NULL;
1198 1198 }
1199 1199 if (ip != target) {
1200 1200 rw_exit(&ip->i_rwlock);
1201 1201 VN_RELE(ITOV(ip));
1202 1202 }
1203 1203
1204 1204 /*
1205 1205 * Race to get the inode.
1206 1206 */
1207 1207 if (err = ud_iget(vfsp, prn, lbno, &tip, NULL, cr)) {
1208 1208 ip = NULL;
1209 1209 break;
1210 1210 }
1211 1211 ip = tip;
1212 1212 rw_enter(&ip->i_rwlock, RW_READER);
1213 1213 }
1214 1214 if (fbp) {
1215 1215 fbrelse(fbp, S_OTHER);
1216 1216 }
1217 1217 out:
1218 1218 if (ip) {
1219 1219 if (ip != target) {
1220 1220 rw_exit(&ip->i_rwlock);
1221 1221 VN_RELE(ITOV(ip));
1222 1222 }
1223 1223 }
1224 1224 return (err);
1225 1225 }
1226 1226
1227 1227 int
1228 1228 ud_dirmakeinode(struct ud_inode *tdp, struct ud_inode **ipp,
1229 1229 struct vattr *vap, enum de_op op, struct cred *cr)
1230 1230 {
1231 1231 struct ud_inode *ip;
1232 1232 int32_t error;
1233 1233
1234 1234 ASSERT(vap != NULL);
1235 1235 ASSERT(op == DE_CREATE || op == DE_MKDIR);
1236 1236 ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
1237 1237 ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1238 1238
1239 1239 /*
1240 1240 * Allocate a new inode.
1241 1241 */
1242 1242 if ((error = ud_ialloc(tdp, &ip, vap, cr)) != 0) {
1243 1243 return (error);
1244 1244 }
1245 1245
1246 1246 ASSERT(ip != NULL);
1247 1247
1248 1248 rw_enter(&ip->i_contents, RW_WRITER);
1249 1249
1250 1250 if (op == DE_MKDIR) {
1251 1251 error = ud_dirmakedirect(ip, tdp, cr);
1252 1252 }
1253 1253
1254 1254 ip->i_flag |= IACC|IUPD|ICHG;
1255 1255 /*
1256 1256 * Clear IACC and/or IUPD if the caller specified the atime and/or
1257 1257 * mtime fields. They were set from the passed in attributes in
1258 1258 * ud_ialloc().
1259 1259 */
1260 1260 if (vap->va_mask & AT_ATIME)
1261 1261 ip->i_flag &= ~IACC;
1262 1262 if (vap->va_mask & AT_MTIME)
1263 1263 ip->i_flag &= ~IUPD;
1264 1264 /*
1265 1265 * push inode before it's name appears in a directory
1266 1266 */
1267 1267 ud_iupdat(ip, 1);
1268 1268 *ipp = ip;
1269 1269 rw_exit(&ip->i_contents);
1270 1270 return (error);
1271 1271 }
1272 1272
1273 1273 /*
1274 1274 * Enter the file sip in the directory tdp with name namep.
1275 1275 */
1276 1276 int
1277 1277 ud_diraddentry(struct ud_inode *tdp, char *namep,
1278 1278 enum de_op op, int32_t namelen, struct slot *slotp,
1279 1279 struct ud_inode *sip, struct ud_inode *sdp, struct cred *cr)
1280 1280 {
1281 1281 struct udf_vfs *udf_vfsp;
1282 1282 int32_t error, temp;
1283 1283 struct file_id *fid;
1284 1284 uint8_t *buf = NULL;
1285 1285
1286 1286 ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1287 1287
1288 1288 ud_printf("ud_diraddentry\n");
1289 1289
1290 1290 udf_vfsp = sip->i_udf;
1291 1291
1292 1292 /*
1293 1293 * Check inode to be linked to see if it is in the
1294 1294 * same filesystem.
1295 1295 */
1296 1296 if (ITOV(tdp)->v_vfsp != ITOV(sip)->v_vfsp) {
1297 1297 error = EXDEV;
1298 1298 goto bad;
1299 1299 }
1300 1300
1301 1301 if ((op == DE_RENAME) && (sip->i_type == VDIR)) {
1302 1302 if ((error = ud_dirfixdotdot(sip, sdp, tdp)) != 0) {
1303 1303 goto bad;
1304 1304 }
1305 1305 }
1306 1306
1307 1307 buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
1308 1308
1309 1309 /*
1310 1310 * Fill in entry data.
1311 1311 */
1312 1312 fid = (struct file_id *)buf;
1313 1313 fid->fid_ver = SWAP_16(1);
1314 1314 if (sip->i_type == VDIR) {
1315 1315 fid->fid_flags = FID_DIR;
1316 1316 } else {
1317 1317 fid->fid_flags = 0;
1318 1318 }
1319 1319 fid->fid_iulen = 0;
1320 1320
1321 1321 fid->fid_icb.lad_ext_len = SWAP_32(sip->i_udf->udf_lbsize);
1322 1322 fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1323 1323 fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1324 1324 fid->fid_iulen = 0;
1325 1325
1326 1326 temp = MIN(udf_vfsp->udf_lbsize - F_LEN, MAXNAMELEN);
1327 1327 if ((error = ud_compress(namelen, &temp,
1328 1328 (uint8_t *)namep, fid->fid_spec)) == 0) {
1329 1329 fid->fid_idlen = (uint8_t)temp;
1330 1330 error = ud_dirprepareentry(tdp, slotp, buf, cr);
1331 1331 }
1332 1332
1333 1333 kmem_free(buf, udf_vfsp->udf_lbsize);
1334 1334
1335 1335 bad:
1336 1336 return (error);
1337 1337 }
1338 1338
1339 1339 /*
1340 1340 * Write a prototype directory into the empty inode ip, whose parent is dp.
1341 1341 */
1342 1342 /* ARGSUSED2 */
1343 1343 int
1344 1344 ud_dirmakedirect(struct ud_inode *ip,
1345 1345 struct ud_inode *dp, struct cred *cr)
1346 1346 {
1347 1347 int32_t err;
1348 1348 uint32_t blkno, size, parent_len, tbno;
1349 1349 struct fbuf *fbp;
1350 1350 struct file_id *fid;
1351 1351 struct icb_ext *iext;
1352 1352
1353 1353 ud_printf("ud_dirmakedirect\n");
1354 1354
1355 1355 ASSERT(RW_WRITE_HELD(&ip->i_contents));
1356 1356 ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1357 1357
1358 1358 parent_len = sizeof (struct file_id);
1359 1359
1360 1360 if ((ip->i_desc_type != ICB_FLAG_ONE_AD) ||
1361 1361 (parent_len > ip->i_max_emb)) {
1362 1362 ASSERT(ip->i_ext);
1363 1363 /*
1364 1364 * Allocate space for the directory we're creating.
1365 1365 */
1366 1366 if ((err = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
1367 1367 0, 1, &blkno, &size, 0, 0)) != 0) {
1368 1368 return (err);
1369 1369 }
1370 1370 /*
1371 1371 * init with the size of
1372 1372 * directory with just the
1373 1373 * parent
1374 1374 */
1375 1375 ip->i_size = sizeof (struct file_id);
1376 1376 ip->i_flag |= IUPD|ICHG|IATTCHG;
1377 1377 iext = ip->i_ext;
1378 1378 iext->ib_prn = ip->i_icb_prn;
1379 1379 iext->ib_block = blkno;
1380 1380 iext->ib_count = ip->i_size;
1381 1381 iext->ib_offset = 0;
1382 1382 ip->i_ext_used = 1;
1383 1383 } else {
1384 1384 ip->i_size = sizeof (struct file_id);
1385 1385 ip->i_flag |= IUPD|ICHG|IATTCHG;
1386 1386 }
1387 1387
1388 1388 ITIMES_NOLOCK(ip);
1389 1389
1390 1390 /*
1391 1391 * Update the dp link count and write out the change.
1392 1392 * This reflects the ".." entry we'll soon write.
1393 1393 */
1394 1394 if (dp->i_nlink == MAXLINK) {
1395 1395 return (EMLINK);
1396 1396 }
1397 1397 dp->i_nlink++;
1398 1398 dp->i_flag |= ICHG;
1399 1399 ud_iupdat(dp, 1);
1400 1400
1401 1401 /*
1402 1402 * Initialize directory with ".."
1403 1403 * Since the parent directory is locked, we don't have to
1404 1404 * worry about anything changing when we drop the write
1405 1405 * lock on (ip).
1406 1406 */
1407 1407 rw_exit(&ip->i_contents);
1408 1408 if ((err = fbread(ITOV(ip), (offset_t)0,
1409 1409 ip->i_udf->udf_lbsize, S_WRITE, &fbp)) != 0) {
1410 1410 rw_enter(&ip->i_contents, RW_WRITER);
1411 1411 return (err);
1412 1412 }
1413 1413
1414 1414 bzero(fbp->fb_addr, ip->i_udf->udf_lbsize);
1415 1415
1416 1416 fid = (struct file_id *)fbp->fb_addr;
1417 1417 fid->fid_ver = SWAP_16(1);
1418 1418 fid->fid_flags = FID_DIR | FID_PARENT;
1419 1419 fid->fid_icb.lad_ext_len = SWAP_32(dp->i_udf->udf_lbsize);
1420 1420 fid->fid_icb.lad_ext_loc = SWAP_32(dp->i_icb_block);
1421 1421 fid->fid_icb.lad_ext_prn = SWAP_16(dp->i_icb_prn);
1422 1422
1423 1423 /*
1424 1424 * fid_idlen, fid_iulen and fid_spec are zero
1425 1425 * due to bzero above
1426 1426 */
1427 1427
1428 1428 if ((err = ud_ip_off2bno(ip, 0, &tbno)) == 0) {
1429 1429 ud_make_tag(ip->i_udf, &fid->fid_tag,
1430 1430 UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1431 1431 }
1432 1432
1433 1433 err = ud_fbwrite(fbp, ip);
1434 1434 rw_enter(&ip->i_contents, RW_WRITER);
1435 1435
1436 1436 return (err);
1437 1437 }
1438 1438
1439 1439 int
1440 1440 ud_dirrename(struct ud_inode *sdp, struct ud_inode *sip,
1441 1441 struct ud_inode *tdp, struct ud_inode *tip, char *namep,
1442 1442 uint8_t *buf, struct slot *slotp, struct cred *cr)
1443 1443 {
1444 1444 int32_t error = 0, doingdirectory;
1445 1445 struct file_id *fid;
1446 1446
1447 1447 ud_printf("ud_dirrename\n");
1448 1448 ASSERT(sdp->i_udf != NULL);
1449 1449 ASSERT(MUTEX_HELD(&sdp->i_udf->udf_rename_lck));
1450 1450 ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1451 1451 ASSERT(RW_WRITE_HELD(&tdp->i_contents));
1452 1452 ASSERT(buf);
1453 1453 ASSERT(slotp->ep);
1454 1454
1455 1455 fid = slotp->ep;
1456 1456
1457 1457 /*
1458 1458 * Short circuit rename of something to itself.
1459 1459 */
1460 1460 if (sip->i_icb_lbano == tip->i_icb_lbano) {
1461 1461 return (ESAME); /* special KLUDGE error code */
1462 1462 }
1463 1463 /*
1464 1464 * Everything is protected under the vfs_rename_lock so the ordering
1465 1465 * of i_contents locks doesn't matter here.
1466 1466 */
1467 1467 rw_enter(&sip->i_contents, RW_READER);
1468 1468 rw_enter(&tip->i_contents, RW_READER);
1469 1469
1470 1470 /*
1471 1471 * Check that everything is on the same filesystem.
1472 1472 */
1473 1473 if ((ITOV(tip)->v_vfsp != ITOV(tdp)->v_vfsp) ||
1474 1474 (ITOV(tip)->v_vfsp != ITOV(sip)->v_vfsp)) {
1475 1475 error = EXDEV; /* XXX archaic */
1476 1476 goto out;
1477 1477 }
1478 1478
1479 1479 /*
1480 1480 * Must have write permission to rewrite target entry.
1481 1481 */
1482 1482 if ((error = ud_iaccess(tdp, IWRITE, cr, 0)) != 0 ||
1483 1483 (error = ud_sticky_remove_access(tdp, tip, cr)) != 0)
1484 1484 goto out;
1485 1485
1486 1486 /*
1487 1487 * Ensure source and target are compatible (both directories
1488 1488 * or both not directories). If target is a directory it must
1489 1489 * be empty and have no links to it; in addition it must not
1490 1490 * be a mount point, and both the source and target must be
1491 1491 * writable.
1492 1492 */
1493 1493 doingdirectory = (sip->i_type == VDIR);
1494 1494 if (tip->i_type == VDIR) {
1495 1495 if (!doingdirectory) {
1496 1496 error = EISDIR;
1497 1497 goto out;
1498 1498 }
1499 1499 /*
1500 1500 * vn_vfswlock will prevent mounts from using the directory
1501 1501 * until we are done.
1502 1502 */
1503 1503 if (vn_vfswlock(ITOV(tip))) {
1504 1504 error = EBUSY;
1505 1505 goto out;
1506 1506 }
1507 1507 if (vn_mountedvfs(ITOV(tip)) != NULL) {
1508 1508 vn_vfsunlock(ITOV(tip));
1509 1509 error = EBUSY;
1510 1510 goto out;
1511 1511 }
1512 1512 if (!ud_dirempty(tip, tdp->i_uniqid, cr) || tip->i_nlink > 2) {
1513 1513 vn_vfsunlock(ITOV(tip));
1514 1514 error = EEXIST; /* SIGH should be ENOTEMPTY */
1515 1515 goto out;
1516 1516 }
1517 1517 } else if (doingdirectory) {
1518 1518 error = ENOTDIR;
1519 1519 goto out;
1520 1520 }
1521 1521
1522 1522 /*
1523 1523 * Rewrite the inode pointer for target name entry
1524 1524 * from the target inode (ip) to the source inode (sip).
1525 1525 * This prevents the target entry from disappearing
1526 1526 * during a crash. Mark the directory inode to reflect the changes.
1527 1527 */
1528 1528 dnlc_remove(ITOV(tdp), namep);
1529 1529 fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1530 1530 fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1531 1531 dnlc_enter(ITOV(tdp), namep, ITOV(sip));
1532 1532
1533 1533 ud_make_tag(tdp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1534 1534 SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1535 1535
1536 1536 error = ud_write_fid(tdp, slotp, buf);
1537 1537
1538 1538 if (error) {
1539 1539 if (doingdirectory) {
1540 1540 vn_vfsunlock(ITOV(tip));
1541 1541 }
1542 1542 goto out;
1543 1543 }
1544 1544
1545 1545 /*
1546 1546 * Upgrade to write lock on tip
1547 1547 */
1548 1548 rw_exit(&tip->i_contents);
1549 1549 rw_enter(&tip->i_contents, RW_WRITER);
1550 1550
1551 1551 mutex_enter(&tdp->i_tlock);
1552 1552 tdp->i_flag |= IUPD|ICHG;
1553 1553 mutex_exit(&tdp->i_tlock);
1554 1554 /*
1555 1555 * Decrement the link count of the target inode.
1556 1556 * Fix the ".." entry in sip to point to dp.
1557 1557 * This is done after the new entry is on the disk.
1558 1558 */
1559 1559 tip->i_nlink--;
1560 1560 mutex_enter(&tip->i_tlock);
1561 1561 tip->i_flag |= ICHG;
1562 1562 mutex_exit(&tip->i_tlock);
1563 1563
1564 1564 if (doingdirectory) {
1565 1565 /*
1566 1566 * The entry for tip no longer exists so I can unlock the
1567 1567 * vfslock.
1568 1568 */
1569 1569 vn_vfsunlock(ITOV(tip));
1570 1570 /*
1571 1571 * Decrement target link count once more if it was a directory.
1572 1572 */
1573 1573 if (tip->i_nlink != 0) {
1574 1574 cmn_err(CE_WARN,
1575 1575 "ud_direnter: target directory link count != 0");
1576 1576 rw_exit(&tip->i_contents);
1577 1577 rw_exit(&sip->i_contents);
1578 1578 return (EINVAL);
1579 1579 }
1580 1580 /*
1581 1581 * Renaming a directory with the parent different
1582 1582 * requires that ".." be rewritten. The window is
1583 1583 * still there for ".." to be inconsistent, but this
1584 1584 * is unavoidable, and a lot shorter than when it was
1585 1585 * done in a user process. We decrement the link
1586 1586 * count in the new parent as appropriate to reflect
1587 1587 * the just-removed target. If the parent is the
1588 1588 * same, this is appropriate since the original
1589 1589 * directory is going away. If the new parent is
1590 1590 * different, dirfixdotdot() will bump the link count
1591 1591 * back.
1592 1592 */
1593 1593 tdp->i_nlink--;
1594 1594 mutex_enter(&tdp->i_tlock);
1595 1595 tdp->i_flag |= ICHG;
1596 1596 mutex_exit(&tdp->i_tlock);
1597 1597 ITIMES_NOLOCK(tdp);
1598 1598 if (sdp != tdp) {
1599 1599 rw_exit(&tip->i_contents);
1600 1600 rw_exit(&sip->i_contents);
1601 1601 error = ud_dirfixdotdot(sip, sdp, tdp);
1602 1602 return (error);
1603 1603 }
1604 1604 }
1605 1605
1606 1606 out:
1607 1607 rw_exit(&tip->i_contents);
1608 1608 rw_exit(&sip->i_contents);
1609 1609 return (error);
1610 1610 }
1611 1611
1612 1612
1613 1613 /*
1614 1614 * 1. When we find a slot that belonged to a file which was deleted
1615 1615 * and is in the middle of the directory
1616 1616 * 2. There is not empty slot available. The new entry
1617 1617 * will be at the end of the directory and fits in the same block.
1618 1618 * 3. There is no empty slot available. The new
1619 1619 * entry will not fit the left over directory
1620 1620 * so we need to allocate a new block. If
1621 1621 * we cannot allocate a proximity block we need
1622 1622 * to allocate a new icb, and data block.
1623 1623 */
1624 1624 int
1625 1625 ud_dirprepareentry(struct ud_inode *dp,
1626 1626 struct slot *slotp, uint8_t *buf, struct cred *cr)
1627 1627 {
1628 1628 struct fbuf *fbp;
1629 1629 uint16_t old_dtype;
1630 1630 int32_t error = 0;
1631 1631 uint32_t entrysize, count, offset, tbno, old_size, off;
1632 1632 struct file_id *fid;
1633 1633 int32_t lbsize, lbmask, mask;
1634 1634
1635 1635 ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1636 1636
1637 1637 ASSERT((slotp->status == NONE) || (slotp->status == FOUND));
1638 1638
1639 1639 ud_printf("ud_dirprepareentry\n");
1640 1640 lbsize = dp->i_udf->udf_lbsize;
1641 1641 lbmask = dp->i_udf->udf_lbmask;
1642 1642 mask = ~lbmask;
1643 1643
1644 1644 fid = (struct file_id *)buf;
1645 1645 entrysize = FID_LEN(fid);
1646 1646
1647 1647 /*
1648 1648 * If we didn't find a slot, then indicate that the
1649 1649 * new slot belongs at the end of the directory.
1650 1650 * If we found a slot, then the new entry can be
1651 1651 * put at slotp->offset.
1652 1652 */
1653 1653 if (slotp->status == NONE) {
1654 1654 /*
1655 1655 * We did not find a slot, the next
1656 1656 * entry will be in the end of the directory
1657 1657 * see if we can fit the new entry inside
1658 1658 * the old block. If not allocate a new block.
1659 1659 */
1660 1660 if (entrysize > slotp->size) {
1661 1661 /*
1662 1662 * extend the directory
1663 1663 * size by one new block
1664 1664 */
1665 1665 old_dtype = dp->i_desc_type;
1666 1666 old_size = (uint32_t)dp->i_size;
1667 1667 error = ud_bmap_write(dp, slotp->offset,
1668 1668 blkoff(dp->i_udf, slotp->offset) + entrysize,
1669 1669 0, cr);
1670 1670 if (error != 0) {
1671 1671 return (error);
1672 1672 }
1673 1673 if (old_dtype != dp->i_desc_type) {
1674 1674 /*
1675 1675 * oops we changed the astrat
1676 1676 * of the file, we have to
1677 1677 * recaliculate tags
1678 1678 * fortunately we donot have more
1679 1679 * than one lbsize to handle here
1680 1680 */
1681 1681 if ((error = ud_ip_off2bno(dp,
1682 1682 0, &tbno)) != 0) {
1683 1683 return (error);
1684 1684 }
1685 1685 if ((error = fbread(ITOV(dp), 0,
1686 1686 dp->i_udf->udf_lbsize,
1687 1687 S_WRITE, &fbp)) != 0) {
1688 1688 return (error);
1689 1689 }
1690 1690 off = 0;
1691 1691 while (off < old_size) {
1692 1692 struct file_id *tfid;
1693 1693
1694 1694 tfid = (struct file_id *)
1695 1695 (fbp->fb_addr + off);
1696 1696
1697 1697 ud_make_tag(dp->i_udf, &tfid->fid_tag,
1698 1698 UD_FILE_ID_DESC, tbno,
1699 1699 FID_LEN(tfid));
1700 1700
1701 1701 off += FID_LEN(tfid);
1702 1702 }
1703 1703 if (error = ud_fbwrite(fbp, dp)) {
1704 1704 return (error);
1705 1705 }
1706 1706 }
1707 1707 } else {
1708 1708 /* Extend the directory size */
1709 1709 if (dp->i_desc_type != ICB_FLAG_ONE_AD) {
1710 1710 ASSERT(dp->i_ext);
1711 1711 dp->i_ext[dp->i_ext_used - 1].ib_count +=
1712 1712 entrysize;
1713 1713 }
1714 1714 }
1715 1715 dp->i_size += entrysize;
1716 1716 dp->i_flag |= IUPD|ICHG|IATTCHG;
1717 1717 ITIMES_NOLOCK(dp);
1718 1718 } else if (slotp->status != FOUND) {
1719 1719 cmn_err(CE_WARN, "status is not NONE/FOUND");
1720 1720 return (EINVAL);
1721 1721 }
1722 1722
1723 1723 if ((error = ud_ip_off2bno(dp, slotp->offset, &tbno)) != 0) {
1724 1724 return (error);
1725 1725 }
1726 1726 ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1727 1727 tbno, FID_LEN(fid));
1728 1728
1729 1729 /*
1730 1730 * fbread cannot cross a
1731 1731 * MAXBSIZE boundary so handle it here
1732 1732 */
1733 1733 offset = slotp->offset;
1734 1734 if ((error = fbread(ITOV(dp), offset & mask, lbsize,
1735 1735 S_WRITE, &fbp)) != 0) {
1736 1736 return (error);
1737 1737 }
1738 1738 if ((offset & mask) != ((offset + entrysize) & mask)) {
1739 1739 count = entrysize - ((offset + entrysize) & lbmask);
1740 1740 } else {
1741 1741 count = entrysize;
1742 1742 }
1743 1743 bcopy((caddr_t)buf, fbp->fb_addr + (offset & lbmask), count);
1744 1744
1745 1745 if (error = ud_fbwrite(fbp, dp)) {
1746 1746 return (error);
1747 1747 }
1748 1748
1749 1749 if (entrysize > count) {
1750 1750 if ((error = fbread(ITOV(dp), (offset + entrysize) & mask,
1751 1751 lbsize, S_WRITE, &fbp)) != 0) {
1752 1752 return (error);
1753 1753 }
1754 1754 bcopy((caddr_t)(buf + count), fbp->fb_addr, entrysize - count);
1755 1755 if (error = ud_fbwrite(fbp, dp)) {
1756 1756 return (error);
1757 1757 }
1758 1758 }
1759 1759
1760 1760 dp->i_flag |= IUPD|ICHG|IATTCHG;
1761 1761 ITIMES_NOLOCK(dp);
1762 1762 return (error);
1763 1763 }
1764 1764
1765 1765
1766 1766 /*
1767 1767 * Fix the FID_PARENT entry of the child directory so that it points
1768 1768 * to the new parent directory instead of the old one. Routine
1769 1769 * assumes that dp is a directory and that all the inodes are on
1770 1770 * the same file system.
1771 1771 */
1772 1772 int
1773 1773 ud_dirfixdotdot(struct ud_inode *dp,
1774 1774 struct ud_inode *opdp, struct ud_inode *npdp)
1775 1775 {
1776 1776 int32_t err = 0;
1777 1777 struct fbuf *fbp;
1778 1778 struct file_id *fid;
1779 1779 uint32_t loc, dummy, tbno;
1780 1780
1781 1781 ud_printf("ud_dirfixdotdot\n");
1782 1782
1783 1783 ASSERT(opdp->i_type == VDIR);
1784 1784 ASSERT(npdp->i_type == VDIR);
1785 1785
1786 1786 ASSERT(RW_WRITE_HELD(&npdp->i_rwlock));
1787 1787
1788 1788 err = fbread(ITOV(dp), (offset_t)0,
1789 1789 dp->i_udf->udf_lbsize, S_WRITE, &fbp);
1790 1790
1791 1791 if (err || dp->i_nlink == 0 ||
1792 1792 dp->i_size < sizeof (struct file_id)) {
1793 1793 goto bad;
1794 1794 }
1795 1795
1796 1796 if ((err = ud_ip_off2bno(dp, 0, &tbno)) != 0) {
1797 1797 goto bad;
1798 1798 }
1799 1799
1800 1800 fid = (struct file_id *)fbp->fb_addr;
1801 1801 if ((ud_verify_tag_and_desc(&fid->fid_tag, UD_FILE_ID_DESC,
1802 1802 tbno,
1803 1803 1, dp->i_udf->udf_lbsize) != 0) ||
1804 1804 ((fid->fid_flags & (FID_DIR | FID_PARENT)) !=
1805 1805 (FID_DIR | FID_PARENT))) {
1806 1806 err = ENOTDIR;
1807 1807 goto bad;
1808 1808 }
1809 1809
1810 1810 loc = ud_xlate_to_daddr(dp->i_udf,
1811 1811 SWAP_16(fid->fid_icb.lad_ext_prn),
1812 1812 SWAP_32(fid->fid_icb.lad_ext_loc), 1, &dummy);
1813 1813 ASSERT(dummy == 1);
1814 1814 if (loc == npdp->i_icb_lbano) {
1815 1815 goto bad;
1816 1816 }
1817 1817
1818 1818 /*
1819 1819 * Increment the link count in the new parent inode and force it out.
1820 1820 */
1821 1821 if (npdp->i_nlink == MAXLINK) {
1822 1822 err = EMLINK;
1823 1823 goto bad;
1824 1824 }
1825 1825
1826 1826 npdp->i_nlink++;
1827 1827 mutex_enter(&npdp->i_tlock);
1828 1828 npdp->i_flag |= ICHG;
1829 1829 mutex_exit(&npdp->i_tlock);
1830 1830 ud_iupdat(npdp, 1);
1831 1831
1832 1832 /*
1833 1833 * Rewrite the child FID_PARENT entry and force it out.
1834 1834 */
1835 1835 dnlc_remove(ITOV(dp), "..");
1836 1836 fid->fid_icb.lad_ext_loc = SWAP_32(npdp->i_icb_block);
1837 1837 fid->fid_icb.lad_ext_prn = SWAP_16(npdp->i_icb_prn);
1838 1838 ud_make_tag(npdp->i_udf, &fid->fid_tag,
1839 1839 UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1840 1840 dnlc_enter(ITOV(dp), "..", ITOV(npdp));
1841 1841
1842 1842 err = ud_fbwrite(fbp, dp);
1843 1843 fbp = NULL;
1844 1844 if (err != 0) {
1845 1845 goto bad;
1846 1846 }
1847 1847
1848 1848 /*
1849 1849 * Decrement the link count of the old parent inode and force
1850 1850 * it out. If opdp is NULL, then this is a new directory link;
1851 1851 * it has no parent, so we need not do anything.
1852 1852 */
1853 1853 if (opdp != NULL) {
1854 1854 rw_enter(&opdp->i_contents, RW_WRITER);
1855 1855 if (opdp->i_nlink != 0) {
1856 1856 opdp->i_nlink--;
1857 1857 mutex_enter(&opdp->i_tlock);
1858 1858 opdp->i_flag |= ICHG;
1859 1859 mutex_exit(&opdp->i_tlock);
1860 1860 ud_iupdat(opdp, 1);
1861 1861 }
1862 1862 rw_exit(&opdp->i_contents);
1863 1863 }
1864 1864 return (0);
1865 1865
1866 1866 bad:
1867 1867 if (fbp) {
1868 1868 fbrelse(fbp, S_OTHER);
1869 1869 }
1870 1870 return (err);
1871 1871 }
1872 1872
1873 1873 int32_t
1874 1874 ud_write_fid(struct ud_inode *dp, struct slot *slot, uint8_t *buf)
1875 1875 {
1876 1876 struct udf_vfs *udf_vfsp;
1877 1877 struct fbuf *lfbp;
1878 1878 struct file_id *fid;
1879 1879 int32_t error = 0;
1880 1880 uint32_t lbsize, lbmask, count, old_count;
1881 1881
1882 1882
1883 1883 ASSERT(slot->fbp);
1884 1884 ASSERT(slot->ep);
1885 1885
1886 1886 udf_vfsp = dp->i_udf;
1887 1887 fid = slot->ep;
1888 1888 lbsize = dp->i_udf->udf_lbsize;
1889 1889 lbmask = dp->i_udf->udf_lbmask;
1890 1890
1891 1891 if (((uint8_t *)fid >= buf) &&
1892 1892 ((uint8_t *)fid < &buf[udf_vfsp->udf_lbsize])) {
1893 1893
1894 1894 if ((error = fbread(ITOV(dp),
1895 1895 (offset_t)(slot->offset & ~lbmask),
1896 1896 lbsize, S_WRITE, &lfbp)) != 0) {
1897 1897 goto out;
1898 1898 }
1899 1899
1900 1900
1901 1901 /*
1902 1902 * We do not need to write the
1903 1903 * file name. So check if the entry
1904 1904 * does not cross a block boundary
1905 1905 * and write only required portions
1906 1906 */
1907 1907 if (((slot->offset & lbmask) +
1908 1908 sizeof (struct file_id)) > lbsize) {
1909 1909
1910 1910 if ((slot->offset & lbmask) != 0) {
1911 1911 old_count = lbsize -
1912 1912 (slot->offset & lbmask);
1913 1913 count = (slot->offset +
1914 1914 sizeof (struct file_id)) &
1915 1915 lbmask;
1916 1916 } else {
1917 1917 old_count = 0;
1918 1918 count = sizeof (struct file_id);
1919 1919 }
1920 1920
1921 1921 bcopy(buf, lfbp->fb_addr +
1922 1922 (slot->offset & lbmask), old_count);
1923 1923 bcopy(buf + old_count,
1924 1924 slot->fbp->fb_addr, count);
1925 1925
1926 1926 error = ud_fbwrite(lfbp, dp);
1927 1927
1928 1928 error = ud_fbwrite(slot->fbp, dp);
1929 1929 } else {
1930 1930 bcopy(buf, lfbp->fb_addr +
1931 1931 (slot->offset & lbmask),
1932 1932 sizeof (struct file_id));
1933 1933
1934 1934 error = ud_fbwrite(lfbp, dp);
1935 1935
1936 1936 fbrelse(slot->fbp, S_OTHER);
1937 1937 }
1938 1938 } else {
1939 1939 if ((error = ud_fbwrite(slot->fbp, dp)) != 0) {
1940 1940 fid->fid_flags &= ~FID_DELETED;
1941 1941 ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1942 1942 SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1943 1943 }
1944 1944 }
1945 1945 slot->fbp = NULL;
1946 1946
1947 1947 out:
1948 1948 return (error);
1949 1949 }
|
↓ open down ↓ |
1372 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX