1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
6 * Created by Or Haimovich on 20/3/18.
10 #include <sys/mount.h>
12 #include "lf_hfs_vnops.h"
14 #include "lf_hfs_catalog.h"
15 #include "lf_hfs_dirops_handler.h"
16 #include "lf_hfs_fileops_handler.h"
17 #include "lf_hfs_vfsutils.h"
18 #include "lf_hfs_logger.h"
19 #include "lf_hfs_attrlist.h"
20 #include "lf_hfs_btree.h"
21 #include "lf_hfs_vfsops.h"
22 #include "lf_hfs_utils.h"
23 #include "lf_hfs_readwrite_ops.h"
24 #include "lf_hfs_generic_buf.h"
25 #include "lf_hfs_endian.h"
27 #include <sys/mount.h>
28 #include "lf_hfs_link.h"
29 #include "lf_hfs_journal.h"
30 #include "lf_hfs_chash.h"
32 #define DOT_DIR_SIZE (UVFS_DIRENTRY_RECLEN(1))
33 #define DOT_X2_DIR_SIZE (UVFS_DIRENTRY_RECLEN(2))
36 /* Options for hfs_removedir and hfs_removefile */
37 #define HFSRM_SKIP_RESERVE 0x01
38 #define _PATH_RSRCFORKSPEC "/..namedfork/rsrc"
40 static int hfs_set_bsd_flags(struct cnode
*cp
, u_int32_t new_bsd_flags
);
43 replace_desc(struct cnode
*cp
, struct cat_desc
*cdp
)
45 // fixes 4348457 and 4463138
46 if (&cp
->c_desc
== cdp
) {
50 /* First release allocated name buffer */
51 if (cp
->c_desc
.cd_flags
& CD_HASBUF
&& cp
->c_desc
.cd_nameptr
!= 0) {
52 const u_int8_t
*name
= cp
->c_desc
.cd_nameptr
;
54 cp
->c_desc
.cd_nameptr
= 0;
55 cp
->c_desc
.cd_namelen
= 0;
56 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
57 hfs_free((void*)name
);
59 bcopy(cdp
, &cp
->c_desc
, sizeof(cp
->c_desc
));
61 /* Cnode now owns the name buffer */
62 cdp
->cd_nameptr
= NULL
;
64 cdp
->cd_flags
&= ~CD_HASBUF
;
67 static void SynthesizeDotAndDotX2(u_int64_t uCnid
, void* puBuff
, bool bIsDot
, bool bIsLastEntry
)
69 UVFSDirEntry
* psDotEntry
= (UVFSDirEntry
*)puBuff
;
70 uint8_t uNameLen
= bIsDot
? 1: 2;
71 memset( psDotEntry
, 0, UVFS_DIRENTRY_RECLEN(uNameLen
));
73 psDotEntry
->de_fileid
= uCnid
;
74 psDotEntry
->de_filetype
= UVFS_FA_TYPE_DIR
;
75 psDotEntry
->de_reclen
= bIsLastEntry
? 0 : UVFS_DIRENTRY_RECLEN(uNameLen
);
76 psDotEntry
->de_nextcookie
= uNameLen
;
77 psDotEntry
->de_namelen
= uNameLen
;
78 uint8_t* puNameBuf
= (uint8_t*)psDotEntry
->de_name
;
91 static int SyntisizeEntries(uint64_t* puOffset
, ReadDirBuff_s
* psReadDirBuffer
, int iIsExtended
, u_int64_t uCnid
, u_int64_t uParentCnid
, UVFSDirEntry
** ppsDotDotEntry
)
97 //Curently not supporting nonextended ReadDir
101 if (DOT_DIR_SIZE
> psReadDirBuffer
->uBufferResid
)
106 pvBuff
= hfs_malloc(DOT_DIR_SIZE
);
109 LFHFS_LOG(LEVEL_ERROR
, "SyntisizeEntries: Failed to allocate buffer for DOT entry\n");
115 bool bIsEnoughRoomForAll
= (DOT_DIR_SIZE
+ DOT_X2_DIR_SIZE
> psReadDirBuffer
->uBufferResid
);
116 SynthesizeDotAndDotX2(uCnid
, pvBuff
, true, bIsEnoughRoomForAll
);
117 memcpy(psReadDirBuffer
->pvBuffer
+ READDIR_BUF_OFFSET(psReadDirBuffer
) , pvBuff
, DOT_DIR_SIZE
);
119 psReadDirBuffer
->uBufferResid
-= DOT_DIR_SIZE
;
122 if (DOT_X2_DIR_SIZE
> psReadDirBuffer
->uBufferResid
)
128 pvBuff
= hfs_malloc(DOT_X2_DIR_SIZE
);
131 LFHFS_LOG(LEVEL_ERROR
, "SyntisizeEntries: Failed to allocate buffer for DOTx2 entry\n");
137 SynthesizeDotAndDotX2(uParentCnid
, pvBuff
, false, false);
138 memcpy(psReadDirBuffer
->pvBuffer
+ READDIR_BUF_OFFSET(psReadDirBuffer
), pvBuff
, DOT_X2_DIR_SIZE
);
139 *ppsDotDotEntry
= (UVFSDirEntry
*) (psReadDirBuffer
->pvBuffer
+ READDIR_BUF_OFFSET(psReadDirBuffer
));
141 psReadDirBuffer
->uBufferResid
-= DOT_X2_DIR_SIZE
;
151 * hfs_vnop_readdir reads directory entries into the buffer pointed
152 * to by uio, in a filesystem independent format. Up to uio_resid
153 * bytes of data can be transferred. The data in the buffer is a
154 * series of packed dirent structures where each one contains the
157 * u_int32_t d_fileno; // file number of entry
158 * u_int16_t d_reclen; // length of this record
159 * u_int8_t d_type; // file type
160 * u_int8_t d_namlen; // length of string in d_name
161 * char d_name[MAXNAMELEN+1]; // null terminated file name
163 * The current position (uio_offset) refers to the next block of
164 * entries. The offset can only be set to a value previously
165 * returned by hfs_vnop_readdir or zero. This offset does not have
166 * to match the number of bytes returned (in uio_resid).
168 * In fact, the offset used by HFS is essentially an index (26 bits)
169 * with a tag (6 bits). The tag is for associating the next request
170 * with the current request. This enables us to have multiple threads
171 * reading the directory while the directory is also being modified.
173 * Each tag/index pair is tied to a unique directory hint. The hint
174 * contains information (filename) needed to build the catalog b-tree
175 * key for finding the next set of entries.
177 * If the directory is marked as deleted-but-in-use (cp->c_flag & C_DELETED),
178 * do NOT synthesize entries for "." and "..".
181 hfs_vnop_readdir(vnode_t vp
, int *eofflag
, int *numdirent
, ReadDirBuff_s
* psReadDirBuffer
, uint64_t puCookie
, int flags
)
183 struct cnode
*cp
= NULL
;
184 struct hfsmount
*hfsmp
= VTOHFS(vp
);
185 directoryhint_t
*dirhint
= NULL
;
186 directoryhint_t localhint
;
187 bool bLocalEOFflag
= false;
190 user_size_t user_original_resid
= psReadDirBuffer
->uBufferResid
;
192 cnid_t cnid_hint
= 0;
193 int bump_valence
= 0;
195 uint64_t startoffset
= offset
= puCookie
;
196 bool extended
= (flags
& VNODE_READDIR_EXTENDED
);
197 bool nfs_cookies
= extended
&& (flags
& VNODE_READDIR_REQSEEKOFF
);
199 if (psReadDirBuffer
->pvBuffer
== NULL
|| psReadDirBuffer
->uBufferResid
< sizeof(UVFSDirEntry
))
201 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: readDir input is not valid\n");
205 /* Note that the dirhint calls require an exclusive lock. */
206 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
208 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: Failed to lock vnode\n");
213 /* Pick up cnid hint (if any). */
216 cnid_hint
= (cnid_t
)(offset
>> 32);
217 offset
&= 0x00000000ffffffffLL
;
218 if (cnid_hint
== INT_MAX
)
219 { /* searching pass the last item */
220 bLocalEOFflag
= true;
226 * Synthesize entries for "." and "..", unless the directory has
227 * been deleted, but not closed yet (lazy delete in progress).
229 UVFSDirEntry
* psDotDotEntry
= NULL
;
230 if (!(cp
->c_flag
& C_DELETED
))
232 if ( (error
= SyntisizeEntries(&offset
, psReadDirBuffer
, extended
, cp
->c_cnid
, cp
->c_parentcnid
, &psDotDotEntry
)) != 0 )
234 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: Failed to syntisize dot/dotdot entries\n");
239 /* Convert offset into a catalog directory index. */
240 int index
= (offset
& HFS_INDEX_MASK
) - 2;
241 unsigned int tag
= (unsigned int) (offset
& ~HFS_INDEX_MASK
);
243 /* Lock catalog during cat_findname and cat_getdirentries. */
244 int lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
246 /* When called from NFS, try and resolve a cnid hint. */
247 if (nfs_cookies
&& cnid_hint
!= 0)
249 if (cat_findname(hfsmp
, cnid_hint
, &localhint
.dh_desc
) == 0)
251 if ( localhint
.dh_desc
.cd_parentcnid
== cp
->c_fileid
)
253 localhint
.dh_index
= index
- 1;
254 localhint
.dh_time
= 0;
255 bzero(&localhint
.dh_link
, sizeof(localhint
.dh_link
));
256 dirhint
= &localhint
; /* don't forget to release the descriptor */
260 cat_releasedesc(&localhint
.dh_desc
);
265 /* Get a directory hint (cnode must be locked exclusive) */
268 dirhint
= hfs_getdirhint(cp
, ((index
- 1) & HFS_INDEX_MASK
) | tag
, 0);
270 /* Hide tag from catalog layer. */
271 dirhint
->dh_index
&= HFS_INDEX_MASK
;
272 if (dirhint
->dh_index
== HFS_INDEX_MASK
)
274 dirhint
->dh_index
= -1;
280 dirhint
->dh_threadhint
= cp
->c_dirthreadhint
;
285 * If we have a non-zero index, there is a possibility that during the last
286 * call to hfs_vnop_readdir we hit EOF for this directory. If that is the case
287 * then we don't want to return any new entries for the caller. Just return 0
288 * items, mark the eofflag, and bail out. Because we won't have done any work, the
289 * code at the end of the function will release the dirhint for us.
291 * Don't forget to unlock the catalog lock on the way out, too.
293 if (dirhint
->dh_desc
.cd_flags
& CD_EOF
)
296 bLocalEOFflag
= true;
297 offset
= startoffset
;
298 if (user_original_resid
> 0) {
299 psReadDirBuffer
->uBufferResid
= user_original_resid
;
301 hfs_systemfile_unlock (hfsmp
, lockflags
);
307 /* Pack the buffer with dirent entries. */
308 error
= cat_getdirentries(hfsmp
, cp
->c_entries
, dirhint
, psReadDirBuffer
, flags
, &items
, &bLocalEOFflag
, psDotDotEntry
);
310 if (index
== 0 && error
== 0)
312 cp
->c_dirthreadhint
= dirhint
->dh_threadhint
;
315 hfs_systemfile_unlock(hfsmp
, lockflags
);
319 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: Failed to get dir entries\n");
323 /* Get index to the next item */
326 if (items
>= (int)cp
->c_entries
)
328 bLocalEOFflag
= true;
332 * Detect valence FS corruption.
334 * We are holding the cnode lock exclusive, so there should not be
335 * anybody modifying the valence field of this cnode. If we enter
336 * this block, that means we observed filesystem corruption, because
337 * this directory reported a valence of 0, yet we found at least one
338 * item. In this case, we need to minimally self-heal this
339 * directory to prevent userland from tripping over a directory
340 * that appears empty (getattr of valence reports 0), but actually
343 * We'll force the cnode update at the end of the function after
344 * completing all of the normal getdirentries steps.
346 if ((cp
->c_entries
== 0) && (items
> 0))
348 /* disk corruption */
350 /* Mark the cnode as dirty. */
351 cp
->c_flag
|= C_MODIFIED
;
352 LFHFS_LOG(LEVEL_DEBUG
, "hfs_vnop_readdir: repairing valence to non-zero! \n");
357 /* Convert catalog directory index back into an offset. */
359 tag
= (++cp
->c_dirhinttag
) << HFS_INDEX_BITS
;
360 offset
= ((index
+ 2) | tag
);
361 dirhint
->dh_index
|= tag
;
364 cp
->c_touch_acctime
= TRUE
;
368 if (startoffset
== 0)
370 else if (startoffset
== 1)
377 /* If we didn't do anything then go ahead and dump the hint. */
378 if ((dirhint
!= NULL
) && (dirhint
!= &localhint
) && (offset
== startoffset
))
380 hfs_reldirhint(cp
, dirhint
);
381 bLocalEOFflag
= true;
386 *eofflag
= bLocalEOFflag
;
389 if (dirhint
== &localhint
)
391 cat_releasedesc(&localhint
.dh_desc
);
396 /* force the update before dropping the cnode lock*/
406 * readdirattr operation will return attributes for the items in the
407 * directory specified.
409 * It does not do . and .. entries. The problem is if you are at the root of the
410 * hfs directory and go to .. you could be crossing a mountpoint into a
411 * different (ufs) file system. The attributes that apply for it may not
412 * apply for the file system you are doing the readdirattr on. To make life
413 * simpler, this call will only return entries in its directory, hfs like.
416 hfs_vnop_readdirattr(vnode_t vp
, int *eofflag
, int *numdirent
, ReadDirBuff_s
* psReadDirBuffer
, uint64_t puCookie
)
420 uint32_t uMaxCount
= (uint32_t) psReadDirBuffer
->uBufferResid
/ _UVFS_DIRENTRYATTR_RECLEN(UVFS_DIRENTRYATTR_NAMEOFF
,0);
422 if (psReadDirBuffer
->pvBuffer
== NULL
|| psReadDirBuffer
->uBufferResid
< sizeof(UVFSDirEntry
))
424 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdirattr: buffer input is invalid\n");
428 error
= hfs_readdirattr_internal(vp
, psReadDirBuffer
, uMaxCount
, &newstate
, eofflag
, numdirent
, puCookie
);
434 * Sync all hfs B-trees. Use this instead of journal_flush for a volume
435 * without a journal. Note that the volume bitmap does not get written;
436 * we rely on fsck_hfs to fix that up (which it can do without any loss
440 hfs_metasync_all(struct hfsmount
*hfsmp
)
444 /* Lock all of the B-trees so we get a mutually consistent state */
445 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
|SFL_EXTENTS
|SFL_ATTRIBUTE
, HFS_EXCLUSIVE_LOCK
);
447 #if LF_HFS_FULL_VNODE_SUPPORT
448 //Curently we don't keep any cache for btree buffers.
449 //When we will have a cache we will have to flush it out here.
450 /* Sync each of the B-trees */
451 if (hfsmp
->hfs_catalog_vp
)
452 hfs_btsync(hfsmp
->hfs_catalog_vp
, 0);
453 if (hfsmp
->hfs_extents_vp
)
454 hfs_btsync(hfsmp
->hfs_extents_vp
, 0);
455 if (hfsmp
->hfs_attribute_vp
)
456 hfs_btsync(hfsmp
->hfs_attribute_vp
, 0);
458 hfs_systemfile_unlock(hfsmp
, lockflags
);
463 * cnode must be locked
466 hfs_fsync(struct vnode
*vp
, int waitfor
, hfs_fsync_mode_t fsyncmode
)
468 struct cnode
*cp
= VTOC(vp
);
469 struct filefork
*fp
= NULL
;
472 int took_trunc_lock
= 0;
473 int fsync_default
= 1;
476 * Applications which only care about data integrity rather than full
477 * file integrity may opt out of (delay) expensive metadata update
478 * operations as a performance optimization.
480 int wait
= (waitfor
== MNT_WAIT
); /* attributes necessary for data retrieval */
481 if (fsyncmode
!= HFS_FSYNC
)
484 /* HFS directories don't have any data blocks. */
490 * For system files flush the B-tree header and
491 * for regular files write out any clusters
493 if (vnode_issystem(vp
))
495 if (VTOF(vp
)->fcbBTCBPtr
!= NULL
)
498 if (VTOHFS(vp
)->jnl
== NULL
)
500 BTFlushPath(VTOF(vp
));
506 //TBD- Since we always flush the data for every file when it is being updated
507 // we don't need to do that here.
509 // hfs_lock_truncate(cp, HFS_SHARED_LOCK, HFS_LOCK_DEFAULT);
510 // took_trunc_lock = 1;
512 // if (fp->ff_unallocblocks != 0)
514 // hfs_unlock_truncate(cp, HFS_LOCK_DEFAULT);
516 // hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
519 //#if LF_HFS_FULL_VNODE_SUPPORT
520 // /* Don't hold cnode lock when calling into cluster layer. */
521 // (void) cluster_push(vp, waitdata ? IO_SYNC : 0);
524 // hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_ALLOW_NOEXISTS);
528 * When MNT_WAIT is requested and the zero fill timeout
529 * has expired then we must explicitly zero out any areas
530 * that are currently marked invalid (holes).
532 * Files with NODUMP can bypass zero filling here.
534 if (fp
&& (((cp
->c_flag
& C_ALWAYS_ZEROFILL
) && !TAILQ_EMPTY(&fp
->ff_invalidranges
)) ||
535 ((wait
|| (cp
->c_flag
& C_ZFWANTSYNC
)) &&
536 ((cp
->c_bsdflags
& UF_NODUMP
) == 0) &&
537 (vnode_issystem(vp
) ==0) &&
538 cp
->c_zftimeout
!= 0)))
541 if ((cp
->c_flag
& C_ALWAYS_ZEROFILL
) == 0 && fsync_default
&& tv
.tv_sec
< (long)cp
->c_zftimeout
)
543 /* Remember that a force sync was requested. */
544 cp
->c_flag
|= C_ZFWANTSYNC
;
547 if (!TAILQ_EMPTY(&fp
->ff_invalidranges
))
549 if (!took_trunc_lock
|| (cp
->c_truncatelockowner
== HFS_SHARED_OWNER
))
552 if (took_trunc_lock
) {
553 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
555 hfs_lock_truncate(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
556 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_ALLOW_NOEXISTS
);
560 #if LF_HFS_FULL_VNODE_SUPPORT
561 hfs_flush_invalid_ranges(vp
);
563 (void) cluster_push(vp
, waitdata
? IO_SYNC
: 0);
564 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_ALLOW_NOEXISTS
);
571 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
573 // TBD - symlink can't be dirsty since we always write the data fully to the device
574 // else if (fsync_default && vnode_islnk(vp) && vnode_hasdirtyblks(vp) && vnode_isrecycled(vp))
577 // * If it's a symlink that's dirty and is about to be recycled,
578 // * we need to flush the journal.
580 // fsync_default = 0;
584 if (vnode_isreg(vp
) && vnode_issystem(vp
))
586 if (VTOF(vp
)->fcbBTCBPtr
!= NULL
)
589 BTSetLastSync(VTOF(vp
), (u_int32_t
) tv
.tv_sec
);
591 cp
->c_touch_acctime
= FALSE
;
592 cp
->c_touch_chgtime
= FALSE
;
593 cp
->c_touch_modtime
= FALSE
;
597 retval
= hfs_update(vp
, HFS_UPDATE_FORCE
);
599 * When MNT_WAIT is requested push out the catalog record for
600 * this file. If they asked for a full fsync, we can skip this
601 * because the journal_flush or hfs_metasync_all will push out
602 * all of the metadata changes.
606 * As we are not supporting any write buf caches / delay writes,
607 * this is not needed.
609 if ((retval
== 0) && wait
&& fsync_default
&& cp
->c_hint
&&
610 !ISSET(cp
->c_flag
, C_DELETED
| C_NOEXISTS
)) {
611 hfs_metasync(VTOHFS(vp
), (daddr64_t
)cp
->c_hint
);
615 * If this was a full fsync, make sure all metadata
616 * changes get to stable storage.
620 if (VTOHFS(vp
)->jnl
) {
621 if (fsyncmode
== HFS_FSYNC_FULL
)
622 hfs_flush(VTOHFS(vp
), HFS_FLUSH_FULL
);
624 hfs_flush(VTOHFS(vp
), HFS_FLUSH_JOURNAL_BARRIER
);
628 retval
= hfs_metasync_all(VTOHFS(vp
));
629 hfs_flush(VTOHFS(vp
), HFS_FLUSH_CACHE
);
634 #if LF_HFS_FULL_VNODE_SUPPORT
635 if (!hfs_is_dirty(cp
) && !ISSET(cp
->c_flag
, C_DELETED
))
636 vnode_cleardirty(vp
);
645 * Similar to hfs_vnop_remove except there are additional options.
646 * This function may be used to remove directories if they have
647 * lots of EA's -- note the 'allow_dirs' argument.
649 * This function is able to delete blocks & fork data for the resource
650 * fork even if it does not exist in core (and have a backing vnode).
651 * It should infer the correct behavior based on the number of blocks
652 * in the cnode and whether or not the resource fork pointer exists or
653 * not. As a result, one only need pass in the 'vp' corresponding to the
654 * data fork of this file (or main vnode in the case of a directory).
655 * Passing in a resource fork will result in an error.
657 * Because we do not create any vnodes in this function, we are not at
658 * risk of deadlocking against ourselves by double-locking.
660 * Requires cnode and truncate locks to be held.
663 hfs_removefile(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
,
664 int flags
, int skip_reserve
, int allow_dirs
, int only_unlink
)
668 struct vnode
*rsrc_vp
= NULL
;
669 struct hfsmount
*hfsmp
;
670 struct cat_desc desc
;
671 int dataforkbusy
= 0;
672 int rsrcforkbusy
= 0;
676 int isbigfile
= 0, defer_remove
=0;
684 /* Check if we lost a race post lookup. */
685 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
689 if (!hfs_valid_cnode(hfsmp
, dvp
, cnp
, cp
->c_fileid
, NULL
, &error
))
694 /* Make sure a remove is permitted */
695 /* Don't allow deleting the journal or journal_info_block. */
696 if (VNODE_IS_RSRC(vp
) || vnode_issystem(vp
) || IsEntryAJnlFile(hfsmp
, cp
->c_fileid
))
698 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: Removing %s file is not premited\n", VNODE_IS_RSRC(vp
) ? "Resource" : (vnode_issystem(vp
)? "System" : "Journal"));
704 * We know it's a data fork.
705 * Probe the cnode to see if we have a valid resource fork
708 rsrc_vp
= cp
->c_rsrc_vp
;
712 * Hard links require special handling.
714 if (cp
->c_flag
& C_HARDLINK
)
716 /* A directory hard link with a link count of one is
717 * treated as a regular directory. Therefore it should
718 * only be removed using rmdir().
720 if (IS_DIR(vp
) && (cp
->c_linkcount
== 1) && (allow_dirs
== 0))
722 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: Trying to remove an hardlink directory\n");
726 return hfs_unlink(hfsmp
, dvp
, vp
, cnp
, skip_reserve
);
729 /* Directories should call hfs_rmdir! (unless they have a lot of attributes) */
734 return (EPERM
); /* POSIX */
739 /* Sanity check the parent ids. */
740 if ((cp
->c_parentcnid
!= hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
741 (cp
->c_parentcnid
!= dcp
->c_fileid
))
743 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: Parent ID's are wrong\n");
747 dcp
->c_flag
|= C_DIR_MODIFICATION
;
749 // this guy is going away so mark him as such
750 cp
->c_flag
|= C_DELETED
;
753 * If the caller was operating on a file (as opposed to a
754 * directory with EAs), then we need to figure out
755 * whether or not it has a valid resource fork vnode.
757 * If there was a valid resource fork vnode, then we need
758 * to use hfs_truncate to eliminate its data. If there is
759 * no vnode, then we hold the cnode lock which would
760 * prevent it from being created. As a result,
761 * we can use the data deletion functions which do not
762 * require that a cnode/vnode pair exist.
765 /* Check if this file is being used. */
768 dataforkbusy
= 0; /*vnode_isinuse(vp, 0);*/
770 * At this point, we know that 'vp' points to the
771 * a data fork because we checked it up front. And if
772 * there is no rsrc fork, rsrc_vp will be NULL.
774 if (rsrc_vp
&& (cp
->c_blocks
- VTOF(vp
)->ff_blocks
))
776 rsrcforkbusy
= 0; /*vnode_isinuse(rsrc_vp, 0);*/
779 /* Check if we have to break the deletion into multiple pieces. */
780 isbigfile
= cp
->c_datafork
->ff_size
>= HFS_BIGFILE_SIZE
;
783 /* Check if the file has xattrs. If it does we'll have to delete them in
784 individual transactions in case there are too many */
785 if ((hfsmp
->hfs_attribute_vp
!= NULL
) && (cp
->c_attr
.ca_recflags
& kHFSHasAttributesMask
) != 0)
790 /* If we are explicitly told to only unlink item and move to hidden dir, then do it */
797 * Carbon semantics prohibit deleting busy files.
798 * (enforced when VNODE_REMOVE_NODELETEBUSY is requested)
800 if (dataforkbusy
|| rsrcforkbusy
)
802 if ((flags
& VNODE_REMOVE_NODELETEBUSY
) || (hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
== 0))
810 * Do a ubc_setsize to indicate we need to wipe contents if:
811 * 1) item is a regular file.
812 * 2) Neither fork is busy AND we are not told to unlink this.
814 * We need to check for the defer_remove since it can be set without
815 * having a busy data or rsrc fork
817 if (isdir
== 0 && (!dataforkbusy
|| !rsrcforkbusy
) && (defer_remove
== 0))
820 * A ubc_setsize can cause a pagein so defer it
821 * until after the cnode lock is dropped. The
822 * cnode lock cannot be dropped/reacquired here
823 * since we might already hold the journal lock.
825 if (!dataforkbusy
&& cp
->c_datafork
->ff_blocks
&& !isbigfile
)
827 cp
->c_flag
|= C_NEED_DATA_SETSIZE
;
829 if (!rsrcforkbusy
&& rsrc_vp
)
831 cp
->c_flag
|= C_NEED_RSRC_SETSIZE
;
835 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
842 * Prepare to truncate any non-busy forks. Busy forks will
843 * get truncated when their vnode goes inactive.
844 * Note that we will only enter this region if we
845 * can avoid creating an open-unlinked file. If
846 * either region is busy, we will have to create an open
849 * Since we are deleting the file, we need to stagger the runtime
850 * modifications to do things in such a way that a crash won't
851 * result in us getting overlapped extents or any other
852 * bad inconsistencies. As such, we call prepare_release_storage
853 * which updates the UBC, updates quota information, and releases
854 * any loaned blocks that belong to this file. No actual
855 * truncation or bitmap manipulation is done until *AFTER*
856 * the catalog record is removed.
858 if (isdir
== 0 && (!dataforkbusy
&& !rsrcforkbusy
) && (only_unlink
== 0))
860 if (!dataforkbusy
&& !isbigfile
&& cp
->c_datafork
->ff_blocks
!= 0)
862 error
= hfs_prepare_release_storage (hfsmp
, vp
);
871 * If the resource fork vnode does not exist, we can skip this step.
873 if (!rsrcforkbusy
&& rsrc_vp
)
875 error
= hfs_prepare_release_storage (hfsmp
, rsrc_vp
);
885 * Protect against a race with rename by using the component
886 * name passed in and parent id from dvp (instead of using
887 * the cp->c_desc which may have changed). Also, be aware that
888 * because we allow directories to be passed in, we need to special case
889 * this temporary descriptor in case we were handed a directory.
893 desc
.cd_flags
= CD_ISDIR
;
899 desc
.cd_encoding
= cp
->c_desc
.cd_encoding
;
900 desc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
901 desc
.cd_namelen
= cnp
->cn_namelen
;
902 desc
.cd_parentcnid
= dcp
->c_fileid
;
903 desc
.cd_hint
= cp
->c_desc
.cd_hint
;
904 desc
.cd_cnid
= cp
->c_cnid
;
909 * There are two cases to consider:
910 * 1. File/Dir is busy/big/defer_remove ==> move/rename the file/dir
911 * 2. File is not in use ==> remove the file
913 * We can get a directory in case 1 because it may have had lots of attributes,
914 * which need to get removed here.
916 if (dataforkbusy
|| rsrcforkbusy
|| isbigfile
|| defer_remove
)
919 struct cat_desc to_desc
;
920 struct cat_desc todir_desc
;
923 * Orphan this file or directory (move to hidden directory).
924 * Again, we need to take care that we treat directories as directories,
925 * and files as files. Because directories with attributes can be passed in
926 * check to make sure that we have a directory or a file before filling in the
927 * temporary descriptor's flags. We keep orphaned directories AND files in
928 * the FILE_HARDLINKS private directory since we're generalizing over all
929 * orphaned filesystem objects.
931 bzero(&todir_desc
, sizeof(todir_desc
));
932 todir_desc
.cd_parentcnid
= 2;
934 MAKE_DELETED_NAME(delname
, sizeof(delname
), cp
->c_fileid
);
935 bzero(&to_desc
, sizeof(to_desc
));
936 to_desc
.cd_nameptr
= (const u_int8_t
*)delname
;
937 to_desc
.cd_namelen
= strlen(delname
);
938 to_desc
.cd_parentcnid
= hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
;
941 to_desc
.cd_flags
= CD_ISDIR
;
945 to_desc
.cd_flags
= 0;
947 to_desc
.cd_cnid
= cp
->c_cnid
;
949 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
952 if ((error
= cat_preflight(hfsmp
, CAT_RENAME
, NULL
)))
954 hfs_systemfile_unlock(hfsmp
, lockflags
);
959 error
= cat_rename(hfsmp
, &desc
, &todir_desc
, &to_desc
, (struct cat_desc
*)NULL
);
963 hfsmp
->hfs_private_attr
[FILE_HARDLINKS
].ca_entries
++;
966 INC_FOLDERCOUNT(hfsmp
, hfsmp
->hfs_private_attr
[FILE_HARDLINKS
]);
968 (void) cat_update(hfsmp
, &hfsmp
->hfs_private_desc
[FILE_HARDLINKS
], &hfsmp
->hfs_private_attr
[FILE_HARDLINKS
], NULL
, NULL
);
970 /* Update the parent directory */
971 if (dcp
->c_entries
> 0)
975 DEC_FOLDERCOUNT(hfsmp
, dcp
->c_attr
);
977 dcp
->c_dirchangecnt
++;
978 hfs_incr_gencount(dcp
);
980 dcp
->c_ctime
= tv
.tv_sec
;
981 dcp
->c_mtime
= tv
.tv_sec
;
982 (void) cat_update(hfsmp
, &dcp
->c_desc
, &dcp
->c_attr
, NULL
, NULL
);
984 /* Update the file or directory's state */
985 cp
->c_flag
|= C_DELETED
;
986 cp
->c_ctime
= tv
.tv_sec
;
988 (void) cat_update(hfsmp
, &to_desc
, &cp
->c_attr
, NULL
, NULL
);
991 hfs_systemfile_unlock(hfsmp
, lockflags
);
998 * Nobody is using this item; we can safely remove everything.
1001 struct filefork
*temp_rsrc_fork
= NULL
;
1002 u_int32_t fileid
= cp
->c_fileid
;
1005 * Figure out if we need to read the resource fork data into
1006 * core before wiping out the catalog record.
1008 * 1) Must not be a directory
1009 * 2) cnode's c_rsrcfork ptr must be NULL.
1010 * 3) rsrc fork must have actual blocks
1012 if ((isdir
== 0) && (cp
->c_rsrcfork
== NULL
) && (cp
->c_blocks
- VTOF(vp
)->ff_blocks
))
1015 * The resource fork vnode & filefork did not exist.
1016 * Create a temporary one for use in this function only.
1018 temp_rsrc_fork
= hfs_mallocz(sizeof(struct filefork
));
1019 temp_rsrc_fork
->ff_cp
= cp
;
1020 rl_init(&temp_rsrc_fork
->ff_invalidranges
);
1023 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
| SFL_ATTRIBUTE
| SFL_BITMAP
, HFS_EXCLUSIVE_LOCK
);
1025 /* Look up the resource fork first, if necessary */
1028 error
= cat_lookup (hfsmp
, &desc
, 1, (struct cat_desc
*) NULL
, (struct cat_attr
*) NULL
, &temp_rsrc_fork
->ff_data
, NULL
);
1031 hfs_free(temp_rsrc_fork
);
1032 hfs_systemfile_unlock (hfsmp
, lockflags
);
1039 if ((error
= cat_preflight(hfsmp
, CAT_DELETE
, NULL
)))
1043 hfs_free(temp_rsrc_fork
);
1045 hfs_systemfile_unlock(hfsmp
, lockflags
);
1050 error
= cat_delete(hfsmp
, &desc
, &cp
->c_attr
);
1052 if (error
&& error
!= ENXIO
&& error
!= ENOENT
)
1054 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: deleting file %s (id=%d) vol=%s err=%d\n",
1055 cp
->c_desc
.cd_nameptr
, cp
->c_attr
.ca_fileid
, hfsmp
->vcbVN
, error
);
1060 /* Update the parent directory */
1061 if (dcp
->c_entries
> 0)
1065 dcp
->c_dirchangecnt
++;
1066 hfs_incr_gencount(dcp
);
1068 dcp
->c_ctime
= tv
.tv_sec
;
1069 dcp
->c_mtime
= tv
.tv_sec
;
1070 (void) cat_update(hfsmp
, &dcp
->c_desc
, &dcp
->c_attr
, NULL
, NULL
);
1073 hfs_systemfile_unlock(hfsmp
, lockflags
);
1079 hfs_free(temp_rsrc_fork
);
1085 * Now that we've wiped out the catalog record, the file effectively doesn't
1086 * exist anymore. So update the quota records to reflect the loss of the
1087 * data fork and the resource fork.
1090 if (IS_LNK(vp
) && cp
->c_datafork
->ff_symlinkptr
)
1092 hfs_free(cp
->c_datafork
->ff_symlinkptr
);
1093 cp
->c_datafork
->ff_symlinkptr
= NULL
;
1097 * If we didn't get any errors deleting the catalog entry, then go ahead
1098 * and release the backing store now. The filefork pointers are still valid.
1102 error
= hfs_release_storage (hfsmp
, cp
->c_datafork
, temp_rsrc_fork
, fileid
);
1106 /* if cp->c_rsrcfork == NULL, hfs_release_storage will skip over it. */
1107 error
= hfs_release_storage (hfsmp
, cp
->c_datafork
, cp
->c_rsrcfork
, fileid
);
1112 * If we encountered an error updating the extents and bitmap,
1113 * mark the volume inconsistent. At this point, the catalog record has
1114 * already been deleted, so we can't recover it at this point. We need
1115 * to proceed and update the volume header and mark the cnode C_NOEXISTS.
1116 * The subsequent fsck should be able to recover the free space for us.
1118 hfs_mark_inconsistent(hfsmp
, HFS_OP_INCOMPLETE
);
1122 /* reset update_vh to 0, since hfs_release_storage should have done it for us */
1126 /* Get rid of the temporary rsrc fork */
1129 hfs_free(temp_rsrc_fork
);
1132 cp
->c_flag
|= C_NOEXISTS
;
1133 cp
->c_flag
&= ~C_DELETED
;
1135 cp
->c_touch_chgtime
= TRUE
;
1139 * We must never get a directory if we're in this else block. We could
1140 * accidentally drop the number of files in the volume header if we did.
1142 hfs_volupdate(hfsmp
, VOL_RMFILE
, (dcp
->c_cnid
== kHFSRootFolderID
));
1146 * All done with this cnode's descriptor...
1148 * Note: all future catalog calls for this cnode must be by
1149 * fileid only. This is OK for HFS (which doesn't have file
1150 * thread records) since HFS doesn't support the removal of
1153 cat_releasedesc(&cp
->c_desc
);
1158 cp
->c_flag
&= ~C_DELETED
;
1164 * If we bailed out earlier, we may need to update the volume header
1165 * to deal with the borrowed blocks accounting.
1167 hfs_volupdate (hfsmp
, VOL_UPDATE
, 0);
1172 hfs_end_transaction(hfsmp
);
1175 dcp
->c_flag
&= ~C_DIR_MODIFICATION
;
1176 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
1177 //wakeup((caddr_t)&dcp->c_flag);
1183 * Remove a file or link.
1186 hfs_vnop_remove(struct vnode
* psParentDir
,struct vnode
*psFileToRemove
, struct componentname
* psCN
, int iFlags
)
1188 struct cnode
*dcp
= VTOC(psParentDir
);
1189 struct cnode
*cp
= VTOC(psFileToRemove
);
1190 struct vnode
*rvp
= NULL
;
1193 if (psParentDir
== psFileToRemove
)
1200 hfs_lock_truncate(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
1202 if ((error
= hfs_lockpair(dcp
, cp
, HFS_EXCLUSIVE_LOCK
)))
1204 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
1207 hfs_chash_lower_OpenLookupCounter(cp
);
1214 * Lazily respond to determining if there is a valid resource fork
1215 * vnode attached to 'cp' if it is a regular file or symlink.
1216 * If the vnode does not exist, then we may proceed without having to
1219 * If, however, it does exist, then we need to acquire an iocount on the
1220 * vnode after acquiring its vid. This ensures that if we have to do I/O
1221 * against it, it can't get recycled from underneath us in the middle
1224 * Note: this function may be invoked for directory hardlinks, so just skip these
1225 * steps if 'vp' is a directory.
1227 enum vtype vtype
= psFileToRemove
->sFSParams
.vnfs_vtype
;
1228 if ((vtype
== VLNK
) || (vtype
== VREG
))
1230 if ((cp
->c_rsrc_vp
) && (rvp
== NULL
))
1232 /* We need to acquire the rsrc vnode */
1233 rvp
= cp
->c_rsrc_vp
;
1234 hfs_chash_raise_OpenLookupCounter(cp
);
1235 /* Unlock everything to acquire iocount on the rsrc vnode */
1236 hfs_unlock_truncate (cp
, HFS_LOCK_DEFAULT
);
1237 hfs_unlockpair (dcp
, cp
);
1244 * Check to see if we raced rmdir for the parent directory
1245 * hfs_removefile already checks for a race on vp/cp
1247 if (dcp
->c_flag
& (C_DELETED
| C_NOEXISTS
))
1253 error
= hfs_removefile(psParentDir
, psFileToRemove
, psCN
, iFlags
, 0, 0, 0);
1256 * Drop the truncate lock before unlocking the cnode
1257 * (which can potentially perform a vnode_put and
1258 * recycle the vnode which in turn might require the
1262 //Update Directory version
1263 psParentDir
->sExtraData
.sDirData
.uDirVersion
++;
1265 hfs_unlockpair(dcp
, cp
);
1266 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
1270 hfs_chash_lower_OpenLookupCounter(cp
);
1277 * Remove a directory.
1280 hfs_vnop_rmdir(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
* psCN
)
1283 struct cnode
*dcp
= VTOC(dvp
);
1284 struct cnode
*cp
= VTOC(vp
);
1286 if (!S_ISDIR(cp
->c_mode
))
1295 if ((error
= hfs_lockpair(dcp
, cp
, HFS_EXCLUSIVE_LOCK
)))
1300 /* Check for a race with rmdir on the parent directory */
1301 if (dcp
->c_flag
& (C_DELETED
| C_NOEXISTS
))
1303 hfs_unlockpair (dcp
, cp
);
1307 error
= hfs_removedir(dvp
, vp
, psCN
, 0, 0);
1309 hfs_unlockpair(dcp
, cp
);
1315 * Remove a directory
1317 * Both dvp and vp cnodes are locked
1320 hfs_removedir(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
, int skip_reserve
, int only_unlink
)
1324 struct hfsmount
* hfsmp
;
1325 struct cat_desc desc
;
1327 int error
= 0, started_tr
= 0;
1333 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)){
1337 if (cp
->c_entries
!= 0){
1341 /* Deal with directory hardlinks */
1342 if (cp
->c_flag
& C_HARDLINK
)
1345 * Note that if we have a directory which was a hardlink at any point,
1346 * its actual directory data is stored in the directory inode in the hidden
1347 * directory rather than the leaf element(s) present in the namespace.
1349 * If there are still other hardlinks to this directory,
1350 * then we'll just eliminate this particular link and the vnode will still exist.
1351 * If this is the last link to an empty directory, then we'll open-unlink the
1352 * directory and it will be only tagged with C_DELETED (as opposed to C_NOEXISTS).
1354 * We could also return EBUSY here.
1357 return hfs_unlink(hfsmp
, dvp
, vp
, cnp
, skip_reserve
);
1361 * In a few cases, we may want to allow the directory to persist in an
1362 * open-unlinked state. If the directory is being open-unlinked (still has usecount
1363 * references), or if it has EAs, or if it was being deleted as part of a rename,
1364 * then we go ahead and move it to the hidden directory.
1366 * If the directory is being open-unlinked, then we want to keep the catalog entry
1367 * alive so that future EA calls and fchmod/fstat etc. do not cause issues later.
1369 * If the directory had EAs, then we want to use the open-unlink trick so that the
1370 * EA removal is not done in one giant transaction. Otherwise, it could cause a panic
1371 * due to overflowing the journal.
1373 * Finally, if it was deleted as part of a rename, we move it to the hidden directory
1374 * in order to maintain rename atomicity.
1376 * Note that the allow_dirs argument to hfs_removefile specifies that it is
1377 * supposed to handle directories for this case.
1380 if (((hfsmp
->hfs_attribute_vp
!= NULL
) && ((cp
->c_attr
.ca_recflags
& kHFSHasAttributesMask
) != 0)) || (only_unlink
!= 0))
1383 int ret
= hfs_removefile(dvp
, vp
, cnp
, 0, 0, 1, only_unlink
);
1384 // Will be released in the layer above where it was created
1385 // vnode_recycle(vp);
1389 dcp
->c_flag
|= C_DIR_MODIFICATION
;
1391 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
1398 * Verify the directory is empty (and valid).
1399 * (Rmdir ".." won't be valid since
1400 * ".." will contain a reference to
1401 * the current directory and thus be
1404 if ((dcp
->c_bsdflags
& (UF_APPEND
| SF_APPEND
)) || (cp
->c_bsdflags
& ((UF_IMMUTABLE
| SF_IMMUTABLE
| UF_APPEND
| SF_APPEND
))))
1411 * Protect against a race with rename by using the component
1412 * name passed in and parent id from dvp (instead of using
1413 * the cp->c_desc which may have changed).
1415 desc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
1416 desc
.cd_namelen
= cnp
->cn_namelen
;
1417 desc
.cd_parentcnid
= dcp
->c_fileid
;
1418 desc
.cd_cnid
= cp
->c_cnid
;
1419 desc
.cd_flags
= CD_ISDIR
;
1420 desc
.cd_encoding
= cp
->c_encoding
;
1423 if (!hfs_valid_cnode(hfsmp
, dvp
, cnp
, cp
->c_fileid
, NULL
, &error
))
1429 /* Remove entry from catalog */
1430 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
| SFL_ATTRIBUTE
| SFL_BITMAP
, HFS_EXCLUSIVE_LOCK
);
1435 * Reserve some space in the Catalog file.
1437 if ((error
= cat_preflight(hfsmp
, CAT_DELETE
, NULL
)))
1439 hfs_systemfile_unlock(hfsmp
, lockflags
);
1444 error
= cat_delete(hfsmp
, &desc
, &cp
->c_attr
);
1448 /* The parent lost a child */
1449 if (dcp
->c_entries
> 0)
1451 DEC_FOLDERCOUNT(hfsmp
, dcp
->c_attr
);
1452 dcp
->c_dirchangecnt
++;
1453 hfs_incr_gencount(dcp
);
1455 dcp
->c_touch_chgtime
= TRUE
;
1456 dcp
->c_touch_modtime
= TRUE
;
1457 dcp
->c_flag
|= C_MODIFIED
;
1459 hfs_update(dcp
->c_vp
, 0);
1462 hfs_systemfile_unlock(hfsmp
, lockflags
);
1467 hfs_volupdate(hfsmp
, VOL_RMDIR
, (dcp
->c_cnid
== kHFSRootFolderID
));
1469 /* Mark C_NOEXISTS since the catalog entry is now gone */
1470 cp
->c_flag
|= C_NOEXISTS
;
1473 dvp
->sExtraData
.sDirData
.uDirVersion
++;
1475 dcp
->c_flag
&= ~C_DIR_MODIFICATION
;
1476 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
1477 // wakeup((caddr_t)&dcp->c_flag);
1481 hfs_end_transaction(hfsmp
);
1488 hfs_set_bsd_flags(struct cnode
*cp
, u_int32_t new_bsd_flags
)
1491 // Currently we don't support UF_TRACKED in detonator
1492 if (new_bsd_flags
& UF_TRACKED
)
1493 new_bsd_flags
&= ~UF_TRACKED
;
1495 cp
->c_bsdflags
= new_bsd_flags
;
1496 cp
->c_flag
|= C_MODIFIED
;
1497 cp
->c_touch_chgtime
= TRUE
;
1500 * Mirror the UF_HIDDEN flag to the invisible bit of the Finder Info.
1502 * The fdFlags for files and frFlags for folders are both 8 bytes
1503 * into the userInfo (the first 16 bytes of the Finder Info). They
1504 * are both 16-bit fields.
1506 fdFlags
= (u_int16_t
*) &cp
->c_finderinfo
[8];
1507 if (new_bsd_flags
& UF_HIDDEN
)
1508 *fdFlags
|= OSSwapHostToBigConstInt16(kFinderInvisibleMask
);
1510 *fdFlags
&= ~OSSwapHostToBigConstInt16(kFinderInvisibleMask
);
1515 int hfs_vnop_setattr( vnode_t vp
, const UVFSFileAttributes
*attr
)
1518 if ( attr
->fa_validmask
== 0 )
1523 if ( ( attr
->fa_validmask
& READ_ONLY_FA_FIELDS
)
1524 /*|| ( attr->fa_validmask & ~VALID_IN_ATTR_MASK )*/)
1529 struct cnode
*cp
= NULL
;
1531 /* Don't allow modification of the journal. */
1532 struct hfsmount
*hfsmp
= VTOHFS(vp
);
1533 if (hfs_is_journal_file(hfsmp
, VTOC(vp
))) {
1538 * File size change request.
1539 * We are guaranteed that this is not a directory, and that
1540 * the filesystem object is writeable.
1543 if ( attr
->fa_validmask
& UVFS_FA_VALID_SIZE
)
1545 if (!vnode_isreg(vp
))
1547 if (vnode_isdir(vp
) || vnode_islnk(vp
))
1551 //otherwise return EINVAL
1555 // Take truncate lock
1556 hfs_lock_truncate(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
1558 // hfs_truncate will deal with the cnode lock
1559 err
= hfs_truncate(vp
, attr
->fa_size
, 0, 0);
1561 hfs_unlock_truncate(VTOC(vp
), HFS_LOCK_DEFAULT
);
1567 if ((err
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
1572 if ( attr
->fa_validmask
& UVFS_FA_VALID_UID
)
1574 cp
->c_flag
|= C_MODIFIED
;
1575 cp
->c_touch_chgtime
= TRUE
;
1576 cp
->c_uid
= attr
->fa_uid
;
1579 if ( attr
->fa_validmask
& UVFS_FA_VALID_GID
)
1581 cp
->c_flag
|= C_MODIFIED
;
1582 cp
->c_touch_chgtime
= TRUE
;
1583 cp
->c_gid
= attr
->fa_gid
;
1586 if ( attr
->fa_validmask
& UVFS_FA_VALID_MODE
)
1588 mode_t new_mode
= (cp
->c_mode
& ~ALLPERMS
) | (attr
->fa_mode
& ALLPERMS
);
1589 if (new_mode
!= cp
->c_mode
) {
1590 cp
->c_mode
= new_mode
;
1591 cp
->c_flag
|= C_MINOR_MOD
;
1595 if ( attr
->fa_validmask
& UVFS_FA_VALID_BSD_FLAGS
)
1597 hfs_set_bsd_flags(cp
, attr
->fa_bsd_flags
);
1601 * Timestamp updates.
1603 if ( attr
->fa_validmask
& UVFS_FA_VALID_ATIME
)
1605 cp
->c_atime
= attr
->fa_atime
.tv_sec
;
1606 cp
->c_touch_acctime
= FALSE
;
1609 if ( attr
->fa_validmask
& UVFS_FA_VALID_BIRTHTIME
)
1611 cp
->c_ctime
= attr
->fa_birthtime
.tv_sec
;
1614 if ( attr
->fa_validmask
& UVFS_FA_VALID_MTIME
)
1616 cp
->c_mtime
= attr
->fa_mtime
.tv_sec
;
1617 cp
->c_touch_modtime
= FALSE
;
1618 cp
->c_touch_chgtime
= TRUE
;
1620 hfs_clear_might_be_dirty_flag(cp
);
1623 err
= hfs_update(vp
, 0);
1625 /* Purge origin cache for cnode, since caller now has correct link ID for it
1626 * We purge it here since it was acquired for us during lookup, and we no longer need it.
1628 if ((cp
->c_flag
& C_HARDLINK
) && (!IS_DIR(vp
))){
1629 hfs_relorigin(cp
, 0);
1638 * Update a cnode's on-disk metadata.
1640 * The cnode must be locked exclusive. See declaration for possible
1644 hfs_update(struct vnode
*vp
, int options
)
1646 #pragma unused (options)
1648 struct cnode
*cp
= VTOC(vp
);
1649 const struct cat_fork
*dataforkp
= NULL
;
1650 const struct cat_fork
*rsrcforkp
= NULL
;
1651 struct cat_fork datafork
;
1652 struct cat_fork rsrcfork
;
1653 struct hfsmount
*hfsmp
;
1657 if (ISSET(cp
->c_flag
, C_NOEXISTS
))
1662 if (((vnode_issystem(vp
) && (cp
->c_cnid
< kHFSFirstUserCatalogNodeID
))) ||
1663 hfsmp
->hfs_catalog_vp
== NULL
){
1667 if ((hfsmp
->hfs_flags
& HFS_READ_ONLY
) || (cp
->c_mode
== 0)) {
1668 CLR(cp
->c_flag
, C_MODIFIED
| C_MINOR_MOD
| C_NEEDS_DATEADDED
);
1669 cp
->c_touch_acctime
= 0;
1670 cp
->c_touch_chgtime
= 0;
1671 cp
->c_touch_modtime
= 0;
1675 hfs_touchtimes(hfsmp
, cp
);
1677 if (!ISSET(cp
->c_flag
, C_MODIFIED
| C_MINOR_MOD
)
1678 && !hfs_should_save_atime(cp
)) {
1679 // Nothing to update
1683 bool check_txn
= false;
1684 if (!ISSET(options
, HFS_UPDATE_FORCE
) && !ISSET(cp
->c_flag
, C_MODIFIED
)) {
1686 * This must be a minor modification. If the current
1687 * transaction already has an update for this node, then we
1688 * bundle in the modification.
1691 && journal_current_txn(hfsmp
->jnl
) == cp
->c_update_txn
) {
1701 error
= hfs_start_transaction(hfsmp
);
1708 && journal_current_txn(hfsmp
->jnl
) != cp
->c_update_txn
) {
1709 hfs_end_transaction(hfsmp
);
1715 * Modify the values passed to cat_update based on whether or not
1716 * the file has invalid ranges or borrowed blocks.
1718 dataforkp
= hfs_prepare_fork_for_update(cp
->c_datafork
, NULL
, &datafork
, hfsmp
->blockSize
);
1719 rsrcforkp
= hfs_prepare_fork_for_update(cp
->c_rsrcfork
, NULL
, &rsrcfork
, hfsmp
->blockSize
);
1722 * Lock the Catalog b-tree file.
1724 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
1726 error
= cat_update(hfsmp
, &cp
->c_desc
, &cp
->c_attr
, dataforkp
, rsrcforkp
);
1729 cp
->c_update_txn
= journal_current_txn(hfsmp
->jnl
);
1731 hfs_systemfile_unlock(hfsmp
, lockflags
);
1733 CLR(cp
->c_flag
, C_MODIFIED
| C_MINOR_MOD
);
1735 hfs_end_transaction(hfsmp
);
1743 * Prepares a fork for cat_update by making sure ff_size and ff_blocks
1744 * are no bigger than the valid data on disk thus reducing the chance
1745 * of exposing uninitialised data in the event of a non clean unmount.
1746 * fork_buf is where to put the temporary copy if required. (It can
1749 const struct cat_fork
*
1750 hfs_prepare_fork_for_update(filefork_t
*ff
, const struct cat_fork
*cf
, struct cat_fork
*cf_buf
, uint32_t block_size
)
1758 cf_buf
= &ff
->ff_data
;
1760 off_t max_size
= ff
->ff_size
;
1762 if (!ff
->ff_unallocblocks
&& ff
->ff_size
<= max_size
)
1763 return cf
; // Nothing to do
1765 if (ff
->ff_blocks
< ff
->ff_unallocblocks
) {
1766 LFHFS_LOG(LEVEL_ERROR
, "hfs_prepare_fork_for_update: ff_blocks %d is less than unalloc blocks %d\n",
1767 ff
->ff_blocks
, ff
->ff_unallocblocks
);
1771 struct cat_fork
*out
= cf_buf
;
1774 bcopy(cf
, out
, sizeof(*cf
));
1776 // Adjust cf_blocks for cf_vblocks
1777 out
->cf_blocks
-= out
->cf_vblocks
;
1780 * Here we trim the size with the updated cf_blocks. This is
1781 * probably unnecessary now because the invalid ranges should
1782 * catch this (but that wasn't always the case).
1784 off_t alloc_bytes
= blk_to_bytes(out
->cf_blocks
, block_size
);
1785 if (out
->cf_size
> alloc_bytes
)
1786 out
->cf_size
= alloc_bytes
;
1788 // Trim cf_size to first invalid range
1789 if (out
->cf_size
> max_size
)
1790 out
->cf_size
= max_size
;
1796 * Read contents of a symbolic link.
1799 hfs_vnop_readlink( struct vnode
*vp
, void* data
, size_t dataSize
, size_t *actuallyRead
)
1802 struct filefork
*fp
;
1805 if (!vnode_islnk(vp
))
1807 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readlink: Received node is not a symlink\n");
1811 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
1816 /* Zero length sym links are not allowed */
1817 if (fp
->ff_size
== 0 || fp
->ff_size
> MAXPATHLEN
) {
1818 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readlink: Symlink is with invalid content length\n");
1823 if ( dataSize
< (size_t)fp
->ff_size
+1 )
1825 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readlink: Received buffer size is too small\n");
1830 /* Cache the path so we don't waste buffer cache resources */
1831 if (fp
->ff_symlinkptr
== NULL
) {
1832 GenericLFBufPtr bp
= NULL
;
1834 fp
->ff_symlinkptr
= hfs_mallocz(fp
->ff_size
);
1835 if ( fp
->ff_symlinkptr
== NULL
)
1841 bp
= lf_hfs_generic_buf_allocate( vp
, 0, roundup((int)fp
->ff_size
, VTOHFS(vp
)->hfs_physical_block_size
), 0);
1842 error
= lf_hfs_generic_buf_read(bp
);
1844 lf_hfs_generic_buf_release(bp
);
1845 if (fp
->ff_symlinkptr
) {
1846 hfs_free(fp
->ff_symlinkptr
);
1847 fp
->ff_symlinkptr
= NULL
;
1851 bcopy(bp
->pvData
, fp
->ff_symlinkptr
, (size_t)fp
->ff_size
);
1852 lf_hfs_generic_buf_release(bp
);
1855 memcpy(data
, fp
->ff_symlinkptr
, fp
->ff_size
);
1856 ((uint8_t*)data
)[fp
->ff_size
] = 0;
1857 *actuallyRead
= fp
->ff_size
+1;
1868 hfs_vnop_mkdir(vnode_t a_dvp
, vnode_t
*a_vpp
, struct componentname
*a_cnp
, UVFSFileAttributes
* a_vap
)
1872 /***** HACK ALERT ********/
1873 a_cnp
->cn_flags
|= MAKEENTRY
;
1874 a_vap
->fa_type
= UVFS_FA_TYPE_DIR
;
1876 iErr
= hfs_makenode(a_dvp
, a_vpp
, a_cnp
, a_vap
);
1879 CRASH_ABORT(CRASH_ABORT_MAKE_DIR
, a_dvp
->mount
, NULL
);
1886 * Create a regular file.
1889 hfs_vnop_create(vnode_t a_dvp
, vnode_t
*a_vpp
, struct componentname
*a_cnp
, UVFSFileAttributes
* a_vap
)
1891 a_vap
->fa_type
= UVFS_FA_TYPE_FILE
;
1892 return hfs_makenode(a_dvp
, a_vpp
, a_cnp
, a_vap
);
1896 * Allocate a new node
1899 hfs_makenode(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
, UVFSFileAttributes
*psGivenAttr
)
1901 struct hfsmount
*hfsmp
= VTOHFS(dvp
);
1902 struct cnode
*dcp
= NULL
;
1903 struct cnode
*cp
= NULL
;
1904 struct vnode
*tvp
= NULL
;
1905 enum vtype vnodetype
= UVFSTOV(psGivenAttr
->fa_type
);
1906 mode_t mode
= MAKEIMODE(vnodetype
);
1907 struct cat_attr attr
= {0};
1909 int error
, started_tr
= 0;
1911 int newvnode_flags
= 0;
1912 u_int32_t gnv_flags
= 0;
1914 struct cat_desc out_desc
= {0};
1915 out_desc
.cd_flags
= 0;
1916 out_desc
.cd_nameptr
= NULL
;
1918 if ((error
= hfs_lock(VTOC(dvp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
1922 /* Don't allow creation of new entries in open-unlinked directories */
1923 if (dcp
->c_flag
& (C_DELETED
| C_NOEXISTS
))
1929 if ( !(psGivenAttr
->fa_validmask
& UVFS_FA_VALID_MODE
) && (vnodetype
!= VDIR
) )
1931 LFHFS_LOG(LEVEL_ERROR
, "hfs_makenode: Invalid mode or type[%#llx, %d]",
1932 (unsigned long long)psGivenAttr
->fa_validmask
, psGivenAttr
->fa_type
);
1937 if ( ( psGivenAttr
->fa_validmask
& READ_ONLY_FA_FIELDS
) /*|| ( psGivenAttr->fa_validmask & ~VALID_IN_ATTR_MASK )*/ )
1939 LFHFS_LOG(LEVEL_ERROR
, "hfs_makenode: Setting readonly fields or invalid mask[%#llx, %#llx]", (unsigned long long)psGivenAttr
->fa_validmask
, (unsigned long long)READ_ONLY_FA_FIELDS
);
1944 dcp
->c_flag
|= C_DIR_MODIFICATION
;
1948 /* Check if were out of usable disk space. */
1949 if (hfs_freeblks(hfsmp
, 1) == 0)
1958 /* Setup the default attributes */
1959 if ( psGivenAttr
->fa_validmask
& UVFS_FA_VALID_MODE
)
1961 mode
= (mode
& ~ALLPERMS
) | (psGivenAttr
->fa_mode
& ALLPERMS
);
1964 attr
.ca_mode
= mode
;
1965 attr
.ca_linkcount
= 1;
1966 attr
.ca_itime
= tv
.tv_sec
;
1967 attr
.ca_atime
= attr
.ca_ctime
= attr
.ca_mtime
= attr
.ca_itime
;
1968 attr
.ca_atimeondisk
= attr
.ca_atime
;
1971 * HFS+ only: all files get ThreadExists
1973 if (vnodetype
== VDIR
)
1975 if (hfsmp
->hfs_flags
& HFS_FOLDERCOUNT
)
1977 attr
.ca_recflags
= kHFSHasFolderCountMask
;
1982 attr
.ca_recflags
= kHFSThreadExistsMask
;
1986 * Add the date added to the item. See above, as
1987 * all of the dates are set to the itime.
1989 hfs_write_dateadded (&attr
, attr
.ca_atime
);
1991 /* Initialize the gen counter to 1 */
1992 hfs_write_gencount(&attr
, (uint32_t)1);
1994 if ( psGivenAttr
->fa_validmask
& UVFS_FA_VALID_UID
)
1996 attr
.ca_uid
= psGivenAttr
->fa_uid
;
1999 if ( psGivenAttr
->fa_validmask
& UVFS_FA_VALID_GID
)
2001 attr
.ca_gid
= psGivenAttr
->fa_gid
;
2004 /* Tag symlinks with a type and creator. */
2005 if (vnodetype
== VLNK
)
2007 struct FndrFileInfo
*fip
;
2009 fip
= (struct FndrFileInfo
*)&attr
.ca_finderinfo
;
2010 fip
->fdType
= SWAP_BE32(kSymLinkFileType
);
2011 fip
->fdCreator
= SWAP_BE32(kSymLinkCreator
);
2014 /* Setup the descriptor */
2015 struct cat_desc in_desc
={0};
2016 in_desc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
2017 in_desc
.cd_namelen
= cnp
->cn_namelen
;
2018 in_desc
.cd_parentcnid
= dcp
->c_fileid
;
2019 in_desc
.cd_flags
= S_ISDIR(mode
) ? CD_ISDIR
: 0;
2020 in_desc
.cd_hint
= dcp
->c_childhint
;
2021 in_desc
.cd_encoding
= 0;
2023 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
2029 // have to also lock the attribute file because cat_create() needs
2030 // to check that any fileID it wants to use does not have orphaned
2031 // attributes in it.
2032 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
| SFL_ATTRIBUTE
, HFS_EXCLUSIVE_LOCK
);
2035 /* Reserve some space in the Catalog file. */
2036 error
= cat_preflight(hfsmp
, CAT_CREATE
, NULL
);
2039 hfs_systemfile_unlock(hfsmp
, lockflags
);
2043 error
= cat_acquire_cnid(hfsmp
, &new_id
);
2046 hfs_systemfile_unlock (hfsmp
, lockflags
);
2050 error
= cat_create(hfsmp
, new_id
, &in_desc
, &attr
, &out_desc
);
2052 /* Update the parent directory */
2053 dcp
->c_childhint
= out_desc
.cd_hint
; /* Cache directory's location */
2056 if (vnodetype
== VDIR
)
2058 INC_FOLDERCOUNT(hfsmp
, dcp
->c_attr
);
2060 dcp
->c_dirchangecnt
++;
2061 hfs_incr_gencount(dcp
);
2063 dcp
->c_touch_chgtime
= dcp
->c_touch_modtime
= true;
2064 dcp
->c_flag
|= C_MODIFIED
;
2066 hfs_update(dcp
->c_vp
, 0);
2068 hfs_systemfile_unlock(hfsmp
, lockflags
);
2072 uint32_t txn
= hfsmp
->jnl
? journal_current_txn(hfsmp
->jnl
) : 0;
2074 hfs_volupdate(hfsmp
, vnodetype
== VDIR
? VOL_MKDIR
: VOL_MKFILE
, (dcp
->c_cnid
== kHFSRootFolderID
));
2077 // have to end the transaction here before we call hfs_getnewvnode()
2078 // because that can cause us to try and reclaim a vnode on a different
2079 // file system which could cause us to start a transaction which can
2080 // deadlock with someone on that other file system (since we could be
2081 // holding two transaction locks as well as various vnodes and we did
2082 // not obtain the locks on them in the proper order).
2084 // NOTE: this means that if the quota check fails or we have to update
2085 // the change time on a block-special device that those changes
2086 // will happen as part of independent transactions.
2090 hfs_end_transaction(hfsmp
);
2094 gnv_flags
|= GNV_CREATE
;
2097 gnv_flags
|= GNV_NOCACHE
;
2101 * Create a vnode for the object just created.
2103 * NOTE: Maintaining the cnode lock on the parent directory is important,
2104 * as it prevents race conditions where other threads want to look up entries
2105 * in the directory and/or add things as we are in the process of creating
2106 * the vnode below. However, this has the potential for causing a
2107 * double lock panic when dealing with shadow files on a HFS boot partition.
2108 * The panic could occur if we are not cleaning up after ourselves properly
2109 * when done with a shadow file or in the error cases. The error would occur if we
2110 * try to create a new vnode, and then end up reclaiming another shadow vnode to
2111 * create the new one. However, if everything is working properly, this should
2112 * be a non-issue as we would never enter that reclaim codepath.
2114 * The cnode is locked on successful return.
2116 error
= hfs_getnewvnode(hfsmp
, dvp
, cnp
, &out_desc
, gnv_flags
, &attr
,
2117 NULL
, &tvp
, &newvnode_flags
);
2123 cp
->c_update_txn
= txn
;
2128 cat_releasedesc(&out_desc
);
2130 //Update Directory version
2131 dvp
->sExtraData
.sDirData
.uDirVersion
++;
2134 * Make sure we release cnode lock on dcp.
2138 dcp
->c_flag
&= ~C_DIR_MODIFICATION
;
2140 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
2141 //wakeup((caddr_t)&dcp->c_flag);
2149 hfs_end_transaction(hfsmp
);
2156 * Create a symbolic link.
2159 hfs_vnop_symlink(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
, char* symlink_content
, UVFSFileAttributes
*attrp
)
2161 struct vnode
*vp
= NULL
;
2162 struct cnode
*cp
= NULL
;
2163 struct hfsmount
*hfsmp
;
2164 struct filefork
*fp
;
2165 GenericLFBufPtr bp
= NULL
;
2171 hfsmp
= VTOHFS(dvp
);
2173 len
= strlen(symlink_content
);
2174 if (len
> MAXPATHLEN
)
2176 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_symlink: Received symlink content too long\n");
2177 return (ENAMETOOLONG
);
2182 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_symlink: Received zero length symlink content\n");
2186 /* Check for free space */
2187 if (((u_int64_t
)hfs_freeblks(hfsmp
, 0) * (u_int64_t
)hfsmp
->blockSize
) < len
) {
2191 attrp
->fa_type
= UVFS_FA_TYPE_SYMLINK
;
2192 attrp
->fa_mode
|= S_IFLNK
;
2193 attrp
->fa_validmask
|= UVFS_FA_VALID_MODE
;
2195 /* Create the vnode */
2196 if ((error
= hfs_makenode(dvp
, vpp
, cnp
, attrp
))) {
2200 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
))) {
2206 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
2211 (void)hfs_getinoquota(cp
);
2214 if ((error
= hfs_start_transaction(hfsmp
)) != 0) {
2220 * Allocate space for the link.
2222 * Since we're already inside a transaction,
2224 * Don't need truncate lock since a symlink is treated as a system file.
2226 error
= hfs_truncate(vp
, len
, IO_NOZEROFILL
, 0);
2228 /* On errors, remove the symlink file */
2231 * End the transaction so we don't re-take the cnode lock
2232 * below while inside a transaction (lock order violation).
2234 hfs_end_transaction(hfsmp
);
2235 /* hfs_removefile() requires holding the truncate lock */
2237 hfs_lock_truncate(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
2238 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_ALLOW_NOEXISTS
);
2240 if (hfs_start_transaction(hfsmp
) != 0) {
2242 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
2246 (void) hfs_removefile(dvp
, vp
, cnp
, 0, 0, 0, 0);
2247 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
2251 /* Write the sym-link to disk */
2252 bp
= lf_hfs_generic_buf_allocate( vp
, 0, roundup((int)fp
->ff_size
, hfsmp
->hfs_physical_block_size
), 0);
2253 error
= lf_hfs_generic_buf_read( bp
);
2261 journal_modify_block_start(hfsmp
->jnl
, bp
);
2264 assert(bp
->uDataSize
>= len
);
2265 bzero(datap
, bp
->uDataSize
);
2266 bcopy(symlink_content
, datap
, len
);
2269 journal_modify_block_end(hfsmp
->jnl
, bp
, NULL
, NULL
);
2270 bp
= NULL
; // block will be released by the journal
2274 error
= lf_hfs_generic_buf_write(bp
);
2282 hfs_end_transaction(hfsmp
);
2284 if ((cp
!= NULL
) && (vp
!= NULL
)) {
2295 lf_hfs_generic_buf_release(bp
);
2298 hfs_flush(hfsmp
, HFS_FLUSH_FULL
);
2306 * The VFS layer guarantees that:
2307 * - source and destination will either both be directories, or
2308 * both not be directories.
2309 * - all the vnodes are from the same file system
2311 * When the target is a directory, HFS must ensure that its empty.
2313 * Note that this function requires up to 6 vnodes in order to work properly
2314 * if it is operating on files (and not on directories). This is because only
2315 * files can have resource forks, and we now require iocounts to be held on the
2316 * vnodes corresponding to the resource forks (if applicable) as well as
2317 * the files or directories undergoing rename. The problem with not holding
2318 * iocounts on the resource fork vnodes is that it can lead to a deadlock
2319 * situation: The rsrc fork of the source file may be recycled and reclaimed
2320 * in order to provide a vnode for the destination file's rsrc fork. Since
2321 * data and rsrc forks share the same cnode, we'd eventually try to lock the
2322 * source file's cnode in order to sync its rsrc fork to disk, but it's already
2323 * been locked. By taking the rsrc fork vnodes up front we ensure that they
2324 * cannot be recycled, and that the situation mentioned above cannot happen.
2327 hfs_vnop_renamex(struct vnode
*fdvp
,struct vnode
*fvp
, struct componentname
*fcnp
, struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
)
2331 * Note that we only need locals for the target/destination's
2332 * resource fork vnode (and only if necessary). We don't care if the
2333 * source has a resource fork vnode or not.
2335 struct vnode
*tvp_rsrc
= NULL
;
2336 struct cnode
*tcp
= NULL
;
2337 struct cnode
*error_cnode
;
2338 struct cat_desc from_desc
;
2340 struct hfsmount
*hfsmp
= VTOHFS(tdvp
);
2341 int tvp_deleted
= 0;
2342 int started_tr
= 0, got_cookie
= 0;
2343 int took_trunc_lock
= 0;
2347 int rename_exclusive
= 0;
2350 /* When tvp exists, take the truncate lock for hfs_removefile(). */
2351 if (tvp
&& (vnode_isreg(tvp
) || vnode_islnk(tvp
))) {
2352 hfs_lock_truncate(VTOC(tvp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
2353 took_trunc_lock
= 1;
2356 if (tvp
&& VTOC(tvp
) == NULL
)
2359 error
= hfs_lockfour(VTOC(fdvp
), VTOC(fvp
), VTOC(tdvp
), tvp
? VTOC(tvp
) : NULL
, HFS_EXCLUSIVE_LOCK
, &error_cnode
);
2362 if (took_trunc_lock
)
2364 hfs_unlock_truncate(VTOC(tvp
), HFS_LOCK_DEFAULT
);
2365 took_trunc_lock
= 0;
2369 * We hit an error path. If we were trying to re-acquire the locks
2370 * after coming through here once, we might have already obtained
2371 * an iocount on tvp's resource fork vnode. Drop that before dealing
2372 * with the failure. Note this is safe -- since we are in an
2373 * error handling path, we can't be holding the cnode locks.
2375 if (tvp_rsrc
&& tcp
)
2377 hfs_chash_lower_OpenLookupCounter(tcp
);
2382 * tvp might no longer exist. If the cause of the lock failure
2383 * was tvp, then we can try again with tvp/tcp set to NULL.
2384 * This is ok because the vfs syscall will vnode_put the vnodes
2385 * after we return from hfs_vnop_rename.
2387 if ((error
== ENOENT
) && (tvp
!= NULL
) && (error_cnode
== VTOC(tvp
))) {
2393 /* If we want to reintroduce notifications for failed renames, this
2394 is the place to do it. */
2399 struct cnode
* fdcp
= VTOC(fdvp
);
2400 struct cnode
* fcp
= VTOC(fvp
);
2401 struct cnode
* tdcp
= VTOC(tdvp
);
2402 tcp
= tvp
? VTOC(tvp
) : NULL
;
2405 * If caller requested an exclusive rename (VFS_RENAME_EXCL) and 'tcp' exists
2406 * then we must fail the operation.
2408 if (tcp
&& rename_exclusive
)
2415 * Acquire iocounts on the destination's resource fork vnode
2416 * if necessary. If dst/src are files and the dst has a resource
2417 * fork vnode, then we need to try and acquire an iocount on the rsrc vnode.
2418 * If it does not exist, then we don't care and can skip it.
2420 if ((vnode_isreg(fvp
)) || (vnode_islnk(fvp
)))
2422 if ((tvp
) && (tcp
->c_rsrc_vp
) && (tvp_rsrc
== NULL
))
2424 tvp_rsrc
= tcp
->c_rsrc_vp
;
2425 hfs_chash_raise_OpenLookupCounter(tcp
);
2427 /* Unlock everything to acquire iocount on this rsrc vnode */
2428 if (took_trunc_lock
)
2430 hfs_unlock_truncate (VTOC(tvp
), HFS_LOCK_DEFAULT
);
2431 took_trunc_lock
= 0;
2434 hfs_unlockfour(fdcp
, fcp
, tdcp
, tcp
);
2440 /* Ensure we didn't race src or dst parent directories with rmdir. */
2441 if (fdcp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
2447 if (tdcp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
2454 /* Check for a race against unlink. The hfs_valid_cnode checks validate
2455 * the parent/child relationship with fdcp and tdcp, as well as the
2456 * component name of the target cnodes.
2458 if ((fcp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) || !hfs_valid_cnode(hfsmp
, fdvp
, fcnp
, fcp
->c_fileid
, NULL
, &error
))
2464 if (tcp
&& ((tcp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) || !hfs_valid_cnode(hfsmp
, tdvp
, tcnp
, tcp
->c_fileid
, NULL
, &error
)))
2467 // hmm, the destination vnode isn't valid any more.
2468 // in this case we can just drop him and pretend he
2469 // never existed in the first place.
2471 if (took_trunc_lock
)
2473 hfs_unlock_truncate(VTOC(tvp
), HFS_LOCK_DEFAULT
);
2474 took_trunc_lock
= 0;
2478 hfs_unlockfour(fdcp
, fcp
, tdcp
, tcp
);
2483 // retry the locking with tvp null'ed out
2487 fdcp
->c_flag
|= C_DIR_MODIFICATION
;
2490 tdcp
->c_flag
|= C_DIR_MODIFICATION
;
2494 * Disallow renaming of a directory hard link if the source and
2495 * destination parent directories are different, or a directory whose
2496 * descendant is a directory hard link and the one of the ancestors
2497 * of the destination directory is a directory hard link.
2499 if (vnode_isdir(fvp
) && (fdvp
!= tdvp
))
2501 if (fcp
->c_flag
& C_HARDLINK
) {
2505 if (fcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
)
2507 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
2508 if (cat_check_link_ancestry(hfsmp
, tdcp
->c_fileid
, 0))
2511 hfs_systemfile_unlock(hfsmp
, lockflags
);
2514 hfs_systemfile_unlock(hfsmp
, lockflags
);
2519 * The following edge case is caught here:
2520 * (to cannot be a descendent of from)
2533 if (tdcp
->c_parentcnid
== fcp
->c_fileid
)
2540 * The following two edge cases are caught here:
2541 * (note tvp is not empty)
2554 if (tvp
&& vnode_isdir(tvp
) && (tcp
->c_entries
!= 0) && fvp
!= tvp
)
2561 * The following edge case is caught here:
2562 * (the from child and parent are the same)
2576 * Make sure "from" vnode and its parent are changeable.
2578 if ((fcp
->c_bsdflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
| UF_APPEND
| SF_APPEND
)) || (fdcp
->c_bsdflags
& (UF_APPEND
| SF_APPEND
)))
2584 /* Don't allow modification of the journal or journal_info_block */
2585 if (hfs_is_journal_file(hfsmp
, fcp
) || (tcp
&& hfs_is_journal_file(hfsmp
, tcp
)))
2591 struct cat_desc out_desc
= {0};
2592 from_desc
.cd_nameptr
= (const u_int8_t
*)fcnp
->cn_nameptr
;
2593 from_desc
.cd_namelen
= fcnp
->cn_namelen
;
2594 from_desc
.cd_parentcnid
= fdcp
->c_fileid
;
2595 from_desc
.cd_flags
= fcp
->c_desc
.cd_flags
& ~(CD_HASBUF
| CD_DECOMPOSED
);
2596 from_desc
.cd_cnid
= fcp
->c_cnid
;
2598 struct cat_desc to_desc
= {0};
2599 to_desc
.cd_nameptr
= (const u_int8_t
*)tcnp
->cn_nameptr
;
2600 to_desc
.cd_namelen
= tcnp
->cn_namelen
;
2601 to_desc
.cd_parentcnid
= tdcp
->c_fileid
;
2602 to_desc
.cd_flags
= fcp
->c_desc
.cd_flags
& ~(CD_HASBUF
| CD_DECOMPOSED
);
2603 to_desc
.cd_cnid
= fcp
->c_cnid
;
2605 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
2611 /* hfs_vnop_link() and hfs_vnop_rename() set kHFSHasChildLinkMask
2612 * inside a journal transaction and without holding a cnode lock.
2613 * As setting of this bit depends on being in journal transaction for
2614 * concurrency, check this bit again after we start journal transaction for rename
2615 * to ensure that this directory does not have any descendant that
2616 * is a directory hard link.
2618 if (vnode_isdir(fvp
) && (fdvp
!= tdvp
))
2620 if (fcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
)
2622 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
2623 if (cat_check_link_ancestry(hfsmp
, tdcp
->c_fileid
, 0)) {
2625 hfs_systemfile_unlock(hfsmp
, lockflags
);
2628 hfs_systemfile_unlock(hfsmp
, lockflags
);
2632 // if it's a hardlink then re-lookup the name so
2633 // that we get the correct cnid in from_desc (see
2634 // the comment in hfs_removefile for more details)
2635 if (fcp
->c_flag
& C_HARDLINK
)
2637 struct cat_desc tmpdesc
;
2640 tmpdesc
.cd_nameptr
= (const u_int8_t
*)fcnp
->cn_nameptr
;
2641 tmpdesc
.cd_namelen
= fcnp
->cn_namelen
;
2642 tmpdesc
.cd_parentcnid
= fdcp
->c_fileid
;
2643 tmpdesc
.cd_hint
= fdcp
->c_childhint
;
2644 tmpdesc
.cd_flags
= fcp
->c_desc
.cd_flags
& CD_ISDIR
;
2645 tmpdesc
.cd_encoding
= 0;
2647 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
2649 if (cat_lookup(hfsmp
, &tmpdesc
, 0, NULL
, NULL
, NULL
, &real_cnid
) != 0)
2651 hfs_systemfile_unlock(hfsmp
, lockflags
);
2655 // use the real cnid instead of whatever happened to be there
2656 from_desc
.cd_cnid
= real_cnid
;
2657 hfs_systemfile_unlock(hfsmp
, lockflags
);
2661 * Reserve some space in the Catalog file.
2663 cat_cookie_t cookie
;
2664 if ((error
= cat_preflight(hfsmp
, CAT_RENAME
+ CAT_DELETE
, &cookie
)))
2671 * If the destination exists then it may need to be removed.
2673 * Due to HFS's locking system, we should always move the
2674 * existing 'tvp' element to the hidden directory in hfs_vnop_rename.
2675 * Because the VNOP_LOOKUP call enters and exits the filesystem independently
2676 * of the actual vnop that it was trying to do (stat, link, readlink),
2677 * we must release the cnode lock of that element during the interim to
2678 * do MAC checking, vnode authorization, and other calls. In that time,
2679 * the item can be deleted (or renamed over). However, only in the rename
2680 * case is it inappropriate to return ENOENT from any of those calls. Either
2681 * the call should return information about the old element (stale), or get
2682 * information about the newer element that we are about to write in its place.
2684 * HFS lookup has been modified to detect a rename and re-drive its
2685 * lookup internally. For other calls that have already succeeded in
2686 * their lookup call and are waiting to acquire the cnode lock in order
2687 * to proceed, that cnode lock will not fail due to the cnode being marked
2688 * C_NOEXISTS, because it won't have been marked as such. It will only
2689 * have C_DELETED. Thus, they will simply act on the stale open-unlinked
2690 * element. All future callers will get the new element.
2692 * To implement this behavior, we pass the "only_unlink" argument to
2693 * hfs_removefile and hfs_removedir. This will result in the vnode acting
2694 * as though it is open-unlinked. Additionally, when we are done moving the
2695 * element to the hidden directory, we vnode_recycle the target so that it is
2696 * reclaimed as soon as possible. Reclaim and inactive are both
2697 * capable of clearing out unused blocks for an open-unlinked file or dir.
2702 * When fvp matches tvp they could be case variants
2703 * or matching hard links.
2707 if (!(fcp
->c_flag
& C_HARDLINK
))
2710 * If they're not hardlinks, then fvp == tvp must mean we
2711 * are using case-insensitive HFS because case-sensitive would
2712 * not use the same vnode for both. In this case we just update
2713 * the catalog for: a -> A
2715 goto skip_rm
; /* simple case variant */
2718 /* For all cases below, we must be using hardlinks */
2719 else if ((fdvp
!= tdvp
) || (hfsmp
->hfs_flags
& HFS_CASE_SENSITIVE
))
2722 * If the parent directories are not the same, AND the two items
2723 * are hardlinks, posix says to do nothing:
2724 * dir1/fred <-> dir2/bob and the op was mv dir1/fred -> dir2/bob
2725 * We just return 0 in this case.
2727 * If case sensitivity is on, and we are using hardlinks
2728 * then renaming is supposed to do nothing.
2729 * dir1/fred <-> dir2/FRED, and op == mv dir1/fred -> dir2/FRED
2734 else if (hfs_namecmp((const u_int8_t
*)fcnp
->cn_nameptr
, fcnp
->cn_namelen
, (const u_int8_t
*)tcnp
->cn_nameptr
, tcnp
->cn_namelen
) == 0)
2737 * If we get here, then the following must be true:
2738 * a) We are running case-insensitive HFS+.
2739 * b) Both paths 'fvp' and 'tvp' are in the same parent directory.
2740 * c) the two names are case-variants of each other.
2742 * In this case, we are really only dealing with a single catalog record
2743 * whose name is being updated.
2745 * op is dir1/fred -> dir1/FRED
2747 * We need to special case the name matching, because if
2748 * dir1/fred <-> dir1/bob were the two links, and the
2749 * op was dir1/fred -> dir1/bob
2750 * That would fail/do nothing.
2752 goto skip_rm
; /* case-variant hardlink in the same dir */
2756 goto out
; /* matching hardlink, nothing to do */
2761 if (vnode_isdir(tvp
))
2764 * hfs_removedir will eventually call hfs_removefile on the directory
2765 * we're working on, because only hfs_removefile does the renaming of the
2766 * item to the hidden directory. The directory will stay around in the
2767 * hidden directory with C_DELETED until it gets an inactive or a reclaim.
2768 * That way, we can destroy all of the EAs as needed and allow new ones to be
2771 error
= hfs_removedir(tdvp
, tvp
, tcnp
, HFSRM_SKIP_RESERVE
, 0);
2775 error
= hfs_removefile(tdvp
, tvp
, tcnp
, 0, HFSRM_SKIP_RESERVE
, 0, 0);
2778 * If the destination file had a resource fork vnode, then we need to get rid of
2779 * its blocks when there are no more references to it. Because the call to
2780 * hfs_removefile above always open-unlinks things, we need to force an inactive/reclaim
2781 * on the resource fork vnode, in order to prevent block leaks. Otherwise,
2782 * the resource fork vnode could prevent the data fork vnode from going out of scope
2783 * because it holds a v_parent reference on it. So we mark it for termination
2784 * with a call to vnode_recycle. hfs_vnop_reclaim has been modified so that it
2785 * can clean up the blocks of open-unlinked files and resource forks.
2787 * We can safely call vnode_recycle on the resource fork because we took an iocount
2788 * reference on it at the beginning of the function.
2791 if ((error
== 0) && (tcp
->c_flag
& C_DELETED
) && (tvp_rsrc
))
2793 hfs_chash_lower_OpenLookupCounter(tcp
);
2805 if ( ((VTOC(tvp
)->c_flag
& C_HARDLINK
) == 0 ) || (VTOC(tvp
)->c_linkcount
== 0) )
2807 INVALIDATE_NODE(tvp
);
2810 /* Mark 'tcp' as being deleted due to a rename */
2811 tcp
->c_flag
|= C_RENAMED
;
2814 * Aggressively mark tvp/tcp for termination to ensure that we recover all blocks
2815 * as quickly as possible.
2817 //TBD -- Need to see what we are doing with recycle
2818 // vnode_recycle(tvp);
2823 * All done with tvp and fvp.
2825 * We also jump to this point if there was no destination observed during lookup and namei.
2826 * However, because only iocounts are held at the VFS layer, there is nothing preventing a
2827 * competing thread from racing us and creating a file or dir at the destination of this rename
2828 * operation. If this occurs, it may cause us to get a spurious EEXIST out of the cat_rename
2829 * call below. To preserve rename's atomicity, we need to signal VFS to re-drive the
2830 * namei/lookup and restart the rename operation. EEXIST is an allowable errno to be bubbled
2831 * out of the rename syscall, but not for this reason, since it is a synonym errno for ENOTEMPTY.
2832 * To signal VFS, we return ERECYCLE (which is also used for lookup restarts). This errno
2833 * will be swallowed and it will restart the operation.
2836 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
2837 error
= cat_rename(hfsmp
, &from_desc
, &tdcp
->c_desc
, &to_desc
, &out_desc
);
2838 hfs_systemfile_unlock(hfsmp
, lockflags
);
2842 if (error
== EEXIST
)
2849 /* Update cnode's catalog descriptor */
2850 replace_desc(fcp
, &out_desc
);
2851 fcp
->c_parentcnid
= tdcp
->c_fileid
;
2855 * Now indicate this cnode needs to have date-added written to the
2856 * finderinfo, but only if moving to a different directory, or if
2857 * it doesn't already have it.
2859 if (fdvp
!= tdvp
|| !ISSET(fcp
->c_attr
.ca_recflags
, kHFSHasDateAddedMask
))
2860 fcp
->c_flag
|= C_NEEDS_DATEADDED
;
2862 (void) hfs_update (fvp
, 0);
2864 hfs_volupdate(hfsmp
, vnode_isdir(fvp
) ? VOL_RMDIR
: VOL_RMFILE
, (fdcp
->c_cnid
== kHFSRootFolderID
));
2865 hfs_volupdate(hfsmp
, vnode_isdir(fvp
) ? VOL_MKDIR
: VOL_MKFILE
, (tdcp
->c_cnid
== kHFSRootFolderID
));
2867 /* Update both parent directories. */
2870 if (vnode_isdir(fvp
))
2872 /* If the source directory has directory hard link
2873 * descendants, set the kHFSHasChildLinkBit in the
2874 * destination parent hierarchy
2876 if ((fcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
) && !(tdcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
))
2879 tdcp
->c_attr
.ca_recflags
|= kHFSHasChildLinkMask
;
2881 error
= cat_set_childlinkbit(hfsmp
, tdcp
->c_parentcnid
);
2884 LFHFS_LOG(LEVEL_DEBUG
, "hfs_vnop_rename: error updating parent chain for %u\n", tdcp
->c_cnid
);
2888 INC_FOLDERCOUNT(hfsmp
, tdcp
->c_attr
);
2889 DEC_FOLDERCOUNT(hfsmp
, fdcp
->c_attr
);
2892 tdcp
->c_dirchangecnt
++;
2893 tdcp
->c_flag
|= C_MODIFIED
;
2894 hfs_incr_gencount(tdcp
);
2896 if (fdcp
->c_entries
> 0)
2898 fdcp
->c_dirchangecnt
++;
2899 fdcp
->c_flag
|= C_MODIFIED
;
2900 fdcp
->c_touch_chgtime
= TRUE
;
2901 fdcp
->c_touch_modtime
= TRUE
;
2903 if (ISSET(fcp
->c_flag
, C_HARDLINK
))
2905 hfs_relorigin(fcp
, fdcp
->c_fileid
);
2906 if (fdcp
->c_fileid
!= fdcp
->c_cnid
)
2907 hfs_relorigin(fcp
, fdcp
->c_cnid
);
2910 (void) hfs_update(fdvp
, 0);
2912 hfs_incr_gencount(fdcp
);
2914 tdcp
->c_childhint
= out_desc
.cd_hint
; /* Cache directory's location */
2915 tdcp
->c_touch_chgtime
= TRUE
;
2916 tdcp
->c_touch_modtime
= TRUE
;
2918 (void) hfs_update(tdvp
, 0);
2920 /* Update the vnode's name now that the rename has completed. */
2921 vnode_update_identity(fvp
, tdvp
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
, tcnp
->cn_hash
, (VNODE_UPDATE_PARENT
| VNODE_UPDATE_NAME
));
2924 * At this point, we may have a resource fork vnode attached to the
2925 * 'from' vnode. If it exists, we will want to update its name, because
2926 * it contains the old name + _PATH_RSRCFORKSPEC. ("/..namedfork/rsrc").
2928 * Note that the only thing we need to update here is the name attached to
2929 * the vnode, since a resource fork vnode does not have a separate resource
2930 * cnode -- it's still 'fcp'.
2934 char* rsrc_path
= NULL
;
2937 /* Create a new temporary buffer that's going to hold the new name */
2938 rsrc_path
= hfs_malloc(MAXPATHLEN
);
2939 len
= snprintf (rsrc_path
, MAXPATHLEN
, "%s%s", tcnp
->cn_nameptr
, _PATH_RSRCFORKSPEC
);
2940 len
= MIN(len
, MAXPATHLEN
);
2943 * vnode_update_identity will do the following for us:
2944 * 1) release reference on the existing rsrc vnode's name.
2945 * 2) attach the new name to the resource vnode
2946 * 3) update the vnode's vid
2948 vnode_update_identity (fcp
->c_rsrc_vp
, fvp
, rsrc_path
, len
, 0, (VNODE_UPDATE_NAME
| VNODE_UPDATE_CACHE
));
2950 /* Free the memory associated with the resource fork's name */
2951 hfs_free(rsrc_path
);
2956 cat_postflight(hfsmp
, &cookie
);
2960 hfs_end_transaction(hfsmp
);
2963 fdvp
->sExtraData
.sDirData
.uDirVersion
++;
2964 fdcp
->c_flag
&= ~C_DIR_MODIFICATION
;
2965 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
2966 // wakeup((caddr_t)&fdcp->c_flag);
2970 tdvp
->sExtraData
.sDirData
.uDirVersion
++;
2971 tdcp
->c_flag
&= ~C_DIR_MODIFICATION
;
2972 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
2973 // wakeup((caddr_t)&tdcp->c_flag);
2977 /* Now vnode_put the resource forks vnodes if necessary */
2980 hfs_chash_lower_OpenLookupCounter(tcp
);
2984 hfs_unlockfour(fdcp
, fcp
, tdcp
, tcp
);
2986 if (took_trunc_lock
)
2988 hfs_unlock_truncate(VTOC(tvp
), HFS_LOCK_DEFAULT
);
2991 /* After tvp is removed the only acceptable error is EIO */
2992 if (error
&& tvp_deleted
)
2999 * link vnode operation
3002 * IN vnode_t a_tdvp;
3003 * IN struct componentname *a_cnp;
3004 * IN vfs_context_t a_context;
3007 hfs_vnop_link(vnode_t vp
, vnode_t tdvp
, struct componentname
*cnp
)
3009 struct hfsmount
*hfsmp
= VTOHFS(vp
);;
3010 struct cnode
*cp
= VTOC(vp
);;
3012 struct cnode
*fdcp
= NULL
;
3013 struct cat_desc todesc
;
3017 enum vtype v_type
= vp
->sFSParams
.vnfs_vtype
;
3021 * For now, return ENOTSUP for a symlink target. This can happen
3022 * for linkat(2) when called without AT_SYMLINK_FOLLOW.
3024 if (v_type
== VLNK
|| v_type
== VDIR
)
3027 /* Make sure our private directory exists. */
3028 if (hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
== 0) {
3032 if (hfs_freeblks(hfsmp
, 0) == 0) {
3036 /* Lock the cnodes. */
3037 if ((error
= hfs_lockpair(VTOC(tdvp
), VTOC(vp
), HFS_EXCLUSIVE_LOCK
))) {
3042 /* grab the parent CNID from originlist after grabbing cnode locks */
3043 parentcnid
= hfs_currentparent(cp
, /* have_lock: */ true);
3045 if (tdcp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
3050 /* Check the source for errors:
3051 * too many links, immutable, race with unlink
3053 if (cp
->c_linkcount
>= HFS_LINK_MAX
) {
3057 if (cp
->c_bsdflags
& (UF_IMMUTABLE
| SF_IMMUTABLE
| UF_APPEND
| SF_APPEND
)) {
3061 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
3066 tdcp
->c_flag
|= C_DIR_MODIFICATION
;
3068 if (hfs_start_transaction(hfsmp
) != 0) {
3074 todesc
.cd_flags
= (v_type
== VDIR
) ? CD_ISDIR
: 0;
3075 todesc
.cd_encoding
= 0;
3076 todesc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
3077 todesc
.cd_namelen
= cnp
->cn_namelen
;
3078 todesc
.cd_parentcnid
= tdcp
->c_fileid
;
3082 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
3084 /* If destination exists then we lost a race with create. */
3085 if (cat_lookup(hfsmp
, &todesc
, 0, NULL
, NULL
, NULL
, NULL
) == 0) {
3089 if (cp
->c_flag
& C_HARDLINK
) {
3090 struct cat_attr cattr
;
3092 /* If inode is missing then we lost a race with unlink. */
3093 if ((cat_idlookup(hfsmp
, cp
->c_fileid
, 0, 0, NULL
, &cattr
, NULL
) != 0) ||
3094 (cattr
.ca_fileid
!= cp
->c_fileid
)) {
3101 /* If source is missing then we lost a race with unlink. */
3102 if ((cat_lookup(hfsmp
, &cp
->c_desc
, 0, NULL
, NULL
, NULL
, &fileid
) != 0) ||
3103 (fileid
!= cp
->c_fileid
)) {
3109 * All directory links must reside in an non-ARCHIVED hierarchy.
3111 if (v_type
== VDIR
) {
3113 * - Source parent and destination parent cannot match
3114 * - A link is not permitted in the root directory
3115 * - Parent of 'pointed at' directory is not the root directory
3116 * - The 'pointed at' directory (source) is not an ancestor
3117 * of the new directory hard link (destination).
3118 * - No ancestor of the new directory hard link (destination)
3119 * is a directory hard link.
3121 if ((parentcnid
== tdcp
->c_fileid
) ||
3122 (tdcp
->c_fileid
== kHFSRootFolderID
) ||
3123 (parentcnid
== kHFSRootFolderID
) ||
3124 cat_check_link_ancestry(hfsmp
, tdcp
->c_fileid
, cp
->c_fileid
)) {
3125 error
= EPERM
; /* abide by the rules, you did not */
3129 hfs_systemfile_unlock(hfsmp
, lockflags
);
3133 cp
->c_flag
|= C_MODIFIED
;
3134 cp
->c_touch_chgtime
= TRUE
;
3135 error
= hfs_makelink(hfsmp
, vp
, cp
, tdcp
, cnp
);
3138 hfs_volupdate(hfsmp
, VOL_UPDATE
, 0);
3140 /* Update the target directory and volume stats */
3142 if (v_type
== VDIR
) {
3143 INC_FOLDERCOUNT(hfsmp
, tdcp
->c_attr
);
3144 tdcp
->c_attr
.ca_recflags
|= kHFSHasChildLinkMask
;
3146 /* Set kHFSHasChildLinkBit in the destination hierarchy */
3147 error
= cat_set_childlinkbit(hfsmp
, tdcp
->c_parentcnid
);
3149 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_link: error updating destination parent chain for id=%u, vol=%s\n", tdcp
->c_cnid
, hfsmp
->vcbVN
);
3152 tdcp
->c_dirchangecnt
++;
3153 tdcp
->c_flag
|= C_MODIFIED
;
3154 hfs_incr_gencount(tdcp
);
3155 tdcp
->c_touch_chgtime
= TRUE
;
3156 tdcp
->c_touch_modtime
= TRUE
;
3158 error
= hfs_update(tdvp
, 0);
3160 if (error
!= EIO
&& error
!= ENXIO
) {
3161 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_link: error %d updating tdvp %p\n", error
, tdvp
);
3164 hfs_mark_inconsistent(hfsmp
, HFS_OP_INCOMPLETE
);
3167 hfs_volupdate(hfsmp
, VOL_MKFILE
, (tdcp
->c_cnid
== kHFSRootFolderID
));
3170 if (error
== 0 && (ret
= hfs_update(vp
, 0)) != 0) {
3171 if (ret
!= EIO
&& ret
!= ENXIO
)
3172 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_link: error %d updating vp @ %p\n", ret
, vp
);
3173 hfs_mark_inconsistent(hfsmp
, HFS_OP_INCOMPLETE
);
3178 hfs_systemfile_unlock(hfsmp
, lockflags
);
3181 hfs_end_transaction(hfsmp
);
3184 tdcp
->c_flag
&= ~C_DIR_MODIFICATION
;
3185 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
3186 // wakeup((caddr_t)&tdcp->c_flag);
3189 hfs_unlockfour(tdcp
, cp
, fdcp
, NULL
);
3191 hfs_unlockpair(tdcp
, cp
);
3197 int hfs_removefile_callback(GenericLFBuf
*psBuff
, void *pvArgs
) {
3199 journal_kill_block(((struct hfsmount
*)pvArgs
)->jnl
, psBuff
);
3206 * hfs_vgetrsrc acquires a resource fork vnode corresponding to the
3207 * cnode that is found in 'vp'. The cnode should be locked upon entry
3208 * and will be returned locked, but it may be dropped temporarily.
3210 * If the resource fork vnode does not exist, HFS will attempt to acquire an
3211 * empty (uninitialized) vnode from VFS so as to avoid deadlocks with
3212 * jetsam. If we let the normal getnewvnode code produce the vnode for us
3213 * we would be doing so while holding the cnode lock of our cnode.
3215 * On success, *rvpp wlll hold the resource fork vnode with an
3216 * iocount. *Don't* forget the vnode_put.
3219 hfs_vgetrsrc( struct vnode
*vp
, struct vnode
**rvpp
)
3221 struct hfsmount
*hfsmp
= VTOHFS(vp
);
3222 struct vnode
*rvp
= NULL
;
3223 struct cnode
*cp
= VTOC(vp
);
3227 /* Attempt to use existing vnode */
3228 if ((rvp
= cp
->c_rsrc_vp
)) {
3229 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
3230 hfs_chash_raise_OpenLookupCounter(cp
);
3233 struct cat_fork rsrcfork
;
3234 struct cat_desc
*descptr
= NULL
;
3235 struct cat_desc to_desc
;
3236 int newvnode_flags
= 0;
3238 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
3241 * We could have raced with another thread here while we dropped our cnode
3242 * lock. See if the cnode now has a resource fork vnode and restart if appropriate.
3244 * Note: We just released the cnode lock, so there is a possibility that the
3245 * cnode that we just acquired has been deleted or even removed from disk
3246 * completely, though this is unlikely. If the file is open-unlinked, the
3247 * check below will resolve it for us. If it has been completely
3248 * removed (even from the catalog!), then when we examine the catalog
3249 * directly, below, while holding the catalog lock, we will not find the
3250 * item and we can fail out properly.
3252 if (cp
->c_rsrc_vp
) {
3253 /* Drop the empty vnode before restarting */
3260 * hfs_vgetsrc may be invoked for a cnode that has already been marked
3261 * C_DELETED. This is because we need to continue to provide rsrc
3262 * fork access to open-unlinked files. In this case, build a fake descriptor
3263 * like in hfs_removefile. If we don't do this, buildkey will fail in
3264 * cat_lookup because this cnode has no name in its descriptor.
3266 if ((cp
->c_flag
& C_DELETED
) && (cp
->c_desc
.cd_namelen
== 0)) {
3268 bzero (&to_desc
, sizeof(to_desc
));
3269 bzero (delname
, 32);
3270 MAKE_DELETED_NAME(delname
, sizeof(delname
), cp
->c_fileid
);
3271 to_desc
.cd_nameptr
= (const u_int8_t
*) delname
;
3272 to_desc
.cd_namelen
= strlen(delname
);
3273 to_desc
.cd_parentcnid
= hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
;
3274 to_desc
.cd_flags
= 0;
3275 to_desc
.cd_cnid
= cp
->c_cnid
;
3280 descptr
= &cp
->c_desc
;
3284 int lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
3287 * We call cat_idlookup (instead of cat_lookup) below because we can't
3288 * trust the descriptor in the provided cnode for lookups at this point.
3289 * Between the time of the original lookup of this vnode and now, the
3290 * descriptor could have gotten swapped or replaced. If this occurred,
3291 * the parent/name combo originally desired may not necessarily be provided
3292 * if we use the descriptor. Even worse, if the vnode represents
3293 * a hardlink, we could have removed one of the links from the namespace
3294 * but left the descriptor alone, since hfs_unlink does not invalidate
3295 * the descriptor in the cnode if other links still point to the inode.
3297 * Consider the following (slightly contrived) scenario:
3298 * /tmp/a <--> /tmp/b (hardlinks).
3299 * 1. Thread A: open rsrc fork on /tmp/b.
3300 * 1a. Thread A: does lookup, goes out to lunch right before calling getnamedstream.
3301 * 2. Thread B does 'mv /foo/b /tmp/b'
3302 * 2. Thread B succeeds.
3303 * 3. Thread A comes back and wants rsrc fork info for /tmp/b.
3305 * Even though the hardlink backing /tmp/b is now eliminated, the descriptor
3306 * is not removed/updated during the unlink process. So, if you were to
3307 * do a lookup on /tmp/b, you'd acquire an entirely different record's resource
3310 * As a result, we use the fileid, which should be invariant for the lifetime
3311 * of the cnode (possibly barring calls to exchangedata).
3313 * Addendum: We can't do the above for HFS standard since we aren't guaranteed to
3314 * have thread records for files. They were only required for directories. So
3315 * we need to do the lookup with the catalog name. This is OK since hardlinks were
3316 * never allowed on HFS standard.
3319 /* Get resource fork data */
3320 error
= cat_idlookup (hfsmp
, cp
->c_fileid
, 0, 1, NULL
, NULL
, &rsrcfork
);
3322 hfs_systemfile_unlock(hfsmp
, lockflags
);
3324 LFHFS_LOG(LEVEL_ERROR
, "hfs_vgetrsrc: cat_idlookup failed with error [%d]\n", error
);
3326 hfs_chash_lower_OpenLookupCounter(cp
);
3330 * Supply hfs_getnewvnode with a component name.
3332 struct componentname cn
;
3334 if (descptr
->cd_nameptr
) {
3335 void *buf
= hfs_malloc(MAXPATHLEN
);
3337 cn
= (struct componentname
){
3338 .cn_nameiop
= LOOKUP
,
3339 .cn_flags
= ISLASTCN
,
3340 .cn_pnlen
= MAXPATHLEN
,
3343 .cn_namelen
= snprintf(buf
, MAXPATHLEN
,
3344 "%s%s", descptr
->cd_nameptr
,
3348 // Should never happen because cn.cn_nameptr won't ever be long...
3349 if (cn
.cn_namelen
>= MAXPATHLEN
) {
3351 LFHFS_LOG(LEVEL_ERROR
, "hfs_vgetrsrc: cnode name too long [ENAMETOOLONG]\n");
3353 hfs_chash_lower_OpenLookupCounter(cp
);
3354 return ENAMETOOLONG
;
3359 * We are about to call hfs_getnewvnode and pass in the vnode that we acquired
3360 * earlier when we were not holding any locks. The semantics of GNV_USE_VP require that
3361 * either hfs_getnewvnode consume the vnode and vend it back to us, properly initialized,
3362 * or it will consume/dispose of it properly if it errors out.
3364 error
= hfs_getnewvnode(hfsmp
, NULL
, cn
.cn_pnbuf
? &cn
: NULL
,
3365 descptr
, (GNV_WANTRSRC
| GNV_SKIPLOCK
),
3366 &cp
->c_attr
, &rsrcfork
, &rvp
, &newvnode_flags
);
3368 hfs_free(cn
.cn_pnbuf
);
3371 } /* End 'else' for rsrc fork not existing */