/*
- * Copyright (c) 1999-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
&to_desc, NULL);
if (retval != 0 && retval != EEXIST) {
- printf("hfs_makelink: cat_rename to %s failed (%d). fileid %d\n",
- inodename, retval, cp->c_fileid);
+ printf("hfs_makelink: cat_rename to %s failed (%d) fileid=%d, vol=%s\n",
+ inodename, retval, cp->c_fileid, hfsmp->vcbVN);
}
} while ((retval == EEXIST) && (type == FILE_HARDLINKS));
if (retval)
return (EPERM);
}
if (v_type == VDIR) {
+#if CONFIG_HFS_DIRLINK
/* Make sure our private directory exists. */
if (hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid == 0) {
return (EPERM);
if ((error = hfs_vget(hfsmp, hfs_currentparent(VTOC(vp)), &fdvp, 1, 0))) {
return (error);
}
+#else
+ /* some platforms don't support directory hardlinks. */
+ return EPERM;
+#endif
} else {
/* Make sure our private directory exists. */
if (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid == 0) {
error = EMLINK;
goto out;
}
- if (cp->c_flags & (IMMUTABLE | APPEND)) {
+ if (cp->c_bsdflags & (IMMUTABLE | APPEND)) {
error = EPERM;
goto out;
}
lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
/* If destination exists then we lost a race with create. */
- if (cat_lookup(hfsmp, &todesc, 0, NULL, NULL, NULL, NULL) == 0) {
+ if (cat_lookup(hfsmp, &todesc, 0, 0, NULL, NULL, NULL, NULL) == 0) {
error = EEXIST;
goto out;
}
struct cat_attr cattr;
/* If inode is missing then we lost a race with unlink. */
- if ((cat_idlookup(hfsmp, cp->c_fileid, 0, NULL, &cattr, NULL) != 0) ||
+ if ((cat_idlookup(hfsmp, cp->c_fileid, 0, 0, NULL, &cattr, NULL) != 0) ||
(cattr.ca_fileid != cp->c_fileid)) {
error = ENOENT;
goto out;
cnid_t fileid;
/* If source is missing then we lost a race with unlink. */
- if ((cat_lookup(hfsmp, &cp->c_desc, 0, NULL, NULL, NULL, &fileid) != 0) ||
+ if ((cat_lookup(hfsmp, &cp->c_desc, 0, 0, NULL, NULL, NULL, &fileid) != 0) ||
(fileid != cp->c_fileid)) {
error = ENOENT;
goto out;
/* Set kHFSHasChildLinkBit in the destination hierarchy */
error = cat_set_childlinkbit(hfsmp, tdcp->c_parentcnid);
if (error) {
- printf ("hfs_vnop_link: error updating destination parent chain for %u\n", tdcp->c_cnid);
+ printf ("hfs_vnop_link: error updating destination parent chain for id=%u, vol=%s\n", tdcp->c_cnid, hfsmp->vcbVN);
error = 0;
}
}
/* Set kHFSHasChildLinkBit in the source hierarchy */
error = cat_set_childlinkbit(hfsmp, fdcp->c_parentcnid);
if (error) {
- printf ("hfs_vnop_link: error updating source parent chain for %u\n", fdcp->c_cnid);
+ printf ("hfs_vnop_link: error updating source parent chain for id=%u, vol=%s\n", fdcp->c_cnid, hfsmp->vcbVN);
error = 0;
}
}
if (nextlinkid) {
(void) cat_update_siblinglinks(hfsmp, nextlinkid, prevlinkid, HFS_IGNORABLE_LINK);
}
+
+ /*
+ * The call to cat_releasedesc below will only release the name buffer;
+ * it does not zero out the rest of the fields in the 'cat_desc' data structure.
+ *
+ * As a result, since there are still other links at this point, we need
+ * to make the current cnode descriptor point to the raw inode. If a path-based
+ * system call comes along first, it will replace the descriptor with a valid link
+ * ID. If a userland process already has a file descriptor open, then they will
+ * bypass that lookup, though. Replacing the descriptor CNID with the raw
+ * inode will force it to generate a new full path.
+ */
+ cp->c_cnid = cp->c_fileid;
+
}
/* Push new link count to disk. */
priv_descp->cd_flags = CD_ISDIR | CD_DECOMPOSED;
lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
- error = cat_lookup(hfsmp, priv_descp, 0, NULL, priv_attrp, NULL, NULL);
+ error = cat_lookup(hfsmp, priv_descp, 0, 0, NULL, priv_attrp, NULL, NULL);
hfs_systemfile_unlock(hfsmp, lockflags);
if (error == 0) {
}
trans = 1;
- lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
+ /* Need the catalog and EA b-trees for CNID acquisition */
+ lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK);
/* Make sure there's space in the Catalog file. */
if (cat_preflight(hfsmp, CAT_CREATE, NULL, 0) != 0) {
goto exit;
}
+ /* Get the CNID for use */
+ cnid_t new_id;
+ if ((error = cat_acquire_cnid(hfsmp, &new_id))) {
+ hfs_systemfile_unlock (hfsmp, lockflags);
+ goto exit;
+ }
+
/* Create the private directory on disk. */
- error = cat_create(hfsmp, priv_descp, priv_attrp, NULL);
+ error = cat_create(hfsmp, new_id, priv_descp, priv_attrp, NULL);
if (error == 0) {
priv_descp->cd_cnid = priv_attrp->ca_fileid;
return (error);
}
+
+/* Find the oldest / last hardlink in the link chain */
+int
+hfs_lookup_lastlink (struct hfsmount *hfsmp, cnid_t linkfileid,
+ cnid_t *lastid, struct cat_desc *cdesc) {
+ int lockflags;
+ int error;
+
+ *lastid = 0;
+
+ lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
+
+ error = cat_lookup_lastlink(hfsmp, linkfileid, lastid, cdesc);
+
+ hfs_systemfile_unlock(hfsmp, lockflags);
+
+ /*
+ * cat_lookup_lastlink will zero out the lastid/cdesc arguments as needed
+ * upon error cases.
+ */
+ return error;
+}
+
+
/*
* Cache the origin of a directory or file hard link
*