]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_readwrite.c
4544a768558eb7658d3ed8dc1510cf04569b26f2
[apple/xnu.git] / bsd / hfs / hfs_readwrite.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* @(#)hfs_readwrite.c 1.0
23 *
24 * (c) 1998-2001 Apple Computer, Inc. All Rights Reserved
25 *
26 * hfs_readwrite.c -- vnode operations to deal with reading and writing files.
27 *
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/resourcevar.h>
33 #include <sys/kernel.h>
34 #include <sys/fcntl.h>
35 #include <sys/stat.h>
36 #include <sys/buf.h>
37 #include <sys/proc.h>
38 #include <sys/vnode.h>
39 #include <sys/uio.h>
40
41 #include <miscfs/specfs/specdev.h>
42
43 #include <sys/ubc.h>
44 #include <vm/vm_pageout.h>
45
46 #include <sys/kdebug.h>
47
48 #include "hfs.h"
49 #include "hfs_endian.h"
50 #include "hfs_quota.h"
51 #include "hfscommon/headers/FileMgrInternal.h"
52 #include "hfscommon/headers/BTreesInternal.h"
53 #include "hfs_cnode.h"
54 #include "hfs_dbg.h"
55
56 extern int overflow_extents(struct filefork *fp);
57
58 #define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
59
60 enum {
61 MAXHFSFILESIZE = 0x7FFFFFFF /* this needs to go in the mount structure */
62 };
63
64 extern u_int32_t GetLogicalBlockSize(struct vnode *vp);
65
66
67 /*****************************************************************************
68 *
69 * Operations on vnodes
70 *
71 *****************************************************************************/
72
73 /*
74 #% read vp L L L
75 #
76 vop_read {
77 IN struct vnode *vp;
78 INOUT struct uio *uio;
79 IN int ioflag;
80 IN struct ucred *cred;
81
82 */
83
84 int
85 hfs_read(ap)
86 struct vop_read_args /* {
87 struct vnode *a_vp;
88 struct uio *a_uio;
89 int a_ioflag;
90 struct ucred *a_cred;
91 } */ *ap;
92 {
93 register struct uio *uio = ap->a_uio;
94 register struct vnode *vp = ap->a_vp;
95 struct cnode *cp;
96 struct filefork *fp;
97 struct buf *bp;
98 daddr_t logBlockNo;
99 u_long fragSize, moveSize, startOffset, ioxfersize;
100 int devBlockSize = 0;
101 off_t bytesRemaining;
102 int retval = 0;
103 off_t filesize;
104 off_t filebytes;
105
106 /* Preflight checks */
107 if (vp->v_type != VREG && vp->v_type != VLNK)
108 return (EISDIR); /* HFS can only read files */
109 if (uio->uio_resid == 0)
110 return (0); /* Nothing left to do */
111 if (uio->uio_offset < 0)
112 return (EINVAL); /* cant read from a negative offset */
113
114 cp = VTOC(vp);
115 fp = VTOF(vp);
116 filesize = fp->ff_size;
117 filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize;
118 if (uio->uio_offset > filesize) {
119 if ((!ISHFSPLUS(VTOVCB(vp))) && (uio->uio_offset > (off_t)MAXHFSFILESIZE))
120 return (EFBIG);
121 else
122 return (0);
123 }
124
125 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
126
127 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START,
128 (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0);
129
130 if (UBCISVALID(vp)) {
131 retval = cluster_read(vp, uio, filesize, devBlockSize, 0);
132 } else {
133
134 for (retval = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
135
136 if ((bytesRemaining = (filesize - uio->uio_offset)) <= 0)
137 break;
138
139 logBlockNo = (daddr_t)(uio->uio_offset / PAGE_SIZE_64);
140 startOffset = (u_long) (uio->uio_offset & PAGE_MASK_64);
141 fragSize = PAGE_SIZE;
142
143 if (((logBlockNo * PAGE_SIZE) + fragSize) < filesize)
144 ioxfersize = fragSize;
145 else {
146 ioxfersize = filesize - (logBlockNo * PAGE_SIZE);
147 ioxfersize = (ioxfersize + (devBlockSize - 1)) & ~(devBlockSize - 1);
148 }
149 moveSize = ioxfersize;
150 moveSize -= startOffset;
151
152 if (bytesRemaining < moveSize)
153 moveSize = bytesRemaining;
154
155 if (uio->uio_resid < moveSize) {
156 moveSize = uio->uio_resid;
157 };
158 if (moveSize == 0) {
159 break;
160 };
161
162 if (( uio->uio_offset + fragSize) >= filesize) {
163 retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp);
164
165 } else if (logBlockNo - 1 == vp->v_lastr && !(vp->v_flag & VRAOFF)) {
166 daddr_t nextLogBlockNo = logBlockNo + 1;
167 int nextsize;
168
169 if (((nextLogBlockNo * PAGE_SIZE) +
170 (daddr_t)fragSize) < filesize)
171 nextsize = fragSize;
172 else {
173 nextsize = filesize - (nextLogBlockNo * PAGE_SIZE);
174 nextsize = (nextsize + (devBlockSize - 1)) & ~(devBlockSize - 1);
175 }
176 retval = breadn(vp, logBlockNo, ioxfersize, &nextLogBlockNo, &nextsize, 1, NOCRED, &bp);
177 } else {
178 retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp);
179 };
180
181 if (retval != E_NONE) {
182 if (bp) {
183 brelse(bp);
184 bp = NULL;
185 }
186 break;
187 };
188 vp->v_lastr = logBlockNo;
189
190 /*
191 * We should only get non-zero b_resid when an I/O retval
192 * has occurred, which should cause us to break above.
193 * However, if the short read did not cause an retval,
194 * then we want to ensure that we do not uiomove bad
195 * or uninitialized data.
196 */
197 ioxfersize -= bp->b_resid;
198
199 if (ioxfersize < moveSize) { /* XXX PPD This should take the offset into account, too! */
200 if (ioxfersize == 0)
201 break;
202 moveSize = ioxfersize;
203 }
204 if ((startOffset + moveSize) > bp->b_bcount)
205 panic("hfs_read: bad startOffset or moveSize\n");
206
207 if ((retval = uiomove((caddr_t)bp->b_data + startOffset, (int)moveSize, uio)))
208 break;
209
210 if (S_ISREG(cp->c_mode) &&
211 (((startOffset + moveSize) == fragSize) || (uio->uio_offset == filesize))) {
212 bp->b_flags |= B_AGE;
213 };
214
215 brelse(bp);
216 /* Start of loop resets bp to NULL before reaching outside this block... */
217 }
218
219 if (bp != NULL) {
220 brelse(bp);
221 }
222 }
223
224 cp->c_flag |= C_ACCESS;
225
226 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
227 (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0);
228
229 return (retval);
230 }
231
232 /*
233 * Write data to a file or directory.
234 #% write vp L L L
235 #
236 vop_write {
237 IN struct vnode *vp;
238 INOUT struct uio *uio;
239 IN int ioflag;
240 IN struct ucred *cred;
241
242 */
243 int
244 hfs_write(ap)
245 struct vop_write_args /* {
246 struct vnode *a_vp;
247 struct uio *a_uio;
248 int a_ioflag;
249 struct ucred *a_cred;
250 } */ *ap;
251 {
252 struct vnode *vp = ap->a_vp;
253 struct uio *uio = ap->a_uio;
254 struct cnode *cp;
255 struct filefork *fp;
256 struct buf *bp;
257 struct proc *p;
258 struct timeval tv;
259 ExtendedVCB *vcb;
260 int devBlockSize = 0;
261 daddr_t logBlockNo;
262 long fragSize;
263 off_t origFileSize, currOffset, writelimit, bytesToAdd;
264 off_t actualBytesAdded;
265 u_long blkoffset, resid, xfersize, clearSize;
266 int eflags, ioflag;
267 int retval;
268 off_t filebytes;
269 u_long fileblocks;
270
271 ioflag = ap->a_ioflag;
272
273 if (uio->uio_offset < 0)
274 return (EINVAL);
275 if (uio->uio_resid == 0)
276 return (E_NONE);
277 if (vp->v_type != VREG && vp->v_type != VLNK)
278 return (EISDIR); /* Can only write files */
279
280 cp = VTOC(vp);
281 fp = VTOF(vp);
282 vcb = VTOVCB(vp);
283 fileblocks = fp->ff_blocks;
284 filebytes = (off_t)fileblocks * (off_t)vcb->blockSize;
285
286 if (ioflag & IO_APPEND)
287 uio->uio_offset = fp->ff_size;
288 if ((cp->c_flags & APPEND) && uio->uio_offset != fp->ff_size)
289 return (EPERM);
290
291 writelimit = uio->uio_offset + uio->uio_resid;
292
293 /*
294 * Maybe this should be above the vnode op call, but so long as
295 * file servers have no limits, I don't think it matters.
296 */
297 p = uio->uio_procp;
298 if (vp->v_type == VREG && p &&
299 writelimit > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
300 psignal(p, SIGXFSZ);
301 return (EFBIG);
302 }
303 p = current_proc();
304
305 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
306
307 resid = uio->uio_resid;
308 origFileSize = fp->ff_size;
309 eflags = kEFDeferMask; /* defer file block allocations */
310 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
311
312 /*
313 * NOTE: In the following loop there are two positions tracked:
314 * currOffset is the current I/O starting offset. currOffset
315 * is never >LEOF; the LEOF is nudged along with currOffset as
316 * data is zeroed or written. uio->uio_offset is the start of
317 * the current I/O operation. It may be arbitrarily beyond
318 * currOffset.
319 *
320 * The following is true at all times:
321 * currOffset <= LEOF <= uio->uio_offset <= writelimit
322 */
323 currOffset = MIN(uio->uio_offset, fp->ff_size);
324
325 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_START,
326 (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0);
327 retval = 0;
328
329 /* Now test if we need to extend the file */
330 /* Doing so will adjust the filebytes for us */
331
332 #if QUOTA
333 if(writelimit > filebytes) {
334 bytesToAdd = writelimit - filebytes;
335
336 retval = hfs_chkdq(cp, (int64_t)(roundup(bytesToAdd, fp->ff_clumpsize)),
337 ap->a_cred, 0);
338 if (retval)
339 return (retval);
340 }
341 #endif /* QUOTA */
342
343 while (writelimit > filebytes) {
344
345 bytesToAdd = writelimit - filebytes;
346 if (suser(ap->a_cred, NULL) != 0)
347 eflags |= kEFReserveMask;
348
349 /* lock extents b-tree (also protects volume bitmap) */
350 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, current_proc());
351 if (retval != E_NONE)
352 break;
353
354 retval = MacToVFSError(ExtendFileC (vcb, (FCB*)fp, bytesToAdd,
355 0, eflags, &actualBytesAdded));
356
357 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
358 if ((actualBytesAdded == 0) && (retval == E_NONE))
359 retval = ENOSPC;
360 if (retval != E_NONE)
361 break;
362 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
363 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_NONE,
364 (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0);
365 }
366
367 if (UBCISVALID(vp) && retval == E_NONE) {
368 off_t filesize;
369 off_t zero_off;
370 off_t tail_off;
371 off_t inval_start;
372 off_t inval_end;
373 off_t io_start, io_end;
374 int lflag;
375 struct rl_entry *invalid_range;
376
377 if (writelimit > fp->ff_size)
378 filesize = writelimit;
379 else
380 filesize = fp->ff_size;
381
382 lflag = (ioflag & IO_SYNC);
383
384 if (uio->uio_offset <= fp->ff_size) {
385 zero_off = uio->uio_offset & ~PAGE_MASK_64;
386
387 /* Check to see whether the area between the zero_offset and the start
388 of the transfer to see whether is invalid and should be zero-filled
389 as part of the transfer:
390 */
391 if (rl_scan(&fp->ff_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP)
392 lflag |= IO_HEADZEROFILL;
393 } else {
394 off_t eof_page_base = fp->ff_size & ~PAGE_MASK_64;
395
396 /* The bytes between fp->ff_size and uio->uio_offset must never be
397 read without being zeroed. The current last block is filled with zeroes
398 if it holds valid data but in all cases merely do a little bookkeeping
399 to track the area from the end of the current last page to the start of
400 the area actually written. For the same reason only the bytes up to the
401 start of the page where this write will start is invalidated; any remainder
402 before uio->uio_offset is explicitly zeroed as part of the cluster_write.
403
404 Note that inval_start, the start of the page after the current EOF,
405 may be past the start of the write, in which case the zeroing
406 will be handled by the cluser_write of the actual data.
407 */
408 inval_start = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
409 inval_end = uio->uio_offset & ~PAGE_MASK_64;
410 zero_off = fp->ff_size;
411
412 if ((fp->ff_size & PAGE_MASK_64) &&
413 (rl_scan(&fp->ff_invalidranges,
414 eof_page_base,
415 fp->ff_size - 1,
416 &invalid_range) != RL_NOOVERLAP)) {
417 /* The page containing the EOF is not valid, so the
418 entire page must be made inaccessible now. If the write
419 starts on a page beyond the page containing the eof
420 (inval_end > eof_page_base), add the
421 whole page to the range to be invalidated. Otherwise
422 (i.e. if the write starts on the same page), zero-fill
423 the entire page explicitly now:
424 */
425 if (inval_end > eof_page_base) {
426 inval_start = eof_page_base;
427 } else {
428 zero_off = eof_page_base;
429 };
430 };
431
432 if (inval_start < inval_end) {
433 /* There's some range of data that's going to be marked invalid */
434
435 if (zero_off < inval_start) {
436 /* The pages between inval_start and inval_end are going to be invalidated,
437 and the actual write will start on a page past inval_end. Now's the last
438 chance to zero-fill the page containing the EOF:
439 */
440 retval = cluster_write(vp, (struct uio *) 0,
441 fp->ff_size, inval_start,
442 zero_off, (off_t)0, devBlockSize,
443 lflag | IO_HEADZEROFILL | IO_NOZERODIRTY);
444 if (retval) goto ioerr_exit;
445 };
446
447 /* Mark the remaining area of the newly allocated space as invalid: */
448 rl_add(inval_start, inval_end - 1 , &fp->ff_invalidranges);
449 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
450 zero_off = fp->ff_size = inval_end;
451 };
452
453 if (uio->uio_offset > zero_off) lflag |= IO_HEADZEROFILL;
454 };
455
456 /* Check to see whether the area between the end of the write and the end of
457 the page it falls in is invalid and should be zero-filled as part of the transfer:
458 */
459 tail_off = (writelimit + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
460 if (tail_off > filesize) tail_off = filesize;
461 if (tail_off > writelimit) {
462 if (rl_scan(&fp->ff_invalidranges, writelimit, tail_off - 1, &invalid_range) != RL_NOOVERLAP) {
463 lflag |= IO_TAILZEROFILL;
464 };
465 };
466
467 /*
468 * if the write starts beyond the current EOF (possibly advanced in the
469 * zeroing of the last block, above), then we'll zero fill from the current EOF
470 * to where the write begins:
471 *
472 * NOTE: If (and ONLY if) the portion of the file about to be written is
473 * before the current EOF it might be marked as invalid now and must be
474 * made readable (removed from the invalid ranges) before cluster_write
475 * tries to write it:
476 */
477 io_start = (lflag & IO_HEADZEROFILL) ? zero_off : uio->uio_offset;
478 io_end = (lflag & IO_TAILZEROFILL) ? tail_off : writelimit;
479 if (io_start < fp->ff_size) {
480 rl_remove(io_start, io_end - 1, &fp->ff_invalidranges);
481 };
482 retval = cluster_write(vp, uio, fp->ff_size, filesize, zero_off,
483 tail_off, devBlockSize, lflag | IO_NOZERODIRTY);
484
485 if (uio->uio_offset > fp->ff_size) {
486 fp->ff_size = uio->uio_offset;
487
488 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
489 }
490 if (resid > uio->uio_resid)
491 cp->c_flag |= C_CHANGE | C_UPDATE;
492 } else {
493 while (retval == E_NONE && uio->uio_resid > 0) {
494 logBlockNo = currOffset / PAGE_SIZE;
495 blkoffset = currOffset & PAGE_MASK;
496
497 if ((filebytes - currOffset) < PAGE_SIZE_64)
498 fragSize = filebytes - ((off_t)logBlockNo * PAGE_SIZE_64);
499 else
500 fragSize = PAGE_SIZE;
501 xfersize = fragSize - blkoffset;
502
503 /* Make any adjustments for boundary conditions */
504 if (currOffset + (off_t)xfersize > writelimit)
505 xfersize = writelimit - currOffset;
506
507 /*
508 * There is no need to read into bp if:
509 * We start on a block boundary and will overwrite the whole block
510 *
511 * OR
512 */
513 if ((blkoffset == 0) && (xfersize >= fragSize)) {
514 bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ);
515 retval = 0;
516
517 if (bp->b_blkno == -1) {
518 brelse(bp);
519 retval = EIO; /* XXX */
520 break;
521 }
522 } else {
523
524 if (currOffset == fp->ff_size && blkoffset == 0) {
525 bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ);
526 retval = 0;
527 if (bp->b_blkno == -1) {
528 brelse(bp);
529 retval = EIO; /* XXX */
530 break;
531 }
532 } else {
533 /*
534 * This I/O transfer is not sufficiently aligned,
535 * so read the affected block into a buffer:
536 */
537 retval = bread(vp, logBlockNo, fragSize, ap->a_cred, &bp);
538 if (retval != E_NONE) {
539 if (bp)
540 brelse(bp);
541 break;
542 }
543 }
544 }
545
546 /* See if we are starting to write within file boundaries:
547 * If not, then we need to present a "hole" for the area
548 * between the current EOF and the start of the current
549 * I/O operation:
550 *
551 * Note that currOffset is only less than uio_offset if
552 * uio_offset > LEOF...
553 */
554 if (uio->uio_offset > currOffset) {
555 clearSize = MIN(uio->uio_offset - currOffset, xfersize);
556 bzero(bp->b_data + blkoffset, clearSize);
557 currOffset += clearSize;
558 blkoffset += clearSize;
559 xfersize -= clearSize;
560 }
561
562 if (xfersize > 0) {
563 retval = uiomove((caddr_t)bp->b_data + blkoffset, (int)xfersize, uio);
564 currOffset += xfersize;
565 }
566
567 if (ioflag & IO_SYNC) {
568 (void)VOP_BWRITE(bp);
569 } else if ((xfersize + blkoffset) == fragSize) {
570 bp->b_flags |= B_AGE;
571 bawrite(bp);
572 } else {
573 bdwrite(bp);
574 }
575
576 /* Update the EOF if we just extended the file
577 * (the PEOF has already been moved out and the
578 * block mapping table has been updated):
579 */
580 if (currOffset > fp->ff_size) {
581 fp->ff_size = currOffset;
582 if (UBCISVALID(vp))
583 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
584 }
585 if (retval || (resid == 0))
586 break;
587 cp->c_flag |= C_CHANGE | C_UPDATE;
588 } /* endwhile */
589 }
590
591 ioerr_exit:
592 /*
593 * If we successfully wrote any data, and we are not the superuser
594 * we clear the setuid and setgid bits as a precaution against
595 * tampering.
596 */
597 if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
598 cp->c_mode &= ~(S_ISUID | S_ISGID);
599
600 if (retval) {
601 if (ioflag & IO_UNIT) {
602 (void)VOP_TRUNCATE(vp, origFileSize,
603 ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
604 uio->uio_offset -= resid - uio->uio_resid;
605 uio->uio_resid = resid;
606 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
607 }
608 } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
609 tv = time;
610 retval = VOP_UPDATE(vp, &tv, &tv, 1);
611 }
612
613 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_END,
614 (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0);
615
616 return (retval);
617 }
618
619
620 /*
621
622 #% ioctl vp U U U
623 #
624 vop_ioctl {
625 IN struct vnode *vp;
626 IN u_long command;
627 IN caddr_t data;
628 IN int fflag;
629 IN struct ucred *cred;
630 IN struct proc *p;
631
632 */
633
634
635 /* ARGSUSED */
636 int
637 hfs_ioctl(ap)
638 struct vop_ioctl_args /* {
639 struct vnode *a_vp;
640 int a_command;
641 caddr_t a_data;
642 int a_fflag;
643 struct ucred *a_cred;
644 struct proc *a_p;
645 } */ *ap;
646 {
647 switch (ap->a_command) {
648 case 1: {
649 register struct cnode *cp;
650 register struct vnode *vp;
651 register struct radvisory *ra;
652 struct filefork *fp;
653 int devBlockSize = 0;
654 int error;
655
656 vp = ap->a_vp;
657
658 if (vp->v_type != VREG)
659 return EINVAL;
660
661 VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ);
662 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
663 if (error)
664 return (error);
665
666 ra = (struct radvisory *)(ap->a_data);
667 cp = VTOC(vp);
668 fp = VTOF(vp);
669
670 if (ra->ra_offset >= fp->ff_size) {
671 VOP_UNLOCK(vp, 0, ap->a_p);
672 return (EFBIG);
673 }
674 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
675
676 error = advisory_read(vp, fp->ff_size, ra->ra_offset, ra->ra_count, devBlockSize);
677 VOP_UNLOCK(vp, 0, ap->a_p);
678
679 return (error);
680 }
681
682 case 2: /* F_READBOOTBLOCKS */
683 case 3: /* F_WRITEBOOTBLOCKS */
684 {
685 struct vnode *vp = ap->a_vp;
686 struct vnode *devvp = NULL;
687 struct fbootstraptransfer *btd = (struct fbootstraptransfer *)ap->a_data;
688 int devBlockSize;
689 int error;
690 struct iovec aiov;
691 struct uio auio;
692 u_long blockNumber;
693 u_long blockOffset;
694 u_long xfersize;
695 struct buf *bp;
696
697 if ((vp->v_flag & VROOT) == 0) return EINVAL;
698 if (btd->fbt_offset + btd->fbt_length > 1024) return EINVAL;
699
700 devvp = VTOHFS(vp)->hfs_devvp;
701 aiov.iov_base = btd->fbt_buffer;
702 aiov.iov_len = btd->fbt_length;
703
704 auio.uio_iov = &aiov;
705 auio.uio_iovcnt = 1;
706 auio.uio_offset = btd->fbt_offset;
707 auio.uio_resid = btd->fbt_length;
708 auio.uio_segflg = UIO_USERSPACE;
709 auio.uio_rw = (ap->a_command == 3) ? UIO_WRITE : UIO_READ; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
710 auio.uio_procp = ap->a_p;
711
712 VOP_DEVBLOCKSIZE(devvp, &devBlockSize);
713
714 while (auio.uio_resid > 0) {
715 blockNumber = auio.uio_offset / devBlockSize;
716 error = bread(devvp, blockNumber, devBlockSize, ap->a_cred, &bp);
717 if (error) {
718 if (bp) brelse(bp);
719 return error;
720 };
721
722 blockOffset = auio.uio_offset % devBlockSize;
723 xfersize = devBlockSize - blockOffset;
724 error = uiomove((caddr_t)bp->b_data + blockOffset, (int)xfersize, &auio);
725 if (error) {
726 brelse(bp);
727 return error;
728 };
729 if (auio.uio_rw == UIO_WRITE) {
730 error = VOP_BWRITE(bp);
731 if (error) return error;
732 } else {
733 brelse(bp);
734 };
735 };
736 };
737 return 0;
738
739 case _IOC(IOC_OUT,'h', 4, 0): /* Create date in local time */
740 {
741 *(time_t *)(ap->a_data) = to_bsd_time(VTOVCB(ap->a_vp)->localCreateDate);
742 return 0;
743 }
744
745 default:
746 return (ENOTTY);
747 }
748
749 /* Should never get here */
750 return 0;
751 }
752
753 /* ARGSUSED */
754 int
755 hfs_select(ap)
756 struct vop_select_args /* {
757 struct vnode *a_vp;
758 int a_which;
759 int a_fflags;
760 struct ucred *a_cred;
761 void *a_wql;
762 struct proc *a_p;
763 } */ *ap;
764 {
765 /*
766 * We should really check to see if I/O is possible.
767 */
768 return (1);
769 }
770
771 /*
772 * Bmap converts a the logical block number of a file to its physical block
773 * number on the disk.
774 */
775
776 /*
777 * vp - address of vnode file the file
778 * bn - which logical block to convert to a physical block number.
779 * vpp - returns the vnode for the block special file holding the filesystem
780 * containing the file of interest
781 * bnp - address of where to return the filesystem physical block number
782 #% bmap vp L L L
783 #% bmap vpp - U -
784 #
785 vop_bmap {
786 IN struct vnode *vp;
787 IN daddr_t bn;
788 OUT struct vnode **vpp;
789 IN daddr_t *bnp;
790 OUT int *runp;
791 */
792 /*
793 * Converts a logical block number to a physical block, and optionally returns
794 * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
795 * The physical block number is based on the device block size, currently its 512.
796 * The block run is returned in logical blocks, and is the REMAINING amount of blocks
797 */
798
799 int
800 hfs_bmap(ap)
801 struct vop_bmap_args /* {
802 struct vnode *a_vp;
803 daddr_t a_bn;
804 struct vnode **a_vpp;
805 daddr_t *a_bnp;
806 int *a_runp;
807 } */ *ap;
808 {
809 struct vnode *vp = ap->a_vp;
810 struct cnode *cp = VTOC(vp);
811 struct filefork *fp = VTOF(vp);
812 struct hfsmount *hfsmp = VTOHFS(vp);
813 int retval = E_NONE;
814 daddr_t logBlockSize;
815 size_t bytesContAvail = 0;
816 off_t blockposition;
817 struct proc *p = NULL;
818 int lockExtBtree;
819 struct rl_entry *invalid_range;
820 enum rl_overlaptype overlaptype;
821
822 /*
823 * Check for underlying vnode requests and ensure that logical
824 * to physical mapping is requested.
825 */
826 if (ap->a_vpp != NULL)
827 *ap->a_vpp = cp->c_devvp;
828 if (ap->a_bnp == NULL)
829 return (0);
830
831 /* Only clustered I/O should have delayed allocations. */
832 DBG_ASSERT(fp->ff_unallocblocks == 0);
833
834 logBlockSize = GetLogicalBlockSize(vp);
835 blockposition = (off_t)ap->a_bn * (off_t)logBlockSize;
836
837 lockExtBtree = overflow_extents(fp);
838 if (lockExtBtree) {
839 p = current_proc();
840 retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID,
841 LK_EXCLUSIVE | LK_CANRECURSE, p);
842 if (retval)
843 return (retval);
844 }
845
846 retval = MacToVFSError(
847 MapFileBlockC (HFSTOVCB(hfsmp),
848 (FCB*)fp,
849 MAXPHYSIO,
850 blockposition,
851 ap->a_bnp,
852 &bytesContAvail));
853
854 if (lockExtBtree) (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
855
856 if (retval == E_NONE) {
857 /* Adjust the mapping information for invalid file ranges: */
858 overlaptype = rl_scan(&fp->ff_invalidranges,
859 blockposition,
860 blockposition + MAXPHYSIO - 1,
861 &invalid_range);
862 if (overlaptype != RL_NOOVERLAP) {
863 switch(overlaptype) {
864 case RL_MATCHINGOVERLAP:
865 case RL_OVERLAPCONTAINSRANGE:
866 case RL_OVERLAPSTARTSBEFORE:
867 /* There's no valid block for this byte offset: */
868 *ap->a_bnp = (daddr_t)-1;
869 bytesContAvail = invalid_range->rl_end + 1 - blockposition;
870 break;
871
872 case RL_OVERLAPISCONTAINED:
873 case RL_OVERLAPENDSAFTER:
874 /* The range of interest hits an invalid block before the end: */
875 if (invalid_range->rl_start == blockposition) {
876 /* There's actually no valid information to be had starting here: */
877 *ap->a_bnp = (daddr_t)-1;
878 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
879 (invalid_range->rl_end + 1 - blockposition < bytesContAvail)) {
880 bytesContAvail = invalid_range->rl_end + 1 - blockposition;
881 };
882 } else {
883 bytesContAvail = invalid_range->rl_start - blockposition;
884 };
885 break;
886 };
887 if (bytesContAvail > MAXPHYSIO) bytesContAvail = MAXPHYSIO;
888 };
889
890 /* Figure out how many read ahead blocks there are */
891 if (ap->a_runp != NULL) {
892 if (can_cluster(logBlockSize)) {
893 /* Make sure this result never goes negative: */
894 *ap->a_runp = (bytesContAvail < logBlockSize) ? 0 : (bytesContAvail / logBlockSize) - 1;
895 } else {
896 *ap->a_runp = 0;
897 };
898 };
899 };
900
901 return (retval);
902 }
903
904 /* blktooff converts logical block number to file offset */
905
906 int
907 hfs_blktooff(ap)
908 struct vop_blktooff_args /* {
909 struct vnode *a_vp;
910 daddr_t a_lblkno;
911 off_t *a_offset;
912 } */ *ap;
913 {
914 if (ap->a_vp == NULL)
915 return (EINVAL);
916 *ap->a_offset = (off_t)ap->a_lblkno * PAGE_SIZE_64;
917
918 return(0);
919 }
920
921 int
922 hfs_offtoblk(ap)
923 struct vop_offtoblk_args /* {
924 struct vnode *a_vp;
925 off_t a_offset;
926 daddr_t *a_lblkno;
927 } */ *ap;
928 {
929 if (ap->a_vp == NULL)
930 return (EINVAL);
931 *ap->a_lblkno = ap->a_offset / PAGE_SIZE_64;
932
933 return(0);
934 }
935
936 int
937 hfs_cmap(ap)
938 struct vop_cmap_args /* {
939 struct vnode *a_vp;
940 off_t a_foffset;
941 size_t a_size;
942 daddr_t *a_bpn;
943 size_t *a_run;
944 void *a_poff;
945 } */ *ap;
946 {
947 struct hfsmount *hfsmp = VTOHFS(ap->a_vp);
948 struct filefork *fp = VTOF(ap->a_vp);
949 size_t bytesContAvail = 0;
950 int retval = E_NONE;
951 int lockExtBtree = 0;
952 struct proc *p = NULL;
953 struct rl_entry *invalid_range;
954 enum rl_overlaptype overlaptype;
955
956 /*
957 * Check for underlying vnode requests and ensure that logical
958 * to physical mapping is requested.
959 */
960 if (ap->a_bpn == NULL)
961 return (0);
962
963 if (overflow_extents(fp) || fp->ff_unallocblocks) {
964 lockExtBtree = 1;
965 p = current_proc();
966 if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
967 return (retval);
968 }
969 }
970
971 /*
972 * Check for any delayed allocations.
973 */
974 if (fp->ff_unallocblocks) {
975 SInt64 reqbytes, actbytes;
976
977 reqbytes = (SInt64)fp->ff_unallocblocks *
978 (SInt64)HFSTOVCB(hfsmp)->blockSize;
979 /*
980 * Release the blocks on loan and aquire some real ones.
981 * Note that we can race someone else for these blocks
982 * (and lose) so cmap needs to handle a failure here.
983 * Currently this race can't occur because all allocations
984 * are protected by an exclusive lock on the Extents
985 * Overflow file.
986 */
987 HFSTOVCB(hfsmp)->loanedBlocks -= fp->ff_unallocblocks;
988 FTOC(fp)->c_blocks -= fp->ff_unallocblocks;
989 fp->ff_blocks -= fp->ff_unallocblocks;
990 fp->ff_unallocblocks = 0;
991
992 while (retval == 0 && reqbytes > 0) {
993 retval = MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp),
994 (FCB*)fp, reqbytes, 0,
995 kEFAllMask | kEFNoClumpMask, &actbytes));
996 if (retval == 0 && actbytes == 0)
997 retval = ENOSPC;
998
999 if (retval) {
1000 fp->ff_unallocblocks =
1001 reqbytes / HFSTOVCB(hfsmp)->blockSize;
1002 HFSTOVCB(hfsmp)->loanedBlocks += fp->ff_unallocblocks;
1003 FTOC(fp)->c_blocks += fp->ff_unallocblocks;
1004 fp->ff_blocks += fp->ff_unallocblocks;
1005 }
1006 reqbytes -= actbytes;
1007 }
1008
1009 if (retval) {
1010 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
1011 return (retval);
1012 }
1013 VTOC(ap->a_vp)->c_flag |= C_MODIFIED;
1014 }
1015
1016 retval = MacToVFSError(
1017 MapFileBlockC (HFSTOVCB(hfsmp),
1018 (FCB *)fp,
1019 ap->a_size,
1020 ap->a_foffset,
1021 ap->a_bpn,
1022 &bytesContAvail));
1023
1024 if (lockExtBtree)
1025 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
1026
1027 if (retval == E_NONE) {
1028 /* Adjust the mapping information for invalid file ranges: */
1029 overlaptype = rl_scan(&fp->ff_invalidranges,
1030 ap->a_foffset,
1031 ap->a_foffset + (off_t)bytesContAvail - 1,
1032 &invalid_range);
1033 if (overlaptype != RL_NOOVERLAP) {
1034 switch(overlaptype) {
1035 case RL_MATCHINGOVERLAP:
1036 case RL_OVERLAPCONTAINSRANGE:
1037 case RL_OVERLAPSTARTSBEFORE:
1038 /* There's no valid block for this byte offset: */
1039 *ap->a_bpn = (daddr_t)-1;
1040
1041 /* There's no point limiting the amount to be returned if the
1042 invalid range that was hit extends all the way to the EOF
1043 (i.e. there's no valid bytes between the end of this range
1044 and the file's EOF):
1045 */
1046 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
1047 (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) {
1048 bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset;
1049 };
1050 break;
1051
1052 case RL_OVERLAPISCONTAINED:
1053 case RL_OVERLAPENDSAFTER:
1054 /* The range of interest hits an invalid block before the end: */
1055 if (invalid_range->rl_start == ap->a_foffset) {
1056 /* There's actually no valid information to be had starting here: */
1057 *ap->a_bpn = (daddr_t)-1;
1058 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
1059 (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) {
1060 bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset;
1061 };
1062 } else {
1063 bytesContAvail = invalid_range->rl_start - ap->a_foffset;
1064 };
1065 break;
1066 };
1067 if (bytesContAvail > ap->a_size) bytesContAvail = ap->a_size;
1068 };
1069
1070 if (ap->a_run) *ap->a_run = bytesContAvail;
1071 };
1072
1073 if (ap->a_poff)
1074 *(int *)ap->a_poff = 0;
1075
1076 return (retval);
1077 }
1078
1079
1080 /*
1081 * Read or write a buffer that is not contiguous on disk. We loop over
1082 * each device block, copying to or from caller's buffer.
1083 *
1084 * We could be a bit more efficient by transferring as much data as is
1085 * contiguous. But since this routine should rarely be called, and that
1086 * would be more complicated; best to keep it simple.
1087 */
1088 static int
1089 hfs_strategy_fragmented(struct buf *bp)
1090 {
1091 register struct vnode *vp = bp->b_vp;
1092 register struct cnode *cp = VTOC(vp);
1093 register struct vnode *devvp = cp->c_devvp;
1094 caddr_t ioaddr; /* Address of fragment within bp */
1095 struct buf *frag = NULL; /* For reading or writing a single block */
1096 int retval = 0;
1097 long remaining; /* Bytes (in bp) left to transfer */
1098 off_t offset; /* Logical offset of current fragment in vp */
1099 u_long block_size; /* Size of one device block (and one I/O) */
1100
1101 /* Make sure we redo this mapping for the next I/O */
1102 bp->b_blkno = bp->b_lblkno;
1103
1104 /* Set up the logical position and number of bytes to read/write */
1105 offset = (off_t) bp->b_lblkno * (off_t) GetLogicalBlockSize(vp);
1106 block_size = VTOHFS(vp)->hfs_phys_block_size;
1107
1108 /* Get an empty buffer to do the deblocking */
1109 frag = geteblk(block_size);
1110 if (ISSET(bp->b_flags, B_READ))
1111 SET(frag->b_flags, B_READ);
1112
1113 for (ioaddr = bp->b_data, remaining = bp->b_bcount; remaining != 0;
1114 ioaddr += block_size, offset += block_size,
1115 remaining -= block_size) {
1116 frag->b_resid = frag->b_bcount;
1117 CLR(frag->b_flags, B_DONE);
1118
1119 /* Map the current position to a physical block number */
1120 retval = VOP_CMAP(vp, offset, block_size, &frag->b_lblkno,
1121 NULL, NULL);
1122 if (retval != 0)
1123 break;
1124
1125 /*
1126 * Did we try to read a hole?
1127 * (Should never happen for metadata!)
1128 */
1129 if ((long)frag->b_lblkno == -1) {
1130 bzero(ioaddr, block_size);
1131 continue;
1132 }
1133
1134 /* If writing, copy before I/O */
1135 if (!ISSET(bp->b_flags, B_READ))
1136 bcopy(ioaddr, frag->b_data, block_size);
1137
1138 /* Call the device to do the I/O and wait for it */
1139 frag->b_blkno = frag->b_lblkno;
1140 frag->b_vp = devvp; /* Used to dispatch via VOP_STRATEGY */
1141 frag->b_dev = devvp->v_rdev;
1142 retval = VOP_STRATEGY(frag);
1143 frag->b_vp = NULL;
1144 if (retval != 0)
1145 break;
1146 retval = biowait(frag);
1147 if (retval != 0)
1148 break;
1149
1150 /* If reading, copy after the I/O */
1151 if (ISSET(bp->b_flags, B_READ))
1152 bcopy(frag->b_data, ioaddr, block_size);
1153 }
1154
1155 frag->b_vp = NULL;
1156 SET(frag->b_flags, B_INVAL);
1157 brelse(frag);
1158
1159 if ((bp->b_error = retval) != 0)
1160 SET(bp->b_flags, B_ERROR);
1161
1162 biodone(bp); /* This I/O is now complete */
1163 return retval;
1164 }
1165
1166
1167 /*
1168 * Calculate the logical to physical mapping if not done already,
1169 * then call the device strategy routine.
1170 #
1171 #vop_strategy {
1172 # IN struct buf *bp;
1173 */
1174 int
1175 hfs_strategy(ap)
1176 struct vop_strategy_args /* {
1177 struct buf *a_bp;
1178 } */ *ap;
1179 {
1180 register struct buf *bp = ap->a_bp;
1181 register struct vnode *vp = bp->b_vp;
1182 register struct cnode *cp = VTOC(vp);
1183 int retval = 0;
1184 off_t offset;
1185 size_t bytes_contig;
1186
1187 if ( !(bp->b_flags & B_VECTORLIST)) {
1188 if (vp->v_type == VBLK || vp->v_type == VCHR)
1189 panic("hfs_strategy: device vnode passed!");
1190
1191 if (bp->b_flags & B_PAGELIST) {
1192 /*
1193 * If we have a page list associated with this bp,
1194 * then go through cluster_bp since it knows how to
1195 * deal with a page request that might span non-
1196 * contiguous physical blocks on the disk...
1197 */
1198 retval = cluster_bp(bp);
1199 vp = cp->c_devvp;
1200 bp->b_dev = vp->v_rdev;
1201
1202 return (retval);
1203 }
1204
1205 /*
1206 * If we don't already know the filesystem relative block
1207 * number then get it using VOP_BMAP(). If VOP_BMAP()
1208 * returns the block number as -1 then we've got a hole in
1209 * the file. Although HFS filesystems don't create files with
1210 * holes, invalidating of subranges of the file (lazy zero
1211 * filling) may create such a situation.
1212 */
1213 if (bp->b_blkno == bp->b_lblkno) {
1214 offset = (off_t) bp->b_lblkno *
1215 (off_t) GetLogicalBlockSize(vp);
1216
1217 if ((retval = VOP_CMAP(vp, offset, bp->b_bcount,
1218 &bp->b_blkno, &bytes_contig, NULL))) {
1219 bp->b_error = retval;
1220 bp->b_flags |= B_ERROR;
1221 biodone(bp);
1222 return (retval);
1223 }
1224 if (bytes_contig < bp->b_bcount)
1225 {
1226 /*
1227 * We were asked to read a block that wasn't
1228 * contiguous, so we have to read each of the
1229 * pieces and copy them into the buffer.
1230 * Since ordinary file I/O goes through
1231 * cluster_io (which won't ask us for
1232 * discontiguous data), this is probably an
1233 * attempt to read or write metadata.
1234 */
1235 return hfs_strategy_fragmented(bp);
1236 }
1237 if ((long)bp->b_blkno == -1)
1238 clrbuf(bp);
1239 }
1240 if ((long)bp->b_blkno == -1) {
1241 biodone(bp);
1242 return (0);
1243 }
1244 if (bp->b_validend == 0) {
1245 /*
1246 * Record the exact size of the I/O transfer about to
1247 * be made:
1248 */
1249 bp->b_validend = bp->b_bcount;
1250 }
1251 }
1252 vp = cp->c_devvp;
1253 bp->b_dev = vp->v_rdev;
1254
1255 return VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
1256 }
1257
1258
1259 /*
1260 #
1261 #% truncate vp L L L
1262 #
1263 vop_truncate {
1264 IN struct vnode *vp;
1265 IN off_t length;
1266 IN int flags; (IO_SYNC)
1267 IN struct ucred *cred;
1268 IN struct proc *p;
1269 };
1270 * Truncate a cnode to at most length size, freeing (or adding) the
1271 * disk blocks.
1272 */
1273 int hfs_truncate(ap)
1274 struct vop_truncate_args /* {
1275 struct vnode *a_vp;
1276 off_t a_length;
1277 int a_flags;
1278 struct ucred *a_cred;
1279 struct proc *a_p;
1280 } */ *ap;
1281 {
1282 register struct vnode *vp = ap->a_vp;
1283 register struct cnode *cp = VTOC(vp);
1284 struct filefork *fp = VTOF(vp);
1285 off_t length;
1286 long vflags;
1287 struct timeval tv;
1288 int retval;
1289 off_t bytesToAdd;
1290 off_t actualBytesAdded;
1291 off_t filebytes;
1292 u_long fileblocks;
1293 int blksize;
1294
1295 if (vp->v_type != VREG && vp->v_type != VLNK)
1296 return (EISDIR); /* cannot truncate an HFS directory! */
1297
1298 length = ap->a_length;
1299 blksize = VTOVCB(vp)->blockSize;
1300 fileblocks = fp->ff_blocks;
1301 filebytes = (off_t)fileblocks * (off_t)blksize;
1302
1303 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_START,
1304 (int)length, (int)fp->ff_size, (int)filebytes, 0, 0);
1305
1306 if (length < 0)
1307 return (EINVAL);
1308
1309 if ((!ISHFSPLUS(VTOVCB(vp))) && (length > (off_t)MAXHFSFILESIZE))
1310 return (EFBIG);
1311
1312
1313 tv = time;
1314 retval = E_NONE;
1315
1316 /*
1317 * We cannot just check if fp->ff_size == length (as an optimization)
1318 * since there may be extra physical blocks that also need truncation.
1319 */
1320 #if QUOTA
1321 if (retval = hfs_getinoquota(cp))
1322 return(retval);
1323 #endif /* QUOTA */
1324
1325 /*
1326 * Lengthen the size of the file. We must ensure that the
1327 * last byte of the file is allocated. Since the smallest
1328 * value of ff_size is 0, length will be at least 1.
1329 */
1330 if (length > fp->ff_size) {
1331 #if QUOTA
1332 retval = hfs_chkdq(cp, (int64_t)(roundup(length - filebytes, fp->ff_clumpsize)),
1333 ap->a_cred, 0);
1334 if (retval)
1335 goto Err_Exit;
1336 #endif /* QUOTA */
1337 /*
1338 * If we don't have enough physical space then
1339 * we need to extend the physical size.
1340 */
1341 if (length > filebytes) {
1342 int eflags;
1343
1344 /* All or nothing and don't round up to clumpsize. */
1345 eflags = kEFAllMask | kEFNoClumpMask;
1346
1347 if (suser(ap->a_cred, NULL) != 0)
1348 eflags |= kEFReserveMask; /* keep a reserve */
1349
1350 /* lock extents b-tree (also protects volume bitmap) */
1351 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
1352 if (retval)
1353 goto Err_Exit;
1354
1355 while ((length > filebytes) && (retval == E_NONE)) {
1356 bytesToAdd = length - filebytes;
1357 retval = MacToVFSError(ExtendFileC(VTOVCB(vp),
1358 (FCB*)fp,
1359 bytesToAdd,
1360 0,
1361 eflags,
1362 &actualBytesAdded));
1363
1364 filebytes = (off_t)fp->ff_blocks * (off_t)blksize;
1365 if (actualBytesAdded == 0 && retval == E_NONE) {
1366 if (length > filebytes)
1367 length = filebytes;
1368 break;
1369 }
1370 } /* endwhile */
1371 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1372 if (retval)
1373 goto Err_Exit;
1374
1375 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE,
1376 (int)length, (int)fp->ff_size, (int)filebytes, 0, 0);
1377 }
1378
1379 if (!(ap->a_flags & IO_NOZEROFILL)) {
1380 if (UBCINFOEXISTS(vp) && retval == E_NONE) {
1381 struct rl_entry *invalid_range;
1382 int devBlockSize;
1383 off_t zero_limit;
1384
1385 zero_limit = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
1386 if (length < zero_limit) zero_limit = length;
1387
1388 if (length > fp->ff_size) {
1389 /* Extending the file: time to fill out the current last page w. zeroes? */
1390 if ((fp->ff_size & PAGE_MASK_64) &&
1391 (rl_scan(&fp->ff_invalidranges, fp->ff_size & ~PAGE_MASK_64,
1392 fp->ff_size - 1, &invalid_range) == RL_NOOVERLAP)) {
1393
1394 /* There's some valid data at the start of the (current) last page
1395 of the file, so zero out the remainder of that page to ensure the
1396 entire page contains valid data. Since there is no invalid range
1397 possible past the (current) eof, there's no need to remove anything
1398 from the invalid range list before calling cluster_write(): */
1399 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1400 retval = cluster_write(vp, (struct uio *) 0, fp->ff_size, zero_limit,
1401 fp->ff_size, (off_t)0, devBlockSize,
1402 (ap->a_flags & IO_SYNC) | IO_HEADZEROFILL | IO_NOZERODIRTY);
1403 if (retval) goto Err_Exit;
1404
1405 /* Merely invalidate the remaining area, if necessary: */
1406 if (length > zero_limit) {
1407 rl_add(zero_limit, length - 1, &fp->ff_invalidranges);
1408 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
1409 }
1410 } else {
1411 /* The page containing the (current) eof is invalid: just add the
1412 remainder of the page to the invalid list, along with the area
1413 being newly allocated:
1414 */
1415 rl_add(fp->ff_size, length - 1, &fp->ff_invalidranges);
1416 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
1417 };
1418 }
1419 } else {
1420 panic("hfs_truncate: invoked on non-UBC object?!");
1421 };
1422 }
1423 cp->c_flag |= C_UPDATE;
1424 fp->ff_size = length;
1425
1426 if (UBCISVALID(vp))
1427 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
1428
1429 } else { /* Shorten the size of the file */
1430
1431 if (fp->ff_size > length) {
1432 /*
1433 * Any buffers that are past the truncation point need to be
1434 * invalidated (to maintain buffer cache consistency). For
1435 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1436 */
1437 if (UBCISVALID(vp))
1438 ubc_setsize(vp, length); /* XXX check errors */
1439
1440 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
1441 retval = vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
1442
1443 /* Any space previously marked as invalid is now irrelevant: */
1444 rl_remove(length, fp->ff_size - 1, &fp->ff_invalidranges);
1445 }
1446
1447 /*
1448 * Account for any unmapped blocks. Note that the new
1449 * file length can still end up with unmapped blocks.
1450 */
1451 if (fp->ff_unallocblocks > 0) {
1452 u_int32_t finalblks;
1453
1454 /* lock extents b-tree */
1455 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID,
1456 LK_EXCLUSIVE, ap->a_p);
1457 if (retval)
1458 goto Err_Exit;
1459
1460 VTOVCB(vp)->loanedBlocks -= fp->ff_unallocblocks;
1461 cp->c_blocks -= fp->ff_unallocblocks;
1462 fp->ff_blocks -= fp->ff_unallocblocks;
1463 fp->ff_unallocblocks = 0;
1464
1465 finalblks = (length + blksize - 1) / blksize;
1466 if (finalblks > fp->ff_blocks) {
1467 /* calculate required unmapped blocks */
1468 fp->ff_unallocblocks = finalblks - fp->ff_blocks;
1469 VTOVCB(vp)->loanedBlocks += fp->ff_unallocblocks;
1470 cp->c_blocks += fp->ff_unallocblocks;
1471 fp->ff_blocks += fp->ff_unallocblocks;
1472 }
1473 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID,
1474 LK_RELEASE, ap->a_p);
1475 }
1476
1477 /*
1478 * For a TBE process the deallocation of the file blocks is
1479 * delayed until the file is closed. And hfs_close calls
1480 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1481 * isn't set, we make sure this isn't a TBE process.
1482 */
1483 if ((ap->a_flags & IO_NDELAY) || (!ISSET(ap->a_p->p_flag, P_TBE))) {
1484 #if QUOTA
1485 off_t savedbytes = ((off_t)fp->ff_blocks * (off_t)blksize);
1486 #endif /* QUOTA */
1487 /* lock extents b-tree (also protects volume bitmap) */
1488 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
1489 if (retval)
1490 goto Err_Exit;
1491
1492 if (fp->ff_unallocblocks == 0)
1493 retval = MacToVFSError(TruncateFileC(VTOVCB(vp),
1494 (FCB*)fp, length, false));
1495
1496 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1497 filebytes = (off_t)fp->ff_blocks * (off_t)blksize;
1498 if (retval)
1499 goto Err_Exit;
1500 #if QUOTA
1501 /* These are bytesreleased */
1502 (void) hfs_chkdq(cp, (int64_t)-(savedbytes - filebytes), NOCRED, 0);
1503 #endif /* QUOTA */
1504 }
1505 /* Only set update flag if the logical length changes */
1506 if (fp->ff_size != length)
1507 cp->c_flag |= C_UPDATE;
1508 fp->ff_size = length;
1509 }
1510 cp->c_flag |= C_CHANGE;
1511 retval = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
1512 if (retval) {
1513 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE,
1514 -1, -1, -1, retval, 0);
1515 }
1516
1517 Err_Exit:
1518
1519 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_END,
1520 (int)length, (int)fp->ff_size, (int)filebytes, retval, 0);
1521
1522 return (retval);
1523 }
1524
1525
1526
1527 /*
1528 #
1529 #% allocate vp L L L
1530 #
1531 vop_allocate {
1532 IN struct vnode *vp;
1533 IN off_t length;
1534 IN int flags;
1535 OUT off_t *bytesallocated;
1536 IN off_t offset;
1537 IN struct ucred *cred;
1538 IN struct proc *p;
1539 };
1540 * allocate a cnode to at most length size
1541 */
1542 int hfs_allocate(ap)
1543 struct vop_allocate_args /* {
1544 struct vnode *a_vp;
1545 off_t a_length;
1546 u_int32_t a_flags;
1547 off_t *a_bytesallocated;
1548 off_t a_offset;
1549 struct ucred *a_cred;
1550 struct proc *a_p;
1551 } */ *ap;
1552 {
1553 struct vnode *vp = ap->a_vp;
1554 struct cnode *cp = VTOC(vp);
1555 struct filefork *fp = VTOF(vp);
1556 off_t length = ap->a_length;
1557 off_t startingPEOF;
1558 off_t moreBytesRequested;
1559 off_t actualBytesAdded;
1560 off_t filebytes;
1561 u_long fileblocks;
1562 long vflags;
1563 struct timeval tv;
1564 int retval, retval2;
1565 UInt32 blockHint;
1566 UInt32 extendFlags =0; /* For call to ExtendFileC */
1567
1568 *(ap->a_bytesallocated) = 0;
1569 fileblocks = fp->ff_blocks;
1570 filebytes = (off_t)fileblocks * (off_t)VTOVCB(vp)->blockSize;
1571
1572 if (length < (off_t)0)
1573 return (EINVAL);
1574 if (vp->v_type != VREG && vp->v_type != VLNK)
1575 return (EISDIR);
1576 if ((ap->a_flags & ALLOCATEFROMVOL) && (length <= filebytes))
1577 return (EINVAL);
1578
1579 /* Fill in the flags word for the call to Extend the file */
1580
1581 if (ap->a_flags & ALLOCATECONTIG)
1582 extendFlags |= kEFContigMask;
1583
1584 if (ap->a_flags & ALLOCATEALL)
1585 extendFlags |= kEFAllMask;
1586
1587 if (suser(ap->a_cred, NULL) != 0)
1588 extendFlags |= kEFReserveMask;
1589
1590 tv = time;
1591 retval = E_NONE;
1592 blockHint = 0;
1593 startingPEOF = filebytes;
1594
1595 if (ap->a_flags & ALLOCATEFROMPEOF)
1596 length += filebytes;
1597 else if (ap->a_flags & ALLOCATEFROMVOL)
1598 blockHint = ap->a_offset / VTOVCB(vp)->blockSize;
1599
1600 /* If no changes are necesary, then we're done */
1601 if (filebytes == length)
1602 goto Std_Exit;
1603
1604 /*
1605 * Lengthen the size of the file. We must ensure that the
1606 * last byte of the file is allocated. Since the smallest
1607 * value of filebytes is 0, length will be at least 1.
1608 */
1609 if (length > filebytes) {
1610 moreBytesRequested = length - filebytes;
1611
1612 #if QUOTA
1613 retval = hfs_chkdq(cp, (int64_t)(roundup(moreBytesRequested, fp->ff_clumpsize)),
1614 ap->a_cred, 0);
1615 if (retval)
1616 return (retval);
1617
1618 #endif /* QUOTA */
1619 /* lock extents b-tree (also protects volume bitmap) */
1620 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
1621 if (retval) goto Err_Exit;
1622
1623 retval = MacToVFSError(ExtendFileC(VTOVCB(vp),
1624 (FCB*)fp,
1625 moreBytesRequested,
1626 blockHint,
1627 extendFlags,
1628 &actualBytesAdded));
1629
1630 *(ap->a_bytesallocated) = actualBytesAdded;
1631 filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize;
1632 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1633
1634 /*
1635 * if we get an error and no changes were made then exit
1636 * otherwise we must do the VOP_UPDATE to reflect the changes
1637 */
1638 if (retval && (startingPEOF == filebytes))
1639 goto Err_Exit;
1640
1641 /*
1642 * Adjust actualBytesAdded to be allocation block aligned, not
1643 * clump size aligned.
1644 * NOTE: So what we are reporting does not affect reality
1645 * until the file is closed, when we truncate the file to allocation
1646 * block size.
1647 */
1648 if ((actualBytesAdded != 0) && (moreBytesRequested < actualBytesAdded))
1649 *(ap->a_bytesallocated) =
1650 roundup(moreBytesRequested, (off_t)VTOVCB(vp)->blockSize);
1651
1652 } else { /* Shorten the size of the file */
1653
1654 if (fp->ff_size > length) {
1655 /*
1656 * Any buffers that are past the truncation point need to be
1657 * invalidated (to maintain buffer cache consistency). For
1658 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1659 */
1660 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
1661 (void) vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
1662 }
1663
1664 /* lock extents b-tree (also protects volume bitmap) */
1665 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
1666 if (retval) goto Err_Exit;
1667
1668 retval = MacToVFSError(
1669 TruncateFileC(
1670 VTOVCB(vp),
1671 (FCB*)fp,
1672 length,
1673 false));
1674 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1675 filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize;
1676 /*
1677 * if we get an error and no changes were made then exit
1678 * otherwise we must do the VOP_UPDATE to reflect the changes
1679 */
1680 if (retval && (startingPEOF == filebytes)) goto Err_Exit;
1681 #if QUOTA
1682 /* These are bytesreleased */
1683 (void) hfs_chkdq(cp, (int64_t)-((startingPEOF - filebytes)), NOCRED,0);
1684 #endif /* QUOTA */
1685
1686 if (fp->ff_size > filebytes) {
1687 fp->ff_size = filebytes;
1688
1689 if (UBCISVALID(vp))
1690 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
1691 }
1692 }
1693
1694 Std_Exit:
1695 cp->c_flag |= C_CHANGE | C_UPDATE;
1696 retval2 = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
1697
1698 if (retval == 0)
1699 retval = retval2;
1700 Err_Exit:
1701 return (retval);
1702 }
1703
1704
1705 /*
1706 * pagein for HFS filesystem
1707 */
1708 int
1709 hfs_pagein(ap)
1710 struct vop_pagein_args /* {
1711 struct vnode *a_vp,
1712 upl_t a_pl,
1713 vm_offset_t a_pl_offset,
1714 off_t a_f_offset,
1715 size_t a_size,
1716 struct ucred *a_cred,
1717 int a_flags
1718 } */ *ap;
1719 {
1720 register struct vnode *vp = ap->a_vp;
1721 int devBlockSize = 0;
1722 int error;
1723
1724 if (vp->v_type != VREG && vp->v_type != VLNK)
1725 panic("hfs_pagein: vp not UBC type\n");
1726
1727 VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devBlockSize);
1728
1729 error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset,
1730 ap->a_size, (off_t)VTOF(vp)->ff_size, devBlockSize,
1731 ap->a_flags);
1732 return (error);
1733 }
1734
1735 /*
1736 * pageout for HFS filesystem.
1737 */
1738 int
1739 hfs_pageout(ap)
1740 struct vop_pageout_args /* {
1741 struct vnode *a_vp,
1742 upl_t a_pl,
1743 vm_offset_t a_pl_offset,
1744 off_t a_f_offset,
1745 size_t a_size,
1746 struct ucred *a_cred,
1747 int a_flags
1748 } */ *ap;
1749 {
1750 struct vnode *vp = ap->a_vp;
1751 struct cnode *cp = VTOC(vp);
1752 struct filefork *fp = VTOF(vp);
1753 int retval;
1754 int devBlockSize = 0;
1755 off_t end_of_range;
1756 off_t filesize;
1757
1758 if (UBCINVALID(vp))
1759 panic("hfs_pageout: Not a VREG: vp=%x", vp);
1760
1761 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1762 filesize = fp->ff_size;
1763 end_of_range = ap->a_f_offset + ap->a_size - 1;
1764
1765 if (end_of_range >= filesize)
1766 end_of_range = (off_t)(filesize - 1);
1767 if (ap->a_f_offset < filesize)
1768 rl_remove(ap->a_f_offset, end_of_range, &fp->ff_invalidranges);
1769
1770 retval = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, ap->a_size,
1771 filesize, devBlockSize, ap->a_flags);
1772
1773 /*
1774 * If we successfully wrote any data, and we are not the superuser
1775 * we clear the setuid and setgid bits as a precaution against
1776 * tampering.
1777 */
1778 if (retval == 0 && ap->a_cred && ap->a_cred->cr_uid != 0)
1779 cp->c_mode &= ~(S_ISUID | S_ISGID);
1780
1781 return (retval);
1782 }
1783
1784 /*
1785 * Intercept B-Tree node writes to unswap them if necessary.
1786 #
1787 #vop_bwrite {
1788 # IN struct buf *bp;
1789 */
1790 int
1791 hfs_bwrite(ap)
1792 struct vop_bwrite_args /* {
1793 struct buf *a_bp;
1794 } */ *ap;
1795 {
1796 int retval = 0;
1797 #if BYTE_ORDER == LITTLE_ENDIAN
1798 register struct buf *bp = ap->a_bp;
1799 register struct vnode *vp = bp->b_vp;
1800 BlockDescriptor block;
1801
1802 /* Trap B-Tree writes */
1803 if ((VTOC(vp)->c_fileid == kHFSExtentsFileID) ||
1804 (VTOC(vp)->c_fileid == kHFSCatalogFileID)) {
1805
1806 /* Swap if the B-Tree node is in native byte order */
1807 if (((UInt16 *)((char *)bp->b_data + bp->b_bcount - 2))[0] == 0x000e) {
1808 /* Prepare the block pointer */
1809 block.blockHeader = bp;
1810 block.buffer = bp->b_data;
1811 /* not found in cache ==> came from disk */
1812 block.blockReadFromDisk = (bp->b_flags & B_CACHE) == 0;
1813 block.blockSize = bp->b_bcount;
1814
1815 /* Endian un-swap B-Tree node */
1816 SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1);
1817 }
1818
1819 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
1820 }
1821 #endif
1822 /* This buffer shouldn't be locked anymore but if it is clear it */
1823 if (ISSET(ap->a_bp->b_flags, B_LOCKED)) {
1824 CLR(ap->a_bp->b_flags, B_LOCKED);
1825 printf("hfs_bwrite: called with lock bit set\n");
1826 }
1827 retval = vn_bwrite (ap);
1828
1829 return (retval);
1830 }