]>
git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_link.c
2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/systm.h>
26 #include <sys/kernel.h>
27 #include <sys/malloc.h>
28 #include <sys/namei.h>
30 #include <sys/vnode.h>
31 #include <vfs/vfs_support.h>
32 #include <libkern/libkern.h>
35 #include "hfscommon/headers/FileMgrInternal.h"
39 * Create a new indirect link
41 * An indirect link is a reference to a data node. The only useable fields in the
42 * link are the parentID, name and text encoding. All other catalog fields
46 createindirectlink(struct hfsnode
*dnhp
, UInt32 linkPID
, char *linkName
)
48 struct hfsCatalogInfo catInfo
;
55 /* Create the indirect link directly in the catalog */
56 result
= hfsCreate(vcb
, linkPID
, linkName
, IFREG
);
57 if (result
) return (result
);
60 * XXX SER Here is a good example where hfsCreate should pass in a catinfo and return
61 * things like the hint and file ID there should be no reason to call lookup here
64 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
66 result
= hfs_getcatalog(vcb
, linkPID
, linkName
, -1, &catInfo
);
67 if (result
) goto errExit
;
69 fip
= (struct FInfo
*)&catInfo
.nodeData
.cnd_finderInfo
;
70 fip
->fdType
= kHardLinkFileType
; /* 'hlnk' */
71 fip
->fdCreator
= kHFSPlusCreator
; /* 'hfs+' */
72 fip
->fdFlags
|= kHasBeenInited
;
74 /* links are matched to data nodes by nodeID and to volumes by create date */
75 catInfo
.nodeData
.cnd_iNodeNum
= dnhp
->h_meta
->h_indnodeno
;
76 catInfo
.nodeData
.cnd_createDate
= vcb
->vcbCrDate
;
78 result
= UpdateCatalogNode(vcb
, linkPID
, linkName
, catInfo
.hint
, &catInfo
.nodeData
);
79 if (result
) goto errExit
;
81 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
85 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
87 /* get rid of link node */
88 (void) hfsDelete(vcb
, linkPID
, linkName
, TRUE
, 0);
95 * 2 locks are needed (dvp and hp)
96 * also need catalog lock
98 * caller's responsibility:
99 * componentname cleanup
100 * unlocking dvp and hp
103 hfs_makelink(hp
, dvp
, cnp
)
106 register struct componentname
*cnp
;
108 struct proc
*p
= cnp
->cn_proc
;
109 struct hfsnode
*dhp
= VTOH(dvp
);
110 u_int32_t ldirID
; /* directory ID of linked nodes directory */
111 ExtendedVCB
*vcb
= VTOVCB(dvp
);
113 u_int32_t indnodeno
= 0;
117 ldirID
= VTOHFS(dvp
)->hfs_private_metadata_dir
;
119 /* We don't allow link nodes in our Private Meta Data folder! */
120 if ( H_FILEID(dhp
) == ldirID
)
123 if (vcb
->freeBlocks
== 0)
126 /* lock catalog b-tree */
127 retval
= hfs_metafilelocking(VTOHFS(dvp
), kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
128 if (retval
!= E_NONE
)
132 * If this is a new hardlink then we need to create the data
133 * node (inode) and replace the original file with a link node.
135 if (hp
->h_meta
->h_nlink
== 1) {
137 /* get a unique indirect node number */
138 indnodeno
= ((random() & 0x3fffffff) + 100);
139 MAKE_INODE_NAME(inodename
, indnodeno
);
141 /* move source file to data node directory */
143 retval
= hfsMoveRename(vcb
, H_DIRID(hp
), H_NAME(hp
), ldirID
, inodename
, &hint
);
144 } while (retval
== cmExists
);
146 if (retval
) goto out
;
148 hp
->h_meta
->h_indnodeno
= indnodeno
;
150 /* replace source file with link node */
151 retval
= createindirectlink(hp
, H_DIRID(hp
), H_NAME(hp
));
153 /* put it source file back */
155 (void) hfsMoveRename(vcb
, ldirID
, inodename
, H_DIRID(hp
), H_NAME(hp
), &hint
);
161 * Create a catalog entry for the new link (parentID + name).
163 retval
= createindirectlink(hp
, H_FILEID(dhp
), cnp
->cn_nameptr
);
164 if (retval
&& hp
->h_meta
->h_nlink
== 1) {
165 /* get rid of new link */
166 (void) hfsDelete(vcb
, H_DIRID(hp
), H_NAME(hp
), TRUE
, 0);
168 /* put it source file back */
170 (void) hfsMoveRename(vcb
, ldirID
, inodename
, H_DIRID(hp
), H_NAME(hp
), &hint
);
175 * Finally, if this is a new hardlink then we need to mark the hfs node
177 if (hp
->h_meta
->h_nlink
== 1) {
178 hp
->h_meta
->h_nlink
++;
179 hp
->h_nodeflags
|= IN_CHANGE
;
180 hp
->h_meta
->h_metaflags
|= IN_DATANODE
;
184 /* unlock catalog b-tree */
185 (void) hfs_metafilelocking(VTOHFS(dvp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
197 IN WILLRELE struct vnode *vp;
198 IN struct vnode *targetPar_vp;
199 IN struct componentname *cnp;
204 struct vop_link_args
/* {
206 struct vnode *a_tdvp;
207 struct componentname *a_cnp;
210 struct vnode
*vp
= ap
->a_vp
;
211 struct vnode
*tdvp
= ap
->a_tdvp
;
212 struct componentname
*cnp
= ap
->a_cnp
;
213 struct proc
*p
= cnp
->cn_proc
;
219 if ((cnp
->cn_flags
& HASBUF
) == 0)
220 panic("hfs_link: no name");
222 if (tdvp
->v_mount
!= vp
->v_mount
) {
223 VOP_ABORTOP(tdvp
, cnp
);
227 if (VTOVCB(tdvp
)->vcbSigWord
!= kHFSPlusSigWord
)
228 return err_link(ap
); /* hfs disks don't support hard links */
230 if (VTOHFS(vp
)->hfs_private_metadata_dir
== 0)
231 return err_link(ap
); /* no private metadata dir, no links possible */
233 if (tdvp
!= vp
&& (error
= vn_lock(vp
, LK_EXCLUSIVE
, p
))) {
234 VOP_ABORTOP(tdvp
, cnp
);
238 if (hp
->h_meta
->h_nlink
>= HFS_LINK_MAX
) {
239 VOP_ABORTOP(tdvp
, cnp
);
243 if (hp
->h_meta
->h_pflags
& (IMMUTABLE
| APPEND
)) {
244 VOP_ABORTOP(tdvp
, cnp
);
248 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) {
249 VOP_ABORTOP(tdvp
, cnp
);
250 error
= EINVAL
; /* cannot link to a special file */
254 hp
->h_meta
->h_nlink
++;
255 hp
->h_nodeflags
|= IN_CHANGE
;
257 error
= VOP_UPDATE(vp
, &tv
, &tv
, 1);
259 error
= hfs_makelink(hp
, tdvp
, cnp
);
261 hp
->h_meta
->h_nlink
--;
262 hp
->h_nodeflags
|= IN_CHANGE
;
264 FREE_ZONE(cnp
->cn_pnbuf
, cnp
->cn_pnlen
, M_NAMEI
);
267 VOP_UNLOCK(vp
, 0, p
);