The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_link.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 
   26 
   27 #include <sys/systm.h>
   28 #include <sys/kernel.h>
   29 #include <sys/malloc.h>
   30 #include <sys/mount.h>
   31 #include <sys/namei.h>
   32 #include <sys/stat.h>
   33 #include <sys/vnode.h>
   34 #include <vfs/vfs_support.h>
   35 #include <libkern/libkern.h>
   36 
   37 #include "hfs.h"
   38 #include "hfs_catalog.h"
   39 #include "hfs_format.h"
   40 #include "hfs_endian.h"
   41 
   42 
   43 /*
   44  * Create a new indirect link
   45  *
   46  * An indirect link is a reference to a data node.  The only useable
   47  * fields in the link are the link number, parentID, name and text
   48  * encoding.  All other catalog fields are ignored.
   49  */
   50 static int
   51 createindirectlink(struct hfsmount *hfsmp, u_int32_t linknum,
   52                         u_int32_t linkparid, char *linkName, cnid_t *linkcnid)
   53 {
   54         struct FndrFileInfo *fip;
   55         struct cat_desc desc;
   56         struct cat_attr attr;
   57         int result;
   58 
   59         /* Setup the descriptor */
   60         bzero(&desc, sizeof(desc));
   61         desc.cd_nameptr = linkName;
   62         desc.cd_namelen = strlen(linkName);
   63         desc.cd_parentcnid = linkparid;
   64 
   65         /* Setup the default attributes */
   66         bzero(&attr, sizeof(attr));
   67         
   68         /* links are matched to data nodes by link ID and to volumes by create date */
   69         attr.ca_rdev = linknum;  /* note: cat backend overloads ca_rdev to be the linknum when nlink = 0 */
   70         attr.ca_itime = HFSTOVCB(hfsmp)->vcbCrDate;
   71         attr.ca_mode = S_IFREG;
   72 
   73         fip = (struct FndrFileInfo *)&attr.ca_finderinfo;
   74         fip->fdType    = SWAP_BE32 (kHardLinkFileType); /* 'hlnk' */
   75         fip->fdCreator = SWAP_BE32 (kHFSPlusCreator);   /* 'hfs+' */
   76         fip->fdFlags   = SWAP_BE16 (kHasBeenInited);
   77 
   78         hfs_global_shared_lock_acquire(hfsmp);
   79         if (hfsmp->jnl) {
   80             if (journal_start_transaction(hfsmp->jnl) != 0) {
   81                         hfs_global_shared_lock_release(hfsmp);
   82                         return EINVAL;
   83             }
   84         }
   85 
   86         /* Create the indirect link directly in the catalog */
   87         result = cat_create(hfsmp, &desc, &attr, NULL);
   88 
   89         if (result == 0 && linkcnid != NULL)
   90                 *linkcnid = attr.ca_fileid;
   91 
   92         if (hfsmp->jnl) {
   93             journal_end_transaction(hfsmp->jnl);
   94         }
   95         hfs_global_shared_lock_release(hfsmp);
   96 
   97         return (result);
   98 }
   99 
  100 
  101 /*
  102  * 2 locks are needed (dvp and vp)
  103  * also need catalog lock
  104  *
  105  * caller's responsibility:
  106  *              componentname cleanup
  107  *              unlocking dvp and vp
  108  */
  109 static int
  110 hfs_makelink(struct hfsmount *hfsmp, struct cnode *cp, struct cnode *dcp,
  111                 struct componentname *cnp)
  112 {
  113         struct proc *p = cnp->cn_proc;
  114         u_int32_t indnodeno = 0;
  115         char inodename[32];
  116         struct cat_desc to_desc;
  117         int newlink = 0;
  118         int retval;
  119         cat_cookie_t cookie = {0};
  120 
  121 
  122         /* We don't allow link nodes in our Private Meta Data folder! */
  123         if (dcp->c_fileid == hfsmp->hfs_privdir_desc.cd_cnid)
  124                 return (EPERM);
  125 
  126         if (hfs_freeblks(hfsmp, 0) == 0)
  127                 return (ENOSPC);
  128 
  129         /* Reserve some space in the Catalog file. */
  130         if ((retval = cat_preflight(hfsmp, (2 * CAT_CREATE)+ CAT_RENAME, &cookie, p))) {
  131                 return (retval);
  132         }
  133 
  134         /* Lock catalog b-tree */
  135         retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
  136         if (retval) {
  137            goto out2;
  138         }
  139 
  140         /*
  141          * If this is a new hardlink then we need to create the data
  142          * node (inode) and replace the original file with a link node.
  143          */
  144         if (cp->c_nlink == 2 && (cp->c_flag & C_HARDLINK) == 0) {
  145                 newlink = 1;
  146                 bzero(&to_desc, sizeof(to_desc));
  147                 to_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid;
  148                 to_desc.cd_cnid = cp->c_fileid;
  149 
  150                 do {
  151                         /* get a unique indirect node number */
  152                         indnodeno = ((random() & 0x3fffffff) + 100);
  153                         MAKE_INODE_NAME(inodename, indnodeno);
  154 
  155                         /* move source file to data node directory */
  156                         to_desc.cd_nameptr = inodename;
  157                         to_desc.cd_namelen = strlen(inodename);
  158                 
  159                         retval = cat_rename(hfsmp, &cp->c_desc, &hfsmp->hfs_privdir_desc,
  160                                         &to_desc, NULL);
  161 
  162                 } while (retval == EEXIST);
  163                 if (retval)
  164                         goto out;
  165 
  166                 /* Replace source file with link node */
  167                 retval = createindirectlink(hfsmp, indnodeno, cp->c_parentcnid,
  168                                 cp->c_desc.cd_nameptr, &cp->c_desc.cd_cnid);
  169                 if (retval) {
  170                         /* put it source file back */
  171                 // XXXdbg
  172                 #if 1
  173                     {
  174                         int err;
  175                                 err = cat_rename(hfsmp, &to_desc, &dcp->c_desc, &cp->c_desc, NULL);
  176                                 if (err)
  177                                         panic("hfs_makelink: error %d from cat_rename backout 1", err);
  178                     }
  179                 #else
  180                         (void) cat_rename(hfsmp, &to_desc, &dcp->c_desc, &cp->c_desc, NULL);
  181                 #endif
  182                         goto out;
  183                 }
  184                 cp->c_rdev = indnodeno;
  185         } else {
  186                 indnodeno = cp->c_rdev;
  187         }
  188 
  189         /*
  190          * Create a catalog entry for the new link (parentID + name).
  191          */
  192         retval = createindirectlink(hfsmp, indnodeno, dcp->c_fileid, cnp->cn_nameptr, NULL);
  193         if (retval && newlink) {
  194                 /* Get rid of new link */
  195                 (void) cat_delete(hfsmp, &cp->c_desc, &cp->c_attr);
  196 
  197                 /* Put the source file back */
  198         // XXXdbg
  199         #if 1
  200                 {
  201                         int err;
  202                         err = cat_rename(hfsmp, &to_desc, &dcp->c_desc, &cp->c_desc, NULL);
  203                         if (err)
  204                                 panic("hfs_makelink: error %d from cat_rename backout 2", err);
  205                 }
  206         #else
  207                 (void) cat_rename(hfsmp, &to_desc, &dcp->c_desc, &cp->c_desc, NULL);
  208         #endif
  209                 goto out;
  210         }
  211 
  212         /*
  213          * Finally, if this is a new hardlink then:
  214          *  - update HFS Private Data dir
  215          *  - mark the cnode as a hard link
  216          */
  217         if (newlink) {
  218                 hfsmp->hfs_privdir_attr.ca_entries++;
  219                 (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
  220                         &hfsmp->hfs_privdir_attr, NULL, NULL);
  221                 hfs_volupdate(hfsmp, VOL_MKFILE, 0);
  222                 cp->c_flag |= (C_CHANGE | C_HARDLINK);
  223         }
  224 
  225 out:
  226         /* Unlock catalog b-tree */
  227         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  228 out2:
  229         cat_postflight(hfsmp, &cookie, p);
  230         return (retval);
  231 }
  232 
  233 
  234 /*
  235  * link vnode call
  236 #% link         vp      U U U
  237 #% link         tdvp    L U U
  238 #
  239  vop_link {
  240      IN WILLRELE struct vnode *vp;
  241      IN struct vnode *targetPar_vp;
  242      IN struct componentname *cnp;
  243 
  244      */
  245 __private_extern__
  246 int
  247 hfs_link(ap)
  248         struct vop_link_args /* {
  249                 struct vnode *a_vp;
  250                 struct vnode *a_tdvp;
  251                 struct componentname *a_cnp;
  252         } */ *ap;
  253 {
  254         struct hfsmount *hfsmp;
  255         struct vnode *vp = ap->a_vp;
  256         struct vnode *tdvp = ap->a_tdvp;
  257         struct componentname *cnp = ap->a_cnp;
  258         struct proc *p = cnp->cn_proc;
  259         struct cnode *cp;
  260         struct cnode *tdcp;
  261         struct timeval tv;
  262         int error;
  263 
  264         hfsmp = VTOHFS(vp);
  265         
  266 #if HFS_DIAGNOSTIC
  267         if ((cnp->cn_flags & HASBUF) == 0)
  268                 panic("hfs_link: no name");
  269 #endif
  270         if (tdvp->v_mount != vp->v_mount) {
  271                 VOP_ABORTOP(tdvp, cnp);
  272                 error = EXDEV;
  273                 goto out2;
  274         }
  275         if (VTOVCB(tdvp)->vcbSigWord != kHFSPlusSigWord)
  276                 return err_link(ap);    /* hfs disks don't support hard links */
  277         
  278         if (hfsmp->hfs_privdir_desc.cd_cnid == 0)
  279                 return err_link(ap);    /* no private metadata dir, no links possible */
  280 
  281         if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
  282                 VOP_ABORTOP(tdvp, cnp);
  283                 goto out2;
  284         }
  285         cp = VTOC(vp);
  286         tdcp = VTOC(tdvp);
  287 
  288         if (cp->c_nlink >= HFS_LINK_MAX) {
  289                 VOP_ABORTOP(tdvp, cnp);
  290                 error = EMLINK;
  291                 goto out1;
  292         }
  293         if (cp->c_flags & (IMMUTABLE | APPEND)) {
  294                 VOP_ABORTOP(tdvp, cnp);
  295                 error = EPERM;
  296                 goto out1;
  297         }
  298         if (vp->v_type == VBLK || vp->v_type == VCHR) {
  299                 VOP_ABORTOP(tdvp, cnp);
  300                 error = EINVAL;  /* cannot link to a special file */
  301                 goto out1;
  302         }
  303 
  304         hfs_global_shared_lock_acquire(hfsmp);
  305         if (hfsmp->jnl) {
  306             if (journal_start_transaction(hfsmp->jnl) != 0) {
  307                         hfs_global_shared_lock_release(hfsmp);
  308                         VOP_ABORTOP(tdvp, cnp);
  309                         error = EINVAL;  /* cannot link to a special file */
  310                         goto out1;
  311             }
  312         }
  313 
  314         cp->c_nlink++;
  315         cp->c_flag |= C_CHANGE;
  316         tv = time;
  317 
  318         error = VOP_UPDATE(vp, &tv, &tv, 1);
  319         if (!error) {
  320                 error = hfs_makelink(hfsmp, cp, tdcp, cnp);
  321         }
  322         if (error) {
  323                 cp->c_nlink--;
  324                 cp->c_flag |= C_CHANGE;
  325         } else {
  326                 /* Update the target directory and volume stats */
  327                 tdcp->c_nlink++;
  328                 tdcp->c_entries++;
  329                 tdcp->c_flag |= C_CHANGE | C_UPDATE;
  330                 tv = time;
  331                 (void) VOP_UPDATE(tdvp, &tv, &tv, 0);
  332 
  333                 hfs_volupdate(hfsmp, VOL_MKFILE,
  334                         (tdcp->c_cnid == kHFSRootFolderID));
  335         }
  336 
  337         // XXXdbg - need to do this here as well because cp could have changed
  338         error = VOP_UPDATE(vp, &tv, &tv, 1);
  339 
  340 
  341         if (hfsmp->jnl) {
  342             journal_end_transaction(hfsmp->jnl);
  343         }
  344         hfs_global_shared_lock_release(hfsmp);
  345 
  346         /* free the pathname buffer */
  347         {
  348                 char *tmp = cnp->cn_pnbuf;
  349                 cnp->cn_pnbuf = NULL;
  350                 cnp->cn_flags &= ~HASBUF;
  351                 FREE_ZONE(tmp, cnp->cn_pnlen, M_NAMEI);
  352         }
  353         
  354         HFS_KNOTE(vp, NOTE_LINK);
  355         HFS_KNOTE(tdvp, NOTE_WRITE);
  356 
  357 out1:
  358         if (tdvp != vp)
  359                 VOP_UNLOCK(vp, 0, p);
  360 out2:
  361         vput(tdvp);
  362         return (error);
  363 }

Cache object: 7f3a9f09bcf62bc6fc72d994ae2bd42e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.