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"
41 replace_desc(struct cnode
*cp
, struct cat_desc
*cdp
)
43 // fixes 4348457 and 4463138
44 if (&cp
->c_desc
== cdp
) {
48 /* First release allocated name buffer */
49 if (cp
->c_desc
.cd_flags
& CD_HASBUF
&& cp
->c_desc
.cd_nameptr
!= 0) {
50 const u_int8_t
*name
= cp
->c_desc
.cd_nameptr
;
52 cp
->c_desc
.cd_nameptr
= 0;
53 cp
->c_desc
.cd_namelen
= 0;
54 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
55 hfs_free((void*)name
);
57 bcopy(cdp
, &cp
->c_desc
, sizeof(cp
->c_desc
));
59 /* Cnode now owns the name buffer */
60 cdp
->cd_nameptr
= NULL
;
62 cdp
->cd_flags
&= ~CD_HASBUF
;
65 static void SynthesizeDotAndDotX2(u_int64_t uCnid
, void* puBuff
, bool bIsDot
, bool bIsLastEntry
)
67 UVFSDirEntry
* psDotEntry
= (UVFSDirEntry
*)puBuff
;
68 uint8_t uNameLen
= bIsDot
? 1: 2;
69 memset( psDotEntry
, 0, UVFS_DIRENTRY_RECLEN(uNameLen
));
71 psDotEntry
->de_fileid
= uCnid
;
72 psDotEntry
->de_filetype
= UVFS_FA_TYPE_DIR
;
73 psDotEntry
->de_reclen
= bIsLastEntry
? 0 : UVFS_DIRENTRY_RECLEN(uNameLen
);
74 psDotEntry
->de_nextcookie
= uNameLen
;
75 psDotEntry
->de_namelen
= uNameLen
;
76 uint8_t* puNameBuf
= (uint8_t*)psDotEntry
->de_name
;
89 static int SyntisizeEntries(uint64_t* puOffset
, ReadDirBuff_s
* psReadDirBuffer
, int iIsExtended
, u_int64_t uCnid
, u_int64_t uParentCnid
, UVFSDirEntry
** ppsDotDotEntry
)
95 //Curently not supporting nonextended ReadDir
99 if (DOT_DIR_SIZE
> psReadDirBuffer
->uBufferResid
)
104 pvBuff
= hfs_malloc(DOT_DIR_SIZE
);
107 LFHFS_LOG(LEVEL_ERROR
, "SyntisizeEntries: Failed to allocate buffer for DOT entry\n");
113 bool bIsEnoughRoomForAll
= (DOT_DIR_SIZE
+ DOT_X2_DIR_SIZE
> psReadDirBuffer
->uBufferResid
);
114 SynthesizeDotAndDotX2(uCnid
, pvBuff
, true, bIsEnoughRoomForAll
);
115 memcpy(psReadDirBuffer
->pvBuffer
+ READDIR_BUF_OFFSET(psReadDirBuffer
) , pvBuff
, DOT_DIR_SIZE
);
117 psReadDirBuffer
->uBufferResid
-= DOT_DIR_SIZE
;
120 if (DOT_X2_DIR_SIZE
> psReadDirBuffer
->uBufferResid
)
126 pvBuff
= hfs_malloc(DOT_X2_DIR_SIZE
);
129 LFHFS_LOG(LEVEL_ERROR
, "SyntisizeEntries: Failed to allocate buffer for DOTx2 entry\n");
135 SynthesizeDotAndDotX2(uParentCnid
, pvBuff
, false, false);
136 memcpy(psReadDirBuffer
->pvBuffer
+ READDIR_BUF_OFFSET(psReadDirBuffer
), pvBuff
, DOT_X2_DIR_SIZE
);
137 *ppsDotDotEntry
= (UVFSDirEntry
*) (psReadDirBuffer
->pvBuffer
+ READDIR_BUF_OFFSET(psReadDirBuffer
));
139 psReadDirBuffer
->uBufferResid
-= DOT_X2_DIR_SIZE
;
149 * hfs_vnop_readdir reads directory entries into the buffer pointed
150 * to by uio, in a filesystem independent format. Up to uio_resid
151 * bytes of data can be transferred. The data in the buffer is a
152 * series of packed dirent structures where each one contains the
155 * u_int32_t d_fileno; // file number of entry
156 * u_int16_t d_reclen; // length of this record
157 * u_int8_t d_type; // file type
158 * u_int8_t d_namlen; // length of string in d_name
159 * char d_name[MAXNAMELEN+1]; // null terminated file name
161 * The current position (uio_offset) refers to the next block of
162 * entries. The offset can only be set to a value previously
163 * returned by hfs_vnop_readdir or zero. This offset does not have
164 * to match the number of bytes returned (in uio_resid).
166 * In fact, the offset used by HFS is essentially an index (26 bits)
167 * with a tag (6 bits). The tag is for associating the next request
168 * with the current request. This enables us to have multiple threads
169 * reading the directory while the directory is also being modified.
171 * Each tag/index pair is tied to a unique directory hint. The hint
172 * contains information (filename) needed to build the catalog b-tree
173 * key for finding the next set of entries.
175 * If the directory is marked as deleted-but-in-use (cp->c_flag & C_DELETED),
176 * do NOT synthesize entries for "." and "..".
179 hfs_vnop_readdir(vnode_t vp
, int *eofflag
, int *numdirent
, ReadDirBuff_s
* psReadDirBuffer
, uint64_t puCookie
, int flags
)
181 struct cnode
*cp
= NULL
;
182 struct hfsmount
*hfsmp
= VTOHFS(vp
);
183 directoryhint_t
*dirhint
= NULL
;
184 directoryhint_t localhint
;
185 bool bLocalEOFflag
= false;
188 user_size_t user_original_resid
= psReadDirBuffer
->uBufferResid
;
190 cnid_t cnid_hint
= 0;
191 int bump_valence
= 0;
193 uint64_t startoffset
= offset
= puCookie
;
194 bool extended
= (flags
& VNODE_READDIR_EXTENDED
);
195 bool nfs_cookies
= extended
&& (flags
& VNODE_READDIR_REQSEEKOFF
);
197 if (psReadDirBuffer
->pvBuffer
== NULL
|| psReadDirBuffer
->uBufferResid
< sizeof(UVFSDirEntry
))
199 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: readDir input is not valid\n");
203 /* Note that the dirhint calls require an exclusive lock. */
204 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
206 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: Failed to lock vnode\n");
211 /* Pick up cnid hint (if any). */
214 cnid_hint
= (cnid_t
)(offset
>> 32);
215 offset
&= 0x00000000ffffffffLL
;
216 if (cnid_hint
== INT_MAX
)
217 { /* searching pass the last item */
218 bLocalEOFflag
= true;
224 * Synthesize entries for "." and "..", unless the directory has
225 * been deleted, but not closed yet (lazy delete in progress).
227 UVFSDirEntry
* psDotDotEntry
= NULL
;
228 if (!(cp
->c_flag
& C_DELETED
))
230 if ( (error
= SyntisizeEntries(&offset
, psReadDirBuffer
, extended
, cp
->c_cnid
, cp
->c_parentcnid
, &psDotDotEntry
)) != 0 )
232 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: Failed to syntisize dot/dotdot entries\n");
237 /* Convert offset into a catalog directory index. */
238 int index
= (offset
& HFS_INDEX_MASK
) - 2;
239 unsigned int tag
= (unsigned int) (offset
& ~HFS_INDEX_MASK
);
241 /* Lock catalog during cat_findname and cat_getdirentries. */
242 int lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
244 /* When called from NFS, try and resolve a cnid hint. */
245 if (nfs_cookies
&& cnid_hint
!= 0)
247 if (cat_findname(hfsmp
, cnid_hint
, &localhint
.dh_desc
) == 0)
249 if ( localhint
.dh_desc
.cd_parentcnid
== cp
->c_fileid
)
251 localhint
.dh_index
= index
- 1;
252 localhint
.dh_time
= 0;
253 bzero(&localhint
.dh_link
, sizeof(localhint
.dh_link
));
254 dirhint
= &localhint
; /* don't forget to release the descriptor */
258 cat_releasedesc(&localhint
.dh_desc
);
263 /* Get a directory hint (cnode must be locked exclusive) */
266 dirhint
= hfs_getdirhint(cp
, ((index
- 1) & HFS_INDEX_MASK
) | tag
, 0);
268 /* Hide tag from catalog layer. */
269 dirhint
->dh_index
&= HFS_INDEX_MASK
;
270 if (dirhint
->dh_index
== HFS_INDEX_MASK
)
272 dirhint
->dh_index
= -1;
278 dirhint
->dh_threadhint
= cp
->c_dirthreadhint
;
283 * If we have a non-zero index, there is a possibility that during the last
284 * call to hfs_vnop_readdir we hit EOF for this directory. If that is the case
285 * then we don't want to return any new entries for the caller. Just return 0
286 * items, mark the eofflag, and bail out. Because we won't have done any work, the
287 * code at the end of the function will release the dirhint for us.
289 * Don't forget to unlock the catalog lock on the way out, too.
291 if (dirhint
->dh_desc
.cd_flags
& CD_EOF
)
294 bLocalEOFflag
= true;
295 offset
= startoffset
;
296 if (user_original_resid
> 0) {
297 psReadDirBuffer
->uBufferResid
= user_original_resid
;
299 hfs_systemfile_unlock (hfsmp
, lockflags
);
305 /* Pack the buffer with dirent entries. */
306 error
= cat_getdirentries(hfsmp
, cp
->c_entries
, dirhint
, psReadDirBuffer
, flags
, &items
, &bLocalEOFflag
, psDotDotEntry
);
308 if (index
== 0 && error
== 0)
310 cp
->c_dirthreadhint
= dirhint
->dh_threadhint
;
313 hfs_systemfile_unlock(hfsmp
, lockflags
);
317 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdir: Failed to get dir entries\n");
321 /* Get index to the next item */
324 if (items
>= (int)cp
->c_entries
)
326 bLocalEOFflag
= true;
330 * Detect valence FS corruption.
332 * We are holding the cnode lock exclusive, so there should not be
333 * anybody modifying the valence field of this cnode. If we enter
334 * this block, that means we observed filesystem corruption, because
335 * this directory reported a valence of 0, yet we found at least one
336 * item. In this case, we need to minimally self-heal this
337 * directory to prevent userland from tripping over a directory
338 * that appears empty (getattr of valence reports 0), but actually
341 * We'll force the cnode update at the end of the function after
342 * completing all of the normal getdirentries steps.
344 if ((cp
->c_entries
== 0) && (items
> 0))
346 /* disk corruption */
348 /* Mark the cnode as dirty. */
349 cp
->c_flag
|= C_MODIFIED
;
350 LFHFS_LOG(LEVEL_DEBUG
, "hfs_vnop_readdir: repairing valence to non-zero! \n");
355 /* Convert catalog directory index back into an offset. */
357 tag
= (++cp
->c_dirhinttag
) << HFS_INDEX_BITS
;
358 offset
= ((index
+ 2) | tag
);
359 dirhint
->dh_index
|= tag
;
362 cp
->c_touch_acctime
= TRUE
;
366 if (startoffset
== 0)
368 else if (startoffset
== 1)
375 /* If we didn't do anything then go ahead and dump the hint. */
376 if ((dirhint
!= NULL
) && (dirhint
!= &localhint
) && (offset
== startoffset
))
378 hfs_reldirhint(cp
, dirhint
);
379 bLocalEOFflag
= true;
384 *eofflag
= bLocalEOFflag
;
387 if (dirhint
== &localhint
)
389 cat_releasedesc(&localhint
.dh_desc
);
394 /* force the update before dropping the cnode lock*/
404 * readdirattr operation will return attributes for the items in the
405 * directory specified.
407 * It does not do . and .. entries. The problem is if you are at the root of the
408 * hfs directory and go to .. you could be crossing a mountpoint into a
409 * different (ufs) file system. The attributes that apply for it may not
410 * apply for the file system you are doing the readdirattr on. To make life
411 * simpler, this call will only return entries in its directory, hfs like.
414 hfs_vnop_readdirattr(vnode_t vp
, int *eofflag
, int *numdirent
, ReadDirBuff_s
* psReadDirBuffer
, uint64_t puCookie
)
418 uint32_t uMaxCount
= (uint32_t) psReadDirBuffer
->uBufferResid
/ _UVFS_DIRENTRYATTR_RECLEN(UVFS_DIRENTRYATTR_NAMEOFF
,0);
420 if (psReadDirBuffer
->pvBuffer
== NULL
|| psReadDirBuffer
->uBufferResid
< sizeof(UVFSDirEntry
))
422 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readdirattr: buffer input is invalid\n");
426 error
= hfs_readdirattr_internal(vp
, psReadDirBuffer
, uMaxCount
, &newstate
, eofflag
, numdirent
, puCookie
);
432 * Sync all hfs B-trees. Use this instead of journal_flush for a volume
433 * without a journal. Note that the volume bitmap does not get written;
434 * we rely on fsck_hfs to fix that up (which it can do without any loss
438 hfs_metasync_all(struct hfsmount
*hfsmp
)
442 /* Lock all of the B-trees so we get a mutually consistent state */
443 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
|SFL_EXTENTS
|SFL_ATTRIBUTE
, HFS_EXCLUSIVE_LOCK
);
445 #if LF_HFS_FULL_VNODE_SUPPORT
446 //Curently we don't keep any cache for btree buffers.
447 //When we will have a cache we will have to flush it out here.
448 /* Sync each of the B-trees */
449 if (hfsmp
->hfs_catalog_vp
)
450 hfs_btsync(hfsmp
->hfs_catalog_vp
, 0);
451 if (hfsmp
->hfs_extents_vp
)
452 hfs_btsync(hfsmp
->hfs_extents_vp
, 0);
453 if (hfsmp
->hfs_attribute_vp
)
454 hfs_btsync(hfsmp
->hfs_attribute_vp
, 0);
456 hfs_systemfile_unlock(hfsmp
, lockflags
);
461 * cnode must be locked
464 hfs_fsync(struct vnode
*vp
, int waitfor
, hfs_fsync_mode_t fsyncmode
)
466 struct cnode
*cp
= VTOC(vp
);
467 struct filefork
*fp
= NULL
;
470 int took_trunc_lock
= 0;
471 int fsync_default
= 1;
474 * Applications which only care about data integrity rather than full
475 * file integrity may opt out of (delay) expensive metadata update
476 * operations as a performance optimization.
478 int wait
= (waitfor
== MNT_WAIT
); /* attributes necessary for data retrieval */
479 if (fsyncmode
!= HFS_FSYNC
)
482 /* HFS directories don't have any data blocks. */
488 * For system files flush the B-tree header and
489 * for regular files write out any clusters
491 if (vnode_issystem(vp
))
493 if (VTOF(vp
)->fcbBTCBPtr
!= NULL
)
496 if (VTOHFS(vp
)->jnl
== NULL
)
498 BTFlushPath(VTOF(vp
));
504 //TBD- Since we always flush the data for every file when it is being updated
505 // we don't need to do that here.
507 // hfs_lock_truncate(cp, HFS_SHARED_LOCK, HFS_LOCK_DEFAULT);
508 // took_trunc_lock = 1;
510 // if (fp->ff_unallocblocks != 0)
512 // hfs_unlock_truncate(cp, HFS_LOCK_DEFAULT);
514 // hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
517 //#if LF_HFS_FULL_VNODE_SUPPORT
518 // /* Don't hold cnode lock when calling into cluster layer. */
519 // (void) cluster_push(vp, waitdata ? IO_SYNC : 0);
522 // hfs_lock(cp, HFS_EXCLUSIVE_LOCK, HFS_LOCK_ALLOW_NOEXISTS);
526 * When MNT_WAIT is requested and the zero fill timeout
527 * has expired then we must explicitly zero out any areas
528 * that are currently marked invalid (holes).
530 * Files with NODUMP can bypass zero filling here.
532 if (fp
&& (((cp
->c_flag
& C_ALWAYS_ZEROFILL
) && !TAILQ_EMPTY(&fp
->ff_invalidranges
)) ||
533 ((wait
|| (cp
->c_flag
& C_ZFWANTSYNC
)) &&
534 ((cp
->c_bsdflags
& UF_NODUMP
) == 0) &&
535 (vnode_issystem(vp
) ==0) &&
536 cp
->c_zftimeout
!= 0)))
539 if ((cp
->c_flag
& C_ALWAYS_ZEROFILL
) == 0 && fsync_default
&& tv
.tv_sec
< (long)cp
->c_zftimeout
)
541 /* Remember that a force sync was requested. */
542 cp
->c_flag
|= C_ZFWANTSYNC
;
545 if (!TAILQ_EMPTY(&fp
->ff_invalidranges
))
547 if (!took_trunc_lock
|| (cp
->c_truncatelockowner
== HFS_SHARED_OWNER
))
550 if (took_trunc_lock
) {
551 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
553 hfs_lock_truncate(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
554 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_ALLOW_NOEXISTS
);
558 #if LF_HFS_FULL_VNODE_SUPPORT
559 hfs_flush_invalid_ranges(vp
);
561 (void) cluster_push(vp
, waitdata
? IO_SYNC
: 0);
562 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_ALLOW_NOEXISTS
);
569 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
571 // TBD - symlink can't be dirsty since we always write the data fully to the device
572 // else if (fsync_default && vnode_islnk(vp) && vnode_hasdirtyblks(vp) && vnode_isrecycled(vp))
575 // * If it's a symlink that's dirty and is about to be recycled,
576 // * we need to flush the journal.
578 // fsync_default = 0;
582 if (vnode_isreg(vp
) && vnode_issystem(vp
))
584 if (VTOF(vp
)->fcbBTCBPtr
!= NULL
)
587 BTSetLastSync(VTOF(vp
), (u_int32_t
) tv
.tv_sec
);
589 cp
->c_touch_acctime
= FALSE
;
590 cp
->c_touch_chgtime
= FALSE
;
591 cp
->c_touch_modtime
= FALSE
;
595 retval
= hfs_update(vp
, HFS_UPDATE_FORCE
);
597 * When MNT_WAIT is requested push out the catalog record for
598 * this file. If they asked for a full fsync, we can skip this
599 * because the journal_flush or hfs_metasync_all will push out
600 * all of the metadata changes.
604 * As we are not supporting any write buf caches / delay writes,
605 * this is not needed.
607 if ((retval
== 0) && wait
&& fsync_default
&& cp
->c_hint
&&
608 !ISSET(cp
->c_flag
, C_DELETED
| C_NOEXISTS
)) {
609 hfs_metasync(VTOHFS(vp
), (daddr64_t
)cp
->c_hint
);
613 * If this was a full fsync, make sure all metadata
614 * changes get to stable storage.
618 if (VTOHFS(vp
)->jnl
) {
619 if (fsyncmode
== HFS_FSYNC_FULL
)
620 hfs_flush(VTOHFS(vp
), HFS_FLUSH_FULL
);
622 hfs_flush(VTOHFS(vp
), HFS_FLUSH_JOURNAL_BARRIER
);
626 retval
= hfs_metasync_all(VTOHFS(vp
));
627 hfs_flush(VTOHFS(vp
), HFS_FLUSH_CACHE
);
632 #if LF_HFS_FULL_VNODE_SUPPORT
633 if (!hfs_is_dirty(cp
) && !ISSET(cp
->c_flag
, C_DELETED
))
634 vnode_cleardirty(vp
);
643 * Similar to hfs_vnop_remove except there are additional options.
644 * This function may be used to remove directories if they have
645 * lots of EA's -- note the 'allow_dirs' argument.
647 * This function is able to delete blocks & fork data for the resource
648 * fork even if it does not exist in core (and have a backing vnode).
649 * It should infer the correct behavior based on the number of blocks
650 * in the cnode and whether or not the resource fork pointer exists or
651 * not. As a result, one only need pass in the 'vp' corresponding to the
652 * data fork of this file (or main vnode in the case of a directory).
653 * Passing in a resource fork will result in an error.
655 * Because we do not create any vnodes in this function, we are not at
656 * risk of deadlocking against ourselves by double-locking.
658 * Requires cnode and truncate locks to be held.
661 hfs_removefile(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
,
662 int flags
, int skip_reserve
, int allow_dirs
, int only_unlink
)
666 struct vnode
*rsrc_vp
= NULL
;
667 struct hfsmount
*hfsmp
;
668 struct cat_desc desc
;
669 int dataforkbusy
= 0;
670 int rsrcforkbusy
= 0;
674 int isbigfile
= 0, defer_remove
=0;
682 /* Check if we lost a race post lookup. */
683 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
687 if (!hfs_valid_cnode(hfsmp
, dvp
, cnp
, cp
->c_fileid
, NULL
, &error
))
692 /* Make sure a remove is permitted */
693 /* Don't allow deleting the journal or journal_info_block. */
694 if (VNODE_IS_RSRC(vp
) || vnode_issystem(vp
) || IsEntryAJnlFile(hfsmp
, cp
->c_fileid
))
696 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: Removing %s file is not premited\n", VNODE_IS_RSRC(vp
) ? "Resource" : (vnode_issystem(vp
)? "System" : "Journal"));
702 * We know it's a data fork.
703 * Probe the cnode to see if we have a valid resource fork
706 rsrc_vp
= cp
->c_rsrc_vp
;
710 * Hard links require special handling.
712 if (cp
->c_flag
& C_HARDLINK
)
714 /* A directory hard link with a link count of one is
715 * treated as a regular directory. Therefore it should
716 * only be removed using rmdir().
718 if (IS_DIR(vp
) && (cp
->c_linkcount
== 1) && (allow_dirs
== 0))
720 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: Trying to remove an hardlink directory\n");
724 return hfs_unlink(hfsmp
, dvp
, vp
, cnp
, skip_reserve
);
727 /* Directories should call hfs_rmdir! (unless they have a lot of attributes) */
732 return (EPERM
); /* POSIX */
737 /* Sanity check the parent ids. */
738 if ((cp
->c_parentcnid
!= hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
) &&
739 (cp
->c_parentcnid
!= dcp
->c_fileid
))
741 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: Parent ID's are wrong\n");
745 dcp
->c_flag
|= C_DIR_MODIFICATION
;
747 // this guy is going away so mark him as such
748 cp
->c_flag
|= C_DELETED
;
751 * If the caller was operating on a file (as opposed to a
752 * directory with EAs), then we need to figure out
753 * whether or not it has a valid resource fork vnode.
755 * If there was a valid resource fork vnode, then we need
756 * to use hfs_truncate to eliminate its data. If there is
757 * no vnode, then we hold the cnode lock which would
758 * prevent it from being created. As a result,
759 * we can use the data deletion functions which do not
760 * require that a cnode/vnode pair exist.
763 /* Check if this file is being used. */
766 dataforkbusy
= 0; /*vnode_isinuse(vp, 0);*/
768 * At this point, we know that 'vp' points to the
769 * a data fork because we checked it up front. And if
770 * there is no rsrc fork, rsrc_vp will be NULL.
772 if (rsrc_vp
&& (cp
->c_blocks
- VTOF(vp
)->ff_blocks
))
774 rsrcforkbusy
= 0; /*vnode_isinuse(rsrc_vp, 0);*/
777 /* Check if we have to break the deletion into multiple pieces. */
778 isbigfile
= cp
->c_datafork
->ff_size
>= HFS_BIGFILE_SIZE
;
781 /* Check if the file has xattrs. If it does we'll have to delete them in
782 individual transactions in case there are too many */
783 if ((hfsmp
->hfs_attribute_vp
!= NULL
) && (cp
->c_attr
.ca_recflags
& kHFSHasAttributesMask
) != 0)
788 /* If we are explicitly told to only unlink item and move to hidden dir, then do it */
795 * Carbon semantics prohibit deleting busy files.
796 * (enforced when VNODE_REMOVE_NODELETEBUSY is requested)
798 if (dataforkbusy
|| rsrcforkbusy
)
800 if ((flags
& VNODE_REMOVE_NODELETEBUSY
) || (hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
== 0))
808 * Do a ubc_setsize to indicate we need to wipe contents if:
809 * 1) item is a regular file.
810 * 2) Neither fork is busy AND we are not told to unlink this.
812 * We need to check for the defer_remove since it can be set without
813 * having a busy data or rsrc fork
815 if (isdir
== 0 && (!dataforkbusy
|| !rsrcforkbusy
) && (defer_remove
== 0))
818 * A ubc_setsize can cause a pagein so defer it
819 * until after the cnode lock is dropped. The
820 * cnode lock cannot be dropped/reacquired here
821 * since we might already hold the journal lock.
823 if (!dataforkbusy
&& cp
->c_datafork
->ff_blocks
&& !isbigfile
)
825 cp
->c_flag
|= C_NEED_DATA_SETSIZE
;
827 if (!rsrcforkbusy
&& rsrc_vp
)
829 cp
->c_flag
|= C_NEED_RSRC_SETSIZE
;
833 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
840 * Prepare to truncate any non-busy forks. Busy forks will
841 * get truncated when their vnode goes inactive.
842 * Note that we will only enter this region if we
843 * can avoid creating an open-unlinked file. If
844 * either region is busy, we will have to create an open
847 * Since we are deleting the file, we need to stagger the runtime
848 * modifications to do things in such a way that a crash won't
849 * result in us getting overlapped extents or any other
850 * bad inconsistencies. As such, we call prepare_release_storage
851 * which updates the UBC, updates quota information, and releases
852 * any loaned blocks that belong to this file. No actual
853 * truncation or bitmap manipulation is done until *AFTER*
854 * the catalog record is removed.
856 if (isdir
== 0 && (!dataforkbusy
&& !rsrcforkbusy
) && (only_unlink
== 0))
858 if (!dataforkbusy
&& !isbigfile
&& cp
->c_datafork
->ff_blocks
!= 0)
860 error
= hfs_prepare_release_storage (hfsmp
, vp
);
869 * If the resource fork vnode does not exist, we can skip this step.
871 if (!rsrcforkbusy
&& rsrc_vp
)
873 error
= hfs_prepare_release_storage (hfsmp
, rsrc_vp
);
883 * Protect against a race with rename by using the component
884 * name passed in and parent id from dvp (instead of using
885 * the cp->c_desc which may have changed). Also, be aware that
886 * because we allow directories to be passed in, we need to special case
887 * this temporary descriptor in case we were handed a directory.
891 desc
.cd_flags
= CD_ISDIR
;
897 desc
.cd_encoding
= cp
->c_desc
.cd_encoding
;
898 desc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
899 desc
.cd_namelen
= cnp
->cn_namelen
;
900 desc
.cd_parentcnid
= dcp
->c_fileid
;
901 desc
.cd_hint
= cp
->c_desc
.cd_hint
;
902 desc
.cd_cnid
= cp
->c_cnid
;
907 * There are two cases to consider:
908 * 1. File/Dir is busy/big/defer_remove ==> move/rename the file/dir
909 * 2. File is not in use ==> remove the file
911 * We can get a directory in case 1 because it may have had lots of attributes,
912 * which need to get removed here.
914 if (dataforkbusy
|| rsrcforkbusy
|| isbigfile
|| defer_remove
)
917 struct cat_desc to_desc
;
918 struct cat_desc todir_desc
;
921 * Orphan this file or directory (move to hidden directory).
922 * Again, we need to take care that we treat directories as directories,
923 * and files as files. Because directories with attributes can be passed in
924 * check to make sure that we have a directory or a file before filling in the
925 * temporary descriptor's flags. We keep orphaned directories AND files in
926 * the FILE_HARDLINKS private directory since we're generalizing over all
927 * orphaned filesystem objects.
929 bzero(&todir_desc
, sizeof(todir_desc
));
930 todir_desc
.cd_parentcnid
= 2;
932 MAKE_DELETED_NAME(delname
, sizeof(delname
), cp
->c_fileid
);
933 bzero(&to_desc
, sizeof(to_desc
));
934 to_desc
.cd_nameptr
= (const u_int8_t
*)delname
;
935 to_desc
.cd_namelen
= strlen(delname
);
936 to_desc
.cd_parentcnid
= hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
;
939 to_desc
.cd_flags
= CD_ISDIR
;
943 to_desc
.cd_flags
= 0;
945 to_desc
.cd_cnid
= cp
->c_cnid
;
947 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
950 if ((error
= cat_preflight(hfsmp
, CAT_RENAME
, NULL
)))
952 hfs_systemfile_unlock(hfsmp
, lockflags
);
957 error
= cat_rename(hfsmp
, &desc
, &todir_desc
, &to_desc
, (struct cat_desc
*)NULL
);
961 hfsmp
->hfs_private_attr
[FILE_HARDLINKS
].ca_entries
++;
964 INC_FOLDERCOUNT(hfsmp
, hfsmp
->hfs_private_attr
[FILE_HARDLINKS
]);
966 (void) cat_update(hfsmp
, &hfsmp
->hfs_private_desc
[FILE_HARDLINKS
], &hfsmp
->hfs_private_attr
[FILE_HARDLINKS
], NULL
, NULL
);
968 /* Update the parent directory */
969 if (dcp
->c_entries
> 0)
973 DEC_FOLDERCOUNT(hfsmp
, dcp
->c_attr
);
975 dcp
->c_dirchangecnt
++;
976 hfs_incr_gencount(dcp
);
978 dcp
->c_ctime
= tv
.tv_sec
;
979 dcp
->c_mtime
= tv
.tv_sec
;
980 (void) cat_update(hfsmp
, &dcp
->c_desc
, &dcp
->c_attr
, NULL
, NULL
);
982 /* Update the file or directory's state */
983 cp
->c_flag
|= C_DELETED
;
984 cp
->c_ctime
= tv
.tv_sec
;
986 (void) cat_update(hfsmp
, &to_desc
, &cp
->c_attr
, NULL
, NULL
);
989 hfs_systemfile_unlock(hfsmp
, lockflags
);
996 * Nobody is using this item; we can safely remove everything.
999 struct filefork
*temp_rsrc_fork
= NULL
;
1000 u_int32_t fileid
= cp
->c_fileid
;
1003 * Figure out if we need to read the resource fork data into
1004 * core before wiping out the catalog record.
1006 * 1) Must not be a directory
1007 * 2) cnode's c_rsrcfork ptr must be NULL.
1008 * 3) rsrc fork must have actual blocks
1010 if ((isdir
== 0) && (cp
->c_rsrcfork
== NULL
) && (cp
->c_blocks
- VTOF(vp
)->ff_blocks
))
1013 * The resource fork vnode & filefork did not exist.
1014 * Create a temporary one for use in this function only.
1016 temp_rsrc_fork
= hfs_mallocz(sizeof(struct filefork
));
1017 temp_rsrc_fork
->ff_cp
= cp
;
1018 rl_init(&temp_rsrc_fork
->ff_invalidranges
);
1021 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
| SFL_ATTRIBUTE
| SFL_BITMAP
, HFS_EXCLUSIVE_LOCK
);
1023 /* Look up the resource fork first, if necessary */
1026 error
= cat_lookup (hfsmp
, &desc
, 1, (struct cat_desc
*) NULL
, (struct cat_attr
*) NULL
, &temp_rsrc_fork
->ff_data
, NULL
);
1029 hfs_free(temp_rsrc_fork
);
1030 hfs_systemfile_unlock (hfsmp
, lockflags
);
1037 if ((error
= cat_preflight(hfsmp
, CAT_DELETE
, NULL
)))
1041 hfs_free(temp_rsrc_fork
);
1043 hfs_systemfile_unlock(hfsmp
, lockflags
);
1048 error
= cat_delete(hfsmp
, &desc
, &cp
->c_attr
);
1050 if (error
&& error
!= ENXIO
&& error
!= ENOENT
)
1052 LFHFS_LOG(LEVEL_ERROR
, "hfs_removefile: deleting file %s (id=%d) vol=%s err=%d\n",
1053 cp
->c_desc
.cd_nameptr
, cp
->c_attr
.ca_fileid
, hfsmp
->vcbVN
, error
);
1058 /* Update the parent directory */
1059 if (dcp
->c_entries
> 0)
1063 dcp
->c_dirchangecnt
++;
1064 hfs_incr_gencount(dcp
);
1066 dcp
->c_ctime
= tv
.tv_sec
;
1067 dcp
->c_mtime
= tv
.tv_sec
;
1068 (void) cat_update(hfsmp
, &dcp
->c_desc
, &dcp
->c_attr
, NULL
, NULL
);
1071 hfs_systemfile_unlock(hfsmp
, lockflags
);
1077 hfs_free(temp_rsrc_fork
);
1083 * Now that we've wiped out the catalog record, the file effectively doesn't
1084 * exist anymore. So update the quota records to reflect the loss of the
1085 * data fork and the resource fork.
1088 if (IS_LNK(vp
) && cp
->c_datafork
->ff_symlinkptr
)
1090 hfs_free(cp
->c_datafork
->ff_symlinkptr
);
1091 cp
->c_datafork
->ff_symlinkptr
= NULL
;
1095 * If we didn't get any errors deleting the catalog entry, then go ahead
1096 * and release the backing store now. The filefork pointers are still valid.
1100 error
= hfs_release_storage (hfsmp
, cp
->c_datafork
, temp_rsrc_fork
, fileid
);
1104 /* if cp->c_rsrcfork == NULL, hfs_release_storage will skip over it. */
1105 error
= hfs_release_storage (hfsmp
, cp
->c_datafork
, cp
->c_rsrcfork
, fileid
);
1110 * If we encountered an error updating the extents and bitmap,
1111 * mark the volume inconsistent. At this point, the catalog record has
1112 * already been deleted, so we can't recover it at this point. We need
1113 * to proceed and update the volume header and mark the cnode C_NOEXISTS.
1114 * The subsequent fsck should be able to recover the free space for us.
1116 hfs_mark_inconsistent(hfsmp
, HFS_OP_INCOMPLETE
);
1120 /* reset update_vh to 0, since hfs_release_storage should have done it for us */
1124 /* Get rid of the temporary rsrc fork */
1127 hfs_free(temp_rsrc_fork
);
1130 cp
->c_flag
|= C_NOEXISTS
;
1131 cp
->c_flag
&= ~C_DELETED
;
1133 cp
->c_touch_chgtime
= TRUE
;
1137 * We must never get a directory if we're in this else block. We could
1138 * accidentally drop the number of files in the volume header if we did.
1140 hfs_volupdate(hfsmp
, VOL_RMFILE
, (dcp
->c_cnid
== kHFSRootFolderID
));
1144 * All done with this cnode's descriptor...
1146 * Note: all future catalog calls for this cnode must be by
1147 * fileid only. This is OK for HFS (which doesn't have file
1148 * thread records) since HFS doesn't support the removal of
1151 cat_releasedesc(&cp
->c_desc
);
1156 cp
->c_flag
&= ~C_DELETED
;
1162 * If we bailed out earlier, we may need to update the volume header
1163 * to deal with the borrowed blocks accounting.
1165 hfs_volupdate (hfsmp
, VOL_UPDATE
, 0);
1170 hfs_end_transaction(hfsmp
);
1173 dcp
->c_flag
&= ~C_DIR_MODIFICATION
;
1174 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
1175 //wakeup((caddr_t)&dcp->c_flag);
1181 * Remove a file or link.
1184 hfs_vnop_remove(struct vnode
* psParentDir
,struct vnode
*psFileToRemove
, struct componentname
* psCN
, int iFlags
)
1186 struct cnode
*dcp
= VTOC(psParentDir
);
1187 struct cnode
*cp
= VTOC(psFileToRemove
);
1188 struct vnode
*rvp
= NULL
;
1191 if (psParentDir
== psFileToRemove
)
1198 hfs_lock_truncate(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
1200 if ((error
= hfs_lockpair(dcp
, cp
, HFS_EXCLUSIVE_LOCK
)))
1202 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
1205 hfs_chash_lower_OpenLookupCounter(cp
);
1212 * Lazily respond to determining if there is a valid resource fork
1213 * vnode attached to 'cp' if it is a regular file or symlink.
1214 * If the vnode does not exist, then we may proceed without having to
1217 * If, however, it does exist, then we need to acquire an iocount on the
1218 * vnode after acquiring its vid. This ensures that if we have to do I/O
1219 * against it, it can't get recycled from underneath us in the middle
1222 * Note: this function may be invoked for directory hardlinks, so just skip these
1223 * steps if 'vp' is a directory.
1225 enum vtype vtype
= psFileToRemove
->sFSParams
.vnfs_vtype
;
1226 if ((vtype
== VLNK
) || (vtype
== VREG
))
1228 if ((cp
->c_rsrc_vp
) && (rvp
== NULL
))
1230 /* We need to acquire the rsrc vnode */
1231 rvp
= cp
->c_rsrc_vp
;
1232 hfs_chash_raise_OpenLookupCounter(cp
);
1233 /* Unlock everything to acquire iocount on the rsrc vnode */
1234 hfs_unlock_truncate (cp
, HFS_LOCK_DEFAULT
);
1235 hfs_unlockpair (dcp
, cp
);
1242 * Check to see if we raced rmdir for the parent directory
1243 * hfs_removefile already checks for a race on vp/cp
1245 if (dcp
->c_flag
& (C_DELETED
| C_NOEXISTS
))
1251 error
= hfs_removefile(psParentDir
, psFileToRemove
, psCN
, iFlags
, 0, 0, 0);
1254 * Drop the truncate lock before unlocking the cnode
1255 * (which can potentially perform a vnode_put and
1256 * recycle the vnode which in turn might require the
1260 //Update Directory version
1261 psParentDir
->sExtraData
.sDirData
.uDirVersion
++;
1263 hfs_unlockpair(dcp
, cp
);
1264 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
1268 hfs_chash_lower_OpenLookupCounter(cp
);
1275 * Remove a directory.
1278 hfs_vnop_rmdir(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
* psCN
)
1281 struct cnode
*dcp
= VTOC(dvp
);
1282 struct cnode
*cp
= VTOC(vp
);
1284 if (!S_ISDIR(cp
->c_mode
))
1293 if ((error
= hfs_lockpair(dcp
, cp
, HFS_EXCLUSIVE_LOCK
)))
1298 /* Check for a race with rmdir on the parent directory */
1299 if (dcp
->c_flag
& (C_DELETED
| C_NOEXISTS
))
1301 hfs_unlockpair (dcp
, cp
);
1305 error
= hfs_removedir(dvp
, vp
, psCN
, 0, 0);
1307 hfs_unlockpair(dcp
, cp
);
1313 * Remove a directory
1315 * Both dvp and vp cnodes are locked
1318 hfs_removedir(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
, int skip_reserve
, int only_unlink
)
1322 struct hfsmount
* hfsmp
;
1323 struct cat_desc desc
;
1325 int error
= 0, started_tr
= 0;
1331 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)){
1335 if (cp
->c_entries
!= 0){
1339 /* Deal with directory hardlinks */
1340 if (cp
->c_flag
& C_HARDLINK
)
1343 * Note that if we have a directory which was a hardlink at any point,
1344 * its actual directory data is stored in the directory inode in the hidden
1345 * directory rather than the leaf element(s) present in the namespace.
1347 * If there are still other hardlinks to this directory,
1348 * then we'll just eliminate this particular link and the vnode will still exist.
1349 * If this is the last link to an empty directory, then we'll open-unlink the
1350 * directory and it will be only tagged with C_DELETED (as opposed to C_NOEXISTS).
1352 * We could also return EBUSY here.
1355 return hfs_unlink(hfsmp
, dvp
, vp
, cnp
, skip_reserve
);
1359 * In a few cases, we may want to allow the directory to persist in an
1360 * open-unlinked state. If the directory is being open-unlinked (still has usecount
1361 * references), or if it has EAs, or if it was being deleted as part of a rename,
1362 * then we go ahead and move it to the hidden directory.
1364 * If the directory is being open-unlinked, then we want to keep the catalog entry
1365 * alive so that future EA calls and fchmod/fstat etc. do not cause issues later.
1367 * If the directory had EAs, then we want to use the open-unlink trick so that the
1368 * EA removal is not done in one giant transaction. Otherwise, it could cause a panic
1369 * due to overflowing the journal.
1371 * Finally, if it was deleted as part of a rename, we move it to the hidden directory
1372 * in order to maintain rename atomicity.
1374 * Note that the allow_dirs argument to hfs_removefile specifies that it is
1375 * supposed to handle directories for this case.
1378 if (((hfsmp
->hfs_attribute_vp
!= NULL
) && ((cp
->c_attr
.ca_recflags
& kHFSHasAttributesMask
) != 0)) || (only_unlink
!= 0))
1381 int ret
= hfs_removefile(dvp
, vp
, cnp
, 0, 0, 1, only_unlink
);
1382 // Will be released in the layer above where it was created
1383 // vnode_recycle(vp);
1387 dcp
->c_flag
|= C_DIR_MODIFICATION
;
1389 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
1396 * Verify the directory is empty (and valid).
1397 * (Rmdir ".." won't be valid since
1398 * ".." will contain a reference to
1399 * the current directory and thus be
1402 if ((dcp
->c_bsdflags
& (UF_APPEND
| SF_APPEND
)) || (cp
->c_bsdflags
& ((UF_IMMUTABLE
| SF_IMMUTABLE
| UF_APPEND
| SF_APPEND
))))
1409 * Protect against a race with rename by using the component
1410 * name passed in and parent id from dvp (instead of using
1411 * the cp->c_desc which may have changed).
1413 desc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
1414 desc
.cd_namelen
= cnp
->cn_namelen
;
1415 desc
.cd_parentcnid
= dcp
->c_fileid
;
1416 desc
.cd_cnid
= cp
->c_cnid
;
1417 desc
.cd_flags
= CD_ISDIR
;
1418 desc
.cd_encoding
= cp
->c_encoding
;
1421 if (!hfs_valid_cnode(hfsmp
, dvp
, cnp
, cp
->c_fileid
, NULL
, &error
))
1427 /* Remove entry from catalog */
1428 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
| SFL_ATTRIBUTE
| SFL_BITMAP
, HFS_EXCLUSIVE_LOCK
);
1433 * Reserve some space in the Catalog file.
1435 if ((error
= cat_preflight(hfsmp
, CAT_DELETE
, NULL
)))
1437 hfs_systemfile_unlock(hfsmp
, lockflags
);
1442 error
= cat_delete(hfsmp
, &desc
, &cp
->c_attr
);
1446 /* The parent lost a child */
1447 if (dcp
->c_entries
> 0)
1449 DEC_FOLDERCOUNT(hfsmp
, dcp
->c_attr
);
1450 dcp
->c_dirchangecnt
++;
1451 hfs_incr_gencount(dcp
);
1453 dcp
->c_touch_chgtime
= TRUE
;
1454 dcp
->c_touch_modtime
= TRUE
;
1455 dcp
->c_flag
|= C_MODIFIED
;
1457 hfs_update(dcp
->c_vp
, 0);
1460 hfs_systemfile_unlock(hfsmp
, lockflags
);
1465 hfs_volupdate(hfsmp
, VOL_RMDIR
, (dcp
->c_cnid
== kHFSRootFolderID
));
1467 /* Mark C_NOEXISTS since the catalog entry is now gone */
1468 cp
->c_flag
|= C_NOEXISTS
;
1471 dvp
->sExtraData
.sDirData
.uDirVersion
++;
1473 dcp
->c_flag
&= ~C_DIR_MODIFICATION
;
1474 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
1475 // wakeup((caddr_t)&dcp->c_flag);
1479 hfs_end_transaction(hfsmp
);
1485 int hfs_vnop_setattr( vnode_t vp
, const UVFSFileAttributes
*attr
)
1488 if ( attr
->fa_validmask
== 0 )
1493 if ( ( attr
->fa_validmask
& READ_ONLY_FA_FIELDS
)
1494 /*|| ( attr->fa_validmask & ~VALID_IN_ATTR_MASK )*/)
1499 struct cnode
*cp
= NULL
;
1501 /* Don't allow modification of the journal. */
1502 struct hfsmount
*hfsmp
= VTOHFS(vp
);
1503 if (hfs_is_journal_file(hfsmp
, VTOC(vp
))) {
1508 * File size change request.
1509 * We are guaranteed that this is not a directory, and that
1510 * the filesystem object is writeable.
1513 if ( attr
->fa_validmask
& UVFS_FA_VALID_SIZE
)
1515 if (!vnode_isreg(vp
))
1517 if (vnode_isdir(vp
) || vnode_islnk(vp
))
1521 //otherwise return EINVAL
1525 // Take truncate lock
1526 hfs_lock_truncate(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
1528 // hfs_truncate will deal with the cnode lock
1529 err
= hfs_truncate(vp
, attr
->fa_size
, 0, 0);
1531 hfs_unlock_truncate(VTOC(vp
), HFS_LOCK_DEFAULT
);
1537 if ((err
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
1542 if ( attr
->fa_validmask
& UVFS_FA_VALID_UID
)
1544 cp
->c_flag
|= C_MODIFIED
;
1545 cp
->c_touch_chgtime
= TRUE
;
1546 cp
->c_uid
= attr
->fa_uid
;
1549 if ( attr
->fa_validmask
& UVFS_FA_VALID_GID
)
1551 cp
->c_flag
|= C_MODIFIED
;
1552 cp
->c_touch_chgtime
= TRUE
;
1553 cp
->c_gid
= attr
->fa_gid
;
1556 if ( attr
->fa_validmask
& UVFS_FA_VALID_MODE
)
1558 mode_t new_mode
= (cp
->c_mode
& ~ALLPERMS
) | (attr
->fa_mode
& ALLPERMS
);
1559 if (new_mode
!= cp
->c_mode
) {
1560 cp
->c_mode
= new_mode
;
1561 cp
->c_flag
|= C_MINOR_MOD
;
1565 if ( attr
->fa_validmask
& UVFS_FA_VALID_BSD_FLAGS
)
1567 cp
->c_bsdflags
= attr
->fa_bsd_flags
;
1571 * Timestamp updates.
1573 if ( attr
->fa_validmask
& UVFS_FA_VALID_ATIME
)
1575 cp
->c_atime
= attr
->fa_atime
.tv_sec
;
1576 cp
->c_touch_acctime
= FALSE
;
1579 if ( attr
->fa_validmask
& UVFS_FA_VALID_BIRTHTIME
)
1581 cp
->c_ctime
= attr
->fa_birthtime
.tv_sec
;
1584 if ( attr
->fa_validmask
& UVFS_FA_VALID_MTIME
)
1586 cp
->c_mtime
= attr
->fa_mtime
.tv_sec
;
1587 cp
->c_touch_modtime
= FALSE
;
1588 cp
->c_touch_chgtime
= TRUE
;
1590 hfs_clear_might_be_dirty_flag(cp
);
1593 err
= hfs_update(vp
, 0);
1595 /* Purge origin cache for cnode, since caller now has correct link ID for it
1596 * We purge it here since it was acquired for us during lookup, and we no longer need it.
1598 if ((cp
->c_flag
& C_HARDLINK
) && (!IS_DIR(vp
))){
1599 hfs_relorigin(cp
, 0);
1608 * Update a cnode's on-disk metadata.
1610 * The cnode must be locked exclusive. See declaration for possible
1614 hfs_update(struct vnode
*vp
, int options
)
1616 #pragma unused (options)
1618 struct cnode
*cp
= VTOC(vp
);
1619 const struct cat_fork
*dataforkp
= NULL
;
1620 const struct cat_fork
*rsrcforkp
= NULL
;
1621 struct cat_fork datafork
;
1622 struct cat_fork rsrcfork
;
1623 struct hfsmount
*hfsmp
;
1627 if (ISSET(cp
->c_flag
, C_NOEXISTS
))
1632 if (((vnode_issystem(vp
) && (cp
->c_cnid
< kHFSFirstUserCatalogNodeID
))) ||
1633 hfsmp
->hfs_catalog_vp
== NULL
){
1637 if ((hfsmp
->hfs_flags
& HFS_READ_ONLY
) || (cp
->c_mode
== 0)) {
1638 CLR(cp
->c_flag
, C_MODIFIED
| C_MINOR_MOD
| C_NEEDS_DATEADDED
);
1639 cp
->c_touch_acctime
= 0;
1640 cp
->c_touch_chgtime
= 0;
1641 cp
->c_touch_modtime
= 0;
1645 hfs_touchtimes(hfsmp
, cp
);
1647 if (!ISSET(cp
->c_flag
, C_MODIFIED
| C_MINOR_MOD
)
1648 && !hfs_should_save_atime(cp
)) {
1649 // Nothing to update
1653 bool check_txn
= false;
1654 if (!ISSET(options
, HFS_UPDATE_FORCE
) && !ISSET(cp
->c_flag
, C_MODIFIED
)) {
1656 * This must be a minor modification. If the current
1657 * transaction already has an update for this node, then we
1658 * bundle in the modification.
1661 && journal_current_txn(hfsmp
->jnl
) == cp
->c_update_txn
) {
1671 error
= hfs_start_transaction(hfsmp
);
1678 && journal_current_txn(hfsmp
->jnl
) != cp
->c_update_txn
) {
1679 hfs_end_transaction(hfsmp
);
1685 * Modify the values passed to cat_update based on whether or not
1686 * the file has invalid ranges or borrowed blocks.
1688 dataforkp
= hfs_prepare_fork_for_update(cp
->c_datafork
, NULL
, &datafork
, hfsmp
->blockSize
);
1689 rsrcforkp
= hfs_prepare_fork_for_update(cp
->c_rsrcfork
, NULL
, &rsrcfork
, hfsmp
->blockSize
);
1692 * Lock the Catalog b-tree file.
1694 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
1696 error
= cat_update(hfsmp
, &cp
->c_desc
, &cp
->c_attr
, dataforkp
, rsrcforkp
);
1699 cp
->c_update_txn
= journal_current_txn(hfsmp
->jnl
);
1701 hfs_systemfile_unlock(hfsmp
, lockflags
);
1703 CLR(cp
->c_flag
, C_MODIFIED
| C_MINOR_MOD
);
1705 hfs_end_transaction(hfsmp
);
1713 * Prepares a fork for cat_update by making sure ff_size and ff_blocks
1714 * are no bigger than the valid data on disk thus reducing the chance
1715 * of exposing uninitialised data in the event of a non clean unmount.
1716 * fork_buf is where to put the temporary copy if required. (It can
1719 const struct cat_fork
*
1720 hfs_prepare_fork_for_update(filefork_t
*ff
, const struct cat_fork
*cf
, struct cat_fork
*cf_buf
, uint32_t block_size
)
1728 cf_buf
= &ff
->ff_data
;
1730 off_t max_size
= ff
->ff_size
;
1732 if (!ff
->ff_unallocblocks
&& ff
->ff_size
<= max_size
)
1733 return cf
; // Nothing to do
1735 if (ff
->ff_blocks
< ff
->ff_unallocblocks
) {
1736 LFHFS_LOG(LEVEL_ERROR
, "hfs_prepare_fork_for_update: ff_blocks %d is less than unalloc blocks %d\n",
1737 ff
->ff_blocks
, ff
->ff_unallocblocks
);
1741 struct cat_fork
*out
= cf_buf
;
1744 bcopy(cf
, out
, sizeof(*cf
));
1746 // Adjust cf_blocks for cf_vblocks
1747 out
->cf_blocks
-= out
->cf_vblocks
;
1750 * Here we trim the size with the updated cf_blocks. This is
1751 * probably unnecessary now because the invalid ranges should
1752 * catch this (but that wasn't always the case).
1754 off_t alloc_bytes
= blk_to_bytes(out
->cf_blocks
, block_size
);
1755 if (out
->cf_size
> alloc_bytes
)
1756 out
->cf_size
= alloc_bytes
;
1758 // Trim cf_size to first invalid range
1759 if (out
->cf_size
> max_size
)
1760 out
->cf_size
= max_size
;
1766 * Read contents of a symbolic link.
1769 hfs_vnop_readlink( struct vnode
*vp
, void* data
, size_t dataSize
, size_t *actuallyRead
)
1772 struct filefork
*fp
;
1775 if (!vnode_islnk(vp
))
1777 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readlink: Received node is not a symlink\n");
1781 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
1786 /* Zero length sym links are not allowed */
1787 if (fp
->ff_size
== 0 || fp
->ff_size
> MAXPATHLEN
) {
1788 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readlink: Symlink is with invalid content length\n");
1793 if ( dataSize
< (size_t)fp
->ff_size
+1 )
1795 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_readlink: Received buffer size is too small\n");
1800 /* Cache the path so we don't waste buffer cache resources */
1801 if (fp
->ff_symlinkptr
== NULL
) {
1802 GenericLFBufPtr bp
= NULL
;
1804 fp
->ff_symlinkptr
= hfs_mallocz(fp
->ff_size
);
1805 if ( fp
->ff_symlinkptr
== NULL
)
1811 bp
= lf_hfs_generic_buf_allocate( vp
, 0, roundup((int)fp
->ff_size
, VTOHFS(vp
)->hfs_physical_block_size
), 0);
1812 error
= lf_hfs_generic_buf_read(bp
);
1814 lf_hfs_generic_buf_release(bp
);
1815 if (fp
->ff_symlinkptr
) {
1816 hfs_free(fp
->ff_symlinkptr
);
1817 fp
->ff_symlinkptr
= NULL
;
1821 bcopy(bp
->pvData
, fp
->ff_symlinkptr
, (size_t)fp
->ff_size
);
1822 lf_hfs_generic_buf_release(bp
);
1825 memcpy(data
, fp
->ff_symlinkptr
, fp
->ff_size
);
1826 ((uint8_t*)data
)[fp
->ff_size
] = 0;
1827 *actuallyRead
= fp
->ff_size
+1;
1838 hfs_vnop_mkdir(vnode_t a_dvp
, vnode_t
*a_vpp
, struct componentname
*a_cnp
, UVFSFileAttributes
* a_vap
)
1842 /***** HACK ALERT ********/
1843 a_cnp
->cn_flags
|= MAKEENTRY
;
1844 a_vap
->fa_type
= UVFS_FA_TYPE_DIR
;
1846 iErr
= hfs_makenode(a_dvp
, a_vpp
, a_cnp
, a_vap
);
1849 CRASH_ABORT(CRASH_ABORT_MAKE_DIR
, a_dvp
->mount
, NULL
);
1856 * Create a regular file.
1859 hfs_vnop_create(vnode_t a_dvp
, vnode_t
*a_vpp
, struct componentname
*a_cnp
, UVFSFileAttributes
* a_vap
)
1861 a_vap
->fa_type
= UVFS_FA_TYPE_FILE
;
1862 return hfs_makenode(a_dvp
, a_vpp
, a_cnp
, a_vap
);
1866 * Allocate a new node
1869 hfs_makenode(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
, UVFSFileAttributes
*psGivenAttr
)
1871 struct hfsmount
*hfsmp
= VTOHFS(dvp
);
1872 struct cnode
*dcp
= NULL
;
1873 struct cnode
*cp
= NULL
;
1874 struct vnode
*tvp
= NULL
;
1875 enum vtype vnodetype
= UVFSTOV(psGivenAttr
->fa_type
);
1876 mode_t mode
= MAKEIMODE(vnodetype
);
1877 struct cat_attr attr
= {0};
1879 int error
, started_tr
= 0;
1881 int newvnode_flags
= 0;
1882 u_int32_t gnv_flags
= 0;
1884 struct cat_desc out_desc
= {0};
1885 out_desc
.cd_flags
= 0;
1886 out_desc
.cd_nameptr
= NULL
;
1888 if ((error
= hfs_lock(VTOC(dvp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
)))
1892 /* Don't allow creation of new entries in open-unlinked directories */
1893 if (dcp
->c_flag
& (C_DELETED
| C_NOEXISTS
))
1899 if ( !(psGivenAttr
->fa_validmask
& UVFS_FA_VALID_MODE
) && (vnodetype
!= VDIR
) )
1901 LFHFS_LOG(LEVEL_ERROR
, "hfs_makenode: Invalid mode or type[%#llx, %d]",
1902 (unsigned long long)psGivenAttr
->fa_validmask
, psGivenAttr
->fa_type
);
1907 if ( ( psGivenAttr
->fa_validmask
& READ_ONLY_FA_FIELDS
) /*|| ( psGivenAttr->fa_validmask & ~VALID_IN_ATTR_MASK )*/ )
1909 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
);
1914 dcp
->c_flag
|= C_DIR_MODIFICATION
;
1918 /* Check if were out of usable disk space. */
1919 if (hfs_freeblks(hfsmp
, 1) == 0)
1928 /* Setup the default attributes */
1929 if ( psGivenAttr
->fa_validmask
& UVFS_FA_VALID_MODE
)
1931 mode
= (mode
& ~ALLPERMS
) | (psGivenAttr
->fa_mode
& ALLPERMS
);
1934 attr
.ca_mode
= mode
;
1935 attr
.ca_linkcount
= 1;
1936 attr
.ca_itime
= tv
.tv_sec
;
1937 attr
.ca_atime
= attr
.ca_ctime
= attr
.ca_mtime
= attr
.ca_itime
;
1938 attr
.ca_atimeondisk
= attr
.ca_atime
;
1941 * HFS+ only: all files get ThreadExists
1943 if (vnodetype
== VDIR
)
1945 if (hfsmp
->hfs_flags
& HFS_FOLDERCOUNT
)
1947 attr
.ca_recflags
= kHFSHasFolderCountMask
;
1952 attr
.ca_recflags
= kHFSThreadExistsMask
;
1956 * Add the date added to the item. See above, as
1957 * all of the dates are set to the itime.
1959 hfs_write_dateadded (&attr
, attr
.ca_atime
);
1961 /* Initialize the gen counter to 1 */
1962 hfs_write_gencount(&attr
, (uint32_t)1);
1964 if ( psGivenAttr
->fa_validmask
& UVFS_FA_VALID_UID
)
1966 attr
.ca_uid
= psGivenAttr
->fa_uid
;
1969 if ( psGivenAttr
->fa_validmask
& UVFS_FA_VALID_GID
)
1971 attr
.ca_gid
= psGivenAttr
->fa_gid
;
1974 /* Tag symlinks with a type and creator. */
1975 if (vnodetype
== VLNK
)
1977 struct FndrFileInfo
*fip
;
1979 fip
= (struct FndrFileInfo
*)&attr
.ca_finderinfo
;
1980 fip
->fdType
= SWAP_BE32(kSymLinkFileType
);
1981 fip
->fdCreator
= SWAP_BE32(kSymLinkCreator
);
1984 /* Setup the descriptor */
1985 struct cat_desc in_desc
={0};
1986 in_desc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
1987 in_desc
.cd_namelen
= cnp
->cn_namelen
;
1988 in_desc
.cd_parentcnid
= dcp
->c_fileid
;
1989 in_desc
.cd_flags
= S_ISDIR(mode
) ? CD_ISDIR
: 0;
1990 in_desc
.cd_hint
= dcp
->c_childhint
;
1991 in_desc
.cd_encoding
= 0;
1993 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
1999 // have to also lock the attribute file because cat_create() needs
2000 // to check that any fileID it wants to use does not have orphaned
2001 // attributes in it.
2002 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
| SFL_ATTRIBUTE
, HFS_EXCLUSIVE_LOCK
);
2005 /* Reserve some space in the Catalog file. */
2006 error
= cat_preflight(hfsmp
, CAT_CREATE
, NULL
);
2009 hfs_systemfile_unlock(hfsmp
, lockflags
);
2013 error
= cat_acquire_cnid(hfsmp
, &new_id
);
2016 hfs_systemfile_unlock (hfsmp
, lockflags
);
2020 error
= cat_create(hfsmp
, new_id
, &in_desc
, &attr
, &out_desc
);
2022 /* Update the parent directory */
2023 dcp
->c_childhint
= out_desc
.cd_hint
; /* Cache directory's location */
2026 if (vnodetype
== VDIR
)
2028 INC_FOLDERCOUNT(hfsmp
, dcp
->c_attr
);
2030 dcp
->c_dirchangecnt
++;
2031 hfs_incr_gencount(dcp
);
2033 dcp
->c_touch_chgtime
= dcp
->c_touch_modtime
= true;
2034 dcp
->c_flag
|= C_MODIFIED
;
2036 hfs_update(dcp
->c_vp
, 0);
2038 hfs_systemfile_unlock(hfsmp
, lockflags
);
2042 uint32_t txn
= hfsmp
->jnl
? journal_current_txn(hfsmp
->jnl
) : 0;
2044 hfs_volupdate(hfsmp
, vnodetype
== VDIR
? VOL_MKDIR
: VOL_MKFILE
, (dcp
->c_cnid
== kHFSRootFolderID
));
2047 // have to end the transaction here before we call hfs_getnewvnode()
2048 // because that can cause us to try and reclaim a vnode on a different
2049 // file system which could cause us to start a transaction which can
2050 // deadlock with someone on that other file system (since we could be
2051 // holding two transaction locks as well as various vnodes and we did
2052 // not obtain the locks on them in the proper order).
2054 // NOTE: this means that if the quota check fails or we have to update
2055 // the change time on a block-special device that those changes
2056 // will happen as part of independent transactions.
2060 hfs_end_transaction(hfsmp
);
2064 gnv_flags
|= GNV_CREATE
;
2067 gnv_flags
|= GNV_NOCACHE
;
2071 * Create a vnode for the object just created.
2073 * NOTE: Maintaining the cnode lock on the parent directory is important,
2074 * as it prevents race conditions where other threads want to look up entries
2075 * in the directory and/or add things as we are in the process of creating
2076 * the vnode below. However, this has the potential for causing a
2077 * double lock panic when dealing with shadow files on a HFS boot partition.
2078 * The panic could occur if we are not cleaning up after ourselves properly
2079 * when done with a shadow file or in the error cases. The error would occur if we
2080 * try to create a new vnode, and then end up reclaiming another shadow vnode to
2081 * create the new one. However, if everything is working properly, this should
2082 * be a non-issue as we would never enter that reclaim codepath.
2084 * The cnode is locked on successful return.
2086 error
= hfs_getnewvnode(hfsmp
, dvp
, cnp
, &out_desc
, gnv_flags
, &attr
,
2087 NULL
, &tvp
, &newvnode_flags
);
2093 cp
->c_update_txn
= txn
;
2098 cat_releasedesc(&out_desc
);
2100 //Update Directory version
2101 dvp
->sExtraData
.sDirData
.uDirVersion
++;
2104 * Make sure we release cnode lock on dcp.
2108 dcp
->c_flag
&= ~C_DIR_MODIFICATION
;
2110 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
2111 //wakeup((caddr_t)&dcp->c_flag);
2119 hfs_end_transaction(hfsmp
);
2126 * Create a symbolic link.
2129 hfs_vnop_symlink(struct vnode
*dvp
, struct vnode
**vpp
, struct componentname
*cnp
, char* symlink_content
, UVFSFileAttributes
*attrp
)
2131 struct vnode
*vp
= NULL
;
2132 struct cnode
*cp
= NULL
;
2133 struct hfsmount
*hfsmp
;
2134 struct filefork
*fp
;
2135 GenericLFBufPtr bp
= NULL
;
2141 hfsmp
= VTOHFS(dvp
);
2143 len
= strlen(symlink_content
);
2144 if (len
> MAXPATHLEN
)
2146 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_symlink: Received symlink content too long\n");
2147 return (ENAMETOOLONG
);
2152 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_symlink: Received zero length symlink content\n");
2156 /* Check for free space */
2157 if (((u_int64_t
)hfs_freeblks(hfsmp
, 0) * (u_int64_t
)hfsmp
->blockSize
) < len
) {
2161 attrp
->fa_type
= UVFS_FA_TYPE_SYMLINK
;
2162 attrp
->fa_mode
|= S_IFLNK
;
2163 attrp
->fa_validmask
|= UVFS_FA_VALID_MODE
;
2165 /* Create the vnode */
2166 if ((error
= hfs_makenode(dvp
, vpp
, cnp
, attrp
))) {
2170 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
))) {
2176 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
2181 (void)hfs_getinoquota(cp
);
2184 if ((error
= hfs_start_transaction(hfsmp
)) != 0) {
2190 * Allocate space for the link.
2192 * Since we're already inside a transaction,
2194 * Don't need truncate lock since a symlink is treated as a system file.
2196 error
= hfs_truncate(vp
, len
, IO_NOZEROFILL
, 0);
2198 /* On errors, remove the symlink file */
2201 * End the transaction so we don't re-take the cnode lock
2202 * below while inside a transaction (lock order violation).
2204 hfs_end_transaction(hfsmp
);
2205 /* hfs_removefile() requires holding the truncate lock */
2207 hfs_lock_truncate(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
2208 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_ALLOW_NOEXISTS
);
2210 if (hfs_start_transaction(hfsmp
) != 0) {
2212 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
2216 (void) hfs_removefile(dvp
, vp
, cnp
, 0, 0, 0, 0);
2217 hfs_unlock_truncate(cp
, HFS_LOCK_DEFAULT
);
2221 /* Write the sym-link to disk */
2222 bp
= lf_hfs_generic_buf_allocate( vp
, 0, roundup((int)fp
->ff_size
, hfsmp
->hfs_physical_block_size
), 0);
2223 error
= lf_hfs_generic_buf_read( bp
);
2231 journal_modify_block_start(hfsmp
->jnl
, bp
);
2234 assert(bp
->uDataSize
>= len
);
2235 bzero(datap
, bp
->uDataSize
);
2236 bcopy(symlink_content
, datap
, len
);
2239 journal_modify_block_end(hfsmp
->jnl
, bp
, NULL
, NULL
);
2240 bp
= NULL
; // block will be released by the journal
2244 error
= lf_hfs_generic_buf_write(bp
);
2252 hfs_end_transaction(hfsmp
);
2254 if ((cp
!= NULL
) && (vp
!= NULL
)) {
2265 lf_hfs_generic_buf_release(bp
);
2268 hfs_flush(hfsmp
, HFS_FLUSH_FULL
);
2276 * The VFS layer guarantees that:
2277 * - source and destination will either both be directories, or
2278 * both not be directories.
2279 * - all the vnodes are from the same file system
2281 * When the target is a directory, HFS must ensure that its empty.
2283 * Note that this function requires up to 6 vnodes in order to work properly
2284 * if it is operating on files (and not on directories). This is because only
2285 * files can have resource forks, and we now require iocounts to be held on the
2286 * vnodes corresponding to the resource forks (if applicable) as well as
2287 * the files or directories undergoing rename. The problem with not holding
2288 * iocounts on the resource fork vnodes is that it can lead to a deadlock
2289 * situation: The rsrc fork of the source file may be recycled and reclaimed
2290 * in order to provide a vnode for the destination file's rsrc fork. Since
2291 * data and rsrc forks share the same cnode, we'd eventually try to lock the
2292 * source file's cnode in order to sync its rsrc fork to disk, but it's already
2293 * been locked. By taking the rsrc fork vnodes up front we ensure that they
2294 * cannot be recycled, and that the situation mentioned above cannot happen.
2297 hfs_vnop_renamex(struct vnode
*fdvp
,struct vnode
*fvp
, struct componentname
*fcnp
, struct vnode
*tdvp
, struct vnode
*tvp
, struct componentname
*tcnp
)
2301 * Note that we only need locals for the target/destination's
2302 * resource fork vnode (and only if necessary). We don't care if the
2303 * source has a resource fork vnode or not.
2305 struct vnode
*tvp_rsrc
= NULL
;
2306 struct cnode
*tcp
= NULL
;
2307 struct cnode
*error_cnode
;
2308 struct cat_desc from_desc
;
2310 struct hfsmount
*hfsmp
= VTOHFS(tdvp
);
2311 int tvp_deleted
= 0;
2312 int started_tr
= 0, got_cookie
= 0;
2313 int took_trunc_lock
= 0;
2317 int rename_exclusive
= 0;
2320 /* When tvp exists, take the truncate lock for hfs_removefile(). */
2321 if (tvp
&& (vnode_isreg(tvp
) || vnode_islnk(tvp
))) {
2322 hfs_lock_truncate(VTOC(tvp
), HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
2323 took_trunc_lock
= 1;
2326 if (tvp
&& VTOC(tvp
) == NULL
)
2329 error
= hfs_lockfour(VTOC(fdvp
), VTOC(fvp
), VTOC(tdvp
), tvp
? VTOC(tvp
) : NULL
, HFS_EXCLUSIVE_LOCK
, &error_cnode
);
2332 if (took_trunc_lock
)
2334 hfs_unlock_truncate(VTOC(tvp
), HFS_LOCK_DEFAULT
);
2335 took_trunc_lock
= 0;
2339 * We hit an error path. If we were trying to re-acquire the locks
2340 * after coming through here once, we might have already obtained
2341 * an iocount on tvp's resource fork vnode. Drop that before dealing
2342 * with the failure. Note this is safe -- since we are in an
2343 * error handling path, we can't be holding the cnode locks.
2345 if (tvp_rsrc
&& tcp
)
2347 hfs_chash_lower_OpenLookupCounter(tcp
);
2352 * tvp might no longer exist. If the cause of the lock failure
2353 * was tvp, then we can try again with tvp/tcp set to NULL.
2354 * This is ok because the vfs syscall will vnode_put the vnodes
2355 * after we return from hfs_vnop_rename.
2357 if ((error
== ENOENT
) && (tvp
!= NULL
) && (error_cnode
== VTOC(tvp
))) {
2363 /* If we want to reintroduce notifications for failed renames, this
2364 is the place to do it. */
2369 struct cnode
* fdcp
= VTOC(fdvp
);
2370 struct cnode
* fcp
= VTOC(fvp
);
2371 struct cnode
* tdcp
= VTOC(tdvp
);
2372 tcp
= tvp
? VTOC(tvp
) : NULL
;
2375 * If caller requested an exclusive rename (VFS_RENAME_EXCL) and 'tcp' exists
2376 * then we must fail the operation.
2378 if (tcp
&& rename_exclusive
)
2385 * Acquire iocounts on the destination's resource fork vnode
2386 * if necessary. If dst/src are files and the dst has a resource
2387 * fork vnode, then we need to try and acquire an iocount on the rsrc vnode.
2388 * If it does not exist, then we don't care and can skip it.
2390 if ((vnode_isreg(fvp
)) || (vnode_islnk(fvp
)))
2392 if ((tvp
) && (tcp
->c_rsrc_vp
) && (tvp_rsrc
== NULL
))
2394 tvp_rsrc
= tcp
->c_rsrc_vp
;
2395 hfs_chash_raise_OpenLookupCounter(tcp
);
2397 /* Unlock everything to acquire iocount on this rsrc vnode */
2398 if (took_trunc_lock
)
2400 hfs_unlock_truncate (VTOC(tvp
), HFS_LOCK_DEFAULT
);
2401 took_trunc_lock
= 0;
2404 hfs_unlockfour(fdcp
, fcp
, tdcp
, tcp
);
2410 /* Ensure we didn't race src or dst parent directories with rmdir. */
2411 if (fdcp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
2417 if (tdcp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
2424 /* Check for a race against unlink. The hfs_valid_cnode checks validate
2425 * the parent/child relationship with fdcp and tdcp, as well as the
2426 * component name of the target cnodes.
2428 if ((fcp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) || !hfs_valid_cnode(hfsmp
, fdvp
, fcnp
, fcp
->c_fileid
, NULL
, &error
))
2434 if (tcp
&& ((tcp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) || !hfs_valid_cnode(hfsmp
, tdvp
, tcnp
, tcp
->c_fileid
, NULL
, &error
)))
2437 // hmm, the destination vnode isn't valid any more.
2438 // in this case we can just drop him and pretend he
2439 // never existed in the first place.
2441 if (took_trunc_lock
)
2443 hfs_unlock_truncate(VTOC(tvp
), HFS_LOCK_DEFAULT
);
2444 took_trunc_lock
= 0;
2448 hfs_unlockfour(fdcp
, fcp
, tdcp
, tcp
);
2453 // retry the locking with tvp null'ed out
2457 fdcp
->c_flag
|= C_DIR_MODIFICATION
;
2460 tdcp
->c_flag
|= C_DIR_MODIFICATION
;
2464 * Disallow renaming of a directory hard link if the source and
2465 * destination parent directories are different, or a directory whose
2466 * descendant is a directory hard link and the one of the ancestors
2467 * of the destination directory is a directory hard link.
2469 if (vnode_isdir(fvp
) && (fdvp
!= tdvp
))
2471 if (fcp
->c_flag
& C_HARDLINK
) {
2475 if (fcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
)
2477 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
2478 if (cat_check_link_ancestry(hfsmp
, tdcp
->c_fileid
, 0))
2481 hfs_systemfile_unlock(hfsmp
, lockflags
);
2484 hfs_systemfile_unlock(hfsmp
, lockflags
);
2489 * The following edge case is caught here:
2490 * (to cannot be a descendent of from)
2503 if (tdcp
->c_parentcnid
== fcp
->c_fileid
)
2510 * The following two edge cases are caught here:
2511 * (note tvp is not empty)
2524 if (tvp
&& vnode_isdir(tvp
) && (tcp
->c_entries
!= 0) && fvp
!= tvp
)
2531 * The following edge case is caught here:
2532 * (the from child and parent are the same)
2546 * Make sure "from" vnode and its parent are changeable.
2548 if ((fcp
->c_bsdflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
| UF_APPEND
| SF_APPEND
)) || (fdcp
->c_bsdflags
& (UF_APPEND
| SF_APPEND
)))
2554 /* Don't allow modification of the journal or journal_info_block */
2555 if (hfs_is_journal_file(hfsmp
, fcp
) || (tcp
&& hfs_is_journal_file(hfsmp
, tcp
)))
2561 struct cat_desc out_desc
= {0};
2562 from_desc
.cd_nameptr
= (const u_int8_t
*)fcnp
->cn_nameptr
;
2563 from_desc
.cd_namelen
= fcnp
->cn_namelen
;
2564 from_desc
.cd_parentcnid
= fdcp
->c_fileid
;
2565 from_desc
.cd_flags
= fcp
->c_desc
.cd_flags
& ~(CD_HASBUF
| CD_DECOMPOSED
);
2566 from_desc
.cd_cnid
= fcp
->c_cnid
;
2568 struct cat_desc to_desc
= {0};
2569 to_desc
.cd_nameptr
= (const u_int8_t
*)tcnp
->cn_nameptr
;
2570 to_desc
.cd_namelen
= tcnp
->cn_namelen
;
2571 to_desc
.cd_parentcnid
= tdcp
->c_fileid
;
2572 to_desc
.cd_flags
= fcp
->c_desc
.cd_flags
& ~(CD_HASBUF
| CD_DECOMPOSED
);
2573 to_desc
.cd_cnid
= fcp
->c_cnid
;
2575 if ((error
= hfs_start_transaction(hfsmp
)) != 0)
2581 /* hfs_vnop_link() and hfs_vnop_rename() set kHFSHasChildLinkMask
2582 * inside a journal transaction and without holding a cnode lock.
2583 * As setting of this bit depends on being in journal transaction for
2584 * concurrency, check this bit again after we start journal transaction for rename
2585 * to ensure that this directory does not have any descendant that
2586 * is a directory hard link.
2588 if (vnode_isdir(fvp
) && (fdvp
!= tdvp
))
2590 if (fcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
)
2592 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
2593 if (cat_check_link_ancestry(hfsmp
, tdcp
->c_fileid
, 0)) {
2595 hfs_systemfile_unlock(hfsmp
, lockflags
);
2598 hfs_systemfile_unlock(hfsmp
, lockflags
);
2602 // if it's a hardlink then re-lookup the name so
2603 // that we get the correct cnid in from_desc (see
2604 // the comment in hfs_removefile for more details)
2605 if (fcp
->c_flag
& C_HARDLINK
)
2607 struct cat_desc tmpdesc
;
2610 tmpdesc
.cd_nameptr
= (const u_int8_t
*)fcnp
->cn_nameptr
;
2611 tmpdesc
.cd_namelen
= fcnp
->cn_namelen
;
2612 tmpdesc
.cd_parentcnid
= fdcp
->c_fileid
;
2613 tmpdesc
.cd_hint
= fdcp
->c_childhint
;
2614 tmpdesc
.cd_flags
= fcp
->c_desc
.cd_flags
& CD_ISDIR
;
2615 tmpdesc
.cd_encoding
= 0;
2617 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
2619 if (cat_lookup(hfsmp
, &tmpdesc
, 0, NULL
, NULL
, NULL
, &real_cnid
) != 0)
2621 hfs_systemfile_unlock(hfsmp
, lockflags
);
2625 // use the real cnid instead of whatever happened to be there
2626 from_desc
.cd_cnid
= real_cnid
;
2627 hfs_systemfile_unlock(hfsmp
, lockflags
);
2631 * Reserve some space in the Catalog file.
2633 cat_cookie_t cookie
;
2634 if ((error
= cat_preflight(hfsmp
, CAT_RENAME
+ CAT_DELETE
, &cookie
)))
2641 * If the destination exists then it may need to be removed.
2643 * Due to HFS's locking system, we should always move the
2644 * existing 'tvp' element to the hidden directory in hfs_vnop_rename.
2645 * Because the VNOP_LOOKUP call enters and exits the filesystem independently
2646 * of the actual vnop that it was trying to do (stat, link, readlink),
2647 * we must release the cnode lock of that element during the interim to
2648 * do MAC checking, vnode authorization, and other calls. In that time,
2649 * the item can be deleted (or renamed over). However, only in the rename
2650 * case is it inappropriate to return ENOENT from any of those calls. Either
2651 * the call should return information about the old element (stale), or get
2652 * information about the newer element that we are about to write in its place.
2654 * HFS lookup has been modified to detect a rename and re-drive its
2655 * lookup internally. For other calls that have already succeeded in
2656 * their lookup call and are waiting to acquire the cnode lock in order
2657 * to proceed, that cnode lock will not fail due to the cnode being marked
2658 * C_NOEXISTS, because it won't have been marked as such. It will only
2659 * have C_DELETED. Thus, they will simply act on the stale open-unlinked
2660 * element. All future callers will get the new element.
2662 * To implement this behavior, we pass the "only_unlink" argument to
2663 * hfs_removefile and hfs_removedir. This will result in the vnode acting
2664 * as though it is open-unlinked. Additionally, when we are done moving the
2665 * element to the hidden directory, we vnode_recycle the target so that it is
2666 * reclaimed as soon as possible. Reclaim and inactive are both
2667 * capable of clearing out unused blocks for an open-unlinked file or dir.
2672 * When fvp matches tvp they could be case variants
2673 * or matching hard links.
2677 if (!(fcp
->c_flag
& C_HARDLINK
))
2680 * If they're not hardlinks, then fvp == tvp must mean we
2681 * are using case-insensitive HFS because case-sensitive would
2682 * not use the same vnode for both. In this case we just update
2683 * the catalog for: a -> A
2685 goto skip_rm
; /* simple case variant */
2688 /* For all cases below, we must be using hardlinks */
2689 else if ((fdvp
!= tdvp
) || (hfsmp
->hfs_flags
& HFS_CASE_SENSITIVE
))
2692 * If the parent directories are not the same, AND the two items
2693 * are hardlinks, posix says to do nothing:
2694 * dir1/fred <-> dir2/bob and the op was mv dir1/fred -> dir2/bob
2695 * We just return 0 in this case.
2697 * If case sensitivity is on, and we are using hardlinks
2698 * then renaming is supposed to do nothing.
2699 * dir1/fred <-> dir2/FRED, and op == mv dir1/fred -> dir2/FRED
2704 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)
2707 * If we get here, then the following must be true:
2708 * a) We are running case-insensitive HFS+.
2709 * b) Both paths 'fvp' and 'tvp' are in the same parent directory.
2710 * c) the two names are case-variants of each other.
2712 * In this case, we are really only dealing with a single catalog record
2713 * whose name is being updated.
2715 * op is dir1/fred -> dir1/FRED
2717 * We need to special case the name matching, because if
2718 * dir1/fred <-> dir1/bob were the two links, and the
2719 * op was dir1/fred -> dir1/bob
2720 * That would fail/do nothing.
2722 goto skip_rm
; /* case-variant hardlink in the same dir */
2726 goto out
; /* matching hardlink, nothing to do */
2731 if (vnode_isdir(tvp
))
2734 * hfs_removedir will eventually call hfs_removefile on the directory
2735 * we're working on, because only hfs_removefile does the renaming of the
2736 * item to the hidden directory. The directory will stay around in the
2737 * hidden directory with C_DELETED until it gets an inactive or a reclaim.
2738 * That way, we can destroy all of the EAs as needed and allow new ones to be
2741 error
= hfs_removedir(tdvp
, tvp
, tcnp
, HFSRM_SKIP_RESERVE
, 0);
2745 error
= hfs_removefile(tdvp
, tvp
, tcnp
, 0, HFSRM_SKIP_RESERVE
, 0, 0);
2748 * If the destination file had a resource fork vnode, then we need to get rid of
2749 * its blocks when there are no more references to it. Because the call to
2750 * hfs_removefile above always open-unlinks things, we need to force an inactive/reclaim
2751 * on the resource fork vnode, in order to prevent block leaks. Otherwise,
2752 * the resource fork vnode could prevent the data fork vnode from going out of scope
2753 * because it holds a v_parent reference on it. So we mark it for termination
2754 * with a call to vnode_recycle. hfs_vnop_reclaim has been modified so that it
2755 * can clean up the blocks of open-unlinked files and resource forks.
2757 * We can safely call vnode_recycle on the resource fork because we took an iocount
2758 * reference on it at the beginning of the function.
2761 if ((error
== 0) && (tcp
->c_flag
& C_DELETED
) && (tvp_rsrc
))
2763 hfs_chash_lower_OpenLookupCounter(tcp
);
2775 if ( ((VTOC(tvp
)->c_flag
& C_HARDLINK
) == 0 ) || (VTOC(tvp
)->c_linkcount
== 0) )
2777 INVALIDATE_NODE(tvp
);
2780 /* Mark 'tcp' as being deleted due to a rename */
2781 tcp
->c_flag
|= C_RENAMED
;
2784 * Aggressively mark tvp/tcp for termination to ensure that we recover all blocks
2785 * as quickly as possible.
2787 //TBD -- Need to see what we are doing with recycle
2788 // vnode_recycle(tvp);
2793 * All done with tvp and fvp.
2795 * We also jump to this point if there was no destination observed during lookup and namei.
2796 * However, because only iocounts are held at the VFS layer, there is nothing preventing a
2797 * competing thread from racing us and creating a file or dir at the destination of this rename
2798 * operation. If this occurs, it may cause us to get a spurious EEXIST out of the cat_rename
2799 * call below. To preserve rename's atomicity, we need to signal VFS to re-drive the
2800 * namei/lookup and restart the rename operation. EEXIST is an allowable errno to be bubbled
2801 * out of the rename syscall, but not for this reason, since it is a synonym errno for ENOTEMPTY.
2802 * To signal VFS, we return ERECYCLE (which is also used for lookup restarts). This errno
2803 * will be swallowed and it will restart the operation.
2806 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
2807 error
= cat_rename(hfsmp
, &from_desc
, &tdcp
->c_desc
, &to_desc
, &out_desc
);
2808 hfs_systemfile_unlock(hfsmp
, lockflags
);
2812 if (error
== EEXIST
)
2819 /* Update cnode's catalog descriptor */
2820 replace_desc(fcp
, &out_desc
);
2821 fcp
->c_parentcnid
= tdcp
->c_fileid
;
2825 * Now indicate this cnode needs to have date-added written to the
2826 * finderinfo, but only if moving to a different directory, or if
2827 * it doesn't already have it.
2829 if (fdvp
!= tdvp
|| !ISSET(fcp
->c_attr
.ca_recflags
, kHFSHasDateAddedMask
))
2830 fcp
->c_flag
|= C_NEEDS_DATEADDED
;
2832 (void) hfs_update (fvp
, 0);
2834 hfs_volupdate(hfsmp
, vnode_isdir(fvp
) ? VOL_RMDIR
: VOL_RMFILE
, (fdcp
->c_cnid
== kHFSRootFolderID
));
2835 hfs_volupdate(hfsmp
, vnode_isdir(fvp
) ? VOL_MKDIR
: VOL_MKFILE
, (tdcp
->c_cnid
== kHFSRootFolderID
));
2837 /* Update both parent directories. */
2840 if (vnode_isdir(fvp
))
2842 /* If the source directory has directory hard link
2843 * descendants, set the kHFSHasChildLinkBit in the
2844 * destination parent hierarchy
2846 if ((fcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
) && !(tdcp
->c_attr
.ca_recflags
& kHFSHasChildLinkMask
))
2849 tdcp
->c_attr
.ca_recflags
|= kHFSHasChildLinkMask
;
2851 error
= cat_set_childlinkbit(hfsmp
, tdcp
->c_parentcnid
);
2854 LFHFS_LOG(LEVEL_DEBUG
, "hfs_vnop_rename: error updating parent chain for %u\n", tdcp
->c_cnid
);
2858 INC_FOLDERCOUNT(hfsmp
, tdcp
->c_attr
);
2859 DEC_FOLDERCOUNT(hfsmp
, fdcp
->c_attr
);
2862 tdcp
->c_dirchangecnt
++;
2863 tdcp
->c_flag
|= C_MODIFIED
;
2864 hfs_incr_gencount(tdcp
);
2866 if (fdcp
->c_entries
> 0)
2868 fdcp
->c_dirchangecnt
++;
2869 fdcp
->c_flag
|= C_MODIFIED
;
2870 fdcp
->c_touch_chgtime
= TRUE
;
2871 fdcp
->c_touch_modtime
= TRUE
;
2873 if (ISSET(fcp
->c_flag
, C_HARDLINK
))
2875 hfs_relorigin(fcp
, fdcp
->c_fileid
);
2876 if (fdcp
->c_fileid
!= fdcp
->c_cnid
)
2877 hfs_relorigin(fcp
, fdcp
->c_cnid
);
2880 (void) hfs_update(fdvp
, 0);
2882 hfs_incr_gencount(fdcp
);
2884 tdcp
->c_childhint
= out_desc
.cd_hint
; /* Cache directory's location */
2885 tdcp
->c_touch_chgtime
= TRUE
;
2886 tdcp
->c_touch_modtime
= TRUE
;
2888 (void) hfs_update(tdvp
, 0);
2890 /* Update the vnode's name now that the rename has completed. */
2891 vnode_update_identity(fvp
, tdvp
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
, tcnp
->cn_hash
, (VNODE_UPDATE_PARENT
| VNODE_UPDATE_NAME
));
2894 * At this point, we may have a resource fork vnode attached to the
2895 * 'from' vnode. If it exists, we will want to update its name, because
2896 * it contains the old name + _PATH_RSRCFORKSPEC. ("/..namedfork/rsrc").
2898 * Note that the only thing we need to update here is the name attached to
2899 * the vnode, since a resource fork vnode does not have a separate resource
2900 * cnode -- it's still 'fcp'.
2904 char* rsrc_path
= NULL
;
2907 /* Create a new temporary buffer that's going to hold the new name */
2908 rsrc_path
= hfs_malloc(MAXPATHLEN
);
2909 len
= snprintf (rsrc_path
, MAXPATHLEN
, "%s%s", tcnp
->cn_nameptr
, _PATH_RSRCFORKSPEC
);
2910 len
= MIN(len
, MAXPATHLEN
);
2913 * vnode_update_identity will do the following for us:
2914 * 1) release reference on the existing rsrc vnode's name.
2915 * 2) attach the new name to the resource vnode
2916 * 3) update the vnode's vid
2918 vnode_update_identity (fcp
->c_rsrc_vp
, fvp
, rsrc_path
, len
, 0, (VNODE_UPDATE_NAME
| VNODE_UPDATE_CACHE
));
2920 /* Free the memory associated with the resource fork's name */
2921 hfs_free(rsrc_path
);
2926 cat_postflight(hfsmp
, &cookie
);
2930 hfs_end_transaction(hfsmp
);
2933 fdvp
->sExtraData
.sDirData
.uDirVersion
++;
2934 fdcp
->c_flag
&= ~C_DIR_MODIFICATION
;
2935 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
2936 // wakeup((caddr_t)&fdcp->c_flag);
2940 tdvp
->sExtraData
.sDirData
.uDirVersion
++;
2941 tdcp
->c_flag
&= ~C_DIR_MODIFICATION
;
2942 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
2943 // wakeup((caddr_t)&tdcp->c_flag);
2947 /* Now vnode_put the resource forks vnodes if necessary */
2950 hfs_chash_lower_OpenLookupCounter(tcp
);
2954 hfs_unlockfour(fdcp
, fcp
, tdcp
, tcp
);
2956 if (took_trunc_lock
)
2958 hfs_unlock_truncate(VTOC(tvp
), HFS_LOCK_DEFAULT
);
2961 /* After tvp is removed the only acceptable error is EIO */
2962 if (error
&& tvp_deleted
)
2969 * link vnode operation
2972 * IN vnode_t a_tdvp;
2973 * IN struct componentname *a_cnp;
2974 * IN vfs_context_t a_context;
2977 hfs_vnop_link(vnode_t vp
, vnode_t tdvp
, struct componentname
*cnp
)
2979 struct hfsmount
*hfsmp
= VTOHFS(vp
);;
2980 struct cnode
*cp
= VTOC(vp
);;
2982 struct cnode
*fdcp
= NULL
;
2983 struct cat_desc todesc
;
2987 enum vtype v_type
= vp
->sFSParams
.vnfs_vtype
;
2991 * For now, return ENOTSUP for a symlink target. This can happen
2992 * for linkat(2) when called without AT_SYMLINK_FOLLOW.
2994 if (v_type
== VLNK
|| v_type
== VDIR
)
2997 /* Make sure our private directory exists. */
2998 if (hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
== 0) {
3002 if (hfs_freeblks(hfsmp
, 0) == 0) {
3006 /* Lock the cnodes. */
3007 if ((error
= hfs_lockpair(VTOC(tdvp
), VTOC(vp
), HFS_EXCLUSIVE_LOCK
))) {
3012 /* grab the parent CNID from originlist after grabbing cnode locks */
3013 parentcnid
= hfs_currentparent(cp
, /* have_lock: */ true);
3015 if (tdcp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
3020 /* Check the source for errors:
3021 * too many links, immutable, race with unlink
3023 if (cp
->c_linkcount
>= HFS_LINK_MAX
) {
3027 if (cp
->c_bsdflags
& (UF_IMMUTABLE
| SF_IMMUTABLE
| UF_APPEND
| SF_APPEND
)) {
3031 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
3036 tdcp
->c_flag
|= C_DIR_MODIFICATION
;
3038 if (hfs_start_transaction(hfsmp
) != 0) {
3044 todesc
.cd_flags
= (v_type
== VDIR
) ? CD_ISDIR
: 0;
3045 todesc
.cd_encoding
= 0;
3046 todesc
.cd_nameptr
= (const u_int8_t
*)cnp
->cn_nameptr
;
3047 todesc
.cd_namelen
= cnp
->cn_namelen
;
3048 todesc
.cd_parentcnid
= tdcp
->c_fileid
;
3052 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
3054 /* If destination exists then we lost a race with create. */
3055 if (cat_lookup(hfsmp
, &todesc
, 0, NULL
, NULL
, NULL
, NULL
) == 0) {
3059 if (cp
->c_flag
& C_HARDLINK
) {
3060 struct cat_attr cattr
;
3062 /* If inode is missing then we lost a race with unlink. */
3063 if ((cat_idlookup(hfsmp
, cp
->c_fileid
, 0, 0, NULL
, &cattr
, NULL
) != 0) ||
3064 (cattr
.ca_fileid
!= cp
->c_fileid
)) {
3071 /* If source is missing then we lost a race with unlink. */
3072 if ((cat_lookup(hfsmp
, &cp
->c_desc
, 0, NULL
, NULL
, NULL
, &fileid
) != 0) ||
3073 (fileid
!= cp
->c_fileid
)) {
3079 * All directory links must reside in an non-ARCHIVED hierarchy.
3081 if (v_type
== VDIR
) {
3083 * - Source parent and destination parent cannot match
3084 * - A link is not permitted in the root directory
3085 * - Parent of 'pointed at' directory is not the root directory
3086 * - The 'pointed at' directory (source) is not an ancestor
3087 * of the new directory hard link (destination).
3088 * - No ancestor of the new directory hard link (destination)
3089 * is a directory hard link.
3091 if ((parentcnid
== tdcp
->c_fileid
) ||
3092 (tdcp
->c_fileid
== kHFSRootFolderID
) ||
3093 (parentcnid
== kHFSRootFolderID
) ||
3094 cat_check_link_ancestry(hfsmp
, tdcp
->c_fileid
, cp
->c_fileid
)) {
3095 error
= EPERM
; /* abide by the rules, you did not */
3099 hfs_systemfile_unlock(hfsmp
, lockflags
);
3103 cp
->c_flag
|= C_MODIFIED
;
3104 cp
->c_touch_chgtime
= TRUE
;
3105 error
= hfs_makelink(hfsmp
, vp
, cp
, tdcp
, cnp
);
3108 hfs_volupdate(hfsmp
, VOL_UPDATE
, 0);
3110 /* Update the target directory and volume stats */
3112 if (v_type
== VDIR
) {
3113 INC_FOLDERCOUNT(hfsmp
, tdcp
->c_attr
);
3114 tdcp
->c_attr
.ca_recflags
|= kHFSHasChildLinkMask
;
3116 /* Set kHFSHasChildLinkBit in the destination hierarchy */
3117 error
= cat_set_childlinkbit(hfsmp
, tdcp
->c_parentcnid
);
3119 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_link: error updating destination parent chain for id=%u, vol=%s\n", tdcp
->c_cnid
, hfsmp
->vcbVN
);
3122 tdcp
->c_dirchangecnt
++;
3123 tdcp
->c_flag
|= C_MODIFIED
;
3124 hfs_incr_gencount(tdcp
);
3125 tdcp
->c_touch_chgtime
= TRUE
;
3126 tdcp
->c_touch_modtime
= TRUE
;
3128 error
= hfs_update(tdvp
, 0);
3130 if (error
!= EIO
&& error
!= ENXIO
) {
3131 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_link: error %d updating tdvp %p\n", error
, tdvp
);
3134 hfs_mark_inconsistent(hfsmp
, HFS_OP_INCOMPLETE
);
3137 hfs_volupdate(hfsmp
, VOL_MKFILE
, (tdcp
->c_cnid
== kHFSRootFolderID
));
3140 if (error
== 0 && (ret
= hfs_update(vp
, 0)) != 0) {
3141 if (ret
!= EIO
&& ret
!= ENXIO
)
3142 LFHFS_LOG(LEVEL_ERROR
, "hfs_vnop_link: error %d updating vp @ %p\n", ret
, vp
);
3143 hfs_mark_inconsistent(hfsmp
, HFS_OP_INCOMPLETE
);
3148 hfs_systemfile_unlock(hfsmp
, lockflags
);
3151 hfs_end_transaction(hfsmp
);
3154 tdcp
->c_flag
&= ~C_DIR_MODIFICATION
;
3155 //TBD - We have wakeup here but can't see anyone who's msleeping on c_flag...
3156 // wakeup((caddr_t)&tdcp->c_flag);
3159 hfs_unlockfour(tdcp
, cp
, fdcp
, NULL
);
3161 hfs_unlockpair(tdcp
, cp
);
3167 int hfs_removefile_callback(GenericLFBuf
*psBuff
, void *pvArgs
) {
3169 journal_kill_block(((struct hfsmount
*)pvArgs
)->jnl
, psBuff
);
3176 * hfs_vgetrsrc acquires a resource fork vnode corresponding to the
3177 * cnode that is found in 'vp'. The cnode should be locked upon entry
3178 * and will be returned locked, but it may be dropped temporarily.
3180 * If the resource fork vnode does not exist, HFS will attempt to acquire an
3181 * empty (uninitialized) vnode from VFS so as to avoid deadlocks with
3182 * jetsam. If we let the normal getnewvnode code produce the vnode for us
3183 * we would be doing so while holding the cnode lock of our cnode.
3185 * On success, *rvpp wlll hold the resource fork vnode with an
3186 * iocount. *Don't* forget the vnode_put.
3189 hfs_vgetrsrc( struct vnode
*vp
, struct vnode
**rvpp
)
3191 struct hfsmount
*hfsmp
= VTOHFS(vp
);
3192 struct vnode
*rvp
= NULL
;
3193 struct cnode
*cp
= VTOC(vp
);
3197 /* Attempt to use existing vnode */
3198 if ((rvp
= cp
->c_rsrc_vp
)) {
3199 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
3200 hfs_chash_raise_OpenLookupCounter(cp
);
3203 struct cat_fork rsrcfork
;
3204 struct cat_desc
*descptr
= NULL
;
3205 struct cat_desc to_desc
;
3206 int newvnode_flags
= 0;
3208 hfs_lock(cp
, HFS_EXCLUSIVE_LOCK
, HFS_LOCK_DEFAULT
);
3211 * We could have raced with another thread here while we dropped our cnode
3212 * lock. See if the cnode now has a resource fork vnode and restart if appropriate.
3214 * Note: We just released the cnode lock, so there is a possibility that the
3215 * cnode that we just acquired has been deleted or even removed from disk
3216 * completely, though this is unlikely. If the file is open-unlinked, the
3217 * check below will resolve it for us. If it has been completely
3218 * removed (even from the catalog!), then when we examine the catalog
3219 * directly, below, while holding the catalog lock, we will not find the
3220 * item and we can fail out properly.
3222 if (cp
->c_rsrc_vp
) {
3223 /* Drop the empty vnode before restarting */
3230 * hfs_vgetsrc may be invoked for a cnode that has already been marked
3231 * C_DELETED. This is because we need to continue to provide rsrc
3232 * fork access to open-unlinked files. In this case, build a fake descriptor
3233 * like in hfs_removefile. If we don't do this, buildkey will fail in
3234 * cat_lookup because this cnode has no name in its descriptor.
3236 if ((cp
->c_flag
& C_DELETED
) && (cp
->c_desc
.cd_namelen
== 0)) {
3238 bzero (&to_desc
, sizeof(to_desc
));
3239 bzero (delname
, 32);
3240 MAKE_DELETED_NAME(delname
, sizeof(delname
), cp
->c_fileid
);
3241 to_desc
.cd_nameptr
= (const u_int8_t
*) delname
;
3242 to_desc
.cd_namelen
= strlen(delname
);
3243 to_desc
.cd_parentcnid
= hfsmp
->hfs_private_desc
[FILE_HARDLINKS
].cd_cnid
;
3244 to_desc
.cd_flags
= 0;
3245 to_desc
.cd_cnid
= cp
->c_cnid
;
3250 descptr
= &cp
->c_desc
;
3254 int lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
3257 * We call cat_idlookup (instead of cat_lookup) below because we can't
3258 * trust the descriptor in the provided cnode for lookups at this point.
3259 * Between the time of the original lookup of this vnode and now, the
3260 * descriptor could have gotten swapped or replaced. If this occurred,
3261 * the parent/name combo originally desired may not necessarily be provided
3262 * if we use the descriptor. Even worse, if the vnode represents
3263 * a hardlink, we could have removed one of the links from the namespace
3264 * but left the descriptor alone, since hfs_unlink does not invalidate
3265 * the descriptor in the cnode if other links still point to the inode.
3267 * Consider the following (slightly contrived) scenario:
3268 * /tmp/a <--> /tmp/b (hardlinks).
3269 * 1. Thread A: open rsrc fork on /tmp/b.
3270 * 1a. Thread A: does lookup, goes out to lunch right before calling getnamedstream.
3271 * 2. Thread B does 'mv /foo/b /tmp/b'
3272 * 2. Thread B succeeds.
3273 * 3. Thread A comes back and wants rsrc fork info for /tmp/b.
3275 * Even though the hardlink backing /tmp/b is now eliminated, the descriptor
3276 * is not removed/updated during the unlink process. So, if you were to
3277 * do a lookup on /tmp/b, you'd acquire an entirely different record's resource
3280 * As a result, we use the fileid, which should be invariant for the lifetime
3281 * of the cnode (possibly barring calls to exchangedata).
3283 * Addendum: We can't do the above for HFS standard since we aren't guaranteed to
3284 * have thread records for files. They were only required for directories. So
3285 * we need to do the lookup with the catalog name. This is OK since hardlinks were
3286 * never allowed on HFS standard.
3289 /* Get resource fork data */
3290 error
= cat_idlookup (hfsmp
, cp
->c_fileid
, 0, 1, NULL
, NULL
, &rsrcfork
);
3292 hfs_systemfile_unlock(hfsmp
, lockflags
);
3294 LFHFS_LOG(LEVEL_ERROR
, "hfs_vgetrsrc: cat_idlookup failed with error [%d]\n", error
);
3296 hfs_chash_lower_OpenLookupCounter(cp
);
3300 * Supply hfs_getnewvnode with a component name.
3302 struct componentname cn
;
3304 if (descptr
->cd_nameptr
) {
3305 void *buf
= hfs_malloc(MAXPATHLEN
);
3307 cn
= (struct componentname
){
3308 .cn_nameiop
= LOOKUP
,
3309 .cn_flags
= ISLASTCN
,
3310 .cn_pnlen
= MAXPATHLEN
,
3313 .cn_namelen
= snprintf(buf
, MAXPATHLEN
,
3314 "%s%s", descptr
->cd_nameptr
,
3318 // Should never happen because cn.cn_nameptr won't ever be long...
3319 if (cn
.cn_namelen
>= MAXPATHLEN
) {
3321 LFHFS_LOG(LEVEL_ERROR
, "hfs_vgetrsrc: cnode name too long [ENAMETOOLONG]\n");
3323 hfs_chash_lower_OpenLookupCounter(cp
);
3324 return ENAMETOOLONG
;
3329 * We are about to call hfs_getnewvnode and pass in the vnode that we acquired
3330 * earlier when we were not holding any locks. The semantics of GNV_USE_VP require that
3331 * either hfs_getnewvnode consume the vnode and vend it back to us, properly initialized,
3332 * or it will consume/dispose of it properly if it errors out.
3334 error
= hfs_getnewvnode(hfsmp
, NULL
, cn
.cn_pnbuf
? &cn
: NULL
,
3335 descptr
, (GNV_WANTRSRC
| GNV_SKIPLOCK
),
3336 &cp
->c_attr
, &rsrcfork
, &rvp
, &newvnode_flags
);
3338 hfs_free(cn
.cn_pnbuf
);
3341 } /* End 'else' for rsrc fork not existing */